Home | History | Annotate | Line # | Download | only in acpi
      1 /* $NetBSD: gicv3_acpi.c,v 1.8 2020/12/23 11:05:08 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2018 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jared McNeill <jmcneill (at) invisible.ca>.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "pci.h"
     33 
     34 #define	_INTR_PRIVATE
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: gicv3_acpi.c,v 1.8 2020/12/23 11:05:08 jmcneill Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/bus.h>
     41 #include <sys/cpu.h>
     42 #include <sys/kernel.h>
     43 #include <sys/device.h>
     44 #include <sys/kmem.h>
     45 
     46 #include <dev/acpi/acpireg.h>
     47 #include <dev/acpi/acpivar.h>
     48 
     49 #include <dev/fdt/fdtvar.h>
     50 
     51 #include <arm/cortex/gicv3.h>
     52 #include <arm/cortex/gicv3_its.h>
     53 #include <arm/cortex/gic_reg.h>
     54 
     55 #include <arm/acpi/gic_v2m_acpi.h>
     56 
     57 #define	GICD_SIZE	0x10000
     58 #define	GICR_SIZE	0x20000
     59 #define	GITS_SIZE	0x20000
     60 
     61 extern struct bus_space arm_generic_bs_tag;
     62 extern struct arm32_bus_dma_tag arm_generic_dma_tag;
     63 
     64 struct gicv3_acpi_softc {
     65 	struct gicv3_softc	sc_gic;
     66 
     67 	ACPI_MADT_GENERIC_DISTRIBUTOR *sc_madt_gicd;
     68 };
     69 
     70 static int	gicv3_acpi_match(device_t, cfdata_t, void *);
     71 static void	gicv3_acpi_attach(device_t, device_t, void *);
     72 
     73 static int	gicv3_acpi_map_dist(struct gicv3_acpi_softc *);
     74 static int	gicv3_acpi_map_redist(struct gicv3_acpi_softc *);
     75 #if NPCI > 0
     76 static int	gicv3_acpi_map_msi(struct gicv3_acpi_softc *);
     77 #endif
     78 
     79 CFATTACH_DECL_NEW(gicv3_acpi, sizeof(struct gicv3_acpi_softc), gicv3_acpi_match, gicv3_acpi_attach, NULL, NULL);
     80 
     81 static int
     82 gicv3_acpi_match(device_t parent, cfdata_t cf, void *aux)
     83 {
     84 	ACPI_SUBTABLE_HEADER *hdrp = aux;
     85 	ACPI_MADT_GENERIC_DISTRIBUTOR *gicd;
     86 
     87 	if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR)
     88 		return 0;
     89 
     90 	gicd = (ACPI_MADT_GENERIC_DISTRIBUTOR *)hdrp;
     91 
     92 	switch (gicd->Version) {
     93 	case ACPI_MADT_GIC_VERSION_NONE:
     94 		return __SHIFTOUT(reg_id_aa64pfr0_el1_read(), ID_AA64PFR0_EL1_GIC) != 0;
     95 	case ACPI_MADT_GIC_VERSION_V3:
     96 	case ACPI_MADT_GIC_VERSION_V4:
     97 		return 1;
     98 	default:
     99 		return 0;
    100 	}
    101 }
    102 
    103 static void
    104 gicv3_acpi_attach(device_t parent, device_t self, void *aux)
    105 {
    106 	struct gicv3_acpi_softc * const sc = device_private(self);
    107 	ACPI_MADT_GENERIC_DISTRIBUTOR *gicd = aux;
    108 	int error;
    109 
    110 	sc->sc_gic.sc_dev = self;
    111 	sc->sc_gic.sc_bst = &arm_generic_bs_tag;
    112 	sc->sc_gic.sc_dmat = &arm_generic_dma_tag;
    113 	sc->sc_madt_gicd = gicd;
    114 
    115 	aprint_naive("\n");
    116 	aprint_normal(": GICv3\n");
    117 
    118 	error = gicv3_acpi_map_dist(sc);
    119 	if (error) {
    120 		aprint_error_dev(self, "failed to map distributor: %d\n", error);
    121 		return;
    122 	}
    123 
    124 	error = gicv3_acpi_map_redist(sc);
    125 	if (error) {
    126 		aprint_error_dev(self, "failed to map redistributor: %d\n", error);
    127 		return;
    128 	}
    129 
    130 	error = gicv3_init(&sc->sc_gic);
    131 	if (error) {
    132 		aprint_error_dev(self, "failed to initialize GIC: %d\n", error);
    133 		return;
    134 	}
    135 
    136 #if NPCI > 0
    137 	gicv3_acpi_map_msi(sc);
    138 #endif
    139 
    140 	arm_fdt_irq_set_handler(gicv3_irq_handler);
    141 }
    142 
    143 static int
    144 gicv3_acpi_map_dist(struct gicv3_acpi_softc *sc)
    145 {
    146 	const bus_addr_t addr = sc->sc_madt_gicd->BaseAddress;
    147 	const bus_size_t size = GICD_SIZE;
    148 	int error;
    149 
    150 	error = bus_space_map(sc->sc_gic.sc_bst, addr, size, 0, &sc->sc_gic.sc_bsh_d);
    151 	if (error)
    152 		return error;
    153 
    154 	return 0;
    155 }
    156 
    157 static ACPI_STATUS
    158 gicv3_acpi_count_gicr(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
    159 {
    160 	ACPI_MADT_GENERIC_REDISTRIBUTOR *gicr;
    161 	int *count = aux;
    162 
    163 	if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR) {
    164 		gicr = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)hdrp;
    165 		*count += howmany(gicr->Length, GICR_SIZE);
    166 	}
    167 
    168 	return AE_OK;
    169 }
    170 
    171 static ACPI_STATUS
    172 gicv3_acpi_map_gicr(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
    173 {
    174 	struct gicv3_acpi_softc * const sc = aux;
    175 	ACPI_MADT_GENERIC_REDISTRIBUTOR *gicr;
    176 	bus_space_handle_t bsh;
    177 	bus_size_t off;
    178 
    179 	if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR)
    180 		return AE_OK;
    181 
    182 	gicr = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)hdrp;
    183 
    184 	if (bus_space_map(sc->sc_gic.sc_bst, gicr->BaseAddress, gicr->Length, 0, &bsh) != 0) {
    185 		aprint_error_dev(sc->sc_gic.sc_dev, "failed to map redistributor at 0x%" PRIx64 " len %#x\n",
    186 		    gicr->BaseAddress, gicr->Length);
    187 		return AE_OK;
    188 	}
    189 
    190 	for (off = 0; off < gicr->Length; off += GICR_SIZE) {
    191 		const int redist = sc->sc_gic.sc_bsh_r_count;
    192 		if (bus_space_subregion(sc->sc_gic.sc_bst, bsh, off, GICR_SIZE, &sc->sc_gic.sc_bsh_r[redist]) != 0) {
    193 			aprint_error_dev(sc->sc_gic.sc_dev, "couldn't subregion redistributor registers\n");
    194 			return AE_OK;
    195 		}
    196 
    197 		aprint_debug_dev(sc->sc_gic.sc_dev, "redist at 0x%" PRIx64 " [GICR]\n", gicr->BaseAddress + off);
    198 
    199 		sc->sc_gic.sc_bsh_r_count++;
    200 
    201 		/* If this is the last redist in this region, skip to the next one */
    202 		const uint32_t typer = bus_space_read_4(sc->sc_gic.sc_bst, sc->sc_gic.sc_bsh_r[redist], GICR_TYPER);
    203 		if (typer & GICR_TYPER_Last)
    204 			break;
    205 
    206 		/* If the redistributor supports virtual LPIs, skip the VLPI register region */
    207 		if (typer & GICR_TYPER_VLPIS)
    208 			off += GICR_SIZE;
    209 	}
    210 
    211 	return AE_OK;
    212 }
    213 
    214 static ACPI_STATUS
    215 gicv3_acpi_count_gicc(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
    216 {
    217 	ACPI_MADT_GENERIC_INTERRUPT *gicc;
    218 	int *count = aux;
    219 
    220 	if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
    221 		gicc = (ACPI_MADT_GENERIC_INTERRUPT *)hdrp;
    222 		if ((gicc->Flags & ACPI_MADT_ENABLED) != 0)
    223 			(*count)++;
    224 	}
    225 
    226 	return AE_OK;
    227 }
    228 
    229 static ACPI_STATUS
    230 gicv3_acpi_map_gicc(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
    231 {
    232 	struct gicv3_acpi_softc * const sc = aux;
    233 	ACPI_MADT_GENERIC_INTERRUPT *gicc;
    234 
    235 	if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_INTERRUPT)
    236 		return AE_OK;
    237 
    238 	gicc = (ACPI_MADT_GENERIC_INTERRUPT *)hdrp;
    239 	if ((gicc->Flags & ACPI_MADT_ENABLED) == 0)
    240 		return AE_OK;
    241 
    242 	const int redist = sc->sc_gic.sc_bsh_r_count;
    243 	if (bus_space_map(sc->sc_gic.sc_bst, gicc->GicrBaseAddress, GICR_SIZE, 0, &sc->sc_gic.sc_bsh_r[redist]) != 0) {
    244 		aprint_error_dev(sc->sc_gic.sc_dev, "failed to map redistributor at 0x%" PRIx64 " len %#x\n",
    245 		    gicc->GicrBaseAddress, GICR_SIZE);
    246 		return AE_OK;
    247 	}
    248 
    249 	aprint_debug_dev(sc->sc_gic.sc_dev, "redist at 0x%" PRIx64 " [GICC]\n", gicc->GicrBaseAddress);
    250 
    251 	sc->sc_gic.sc_bsh_r_count++;
    252 
    253 	return AE_OK;
    254 }
    255 
    256 static int
    257 gicv3_acpi_map_redist(struct gicv3_acpi_softc *sc)
    258 {
    259 	bool use_gicr = false;
    260 	int max_redist = 0;
    261 
    262 	/*
    263 	 * Try to use GICR structures to describe redistributors. If no GICR
    264 	 * subtables are found, use the GICR address from the GICC subtables.
    265 	 */
    266 	acpi_madt_walk(gicv3_acpi_count_gicr, &max_redist);
    267 	if (max_redist != 0)
    268 		use_gicr = true;
    269 	else
    270 		acpi_madt_walk(gicv3_acpi_count_gicc, &max_redist);
    271 
    272 	if (max_redist == 0)
    273 		return ENODEV;
    274 
    275 	sc->sc_gic.sc_bsh_r = kmem_alloc(sizeof(bus_space_handle_t) * max_redist, KM_SLEEP);
    276 	if (use_gicr)
    277 		acpi_madt_walk(gicv3_acpi_map_gicr, sc);
    278 	else
    279 		acpi_madt_walk(gicv3_acpi_map_gicc, sc);
    280 
    281 	if (sc->sc_gic.sc_bsh_r_count == 0)
    282 		return ENXIO;
    283 
    284 	return 0;
    285 }
    286 
    287 #if NPCI > 0
    288 static ACPI_STATUS
    289 gicv3_acpi_map_gits(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
    290 {
    291 	struct gicv3_acpi_softc * const sc = aux;
    292 	ACPI_MADT_GENERIC_TRANSLATOR *gits;
    293 	bus_space_handle_t bsh;
    294 
    295 	if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_TRANSLATOR)
    296 		return AE_OK;
    297 
    298 	gits = (ACPI_MADT_GENERIC_TRANSLATOR *)hdrp;
    299 
    300 	if (bus_space_map(sc->sc_gic.sc_bst, gits->BaseAddress, GITS_SIZE, 0, &bsh) != 0) {
    301 		aprint_error_dev(sc->sc_gic.sc_dev, "failed to map ITS at 0x%" PRIx64 " len %#x\n",
    302 		    gits->BaseAddress, GITS_SIZE);
    303 		return AE_OK;
    304 	}
    305 
    306 	aprint_normal_dev(sc->sc_gic.sc_dev, "ITS #%d at 0x%" PRIx64 "\n",
    307 	    gits->TranslationId, gits->BaseAddress);
    308 
    309 	gicv3_its_init(&sc->sc_gic, bsh, gits->BaseAddress, gits->TranslationId);
    310 
    311 	return AE_OK;
    312 }
    313 
    314 static int
    315 gicv3_acpi_map_msi(struct gicv3_acpi_softc *sc)
    316 {
    317 	acpi_madt_walk(gicv3_acpi_map_gits, sc);
    318 	acpi_madt_walk(gic_v2m_acpi_find_msi_frame, sc->sc_gic.sc_dev);
    319 
    320 	return 0;
    321 }
    322 
    323 #endif
    324