1 1.41 jmcneill /* $NetBSD: gicv3_its.c,v 1.41 2025/01/28 21:20:45 jmcneill Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jmcneill * by Jared McNeill <jmcneill (at) invisible.ca>. 9 1.1 jmcneill * 10 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 11 1.1 jmcneill * modification, are permitted provided that the following conditions 12 1.1 jmcneill * are met: 13 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 14 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 15 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 17 1.1 jmcneill * documentation and/or other materials provided with the distribution. 18 1.1 jmcneill * 19 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jmcneill */ 31 1.1 jmcneill 32 1.1 jmcneill #define _INTR_PRIVATE 33 1.1 jmcneill 34 1.1 jmcneill #include <sys/cdefs.h> 35 1.41 jmcneill __KERNEL_RCSID(0, "$NetBSD: gicv3_its.c,v 1.41 2025/01/28 21:20:45 jmcneill Exp $"); 36 1.1 jmcneill 37 1.1 jmcneill #include <sys/param.h> 38 1.1 jmcneill #include <sys/kmem.h> 39 1.1 jmcneill #include <sys/bus.h> 40 1.1 jmcneill #include <sys/cpu.h> 41 1.7 jmcneill #include <sys/bitops.h> 42 1.1 jmcneill 43 1.1 jmcneill #include <uvm/uvm.h> 44 1.1 jmcneill 45 1.1 jmcneill #include <dev/pci/pcireg.h> 46 1.1 jmcneill #include <dev/pci/pcivar.h> 47 1.1 jmcneill 48 1.36 jmcneill #include <machine/cpufunc.h> 49 1.36 jmcneill 50 1.1 jmcneill #include <arm/pic/picvar.h> 51 1.1 jmcneill #include <arm/cortex/gicv3_its.h> 52 1.1 jmcneill 53 1.36 jmcneill #ifdef ITS_DEBUG 54 1.36 jmcneill #define DPRINTF(x) printf x 55 1.36 jmcneill #else 56 1.37 riastrad #define DPRINTF(x) __nothing 57 1.36 jmcneill #endif 58 1.36 jmcneill 59 1.1 jmcneill /* 60 1.1 jmcneill * ITS translation table sizes 61 1.1 jmcneill */ 62 1.1 jmcneill #define GITS_COMMANDS_SIZE 0x1000 63 1.1 jmcneill #define GITS_COMMANDS_ALIGN 0x10000 64 1.1 jmcneill 65 1.1 jmcneill #define GITS_ITT_ALIGN 0x100 66 1.1 jmcneill 67 1.36 jmcneill #define GITS_INDIRECT_ENTRY_SIZE 8 68 1.36 jmcneill 69 1.8 skrll /* 70 1.8 skrll * IIDR values used for errata 71 1.8 skrll */ 72 1.8 skrll #define GITS_IIDR_PID_CAVIUM_THUNDERX 0xa1 73 1.8 skrll #define GITS_IIDR_IMP_CAVIUM 0x34c 74 1.21 jmcneill #define GITS_IIDR_CAVIUM_ERRATA_MASK (GITS_IIDR_Implementor|GITS_IIDR_ProductID|GITS_IIDR_Variant) 75 1.21 jmcneill #define GITS_IIDR_CAVIUM_ERRATA_VALUE \ 76 1.21 jmcneill (__SHIFTIN(GITS_IIDR_IMP_CAVIUM, GITS_IIDR_Implementor) | \ 77 1.21 jmcneill __SHIFTIN(GITS_IIDR_PID_CAVIUM_THUNDERX, GITS_IIDR_ProductID) | \ 78 1.21 jmcneill __SHIFTIN(0, GITS_IIDR_Variant)) 79 1.21 jmcneill 80 1.21 jmcneill static const char * gits_cache_type[] = { 81 1.21 jmcneill [GITS_Cache_DEVICE_nGnRnE] = "Device-nGnRnE", 82 1.21 jmcneill [GITS_Cache_NORMAL_NC] = "Non-cacheable", 83 1.21 jmcneill [GITS_Cache_NORMAL_RA_WT] = "Cacheable RA WT", 84 1.21 jmcneill [GITS_Cache_NORMAL_RA_WB] = "Cacheable RA WB", 85 1.21 jmcneill [GITS_Cache_NORMAL_WA_WT] = "Cacheable WA WT", 86 1.21 jmcneill [GITS_Cache_NORMAL_WA_WB] = "Cacheable WA WB", 87 1.21 jmcneill [GITS_Cache_NORMAL_RA_WA_WT] = "Cacheable RA WA WT", 88 1.21 jmcneill [GITS_Cache_NORMAL_RA_WA_WB] = "Cacheable RA WA WB", 89 1.21 jmcneill }; 90 1.21 jmcneill 91 1.21 jmcneill static const char * gits_share_type[] = { 92 1.21 jmcneill [GITS_Shareability_NS] = "Non-shareable", 93 1.21 jmcneill [GITS_Shareability_IS] = "Inner shareable", 94 1.21 jmcneill [GITS_Shareability_OS] = "Outer shareable", 95 1.21 jmcneill [3] = "(Reserved)", 96 1.21 jmcneill }; 97 1.8 skrll 98 1.1 jmcneill static inline uint32_t 99 1.1 jmcneill gits_read_4(struct gicv3_its *its, bus_size_t reg) 100 1.1 jmcneill { 101 1.1 jmcneill return bus_space_read_4(its->its_bst, its->its_bsh, reg); 102 1.1 jmcneill } 103 1.1 jmcneill 104 1.1 jmcneill static inline void 105 1.1 jmcneill gits_write_4(struct gicv3_its *its, bus_size_t reg, uint32_t val) 106 1.1 jmcneill { 107 1.1 jmcneill bus_space_write_4(its->its_bst, its->its_bsh, reg, val); 108 1.1 jmcneill } 109 1.1 jmcneill 110 1.1 jmcneill static inline uint64_t 111 1.1 jmcneill gits_read_8(struct gicv3_its *its, bus_size_t reg) 112 1.1 jmcneill { 113 1.1 jmcneill return bus_space_read_8(its->its_bst, its->its_bsh, reg); 114 1.1 jmcneill } 115 1.1 jmcneill 116 1.1 jmcneill static inline void 117 1.1 jmcneill gits_write_8(struct gicv3_its *its, bus_size_t reg, uint64_t val) 118 1.1 jmcneill { 119 1.1 jmcneill bus_space_write_8(its->its_bst, its->its_bsh, reg, val); 120 1.1 jmcneill } 121 1.1 jmcneill 122 1.36 jmcneill static int 123 1.1 jmcneill gits_command(struct gicv3_its *its, const struct gicv3_its_command *cmd) 124 1.1 jmcneill { 125 1.36 jmcneill uint64_t cwriter, creadr; 126 1.1 jmcneill u_int woff; 127 1.1 jmcneill 128 1.36 jmcneill creadr = gits_read_8(its, GITS_CREADR); 129 1.36 jmcneill if (ISSET(creadr, GITS_CREADR_Stalled)) { 130 1.36 jmcneill DPRINTF(("ITS: stalled! GITS_CREADR = 0x%lx\n", creadr)); 131 1.36 jmcneill return EIO; 132 1.36 jmcneill } 133 1.36 jmcneill 134 1.1 jmcneill cwriter = gits_read_8(its, GITS_CWRITER); 135 1.1 jmcneill woff = cwriter & GITS_CWRITER_Offset; 136 1.1 jmcneill 137 1.28 ryo uint64_t *dw = (uint64_t *)(its->its_cmd.base + woff); 138 1.36 jmcneill for (int i = 0; i < __arraycount(cmd->dw); i++) { 139 1.28 ryo dw[i] = htole64(cmd->dw[i]); 140 1.36 jmcneill DPRINTF(("ITS: dw[%u] = 0x%016lx\n", i, cmd->dw[i])); 141 1.36 jmcneill } 142 1.36 jmcneill 143 1.36 jmcneill if (its->its_cmd_flush) { 144 1.36 jmcneill cpu_dcache_wb_range((vaddr_t)dw, sizeof(cmd->dw)); 145 1.36 jmcneill } 146 1.36 jmcneill dsb(sy); 147 1.1 jmcneill 148 1.1 jmcneill woff += sizeof(cmd->dw); 149 1.1 jmcneill if (woff == its->its_cmd.len) 150 1.1 jmcneill woff = 0; 151 1.1 jmcneill 152 1.1 jmcneill gits_write_8(its, GITS_CWRITER, woff); 153 1.36 jmcneill 154 1.36 jmcneill return 0; 155 1.1 jmcneill } 156 1.1 jmcneill 157 1.36 jmcneill static int 158 1.1 jmcneill gits_command_mapc(struct gicv3_its *its, uint16_t icid, uint64_t rdbase, bool v) 159 1.1 jmcneill { 160 1.1 jmcneill struct gicv3_its_command cmd; 161 1.1 jmcneill 162 1.1 jmcneill KASSERT((rdbase & 0xffff) == 0); 163 1.1 jmcneill 164 1.1 jmcneill /* 165 1.1 jmcneill * Map a collection table entry (ICID) to the target redistributor (RDbase). 166 1.1 jmcneill */ 167 1.1 jmcneill memset(&cmd, 0, sizeof(cmd)); 168 1.1 jmcneill cmd.dw[0] = GITS_CMD_MAPC; 169 1.1 jmcneill cmd.dw[2] = icid; 170 1.1 jmcneill if (v) { 171 1.1 jmcneill cmd.dw[2] |= rdbase; 172 1.1 jmcneill cmd.dw[2] |= __BIT(63); 173 1.1 jmcneill } 174 1.1 jmcneill 175 1.36 jmcneill DPRINTF(("ITS #%u: MAPC icid 0x%x rdbase 0x%lx valid %u\n", 176 1.36 jmcneill its->its_id, icid, rdbase, v)); 177 1.36 jmcneill 178 1.36 jmcneill return gits_command(its, &cmd); 179 1.1 jmcneill } 180 1.1 jmcneill 181 1.36 jmcneill static int 182 1.1 jmcneill gits_command_mapd(struct gicv3_its *its, uint32_t deviceid, uint64_t itt_addr, u_int size, bool v) 183 1.1 jmcneill { 184 1.1 jmcneill struct gicv3_its_command cmd; 185 1.1 jmcneill 186 1.1 jmcneill KASSERT((itt_addr & 0xff) == 0); 187 1.1 jmcneill 188 1.1 jmcneill /* 189 1.1 jmcneill * Map a device table entry (DeviceID) to its associated ITT (ITT_addr). 190 1.1 jmcneill */ 191 1.1 jmcneill memset(&cmd, 0, sizeof(cmd)); 192 1.1 jmcneill cmd.dw[0] = GITS_CMD_MAPD | ((uint64_t)deviceid << 32); 193 1.1 jmcneill if (v) { 194 1.36 jmcneill cmd.dw[1] = uimax(1, size) - 1; 195 1.1 jmcneill cmd.dw[2] = itt_addr | __BIT(63); 196 1.1 jmcneill } 197 1.1 jmcneill 198 1.36 jmcneill DPRINTF(("ITS #%u: MAPD deviceid 0x%x itt_addr 0x%lx size %u valid %u\n", 199 1.36 jmcneill its->its_id, deviceid, itt_addr, size, v)); 200 1.36 jmcneill 201 1.36 jmcneill return gits_command(its, &cmd); 202 1.1 jmcneill } 203 1.1 jmcneill 204 1.36 jmcneill static int 205 1.15 jmcneill gits_command_mapti(struct gicv3_its *its, uint32_t deviceid, uint32_t eventid, uint32_t pintid, uint16_t icid) 206 1.1 jmcneill { 207 1.1 jmcneill struct gicv3_its_command cmd; 208 1.1 jmcneill 209 1.1 jmcneill /* 210 1.15 jmcneill * Map the event defined by EventID and DeviceID to its associated ITE, defined by ICID and pINTID 211 1.15 jmcneill * in the ITT associated with DeviceID. 212 1.1 jmcneill */ 213 1.1 jmcneill memset(&cmd, 0, sizeof(cmd)); 214 1.15 jmcneill cmd.dw[0] = GITS_CMD_MAPTI | ((uint64_t)deviceid << 32); 215 1.15 jmcneill cmd.dw[1] = eventid | ((uint64_t)pintid << 32); 216 1.1 jmcneill cmd.dw[2] = icid; 217 1.1 jmcneill 218 1.36 jmcneill DPRINTF(("ITS #%u: MAPTI deviceid 0x%x eventid 0x%x pintid 0x%x icid 0x%x\n", 219 1.36 jmcneill its->its_id, deviceid, eventid, pintid, icid)); 220 1.36 jmcneill 221 1.36 jmcneill return gits_command(its, &cmd); 222 1.1 jmcneill } 223 1.1 jmcneill 224 1.36 jmcneill static int 225 1.2 jmcneill gits_command_movi(struct gicv3_its *its, uint32_t deviceid, uint32_t eventid, uint16_t icid) 226 1.2 jmcneill { 227 1.2 jmcneill struct gicv3_its_command cmd; 228 1.2 jmcneill 229 1.2 jmcneill /* 230 1.2 jmcneill * Update the ICID field in the ITT entry for the event defined by DeviceID and 231 1.2 jmcneill * EventID. 232 1.2 jmcneill */ 233 1.2 jmcneill memset(&cmd, 0, sizeof(cmd)); 234 1.2 jmcneill cmd.dw[0] = GITS_CMD_MOVI | ((uint64_t)deviceid << 32); 235 1.2 jmcneill cmd.dw[1] = eventid; 236 1.2 jmcneill cmd.dw[2] = icid; 237 1.2 jmcneill 238 1.36 jmcneill DPRINTF(("ITS #%u: MOVI deviceid 0x%x eventid 0x%x icid 0x%x\n", 239 1.36 jmcneill its->its_id, deviceid, eventid, icid)); 240 1.36 jmcneill 241 1.36 jmcneill return gits_command(its, &cmd); 242 1.2 jmcneill } 243 1.2 jmcneill 244 1.36 jmcneill static int 245 1.1 jmcneill gits_command_inv(struct gicv3_its *its, uint32_t deviceid, uint32_t eventid) 246 1.1 jmcneill { 247 1.1 jmcneill struct gicv3_its_command cmd; 248 1.1 jmcneill 249 1.1 jmcneill /* 250 1.1 jmcneill * Ensure any caching in the redistributors associated with the specified 251 1.1 jmcneill * EventID is consistent with the LPI configuration tables. 252 1.1 jmcneill */ 253 1.1 jmcneill memset(&cmd, 0, sizeof(cmd)); 254 1.1 jmcneill cmd.dw[0] = GITS_CMD_INV | ((uint64_t)deviceid << 32); 255 1.1 jmcneill cmd.dw[1] = eventid; 256 1.1 jmcneill 257 1.36 jmcneill DPRINTF(("ITS #%u: INV deviceid 0x%x eventid 0x%x\n", 258 1.36 jmcneill its->its_id, deviceid, eventid)); 259 1.36 jmcneill 260 1.36 jmcneill return gits_command(its, &cmd); 261 1.1 jmcneill } 262 1.1 jmcneill 263 1.36 jmcneill static int 264 1.1 jmcneill gits_command_invall(struct gicv3_its *its, uint16_t icid) 265 1.1 jmcneill { 266 1.1 jmcneill struct gicv3_its_command cmd; 267 1.1 jmcneill 268 1.1 jmcneill /* 269 1.1 jmcneill * Ensure any caching associated with this ICID is consistent with LPI 270 1.1 jmcneill * configuration tables for all redistributors. 271 1.1 jmcneill */ 272 1.1 jmcneill memset(&cmd, 0, sizeof(cmd)); 273 1.1 jmcneill cmd.dw[0] = GITS_CMD_INVALL; 274 1.1 jmcneill cmd.dw[2] = icid; 275 1.1 jmcneill 276 1.36 jmcneill DPRINTF(("ITS #%u: INVALL icid 0x%x\n", its->its_id, icid)); 277 1.36 jmcneill 278 1.36 jmcneill return gits_command(its, &cmd); 279 1.1 jmcneill } 280 1.1 jmcneill 281 1.36 jmcneill static int 282 1.1 jmcneill gits_command_sync(struct gicv3_its *its, uint64_t rdbase) 283 1.1 jmcneill { 284 1.1 jmcneill struct gicv3_its_command cmd; 285 1.1 jmcneill 286 1.1 jmcneill KASSERT((rdbase & 0xffff) == 0); 287 1.1 jmcneill 288 1.1 jmcneill /* 289 1.1 jmcneill * Ensure all outstanding ITS operations associated with physical interrupts 290 1.1 jmcneill * for the specified redistributor (RDbase) are globally observed before 291 1.1 jmcneill * further ITS commands are executed. 292 1.1 jmcneill */ 293 1.1 jmcneill memset(&cmd, 0, sizeof(cmd)); 294 1.1 jmcneill cmd.dw[0] = GITS_CMD_SYNC; 295 1.1 jmcneill cmd.dw[2] = rdbase; 296 1.1 jmcneill 297 1.36 jmcneill DPRINTF(("ITS #%u: SYNC rdbase 0x%lx\n", its->its_id, rdbase)); 298 1.36 jmcneill 299 1.36 jmcneill return gits_command(its, &cmd); 300 1.1 jmcneill } 301 1.1 jmcneill 302 1.35 tnn #if 0 303 1.36 jmcneill static int 304 1.35 tnn gits_command_int(struct gicv3_its *its, uint32_t deviceid, uint32_t eventid) 305 1.35 tnn { 306 1.35 tnn struct gicv3_its_command cmd; 307 1.35 tnn 308 1.35 tnn /* 309 1.35 tnn * Translate the deviceid and eventid into an icid and pintid through 310 1.35 tnn * the device table and ITT. Mark the pintid as pending 311 1.35 tnn * on the redistributor. 312 1.35 tnn * If the interrupt is not configured the command queue stalls. 313 1.35 tnn */ 314 1.35 tnn memset(&cmd, 0, sizeof(cmd)); 315 1.35 tnn cmd.dw[0] = GITS_CMD_INT | ((uint64_t)deviceid << 32); 316 1.35 tnn cmd.dw[1] = eventid; 317 1.35 tnn 318 1.36 jmcneill DPRINTF(("ITS #%u: INT deviceid 0x%x eventid 0x%x\n", 319 1.36 jmcneill its->its_id, deviceid, eventid)); 320 1.36 jmcneill 321 1.36 jmcneill return gits_command(its, &cmd); 322 1.35 tnn } 323 1.35 tnn #endif 324 1.35 tnn 325 1.36 jmcneill static int 326 1.1 jmcneill gits_wait(struct gicv3_its *its) 327 1.1 jmcneill { 328 1.1 jmcneill u_int woff, roff; 329 1.1 jmcneill int retry = 100000; 330 1.1 jmcneill 331 1.1 jmcneill /* 332 1.1 jmcneill * The ITS command queue is empty when CWRITER and CREADR specify the 333 1.1 jmcneill * same base address offset value. 334 1.1 jmcneill */ 335 1.1 jmcneill for (retry = 1000; retry > 0; retry--) { 336 1.1 jmcneill woff = gits_read_8(its, GITS_CWRITER) & GITS_CWRITER_Offset; 337 1.1 jmcneill roff = gits_read_8(its, GITS_CREADR) & GITS_CREADR_Offset; 338 1.1 jmcneill if (woff == roff) 339 1.1 jmcneill break; 340 1.1 jmcneill delay(100); 341 1.1 jmcneill } 342 1.1 jmcneill if (retry == 0) { 343 1.36 jmcneill device_printf(its->its_gic->sc_dev, 344 1.36 jmcneill "ITS command queue timeout! CREADR=0x%lx CWRITER=0x%lx\n", 345 1.36 jmcneill gits_read_8(its, GITS_CREADR), gits_read_8(its, GITS_CWRITER)); 346 1.1 jmcneill return ETIMEDOUT; 347 1.1 jmcneill } 348 1.1 jmcneill 349 1.1 jmcneill return 0; 350 1.1 jmcneill } 351 1.1 jmcneill 352 1.1 jmcneill static int 353 1.1 jmcneill gicv3_its_msi_alloc_lpi(struct gicv3_its *its, 354 1.1 jmcneill const struct pci_attach_args *pa) 355 1.1 jmcneill { 356 1.12 jmcneill struct pci_attach_args *new_pa; 357 1.26 jmcneill vmem_addr_t n; 358 1.1 jmcneill 359 1.26 jmcneill KASSERT(its->its_gic->sc_lpi_pool != NULL); 360 1.1 jmcneill 361 1.26 jmcneill if (vmem_alloc(its->its_gic->sc_lpi_pool, 1, VM_INSTANTFIT|VM_SLEEP, &n) != 0) 362 1.26 jmcneill return -1; 363 1.31 jmcneill 364 1.26 jmcneill KASSERT(its->its_pa[n] == NULL); 365 1.26 jmcneill 366 1.26 jmcneill new_pa = kmem_alloc(sizeof(*new_pa), KM_SLEEP); 367 1.26 jmcneill memcpy(new_pa, pa, sizeof(*new_pa)); 368 1.26 jmcneill its->its_pa[n] = new_pa; 369 1.26 jmcneill return n + its->its_pic->pic_irqbase; 370 1.1 jmcneill } 371 1.23 skrll 372 1.1 jmcneill static void 373 1.1 jmcneill gicv3_its_msi_free_lpi(struct gicv3_its *its, int lpi) 374 1.1 jmcneill { 375 1.12 jmcneill struct pci_attach_args *pa; 376 1.12 jmcneill 377 1.26 jmcneill KASSERT(its->its_gic->sc_lpi_pool != NULL); 378 1.1 jmcneill KASSERT(lpi >= its->its_pic->pic_irqbase); 379 1.12 jmcneill 380 1.12 jmcneill pa = its->its_pa[lpi - its->its_pic->pic_irqbase]; 381 1.1 jmcneill its->its_pa[lpi - its->its_pic->pic_irqbase] = NULL; 382 1.12 jmcneill kmem_free(pa, sizeof(*pa)); 383 1.26 jmcneill 384 1.26 jmcneill vmem_free(its->its_gic->sc_lpi_pool, lpi - its->its_pic->pic_irqbase, 1); 385 1.1 jmcneill } 386 1.1 jmcneill 387 1.1 jmcneill static uint32_t 388 1.1 jmcneill gicv3_its_devid(pci_chipset_tag_t pc, pcitag_t tag) 389 1.1 jmcneill { 390 1.10 jmcneill uint32_t devid; 391 1.1 jmcneill int b, d, f; 392 1.1 jmcneill 393 1.1 jmcneill pci_decompose_tag(pc, tag, &b, &d, &f); 394 1.1 jmcneill 395 1.10 jmcneill devid = (b << 8) | (d << 3) | f; 396 1.10 jmcneill 397 1.10 jmcneill return pci_get_devid(pc, devid); 398 1.1 jmcneill } 399 1.1 jmcneill 400 1.7 jmcneill static int 401 1.7 jmcneill gicv3_its_device_map(struct gicv3_its *its, uint32_t devid, u_int count) 402 1.1 jmcneill { 403 1.1 jmcneill struct gicv3_its_device *dev; 404 1.36 jmcneill struct gicv3_its_table *itstab = &its->its_tab_device; 405 1.9 jmcneill u_int vectors; 406 1.36 jmcneill int error; 407 1.1 jmcneill 408 1.9 jmcneill vectors = MAX(2, count); 409 1.9 jmcneill while (!powerof2(vectors)) 410 1.9 jmcneill vectors++; 411 1.1 jmcneill 412 1.1 jmcneill const uint64_t typer = gits_read_8(its, GITS_TYPER); 413 1.1 jmcneill const u_int itt_entry_size = __SHIFTOUT(typer, GITS_TYPER_ITT_entry_size) + 1; 414 1.36 jmcneill const u_int itt_size = roundup(uimax(vectors, 2) * itt_entry_size, GITS_ITT_ALIGN); 415 1.1 jmcneill 416 1.9 jmcneill LIST_FOREACH(dev, &its->its_devices, dev_list) 417 1.9 jmcneill if (dev->dev_id == devid) { 418 1.9 jmcneill return itt_size <= dev->dev_size ? 0 : EEXIST; 419 1.9 jmcneill } 420 1.9 jmcneill 421 1.36 jmcneill if (itstab->tab_indirect) { 422 1.36 jmcneill uint64_t *l1_tab = itstab->tab_l1; 423 1.36 jmcneill const u_int index = devid / itstab->tab_l2_num_ids; 424 1.36 jmcneill 425 1.41 jmcneill if ((l1_tab[index] & GITS_BASER_Valid) == 0) { 426 1.41 jmcneill /* Need to allocate the L2 table. */ 427 1.41 jmcneill struct gicv3_its_page_table *pt; 428 1.41 jmcneill 429 1.41 jmcneill pt = kmem_alloc(sizeof(*pt), KM_SLEEP); 430 1.41 jmcneill pt->pt_index = index; 431 1.41 jmcneill gicv3_dma_alloc(its->its_gic, &pt->pt_dma, itstab->tab_l2_entry_size, 432 1.41 jmcneill itstab->tab_page_size); 433 1.41 jmcneill LIST_INSERT_HEAD(&itstab->tab_pt, pt, pt_list); 434 1.41 jmcneill 435 1.41 jmcneill if (!itstab->tab_shareable) { 436 1.41 jmcneill cpu_dcache_wb_range((vaddr_t)pt->pt_dma.base, 437 1.41 jmcneill itstab->tab_l2_entry_size); 438 1.41 jmcneill } 439 1.41 jmcneill l1_tab[index] = pt->pt_dma.segs[0].ds_addr | GITS_BASER_Valid; 440 1.41 jmcneill if (!itstab->tab_shareable) { 441 1.41 jmcneill cpu_dcache_wb_range((vaddr_t)&l1_tab[index], 442 1.41 jmcneill sizeof(l1_tab[index])); 443 1.41 jmcneill } 444 1.41 jmcneill dsb(sy); 445 1.41 jmcneill 446 1.41 jmcneill DPRINTF(("ITS: Allocated L2 entry at index %u\n", index)); 447 1.36 jmcneill } 448 1.36 jmcneill } 449 1.36 jmcneill 450 1.1 jmcneill dev = kmem_alloc(sizeof(*dev), KM_SLEEP); 451 1.1 jmcneill dev->dev_id = devid; 452 1.9 jmcneill dev->dev_size = itt_size; 453 1.1 jmcneill gicv3_dma_alloc(its->its_gic, &dev->dev_itt, itt_size, GITS_ITT_ALIGN); 454 1.38 jmcneill LIST_INSERT_HEAD(&its->its_devices, dev, dev_list); 455 1.36 jmcneill 456 1.36 jmcneill if (its->its_cmd_flush) { 457 1.36 jmcneill cpu_dcache_wb_range((vaddr_t)dev->dev_itt.base, itt_size); 458 1.36 jmcneill } 459 1.36 jmcneill dsb(sy); 460 1.1 jmcneill 461 1.6 jmcneill /* 462 1.6 jmcneill * Map the device to the ITT 463 1.6 jmcneill */ 464 1.40 jmcneill const u_int size = __SHIFTOUT(typer, GITS_TYPER_ID_bits) + 1; 465 1.35 tnn mutex_enter(its->its_lock); 466 1.36 jmcneill error = gits_command_mapd(its, devid, dev->dev_itt.segs[0].ds_addr, size, true); 467 1.36 jmcneill if (error == 0) { 468 1.36 jmcneill error = gits_wait(its); 469 1.36 jmcneill } 470 1.35 tnn mutex_exit(its->its_lock); 471 1.7 jmcneill 472 1.36 jmcneill return error; 473 1.1 jmcneill } 474 1.1 jmcneill 475 1.1 jmcneill static void 476 1.13 jmcneill gicv3_its_msi_enable(struct gicv3_its *its, int lpi, int count) 477 1.1 jmcneill { 478 1.1 jmcneill const struct pci_attach_args *pa = its->its_pa[lpi - its->its_pic->pic_irqbase]; 479 1.1 jmcneill pci_chipset_tag_t pc = pa->pa_pc; 480 1.1 jmcneill pcitag_t tag = pa->pa_tag; 481 1.1 jmcneill pcireg_t ctl; 482 1.1 jmcneill int off; 483 1.1 jmcneill 484 1.1 jmcneill if (!pci_get_capability(pc, tag, PCI_CAP_MSI, &off, NULL)) 485 1.1 jmcneill panic("gicv3_its_msi_enable: device is not MSI-capable"); 486 1.1 jmcneill 487 1.13 jmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL); 488 1.13 jmcneill ctl &= ~PCI_MSI_CTL_MME_MASK; 489 1.13 jmcneill ctl |= __SHIFTIN(ilog2(count), PCI_MSI_CTL_MME_MASK); 490 1.13 jmcneill pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl); 491 1.13 jmcneill 492 1.1 jmcneill const uint64_t addr = its->its_base + GITS_TRANSLATER; 493 1.1 jmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL); 494 1.1 jmcneill if (ctl & PCI_MSI_CTL_64BIT_ADDR) { 495 1.1 jmcneill pci_conf_write(pc, tag, off + PCI_MSI_MADDR64_LO, 496 1.1 jmcneill addr & 0xffffffff); 497 1.1 jmcneill pci_conf_write(pc, tag, off + PCI_MSI_MADDR64_HI, 498 1.1 jmcneill (addr >> 32) & 0xffffffff); 499 1.15 jmcneill pci_conf_write(pc, tag, off + PCI_MSI_MDATA64, 500 1.15 jmcneill lpi - its->its_pic->pic_irqbase); 501 1.1 jmcneill } else { 502 1.35 tnn KASSERT((addr >> 32) == 0); 503 1.1 jmcneill pci_conf_write(pc, tag, off + PCI_MSI_MADDR, 504 1.1 jmcneill addr & 0xffffffff); 505 1.15 jmcneill pci_conf_write(pc, tag, off + PCI_MSI_MDATA, 506 1.15 jmcneill lpi - its->its_pic->pic_irqbase); 507 1.1 jmcneill } 508 1.1 jmcneill ctl |= PCI_MSI_CTL_MSI_ENABLE; 509 1.1 jmcneill pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl); 510 1.1 jmcneill } 511 1.1 jmcneill 512 1.1 jmcneill static void 513 1.1 jmcneill gicv3_its_msi_disable(struct gicv3_its *its, int lpi) 514 1.1 jmcneill { 515 1.1 jmcneill const struct pci_attach_args *pa = its->its_pa[lpi - its->its_pic->pic_irqbase]; 516 1.1 jmcneill pci_chipset_tag_t pc = pa->pa_pc; 517 1.1 jmcneill pcitag_t tag = pa->pa_tag; 518 1.1 jmcneill pcireg_t ctl; 519 1.1 jmcneill int off; 520 1.1 jmcneill 521 1.1 jmcneill if (!pci_get_capability(pc, tag, PCI_CAP_MSI, &off, NULL)) 522 1.1 jmcneill panic("gicv3_its_msi_enable: device is not MSI-capable"); 523 1.1 jmcneill 524 1.1 jmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSI_CTL); 525 1.1 jmcneill ctl &= ~PCI_MSI_CTL_MSI_ENABLE; 526 1.1 jmcneill pci_conf_write(pc, tag, off + PCI_MSI_CTL, ctl); 527 1.1 jmcneill } 528 1.1 jmcneill 529 1.1 jmcneill static void 530 1.1 jmcneill gicv3_its_msix_enable(struct gicv3_its *its, int lpi, int msix_vec, 531 1.1 jmcneill bus_space_tag_t bst, bus_space_handle_t bsh) 532 1.1 jmcneill { 533 1.1 jmcneill const struct pci_attach_args *pa = its->its_pa[lpi - its->its_pic->pic_irqbase]; 534 1.1 jmcneill pci_chipset_tag_t pc = pa->pa_pc; 535 1.1 jmcneill pcitag_t tag = pa->pa_tag; 536 1.1 jmcneill pcireg_t ctl; 537 1.29 jmcneill uint32_t val; 538 1.1 jmcneill int off; 539 1.1 jmcneill 540 1.1 jmcneill if (!pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL)) 541 1.1 jmcneill panic("gicv3_its_msix_enable: device is not MSI-X-capable"); 542 1.1 jmcneill 543 1.1 jmcneill const uint64_t addr = its->its_base + GITS_TRANSLATER; 544 1.1 jmcneill const uint64_t entry_base = PCI_MSIX_TABLE_ENTRY_SIZE * msix_vec; 545 1.1 jmcneill bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_ADDR_LO, (uint32_t)addr); 546 1.1 jmcneill bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_ADDR_HI, (uint32_t)(addr >> 32)); 547 1.15 jmcneill bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_DATA, lpi - its->its_pic->pic_irqbase); 548 1.29 jmcneill val = bus_space_read_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_VECTCTL); 549 1.31 jmcneill val &= ~PCI_MSIX_VECTCTL_MASK; 550 1.29 jmcneill bus_space_write_4(bst, bsh, entry_base + PCI_MSIX_TABLE_ENTRY_VECTCTL, val); 551 1.1 jmcneill 552 1.1 jmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL); 553 1.1 jmcneill ctl |= PCI_MSIX_CTL_ENABLE; 554 1.1 jmcneill pci_conf_write(pc, tag, off + PCI_MSIX_CTL, ctl); 555 1.1 jmcneill } 556 1.1 jmcneill 557 1.1 jmcneill static void 558 1.1 jmcneill gicv3_its_msix_disable(struct gicv3_its *its, int lpi) 559 1.1 jmcneill { 560 1.1 jmcneill const struct pci_attach_args *pa = its->its_pa[lpi - its->its_pic->pic_irqbase]; 561 1.1 jmcneill pci_chipset_tag_t pc = pa->pa_pc; 562 1.1 jmcneill pcitag_t tag = pa->pa_tag; 563 1.1 jmcneill pcireg_t ctl; 564 1.1 jmcneill int off; 565 1.1 jmcneill 566 1.1 jmcneill if (!pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, NULL)) 567 1.1 jmcneill panic("gicv3_its_msix_disable: device is not MSI-X-capable"); 568 1.1 jmcneill 569 1.1 jmcneill ctl = pci_conf_read(pc, tag, off + PCI_MSIX_CTL); 570 1.1 jmcneill ctl &= ~PCI_MSIX_CTL_ENABLE; 571 1.1 jmcneill pci_conf_write(pc, tag, off + PCI_MSIX_CTL, ctl); 572 1.1 jmcneill } 573 1.1 jmcneill 574 1.1 jmcneill static pci_intr_handle_t * 575 1.1 jmcneill gicv3_its_msi_alloc(struct arm_pci_msi *msi, int *count, 576 1.1 jmcneill const struct pci_attach_args *pa, bool exact) 577 1.1 jmcneill { 578 1.1 jmcneill struct gicv3_its * const its = msi->msi_priv; 579 1.2 jmcneill struct cpu_info * const ci = cpu_lookup(0); 580 1.1 jmcneill pci_intr_handle_t *vectors; 581 1.36 jmcneill int n, off, error; 582 1.1 jmcneill 583 1.1 jmcneill if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSI, &off, NULL)) 584 1.1 jmcneill return NULL; 585 1.1 jmcneill 586 1.1 jmcneill const uint64_t typer = gits_read_8(its, GITS_TYPER); 587 1.1 jmcneill const u_int id_bits = __SHIFTOUT(typer, GITS_TYPER_ID_bits) + 1; 588 1.1 jmcneill if (*count == 0 || *count > (1 << id_bits)) 589 1.1 jmcneill return NULL; 590 1.1 jmcneill 591 1.1 jmcneill const uint32_t devid = gicv3_its_devid(pa->pa_pc, pa->pa_tag); 592 1.1 jmcneill 593 1.7 jmcneill if (gicv3_its_device_map(its, devid, *count) != 0) 594 1.7 jmcneill return NULL; 595 1.1 jmcneill 596 1.1 jmcneill vectors = kmem_alloc(sizeof(*vectors) * *count, KM_SLEEP); 597 1.35 tnn mutex_enter(its->its_lock); 598 1.1 jmcneill for (n = 0; n < *count; n++) { 599 1.1 jmcneill const int lpi = gicv3_its_msi_alloc_lpi(its, pa); 600 1.35 tnn KASSERT(lpi >= 0); 601 1.1 jmcneill vectors[n] = ARM_PCI_INTR_MSI | 602 1.1 jmcneill __SHIFTIN(lpi, ARM_PCI_INTR_IRQ) | 603 1.1 jmcneill __SHIFTIN(n, ARM_PCI_INTR_MSI_VEC) | 604 1.1 jmcneill __SHIFTIN(msi->msi_id, ARM_PCI_INTR_FRAME); 605 1.1 jmcneill 606 1.13 jmcneill if (n == 0) 607 1.13 jmcneill gicv3_its_msi_enable(its, lpi, *count); 608 1.1 jmcneill 609 1.1 jmcneill /* 610 1.33 skrll * Record devid and target PE 611 1.2 jmcneill */ 612 1.33 skrll its->its_devid[lpi - its->its_pic->pic_irqbase] = devid; 613 1.2 jmcneill its->its_targets[lpi - its->its_pic->pic_irqbase] = ci; 614 1.2 jmcneill 615 1.2 jmcneill /* 616 1.1 jmcneill * Map event 617 1.1 jmcneill */ 618 1.15 jmcneill gits_command_mapti(its, devid, lpi - its->its_pic->pic_irqbase, lpi, cpu_index(ci)); 619 1.1 jmcneill gits_command_sync(its, its->its_rdbase[cpu_index(ci)]); 620 1.1 jmcneill } 621 1.36 jmcneill error = gits_wait(its); 622 1.35 tnn mutex_exit(its->its_lock); 623 1.1 jmcneill 624 1.36 jmcneill if (error != 0) { 625 1.36 jmcneill kmem_free(vectors, sizeof(*vectors) * *count); 626 1.36 jmcneill vectors = NULL; 627 1.36 jmcneill } 628 1.36 jmcneill 629 1.1 jmcneill return vectors; 630 1.1 jmcneill } 631 1.1 jmcneill 632 1.1 jmcneill static pci_intr_handle_t * 633 1.1 jmcneill gicv3_its_msix_alloc(struct arm_pci_msi *msi, u_int *table_indexes, int *count, 634 1.1 jmcneill const struct pci_attach_args *pa, bool exact) 635 1.1 jmcneill { 636 1.1 jmcneill struct gicv3_its * const its = msi->msi_priv; 637 1.2 jmcneill struct cpu_info *ci = cpu_lookup(0); 638 1.1 jmcneill pci_intr_handle_t *vectors; 639 1.1 jmcneill bus_space_tag_t bst; 640 1.1 jmcneill bus_space_handle_t bsh; 641 1.1 jmcneill bus_size_t bsz; 642 1.1 jmcneill uint32_t table_offset, table_size; 643 1.1 jmcneill int n, off, bar, error; 644 1.1 jmcneill pcireg_t tbl; 645 1.1 jmcneill 646 1.1 jmcneill if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_MSIX, &off, NULL)) 647 1.1 jmcneill return NULL; 648 1.1 jmcneill 649 1.1 jmcneill const uint64_t typer = gits_read_8(its, GITS_TYPER); 650 1.1 jmcneill const u_int id_bits = __SHIFTOUT(typer, GITS_TYPER_ID_bits) + 1; 651 1.1 jmcneill if (*count == 0 || *count > (1 << id_bits)) 652 1.1 jmcneill return NULL; 653 1.1 jmcneill 654 1.1 jmcneill tbl = pci_conf_read(pa->pa_pc, pa->pa_tag, off + PCI_MSIX_TBLOFFSET); 655 1.22 msaitoh bar = PCI_BAR0 + (4 * (tbl & PCI_MSIX_TBLBIR_MASK)); 656 1.1 jmcneill table_offset = tbl & PCI_MSIX_TBLOFFSET_MASK; 657 1.1 jmcneill table_size = pci_msix_count(pa->pa_pc, pa->pa_tag) * PCI_MSIX_TABLE_ENTRY_SIZE; 658 1.1 jmcneill if (table_size == 0) 659 1.1 jmcneill return NULL; 660 1.1 jmcneill 661 1.1 jmcneill error = pci_mapreg_submap(pa, bar, pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar), 662 1.1 jmcneill BUS_SPACE_MAP_LINEAR, roundup(table_size, PAGE_SIZE), table_offset, 663 1.1 jmcneill &bst, &bsh, NULL, &bsz); 664 1.1 jmcneill if (error) 665 1.1 jmcneill return NULL; 666 1.1 jmcneill 667 1.1 jmcneill const uint32_t devid = gicv3_its_devid(pa->pa_pc, pa->pa_tag); 668 1.1 jmcneill 669 1.7 jmcneill if (gicv3_its_device_map(its, devid, *count) != 0) { 670 1.7 jmcneill bus_space_unmap(bst, bsh, bsz); 671 1.7 jmcneill return NULL; 672 1.7 jmcneill } 673 1.1 jmcneill 674 1.1 jmcneill vectors = kmem_alloc(sizeof(*vectors) * *count, KM_SLEEP); 675 1.35 tnn mutex_enter(its->its_lock); 676 1.1 jmcneill for (n = 0; n < *count; n++) { 677 1.1 jmcneill const int lpi = gicv3_its_msi_alloc_lpi(its, pa); 678 1.35 tnn KASSERT(lpi >= 0); 679 1.1 jmcneill const int msix_vec = table_indexes ? table_indexes[n] : n; 680 1.1 jmcneill vectors[msix_vec] = ARM_PCI_INTR_MSIX | 681 1.1 jmcneill __SHIFTIN(lpi, ARM_PCI_INTR_IRQ) | 682 1.1 jmcneill __SHIFTIN(msix_vec, ARM_PCI_INTR_MSI_VEC) | 683 1.1 jmcneill __SHIFTIN(msi->msi_id, ARM_PCI_INTR_FRAME); 684 1.1 jmcneill 685 1.1 jmcneill gicv3_its_msix_enable(its, lpi, msix_vec, bst, bsh); 686 1.1 jmcneill 687 1.1 jmcneill /* 688 1.33 skrll * Record devid and target PE 689 1.2 jmcneill */ 690 1.33 skrll its->its_devid[lpi - its->its_pic->pic_irqbase] = devid; 691 1.2 jmcneill its->its_targets[lpi - its->its_pic->pic_irqbase] = ci; 692 1.2 jmcneill 693 1.2 jmcneill /* 694 1.1 jmcneill * Map event 695 1.1 jmcneill */ 696 1.15 jmcneill gits_command_mapti(its, devid, lpi - its->its_pic->pic_irqbase, lpi, cpu_index(ci)); 697 1.1 jmcneill gits_command_sync(its, its->its_rdbase[cpu_index(ci)]); 698 1.1 jmcneill } 699 1.1 jmcneill gits_wait(its); 700 1.35 tnn mutex_exit(its->its_lock); 701 1.1 jmcneill 702 1.1 jmcneill bus_space_unmap(bst, bsh, bsz); 703 1.1 jmcneill 704 1.1 jmcneill return vectors; 705 1.1 jmcneill } 706 1.1 jmcneill 707 1.1 jmcneill static void * 708 1.1 jmcneill gicv3_its_msi_intr_establish(struct arm_pci_msi *msi, 709 1.3 jmcneill pci_intr_handle_t ih, int ipl, int (*func)(void *), void *arg, const char *xname) 710 1.1 jmcneill { 711 1.1 jmcneill struct gicv3_its * const its = msi->msi_priv; 712 1.1 jmcneill void *intrh; 713 1.1 jmcneill 714 1.1 jmcneill const int lpi = __SHIFTOUT(ih, ARM_PCI_INTR_IRQ); 715 1.1 jmcneill const int mpsafe = (ih & ARM_PCI_INTR_MPSAFE) ? IST_MPSAFE : 0; 716 1.1 jmcneill 717 1.1 jmcneill intrh = pic_establish_intr(its->its_pic, lpi - its->its_pic->pic_irqbase, ipl, 718 1.3 jmcneill IST_EDGE | mpsafe, func, arg, xname); 719 1.1 jmcneill if (intrh == NULL) 720 1.1 jmcneill return NULL; 721 1.1 jmcneill 722 1.1 jmcneill /* Invalidate LPI configuration tables */ 723 1.34 skrll KASSERT(its->its_pa[lpi - its->its_pic->pic_irqbase] != NULL); 724 1.33 skrll const uint32_t devid = its->its_devid[lpi - its->its_pic->pic_irqbase]; 725 1.17 jmcneill gits_command_inv(its, devid, lpi - its->its_pic->pic_irqbase); 726 1.1 jmcneill 727 1.1 jmcneill return intrh; 728 1.1 jmcneill } 729 1.1 jmcneill 730 1.1 jmcneill static void 731 1.1 jmcneill gicv3_its_msi_intr_release(struct arm_pci_msi *msi, pci_intr_handle_t *pih, 732 1.1 jmcneill int count) 733 1.1 jmcneill { 734 1.1 jmcneill struct gicv3_its * const its = msi->msi_priv; 735 1.1 jmcneill int n; 736 1.1 jmcneill 737 1.1 jmcneill for (n = 0; n < count; n++) { 738 1.1 jmcneill const int lpi = __SHIFTOUT(pih[n], ARM_PCI_INTR_IRQ); 739 1.1 jmcneill KASSERT(lpi >= its->its_pic->pic_irqbase); 740 1.1 jmcneill if (pih[n] & ARM_PCI_INTR_MSIX) 741 1.1 jmcneill gicv3_its_msix_disable(its, lpi); 742 1.1 jmcneill if (pih[n] & ARM_PCI_INTR_MSI) 743 1.1 jmcneill gicv3_its_msi_disable(its, lpi); 744 1.1 jmcneill gicv3_its_msi_free_lpi(its, lpi); 745 1.2 jmcneill its->its_targets[lpi - its->its_pic->pic_irqbase] = NULL; 746 1.33 skrll its->its_devid[lpi - its->its_pic->pic_irqbase] = 0; 747 1.1 jmcneill struct intrsource * const is = 748 1.1 jmcneill its->its_pic->pic_sources[lpi - its->its_pic->pic_irqbase]; 749 1.1 jmcneill if (is != NULL) 750 1.1 jmcneill pic_disestablish_source(is); 751 1.1 jmcneill } 752 1.1 jmcneill } 753 1.1 jmcneill 754 1.1 jmcneill static void 755 1.1 jmcneill gicv3_its_command_init(struct gicv3_softc *sc, struct gicv3_its *its) 756 1.1 jmcneill { 757 1.36 jmcneill uint64_t cbaser, tmp; 758 1.1 jmcneill 759 1.1 jmcneill gicv3_dma_alloc(sc, &its->its_cmd, GITS_COMMANDS_SIZE, GITS_COMMANDS_ALIGN); 760 1.36 jmcneill if (its->its_cmd_flush) { 761 1.36 jmcneill cpu_dcache_wb_range((vaddr_t)its->its_cmd.base, GITS_COMMANDS_SIZE); 762 1.36 jmcneill } 763 1.36 jmcneill dsb(sy); 764 1.1 jmcneill 765 1.35 tnn KASSERT((gits_read_4(its, GITS_CTLR) & GITS_CTLR_Enabled) == 0); 766 1.35 tnn KASSERT((gits_read_4(its, GITS_CTLR) & GITS_CTLR_Quiescent) != 0); 767 1.35 tnn 768 1.1 jmcneill cbaser = its->its_cmd.segs[0].ds_addr; 769 1.1 jmcneill cbaser |= __SHIFTIN((its->its_cmd.len / 4096) - 1, GITS_CBASER_Size); 770 1.1 jmcneill cbaser |= GITS_CBASER_Valid; 771 1.1 jmcneill 772 1.36 jmcneill cbaser |= __SHIFTIN(GITS_Cache_NORMAL_WA_WB, GITS_CBASER_InnerCache); 773 1.36 jmcneill cbaser |= __SHIFTIN(GITS_Shareability_IS, GITS_CBASER_Shareability); 774 1.36 jmcneill gits_write_8(its, GITS_CBASER, cbaser); 775 1.36 jmcneill 776 1.36 jmcneill tmp = gits_read_8(its, GITS_CBASER); 777 1.36 jmcneill if (__SHIFTOUT(tmp, GITS_CBASER_Shareability) != GITS_Shareability_IS) { 778 1.36 jmcneill if (__SHIFTOUT(tmp, GITS_CBASER_InnerCache) == GITS_Shareability_NS) { 779 1.36 jmcneill cbaser &= ~GITS_CBASER_InnerCache; 780 1.36 jmcneill cbaser |= __SHIFTIN(GITS_Cache_NORMAL_NC, GITS_CBASER_InnerCache); 781 1.36 jmcneill cbaser &= ~GITS_CBASER_Shareability; 782 1.36 jmcneill cbaser |= __SHIFTIN(GITS_Shareability_NS, GITS_CBASER_Shareability); 783 1.36 jmcneill gits_write_8(its, GITS_CBASER, cbaser); 784 1.36 jmcneill } 785 1.36 jmcneill 786 1.36 jmcneill its->its_cmd_flush = true; 787 1.36 jmcneill } 788 1.39 skrll aprint_normal_dev(sc->sc_dev, "ITS command table @ %#lx/%#lx, %s, %s\n", 789 1.39 skrll its->its_cmd.segs[0].ds_addr, its->its_cmd.len, 790 1.39 skrll gits_cache_type[__SHIFTOUT(cbaser, GITS_BASER_InnerCache)], 791 1.39 skrll gits_share_type[__SHIFTOUT(cbaser, GITS_BASER_Shareability)]); 792 1.36 jmcneill 793 1.35 tnn gits_write_8(its, GITS_CWRITER, 0); 794 1.1 jmcneill } 795 1.1 jmcneill 796 1.1 jmcneill static void 797 1.21 jmcneill gicv3_its_table_params(struct gicv3_softc *sc, struct gicv3_its *its, 798 1.21 jmcneill u_int *devbits, u_int *innercache, u_int *share) 799 1.21 jmcneill { 800 1.21 jmcneill 801 1.21 jmcneill const uint64_t typer = gits_read_8(its, GITS_TYPER); 802 1.21 jmcneill const uint32_t iidr = gits_read_4(its, GITS_IIDR); 803 1.21 jmcneill 804 1.21 jmcneill /* Default values */ 805 1.21 jmcneill *devbits = __SHIFTOUT(typer, GITS_TYPER_Devbits) + 1; 806 1.21 jmcneill *innercache = GITS_Cache_NORMAL_WA_WB; 807 1.21 jmcneill *share = GITS_Shareability_IS; 808 1.21 jmcneill 809 1.21 jmcneill /* Cavium ThunderX errata */ 810 1.21 jmcneill if ((iidr & GITS_IIDR_CAVIUM_ERRATA_MASK) == GITS_IIDR_CAVIUM_ERRATA_VALUE) { 811 1.21 jmcneill *devbits = 20; /* 8Mb */ 812 1.21 jmcneill *innercache = GITS_Cache_DEVICE_nGnRnE; 813 1.21 jmcneill aprint_normal_dev(sc->sc_dev, "Cavium ThunderX errata detected\n"); 814 1.21 jmcneill } 815 1.21 jmcneill } 816 1.21 jmcneill 817 1.36 jmcneill static bool 818 1.36 jmcneill gicv3_its_table_probe_indirect(struct gicv3_its *its, int tab) 819 1.36 jmcneill { 820 1.36 jmcneill uint64_t baser; 821 1.36 jmcneill 822 1.36 jmcneill baser = gits_read_8(its, GITS_BASERn(tab)); 823 1.36 jmcneill baser |= GITS_BASER_Indirect; 824 1.36 jmcneill gits_write_8(its, GITS_BASERn(tab), baser); 825 1.36 jmcneill 826 1.36 jmcneill baser = gits_read_8(its, GITS_BASERn(tab)); 827 1.36 jmcneill 828 1.36 jmcneill return (baser & GITS_BASER_Indirect) != 0; 829 1.36 jmcneill } 830 1.36 jmcneill 831 1.21 jmcneill static void 832 1.1 jmcneill gicv3_its_table_init(struct gicv3_softc *sc, struct gicv3_its *its) 833 1.1 jmcneill { 834 1.36 jmcneill u_int page_size, table_align; 835 1.21 jmcneill u_int devbits, innercache, share; 836 1.21 jmcneill const char *table_type; 837 1.1 jmcneill uint64_t baser; 838 1.1 jmcneill int tab; 839 1.1 jmcneill 840 1.21 jmcneill gicv3_its_table_params(sc, its, &devbits, &innercache, &share); 841 1.1 jmcneill 842 1.36 jmcneill DPRINTF(("ITS: devbits = %u\n", devbits)); 843 1.36 jmcneill 844 1.1 jmcneill for (tab = 0; tab < 8; tab++) { 845 1.36 jmcneill struct gicv3_its_table *itstab; 846 1.36 jmcneill bool indirect = false; 847 1.36 jmcneill uint64_t l1_entry_size, l2_entry_size; 848 1.36 jmcneill uint64_t l1_num_ids, l2_num_ids; 849 1.36 jmcneill uint64_t table_size; 850 1.36 jmcneill 851 1.1 jmcneill baser = gits_read_8(its, GITS_BASERn(tab)); 852 1.1 jmcneill 853 1.36 jmcneill l1_entry_size = __SHIFTOUT(baser, GITS_BASER_Entry_Size) + 1; 854 1.36 jmcneill l2_entry_size = 0; 855 1.36 jmcneill l2_num_ids = 0; 856 1.1 jmcneill 857 1.40 jmcneill switch (__SHIFTOUT(baser, GITS_BASER_Page_Size)) { 858 1.40 jmcneill case GITS_Page_Size_64KB: 859 1.40 jmcneill page_size = 65536; 860 1.40 jmcneill break; 861 1.40 jmcneill case GITS_Page_Size_16KB: 862 1.40 jmcneill page_size = 16384; 863 1.40 jmcneill break; 864 1.40 jmcneill case GITS_Page_Size_4KB: 865 1.40 jmcneill default: 866 1.40 jmcneill page_size = 4096; 867 1.40 jmcneill } 868 1.40 jmcneill table_align = page_size; 869 1.1 jmcneill 870 1.1 jmcneill switch (__SHIFTOUT(baser, GITS_BASER_Type)) { 871 1.1 jmcneill case GITS_Type_Devices: 872 1.1 jmcneill /* 873 1.1 jmcneill * Table size scales with the width of the DeviceID. 874 1.1 jmcneill */ 875 1.36 jmcneill l1_num_ids = 1ULL << devbits; 876 1.36 jmcneill DPRINTF(("ITS: l1_num_ids = %lu\n", l1_num_ids)); 877 1.36 jmcneill indirect = 878 1.36 jmcneill gicv3_its_table_probe_indirect(its, tab); 879 1.36 jmcneill if (indirect) { 880 1.36 jmcneill DPRINTF(("ITS: indirect\n")); 881 1.36 jmcneill l2_entry_size = l1_entry_size; 882 1.36 jmcneill l2_num_ids = page_size / l2_entry_size; 883 1.36 jmcneill l1_num_ids = l1_num_ids / l2_num_ids; 884 1.36 jmcneill l1_entry_size = GITS_INDIRECT_ENTRY_SIZE; 885 1.36 jmcneill } 886 1.36 jmcneill table_size = roundup2(l1_entry_size * l1_num_ids, page_size); 887 1.36 jmcneill if (howmany(table_size, page_size) > GITS_BASER_Size + 1) { 888 1.36 jmcneill DPRINTF(("ITS: clamp table size 0x%lx -> ", table_size)); 889 1.36 jmcneill table_size = (GITS_BASER_Size + 1) * page_size; 890 1.36 jmcneill DPRINTF(("0x%lx\n", table_size)); 891 1.36 jmcneill } 892 1.21 jmcneill table_type = "Devices"; 893 1.36 jmcneill 894 1.36 jmcneill DPRINTF(("ITS: table_size is 0x%lx\n", table_size)); 895 1.36 jmcneill 896 1.36 jmcneill itstab = &its->its_tab_device; 897 1.36 jmcneill itstab->tab_page_size = page_size; 898 1.36 jmcneill itstab->tab_l1_entry_size = l1_entry_size; 899 1.36 jmcneill itstab->tab_l1_num_ids = l1_num_ids; 900 1.36 jmcneill itstab->tab_l2_entry_size = l2_entry_size; 901 1.36 jmcneill itstab->tab_l2_num_ids = l2_num_ids; 902 1.36 jmcneill itstab->tab_indirect = indirect; 903 1.36 jmcneill LIST_INIT(&itstab->tab_pt); 904 1.1 jmcneill break; 905 1.1 jmcneill case GITS_Type_InterruptCollections: 906 1.1 jmcneill /* 907 1.1 jmcneill * Allocate space for one interrupt collection per CPU. 908 1.1 jmcneill */ 909 1.36 jmcneill table_size = roundup(l1_entry_size * ncpu, page_size); 910 1.21 jmcneill table_type = "Collections"; 911 1.1 jmcneill break; 912 1.1 jmcneill default: 913 1.1 jmcneill table_size = 0; 914 1.1 jmcneill break; 915 1.1 jmcneill } 916 1.1 jmcneill 917 1.1 jmcneill if (table_size == 0) 918 1.1 jmcneill continue; 919 1.1 jmcneill 920 1.1 jmcneill gicv3_dma_alloc(sc, &its->its_tab[tab], table_size, table_align); 921 1.36 jmcneill if (its->its_cmd_flush) { 922 1.36 jmcneill cpu_dcache_wb_range((vaddr_t)its->its_tab[tab].base, table_size); 923 1.36 jmcneill } 924 1.36 jmcneill dsb(sy); 925 1.1 jmcneill 926 1.1 jmcneill baser &= ~GITS_BASER_Size; 927 1.36 jmcneill baser |= __SHIFTIN(howmany(table_size, page_size) - 1, GITS_BASER_Size); 928 1.1 jmcneill baser &= ~GITS_BASER_Physical_Address; 929 1.1 jmcneill baser |= its->its_tab[tab].segs[0].ds_addr; 930 1.1 jmcneill baser &= ~GITS_BASER_InnerCache; 931 1.8 skrll baser |= __SHIFTIN(innercache, GITS_BASER_InnerCache); 932 1.1 jmcneill baser &= ~GITS_BASER_Shareability; 933 1.20 jmcneill baser |= __SHIFTIN(share, GITS_BASER_Shareability); 934 1.1 jmcneill baser |= GITS_BASER_Valid; 935 1.36 jmcneill if (indirect) { 936 1.36 jmcneill baser |= GITS_BASER_Indirect; 937 1.36 jmcneill } else { 938 1.36 jmcneill baser &= ~GITS_BASER_Indirect; 939 1.36 jmcneill } 940 1.8 skrll 941 1.1 jmcneill gits_write_8(its, GITS_BASERn(tab), baser); 942 1.20 jmcneill 943 1.20 jmcneill baser = gits_read_8(its, GITS_BASERn(tab)); 944 1.20 jmcneill if (__SHIFTOUT(baser, GITS_BASER_Shareability) == GITS_Shareability_NS) { 945 1.20 jmcneill baser &= ~GITS_BASER_InnerCache; 946 1.20 jmcneill baser |= __SHIFTIN(GITS_Cache_NORMAL_NC, GITS_BASER_InnerCache); 947 1.20 jmcneill 948 1.20 jmcneill gits_write_8(its, GITS_BASERn(tab), baser); 949 1.20 jmcneill } 950 1.21 jmcneill 951 1.21 jmcneill baser = gits_read_8(its, GITS_BASERn(tab)); 952 1.36 jmcneill aprint_normal_dev(sc->sc_dev, "ITS [#%d] %s table @ %#lx/%#lx, %s, %s%s\n", 953 1.21 jmcneill tab, table_type, its->its_tab[tab].segs[0].ds_addr, table_size, 954 1.21 jmcneill gits_cache_type[__SHIFTOUT(baser, GITS_BASER_InnerCache)], 955 1.36 jmcneill gits_share_type[__SHIFTOUT(baser, GITS_BASER_Shareability)], 956 1.36 jmcneill indirect ? ", indirect" : ""); 957 1.36 jmcneill 958 1.36 jmcneill if (__SHIFTOUT(baser, GITS_BASER_Type) == GITS_Type_Devices) { 959 1.36 jmcneill its->its_tab_device.tab_l1 = its->its_tab[tab].base; 960 1.36 jmcneill its->its_tab_device.tab_shareable = 961 1.36 jmcneill __SHIFTOUT(baser, GITS_BASER_Shareability) != GITS_Shareability_NS; 962 1.36 jmcneill } 963 1.36 jmcneill 964 1.1 jmcneill } 965 1.1 jmcneill } 966 1.1 jmcneill 967 1.1 jmcneill static void 968 1.1 jmcneill gicv3_its_enable(struct gicv3_softc *sc, struct gicv3_its *its) 969 1.1 jmcneill { 970 1.1 jmcneill uint32_t ctlr; 971 1.1 jmcneill 972 1.1 jmcneill ctlr = gits_read_4(its, GITS_CTLR); 973 1.1 jmcneill ctlr |= GITS_CTLR_Enabled; 974 1.1 jmcneill gits_write_4(its, GITS_CTLR, ctlr); 975 1.1 jmcneill } 976 1.1 jmcneill 977 1.1 jmcneill static void 978 1.1 jmcneill gicv3_its_cpu_init(void *priv, struct cpu_info *ci) 979 1.1 jmcneill { 980 1.1 jmcneill struct gicv3_its * const its = priv; 981 1.1 jmcneill struct gicv3_softc * const sc = its->its_gic; 982 1.1 jmcneill uint64_t rdbase; 983 1.12 jmcneill size_t irq; 984 1.1 jmcneill 985 1.1 jmcneill const uint64_t typer = bus_space_read_8(sc->sc_bst, its->its_bsh, GITS_TYPER); 986 1.1 jmcneill if (typer & GITS_TYPER_PTA) { 987 1.1 jmcneill void *va = bus_space_vaddr(sc->sc_bst, sc->sc_bsh_r[ci->ci_gic_redist]); 988 1.1 jmcneill rdbase = vtophys((vaddr_t)va); 989 1.1 jmcneill } else { 990 1.1 jmcneill rdbase = (uint64_t)sc->sc_processor_id[cpu_index(ci)] << 16; 991 1.1 jmcneill } 992 1.1 jmcneill its->its_rdbase[cpu_index(ci)] = rdbase; 993 1.1 jmcneill 994 1.1 jmcneill /* 995 1.1 jmcneill * Map collection ID of this CPU's index to this CPU's redistributor. 996 1.1 jmcneill */ 997 1.33 skrll mutex_enter(its->its_lock); 998 1.1 jmcneill gits_command_mapc(its, cpu_index(ci), rdbase, true); 999 1.1 jmcneill gits_command_invall(its, cpu_index(ci)); 1000 1.1 jmcneill gits_wait(its); 1001 1.11 jmcneill 1002 1.12 jmcneill /* 1003 1.12 jmcneill * Update routing for LPIs targetting this CPU 1004 1.12 jmcneill */ 1005 1.12 jmcneill for (irq = 0; irq < its->its_pic->pic_maxsources; irq++) { 1006 1.12 jmcneill if (its->its_targets[irq] != ci) 1007 1.12 jmcneill continue; 1008 1.34 skrll KASSERT(its->its_pa[irq] != NULL); 1009 1.12 jmcneill 1010 1.33 skrll const uint32_t devid = its->its_devid[irq]; 1011 1.17 jmcneill gits_command_movi(its, devid, irq, cpu_index(ci)); 1012 1.12 jmcneill gits_command_sync(its, its->its_rdbase[cpu_index(ci)]); 1013 1.12 jmcneill } 1014 1.33 skrll gits_wait(its); 1015 1.33 skrll mutex_exit(its->its_lock); 1016 1.12 jmcneill 1017 1.11 jmcneill its->its_cpuonline[cpu_index(ci)] = true; 1018 1.1 jmcneill } 1019 1.1 jmcneill 1020 1.2 jmcneill static void 1021 1.2 jmcneill gicv3_its_get_affinity(void *priv, size_t irq, kcpuset_t *affinity) 1022 1.2 jmcneill { 1023 1.2 jmcneill struct gicv3_its * const its = priv; 1024 1.2 jmcneill struct cpu_info *ci; 1025 1.2 jmcneill 1026 1.5 jakllsch ci = its->its_targets[irq]; 1027 1.2 jmcneill if (ci) 1028 1.2 jmcneill kcpuset_set(affinity, cpu_index(ci)); 1029 1.2 jmcneill } 1030 1.2 jmcneill 1031 1.2 jmcneill static int 1032 1.2 jmcneill gicv3_its_set_affinity(void *priv, size_t irq, const kcpuset_t *affinity) 1033 1.2 jmcneill { 1034 1.2 jmcneill struct gicv3_its * const its = priv; 1035 1.2 jmcneill const struct pci_attach_args *pa; 1036 1.2 jmcneill struct cpu_info *ci; 1037 1.2 jmcneill 1038 1.2 jmcneill const int set = kcpuset_countset(affinity); 1039 1.2 jmcneill if (set != 1) 1040 1.2 jmcneill return EINVAL; 1041 1.2 jmcneill 1042 1.5 jakllsch pa = its->its_pa[irq]; 1043 1.2 jmcneill if (pa == NULL) 1044 1.27 jmcneill return EPASSTHROUGH; 1045 1.2 jmcneill 1046 1.4 jmcneill ci = cpu_lookup(kcpuset_ffs(affinity) - 1); 1047 1.12 jmcneill its->its_targets[irq] = ci; 1048 1.2 jmcneill 1049 1.12 jmcneill if (its->its_cpuonline[cpu_index(ci)] == true) { 1050 1.12 jmcneill const uint32_t devid = gicv3_its_devid(pa->pa_pc, pa->pa_tag); 1051 1.35 tnn mutex_enter(its->its_lock); 1052 1.17 jmcneill gits_command_movi(its, devid, irq, cpu_index(ci)); 1053 1.12 jmcneill gits_command_sync(its, its->its_rdbase[cpu_index(ci)]); 1054 1.35 tnn mutex_exit(its->its_lock); 1055 1.12 jmcneill } 1056 1.2 jmcneill 1057 1.2 jmcneill return 0; 1058 1.2 jmcneill } 1059 1.2 jmcneill 1060 1.1 jmcneill int 1061 1.1 jmcneill gicv3_its_init(struct gicv3_softc *sc, bus_space_handle_t bsh, 1062 1.1 jmcneill uint64_t its_base, uint32_t its_id) 1063 1.1 jmcneill { 1064 1.1 jmcneill struct gicv3_its *its; 1065 1.1 jmcneill struct arm_pci_msi *msi; 1066 1.1 jmcneill 1067 1.1 jmcneill const uint64_t typer = bus_space_read_8(sc->sc_bst, bsh, GITS_TYPER); 1068 1.1 jmcneill if ((typer & GITS_TYPER_Physical) == 0) 1069 1.1 jmcneill return ENXIO; 1070 1.1 jmcneill 1071 1.25 jmcneill its = kmem_zalloc(sizeof(*its), KM_SLEEP); 1072 1.1 jmcneill its->its_id = its_id; 1073 1.1 jmcneill its->its_bst = sc->sc_bst; 1074 1.1 jmcneill its->its_bsh = bsh; 1075 1.1 jmcneill its->its_dmat = sc->sc_dmat; 1076 1.1 jmcneill its->its_base = its_base; 1077 1.1 jmcneill its->its_pic = &sc->sc_lpi; 1078 1.18 jmcneill snprintf(its->its_pic->pic_name, sizeof(its->its_pic->pic_name), "gicv3-its"); 1079 1.1 jmcneill KASSERT(its->its_pic->pic_maxsources > 0); 1080 1.1 jmcneill its->its_pa = kmem_zalloc(sizeof(struct pci_attach_args *) * its->its_pic->pic_maxsources, KM_SLEEP); 1081 1.2 jmcneill its->its_targets = kmem_zalloc(sizeof(struct cpu_info *) * its->its_pic->pic_maxsources, KM_SLEEP); 1082 1.33 skrll its->its_devid = kmem_zalloc(sizeof(uint32_t) * its->its_pic->pic_maxsources, KM_SLEEP); 1083 1.1 jmcneill its->its_gic = sc; 1084 1.32 jmcneill its->its_rdbase = kmem_zalloc(sizeof(*its->its_rdbase) * ncpu, KM_SLEEP); 1085 1.32 jmcneill its->its_cpuonline = kmem_zalloc(sizeof(*its->its_cpuonline) * ncpu, KM_SLEEP); 1086 1.2 jmcneill its->its_cb.cpu_init = gicv3_its_cpu_init; 1087 1.2 jmcneill its->its_cb.get_affinity = gicv3_its_get_affinity; 1088 1.2 jmcneill its->its_cb.set_affinity = gicv3_its_set_affinity; 1089 1.2 jmcneill its->its_cb.priv = its; 1090 1.1 jmcneill LIST_INIT(&its->its_devices); 1091 1.2 jmcneill LIST_INSERT_HEAD(&sc->sc_lpi_callbacks, &its->its_cb, list); 1092 1.33 skrll its->its_lock = mutex_obj_alloc(MUTEX_SPIN, IPL_NONE); 1093 1.1 jmcneill 1094 1.1 jmcneill gicv3_its_command_init(sc, its); 1095 1.1 jmcneill gicv3_its_table_init(sc, its); 1096 1.1 jmcneill 1097 1.1 jmcneill gicv3_its_enable(sc, its); 1098 1.1 jmcneill 1099 1.1 jmcneill gicv3_its_cpu_init(its, curcpu()); 1100 1.1 jmcneill 1101 1.1 jmcneill msi = &its->its_msi; 1102 1.24 jmcneill msi->msi_id = its_id; 1103 1.1 jmcneill msi->msi_dev = sc->sc_dev; 1104 1.1 jmcneill msi->msi_priv = its; 1105 1.1 jmcneill msi->msi_alloc = gicv3_its_msi_alloc; 1106 1.1 jmcneill msi->msix_alloc = gicv3_its_msix_alloc; 1107 1.1 jmcneill msi->msi_intr_establish = gicv3_its_msi_intr_establish; 1108 1.1 jmcneill msi->msi_intr_release = gicv3_its_msi_intr_release; 1109 1.1 jmcneill 1110 1.1 jmcneill return arm_pci_msi_add(msi); 1111 1.1 jmcneill } 1112