1301265Sandrew/*- 2301265Sandrew * Copyright (c) 2015-2016 The FreeBSD Foundation 3301265Sandrew * All rights reserved. 4301265Sandrew * 5301265Sandrew * This software was developed by Andrew Turner under 6301265Sandrew * the sponsorship of the FreeBSD Foundation. 7301265Sandrew * 8301265Sandrew * This software was developed by Semihalf under 9301265Sandrew * the sponsorship of the FreeBSD Foundation. 10301265Sandrew * 11301265Sandrew * Redistribution and use in source and binary forms, with or without 12301265Sandrew * modification, are permitted provided that the following conditions 13301265Sandrew * are met: 14301265Sandrew * 1. Redistributions of source code must retain the above copyright 15301265Sandrew * notice, this list of conditions and the following disclaimer. 16301265Sandrew * 2. Redistributions in binary form must reproduce the above copyright 17301265Sandrew * notice, this list of conditions and the following disclaimer in the 18301265Sandrew * documentation and/or other materials provided with the distribution. 19301265Sandrew * 20301265Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21301265Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22301265Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23301265Sandrew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24301265Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25301265Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26301265Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27301265Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28301265Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29301265Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30301265Sandrew * SUCH DAMAGE. 31301265Sandrew */ 32301265Sandrew 33301265Sandrew#include "opt_platform.h" 34301265Sandrew 35301265Sandrew#include <sys/cdefs.h> 36301265Sandrew__FBSDID("$FreeBSD$"); 37301265Sandrew 38301265Sandrew#include <sys/param.h> 39301265Sandrew#include <sys/systm.h> 40301265Sandrew#include <sys/bus.h> 41301265Sandrew#include <sys/cpuset.h> 42301265Sandrew#include <sys/endian.h> 43301265Sandrew#include <sys/kernel.h> 44301265Sandrew#include <sys/malloc.h> 45301265Sandrew#include <sys/module.h> 46301265Sandrew#include <sys/proc.h> 47301265Sandrew#include <sys/queue.h> 48301265Sandrew#include <sys/rman.h> 49301265Sandrew#include <sys/smp.h> 50301265Sandrew#include <sys/vmem.h> 51301265Sandrew 52301265Sandrew#include <vm/vm.h> 53301265Sandrew#include <vm/pmap.h> 54301265Sandrew 55301265Sandrew#include <machine/bus.h> 56301265Sandrew#include <machine/intr.h> 57301265Sandrew 58301265Sandrew#include <arm64/arm64/gic_v3_reg.h> 59301265Sandrew#include <arm64/arm64/gic_v3_var.h> 60301265Sandrew 61301265Sandrew#ifdef FDT 62301265Sandrew#include <dev/ofw/openfirm.h> 63301265Sandrew#include <dev/ofw/ofw_bus.h> 64301265Sandrew#include <dev/ofw/ofw_bus_subr.h> 65301265Sandrew#endif 66301265Sandrew#include <dev/pci/pcireg.h> 67301265Sandrew#include <dev/pci/pcivar.h> 68301265Sandrew 69301265Sandrew#include "pcib_if.h" 70301265Sandrew#include "pic_if.h" 71301265Sandrew#include "msi_if.h" 72301265Sandrew 73301265SandrewMALLOC_DEFINE(M_GICV3_ITS, "GICv3 ITS", 74301265Sandrew "ARM GICv3 Interrupt Translation Service"); 75301265Sandrew 76301265Sandrew#define LPI_NIRQS (64 * 1024) 77301265Sandrew 78301265Sandrew/* The size and alignment of the command circular buffer */ 79301265Sandrew#define ITS_CMDQ_SIZE (64 * 1024) /* Must be a multiple of 4K */ 80301265Sandrew#define ITS_CMDQ_ALIGN (64 * 1024) 81301265Sandrew 82301265Sandrew#define LPI_CONFTAB_SIZE LPI_NIRQS 83301265Sandrew#define LPI_CONFTAB_ALIGN (64 * 1024) 84301265Sandrew#define LPI_CONFTAB_MAX_ADDR ((1ul << 48) - 1) /* We need a 47 bit PA */ 85301265Sandrew 86301265Sandrew/* 1 bit per SPI, PPI, and SGI (8k), and 1 bit per LPI (LPI_CONFTAB_SIZE) */ 87301265Sandrew#define LPI_PENDTAB_SIZE ((LPI_NIRQS + GIC_FIRST_LPI) / 8) 88301265Sandrew#define LPI_PENDTAB_ALIGN (64 * 1024) 89301265Sandrew#define LPI_PENDTAB_MAX_ADDR ((1ul << 48) - 1) /* We need a 47 bit PA */ 90301265Sandrew 91301265Sandrew#define LPI_INT_TRANS_TAB_ALIGN 256 92301265Sandrew#define LPI_INT_TRANS_TAB_MAX_ADDR ((1ul << 48) - 1) 93301265Sandrew 94301265Sandrew/* ITS commands encoding */ 95301265Sandrew#define ITS_CMD_MOVI (0x01) 96301265Sandrew#define ITS_CMD_SYNC (0x05) 97301265Sandrew#define ITS_CMD_MAPD (0x08) 98301265Sandrew#define ITS_CMD_MAPC (0x09) 99301265Sandrew#define ITS_CMD_MAPTI (0x0a) 100301265Sandrew#define ITS_CMD_MAPI (0x0b) 101301265Sandrew#define ITS_CMD_INV (0x0c) 102301265Sandrew#define ITS_CMD_INVALL (0x0d) 103301265Sandrew/* Command */ 104301265Sandrew#define CMD_COMMAND_MASK (0xFFUL) 105301265Sandrew/* PCI device ID */ 106301265Sandrew#define CMD_DEVID_SHIFT (32) 107301265Sandrew#define CMD_DEVID_MASK (0xFFFFFFFFUL << CMD_DEVID_SHIFT) 108301265Sandrew/* Size of IRQ ID bitfield */ 109301265Sandrew#define CMD_SIZE_MASK (0xFFUL) 110301265Sandrew/* Virtual LPI ID */ 111301265Sandrew#define CMD_ID_MASK (0xFFFFFFFFUL) 112301265Sandrew/* Physical LPI ID */ 113301265Sandrew#define CMD_PID_SHIFT (32) 114301265Sandrew#define CMD_PID_MASK (0xFFFFFFFFUL << CMD_PID_SHIFT) 115301265Sandrew/* Collection */ 116301265Sandrew#define CMD_COL_MASK (0xFFFFUL) 117301265Sandrew/* Target (CPU or Re-Distributor) */ 118301265Sandrew#define CMD_TARGET_SHIFT (16) 119301265Sandrew#define CMD_TARGET_MASK (0xFFFFFFFFUL << CMD_TARGET_SHIFT) 120301265Sandrew/* Interrupt Translation Table address */ 121301265Sandrew#define CMD_ITT_MASK (0xFFFFFFFFFF00UL) 122301265Sandrew/* Valid command bit */ 123301265Sandrew#define CMD_VALID_SHIFT (63) 124301265Sandrew#define CMD_VALID_MASK (1UL << CMD_VALID_SHIFT) 125301265Sandrew 126305529Sandrew#define ITS_TARGET_NONE 0xFBADBEEF 127305529Sandrew 128305529Sandrew/* LPI chunk owned by ITS device */ 129305529Sandrewstruct lpi_chunk { 130305529Sandrew u_int lpi_base; 131305529Sandrew u_int lpi_free; /* First free LPI in set */ 132305529Sandrew u_int lpi_num; /* Total number of LPIs in chunk */ 133305529Sandrew u_int lpi_busy; /* Number of busy LPIs in chink */ 134305529Sandrew}; 135305529Sandrew 136305529Sandrew/* ITS device */ 137305529Sandrewstruct its_dev { 138305529Sandrew TAILQ_ENTRY(its_dev) entry; 139305529Sandrew /* PCI device */ 140305529Sandrew device_t pci_dev; 141305529Sandrew /* Device ID (i.e. PCI device ID) */ 142305529Sandrew uint32_t devid; 143305529Sandrew /* List of assigned LPIs */ 144305529Sandrew struct lpi_chunk lpis; 145305529Sandrew /* Virtual address of ITT */ 146305529Sandrew vm_offset_t itt; 147305529Sandrew size_t itt_size; 148305529Sandrew}; 149305529Sandrew 150305529Sandrew/* 151305529Sandrew * ITS command descriptor. 152305529Sandrew * Idea for command description passing taken from Linux. 153305529Sandrew */ 154305529Sandrewstruct its_cmd_desc { 155305529Sandrew uint8_t cmd_type; 156305529Sandrew 157305529Sandrew union { 158305529Sandrew struct { 159305529Sandrew struct its_dev *its_dev; 160305529Sandrew struct its_col *col; 161305529Sandrew uint32_t id; 162305529Sandrew } cmd_desc_movi; 163305529Sandrew 164305529Sandrew struct { 165305529Sandrew struct its_col *col; 166305529Sandrew } cmd_desc_sync; 167305529Sandrew 168305529Sandrew struct { 169305529Sandrew struct its_col *col; 170305529Sandrew uint8_t valid; 171305529Sandrew } cmd_desc_mapc; 172305529Sandrew 173305529Sandrew struct { 174305529Sandrew struct its_dev *its_dev; 175305529Sandrew struct its_col *col; 176305529Sandrew uint32_t pid; 177305529Sandrew uint32_t id; 178305529Sandrew } cmd_desc_mapvi; 179305529Sandrew 180305529Sandrew struct { 181305529Sandrew struct its_dev *its_dev; 182305529Sandrew struct its_col *col; 183305529Sandrew uint32_t pid; 184305529Sandrew } cmd_desc_mapi; 185305529Sandrew 186305529Sandrew struct { 187305529Sandrew struct its_dev *its_dev; 188305529Sandrew uint8_t valid; 189305529Sandrew } cmd_desc_mapd; 190305529Sandrew 191305529Sandrew struct { 192305529Sandrew struct its_dev *its_dev; 193305529Sandrew struct its_col *col; 194305529Sandrew uint32_t pid; 195305529Sandrew } cmd_desc_inv; 196305529Sandrew 197305529Sandrew struct { 198305529Sandrew struct its_col *col; 199305529Sandrew } cmd_desc_invall; 200305529Sandrew }; 201305529Sandrew}; 202305529Sandrew 203301265Sandrew/* ITS command. Each command is 32 bytes long */ 204301265Sandrewstruct its_cmd { 205301265Sandrew uint64_t cmd_dword[4]; /* ITS command double word */ 206301265Sandrew}; 207301265Sandrew 208301265Sandrew/* An ITS private table */ 209301265Sandrewstruct its_ptable { 210301265Sandrew vm_offset_t ptab_vaddr; 211301265Sandrew unsigned long ptab_size; 212301265Sandrew}; 213301265Sandrew 214301265Sandrew/* ITS collection description. */ 215301265Sandrewstruct its_col { 216301265Sandrew uint64_t col_target; /* Target Re-Distributor */ 217301265Sandrew uint64_t col_id; /* Collection ID */ 218301265Sandrew}; 219301265Sandrew 220301265Sandrewstruct gicv3_its_irqsrc { 221301265Sandrew struct intr_irqsrc gi_isrc; 222301265Sandrew u_int gi_irq; 223301265Sandrew struct its_dev *gi_its_dev; 224301265Sandrew}; 225301265Sandrew 226301265Sandrewstruct gicv3_its_softc { 227301265Sandrew struct intr_pic *sc_pic; 228301265Sandrew struct resource *sc_its_res; 229301265Sandrew 230301265Sandrew struct its_ptable sc_its_ptab[GITS_BASER_NUM]; 231301265Sandrew struct its_col *sc_its_cols[MAXCPU]; /* Per-CPU collections */ 232301265Sandrew 233301265Sandrew /* 234301265Sandrew * TODO: We should get these from the parent as we only want a 235301265Sandrew * single copy of each across the interrupt controller. 236301265Sandrew */ 237301265Sandrew vm_offset_t sc_conf_base; 238301265Sandrew vm_offset_t sc_pend_base[MAXCPU]; 239301265Sandrew 240301265Sandrew /* Command handling */ 241301265Sandrew struct mtx sc_its_cmd_lock; 242301265Sandrew struct its_cmd *sc_its_cmd_base; /* Command circular buffer address */ 243301265Sandrew size_t sc_its_cmd_next_idx; 244301265Sandrew 245301265Sandrew vmem_t *sc_irq_alloc; 246301265Sandrew struct gicv3_its_irqsrc *sc_irqs; 247301265Sandrew 248301265Sandrew struct mtx sc_its_dev_lock; 249301265Sandrew TAILQ_HEAD(its_dev_list, its_dev) sc_its_dev_list; 250301265Sandrew 251301265Sandrew#define ITS_FLAGS_CMDQ_FLUSH 0x00000001 252301265Sandrew#define ITS_FLAGS_LPI_CONF_FLUSH 0x00000002 253301265Sandrew#define ITS_FLAGS_ERRATA_CAVIUM_22375 0x00000004 254301265Sandrew u_int sc_its_flags; 255301265Sandrew}; 256301265Sandrew 257301265Sandrewtypedef void (its_quirk_func_t)(device_t); 258301265Sandrewstatic its_quirk_func_t its_quirk_cavium_22375; 259301265Sandrew 260301265Sandrewstatic const struct { 261301265Sandrew const char *desc; 262301265Sandrew uint32_t iidr; 263301265Sandrew uint32_t iidr_mask; 264301265Sandrew its_quirk_func_t *func; 265301265Sandrew} its_quirks[] = { 266301265Sandrew { 267301265Sandrew /* Cavium ThunderX Pass 1.x */ 268301265Sandrew .desc = "Cavoum ThunderX errata: 22375, 24313", 269301265Sandrew .iidr = GITS_IIDR_RAW(GITS_IIDR_IMPL_CAVIUM, 270301265Sandrew GITS_IIDR_PROD_THUNDER, GITS_IIDR_VAR_THUNDER_1, 0), 271301265Sandrew .iidr_mask = ~GITS_IIDR_REVISION_MASK, 272301265Sandrew .func = its_quirk_cavium_22375, 273301265Sandrew }, 274301265Sandrew}; 275301265Sandrew 276301265Sandrewstatic u_int gic_irq_cpu; 277301265Sandrew 278301265Sandrew#define gic_its_read_4(sc, reg) \ 279301265Sandrew bus_read_4((sc)->sc_its_res, (reg)) 280301265Sandrew#define gic_its_read_8(sc, reg) \ 281301265Sandrew bus_read_8((sc)->sc_its_res, (reg)) 282301265Sandrew 283301265Sandrew#define gic_its_write_4(sc, reg, val) \ 284301265Sandrew bus_write_4((sc)->sc_its_res, (reg), (val)) 285301265Sandrew#define gic_its_write_8(sc, reg, val) \ 286301265Sandrew bus_write_8((sc)->sc_its_res, (reg), (val)) 287301265Sandrew 288301265Sandrewstatic device_attach_t gicv3_its_attach; 289301265Sandrewstatic device_detach_t gicv3_its_detach; 290301265Sandrew 291301265Sandrewstatic pic_disable_intr_t gicv3_its_disable_intr; 292301265Sandrewstatic pic_enable_intr_t gicv3_its_enable_intr; 293301265Sandrewstatic pic_map_intr_t gicv3_its_map_intr; 294301265Sandrewstatic pic_setup_intr_t gicv3_its_setup_intr; 295301265Sandrewstatic pic_post_filter_t gicv3_its_post_filter; 296301265Sandrewstatic pic_post_ithread_t gicv3_its_post_ithread; 297301265Sandrewstatic pic_pre_ithread_t gicv3_its_pre_ithread; 298301265Sandrewstatic pic_bind_intr_t gicv3_its_bind_intr; 299301265Sandrew#ifdef SMP 300301265Sandrewstatic pic_init_secondary_t gicv3_its_init_secondary; 301301265Sandrew#endif 302301265Sandrewstatic msi_alloc_msi_t gicv3_its_alloc_msi; 303301265Sandrewstatic msi_release_msi_t gicv3_its_release_msi; 304301265Sandrewstatic msi_alloc_msix_t gicv3_its_alloc_msix; 305301265Sandrewstatic msi_release_msix_t gicv3_its_release_msix; 306301265Sandrewstatic msi_map_msi_t gicv3_its_map_msi; 307301265Sandrew 308301265Sandrewstatic void its_cmd_movi(device_t, struct gicv3_its_irqsrc *); 309301265Sandrewstatic void its_cmd_mapc(device_t, struct its_col *, uint8_t); 310301265Sandrewstatic void its_cmd_mapti(device_t, struct gicv3_its_irqsrc *); 311301265Sandrewstatic void its_cmd_mapd(device_t, struct its_dev *, uint8_t); 312301265Sandrewstatic void its_cmd_inv(device_t, struct its_dev *, struct gicv3_its_irqsrc *); 313301265Sandrewstatic void its_cmd_invall(device_t, struct its_col *); 314301265Sandrew 315301265Sandrewstatic device_method_t gicv3_its_methods[] = { 316301265Sandrew /* Device interface */ 317301265Sandrew DEVMETHOD(device_detach, gicv3_its_detach), 318301265Sandrew 319301265Sandrew /* Interrupt controller interface */ 320301265Sandrew DEVMETHOD(pic_disable_intr, gicv3_its_disable_intr), 321301265Sandrew DEVMETHOD(pic_enable_intr, gicv3_its_enable_intr), 322301265Sandrew DEVMETHOD(pic_map_intr, gicv3_its_map_intr), 323301265Sandrew DEVMETHOD(pic_setup_intr, gicv3_its_setup_intr), 324301265Sandrew DEVMETHOD(pic_post_filter, gicv3_its_post_filter), 325301265Sandrew DEVMETHOD(pic_post_ithread, gicv3_its_post_ithread), 326301265Sandrew DEVMETHOD(pic_pre_ithread, gicv3_its_pre_ithread), 327301265Sandrew#ifdef SMP 328301265Sandrew DEVMETHOD(pic_bind_intr, gicv3_its_bind_intr), 329301265Sandrew DEVMETHOD(pic_init_secondary, gicv3_its_init_secondary), 330301265Sandrew#endif 331301265Sandrew 332301265Sandrew /* MSI/MSI-X */ 333301265Sandrew DEVMETHOD(msi_alloc_msi, gicv3_its_alloc_msi), 334301265Sandrew DEVMETHOD(msi_release_msi, gicv3_its_release_msi), 335301265Sandrew DEVMETHOD(msi_alloc_msix, gicv3_its_alloc_msix), 336301265Sandrew DEVMETHOD(msi_release_msix, gicv3_its_release_msix), 337301265Sandrew DEVMETHOD(msi_map_msi, gicv3_its_map_msi), 338301265Sandrew 339301265Sandrew /* End */ 340301265Sandrew DEVMETHOD_END 341301265Sandrew}; 342301265Sandrew 343301265Sandrewstatic DEFINE_CLASS_0(gic, gicv3_its_driver, gicv3_its_methods, 344301265Sandrew sizeof(struct gicv3_its_softc)); 345301265Sandrew 346301265Sandrewstatic void 347301265Sandrewgicv3_its_cmdq_init(struct gicv3_its_softc *sc) 348301265Sandrew{ 349301265Sandrew vm_paddr_t cmd_paddr; 350301265Sandrew uint64_t reg, tmp; 351301265Sandrew 352301265Sandrew /* Set up the command circular buffer */ 353301265Sandrew sc->sc_its_cmd_base = contigmalloc(ITS_CMDQ_SIZE, M_GICV3_ITS, 354301265Sandrew M_WAITOK | M_ZERO, 0, (1ul << 48) - 1, ITS_CMDQ_ALIGN, 0); 355301265Sandrew sc->sc_its_cmd_next_idx = 0; 356301265Sandrew 357301265Sandrew cmd_paddr = vtophys(sc->sc_its_cmd_base); 358301265Sandrew 359301265Sandrew /* Set the base of the command buffer */ 360301265Sandrew reg = GITS_CBASER_VALID | 361301265Sandrew (GITS_CBASER_CACHE_NIWAWB << GITS_CBASER_CACHE_SHIFT) | 362301265Sandrew cmd_paddr | (GITS_CBASER_SHARE_IS << GITS_CBASER_SHARE_SHIFT) | 363301265Sandrew (ITS_CMDQ_SIZE / 4096 - 1); 364301265Sandrew gic_its_write_8(sc, GITS_CBASER, reg); 365301265Sandrew 366301265Sandrew /* Read back to check for fixed value fields */ 367301265Sandrew tmp = gic_its_read_8(sc, GITS_CBASER); 368301265Sandrew 369301265Sandrew if ((tmp & GITS_CBASER_SHARE_MASK) != 370301265Sandrew (GITS_CBASER_SHARE_IS << GITS_CBASER_SHARE_SHIFT)) { 371301265Sandrew /* Check if the hardware reported non-shareable */ 372301265Sandrew if ((tmp & GITS_CBASER_SHARE_MASK) == 373301265Sandrew (GITS_CBASER_SHARE_NS << GITS_CBASER_SHARE_SHIFT)) { 374301265Sandrew /* If so remove the cache attribute */ 375301265Sandrew reg &= ~GITS_CBASER_CACHE_MASK; 376301265Sandrew reg &= ~GITS_CBASER_SHARE_MASK; 377301265Sandrew /* Set to Non-cacheable, Non-shareable */ 378301265Sandrew reg |= GITS_CBASER_CACHE_NIN << GITS_CBASER_CACHE_SHIFT; 379301265Sandrew reg |= GITS_CBASER_SHARE_NS << GITS_CBASER_SHARE_SHIFT; 380301265Sandrew 381301265Sandrew gic_its_write_8(sc, GITS_CBASER, reg); 382301265Sandrew } 383301265Sandrew 384301265Sandrew /* The command queue has to be flushed after each command */ 385301265Sandrew sc->sc_its_flags |= ITS_FLAGS_CMDQ_FLUSH; 386301265Sandrew } 387301265Sandrew 388301265Sandrew /* Get the next command from the start of the buffer */ 389301265Sandrew gic_its_write_8(sc, GITS_CWRITER, 0x0); 390301265Sandrew} 391301265Sandrew 392301265Sandrewstatic int 393301265Sandrewgicv3_its_table_init(device_t dev, struct gicv3_its_softc *sc) 394301265Sandrew{ 395301265Sandrew vm_offset_t table; 396301265Sandrew vm_paddr_t paddr; 397301265Sandrew uint64_t cache, reg, share, tmp, type; 398301265Sandrew size_t esize, its_tbl_size, nidents, nitspages, npages; 399301265Sandrew int i, page_size; 400301265Sandrew int devbits; 401301265Sandrew 402301265Sandrew if ((sc->sc_its_flags & ITS_FLAGS_ERRATA_CAVIUM_22375) != 0) { 403301265Sandrew /* 404301265Sandrew * GITS_TYPER[17:13] of ThunderX reports that device IDs 405301265Sandrew * are to be 21 bits in length. The entry size of the ITS 406301265Sandrew * table can be read from GITS_BASERn[52:48] and on ThunderX 407301265Sandrew * is supposed to be 8 bytes in length (for device table). 408301265Sandrew * Finally the page size that is to be used by ITS to access 409301265Sandrew * this table will be set to 64KB. 410301265Sandrew * 411301265Sandrew * This gives 0x200000 entries of size 0x8 bytes covered by 412301265Sandrew * 256 pages each of which 64KB in size. The number of pages 413301265Sandrew * (minus 1) should then be written to GITS_BASERn[7:0]. In 414301265Sandrew * that case this value would be 0xFF but on ThunderX the 415301265Sandrew * maximum value that HW accepts is 0xFD. 416301265Sandrew * 417301265Sandrew * Set an arbitrary number of device ID bits to 20 in order 418301265Sandrew * to limit the number of entries in ITS device table to 419301265Sandrew * 0x100000 and the table size to 8MB. 420301265Sandrew */ 421301265Sandrew devbits = 20; 422301265Sandrew cache = 0; 423301265Sandrew } else { 424301265Sandrew devbits = GITS_TYPER_DEVB(gic_its_read_8(sc, GITS_TYPER)); 425301265Sandrew cache = GITS_BASER_CACHE_WAWB; 426301265Sandrew } 427301265Sandrew share = GITS_BASER_SHARE_IS; 428301265Sandrew page_size = PAGE_SIZE_64K; 429301265Sandrew 430301265Sandrew for (i = 0; i < GITS_BASER_NUM; i++) { 431301265Sandrew reg = gic_its_read_8(sc, GITS_BASER(i)); 432301265Sandrew /* The type of table */ 433301265Sandrew type = GITS_BASER_TYPE(reg); 434301265Sandrew /* The table entry size */ 435301265Sandrew esize = GITS_BASER_ESIZE(reg); 436301265Sandrew 437301265Sandrew switch(type) { 438301265Sandrew case GITS_BASER_TYPE_DEV: 439301265Sandrew nidents = (1 << devbits); 440301265Sandrew its_tbl_size = esize * nidents; 441301265Sandrew its_tbl_size = roundup2(its_tbl_size, PAGE_SIZE_64K); 442301265Sandrew break; 443301265Sandrew case GITS_BASER_TYPE_VP: 444301265Sandrew case GITS_BASER_TYPE_PP: /* Undocumented? */ 445301265Sandrew case GITS_BASER_TYPE_IC: 446301265Sandrew its_tbl_size = page_size; 447301265Sandrew break; 448301265Sandrew default: 449301265Sandrew continue; 450301265Sandrew } 451301265Sandrew npages = howmany(its_tbl_size, PAGE_SIZE); 452301265Sandrew 453301265Sandrew /* Allocate the table */ 454301265Sandrew table = (vm_offset_t)contigmalloc(npages * PAGE_SIZE, 455301265Sandrew M_GICV3_ITS, M_WAITOK | M_ZERO, 0, (1ul << 48) - 1, 456301265Sandrew PAGE_SIZE, 0); 457301265Sandrew 458301265Sandrew sc->sc_its_ptab[i].ptab_vaddr = table; 459301265Sandrew sc->sc_its_ptab[i].ptab_size = npages * PAGE_SIZE; 460301265Sandrew 461301265Sandrew paddr = vtophys(table); 462301265Sandrew 463301265Sandrew while (1) { 464301265Sandrew nitspages = howmany(its_tbl_size, page_size); 465301265Sandrew 466301265Sandrew /* Clear the fields we will be setting */ 467301265Sandrew reg &= ~(GITS_BASER_VALID | 468301265Sandrew GITS_BASER_CACHE_MASK | GITS_BASER_TYPE_MASK | 469301265Sandrew GITS_BASER_ESIZE_MASK | GITS_BASER_PA_MASK | 470301265Sandrew GITS_BASER_SHARE_MASK | GITS_BASER_PSZ_MASK | 471301265Sandrew GITS_BASER_SIZE_MASK); 472301265Sandrew /* Set the new values */ 473301265Sandrew reg |= GITS_BASER_VALID | 474301265Sandrew (cache << GITS_BASER_CACHE_SHIFT) | 475301265Sandrew (type << GITS_BASER_TYPE_SHIFT) | 476301265Sandrew ((esize - 1) << GITS_BASER_ESIZE_SHIFT) | 477301265Sandrew paddr | (share << GITS_BASER_SHARE_SHIFT) | 478301265Sandrew (nitspages - 1); 479301265Sandrew 480301265Sandrew switch (page_size) { 481301265Sandrew case PAGE_SIZE: /* 4KB */ 482301265Sandrew reg |= 483301265Sandrew GITS_BASER_PSZ_4K << GITS_BASER_PSZ_SHIFT; 484301265Sandrew break; 485301265Sandrew case PAGE_SIZE_16K: /* 16KB */ 486301265Sandrew reg |= 487301265Sandrew GITS_BASER_PSZ_4K << GITS_BASER_PSZ_SHIFT; 488301265Sandrew break; 489301265Sandrew case PAGE_SIZE_64K: /* 64KB */ 490301265Sandrew reg |= 491301265Sandrew GITS_BASER_PSZ_64K << GITS_BASER_PSZ_SHIFT; 492301265Sandrew break; 493301265Sandrew } 494301265Sandrew 495301265Sandrew gic_its_write_8(sc, GITS_BASER(i), reg); 496301265Sandrew 497301265Sandrew /* Read back to check */ 498301265Sandrew tmp = gic_its_read_8(sc, GITS_BASER(i)); 499301265Sandrew 500301265Sandrew /* Do the snareability masks line up? */ 501301265Sandrew if ((tmp & GITS_BASER_SHARE_MASK) != 502301265Sandrew (reg & GITS_BASER_SHARE_MASK)) { 503301265Sandrew share = (tmp & GITS_BASER_SHARE_MASK) >> 504301265Sandrew GITS_BASER_SHARE_SHIFT; 505301265Sandrew continue; 506301265Sandrew } 507301265Sandrew 508301265Sandrew if ((tmp & GITS_BASER_PSZ_MASK) != 509301265Sandrew (reg & GITS_BASER_PSZ_MASK)) { 510301265Sandrew switch (page_size) { 511301265Sandrew case PAGE_SIZE_16K: 512301265Sandrew page_size = PAGE_SIZE; 513301265Sandrew continue; 514301265Sandrew case PAGE_SIZE_64K: 515301265Sandrew page_size = PAGE_SIZE_16K; 516301265Sandrew continue; 517301265Sandrew } 518301265Sandrew } 519301265Sandrew 520301265Sandrew if (tmp != reg) { 521301265Sandrew device_printf(dev, "GITS_BASER%d: " 522301265Sandrew "unable to be updated: %lx != %lx\n", 523301265Sandrew i, reg, tmp); 524301265Sandrew return (ENXIO); 525301265Sandrew } 526301265Sandrew 527301265Sandrew /* We should have made all needed changes */ 528301265Sandrew break; 529301265Sandrew } 530301265Sandrew } 531301265Sandrew 532301265Sandrew return (0); 533301265Sandrew} 534301265Sandrew 535301265Sandrewstatic void 536301265Sandrewgicv3_its_conftable_init(struct gicv3_its_softc *sc) 537301265Sandrew{ 538301265Sandrew 539301265Sandrew sc->sc_conf_base = (vm_offset_t)contigmalloc(LPI_CONFTAB_SIZE, 540301265Sandrew M_GICV3_ITS, M_WAITOK, 0, LPI_CONFTAB_MAX_ADDR, LPI_CONFTAB_ALIGN, 541301265Sandrew 0); 542301265Sandrew 543301265Sandrew /* Set the default configuration */ 544301265Sandrew memset((void *)sc->sc_conf_base, GIC_PRIORITY_MAX | LPI_CONF_GROUP1, 545301265Sandrew LPI_CONFTAB_SIZE); 546301265Sandrew 547301265Sandrew /* Flush the table to memory */ 548301265Sandrew cpu_dcache_wb_range(sc->sc_conf_base, LPI_CONFTAB_SIZE); 549301265Sandrew} 550301265Sandrew 551301265Sandrewstatic void 552301265Sandrewgicv3_its_pendtables_init(struct gicv3_its_softc *sc) 553301265Sandrew{ 554301265Sandrew int i; 555301265Sandrew 556301265Sandrew for (i = 0; i < mp_ncpus; i++) { 557301265Sandrew if (CPU_ISSET(i, &all_cpus) == 0) 558301265Sandrew continue; 559301265Sandrew 560301265Sandrew sc->sc_pend_base[i] = (vm_offset_t)contigmalloc( 561301265Sandrew LPI_PENDTAB_SIZE, M_GICV3_ITS, M_WAITOK | M_ZERO, 562301265Sandrew 0, LPI_PENDTAB_MAX_ADDR, LPI_PENDTAB_ALIGN, 0); 563301265Sandrew 564301265Sandrew /* Flush so the ITS can see the memory */ 565301265Sandrew cpu_dcache_wb_range((vm_offset_t)sc->sc_pend_base, 566301265Sandrew LPI_PENDTAB_SIZE); 567301265Sandrew } 568301265Sandrew} 569301265Sandrew 570301265Sandrewstatic int 571301265Sandrewits_init_cpu(device_t dev, struct gicv3_its_softc *sc) 572301265Sandrew{ 573301265Sandrew device_t gicv3; 574301265Sandrew vm_paddr_t target; 575301265Sandrew uint64_t xbaser, tmp; 576301265Sandrew uint32_t ctlr; 577301265Sandrew u_int cpuid; 578301265Sandrew 579301265Sandrew gicv3 = device_get_parent(dev); 580301265Sandrew cpuid = PCPU_GET(cpuid); 581301265Sandrew 582301265Sandrew /* Check if the ITS is enabled on this CPU */ 583301265Sandrew if ((gic_r_read_4(gicv3, GICR_TYPER) & GICR_TYPER_PLPIS) == 0) { 584301265Sandrew return (ENXIO); 585301265Sandrew } 586301265Sandrew 587301265Sandrew /* Disable LPIs */ 588301265Sandrew ctlr = gic_r_read_4(gicv3, GICR_CTLR); 589301265Sandrew ctlr &= ~GICR_CTLR_LPI_ENABLE; 590301265Sandrew gic_r_write_4(gicv3, GICR_CTLR, ctlr); 591301265Sandrew 592301265Sandrew /* Make sure changes are observable my the GIC */ 593301265Sandrew dsb(sy); 594301265Sandrew 595301265Sandrew /* 596301265Sandrew * Set the redistributor base 597301265Sandrew */ 598301265Sandrew xbaser = vtophys(sc->sc_conf_base) | 599301265Sandrew (GICR_PROPBASER_SHARE_IS << GICR_PROPBASER_SHARE_SHIFT) | 600301265Sandrew (GICR_PROPBASER_CACHE_NIWAWB << GICR_PROPBASER_CACHE_SHIFT) | 601301265Sandrew (flsl(LPI_CONFTAB_SIZE | GIC_FIRST_LPI) - 1); 602301265Sandrew gic_r_write_8(gicv3, GICR_PROPBASER, xbaser); 603301265Sandrew 604301265Sandrew /* Check the cache attributes we set */ 605301265Sandrew tmp = gic_r_read_8(gicv3, GICR_PROPBASER); 606301265Sandrew 607301265Sandrew if ((tmp & GICR_PROPBASER_SHARE_MASK) != 608301265Sandrew (xbaser & GICR_PROPBASER_SHARE_MASK)) { 609301265Sandrew if ((tmp & GICR_PROPBASER_SHARE_MASK) == 610301265Sandrew (GICR_PROPBASER_SHARE_NS << GICR_PROPBASER_SHARE_SHIFT)) { 611301265Sandrew /* We need to mark as non-cacheable */ 612301265Sandrew xbaser &= ~(GICR_PROPBASER_SHARE_MASK | 613301265Sandrew GICR_PROPBASER_CACHE_MASK); 614301265Sandrew /* Non-cacheable */ 615301265Sandrew xbaser |= GICR_PROPBASER_CACHE_NIN << 616301265Sandrew GICR_PROPBASER_CACHE_SHIFT; 617301265Sandrew /* Non-sareable */ 618301265Sandrew xbaser |= GICR_PROPBASER_SHARE_NS << 619301265Sandrew GICR_PROPBASER_SHARE_SHIFT; 620301265Sandrew gic_r_write_8(gicv3, GICR_PROPBASER, xbaser); 621301265Sandrew } 622301265Sandrew sc->sc_its_flags |= ITS_FLAGS_LPI_CONF_FLUSH; 623301265Sandrew } 624301265Sandrew 625301265Sandrew /* 626301265Sandrew * Set the LPI pending table base 627301265Sandrew */ 628301265Sandrew xbaser = vtophys(sc->sc_pend_base[cpuid]) | 629301265Sandrew (GICR_PENDBASER_CACHE_NIWAWB << GICR_PENDBASER_CACHE_SHIFT) | 630301265Sandrew (GICR_PENDBASER_SHARE_IS << GICR_PENDBASER_SHARE_SHIFT); 631301265Sandrew 632301265Sandrew gic_r_write_8(gicv3, GICR_PENDBASER, xbaser); 633301265Sandrew 634301265Sandrew tmp = gic_r_read_8(gicv3, GICR_PENDBASER); 635301265Sandrew 636301265Sandrew if ((tmp & GICR_PENDBASER_SHARE_MASK) == 637301265Sandrew (GICR_PENDBASER_SHARE_NS << GICR_PENDBASER_SHARE_SHIFT)) { 638301265Sandrew /* Clear the cahce and shareability bits */ 639301265Sandrew xbaser &= ~(GICR_PENDBASER_CACHE_MASK | 640301265Sandrew GICR_PENDBASER_SHARE_MASK); 641301265Sandrew /* Mark as non-shareable */ 642301265Sandrew xbaser |= GICR_PENDBASER_SHARE_NS << GICR_PENDBASER_SHARE_SHIFT; 643301265Sandrew /* And non-cacheable */ 644301265Sandrew xbaser |= GICR_PENDBASER_CACHE_NIN << 645301265Sandrew GICR_PENDBASER_CACHE_SHIFT; 646301265Sandrew } 647301265Sandrew 648301265Sandrew /* Enable LPIs */ 649301265Sandrew ctlr = gic_r_read_4(gicv3, GICR_CTLR); 650301265Sandrew ctlr |= GICR_CTLR_LPI_ENABLE; 651301265Sandrew gic_r_write_4(gicv3, GICR_CTLR, ctlr); 652301265Sandrew 653301265Sandrew /* Make sure the GIC has seen everything */ 654301265Sandrew dsb(sy); 655301265Sandrew 656301265Sandrew if ((gic_its_read_8(sc, GITS_TYPER) & GITS_TYPER_PTA) != 0) { 657301265Sandrew /* This ITS wants the redistributor physical address */ 658301265Sandrew target = vtophys(gicv3_get_redist_vaddr(dev)); 659301265Sandrew } else { 660301265Sandrew /* This ITS wants the unique processor number */ 661301265Sandrew target = GICR_TYPER_CPUNUM(gic_r_read_8(gicv3, GICR_TYPER)); 662301265Sandrew } 663301265Sandrew 664301265Sandrew sc->sc_its_cols[cpuid]->col_target = target; 665301265Sandrew sc->sc_its_cols[cpuid]->col_id = cpuid; 666301265Sandrew 667301265Sandrew its_cmd_mapc(dev, sc->sc_its_cols[cpuid], 1); 668301265Sandrew its_cmd_invall(dev, sc->sc_its_cols[cpuid]); 669301265Sandrew 670301265Sandrew return (0); 671301265Sandrew} 672301265Sandrew 673301265Sandrewstatic int 674301265Sandrewgicv3_its_attach(device_t dev) 675301265Sandrew{ 676301265Sandrew struct gicv3_its_softc *sc; 677301265Sandrew const char *name; 678301265Sandrew uint32_t iidr; 679301265Sandrew int err, i, rid; 680301265Sandrew 681301265Sandrew sc = device_get_softc(dev); 682301265Sandrew 683301265Sandrew rid = 0; 684301265Sandrew sc->sc_its_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 685301265Sandrew RF_ACTIVE); 686301265Sandrew if (sc->sc_its_res == NULL) { 687301265Sandrew device_printf(dev, "Could not allocate memory\n"); 688301265Sandrew return (ENXIO); 689301265Sandrew } 690301265Sandrew 691301265Sandrew iidr = gic_its_read_4(sc, GITS_IIDR); 692301265Sandrew for (i = 0; i < nitems(its_quirks); i++) { 693301265Sandrew if ((iidr & its_quirks[i].iidr_mask) == its_quirks[i].iidr) { 694301265Sandrew if (bootverbose) { 695301265Sandrew device_printf(dev, "Applying %s\n", 696301265Sandrew its_quirks[i].desc); 697301265Sandrew } 698301265Sandrew its_quirks[i].func(dev); 699301265Sandrew break; 700301265Sandrew } 701301265Sandrew } 702301265Sandrew 703301265Sandrew /* Allocate the private tables */ 704301265Sandrew err = gicv3_its_table_init(dev, sc); 705301265Sandrew if (err != 0) 706301265Sandrew return (err); 707301265Sandrew 708301265Sandrew /* Protects access to the device list */ 709301265Sandrew mtx_init(&sc->sc_its_dev_lock, "ITS device lock", NULL, MTX_SPIN); 710301265Sandrew 711301265Sandrew /* Protects access to the ITS command circular buffer. */ 712301265Sandrew mtx_init(&sc->sc_its_cmd_lock, "ITS cmd lock", NULL, MTX_SPIN); 713301265Sandrew 714301265Sandrew /* Allocate the command circular buffer */ 715301265Sandrew gicv3_its_cmdq_init(sc); 716301265Sandrew 717301265Sandrew /* Allocate the per-CPU collections */ 718301265Sandrew for (int cpu = 0; cpu < mp_ncpus; cpu++) 719301265Sandrew if (CPU_ISSET(cpu, &all_cpus) != 0) 720301265Sandrew sc->sc_its_cols[cpu] = malloc( 721301265Sandrew sizeof(*sc->sc_its_cols[0]), M_GICV3_ITS, 722301265Sandrew M_WAITOK | M_ZERO); 723301265Sandrew else 724301265Sandrew sc->sc_its_cols[cpu] = NULL; 725301265Sandrew 726301265Sandrew /* Enable the ITS */ 727301265Sandrew gic_its_write_4(sc, GITS_CTLR, 728301265Sandrew gic_its_read_4(sc, GITS_CTLR) | GITS_CTLR_EN); 729301265Sandrew 730301265Sandrew /* Create the LPI configuration table */ 731301265Sandrew gicv3_its_conftable_init(sc); 732301265Sandrew 733301265Sandrew /* And the pending tebles */ 734301265Sandrew gicv3_its_pendtables_init(sc); 735301265Sandrew 736301265Sandrew /* Enable LPIs on this CPU */ 737301265Sandrew its_init_cpu(dev, sc); 738301265Sandrew 739301265Sandrew TAILQ_INIT(&sc->sc_its_dev_list); 740301265Sandrew 741301265Sandrew /* 742301265Sandrew * Create the vmem object to allocate IRQs from. We try to use all 743301265Sandrew * IRQs not already used by the GICv3. 744301265Sandrew * XXX: This assumes there are no other interrupt controllers in the 745301265Sandrew * system. 746301265Sandrew */ 747301265Sandrew sc->sc_irq_alloc = vmem_create("GICv3 ITS IRQs", 0, 748301265Sandrew NIRQ - gicv3_get_nirqs(dev), 1, 1, M_FIRSTFIT | M_WAITOK); 749301265Sandrew 750301265Sandrew sc->sc_irqs = malloc(sizeof(*sc->sc_irqs) * LPI_NIRQS, M_GICV3_ITS, 751301265Sandrew M_WAITOK | M_ZERO); 752301265Sandrew name = device_get_nameunit(dev); 753301265Sandrew for (i = 0; i < LPI_NIRQS; i++) { 754301265Sandrew sc->sc_irqs[i].gi_irq = i; 755301265Sandrew err = intr_isrc_register(&sc->sc_irqs[i].gi_isrc, dev, 0, 756301265Sandrew "%s,%u", name, i); 757301265Sandrew } 758301265Sandrew 759301265Sandrew return (0); 760301265Sandrew} 761301265Sandrew 762301265Sandrewstatic int 763301265Sandrewgicv3_its_detach(device_t dev) 764301265Sandrew{ 765301265Sandrew 766301265Sandrew return (ENXIO); 767301265Sandrew} 768301265Sandrew 769301265Sandrewstatic void 770301265Sandrewits_quirk_cavium_22375(device_t dev) 771301265Sandrew{ 772301265Sandrew struct gicv3_its_softc *sc; 773301265Sandrew 774301265Sandrew sc = device_get_softc(dev); 775301265Sandrew sc->sc_its_flags |= ITS_FLAGS_ERRATA_CAVIUM_22375; 776301265Sandrew} 777301265Sandrew 778301265Sandrewstatic void 779301265Sandrewgicv3_its_disable_intr(device_t dev, struct intr_irqsrc *isrc) 780301265Sandrew{ 781301265Sandrew struct gicv3_its_softc *sc; 782301265Sandrew struct gicv3_its_irqsrc *girq; 783301265Sandrew uint8_t *conf; 784301265Sandrew 785301265Sandrew sc = device_get_softc(dev); 786301265Sandrew girq = (struct gicv3_its_irqsrc *)isrc; 787301265Sandrew conf = (uint8_t *)sc->sc_conf_base; 788301265Sandrew 789301265Sandrew conf[girq->gi_irq] &= ~LPI_CONF_ENABLE; 790301265Sandrew 791301265Sandrew if ((sc->sc_its_flags & ITS_FLAGS_LPI_CONF_FLUSH) != 0) { 792301265Sandrew /* Clean D-cache under command. */ 793301265Sandrew cpu_dcache_wb_range((vm_offset_t)&conf[girq->gi_irq], 1); 794301265Sandrew } else { 795301265Sandrew /* DSB inner shareable, store */ 796301265Sandrew dsb(ishst); 797301265Sandrew } 798301265Sandrew 799301265Sandrew its_cmd_inv(dev, girq->gi_its_dev, girq); 800301265Sandrew} 801301265Sandrew 802301265Sandrewstatic void 803301265Sandrewgicv3_its_enable_intr(device_t dev, struct intr_irqsrc *isrc) 804301265Sandrew{ 805301265Sandrew struct gicv3_its_softc *sc; 806301265Sandrew struct gicv3_its_irqsrc *girq; 807301265Sandrew uint8_t *conf; 808301265Sandrew 809301265Sandrew sc = device_get_softc(dev); 810301265Sandrew girq = (struct gicv3_its_irqsrc *)isrc; 811301265Sandrew conf = (uint8_t *)sc->sc_conf_base; 812301265Sandrew 813301265Sandrew conf[girq->gi_irq] |= LPI_CONF_ENABLE; 814301265Sandrew 815301265Sandrew if ((sc->sc_its_flags & ITS_FLAGS_LPI_CONF_FLUSH) != 0) { 816301265Sandrew /* Clean D-cache under command. */ 817301265Sandrew cpu_dcache_wb_range((vm_offset_t)&conf[girq->gi_irq], 1); 818301265Sandrew } else { 819301265Sandrew /* DSB inner shareable, store */ 820301265Sandrew dsb(ishst); 821301265Sandrew } 822301265Sandrew 823301265Sandrew its_cmd_inv(dev, girq->gi_its_dev, girq); 824301265Sandrew} 825301265Sandrew 826301265Sandrewstatic int 827301265Sandrewgicv3_its_intr(void *arg, uintptr_t irq) 828301265Sandrew{ 829301265Sandrew struct gicv3_its_softc *sc = arg; 830301265Sandrew struct gicv3_its_irqsrc *girq; 831301265Sandrew struct trapframe *tf; 832301265Sandrew 833301265Sandrew irq -= GIC_FIRST_LPI; 834301265Sandrew girq = &sc->sc_irqs[irq]; 835301265Sandrew if (girq == NULL) 836301265Sandrew panic("gicv3_its_intr: Invalid interrupt %ld", 837301265Sandrew irq + GIC_FIRST_LPI); 838301265Sandrew 839301265Sandrew tf = curthread->td_intr_frame; 840301265Sandrew intr_isrc_dispatch(&girq->gi_isrc, tf); 841301265Sandrew return (FILTER_HANDLED); 842301265Sandrew} 843301265Sandrew 844301265Sandrewstatic void 845301265Sandrewgicv3_its_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 846301265Sandrew{ 847301265Sandrew struct gicv3_its_irqsrc *girq; 848301265Sandrew 849301265Sandrew girq = (struct gicv3_its_irqsrc *)isrc; 850301265Sandrew gicv3_its_disable_intr(dev, isrc); 851301265Sandrew gic_icc_write(EOIR1, girq->gi_irq + GIC_FIRST_LPI); 852301265Sandrew} 853301265Sandrew 854301265Sandrewstatic void 855301265Sandrewgicv3_its_post_ithread(device_t dev, struct intr_irqsrc *isrc) 856301265Sandrew{ 857301265Sandrew 858301265Sandrew gicv3_its_enable_intr(dev, isrc); 859301265Sandrew} 860301265Sandrew 861301265Sandrewstatic void 862301265Sandrewgicv3_its_post_filter(device_t dev, struct intr_irqsrc *isrc) 863301265Sandrew{ 864301265Sandrew struct gicv3_its_irqsrc *girq; 865301265Sandrew 866301265Sandrew girq = (struct gicv3_its_irqsrc *)isrc; 867301265Sandrew gic_icc_write(EOIR1, girq->gi_irq + GIC_FIRST_LPI); 868301265Sandrew} 869301265Sandrew 870301265Sandrewstatic int 871301265Sandrewgicv3_its_bind_intr(device_t dev, struct intr_irqsrc *isrc) 872301265Sandrew{ 873301265Sandrew struct gicv3_its_irqsrc *girq; 874301265Sandrew 875301265Sandrew girq = (struct gicv3_its_irqsrc *)isrc; 876301265Sandrew if (CPU_EMPTY(&isrc->isrc_cpu)) { 877301265Sandrew gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus); 878301265Sandrew CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu); 879301265Sandrew } 880301265Sandrew 881301265Sandrew its_cmd_movi(dev, girq); 882301265Sandrew 883301265Sandrew return (0); 884301265Sandrew} 885301265Sandrew 886301265Sandrewstatic int 887301265Sandrewgicv3_its_map_intr(device_t dev, struct intr_map_data *data, 888301265Sandrew struct intr_irqsrc **isrcp) 889301265Sandrew{ 890301265Sandrew 891301265Sandrew /* 892301265Sandrew * This should never happen, we only call this function to map 893301265Sandrew * interrupts found before the controller driver is ready. 894301265Sandrew */ 895301265Sandrew panic("gicv3_its_map_intr: Unable to map a MSI interrupt"); 896301265Sandrew} 897301265Sandrew 898301265Sandrewstatic int 899301265Sandrewgicv3_its_setup_intr(device_t dev, struct intr_irqsrc *isrc, 900301265Sandrew struct resource *res, struct intr_map_data *data) 901301265Sandrew{ 902301265Sandrew 903301265Sandrew /* Bind the interrupt to a CPU */ 904301265Sandrew gicv3_its_bind_intr(dev, isrc); 905301265Sandrew 906301265Sandrew return (0); 907301265Sandrew} 908301265Sandrew 909301265Sandrew#ifdef SMP 910301265Sandrewstatic void 911301265Sandrewgicv3_its_init_secondary(device_t dev) 912301265Sandrew{ 913301265Sandrew struct gicv3_its_softc *sc; 914301265Sandrew 915301265Sandrew sc = device_get_softc(dev); 916301265Sandrew 917301265Sandrew /* 918301265Sandrew * This is fatal as otherwise we may bind interrupts to this CPU. 919301265Sandrew * We need a way to tell the interrupt framework to only bind to a 920301265Sandrew * subset of given CPUs when it performs the shuffle. 921301265Sandrew */ 922301265Sandrew if (its_init_cpu(dev, sc) != 0) 923301265Sandrew panic("gicv3_its_init_secondary: No usable ITS on CPU%d", 924301265Sandrew PCPU_GET(cpuid)); 925301265Sandrew} 926301265Sandrew#endif 927301265Sandrew 928301265Sandrewstatic uint32_t 929301265Sandrewits_get_devid(device_t pci_dev) 930301265Sandrew{ 931301265Sandrew uintptr_t id; 932301265Sandrew 933301265Sandrew if (pci_get_id(pci_dev, PCI_ID_MSI, &id) != 0) 934301265Sandrew panic("its_get_devid: Unable to get the MSI DeviceID"); 935301265Sandrew 936301265Sandrew return (id); 937301265Sandrew} 938301265Sandrew 939301265Sandrewstatic struct its_dev * 940301265Sandrewits_device_find(device_t dev, device_t child) 941301265Sandrew{ 942301265Sandrew struct gicv3_its_softc *sc; 943301265Sandrew struct its_dev *its_dev = NULL; 944301265Sandrew 945301265Sandrew sc = device_get_softc(dev); 946301265Sandrew 947301265Sandrew mtx_lock_spin(&sc->sc_its_dev_lock); 948301265Sandrew TAILQ_FOREACH(its_dev, &sc->sc_its_dev_list, entry) { 949301265Sandrew if (its_dev->pci_dev == child) 950301265Sandrew break; 951301265Sandrew } 952301265Sandrew mtx_unlock_spin(&sc->sc_its_dev_lock); 953301265Sandrew 954301265Sandrew return (its_dev); 955301265Sandrew} 956301265Sandrew 957301265Sandrewstatic struct its_dev * 958301265Sandrewits_device_get(device_t dev, device_t child, u_int nvecs) 959301265Sandrew{ 960301265Sandrew struct gicv3_its_softc *sc; 961301265Sandrew struct its_dev *its_dev; 962301265Sandrew vmem_addr_t irq_base; 963301265Sandrew size_t esize; 964301265Sandrew 965301265Sandrew sc = device_get_softc(dev); 966301265Sandrew 967301265Sandrew its_dev = its_device_find(dev, child); 968301265Sandrew if (its_dev != NULL) 969301265Sandrew return (its_dev); 970301265Sandrew 971301265Sandrew its_dev = malloc(sizeof(*its_dev), M_GICV3_ITS, M_NOWAIT | M_ZERO); 972301265Sandrew if (its_dev == NULL) 973301265Sandrew return (NULL); 974301265Sandrew 975301265Sandrew its_dev->pci_dev = child; 976301265Sandrew its_dev->devid = its_get_devid(child); 977301265Sandrew 978301265Sandrew its_dev->lpis.lpi_busy = 0; 979301265Sandrew its_dev->lpis.lpi_num = nvecs; 980301265Sandrew its_dev->lpis.lpi_free = nvecs; 981301265Sandrew 982301265Sandrew if (vmem_alloc(sc->sc_irq_alloc, nvecs, M_FIRSTFIT | M_NOWAIT, 983301265Sandrew &irq_base) != 0) { 984301265Sandrew free(its_dev, M_GICV3_ITS); 985301265Sandrew return (NULL); 986301265Sandrew } 987301265Sandrew its_dev->lpis.lpi_base = irq_base; 988301265Sandrew 989301265Sandrew /* Get ITT entry size */ 990301265Sandrew esize = GITS_TYPER_ITTES(gic_its_read_8(sc, GITS_TYPER)); 991301265Sandrew 992301265Sandrew /* 993301265Sandrew * Allocate ITT for this device. 994301265Sandrew * PA has to be 256 B aligned. At least two entries for device. 995301265Sandrew */ 996301265Sandrew its_dev->itt_size = roundup2(MAX(nvecs, 2) * esize, 256); 997301265Sandrew its_dev->itt = (vm_offset_t)contigmalloc(its_dev->itt_size, 998301265Sandrew M_GICV3_ITS, M_NOWAIT | M_ZERO, 0, LPI_INT_TRANS_TAB_MAX_ADDR, 999301265Sandrew LPI_INT_TRANS_TAB_ALIGN, 0); 1000301265Sandrew if (its_dev->itt == 0) { 1001301265Sandrew vmem_free(sc->sc_irq_alloc, its_dev->lpis.lpi_base, nvecs); 1002301265Sandrew free(its_dev, M_GICV3_ITS); 1003301265Sandrew return (NULL); 1004301265Sandrew } 1005301265Sandrew 1006301265Sandrew mtx_lock_spin(&sc->sc_its_dev_lock); 1007301265Sandrew TAILQ_INSERT_TAIL(&sc->sc_its_dev_list, its_dev, entry); 1008301265Sandrew mtx_unlock_spin(&sc->sc_its_dev_lock); 1009301265Sandrew 1010301265Sandrew /* Map device to its ITT */ 1011301265Sandrew its_cmd_mapd(dev, its_dev, 1); 1012301265Sandrew 1013301265Sandrew return (its_dev); 1014301265Sandrew} 1015301265Sandrew 1016301265Sandrewstatic void 1017301265Sandrewits_device_release(device_t dev, struct its_dev *its_dev) 1018301265Sandrew{ 1019301265Sandrew struct gicv3_its_softc *sc; 1020301265Sandrew 1021301265Sandrew KASSERT(its_dev->lpis.lpi_busy == 0, 1022301265Sandrew ("its_device_release: Trying to release an inuse ITS device")); 1023301265Sandrew 1024301265Sandrew /* Unmap device in ITS */ 1025301265Sandrew its_cmd_mapd(dev, its_dev, 0); 1026301265Sandrew 1027301265Sandrew sc = device_get_softc(dev); 1028301265Sandrew 1029301265Sandrew /* Remove the device from the list of devices */ 1030301265Sandrew mtx_lock_spin(&sc->sc_its_dev_lock); 1031301265Sandrew TAILQ_REMOVE(&sc->sc_its_dev_list, its_dev, entry); 1032301265Sandrew mtx_unlock_spin(&sc->sc_its_dev_lock); 1033301265Sandrew 1034301265Sandrew /* Free ITT */ 1035301265Sandrew KASSERT(its_dev->itt != 0, ("Invalid ITT in valid ITS device")); 1036301265Sandrew contigfree((void *)its_dev->itt, its_dev->itt_size, M_GICV3_ITS); 1037301265Sandrew 1038301265Sandrew /* Free the IRQ allocation */ 1039301265Sandrew vmem_free(sc->sc_irq_alloc, its_dev->lpis.lpi_base, 1040301265Sandrew its_dev->lpis.lpi_num); 1041301265Sandrew 1042301265Sandrew free(its_dev, M_GICV3_ITS); 1043301265Sandrew} 1044301265Sandrew 1045301265Sandrewstatic int 1046301265Sandrewgicv3_its_alloc_msi(device_t dev, device_t child, int count, int maxcount, 1047301265Sandrew device_t *pic, struct intr_irqsrc **srcs) 1048301265Sandrew{ 1049301265Sandrew struct gicv3_its_softc *sc; 1050301265Sandrew struct gicv3_its_irqsrc *girq; 1051301265Sandrew struct its_dev *its_dev; 1052301265Sandrew u_int irq; 1053301265Sandrew int i; 1054301265Sandrew 1055301265Sandrew its_dev = its_device_get(dev, child, count); 1056301265Sandrew if (its_dev == NULL) 1057301265Sandrew return (ENXIO); 1058301265Sandrew 1059301265Sandrew KASSERT(its_dev->lpis.lpi_free >= count, 1060301265Sandrew ("gicv3_its_alloc_msi: No free LPIs")); 1061301265Sandrew sc = device_get_softc(dev); 1062301265Sandrew irq = its_dev->lpis.lpi_base + its_dev->lpis.lpi_num - 1063301265Sandrew its_dev->lpis.lpi_free; 1064301265Sandrew for (i = 0; i < count; i++, irq++) { 1065301265Sandrew its_dev->lpis.lpi_free--; 1066301265Sandrew girq = &sc->sc_irqs[irq]; 1067301265Sandrew girq->gi_its_dev = its_dev; 1068301265Sandrew srcs[i] = (struct intr_irqsrc *)girq; 1069301265Sandrew } 1070301265Sandrew its_dev->lpis.lpi_busy += count; 1071301265Sandrew *pic = dev; 1072301265Sandrew 1073301265Sandrew return (0); 1074301265Sandrew} 1075301265Sandrew 1076301265Sandrewstatic int 1077301265Sandrewgicv3_its_release_msi(device_t dev, device_t child, int count, 1078301265Sandrew struct intr_irqsrc **isrc) 1079301265Sandrew{ 1080301265Sandrew struct gicv3_its_softc *sc; 1081301265Sandrew struct gicv3_its_irqsrc *girq; 1082301265Sandrew struct its_dev *its_dev; 1083301265Sandrew int i; 1084301265Sandrew 1085301265Sandrew sc = device_get_softc(dev); 1086301265Sandrew its_dev = its_device_find(dev, child); 1087301265Sandrew 1088301265Sandrew KASSERT(its_dev != NULL, 1089301265Sandrew ("gicv3_its_release_msi: Releasing a MSI interrupt with " 1090301265Sandrew "no ITS device")); 1091301265Sandrew KASSERT(its_dev->lpis.lpi_busy >= count, 1092301265Sandrew ("gicv3_its_release_msi: Releasing more interrupts than " 1093301265Sandrew "were allocated: releasing %d, allocated %d", count, 1094301265Sandrew its_dev->lpis.lpi_busy)); 1095301265Sandrew for (i = 0; i < count; i++) { 1096301265Sandrew girq = (struct gicv3_its_irqsrc *)isrc[i]; 1097301265Sandrew girq->gi_its_dev = NULL; 1098301265Sandrew } 1099301265Sandrew its_dev->lpis.lpi_busy -= count; 1100301265Sandrew 1101301265Sandrew if (its_dev->lpis.lpi_busy == 0) 1102301265Sandrew its_device_release(dev, its_dev); 1103301265Sandrew 1104301265Sandrew return (0); 1105301265Sandrew} 1106301265Sandrew 1107301265Sandrewstatic int 1108301265Sandrewgicv3_its_alloc_msix(device_t dev, device_t child, device_t *pic, 1109301265Sandrew struct intr_irqsrc **isrcp) 1110301265Sandrew{ 1111301265Sandrew struct gicv3_its_softc *sc; 1112301265Sandrew struct gicv3_its_irqsrc *girq; 1113301265Sandrew struct its_dev *its_dev; 1114301265Sandrew u_int nvecs, irq; 1115301265Sandrew 1116301265Sandrew nvecs = pci_msix_count(child); 1117301265Sandrew its_dev = its_device_get(dev, child, nvecs); 1118301265Sandrew if (its_dev == NULL) 1119301265Sandrew return (ENXIO); 1120301265Sandrew 1121301265Sandrew KASSERT(its_dev->lpis.lpi_free > 0, 1122301265Sandrew ("gicv3_its_alloc_msix: No free LPIs")); 1123301265Sandrew sc = device_get_softc(dev); 1124301265Sandrew irq = its_dev->lpis.lpi_base + its_dev->lpis.lpi_num - 1125301265Sandrew its_dev->lpis.lpi_free; 1126301265Sandrew its_dev->lpis.lpi_free--; 1127301265Sandrew its_dev->lpis.lpi_busy++; 1128301265Sandrew girq = &sc->sc_irqs[irq]; 1129301265Sandrew girq->gi_its_dev = its_dev; 1130301265Sandrew 1131301265Sandrew *pic = dev; 1132301265Sandrew *isrcp = (struct intr_irqsrc *)girq; 1133301265Sandrew 1134301265Sandrew return (0); 1135301265Sandrew} 1136301265Sandrew 1137301265Sandrewstatic int 1138301265Sandrewgicv3_its_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) 1139301265Sandrew{ 1140301265Sandrew struct gicv3_its_softc *sc; 1141301265Sandrew struct gicv3_its_irqsrc *girq; 1142301265Sandrew struct its_dev *its_dev; 1143301265Sandrew 1144301265Sandrew sc = device_get_softc(dev); 1145301265Sandrew its_dev = its_device_find(dev, child); 1146301265Sandrew 1147301265Sandrew KASSERT(its_dev != NULL, 1148301265Sandrew ("gicv3_its_release_msix: Releasing a MSI-X interrupt with " 1149301265Sandrew "no ITS device")); 1150301265Sandrew KASSERT(its_dev->lpis.lpi_busy > 0, 1151301265Sandrew ("gicv3_its_release_msix: Releasing more interrupts than " 1152301265Sandrew "were allocated: allocated %d", its_dev->lpis.lpi_busy)); 1153301265Sandrew girq = (struct gicv3_its_irqsrc *)isrc; 1154301265Sandrew girq->gi_its_dev = NULL; 1155301265Sandrew its_dev->lpis.lpi_busy--; 1156301265Sandrew 1157301265Sandrew if (its_dev->lpis.lpi_busy == 0) 1158301265Sandrew its_device_release(dev, its_dev); 1159301265Sandrew 1160301265Sandrew return (0); 1161301265Sandrew} 1162301265Sandrew 1163301265Sandrewstatic int 1164301265Sandrewgicv3_its_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, 1165301265Sandrew uint64_t *addr, uint32_t *data) 1166301265Sandrew{ 1167301265Sandrew struct gicv3_its_softc *sc; 1168301265Sandrew struct gicv3_its_irqsrc *girq; 1169301265Sandrew 1170301265Sandrew sc = device_get_softc(dev); 1171301265Sandrew girq = (struct gicv3_its_irqsrc *)isrc; 1172301265Sandrew 1173301265Sandrew /* Map the message to the given IRQ */ 1174301265Sandrew its_cmd_mapti(dev, girq); 1175301265Sandrew 1176301265Sandrew *addr = vtophys(rman_get_virtual(sc->sc_its_res)) + GITS_TRANSLATER; 1177301265Sandrew *data = girq->gi_irq - girq->gi_its_dev->lpis.lpi_base; 1178301265Sandrew 1179301265Sandrew return (0); 1180301265Sandrew} 1181301265Sandrew 1182301265Sandrew/* 1183301265Sandrew * Commands handling. 1184301265Sandrew */ 1185301265Sandrew 1186301265Sandrewstatic __inline void 1187301265Sandrewcmd_format_command(struct its_cmd *cmd, uint8_t cmd_type) 1188301265Sandrew{ 1189301265Sandrew /* Command field: DW0 [7:0] */ 1190301265Sandrew cmd->cmd_dword[0] &= htole64(~CMD_COMMAND_MASK); 1191301265Sandrew cmd->cmd_dword[0] |= htole64(cmd_type); 1192301265Sandrew} 1193301265Sandrew 1194301265Sandrewstatic __inline void 1195301265Sandrewcmd_format_devid(struct its_cmd *cmd, uint32_t devid) 1196301265Sandrew{ 1197301265Sandrew /* Device ID field: DW0 [63:32] */ 1198301265Sandrew cmd->cmd_dword[0] &= htole64(~CMD_DEVID_MASK); 1199301265Sandrew cmd->cmd_dword[0] |= htole64((uint64_t)devid << CMD_DEVID_SHIFT); 1200301265Sandrew} 1201301265Sandrew 1202301265Sandrewstatic __inline void 1203301265Sandrewcmd_format_size(struct its_cmd *cmd, uint16_t size) 1204301265Sandrew{ 1205301265Sandrew /* Size field: DW1 [4:0] */ 1206301265Sandrew cmd->cmd_dword[1] &= htole64(~CMD_SIZE_MASK); 1207301265Sandrew cmd->cmd_dword[1] |= htole64((size & CMD_SIZE_MASK)); 1208301265Sandrew} 1209301265Sandrew 1210301265Sandrewstatic __inline void 1211301265Sandrewcmd_format_id(struct its_cmd *cmd, uint32_t id) 1212301265Sandrew{ 1213301265Sandrew /* ID field: DW1 [31:0] */ 1214301265Sandrew cmd->cmd_dword[1] &= htole64(~CMD_ID_MASK); 1215301265Sandrew cmd->cmd_dword[1] |= htole64(id); 1216301265Sandrew} 1217301265Sandrew 1218301265Sandrewstatic __inline void 1219301265Sandrewcmd_format_pid(struct its_cmd *cmd, uint32_t pid) 1220301265Sandrew{ 1221301265Sandrew /* Physical ID field: DW1 [63:32] */ 1222301265Sandrew cmd->cmd_dword[1] &= htole64(~CMD_PID_MASK); 1223301265Sandrew cmd->cmd_dword[1] |= htole64((uint64_t)pid << CMD_PID_SHIFT); 1224301265Sandrew} 1225301265Sandrew 1226301265Sandrewstatic __inline void 1227301265Sandrewcmd_format_col(struct its_cmd *cmd, uint16_t col_id) 1228301265Sandrew{ 1229301265Sandrew /* Collection field: DW2 [16:0] */ 1230301265Sandrew cmd->cmd_dword[2] &= htole64(~CMD_COL_MASK); 1231301265Sandrew cmd->cmd_dword[2] |= htole64(col_id); 1232301265Sandrew} 1233301265Sandrew 1234301265Sandrewstatic __inline void 1235301265Sandrewcmd_format_target(struct its_cmd *cmd, uint64_t target) 1236301265Sandrew{ 1237301265Sandrew /* Target Address field: DW2 [47:16] */ 1238301265Sandrew cmd->cmd_dword[2] &= htole64(~CMD_TARGET_MASK); 1239301265Sandrew cmd->cmd_dword[2] |= htole64(target & CMD_TARGET_MASK); 1240301265Sandrew} 1241301265Sandrew 1242301265Sandrewstatic __inline void 1243301265Sandrewcmd_format_itt(struct its_cmd *cmd, uint64_t itt) 1244301265Sandrew{ 1245301265Sandrew /* ITT Address field: DW2 [47:8] */ 1246301265Sandrew cmd->cmd_dword[2] &= htole64(~CMD_ITT_MASK); 1247301265Sandrew cmd->cmd_dword[2] |= htole64(itt & CMD_ITT_MASK); 1248301265Sandrew} 1249301265Sandrew 1250301265Sandrewstatic __inline void 1251301265Sandrewcmd_format_valid(struct its_cmd *cmd, uint8_t valid) 1252301265Sandrew{ 1253301265Sandrew /* Valid field: DW2 [63] */ 1254301265Sandrew cmd->cmd_dword[2] &= htole64(~CMD_VALID_MASK); 1255301265Sandrew cmd->cmd_dword[2] |= htole64((uint64_t)valid << CMD_VALID_SHIFT); 1256301265Sandrew} 1257301265Sandrew 1258301265Sandrewstatic inline bool 1259301265Sandrewits_cmd_queue_full(struct gicv3_its_softc *sc) 1260301265Sandrew{ 1261301265Sandrew size_t read_idx, next_write_idx; 1262301265Sandrew 1263301265Sandrew /* Get the index of the next command */ 1264301265Sandrew next_write_idx = (sc->sc_its_cmd_next_idx + 1) % 1265301265Sandrew (ITS_CMDQ_SIZE / sizeof(struct its_cmd)); 1266301265Sandrew /* And the index of the current command being read */ 1267301265Sandrew read_idx = gic_its_read_4(sc, GITS_CREADR) / sizeof(struct its_cmd); 1268301265Sandrew 1269301265Sandrew /* 1270301265Sandrew * The queue is full when the write offset points 1271301265Sandrew * at the command before the current read offset. 1272301265Sandrew */ 1273301265Sandrew return (next_write_idx == read_idx); 1274301265Sandrew} 1275301265Sandrew 1276301265Sandrewstatic inline void 1277301265Sandrewits_cmd_sync(struct gicv3_its_softc *sc, struct its_cmd *cmd) 1278301265Sandrew{ 1279301265Sandrew 1280301265Sandrew if ((sc->sc_its_flags & ITS_FLAGS_CMDQ_FLUSH) != 0) { 1281301265Sandrew /* Clean D-cache under command. */ 1282301265Sandrew cpu_dcache_wb_range((vm_offset_t)cmd, sizeof(*cmd)); 1283301265Sandrew } else { 1284301265Sandrew /* DSB inner shareable, store */ 1285301265Sandrew dsb(ishst); 1286301265Sandrew } 1287301265Sandrew 1288301265Sandrew} 1289301265Sandrew 1290301265Sandrewstatic inline uint64_t 1291301265Sandrewits_cmd_cwriter_offset(struct gicv3_its_softc *sc, struct its_cmd *cmd) 1292301265Sandrew{ 1293301265Sandrew uint64_t off; 1294301265Sandrew 1295301265Sandrew off = (cmd - sc->sc_its_cmd_base) * sizeof(*cmd); 1296301265Sandrew 1297301265Sandrew return (off); 1298301265Sandrew} 1299301265Sandrew 1300301265Sandrewstatic void 1301301265Sandrewits_cmd_wait_completion(device_t dev, struct its_cmd *cmd_first, 1302301265Sandrew struct its_cmd *cmd_last) 1303301265Sandrew{ 1304301265Sandrew struct gicv3_its_softc *sc; 1305301265Sandrew uint64_t first, last, read; 1306301265Sandrew size_t us_left; 1307301265Sandrew 1308301265Sandrew sc = device_get_softc(dev); 1309301265Sandrew 1310301265Sandrew /* 1311301265Sandrew * XXX ARM64TODO: This is obviously a significant delay. 1312301265Sandrew * The reason for that is that currently the time frames for 1313301265Sandrew * the command to complete are not known. 1314301265Sandrew */ 1315301265Sandrew us_left = 1000000; 1316301265Sandrew 1317301265Sandrew first = its_cmd_cwriter_offset(sc, cmd_first); 1318301265Sandrew last = its_cmd_cwriter_offset(sc, cmd_last); 1319301265Sandrew 1320301265Sandrew for (;;) { 1321301265Sandrew read = gic_its_read_8(sc, GITS_CREADR); 1322301265Sandrew if (first < last) { 1323301265Sandrew if (read < first || read >= last) 1324301265Sandrew break; 1325301265Sandrew } else if (read < first && read >= last) 1326301265Sandrew break; 1327301265Sandrew 1328301265Sandrew if (us_left-- == 0) { 1329301265Sandrew /* This means timeout */ 1330301265Sandrew device_printf(dev, 1331301265Sandrew "Timeout while waiting for CMD completion.\n"); 1332301265Sandrew return; 1333301265Sandrew } 1334301265Sandrew DELAY(1); 1335301265Sandrew } 1336301265Sandrew} 1337301265Sandrew 1338301265Sandrew 1339301265Sandrewstatic struct its_cmd * 1340301265Sandrewits_cmd_alloc_locked(device_t dev) 1341301265Sandrew{ 1342301265Sandrew struct gicv3_its_softc *sc; 1343301265Sandrew struct its_cmd *cmd; 1344301265Sandrew size_t us_left; 1345301265Sandrew 1346301265Sandrew sc = device_get_softc(dev); 1347301265Sandrew 1348301265Sandrew /* 1349301265Sandrew * XXX ARM64TODO: This is obviously a significant delay. 1350301265Sandrew * The reason for that is that currently the time frames for 1351301265Sandrew * the command to complete (and therefore free the descriptor) 1352301265Sandrew * are not known. 1353301265Sandrew */ 1354301265Sandrew us_left = 1000000; 1355301265Sandrew 1356301265Sandrew mtx_assert(&sc->sc_its_cmd_lock, MA_OWNED); 1357301265Sandrew while (its_cmd_queue_full(sc)) { 1358301265Sandrew if (us_left-- == 0) { 1359301265Sandrew /* Timeout while waiting for free command */ 1360301265Sandrew device_printf(dev, 1361301265Sandrew "Timeout while waiting for free command\n"); 1362301265Sandrew return (NULL); 1363301265Sandrew } 1364301265Sandrew DELAY(1); 1365301265Sandrew } 1366301265Sandrew 1367301265Sandrew cmd = &sc->sc_its_cmd_base[sc->sc_its_cmd_next_idx]; 1368301265Sandrew sc->sc_its_cmd_next_idx++; 1369301265Sandrew sc->sc_its_cmd_next_idx %= ITS_CMDQ_SIZE / sizeof(struct its_cmd); 1370301265Sandrew 1371301265Sandrew return (cmd); 1372301265Sandrew} 1373301265Sandrew 1374301265Sandrewstatic uint64_t 1375301265Sandrewits_cmd_prepare(struct its_cmd *cmd, struct its_cmd_desc *desc) 1376301265Sandrew{ 1377301265Sandrew uint64_t target; 1378301265Sandrew uint8_t cmd_type; 1379301265Sandrew u_int size; 1380301265Sandrew boolean_t error; 1381301265Sandrew 1382301265Sandrew error = FALSE; 1383301265Sandrew cmd_type = desc->cmd_type; 1384301265Sandrew target = ITS_TARGET_NONE; 1385301265Sandrew 1386301265Sandrew switch (cmd_type) { 1387301265Sandrew case ITS_CMD_MOVI: /* Move interrupt ID to another collection */ 1388301265Sandrew target = desc->cmd_desc_movi.col->col_target; 1389301265Sandrew cmd_format_command(cmd, ITS_CMD_MOVI); 1390301265Sandrew cmd_format_id(cmd, desc->cmd_desc_movi.id); 1391301265Sandrew cmd_format_col(cmd, desc->cmd_desc_movi.col->col_id); 1392301265Sandrew cmd_format_devid(cmd, desc->cmd_desc_movi.its_dev->devid); 1393301265Sandrew break; 1394301265Sandrew case ITS_CMD_SYNC: /* Wait for previous commands completion */ 1395301265Sandrew target = desc->cmd_desc_sync.col->col_target; 1396301265Sandrew cmd_format_command(cmd, ITS_CMD_SYNC); 1397301265Sandrew cmd_format_target(cmd, target); 1398301265Sandrew break; 1399301265Sandrew case ITS_CMD_MAPD: /* Assign ITT to device */ 1400301265Sandrew cmd_format_command(cmd, ITS_CMD_MAPD); 1401301265Sandrew cmd_format_itt(cmd, vtophys(desc->cmd_desc_mapd.its_dev->itt)); 1402301265Sandrew /* 1403301265Sandrew * Size describes number of bits to encode interrupt IDs 1404301265Sandrew * supported by the device minus one. 1405301265Sandrew * When V (valid) bit is zero, this field should be written 1406301265Sandrew * as zero. 1407301265Sandrew */ 1408301265Sandrew if (desc->cmd_desc_mapd.valid != 0) { 1409301265Sandrew size = fls(desc->cmd_desc_mapd.its_dev->lpis.lpi_num); 1410301265Sandrew size = MAX(1, size) - 1; 1411301265Sandrew } else 1412301265Sandrew size = 0; 1413301265Sandrew 1414301265Sandrew cmd_format_size(cmd, size); 1415301265Sandrew cmd_format_devid(cmd, desc->cmd_desc_mapd.its_dev->devid); 1416301265Sandrew cmd_format_valid(cmd, desc->cmd_desc_mapd.valid); 1417301265Sandrew break; 1418301265Sandrew case ITS_CMD_MAPC: /* Map collection to Re-Distributor */ 1419301265Sandrew target = desc->cmd_desc_mapc.col->col_target; 1420301265Sandrew cmd_format_command(cmd, ITS_CMD_MAPC); 1421301265Sandrew cmd_format_col(cmd, desc->cmd_desc_mapc.col->col_id); 1422301265Sandrew cmd_format_valid(cmd, desc->cmd_desc_mapc.valid); 1423301265Sandrew cmd_format_target(cmd, target); 1424301265Sandrew break; 1425301265Sandrew case ITS_CMD_MAPTI: 1426301265Sandrew target = desc->cmd_desc_mapvi.col->col_target; 1427301265Sandrew cmd_format_command(cmd, ITS_CMD_MAPTI); 1428301265Sandrew cmd_format_devid(cmd, desc->cmd_desc_mapvi.its_dev->devid); 1429301265Sandrew cmd_format_id(cmd, desc->cmd_desc_mapvi.id); 1430301265Sandrew cmd_format_pid(cmd, desc->cmd_desc_mapvi.pid); 1431301265Sandrew cmd_format_col(cmd, desc->cmd_desc_mapvi.col->col_id); 1432301265Sandrew break; 1433301265Sandrew case ITS_CMD_MAPI: 1434301265Sandrew target = desc->cmd_desc_mapi.col->col_target; 1435301265Sandrew cmd_format_command(cmd, ITS_CMD_MAPI); 1436301265Sandrew cmd_format_devid(cmd, desc->cmd_desc_mapi.its_dev->devid); 1437301265Sandrew cmd_format_id(cmd, desc->cmd_desc_mapi.pid); 1438301265Sandrew cmd_format_col(cmd, desc->cmd_desc_mapi.col->col_id); 1439301265Sandrew break; 1440301265Sandrew case ITS_CMD_INV: 1441301265Sandrew target = desc->cmd_desc_inv.col->col_target; 1442301265Sandrew cmd_format_command(cmd, ITS_CMD_INV); 1443301265Sandrew cmd_format_devid(cmd, desc->cmd_desc_inv.its_dev->devid); 1444301265Sandrew cmd_format_id(cmd, desc->cmd_desc_inv.pid); 1445301265Sandrew break; 1446301265Sandrew case ITS_CMD_INVALL: 1447301265Sandrew cmd_format_command(cmd, ITS_CMD_INVALL); 1448301265Sandrew cmd_format_col(cmd, desc->cmd_desc_invall.col->col_id); 1449301265Sandrew break; 1450301265Sandrew default: 1451301265Sandrew panic("its_cmd_prepare: Invalid command: %x", cmd_type); 1452301265Sandrew } 1453301265Sandrew 1454301265Sandrew return (target); 1455301265Sandrew} 1456301265Sandrew 1457301265Sandrewstatic int 1458301265Sandrewits_cmd_send(device_t dev, struct its_cmd_desc *desc) 1459301265Sandrew{ 1460301265Sandrew struct gicv3_its_softc *sc; 1461301265Sandrew struct its_cmd *cmd, *cmd_sync, *cmd_write; 1462301265Sandrew struct its_col col_sync; 1463301265Sandrew struct its_cmd_desc desc_sync; 1464301265Sandrew uint64_t target, cwriter; 1465301265Sandrew 1466301265Sandrew sc = device_get_softc(dev); 1467301265Sandrew mtx_lock_spin(&sc->sc_its_cmd_lock); 1468301265Sandrew cmd = its_cmd_alloc_locked(dev); 1469301265Sandrew if (cmd == NULL) { 1470301265Sandrew device_printf(dev, "could not allocate ITS command\n"); 1471301265Sandrew mtx_unlock_spin(&sc->sc_its_cmd_lock); 1472301265Sandrew return (EBUSY); 1473301265Sandrew } 1474301265Sandrew 1475301265Sandrew target = its_cmd_prepare(cmd, desc); 1476301265Sandrew its_cmd_sync(sc, cmd); 1477301265Sandrew 1478301265Sandrew if (target != ITS_TARGET_NONE) { 1479301265Sandrew cmd_sync = its_cmd_alloc_locked(dev); 1480301265Sandrew if (cmd_sync != NULL) { 1481301265Sandrew desc_sync.cmd_type = ITS_CMD_SYNC; 1482301265Sandrew col_sync.col_target = target; 1483301265Sandrew desc_sync.cmd_desc_sync.col = &col_sync; 1484301265Sandrew its_cmd_prepare(cmd_sync, &desc_sync); 1485301265Sandrew its_cmd_sync(sc, cmd_sync); 1486301265Sandrew } 1487301265Sandrew } 1488301265Sandrew 1489301265Sandrew /* Update GITS_CWRITER */ 1490301265Sandrew cwriter = sc->sc_its_cmd_next_idx * sizeof(struct its_cmd); 1491301265Sandrew gic_its_write_8(sc, GITS_CWRITER, cwriter); 1492301265Sandrew cmd_write = &sc->sc_its_cmd_base[sc->sc_its_cmd_next_idx]; 1493301265Sandrew mtx_unlock_spin(&sc->sc_its_cmd_lock); 1494301265Sandrew 1495301265Sandrew its_cmd_wait_completion(dev, cmd, cmd_write); 1496301265Sandrew 1497301265Sandrew return (0); 1498301265Sandrew} 1499301265Sandrew 1500301265Sandrew/* Handlers to send commands */ 1501301265Sandrewstatic void 1502301265Sandrewits_cmd_movi(device_t dev, struct gicv3_its_irqsrc *girq) 1503301265Sandrew{ 1504301265Sandrew struct gicv3_its_softc *sc; 1505301265Sandrew struct its_cmd_desc desc; 1506301265Sandrew struct its_col *col; 1507301265Sandrew 1508301265Sandrew sc = device_get_softc(dev); 1509301265Sandrew col = sc->sc_its_cols[CPU_FFS(&girq->gi_isrc.isrc_cpu) - 1]; 1510301265Sandrew 1511301265Sandrew desc.cmd_type = ITS_CMD_MOVI; 1512301265Sandrew desc.cmd_desc_movi.its_dev = girq->gi_its_dev; 1513301265Sandrew desc.cmd_desc_movi.col = col; 1514301265Sandrew desc.cmd_desc_movi.id = girq->gi_irq - girq->gi_its_dev->lpis.lpi_base; 1515301265Sandrew 1516301265Sandrew its_cmd_send(dev, &desc); 1517301265Sandrew} 1518301265Sandrew 1519301265Sandrewstatic void 1520301265Sandrewits_cmd_mapc(device_t dev, struct its_col *col, uint8_t valid) 1521301265Sandrew{ 1522301265Sandrew struct its_cmd_desc desc; 1523301265Sandrew 1524301265Sandrew desc.cmd_type = ITS_CMD_MAPC; 1525301265Sandrew desc.cmd_desc_mapc.col = col; 1526301265Sandrew /* 1527301265Sandrew * Valid bit set - map the collection. 1528301265Sandrew * Valid bit cleared - unmap the collection. 1529301265Sandrew */ 1530301265Sandrew desc.cmd_desc_mapc.valid = valid; 1531301265Sandrew 1532301265Sandrew its_cmd_send(dev, &desc); 1533301265Sandrew} 1534301265Sandrew 1535301265Sandrewstatic void 1536301265Sandrewits_cmd_mapti(device_t dev, struct gicv3_its_irqsrc *girq) 1537301265Sandrew{ 1538301265Sandrew struct gicv3_its_softc *sc; 1539301265Sandrew struct its_cmd_desc desc; 1540301265Sandrew struct its_col *col; 1541301265Sandrew u_int col_id; 1542301265Sandrew 1543301265Sandrew sc = device_get_softc(dev); 1544301265Sandrew 1545301265Sandrew col_id = CPU_FFS(&girq->gi_isrc.isrc_cpu) - 1; 1546301265Sandrew col = sc->sc_its_cols[col_id]; 1547301265Sandrew 1548301265Sandrew desc.cmd_type = ITS_CMD_MAPTI; 1549301265Sandrew desc.cmd_desc_mapvi.its_dev = girq->gi_its_dev; 1550301265Sandrew desc.cmd_desc_mapvi.col = col; 1551301265Sandrew /* The EventID sent to the device */ 1552301265Sandrew desc.cmd_desc_mapvi.id = girq->gi_irq - girq->gi_its_dev->lpis.lpi_base; 1553301265Sandrew /* The physical interrupt presented to softeware */ 1554301265Sandrew desc.cmd_desc_mapvi.pid = girq->gi_irq + GIC_FIRST_LPI; 1555301265Sandrew 1556301265Sandrew its_cmd_send(dev, &desc); 1557301265Sandrew} 1558301265Sandrew 1559301265Sandrewstatic void 1560301265Sandrewits_cmd_mapd(device_t dev, struct its_dev *its_dev, uint8_t valid) 1561301265Sandrew{ 1562301265Sandrew struct its_cmd_desc desc; 1563301265Sandrew 1564301265Sandrew desc.cmd_type = ITS_CMD_MAPD; 1565301265Sandrew desc.cmd_desc_mapd.its_dev = its_dev; 1566301265Sandrew desc.cmd_desc_mapd.valid = valid; 1567301265Sandrew 1568301265Sandrew its_cmd_send(dev, &desc); 1569301265Sandrew} 1570301265Sandrew 1571301265Sandrewstatic void 1572301265Sandrewits_cmd_inv(device_t dev, struct its_dev *its_dev, 1573301265Sandrew struct gicv3_its_irqsrc *girq) 1574301265Sandrew{ 1575301265Sandrew struct gicv3_its_softc *sc; 1576301265Sandrew struct its_cmd_desc desc; 1577301265Sandrew struct its_col *col; 1578301265Sandrew 1579301265Sandrew sc = device_get_softc(dev); 1580301265Sandrew col = sc->sc_its_cols[CPU_FFS(&girq->gi_isrc.isrc_cpu) - 1]; 1581301265Sandrew 1582301265Sandrew desc.cmd_type = ITS_CMD_INV; 1583301265Sandrew /* The EventID sent to the device */ 1584301265Sandrew desc.cmd_desc_inv.pid = girq->gi_irq - its_dev->lpis.lpi_base; 1585301265Sandrew desc.cmd_desc_inv.its_dev = its_dev; 1586301265Sandrew desc.cmd_desc_inv.col = col; 1587301265Sandrew 1588301265Sandrew its_cmd_send(dev, &desc); 1589301265Sandrew} 1590301265Sandrew 1591301265Sandrewstatic void 1592301265Sandrewits_cmd_invall(device_t dev, struct its_col *col) 1593301265Sandrew{ 1594301265Sandrew struct its_cmd_desc desc; 1595301265Sandrew 1596301265Sandrew desc.cmd_type = ITS_CMD_INVALL; 1597301265Sandrew desc.cmd_desc_invall.col = col; 1598301265Sandrew 1599301265Sandrew its_cmd_send(dev, &desc); 1600301265Sandrew} 1601301265Sandrew 1602301265Sandrew#ifdef FDT 1603301265Sandrewstatic device_probe_t gicv3_its_fdt_probe; 1604301265Sandrewstatic device_attach_t gicv3_its_fdt_attach; 1605301265Sandrew 1606301265Sandrewstatic device_method_t gicv3_its_fdt_methods[] = { 1607301265Sandrew /* Device interface */ 1608301265Sandrew DEVMETHOD(device_probe, gicv3_its_fdt_probe), 1609301265Sandrew DEVMETHOD(device_attach, gicv3_its_fdt_attach), 1610301265Sandrew 1611301265Sandrew /* End */ 1612301265Sandrew DEVMETHOD_END 1613301265Sandrew}; 1614301265Sandrew 1615301265Sandrew#define its_baseclasses its_fdt_baseclasses 1616301265SandrewDEFINE_CLASS_1(its, gicv3_its_fdt_driver, gicv3_its_fdt_methods, 1617301265Sandrew sizeof(struct gicv3_its_softc), gicv3_its_driver); 1618301265Sandrew#undef its_baseclasses 1619301265Sandrewstatic devclass_t gicv3_its_fdt_devclass; 1620301265Sandrew 1621301265SandrewEARLY_DRIVER_MODULE(its, gic, gicv3_its_fdt_driver, 1622301265Sandrew gicv3_its_fdt_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 1623301265Sandrew 1624301265Sandrewstatic int 1625301265Sandrewgicv3_its_fdt_probe(device_t dev) 1626301265Sandrew{ 1627301265Sandrew 1628301265Sandrew if (!ofw_bus_status_okay(dev)) 1629301265Sandrew return (ENXIO); 1630301265Sandrew 1631301265Sandrew if (!ofw_bus_is_compatible(dev, "arm,gic-v3-its")) 1632301265Sandrew return (ENXIO); 1633301265Sandrew 1634301265Sandrew device_set_desc(dev, "ARM GIC Interrupt Translation Service"); 1635301265Sandrew return (BUS_PROBE_DEFAULT); 1636301265Sandrew} 1637301265Sandrew 1638301265Sandrewstatic int 1639301265Sandrewgicv3_its_fdt_attach(device_t dev) 1640301265Sandrew{ 1641301265Sandrew struct gicv3_its_softc *sc; 1642301265Sandrew phandle_t xref; 1643301265Sandrew int err; 1644301265Sandrew 1645301265Sandrew err = gicv3_its_attach(dev); 1646301265Sandrew if (err != 0) 1647301265Sandrew return (err); 1648301265Sandrew 1649301265Sandrew sc = device_get_softc(dev); 1650301265Sandrew 1651301265Sandrew /* Register this device as a interrupt controller */ 1652301265Sandrew xref = OF_xref_from_node(ofw_bus_get_node(dev)); 1653301265Sandrew sc->sc_pic = intr_pic_register(dev, xref); 1654301265Sandrew intr_pic_add_handler(device_get_parent(dev), sc->sc_pic, 1655301265Sandrew gicv3_its_intr, sc, GIC_FIRST_LPI, LPI_NIRQS); 1656301265Sandrew 1657301265Sandrew /* Register this device to handle MSI interrupts */ 1658301265Sandrew intr_msi_register(dev, xref); 1659301265Sandrew 1660301265Sandrew return (0); 1661301265Sandrew} 1662301265Sandrew#endif 1663