1239268Sgonzo/*- 2239268Sgonzo * Copyright (c) 2011 The FreeBSD Foundation 3239268Sgonzo * All rights reserved. 4239268Sgonzo * 5239268Sgonzo * Developed by Damjan Marion <damjan.marion@gmail.com> 6239268Sgonzo * 7239268Sgonzo * Based on OMAP4 GIC code by Ben Gray 8239268Sgonzo * 9239268Sgonzo * Redistribution and use in source and binary forms, with or without 10239268Sgonzo * modification, are permitted provided that the following conditions 11239268Sgonzo * are met: 12239268Sgonzo * 1. Redistributions of source code must retain the above copyright 13239268Sgonzo * notice, this list of conditions and the following disclaimer. 14239268Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 15239268Sgonzo * notice, this list of conditions and the following disclaimer in the 16239268Sgonzo * documentation and/or other materials provided with the distribution. 17239268Sgonzo * 3. The name of the company nor the name of the author may be used to 18239268Sgonzo * endorse or promote products derived from this software without specific 19239268Sgonzo * prior written permission. 20239268Sgonzo * 21239268Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22239268Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23239268Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24239268Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25239268Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26239268Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27239268Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28239268Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29239268Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30239268Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31239268Sgonzo * SUCH DAMAGE. 32239268Sgonzo */ 33239268Sgonzo 34239268Sgonzo#include <sys/cdefs.h> 35239268Sgonzo__FBSDID("$FreeBSD: stable/11/sys/arm/arm/gic.c 329280 2018-02-14 21:39:10Z gonzo $"); 36239268Sgonzo 37289529Sian#include "opt_platform.h" 38289529Sian 39239268Sgonzo#include <sys/param.h> 40239268Sgonzo#include <sys/systm.h> 41239268Sgonzo#include <sys/bus.h> 42239268Sgonzo#include <sys/kernel.h> 43239268Sgonzo#include <sys/ktr.h> 44239268Sgonzo#include <sys/module.h> 45289529Sian#include <sys/malloc.h> 46239268Sgonzo#include <sys/rman.h> 47239268Sgonzo#include <sys/pcpu.h> 48239268Sgonzo#include <sys/proc.h> 49239268Sgonzo#include <sys/cpuset.h> 50239268Sgonzo#include <sys/lock.h> 51239268Sgonzo#include <sys/mutex.h> 52289529Sian#include <sys/smp.h> 53298068Sandrew#ifdef INTRNG 54289529Sian#include <sys/sched.h> 55289529Sian#endif 56299928Sandrew 57299928Sandrew#include <vm/vm.h> 58299928Sandrew#include <vm/pmap.h> 59299928Sandrew 60239268Sgonzo#include <machine/bus.h> 61239268Sgonzo#include <machine/intr.h> 62239268Sgonzo#include <machine/smp.h> 63239268Sgonzo 64239268Sgonzo#include <dev/fdt/fdt_common.h> 65239268Sgonzo#include <dev/ofw/openfirm.h> 66239268Sgonzo#include <dev/ofw/ofw_bus.h> 67239268Sgonzo#include <dev/ofw/ofw_bus_subr.h> 68239268Sgonzo 69298068Sandrew#ifdef INTRNG 70289529Sian#include "pic_if.h" 71299928Sandrew#include "msi_if.h" 72289529Sian#endif 73289529Sian 74291424Smmel#define GIC_DEBUG_SPURIOUS 75291424Smmel 76239268Sgonzo/* We are using GICv2 register naming */ 77239268Sgonzo 78239268Sgonzo/* Distributor Registers */ 79239268Sgonzo#define GICD_CTLR 0x000 /* v1 ICDDCR */ 80239268Sgonzo#define GICD_TYPER 0x004 /* v1 ICDICTR */ 81239268Sgonzo#define GICD_IIDR 0x008 /* v1 ICDIIDR */ 82239268Sgonzo#define GICD_IGROUPR(n) (0x0080 + ((n) * 4)) /* v1 ICDISER */ 83239268Sgonzo#define GICD_ISENABLER(n) (0x0100 + ((n) * 4)) /* v1 ICDISER */ 84239268Sgonzo#define GICD_ICENABLER(n) (0x0180 + ((n) * 4)) /* v1 ICDICER */ 85239268Sgonzo#define GICD_ISPENDR(n) (0x0200 + ((n) * 4)) /* v1 ICDISPR */ 86239268Sgonzo#define GICD_ICPENDR(n) (0x0280 + ((n) * 4)) /* v1 ICDICPR */ 87239268Sgonzo#define GICD_ICACTIVER(n) (0x0380 + ((n) * 4)) /* v1 ICDABR */ 88239268Sgonzo#define GICD_IPRIORITYR(n) (0x0400 + ((n) * 4)) /* v1 ICDIPR */ 89239268Sgonzo#define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */ 90239268Sgonzo#define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */ 91239268Sgonzo#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */ 92297561Sandrew#define GICD_SGI_TARGET_SHIFT 16 93239268Sgonzo 94239268Sgonzo/* CPU Registers */ 95239268Sgonzo#define GICC_CTLR 0x0000 /* v1 ICCICR */ 96239268Sgonzo#define GICC_PMR 0x0004 /* v1 ICCPMR */ 97239268Sgonzo#define GICC_BPR 0x0008 /* v1 ICCBPR */ 98239268Sgonzo#define GICC_IAR 0x000C /* v1 ICCIAR */ 99239268Sgonzo#define GICC_EOIR 0x0010 /* v1 ICCEOIR */ 100239268Sgonzo#define GICC_RPR 0x0014 /* v1 ICCRPR */ 101239268Sgonzo#define GICC_HPPIR 0x0018 /* v1 ICCHPIR */ 102239268Sgonzo#define GICC_ABPR 0x001C /* v1 ICCABPR */ 103239268Sgonzo#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/ 104239268Sgonzo 105289529Sian#define GIC_FIRST_SGI 0 /* Irqs 0-15 are SGIs/IPIs. */ 106289529Sian#define GIC_LAST_SGI 15 107271630Sian#define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */ 108271630Sian#define GIC_LAST_PPI 31 /* core) peripheral interrupts. */ 109271630Sian#define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */ 110266621Sian 111300051Sbz/* TYPER Registers */ 112300051Sbz#define GICD_TYPER_SECURITYEXT 0x400 113300051Sbz#define GIC_SUPPORT_SECEXT(_sc) \ 114300051Sbz ((_sc->typer & GICD_TYPER_SECURITYEXT) == GICD_TYPER_SECURITYEXT) 115300051Sbz 116260161Szbb/* First bit is a polarity bit (0 - low, 1 - high) */ 117260161Szbb#define GICD_ICFGR_POL_LOW (0 << 0) 118260161Szbb#define GICD_ICFGR_POL_HIGH (1 << 0) 119260161Szbb#define GICD_ICFGR_POL_MASK 0x1 120260161Szbb/* Second bit is a trigger bit (0 - level, 1 - edge) */ 121260161Szbb#define GICD_ICFGR_TRIG_LVL (0 << 1) 122260161Szbb#define GICD_ICFGR_TRIG_EDGE (1 << 1) 123260161Szbb#define GICD_ICFGR_TRIG_MASK 0x2 124260161Szbb 125280905Sganbold#ifndef GIC_DEFAULT_ICFGR_INIT 126280905Sganbold#define GIC_DEFAULT_ICFGR_INIT 0x00000000 127280905Sganbold#endif 128280905Sganbold 129298068Sandrew#ifdef INTRNG 130297539Sskrastruct gic_irqsrc { 131297539Sskra struct intr_irqsrc gi_isrc; 132297539Sskra uint32_t gi_irq; 133297539Sskra enum intr_polarity gi_pol; 134297539Sskra enum intr_trigger gi_trig; 135298054Sandrew#define GI_FLAG_EARLY_EOI (1 << 0) 136299928Sandrew#define GI_FLAG_MSI (1 << 1) /* This interrupt source should only */ 137299928Sandrew /* be used for MSI/MSI-X interrupts */ 138299928Sandrew#define GI_FLAG_MSI_USED (1 << 2) /* This irq is already allocated */ 139299928Sandrew /* for a MSI/MSI-X interrupt */ 140298054Sandrew u_int gi_flags; 141297539Sskra}; 142297539Sskra 143289529Sianstatic u_int gic_irq_cpu; 144289529Sianstatic int arm_gic_intr(void *); 145297539Sskrastatic int arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc); 146297230Sskra 147297230Sskra#ifdef SMP 148298403Sandrewstatic u_int sgi_to_ipi[GIC_LAST_SGI - GIC_FIRST_SGI + 1]; 149298403Sandrewstatic u_int sgi_first_unused = GIC_FIRST_SGI; 150289529Sian#endif 151297230Sskra#endif 152289529Sian 153298068Sandrew#ifdef INTRNG 154298051Sandrewstruct arm_gic_range { 155298051Sandrew uint64_t bus; 156298051Sandrew uint64_t host; 157298051Sandrew uint64_t size; 158298051Sandrew}; 159298051Sandrew 160298051Sandrewstruct arm_gic_devinfo { 161298051Sandrew struct ofw_bus_devinfo obdinfo; 162298051Sandrew struct resource_list rl; 163298051Sandrew}; 164298051Sandrew#endif 165298051Sandrew 166239268Sgonzostruct arm_gic_softc { 167276028Sandrew device_t gic_dev; 168298068Sandrew#ifdef INTRNG 169289529Sian void * gic_intrhand; 170297539Sskra struct gic_irqsrc * gic_irqs; 171289529Sian#endif 172239268Sgonzo struct resource * gic_res[3]; 173239268Sgonzo bus_space_tag_t gic_c_bst; 174239268Sgonzo bus_space_tag_t gic_d_bst; 175239268Sgonzo bus_space_handle_t gic_c_bsh; 176239268Sgonzo bus_space_handle_t gic_d_bsh; 177239268Sgonzo uint8_t ver; 178260161Szbb struct mtx mutex; 179260161Szbb uint32_t nirqs; 180300051Sbz uint32_t typer; 181291424Smmel#ifdef GIC_DEBUG_SPURIOUS 182291424Smmel uint32_t last_irq[MAXCPU]; 183291424Smmel#endif 184298051Sandrew 185298068Sandrew#ifdef INTRNG 186298051Sandrew /* FDT child data */ 187298051Sandrew pcell_t addr_cells; 188298051Sandrew pcell_t size_cells; 189298051Sandrew int nranges; 190298051Sandrew struct arm_gic_range * ranges; 191298051Sandrew#endif 192239268Sgonzo}; 193239268Sgonzo 194298068Sandrew#ifdef INTRNG 195297539Sskra#define GIC_INTR_ISRC(sc, irq) (&sc->gic_irqs[irq].gi_isrc) 196297539Sskra#endif 197297539Sskra 198239268Sgonzostatic struct resource_spec arm_gic_spec[] = { 199239268Sgonzo { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ 200239268Sgonzo { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ 201298068Sandrew#ifdef INTRNG 202289529Sian { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ 203289529Sian#endif 204239268Sgonzo { -1, 0 } 205239268Sgonzo}; 206239268Sgonzo 207297561Sandrewstatic u_int arm_gic_map[MAXCPU]; 208297561Sandrew 209289529Sianstatic struct arm_gic_softc *gic_sc = NULL; 210239268Sgonzo 211276015Sandrew#define gic_c_read_4(_sc, _reg) \ 212276015Sandrew bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg)) 213276015Sandrew#define gic_c_write_4(_sc, _reg, _val) \ 214276015Sandrew bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val)) 215276015Sandrew#define gic_d_read_4(_sc, _reg) \ 216276015Sandrew bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg)) 217289529Sian#define gic_d_write_1(_sc, _reg, _val) \ 218289529Sian bus_space_write_1((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) 219276015Sandrew#define gic_d_write_4(_sc, _reg, _val) \ 220276015Sandrew bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) 221239268Sgonzo 222298068Sandrew#ifndef INTRNG 223260161Szbbstatic int gic_config_irq(int irq, enum intr_trigger trig, 224260161Szbb enum intr_polarity pol); 225239268Sgonzostatic void gic_post_filter(void *); 226289529Sian#endif 227239268Sgonzo 228271595Sianstatic struct ofw_compat_data compat_data[] = { 229271595Sian {"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */ 230271595Sian {"arm,gic-400", true}, 231271595Sian {"arm,cortex-a15-gic", true}, 232271595Sian {"arm,cortex-a9-gic", true}, 233271595Sian {"arm,cortex-a7-gic", true}, 234271595Sian {"arm,arm11mp-gic", true}, 235271595Sian {"brcm,brahma-b15-gic", true}, 236298051Sandrew {"qcom,msm-qgic2", true}, 237271595Sian {NULL, false} 238271595Sian}; 239271595Sian 240239268Sgonzostatic int 241239268Sgonzoarm_gic_probe(device_t dev) 242239268Sgonzo{ 243252370Sray 244261410Sian if (!ofw_bus_status_okay(dev)) 245261410Sian return (ENXIO); 246261410Sian 247271595Sian if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 248239268Sgonzo return (ENXIO); 249239268Sgonzo device_set_desc(dev, "ARM Generic Interrupt Controller"); 250239268Sgonzo return (BUS_PROBE_DEFAULT); 251239268Sgonzo} 252239268Sgonzo 253298068Sandrew#ifdef INTRNG 254289529Sianstatic inline void 255289529Siangic_irq_unmask(struct arm_gic_softc *sc, u_int irq) 256289529Sian{ 257289529Sian 258289529Sian gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F))); 259289529Sian} 260289529Sian 261289529Sianstatic inline void 262289529Siangic_irq_mask(struct arm_gic_softc *sc, u_int irq) 263289529Sian{ 264289529Sian 265289529Sian gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F))); 266289529Sian} 267289529Sian#endif 268289529Sian 269297561Sandrewstatic uint8_t 270297561Sandrewgic_cpu_mask(struct arm_gic_softc *sc) 271297561Sandrew{ 272297561Sandrew uint32_t mask; 273297561Sandrew int i; 274297561Sandrew 275297561Sandrew /* Read the current cpuid mask by reading ITARGETSR{0..7} */ 276297561Sandrew for (i = 0; i < 8; i++) { 277297561Sandrew mask = gic_d_read_4(sc, GICD_ITARGETSR(i)); 278297561Sandrew if (mask != 0) 279297561Sandrew break; 280297561Sandrew } 281297561Sandrew /* No mask found, assume we are on CPU interface 0 */ 282297561Sandrew if (mask == 0) 283297561Sandrew return (1); 284297561Sandrew 285297561Sandrew /* Collect the mask in the lower byte */ 286297561Sandrew mask |= mask >> 16; 287297561Sandrew mask |= mask >> 8; 288297561Sandrew 289297561Sandrew return (mask); 290297561Sandrew} 291297561Sandrew 292289529Sian#ifdef SMP 293298068Sandrew#ifdef INTRNG 294276963Sandrewstatic void 295276963Sandrewarm_gic_init_secondary(device_t dev) 296239268Sgonzo{ 297276963Sandrew struct arm_gic_softc *sc = device_get_softc(dev); 298297674Sskra u_int irq, cpu; 299289529Sian 300297561Sandrew /* Set the mask so we can find this CPU to send it IPIs */ 301297674Sskra cpu = PCPU_GET(cpuid); 302297674Sskra arm_gic_map[cpu] = gic_cpu_mask(sc); 303297561Sandrew 304289529Sian for (irq = 0; irq < sc->nirqs; irq += 4) 305289529Sian gic_d_write_4(sc, GICD_IPRIORITYR(irq >> 2), 0); 306289529Sian 307289529Sian /* Set all the interrupts to be in Group 0 (secure) */ 308300051Sbz for (irq = 0; GIC_SUPPORT_SECEXT(sc) && irq < sc->nirqs; irq += 32) { 309289529Sian gic_d_write_4(sc, GICD_IGROUPR(irq >> 5), 0); 310289529Sian } 311289529Sian 312289529Sian /* Enable CPU interface */ 313289529Sian gic_c_write_4(sc, GICC_CTLR, 1); 314289529Sian 315289529Sian /* Set priority mask register. */ 316289529Sian gic_c_write_4(sc, GICC_PMR, 0xff); 317289529Sian 318289529Sian /* Enable interrupt distribution */ 319289529Sian gic_d_write_4(sc, GICD_CTLR, 0x01); 320289529Sian 321289529Sian /* Unmask attached SGI interrupts. */ 322297674Sskra for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) 323297674Sskra if (intr_isrc_init_on_cpu(GIC_INTR_ISRC(sc, irq), cpu)) 324289529Sian gic_irq_unmask(sc, irq); 325289529Sian 326289529Sian /* Unmask attached PPI interrupts. */ 327297674Sskra for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) 328297674Sskra if (intr_isrc_init_on_cpu(GIC_INTR_ISRC(sc, irq), cpu)) 329289529Sian gic_irq_unmask(sc, irq); 330289529Sian} 331289529Sian#else 332289529Sianstatic void 333289529Sianarm_gic_init_secondary(device_t dev) 334289529Sian{ 335289529Sian struct arm_gic_softc *sc = device_get_softc(dev); 336276028Sandrew int i; 337252370Sray 338297561Sandrew /* Set the mask so we can find this CPU to send it IPIs */ 339297561Sandrew arm_gic_map[PCPU_GET(cpuid)] = gic_cpu_mask(sc); 340297561Sandrew 341276028Sandrew for (i = 0; i < sc->nirqs; i += 4) 342276015Sandrew gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); 343252370Sray 344252370Sray /* Set all the interrupts to be in Group 0 (secure) */ 345300051Sbz for (i = 0; GIC_SUPPORT_SECEXT(sc) && i < sc->nirqs; i += 32) { 346276015Sandrew gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); 347252370Sray } 348252370Sray 349239268Sgonzo /* Enable CPU interface */ 350276015Sandrew gic_c_write_4(sc, GICC_CTLR, 1); 351239268Sgonzo 352249762Sdmarion /* Set priority mask register. */ 353276015Sandrew gic_c_write_4(sc, GICC_PMR, 0xff); 354249762Sdmarion 355239268Sgonzo /* Enable interrupt distribution */ 356276015Sandrew gic_d_write_4(sc, GICD_CTLR, 0x01); 357252370Sray 358271181Sandrew /* 359271181Sandrew * Activate the timer interrupts: virtual, secure, and non-secure. 360271181Sandrew */ 361276015Sandrew gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F))); 362276015Sandrew gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F))); 363276015Sandrew gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F))); 364239268Sgonzo} 365298068Sandrew#endif /* INTRNG */ 366289529Sian#endif /* SMP */ 367291424Smmel 368298068Sandrew#ifndef INTRNG 369271601Sianint 370289548Siangic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt, 371271601Sian int *trig, int *pol) 372271601Sian{ 373271601Sian static u_int num_intr_cells; 374289548Sian static phandle_t self; 375289548Sian struct ofw_compat_data *ocd; 376271601Sian 377289548Sian if (self == 0) { 378289548Sian for (ocd = compat_data; ocd->ocd_str != NULL; ocd++) { 379289548Sian if (fdt_is_compatible(iparent, ocd->ocd_str)) { 380289548Sian self = iparent; 381289548Sian break; 382289548Sian } 383289548Sian } 384289548Sian } 385289548Sian if (self != iparent) 386289548Sian return (ENXIO); 387289548Sian 388271601Sian if (num_intr_cells == 0) { 389283366Sandrew if (OF_searchencprop(OF_node_from_xref(iparent), 390283366Sandrew "#interrupt-cells", &num_intr_cells, 391271601Sian sizeof(num_intr_cells)) == -1) { 392271601Sian num_intr_cells = 1; 393271601Sian } 394271601Sian } 395271601Sian 396271601Sian if (num_intr_cells == 1) { 397271601Sian *interrupt = fdt32_to_cpu(intr[0]); 398271601Sian *trig = INTR_TRIGGER_CONFORM; 399271601Sian *pol = INTR_POLARITY_CONFORM; 400271601Sian } else { 401279235Szbb if (fdt32_to_cpu(intr[0]) == 0) 402271630Sian *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_SPI; 403271601Sian else 404271630Sian *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_PPI; 405271601Sian /* 406271601Sian * In intr[2], bits[3:0] are trigger type and level flags. 407271601Sian * 1 = low-to-high edge triggered 408271601Sian * 2 = high-to-low edge triggered 409271601Sian * 4 = active high level-sensitive 410271601Sian * 8 = active low level-sensitive 411294422Szbb * The hardware only supports active-high-level or rising-edge 412294422Szbb * for SPIs 413271601Sian */ 414294422Szbb if (*interrupt >= GIC_FIRST_SPI && 415294422Szbb fdt32_to_cpu(intr[2]) & 0x0a) { 416271601Sian printf("unsupported trigger/polarity configuration " 417291424Smmel "0x%02x\n", fdt32_to_cpu(intr[2]) & 0x0f); 418271601Sian } 419271601Sian *pol = INTR_POLARITY_CONFORM; 420291424Smmel if (fdt32_to_cpu(intr[2]) & 0x03) 421271601Sian *trig = INTR_TRIGGER_EDGE; 422271601Sian else 423271601Sian *trig = INTR_TRIGGER_LEVEL; 424271601Sian } 425271601Sian return (0); 426271601Sian} 427289529Sian#endif 428271601Sian 429298068Sandrew#ifdef INTRNG 430289529Sianstatic inline intptr_t 431289529Siangic_xref(device_t dev) 432289529Sian{ 433289529Sian#ifdef FDT 434289529Sian return (OF_xref_from_node(ofw_bus_get_node(dev))); 435289529Sian#else 436289529Sian return (0); 437289529Sian#endif 438289529Sian} 439297539Sskra 440297539Sskrastatic int 441297539Sskraarm_gic_register_isrcs(struct arm_gic_softc *sc, uint32_t num) 442297539Sskra{ 443297539Sskra int error; 444297539Sskra uint32_t irq; 445297539Sskra struct gic_irqsrc *irqs; 446297539Sskra struct intr_irqsrc *isrc; 447297539Sskra const char *name; 448297539Sskra 449297539Sskra irqs = malloc(num * sizeof(struct gic_irqsrc), M_DEVBUF, 450297539Sskra M_WAITOK | M_ZERO); 451297539Sskra 452297539Sskra name = device_get_nameunit(sc->gic_dev); 453297539Sskra for (irq = 0; irq < num; irq++) { 454297539Sskra irqs[irq].gi_irq = irq; 455297539Sskra irqs[irq].gi_pol = INTR_POLARITY_CONFORM; 456297539Sskra irqs[irq].gi_trig = INTR_TRIGGER_CONFORM; 457297539Sskra 458297539Sskra isrc = &irqs[irq].gi_isrc; 459297539Sskra if (irq <= GIC_LAST_SGI) { 460297539Sskra error = intr_isrc_register(isrc, sc->gic_dev, 461297539Sskra INTR_ISRCF_IPI, "%s,i%u", name, irq - GIC_FIRST_SGI); 462297539Sskra } else if (irq <= GIC_LAST_PPI) { 463297539Sskra error = intr_isrc_register(isrc, sc->gic_dev, 464297539Sskra INTR_ISRCF_PPI, "%s,p%u", name, irq - GIC_FIRST_PPI); 465297539Sskra } else { 466297539Sskra error = intr_isrc_register(isrc, sc->gic_dev, 0, 467297539Sskra "%s,s%u", name, irq - GIC_FIRST_SPI); 468297539Sskra } 469297539Sskra if (error != 0) { 470297539Sskra /* XXX call intr_isrc_deregister() */ 471297539Sskra free(irqs, M_DEVBUF); 472297539Sskra return (error); 473297539Sskra } 474297539Sskra } 475297539Sskra sc->gic_irqs = irqs; 476297539Sskra sc->nirqs = num; 477297539Sskra return (0); 478297539Sskra} 479298051Sandrew 480298051Sandrewstatic int 481298051Sandrewarm_gic_fill_ranges(phandle_t node, struct arm_gic_softc *sc) 482298051Sandrew{ 483298051Sandrew pcell_t host_cells; 484298051Sandrew cell_t *base_ranges; 485298051Sandrew ssize_t nbase_ranges; 486298051Sandrew int i, j, k; 487298051Sandrew 488298051Sandrew host_cells = 1; 489298051Sandrew OF_getencprop(OF_parent(node), "#address-cells", &host_cells, 490298051Sandrew sizeof(host_cells)); 491298051Sandrew sc->addr_cells = 2; 492298051Sandrew OF_getencprop(node, "#address-cells", &sc->addr_cells, 493298051Sandrew sizeof(sc->addr_cells)); 494298051Sandrew sc->size_cells = 2; 495298051Sandrew OF_getencprop(node, "#size-cells", &sc->size_cells, 496298051Sandrew sizeof(sc->size_cells)); 497298051Sandrew 498298051Sandrew nbase_ranges = OF_getproplen(node, "ranges"); 499298051Sandrew if (nbase_ranges < 0) 500298051Sandrew return (-1); 501298051Sandrew sc->nranges = nbase_ranges / sizeof(cell_t) / 502298051Sandrew (sc->addr_cells + host_cells + sc->size_cells); 503298051Sandrew if (sc->nranges == 0) 504298051Sandrew return (0); 505298051Sandrew 506298051Sandrew sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), 507298051Sandrew M_DEVBUF, M_WAITOK); 508298051Sandrew base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); 509298051Sandrew OF_getencprop(node, "ranges", base_ranges, nbase_ranges); 510298051Sandrew 511298051Sandrew for (i = 0, j = 0; i < sc->nranges; i++) { 512298051Sandrew sc->ranges[i].bus = 0; 513298051Sandrew for (k = 0; k < sc->addr_cells; k++) { 514298051Sandrew sc->ranges[i].bus <<= 32; 515298051Sandrew sc->ranges[i].bus |= base_ranges[j++]; 516298051Sandrew } 517298051Sandrew sc->ranges[i].host = 0; 518298051Sandrew for (k = 0; k < host_cells; k++) { 519298051Sandrew sc->ranges[i].host <<= 32; 520298051Sandrew sc->ranges[i].host |= base_ranges[j++]; 521298051Sandrew } 522298051Sandrew sc->ranges[i].size = 0; 523298051Sandrew for (k = 0; k < sc->size_cells; k++) { 524298051Sandrew sc->ranges[i].size <<= 32; 525298051Sandrew sc->ranges[i].size |= base_ranges[j++]; 526298051Sandrew } 527298051Sandrew } 528298051Sandrew 529298051Sandrew free(base_ranges, M_DEVBUF); 530298051Sandrew return (sc->nranges); 531298051Sandrew} 532298051Sandrew 533298051Sandrewstatic bool 534298051Sandrewarm_gic_add_children(device_t dev) 535298051Sandrew{ 536298051Sandrew struct arm_gic_softc *sc; 537298051Sandrew struct arm_gic_devinfo *dinfo; 538298051Sandrew phandle_t child, node; 539298051Sandrew device_t cdev; 540298051Sandrew 541298051Sandrew sc = device_get_softc(dev); 542298051Sandrew node = ofw_bus_get_node(dev); 543298051Sandrew 544298051Sandrew /* If we have no children don't probe for them */ 545298051Sandrew child = OF_child(node); 546298051Sandrew if (child == 0) 547298051Sandrew return (false); 548298051Sandrew 549298051Sandrew if (arm_gic_fill_ranges(node, sc) < 0) { 550298051Sandrew device_printf(dev, "Have a child, but no ranges\n"); 551298051Sandrew return (false); 552298051Sandrew } 553298051Sandrew 554298051Sandrew for (; child != 0; child = OF_peer(child)) { 555298051Sandrew dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); 556298051Sandrew 557298051Sandrew if (ofw_bus_gen_setup_devinfo(&dinfo->obdinfo, child) != 0) { 558298051Sandrew free(dinfo, M_DEVBUF); 559298051Sandrew continue; 560298051Sandrew } 561298051Sandrew 562298051Sandrew resource_list_init(&dinfo->rl); 563298051Sandrew ofw_bus_reg_to_rl(dev, child, sc->addr_cells, 564298051Sandrew sc->size_cells, &dinfo->rl); 565298051Sandrew 566298051Sandrew cdev = device_add_child(dev, NULL, -1); 567298051Sandrew if (cdev == NULL) { 568298051Sandrew device_printf(dev, "<%s>: device_add_child failed\n", 569298051Sandrew dinfo->obdinfo.obd_name); 570298051Sandrew resource_list_free(&dinfo->rl); 571298051Sandrew ofw_bus_gen_destroy_devinfo(&dinfo->obdinfo); 572298051Sandrew free(dinfo, M_DEVBUF); 573298051Sandrew continue; 574298051Sandrew } 575298051Sandrew device_set_ivars(cdev, dinfo); 576298051Sandrew } 577298051Sandrew 578298051Sandrew return (true); 579298051Sandrew} 580299928Sandrew 581299928Sandrewstatic void 582299928Sandrewarm_gic_reserve_msi_range(device_t dev, u_int start, u_int count) 583299928Sandrew{ 584299928Sandrew struct arm_gic_softc *sc; 585299928Sandrew int i; 586299928Sandrew 587299928Sandrew sc = device_get_softc(dev); 588299928Sandrew 589299928Sandrew KASSERT((start + count) < sc->nirqs, 590299928Sandrew ("%s: Trying to allocate too many MSI IRQs: %d + %d > %d", __func__, 591299928Sandrew start, count, sc->nirqs)); 592299928Sandrew for (i = 0; i < count; i++) { 593299928Sandrew KASSERT(sc->gic_irqs[start + i].gi_isrc.isrc_handlers == 0, 594299928Sandrew ("%s: MSI interrupt %d already has a handler", __func__, 595299928Sandrew count + i)); 596299928Sandrew KASSERT(sc->gic_irqs[start + i].gi_pol == INTR_POLARITY_CONFORM, 597299928Sandrew ("%s: MSI interrupt %d already has a polarity", __func__, 598299928Sandrew count + i)); 599299928Sandrew KASSERT(sc->gic_irqs[start + i].gi_trig == INTR_TRIGGER_CONFORM, 600299928Sandrew ("%s: MSI interrupt %d already has a trigger", __func__, 601299928Sandrew count + i)); 602299928Sandrew sc->gic_irqs[start + i].gi_pol = INTR_POLARITY_HIGH; 603299928Sandrew sc->gic_irqs[start + i].gi_trig = INTR_TRIGGER_EDGE; 604299928Sandrew sc->gic_irqs[start + i].gi_flags |= GI_FLAG_MSI; 605299928Sandrew } 606299928Sandrew} 607289529Sian#endif 608289529Sian 609239268Sgonzostatic int 610239268Sgonzoarm_gic_attach(device_t dev) 611239268Sgonzo{ 612252370Sray struct arm_gic_softc *sc; 613239268Sgonzo int i; 614297539Sskra uint32_t icciidr, mask, nirqs; 615298068Sandrew#ifdef INTRNG 616291424Smmel phandle_t pxref; 617289529Sian intptr_t xref = gic_xref(dev); 618289529Sian#endif 619239268Sgonzo 620289529Sian if (gic_sc) 621239268Sgonzo return (ENXIO); 622239268Sgonzo 623252370Sray sc = device_get_softc(dev); 624252370Sray 625239268Sgonzo if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) { 626239268Sgonzo device_printf(dev, "could not allocate resources\n"); 627239268Sgonzo return (ENXIO); 628239268Sgonzo } 629239268Sgonzo 630276028Sandrew sc->gic_dev = dev; 631289529Sian gic_sc = sc; 632276028Sandrew 633260161Szbb /* Initialize mutex */ 634260161Szbb mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN); 635239268Sgonzo 636239268Sgonzo /* Distributor Interface */ 637239268Sgonzo sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]); 638239268Sgonzo sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]); 639239268Sgonzo 640239268Sgonzo /* CPU Interface */ 641239268Sgonzo sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); 642239268Sgonzo sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]); 643239268Sgonzo 644239268Sgonzo /* Disable interrupt forwarding to the CPU interface */ 645276015Sandrew gic_d_write_4(sc, GICD_CTLR, 0x00); 646239268Sgonzo 647239268Sgonzo /* Get the number of interrupts */ 648300051Sbz sc->typer = gic_d_read_4(sc, GICD_TYPER); 649300051Sbz nirqs = 32 * ((sc->typer & 0x1f) + 1); 650239268Sgonzo 651298068Sandrew#ifdef INTRNG 652297539Sskra if (arm_gic_register_isrcs(sc, nirqs)) { 653297539Sskra device_printf(dev, "could not register irqs\n"); 654297539Sskra goto cleanup; 655297539Sskra } 656289529Sian#else 657297539Sskra sc->nirqs = nirqs; 658297539Sskra 659260161Szbb /* Set up function pointers */ 660260161Szbb arm_post_filter = gic_post_filter; 661260161Szbb arm_config_irq = gic_config_irq; 662289529Sian#endif 663260161Szbb 664276015Sandrew icciidr = gic_c_read_4(sc, GICC_IIDR); 665274484Szbb device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n", 666239268Sgonzo icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf, 667260161Szbb (icciidr & 0xfff), sc->nirqs); 668239268Sgonzo 669239268Sgonzo /* Set all global interrupts to be level triggered, active low. */ 670260161Szbb for (i = 32; i < sc->nirqs; i += 16) { 671280905Sganbold gic_d_write_4(sc, GICD_ICFGR(i >> 4), GIC_DEFAULT_ICFGR_INIT); 672239268Sgonzo } 673239268Sgonzo 674239268Sgonzo /* Disable all interrupts. */ 675260161Szbb for (i = 32; i < sc->nirqs; i += 32) { 676276015Sandrew gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF); 677239268Sgonzo } 678239268Sgonzo 679297561Sandrew /* Find the current cpu mask */ 680297561Sandrew mask = gic_cpu_mask(sc); 681297561Sandrew /* Set the mask so we can find this CPU to send it IPIs */ 682297561Sandrew arm_gic_map[PCPU_GET(cpuid)] = mask; 683297561Sandrew /* Set all four targets to this cpu */ 684297390Sandrew mask |= mask << 8; 685297390Sandrew mask |= mask << 16; 686297390Sandrew 687260161Szbb for (i = 0; i < sc->nirqs; i += 4) { 688276015Sandrew gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); 689297390Sandrew if (i > 32) { 690297390Sandrew gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), mask); 691297390Sandrew } 692239268Sgonzo } 693239268Sgonzo 694252370Sray /* Set all the interrupts to be in Group 0 (secure) */ 695300051Sbz for (i = 0; GIC_SUPPORT_SECEXT(sc) && i < sc->nirqs; i += 32) { 696276015Sandrew gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); 697252370Sray } 698252370Sray 699239268Sgonzo /* Enable CPU interface */ 700276015Sandrew gic_c_write_4(sc, GICC_CTLR, 1); 701239268Sgonzo 702249762Sdmarion /* Set priority mask register. */ 703276015Sandrew gic_c_write_4(sc, GICC_PMR, 0xff); 704249762Sdmarion 705239268Sgonzo /* Enable interrupt distribution */ 706276015Sandrew gic_d_write_4(sc, GICD_CTLR, 0x01); 707298068Sandrew#ifndef INTRNG 708289529Sian return (0); 709289529Sian#else 710289529Sian /* 711289529Sian * Now, when everything is initialized, it's right time to 712289529Sian * register interrupt controller to interrupt framefork. 713289529Sian */ 714300149Sandrew if (intr_pic_register(dev, xref) == NULL) { 715289529Sian device_printf(dev, "could not register PIC\n"); 716289529Sian goto cleanup; 717289529Sian } 718239268Sgonzo 719291649Smmel /* 720291649Smmel * Controller is root if: 721291649Smmel * - doesn't have interrupt parent 722291649Smmel * - his interrupt parent is this controller 723291649Smmel */ 724291649Smmel pxref = ofw_bus_find_iparent(ofw_bus_get_node(dev)); 725291649Smmel if (pxref == 0 || xref == pxref) { 726292426Sadrian if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, 727289529Sian GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { 728289529Sian device_printf(dev, "could not set PIC as a root\n"); 729297539Sskra intr_pic_deregister(dev, xref); 730289529Sian goto cleanup; 731289529Sian } 732289529Sian } else { 733291649Smmel if (sc->gic_res[2] == NULL) { 734291649Smmel device_printf(dev, 735291649Smmel "not root PIC must have defined interrupt\n"); 736297539Sskra intr_pic_deregister(dev, xref); 737291649Smmel goto cleanup; 738291649Smmel } 739289529Sian if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK, 740289529Sian arm_gic_intr, NULL, sc, &sc->gic_intrhand)) { 741289529Sian device_printf(dev, "could not setup irq handler\n"); 742297539Sskra intr_pic_deregister(dev, xref); 743289529Sian goto cleanup; 744289529Sian } 745289529Sian } 746289529Sian 747291424Smmel OF_device_register_xref(xref, dev); 748298051Sandrew 749298051Sandrew /* If we have children probe and attach them */ 750298051Sandrew if (arm_gic_add_children(dev)) { 751298051Sandrew bus_generic_probe(dev); 752298051Sandrew return (bus_generic_attach(dev)); 753298051Sandrew } 754298051Sandrew 755239268Sgonzo return (0); 756289529Sian 757289529Siancleanup: 758289529Sian /* 759289529Sian * XXX - not implemented arm_gic_detach() should be called ! 760289529Sian */ 761289529Sian if (sc->gic_irqs != NULL) 762289529Sian free(sc->gic_irqs, M_DEVBUF); 763289529Sian bus_release_resources(dev, arm_gic_spec, sc->gic_res); 764289529Sian return(ENXIO); 765289529Sian#endif 766239268Sgonzo} 767239268Sgonzo 768298068Sandrew#ifdef INTRNG 769298051Sandrewstatic struct resource * 770298051Sandrewarm_gic_alloc_resource(device_t bus, device_t child, int type, int *rid, 771298051Sandrew rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 772298051Sandrew{ 773298051Sandrew struct arm_gic_softc *sc; 774298051Sandrew struct arm_gic_devinfo *di; 775298051Sandrew struct resource_list_entry *rle; 776298051Sandrew int j; 777298051Sandrew 778298051Sandrew KASSERT(type == SYS_RES_MEMORY, ("Invalid resoure type %x", type)); 779298051Sandrew 780298051Sandrew sc = device_get_softc(bus); 781298051Sandrew 782298051Sandrew /* 783298051Sandrew * Request for the default allocation with a given rid: use resource 784298051Sandrew * list stored in the local device info. 785298051Sandrew */ 786298051Sandrew if (RMAN_IS_DEFAULT_RANGE(start, end)) { 787298051Sandrew if ((di = device_get_ivars(child)) == NULL) 788298051Sandrew return (NULL); 789298051Sandrew 790298051Sandrew if (type == SYS_RES_IOPORT) 791298051Sandrew type = SYS_RES_MEMORY; 792298051Sandrew 793298051Sandrew rle = resource_list_find(&di->rl, type, *rid); 794298051Sandrew if (rle == NULL) { 795298051Sandrew if (bootverbose) 796298051Sandrew device_printf(bus, "no default resources for " 797298051Sandrew "rid = %d, type = %d\n", *rid, type); 798298051Sandrew return (NULL); 799298051Sandrew } 800298051Sandrew start = rle->start; 801298051Sandrew end = rle->end; 802298051Sandrew count = rle->count; 803298051Sandrew } 804298051Sandrew 805298051Sandrew /* Remap through ranges property */ 806298051Sandrew for (j = 0; j < sc->nranges; j++) { 807298051Sandrew if (start >= sc->ranges[j].bus && end < 808298051Sandrew sc->ranges[j].bus + sc->ranges[j].size) { 809298051Sandrew start -= sc->ranges[j].bus; 810298051Sandrew start += sc->ranges[j].host; 811298051Sandrew end -= sc->ranges[j].bus; 812298051Sandrew end += sc->ranges[j].host; 813298051Sandrew break; 814298051Sandrew } 815298051Sandrew } 816298051Sandrew if (j == sc->nranges && sc->nranges != 0) { 817298051Sandrew if (bootverbose) 818298051Sandrew device_printf(bus, "Could not map resource " 819298051Sandrew "%#jx-%#jx\n", (uintmax_t)start, (uintmax_t)end); 820298051Sandrew 821298051Sandrew return (NULL); 822298051Sandrew } 823298051Sandrew 824298051Sandrew return (bus_generic_alloc_resource(bus, child, type, rid, start, end, 825298051Sandrew count, flags)); 826298051Sandrew} 827298051Sandrew 828298051Sandrewstatic const struct ofw_bus_devinfo * 829298051Sandrewarm_gic_ofw_get_devinfo(device_t bus __unused, device_t child) 830298051Sandrew{ 831298051Sandrew struct arm_gic_devinfo *di; 832298051Sandrew 833298051Sandrew di = device_get_ivars(child); 834298051Sandrew 835298051Sandrew return (&di->obdinfo); 836298051Sandrew} 837298051Sandrew 838276963Sandrewstatic int 839289529Sianarm_gic_intr(void *arg) 840289529Sian{ 841289529Sian struct arm_gic_softc *sc = arg; 842297539Sskra struct gic_irqsrc *gi; 843289529Sian uint32_t irq_active_reg, irq; 844289529Sian struct trapframe *tf; 845289529Sian 846289529Sian irq_active_reg = gic_c_read_4(sc, GICC_IAR); 847289529Sian irq = irq_active_reg & 0x3FF; 848289529Sian 849289529Sian /* 850289529Sian * 1. We do EOI here because recent read value from active interrupt 851289529Sian * register must be used for it. Another approach is to save this 852289529Sian * value into associated interrupt source. 853289529Sian * 2. EOI must be done on same CPU where interrupt has fired. Thus 854289529Sian * we must ensure that interrupted thread does not migrate to 855289529Sian * another CPU. 856289529Sian * 3. EOI cannot be delayed by any preemption which could happen on 857289529Sian * critical_exit() used in MI intr code, when interrupt thread is 858289529Sian * scheduled. See next point. 859289529Sian * 4. IPI_RENDEZVOUS assumes that no preemption is permitted during 860289529Sian * an action and any use of critical_exit() could break this 861289529Sian * assumption. See comments within smp_rendezvous_action(). 862289529Sian * 5. We always return FILTER_HANDLED as this is an interrupt 863289529Sian * controller dispatch function. Otherwise, in cascaded interrupt 864289529Sian * case, the whole interrupt subtree would be masked. 865289529Sian */ 866289529Sian 867289529Sian if (irq >= sc->nirqs) { 868291424Smmel#ifdef GIC_DEBUG_SPURIOUS 869291424Smmel device_printf(sc->gic_dev, 870291424Smmel "Spurious interrupt detected: last irq: %d on CPU%d\n", 871291424Smmel sc->last_irq[PCPU_GET(cpuid)], PCPU_GET(cpuid)); 872291424Smmel#endif 873289529Sian return (FILTER_HANDLED); 874289529Sian } 875289529Sian 876289529Sian tf = curthread->td_intr_frame; 877289529Siandispatch_irq: 878297539Sskra gi = sc->gic_irqs + irq; 879289529Sian /* 880289529Sian * Note that GIC_FIRST_SGI is zero and is not used in 'if' statement 881289529Sian * as compiler complains that comparing u_int >= 0 is always true. 882289529Sian */ 883289529Sian if (irq <= GIC_LAST_SGI) { 884289529Sian#ifdef SMP 885289529Sian /* Call EOI for all IPI before dispatch. */ 886289529Sian gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 887297539Sskra intr_ipi_dispatch(sgi_to_ipi[gi->gi_irq], tf); 888289529Sian goto next_irq; 889289529Sian#else 890291424Smmel device_printf(sc->gic_dev, "SGI %u on UP system detected\n", 891291424Smmel irq - GIC_FIRST_SGI); 892289529Sian gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 893289529Sian goto next_irq; 894289529Sian#endif 895289529Sian } 896289529Sian 897291424Smmel#ifdef GIC_DEBUG_SPURIOUS 898291424Smmel sc->last_irq[PCPU_GET(cpuid)] = irq; 899291424Smmel#endif 900298054Sandrew if ((gi->gi_flags & GI_FLAG_EARLY_EOI) == GI_FLAG_EARLY_EOI) 901289529Sian gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 902289529Sian 903297539Sskra if (intr_isrc_dispatch(&gi->gi_isrc, tf) != 0) { 904297539Sskra gic_irq_mask(sc, irq); 905298054Sandrew if ((gi->gi_flags & GI_FLAG_EARLY_EOI) != GI_FLAG_EARLY_EOI) 906297539Sskra gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 907297539Sskra device_printf(sc->gic_dev, "Stray irq %u disabled\n", irq); 908297539Sskra } 909289529Sian 910289529Siannext_irq: 911289631Sian arm_irq_memory_barrier(irq); 912289631Sian irq_active_reg = gic_c_read_4(sc, GICC_IAR); 913289631Sian irq = irq_active_reg & 0x3FF; 914289631Sian if (irq < sc->nirqs) 915289529Sian goto dispatch_irq; 916289529Sian 917289529Sian return (FILTER_HANDLED); 918289529Sian} 919289529Sian 920289529Sianstatic void 921289529Siangic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig, 922289529Sian enum intr_polarity pol) 923289529Sian{ 924289529Sian uint32_t reg; 925289529Sian uint32_t mask; 926289529Sian 927289529Sian if (irq < GIC_FIRST_SPI) 928289529Sian return; 929289529Sian 930289529Sian mtx_lock_spin(&sc->mutex); 931289529Sian 932289529Sian reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4)); 933289529Sian mask = (reg >> 2*(irq % 16)) & 0x3; 934289529Sian 935289529Sian if (pol == INTR_POLARITY_LOW) { 936289529Sian mask &= ~GICD_ICFGR_POL_MASK; 937289529Sian mask |= GICD_ICFGR_POL_LOW; 938289529Sian } else if (pol == INTR_POLARITY_HIGH) { 939289529Sian mask &= ~GICD_ICFGR_POL_MASK; 940289529Sian mask |= GICD_ICFGR_POL_HIGH; 941289529Sian } 942289529Sian 943289529Sian if (trig == INTR_TRIGGER_LEVEL) { 944289529Sian mask &= ~GICD_ICFGR_TRIG_MASK; 945289529Sian mask |= GICD_ICFGR_TRIG_LVL; 946289529Sian } else if (trig == INTR_TRIGGER_EDGE) { 947289529Sian mask &= ~GICD_ICFGR_TRIG_MASK; 948289529Sian mask |= GICD_ICFGR_TRIG_EDGE; 949289529Sian } 950289529Sian 951289529Sian /* Set mask */ 952289529Sian reg = reg & ~(0x3 << 2*(irq % 16)); 953289529Sian reg = reg | (mask << 2*(irq % 16)); 954289529Sian gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg); 955289529Sian 956289529Sian mtx_unlock_spin(&sc->mutex); 957289529Sian} 958289529Sian 959289529Sianstatic int 960289529Siangic_bind(struct arm_gic_softc *sc, u_int irq, cpuset_t *cpus) 961289529Sian{ 962289529Sian uint32_t cpu, end, mask; 963289529Sian 964289529Sian end = min(mp_ncpus, 8); 965289529Sian for (cpu = end; cpu < MAXCPU; cpu++) 966289529Sian if (CPU_ISSET(cpu, cpus)) 967289529Sian return (EINVAL); 968289529Sian 969289529Sian for (mask = 0, cpu = 0; cpu < end; cpu++) 970289529Sian if (CPU_ISSET(cpu, cpus)) 971301062Sandrew mask |= arm_gic_map[cpu]; 972289529Sian 973289529Sian gic_d_write_1(sc, GICD_ITARGETSR(0) + irq, mask); 974289529Sian return (0); 975289529Sian} 976289529Sian 977297539Sskra#ifdef FDT 978289529Sianstatic int 979297539Sskragic_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp, 980297539Sskra enum intr_polarity *polp, enum intr_trigger *trigp) 981289529Sian{ 982289529Sian 983297539Sskra if (ncells == 1) { 984297539Sskra *irqp = cells[0]; 985297539Sskra *polp = INTR_POLARITY_CONFORM; 986297539Sskra *trigp = INTR_TRIGGER_CONFORM; 987297539Sskra return (0); 988297539Sskra } 989297539Sskra if (ncells == 3) { 990297539Sskra u_int irq, tripol; 991289529Sian 992297539Sskra /* 993297539Sskra * The 1st cell is the interrupt type: 994297539Sskra * 0 = SPI 995297539Sskra * 1 = PPI 996297539Sskra * The 2nd cell contains the interrupt number: 997297539Sskra * [0 - 987] for SPI 998297539Sskra * [0 - 15] for PPI 999297539Sskra * The 3rd cell is the flags, encoded as follows: 1000297539Sskra * bits[3:0] trigger type and level flags 1001297539Sskra * 1 = low-to-high edge triggered 1002297539Sskra * 2 = high-to-low edge triggered 1003297539Sskra * 4 = active high level-sensitive 1004297539Sskra * 8 = active low level-sensitive 1005297539Sskra * bits[15:8] PPI interrupt cpu mask 1006297539Sskra * Each bit corresponds to each of the 8 possible cpus 1007297539Sskra * attached to the GIC. A bit set to '1' indicated 1008297539Sskra * the interrupt is wired to that CPU. 1009297539Sskra */ 1010297539Sskra switch (cells[0]) { 1011297539Sskra case 0: 1012297539Sskra irq = GIC_FIRST_SPI + cells[1]; 1013297539Sskra /* SPI irq is checked later. */ 1014297539Sskra break; 1015297539Sskra case 1: 1016297539Sskra irq = GIC_FIRST_PPI + cells[1]; 1017297539Sskra if (irq > GIC_LAST_PPI) { 1018297539Sskra device_printf(dev, "unsupported PPI interrupt " 1019297539Sskra "number %u\n", cells[1]); 1020297539Sskra return (EINVAL); 1021297539Sskra } 1022297539Sskra break; 1023297539Sskra default: 1024297539Sskra device_printf(dev, "unsupported interrupt type " 1025297539Sskra "configuration %u\n", cells[0]); 1026297539Sskra return (EINVAL); 1027297539Sskra } 1028289529Sian 1029297539Sskra tripol = cells[2] & 0xff; 1030297539Sskra if (tripol & 0xf0 || (tripol & 0x0a && cells[0] == 0)) 1031297539Sskra device_printf(dev, "unsupported trigger/polarity " 1032297539Sskra "configuration 0x%02x\n", tripol); 1033289529Sian 1034297539Sskra *irqp = irq; 1035297539Sskra *polp = INTR_POLARITY_CONFORM; 1036297539Sskra *trigp = tripol & 0x03 ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL; 1037297539Sskra return (0); 1038289529Sian } 1039297539Sskra return (EINVAL); 1040289529Sian} 1041297539Sskra#endif 1042289529Sian 1043289529Sianstatic int 1044297539Sskragic_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp, 1045297539Sskra enum intr_polarity *polp, enum intr_trigger *trigp) 1046289529Sian{ 1047297539Sskra u_int irq; 1048297539Sskra enum intr_polarity pol; 1049297539Sskra enum intr_trigger trig; 1050297539Sskra struct arm_gic_softc *sc; 1051299117Sskra#ifdef FDT 1052299117Sskra struct intr_map_data_fdt *daf; 1053299117Sskra#endif 1054289529Sian 1055297539Sskra sc = device_get_softc(dev); 1056297539Sskra switch (data->type) { 1057289529Sian#ifdef FDT 1058297539Sskra case INTR_MAP_DATA_FDT: 1059299117Sskra daf = (struct intr_map_data_fdt *)data; 1060299117Sskra if (gic_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol, 1061299117Sskra &trig) != 0) 1062297539Sskra return (EINVAL); 1063299928Sandrew KASSERT(irq >= sc->nirqs || 1064299928Sandrew (sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) == 0, 1065299928Sandrew ("%s: Attempting to map a MSI interrupt from FDT", 1066299928Sandrew __func__)); 1067297539Sskra break; 1068297539Sskra#endif 1069297539Sskra default: 1070299117Sskra return (ENOTSUP); 1071297539Sskra } 1072289529Sian 1073289529Sian if (irq >= sc->nirqs) 1074289529Sian return (EINVAL); 1075297539Sskra if (pol != INTR_POLARITY_CONFORM && pol != INTR_POLARITY_LOW && 1076297539Sskra pol != INTR_POLARITY_HIGH) 1077297539Sskra return (EINVAL); 1078297539Sskra if (trig != INTR_TRIGGER_CONFORM && trig != INTR_TRIGGER_EDGE && 1079297539Sskra trig != INTR_TRIGGER_LEVEL) 1080297539Sskra return (EINVAL); 1081289529Sian 1082289529Sian *irqp = irq; 1083297539Sskra if (polp != NULL) 1084297539Sskra *polp = pol; 1085297539Sskra if (trigp != NULL) 1086297539Sskra *trigp = trig; 1087289529Sian return (0); 1088289529Sian} 1089289529Sian 1090289529Sianstatic int 1091297539Sskraarm_gic_map_intr(device_t dev, struct intr_map_data *data, 1092297539Sskra struct intr_irqsrc **isrcp) 1093289529Sian{ 1094297539Sskra int error; 1095289529Sian u_int irq; 1096297539Sskra struct arm_gic_softc *sc; 1097289529Sian 1098297539Sskra error = gic_map_intr(dev, data, &irq, NULL, NULL); 1099297539Sskra if (error == 0) { 1100297539Sskra sc = device_get_softc(dev); 1101297539Sskra *isrcp = GIC_INTR_ISRC(sc, irq); 1102297539Sskra } 1103289529Sian return (error); 1104289529Sian} 1105289529Sian 1106297539Sskrastatic int 1107297539Sskraarm_gic_setup_intr(device_t dev, struct intr_irqsrc *isrc, 1108297539Sskra struct resource *res, struct intr_map_data *data) 1109289529Sian{ 1110289529Sian struct arm_gic_softc *sc = device_get_softc(dev); 1111297539Sskra struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1112297539Sskra enum intr_trigger trig; 1113297539Sskra enum intr_polarity pol; 1114289529Sian 1115299928Sandrew if ((gi->gi_flags & GI_FLAG_MSI) == GI_FLAG_MSI) { 1116299928Sandrew pol = gi->gi_pol; 1117299928Sandrew trig = gi->gi_trig; 1118299928Sandrew KASSERT(pol == INTR_POLARITY_HIGH, 1119299928Sandrew ("%s: MSI interrupts must be active-high", __func__)); 1120299928Sandrew KASSERT(trig == INTR_TRIGGER_EDGE, 1121299928Sandrew ("%s: MSI interrupts must be edge triggered", __func__)); 1122299928Sandrew } else if (data != NULL) { 1123301267Sskra u_int irq; 1124301267Sskra 1125299928Sandrew /* Get config for resource. */ 1126301267Sskra if (gic_map_intr(dev, data, &irq, &pol, &trig) || 1127301267Sskra gi->gi_irq != irq) 1128299928Sandrew return (EINVAL); 1129300951Smmel } else { 1130300951Smmel pol = INTR_POLARITY_CONFORM; 1131300951Smmel trig = INTR_TRIGGER_CONFORM; 1132300951Smmel } 1133289529Sian 1134297539Sskra /* Compare config if this is not first setup. */ 1135297539Sskra if (isrc->isrc_handlers != 0) { 1136297539Sskra if ((pol != INTR_POLARITY_CONFORM && pol != gi->gi_pol) || 1137297539Sskra (trig != INTR_TRIGGER_CONFORM && trig != gi->gi_trig)) 1138297539Sskra return (EINVAL); 1139297539Sskra else 1140297539Sskra return (0); 1141297539Sskra } 1142297539Sskra 1143299928Sandrew /* For MSI/MSI-X we should have already configured these */ 1144299928Sandrew if ((gi->gi_flags & GI_FLAG_MSI) == 0) { 1145299928Sandrew if (pol == INTR_POLARITY_CONFORM) 1146299928Sandrew pol = INTR_POLARITY_LOW; /* just pick some */ 1147299928Sandrew if (trig == INTR_TRIGGER_CONFORM) 1148299928Sandrew trig = INTR_TRIGGER_EDGE; /* just pick some */ 1149297539Sskra 1150299928Sandrew gi->gi_pol = pol; 1151299928Sandrew gi->gi_trig = trig; 1152297539Sskra 1153299928Sandrew /* Edge triggered interrupts need an early EOI sent */ 1154299928Sandrew if (gi->gi_pol == INTR_TRIGGER_EDGE) 1155299928Sandrew gi->gi_flags |= GI_FLAG_EARLY_EOI; 1156299928Sandrew } 1157299928Sandrew 1158289529Sian /* 1159289529Sian * XXX - In case that per CPU interrupt is going to be enabled in time 1160289529Sian * when SMP is already started, we need some IPI call which 1161289529Sian * enables it on others CPUs. Further, it's more complicated as 1162289529Sian * pic_enable_source() and pic_disable_source() should act on 1163289529Sian * per CPU basis only. Thus, it should be solved here somehow. 1164289529Sian */ 1165297539Sskra if (isrc->isrc_flags & INTR_ISRCF_PPI) 1166289529Sian CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 1167289529Sian 1168299928Sandrew gic_config(sc, gi->gi_irq, gi->gi_trig, gi->gi_pol); 1169297539Sskra arm_gic_bind_intr(dev, isrc); 1170297539Sskra return (0); 1171289529Sian} 1172289529Sian 1173297539Sskrastatic int 1174297539Sskraarm_gic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 1175297539Sskra struct resource *res, struct intr_map_data *data) 1176289529Sian{ 1177297539Sskra struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1178289529Sian 1179299928Sandrew if (isrc->isrc_handlers == 0 && (gi->gi_flags & GI_FLAG_MSI) == 0) { 1180297539Sskra gi->gi_pol = INTR_POLARITY_CONFORM; 1181297539Sskra gi->gi_trig = INTR_TRIGGER_CONFORM; 1182297539Sskra } 1183297539Sskra return (0); 1184289529Sian} 1185289529Sian 1186289529Sianstatic void 1187297539Sskraarm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) 1188289529Sian{ 1189289529Sian struct arm_gic_softc *sc = device_get_softc(dev); 1190297539Sskra struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1191289529Sian 1192297539Sskra arm_irq_memory_barrier(gi->gi_irq); 1193297539Sskra gic_irq_unmask(sc, gi->gi_irq); 1194289529Sian} 1195289529Sian 1196297539Sskrastatic void 1197297539Sskraarm_gic_disable_intr(device_t dev, struct intr_irqsrc *isrc) 1198289529Sian{ 1199289529Sian struct arm_gic_softc *sc = device_get_softc(dev); 1200297539Sskra struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1201289529Sian 1202297539Sskra gic_irq_mask(sc, gi->gi_irq); 1203289529Sian} 1204289529Sian 1205289529Sianstatic void 1206292426Sadrianarm_gic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 1207289529Sian{ 1208289529Sian struct arm_gic_softc *sc = device_get_softc(dev); 1209297539Sskra struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1210289529Sian 1211297539Sskra arm_gic_disable_intr(dev, isrc); 1212297539Sskra gic_c_write_4(sc, GICC_EOIR, gi->gi_irq); 1213289529Sian} 1214289529Sian 1215289529Sianstatic void 1216292426Sadrianarm_gic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 1217289529Sian{ 1218289529Sian 1219289529Sian arm_irq_memory_barrier(0); 1220297539Sskra arm_gic_enable_intr(dev, isrc); 1221289529Sian} 1222289529Sian 1223289529Sianstatic void 1224292426Sadrianarm_gic_post_filter(device_t dev, struct intr_irqsrc *isrc) 1225289529Sian{ 1226289529Sian struct arm_gic_softc *sc = device_get_softc(dev); 1227297539Sskra struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1228289529Sian 1229289529Sian /* EOI for edge-triggered done earlier. */ 1230298054Sandrew if ((gi->gi_flags & GI_FLAG_EARLY_EOI) == GI_FLAG_EARLY_EOI) 1231289529Sian return; 1232289529Sian 1233289529Sian arm_irq_memory_barrier(0); 1234297539Sskra gic_c_write_4(sc, GICC_EOIR, gi->gi_irq); 1235289529Sian} 1236289529Sian 1237289529Sianstatic int 1238297539Sskraarm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc) 1239289529Sian{ 1240289529Sian struct arm_gic_softc *sc = device_get_softc(dev); 1241297539Sskra struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1242289529Sian 1243297539Sskra if (gi->gi_irq < GIC_FIRST_SPI) 1244289529Sian return (EINVAL); 1245289529Sian 1246289529Sian if (CPU_EMPTY(&isrc->isrc_cpu)) { 1247292426Sadrian gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus); 1248289529Sian CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu); 1249289529Sian } 1250297539Sskra return (gic_bind(sc, gi->gi_irq, &isrc->isrc_cpu)); 1251289529Sian} 1252289529Sian 1253289698Sian#ifdef SMP 1254289529Sianstatic void 1255297539Sskraarm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, 1256297539Sskra u_int ipi) 1257289529Sian{ 1258289529Sian struct arm_gic_softc *sc = device_get_softc(dev); 1259297539Sskra struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1260297539Sskra uint32_t val = 0, i; 1261289529Sian 1262289529Sian for (i = 0; i < MAXCPU; i++) 1263289529Sian if (CPU_ISSET(i, &cpus)) 1264297561Sandrew val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT; 1265289529Sian 1266297539Sskra gic_d_write_4(sc, GICD_SGIR(0), val | gi->gi_irq); 1267289529Sian} 1268297230Sskra 1269297230Sskrastatic int 1270297539Sskraarm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) 1271297230Sskra{ 1272297677Sskra struct intr_irqsrc *isrc; 1273297230Sskra struct arm_gic_softc *sc = device_get_softc(dev); 1274297230Sskra 1275297539Sskra if (sgi_first_unused > GIC_LAST_SGI) 1276297539Sskra return (ENOSPC); 1277297539Sskra 1278297677Sskra isrc = GIC_INTR_ISRC(sc, sgi_first_unused); 1279297539Sskra sgi_to_ipi[sgi_first_unused++] = ipi; 1280297677Sskra 1281297677Sskra CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 1282297677Sskra 1283297677Sskra *isrcp = isrc; 1284297230Sskra return (0); 1285297230Sskra} 1286289529Sian#endif 1287289529Sian#else 1288289529Sianstatic int 1289276963Sandrewarm_gic_next_irq(struct arm_gic_softc *sc, int last_irq) 1290239268Sgonzo{ 1291239268Sgonzo uint32_t active_irq; 1292239268Sgonzo 1293276015Sandrew active_irq = gic_c_read_4(sc, GICC_IAR); 1294239268Sgonzo 1295252370Sray /* 1296299069Spfg * Immediately EOIR the SGIs, because doing so requires the other 1297239268Sgonzo * bits (ie CPU number), not just the IRQ number, and we do not 1298239268Sgonzo * have this information later. 1299239268Sgonzo */ 1300289529Sian if ((active_irq & 0x3ff) <= GIC_LAST_SGI) 1301276015Sandrew gic_c_write_4(sc, GICC_EOIR, active_irq); 1302239268Sgonzo active_irq &= 0x3FF; 1303239268Sgonzo 1304239268Sgonzo if (active_irq == 0x3FF) { 1305239268Sgonzo if (last_irq == -1) 1306291424Smmel device_printf(sc->gic_dev, 1307291424Smmel "Spurious interrupt detected\n"); 1308239268Sgonzo return -1; 1309239268Sgonzo } 1310239268Sgonzo 1311239268Sgonzo return active_irq; 1312239268Sgonzo} 1313239268Sgonzo 1314260161Szbbstatic int 1315276963Sandrewarm_gic_config(device_t dev, int irq, enum intr_trigger trig, 1316260161Szbb enum intr_polarity pol) 1317260161Szbb{ 1318276963Sandrew struct arm_gic_softc *sc = device_get_softc(dev); 1319260161Szbb uint32_t reg; 1320260161Szbb uint32_t mask; 1321260161Szbb 1322260161Szbb /* Function is public-accessible, so validate input arguments */ 1323276015Sandrew if ((irq < 0) || (irq >= sc->nirqs)) 1324260161Szbb goto invalid_args; 1325260161Szbb if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) && 1326260161Szbb (trig != INTR_TRIGGER_CONFORM)) 1327260161Szbb goto invalid_args; 1328260161Szbb if ((pol != INTR_POLARITY_HIGH) && (pol != INTR_POLARITY_LOW) && 1329260161Szbb (pol != INTR_POLARITY_CONFORM)) 1330260161Szbb goto invalid_args; 1331260161Szbb 1332276015Sandrew mtx_lock_spin(&sc->mutex); 1333260161Szbb 1334276015Sandrew reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4)); 1335260161Szbb mask = (reg >> 2*(irq % 16)) & 0x3; 1336260161Szbb 1337260161Szbb if (pol == INTR_POLARITY_LOW) { 1338260161Szbb mask &= ~GICD_ICFGR_POL_MASK; 1339260161Szbb mask |= GICD_ICFGR_POL_LOW; 1340260161Szbb } else if (pol == INTR_POLARITY_HIGH) { 1341260161Szbb mask &= ~GICD_ICFGR_POL_MASK; 1342260161Szbb mask |= GICD_ICFGR_POL_HIGH; 1343260161Szbb } 1344260161Szbb 1345260161Szbb if (trig == INTR_TRIGGER_LEVEL) { 1346260161Szbb mask &= ~GICD_ICFGR_TRIG_MASK; 1347260161Szbb mask |= GICD_ICFGR_TRIG_LVL; 1348260161Szbb } else if (trig == INTR_TRIGGER_EDGE) { 1349260161Szbb mask &= ~GICD_ICFGR_TRIG_MASK; 1350260161Szbb mask |= GICD_ICFGR_TRIG_EDGE; 1351260161Szbb } 1352260161Szbb 1353260161Szbb /* Set mask */ 1354260161Szbb reg = reg & ~(0x3 << 2*(irq % 16)); 1355260161Szbb reg = reg | (mask << 2*(irq % 16)); 1356276015Sandrew gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg); 1357260161Szbb 1358276015Sandrew mtx_unlock_spin(&sc->mutex); 1359260161Szbb 1360260161Szbb return (0); 1361260161Szbb 1362260161Szbbinvalid_args: 1363276028Sandrew device_printf(dev, "gic_config_irg, invalid parameters\n"); 1364260161Szbb return (EINVAL); 1365260161Szbb} 1366260161Szbb 1367276963Sandrew 1368276963Sandrewstatic void 1369276963Sandrewarm_gic_mask(device_t dev, int irq) 1370276963Sandrew{ 1371276963Sandrew struct arm_gic_softc *sc = device_get_softc(dev); 1372276963Sandrew 1373276963Sandrew gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F))); 1374289529Sian gic_c_write_4(sc, GICC_EOIR, irq); /* XXX - not allowed */ 1375276963Sandrew} 1376276963Sandrew 1377276963Sandrewstatic void 1378276963Sandrewarm_gic_unmask(device_t dev, int irq) 1379276963Sandrew{ 1380276963Sandrew struct arm_gic_softc *sc = device_get_softc(dev); 1381276963Sandrew 1382289529Sian if (irq > GIC_LAST_SGI) 1383276963Sandrew arm_irq_memory_barrier(irq); 1384276963Sandrew 1385276963Sandrew gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F))); 1386276963Sandrew} 1387276963Sandrew 1388239268Sgonzo#ifdef SMP 1389276963Sandrewstatic void 1390276963Sandrewarm_gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi) 1391239268Sgonzo{ 1392276963Sandrew struct arm_gic_softc *sc = device_get_softc(dev); 1393239268Sgonzo uint32_t val = 0, i; 1394239268Sgonzo 1395239268Sgonzo for (i = 0; i < MAXCPU; i++) 1396239268Sgonzo if (CPU_ISSET(i, &cpus)) 1397297561Sandrew val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT; 1398252370Sray 1399276015Sandrew gic_d_write_4(sc, GICD_SGIR(0), val | ipi); 1400239268Sgonzo} 1401239268Sgonzo 1402276963Sandrewstatic int 1403276963Sandrewarm_gic_ipi_read(device_t dev, int i) 1404239268Sgonzo{ 1405252370Sray 1406239268Sgonzo if (i != -1) { 1407239268Sgonzo /* 1408239268Sgonzo * The intr code will automagically give the frame pointer 1409239268Sgonzo * if the interrupt argument is 0. 1410239268Sgonzo */ 1411252370Sray if ((unsigned int)i > 16) 1412239268Sgonzo return (0); 1413239268Sgonzo return (i); 1414239268Sgonzo } 1415276028Sandrew 1416239268Sgonzo return (0x3ff); 1417239268Sgonzo} 1418239268Sgonzo 1419276963Sandrewstatic void 1420276963Sandrewarm_gic_ipi_clear(device_t dev, int ipi) 1421276963Sandrew{ 1422276963Sandrew /* no-op */ 1423276963Sandrew} 1424276963Sandrew#endif 1425276963Sandrew 1426276963Sandrewstatic void 1427276963Sandrewgic_post_filter(void *arg) 1428276963Sandrew{ 1429289529Sian struct arm_gic_softc *sc = gic_sc; 1430276963Sandrew uintptr_t irq = (uintptr_t) arg; 1431276963Sandrew 1432289529Sian if (irq > GIC_LAST_SGI) 1433276963Sandrew arm_irq_memory_barrier(irq); 1434276963Sandrew gic_c_write_4(sc, GICC_EOIR, irq); 1435276963Sandrew} 1436276963Sandrew 1437276963Sandrewstatic int 1438276963Sandrewgic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol) 1439276963Sandrew{ 1440276963Sandrew 1441289529Sian return (arm_gic_config(gic_sc->gic_dev, irq, trig, pol)); 1442276963Sandrew} 1443276963Sandrew 1444239268Sgonzovoid 1445276963Sandrewarm_mask_irq(uintptr_t nb) 1446276963Sandrew{ 1447276963Sandrew 1448289529Sian arm_gic_mask(gic_sc->gic_dev, nb); 1449276963Sandrew} 1450276963Sandrew 1451276963Sandrewvoid 1452276963Sandrewarm_unmask_irq(uintptr_t nb) 1453276963Sandrew{ 1454276963Sandrew 1455289529Sian arm_gic_unmask(gic_sc->gic_dev, nb); 1456276963Sandrew} 1457276963Sandrew 1458276963Sandrewint 1459276963Sandrewarm_get_next_irq(int last_irq) 1460276963Sandrew{ 1461276963Sandrew 1462289529Sian return (arm_gic_next_irq(gic_sc, last_irq)); 1463276963Sandrew} 1464276963Sandrew 1465289529Sian#ifdef SMP 1466276963Sandrewvoid 1467292426Sadrianintr_pic_init_secondary(void) 1468276963Sandrew{ 1469276963Sandrew 1470289529Sian arm_gic_init_secondary(gic_sc->gic_dev); 1471276963Sandrew} 1472276963Sandrew 1473276963Sandrewvoid 1474276963Sandrewpic_ipi_send(cpuset_t cpus, u_int ipi) 1475276963Sandrew{ 1476276963Sandrew 1477289529Sian arm_gic_ipi_send(gic_sc->gic_dev, cpus, ipi); 1478276963Sandrew} 1479276963Sandrew 1480276963Sandrewint 1481276963Sandrewpic_ipi_read(int i) 1482276963Sandrew{ 1483276963Sandrew 1484289529Sian return (arm_gic_ipi_read(gic_sc->gic_dev, i)); 1485276963Sandrew} 1486276963Sandrew 1487276963Sandrewvoid 1488239268Sgonzopic_ipi_clear(int ipi) 1489239268Sgonzo{ 1490276963Sandrew 1491289529Sian arm_gic_ipi_clear(gic_sc->gic_dev, ipi); 1492239268Sgonzo} 1493239268Sgonzo#endif 1494298068Sandrew#endif /* INTRNG */ 1495239268Sgonzo 1496276028Sandrewstatic device_method_t arm_gic_methods[] = { 1497276028Sandrew /* Device interface */ 1498276028Sandrew DEVMETHOD(device_probe, arm_gic_probe), 1499276028Sandrew DEVMETHOD(device_attach, arm_gic_attach), 1500298051Sandrew 1501298068Sandrew#ifdef INTRNG 1502298051Sandrew /* Bus interface */ 1503298051Sandrew DEVMETHOD(bus_add_child, bus_generic_add_child), 1504298051Sandrew DEVMETHOD(bus_alloc_resource, arm_gic_alloc_resource), 1505298051Sandrew DEVMETHOD(bus_release_resource, bus_generic_release_resource), 1506298051Sandrew DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), 1507298051Sandrew 1508298051Sandrew /* ofw_bus interface */ 1509298051Sandrew DEVMETHOD(ofw_bus_get_devinfo, arm_gic_ofw_get_devinfo), 1510298051Sandrew DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 1511298051Sandrew DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 1512298051Sandrew DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 1513298051Sandrew DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 1514298051Sandrew DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 1515298051Sandrew 1516289529Sian /* Interrupt controller interface */ 1517297539Sskra DEVMETHOD(pic_disable_intr, arm_gic_disable_intr), 1518289529Sian DEVMETHOD(pic_enable_intr, arm_gic_enable_intr), 1519297539Sskra DEVMETHOD(pic_map_intr, arm_gic_map_intr), 1520297539Sskra DEVMETHOD(pic_setup_intr, arm_gic_setup_intr), 1521297539Sskra DEVMETHOD(pic_teardown_intr, arm_gic_teardown_intr), 1522289529Sian DEVMETHOD(pic_post_filter, arm_gic_post_filter), 1523289529Sian DEVMETHOD(pic_post_ithread, arm_gic_post_ithread), 1524289529Sian DEVMETHOD(pic_pre_ithread, arm_gic_pre_ithread), 1525289529Sian#ifdef SMP 1526297539Sskra DEVMETHOD(pic_bind_intr, arm_gic_bind_intr), 1527289529Sian DEVMETHOD(pic_init_secondary, arm_gic_init_secondary), 1528289529Sian DEVMETHOD(pic_ipi_send, arm_gic_ipi_send), 1529297230Sskra DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup), 1530289529Sian#endif 1531289529Sian#endif 1532276028Sandrew { 0, 0 } 1533276028Sandrew}; 1534276028Sandrew 1535276028Sandrewstatic driver_t arm_gic_driver = { 1536276028Sandrew "gic", 1537276028Sandrew arm_gic_methods, 1538276028Sandrew sizeof(struct arm_gic_softc), 1539276028Sandrew}; 1540276028Sandrew 1541276028Sandrewstatic devclass_t arm_gic_devclass; 1542276028Sandrew 1543276028SandrewEARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0, 1544276028Sandrew BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 1545276028SandrewEARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_driver, arm_gic_devclass, 0, 0, 1546276028Sandrew BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 1547298051Sandrew 1548298068Sandrew#ifdef INTRNG 1549298051Sandrew/* 1550298051Sandrew * GICv2m support -- the GICv2 MSI/MSI-X controller. 1551298051Sandrew */ 1552298051Sandrew 1553298051Sandrew#define GICV2M_MSI_TYPER 0x008 1554298051Sandrew#define MSI_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff) 1555298051Sandrew#define MSI_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff) 1556298051Sandrew#define GICv2M_MSI_SETSPI_NS 0x040 1557298051Sandrew#define GICV2M_MSI_IIDR 0xFCC 1558298051Sandrew 1559298051Sandrewstruct arm_gicv2m_softc { 1560298051Sandrew struct resource *sc_mem; 1561298051Sandrew struct mtx sc_mutex; 1562298051Sandrew u_int sc_spi_start; 1563299928Sandrew u_int sc_spi_end; 1564298051Sandrew u_int sc_spi_count; 1565298051Sandrew}; 1566298051Sandrew 1567298051Sandrewstatic struct ofw_compat_data gicv2m_compat_data[] = { 1568298051Sandrew {"arm,gic-v2m-frame", true}, 1569298051Sandrew {NULL, false} 1570298051Sandrew}; 1571298051Sandrew 1572298051Sandrewstatic int 1573298051Sandrewarm_gicv2m_probe(device_t dev) 1574298051Sandrew{ 1575298051Sandrew 1576298051Sandrew if (!ofw_bus_status_okay(dev)) 1577298051Sandrew return (ENXIO); 1578298051Sandrew 1579298051Sandrew if (!ofw_bus_search_compatible(dev, gicv2m_compat_data)->ocd_data) 1580298051Sandrew return (ENXIO); 1581298051Sandrew 1582298051Sandrew device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX"); 1583298051Sandrew return (BUS_PROBE_DEFAULT); 1584298051Sandrew} 1585298051Sandrew 1586298051Sandrewstatic int 1587298051Sandrewarm_gicv2m_attach(device_t dev) 1588298051Sandrew{ 1589298051Sandrew struct arm_gicv2m_softc *sc; 1590299928Sandrew struct arm_gic_softc *psc; 1591298051Sandrew uint32_t typer; 1592298051Sandrew int rid; 1593298051Sandrew 1594299928Sandrew psc = device_get_softc(device_get_parent(dev)); 1595298051Sandrew sc = device_get_softc(dev); 1596298051Sandrew 1597298051Sandrew rid = 0; 1598298051Sandrew sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1599298051Sandrew RF_ACTIVE); 1600298051Sandrew if (sc->sc_mem == NULL) { 1601298051Sandrew device_printf(dev, "Unable to allocate resources\n"); 1602298051Sandrew return (ENXIO); 1603298051Sandrew } 1604298051Sandrew 1605298051Sandrew typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER); 1606298051Sandrew sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer); 1607298051Sandrew sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer); 1608299928Sandrew sc->sc_spi_end = sc->sc_spi_start + sc->sc_spi_count; 1609298051Sandrew 1610299928Sandrew /* Reserve these interrupts for MSI/MSI-X use */ 1611299928Sandrew arm_gic_reserve_msi_range(device_get_parent(dev), sc->sc_spi_start, 1612299928Sandrew sc->sc_spi_count); 1613299928Sandrew 1614298051Sandrew mtx_init(&sc->sc_mutex, "GICv2m lock", "", MTX_DEF); 1615298051Sandrew 1616299928Sandrew intr_msi_register(dev, gic_xref(dev)); 1617299928Sandrew 1618298051Sandrew if (bootverbose) 1619298051Sandrew device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start, 1620298051Sandrew sc->sc_spi_start + sc->sc_spi_count - 1); 1621298051Sandrew 1622298051Sandrew return (0); 1623298051Sandrew} 1624298051Sandrew 1625299928Sandrewstatic int 1626299928Sandrewarm_gicv2m_alloc_msi(device_t dev, device_t child, int count, int maxcount, 1627299928Sandrew device_t *pic, struct intr_irqsrc **srcs) 1628299928Sandrew{ 1629299928Sandrew struct arm_gic_softc *psc; 1630299928Sandrew struct arm_gicv2m_softc *sc; 1631299928Sandrew int i, irq, end_irq; 1632299928Sandrew bool found; 1633299928Sandrew 1634299928Sandrew KASSERT(powerof2(count), ("%s: bad count", __func__)); 1635299928Sandrew KASSERT(powerof2(maxcount), ("%s: bad maxcount", __func__)); 1636299928Sandrew 1637299928Sandrew psc = device_get_softc(device_get_parent(dev)); 1638299928Sandrew sc = device_get_softc(dev); 1639299928Sandrew 1640299928Sandrew mtx_lock(&sc->sc_mutex); 1641299928Sandrew 1642299928Sandrew found = false; 1643319915Semaste for (irq = sc->sc_spi_start; irq < sc->sc_spi_end; irq++) { 1644299928Sandrew /* Start on an aligned interrupt */ 1645299928Sandrew if ((irq & (maxcount - 1)) != 0) 1646299928Sandrew continue; 1647299928Sandrew 1648299928Sandrew /* Assume we found a valid range until shown otherwise */ 1649299928Sandrew found = true; 1650299928Sandrew 1651299928Sandrew /* Check this range is valid */ 1652319915Semaste for (end_irq = irq; end_irq != irq + count; end_irq++) { 1653299928Sandrew /* No free interrupts */ 1654299928Sandrew if (end_irq == sc->sc_spi_end) { 1655299928Sandrew found = false; 1656299928Sandrew break; 1657299928Sandrew } 1658299928Sandrew 1659329280Sgonzo KASSERT((psc->gic_irqs[end_irq].gi_flags & GI_FLAG_MSI)!= 0, 1660299928Sandrew ("%s: Non-MSI interrupt found", __func__)); 1661299928Sandrew 1662299928Sandrew /* This is already used */ 1663329280Sgonzo if ((psc->gic_irqs[end_irq].gi_flags & GI_FLAG_MSI_USED) == 1664299928Sandrew GI_FLAG_MSI_USED) { 1665299928Sandrew found = false; 1666299928Sandrew break; 1667299928Sandrew } 1668299928Sandrew } 1669319915Semaste if (found) 1670319915Semaste break; 1671299928Sandrew } 1672299928Sandrew 1673299928Sandrew /* Not enough interrupts were found */ 1674299928Sandrew if (!found || irq == sc->sc_spi_end) { 1675299928Sandrew mtx_unlock(&sc->sc_mutex); 1676299928Sandrew return (ENXIO); 1677299928Sandrew } 1678299928Sandrew 1679299928Sandrew for (i = 0; i < count; i++) { 1680299928Sandrew /* Mark the interrupt as used */ 1681299928Sandrew psc->gic_irqs[irq + i].gi_flags |= GI_FLAG_MSI_USED; 1682299928Sandrew 1683299928Sandrew } 1684299928Sandrew mtx_unlock(&sc->sc_mutex); 1685299928Sandrew 1686299928Sandrew for (i = 0; i < count; i++) 1687299928Sandrew srcs[i] = (struct intr_irqsrc *)&psc->gic_irqs[irq + i]; 1688299928Sandrew *pic = device_get_parent(dev); 1689299928Sandrew 1690299928Sandrew return (0); 1691299928Sandrew} 1692299928Sandrew 1693299928Sandrewstatic int 1694299928Sandrewarm_gicv2m_release_msi(device_t dev, device_t child, int count, 1695299928Sandrew struct intr_irqsrc **isrc) 1696299928Sandrew{ 1697299928Sandrew struct arm_gicv2m_softc *sc; 1698299928Sandrew struct gic_irqsrc *gi; 1699299928Sandrew int i; 1700299928Sandrew 1701299928Sandrew sc = device_get_softc(dev); 1702299928Sandrew 1703299928Sandrew mtx_lock(&sc->sc_mutex); 1704299928Sandrew for (i = 0; i < count; i++) { 1705308382Sgonzo gi = (struct gic_irqsrc *)isrc[i]; 1706299928Sandrew 1707299928Sandrew KASSERT((gi->gi_flags & GI_FLAG_MSI_USED) == GI_FLAG_MSI_USED, 1708299928Sandrew ("%s: Trying to release an unused MSI-X interrupt", 1709299928Sandrew __func__)); 1710299928Sandrew 1711299928Sandrew gi->gi_flags &= ~GI_FLAG_MSI_USED; 1712299928Sandrew } 1713308382Sgonzo mtx_unlock(&sc->sc_mutex); 1714299928Sandrew 1715299928Sandrew return (0); 1716299928Sandrew} 1717299928Sandrew 1718299928Sandrewstatic int 1719299928Sandrewarm_gicv2m_alloc_msix(device_t dev, device_t child, device_t *pic, 1720299928Sandrew struct intr_irqsrc **isrcp) 1721299928Sandrew{ 1722299928Sandrew struct arm_gicv2m_softc *sc; 1723299928Sandrew struct arm_gic_softc *psc; 1724299928Sandrew int irq; 1725299928Sandrew 1726299928Sandrew psc = device_get_softc(device_get_parent(dev)); 1727299928Sandrew sc = device_get_softc(dev); 1728299928Sandrew 1729299928Sandrew mtx_lock(&sc->sc_mutex); 1730299928Sandrew /* Find an unused interrupt */ 1731299928Sandrew for (irq = sc->sc_spi_start; irq < sc->sc_spi_end; irq++) { 1732299928Sandrew KASSERT((psc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) != 0, 1733299928Sandrew ("%s: Non-MSI interrupt found", __func__)); 1734299928Sandrew if ((psc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0) 1735299928Sandrew break; 1736299928Sandrew } 1737299928Sandrew /* No free interrupt was found */ 1738299928Sandrew if (irq == sc->sc_spi_end) { 1739299928Sandrew mtx_unlock(&sc->sc_mutex); 1740299928Sandrew return (ENXIO); 1741299928Sandrew } 1742299928Sandrew 1743299928Sandrew /* Mark the interrupt as used */ 1744299928Sandrew psc->gic_irqs[irq].gi_flags |= GI_FLAG_MSI_USED; 1745299928Sandrew mtx_unlock(&sc->sc_mutex); 1746299928Sandrew 1747299928Sandrew *isrcp = (struct intr_irqsrc *)&psc->gic_irqs[irq]; 1748299928Sandrew *pic = device_get_parent(dev); 1749299928Sandrew 1750299928Sandrew return (0); 1751299928Sandrew} 1752299928Sandrew 1753299928Sandrewstatic int 1754299928Sandrewarm_gicv2m_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) 1755299928Sandrew{ 1756299928Sandrew struct arm_gicv2m_softc *sc; 1757299928Sandrew struct gic_irqsrc *gi; 1758299928Sandrew 1759299928Sandrew sc = device_get_softc(dev); 1760299928Sandrew gi = (struct gic_irqsrc *)isrc; 1761299928Sandrew 1762299928Sandrew KASSERT((gi->gi_flags & GI_FLAG_MSI_USED) == GI_FLAG_MSI_USED, 1763299928Sandrew ("%s: Trying to release an unused MSI-X interrupt", __func__)); 1764299928Sandrew 1765299928Sandrew mtx_lock(&sc->sc_mutex); 1766299928Sandrew gi->gi_flags &= ~GI_FLAG_MSI_USED; 1767299928Sandrew mtx_unlock(&sc->sc_mutex); 1768299928Sandrew 1769299928Sandrew return (0); 1770299928Sandrew} 1771299928Sandrew 1772299928Sandrewstatic int 1773299928Sandrewarm_gicv2m_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, 1774299928Sandrew uint64_t *addr, uint32_t *data) 1775299928Sandrew{ 1776299928Sandrew struct arm_gicv2m_softc *sc = device_get_softc(dev); 1777299928Sandrew struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 1778299928Sandrew 1779299928Sandrew *addr = vtophys(rman_get_virtual(sc->sc_mem)) + GICv2M_MSI_SETSPI_NS; 1780299928Sandrew *data = gi->gi_irq; 1781299928Sandrew 1782299928Sandrew return (0); 1783299928Sandrew} 1784299928Sandrew 1785298051Sandrewstatic device_method_t arm_gicv2m_methods[] = { 1786298051Sandrew /* Device interface */ 1787298051Sandrew DEVMETHOD(device_probe, arm_gicv2m_probe), 1788298051Sandrew DEVMETHOD(device_attach, arm_gicv2m_attach), 1789298051Sandrew 1790299928Sandrew /* MSI/MSI-X */ 1791299928Sandrew DEVMETHOD(msi_alloc_msi, arm_gicv2m_alloc_msi), 1792299928Sandrew DEVMETHOD(msi_release_msi, arm_gicv2m_release_msi), 1793299928Sandrew DEVMETHOD(msi_alloc_msix, arm_gicv2m_alloc_msix), 1794299928Sandrew DEVMETHOD(msi_release_msix, arm_gicv2m_release_msix), 1795299928Sandrew DEVMETHOD(msi_map_msi, arm_gicv2m_map_msi), 1796299928Sandrew 1797298051Sandrew /* End */ 1798298051Sandrew DEVMETHOD_END 1799298051Sandrew}; 1800298051Sandrew 1801298051SandrewDEFINE_CLASS_0(gicv2m, arm_gicv2m_driver, arm_gicv2m_methods, 1802298051Sandrew sizeof(struct arm_gicv2m_softc)); 1803298051Sandrew 1804298051Sandrewstatic devclass_t arm_gicv2m_devclass; 1805298051Sandrew 1806298051SandrewEARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_driver, 1807298051Sandrew arm_gicv2m_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 1808298051Sandrew#endif 1809