1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 27de5c0afSMarc Zyngier /* 37de5c0afSMarc Zyngier * Copyright (C) 2016,2017 ARM Limited, All Rights Reserved. 47de5c0afSMarc Zyngier * Author: Marc Zyngier <marc.zyngier@arm.com> 57de5c0afSMarc Zyngier */ 67de5c0afSMarc Zyngier 77de5c0afSMarc Zyngier #include <linux/interrupt.h> 87de5c0afSMarc Zyngier #include <linux/irq.h> 97de5c0afSMarc Zyngier #include <linux/irqdomain.h> 107de5c0afSMarc Zyngier #include <linux/msi.h> 117de5c0afSMarc Zyngier #include <linux/sched.h> 127de5c0afSMarc Zyngier 137de5c0afSMarc Zyngier #include <linux/irqchip/arm-gic-v4.h> 147de5c0afSMarc Zyngier 157954907bSMarc Zyngier /* 167954907bSMarc Zyngier * WARNING: The blurb below assumes that you understand the 177954907bSMarc Zyngier * intricacies of GICv3, GICv4, and how a guest's view of a GICv3 gets 187954907bSMarc Zyngier * translated into GICv4 commands. So it effectively targets at most 197954907bSMarc Zyngier * two individuals. You know who you are. 207954907bSMarc Zyngier * 217954907bSMarc Zyngier * The core GICv4 code is designed to *avoid* exposing too much of the 227954907bSMarc Zyngier * core GIC code (that would in turn leak into the hypervisor code), 237954907bSMarc Zyngier * and instead provide a hypervisor agnostic interface to the HW (of 247954907bSMarc Zyngier * course, the astute reader will quickly realize that hypervisor 257954907bSMarc Zyngier * agnostic actually means KVM-specific - what were you thinking?). 267954907bSMarc Zyngier * 277954907bSMarc Zyngier * In order to achieve a modicum of isolation, we try to hide most of 287954907bSMarc Zyngier * the GICv4 "stuff" behind normal irqchip operations: 297954907bSMarc Zyngier * 307954907bSMarc Zyngier * - Any guest-visible VLPI is backed by a Linux interrupt (and a 317954907bSMarc Zyngier * physical LPI which gets unmapped when the guest maps the 327954907bSMarc Zyngier * VLPI). This allows the same DevID/EventID pair to be either 337954907bSMarc Zyngier * mapped to the LPI (host) or the VLPI (guest). Note that this is 347954907bSMarc Zyngier * exclusive, and you cannot have both. 357954907bSMarc Zyngier * 367954907bSMarc Zyngier * - Enabling/disabling a VLPI is done by issuing mask/unmask calls. 377954907bSMarc Zyngier * 387954907bSMarc Zyngier * - Guest INT/CLEAR commands are implemented through 397954907bSMarc Zyngier * irq_set_irqchip_state(). 407954907bSMarc Zyngier * 417954907bSMarc Zyngier * - The *bizarre* stuff (mapping/unmapping an interrupt to a VLPI, or 427954907bSMarc Zyngier * issuing an INV after changing a priority) gets shoved into the 437954907bSMarc Zyngier * irq_set_vcpu_affinity() method. While this is quite horrible 447954907bSMarc Zyngier * (let's face it, this is the irqchip version of an ioctl), it 457954907bSMarc Zyngier * confines the crap to a single location. And map/unmap really is 467954907bSMarc Zyngier * about setting the affinity of a VLPI to a vcpu, so only INV is 477954907bSMarc Zyngier * majorly out of place. So there. 487954907bSMarc Zyngier * 497954907bSMarc Zyngier * A number of commands are simply not provided by this interface, as 507954907bSMarc Zyngier * they do not make direct sense. For example, MAPD is purely local to 517954907bSMarc Zyngier * the virtual ITS (because it references a virtual device, and the 527954907bSMarc Zyngier * physical ITS is still very much in charge of the physical 537954907bSMarc Zyngier * device). Same goes for things like MAPC (the physical ITS deals 547954907bSMarc Zyngier * with the actual vPE affinity, and not the braindead concept of 557954907bSMarc Zyngier * collection). SYNC is not provided either, as each and every command 567954907bSMarc Zyngier * is followed by a VSYNC. This could be relaxed in the future, should 577954907bSMarc Zyngier * this be seen as a bottleneck (yes, this means *never*). 587954907bSMarc Zyngier * 597954907bSMarc Zyngier * But handling VLPIs is only one side of the job of the GICv4 607954907bSMarc Zyngier * code. The other (darker) side is to take care of the doorbell 617954907bSMarc Zyngier * interrupts which are delivered when a VLPI targeting a non-running 627954907bSMarc Zyngier * vcpu is being made pending. 637954907bSMarc Zyngier * 647954907bSMarc Zyngier * The choice made here is that each vcpu (VPE in old northern GICv4 657954907bSMarc Zyngier * dialect) gets a single doorbell LPI, no matter how many interrupts 667954907bSMarc Zyngier * are targeting it. This has a nice property, which is that the 677954907bSMarc Zyngier * interrupt becomes a handle for the VPE, and that the hypervisor 687954907bSMarc Zyngier * code can manipulate it through the normal interrupt API: 697954907bSMarc Zyngier * 707954907bSMarc Zyngier * - VMs (or rather the VM abstraction that matters to the GIC) 717954907bSMarc Zyngier * contain an irq domain where each interrupt maps to a VPE. In 727954907bSMarc Zyngier * turn, this domain sits on top of the normal LPI allocator, and a 737954907bSMarc Zyngier * specially crafted irq_chip implementation. 747954907bSMarc Zyngier * 757954907bSMarc Zyngier * - mask/unmask do what is expected on the doorbell interrupt. 767954907bSMarc Zyngier * 777954907bSMarc Zyngier * - irq_set_affinity is used to move a VPE from one redistributor to 787954907bSMarc Zyngier * another. 797954907bSMarc Zyngier * 807954907bSMarc Zyngier * - irq_set_vcpu_affinity once again gets hijacked for the purpose of 817954907bSMarc Zyngier * creating a new sub-API, namely scheduling/descheduling a VPE 827954907bSMarc Zyngier * (which involves programming GICR_V{PROP,PEND}BASER) and 837954907bSMarc Zyngier * performing INVALL operations. 847954907bSMarc Zyngier */ 857954907bSMarc Zyngier 867de5c0afSMarc Zyngier static struct irq_domain *gic_domain; 877de5c0afSMarc Zyngier static const struct irq_domain_ops *vpe_domain_ops; 88166cba71SMarc Zyngier static const struct irq_domain_ops *sgi_domain_ops; 897de5c0afSMarc Zyngier 90*46135d6fSLorenzo Pieralisi #ifdef CONFIG_ARM64 91*46135d6fSLorenzo Pieralisi #include <asm/cpufeature.h> 92*46135d6fSLorenzo Pieralisi 93*46135d6fSLorenzo Pieralisi bool gic_cpuif_has_vsgi(void) 94*46135d6fSLorenzo Pieralisi { 95*46135d6fSLorenzo Pieralisi unsigned long fld, reg = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); 96*46135d6fSLorenzo Pieralisi 97*46135d6fSLorenzo Pieralisi fld = cpuid_feature_extract_unsigned_field(reg, ID_AA64PFR0_GIC_SHIFT); 98*46135d6fSLorenzo Pieralisi 99*46135d6fSLorenzo Pieralisi return fld >= 0x3; 100*46135d6fSLorenzo Pieralisi } 101*46135d6fSLorenzo Pieralisi #else 102*46135d6fSLorenzo Pieralisi bool gic_cpuif_has_vsgi(void) 103*46135d6fSLorenzo Pieralisi { 104*46135d6fSLorenzo Pieralisi return false; 105*46135d6fSLorenzo Pieralisi } 106*46135d6fSLorenzo Pieralisi #endif 107*46135d6fSLorenzo Pieralisi 108ae699ad3SMarc Zyngier static bool has_v4_1(void) 109ae699ad3SMarc Zyngier { 110ae699ad3SMarc Zyngier return !!sgi_domain_ops; 111ae699ad3SMarc Zyngier } 112ae699ad3SMarc Zyngier 113*46135d6fSLorenzo Pieralisi static bool has_v4_1_sgi(void) 114*46135d6fSLorenzo Pieralisi { 115*46135d6fSLorenzo Pieralisi return has_v4_1() && gic_cpuif_has_vsgi(); 116*46135d6fSLorenzo Pieralisi } 117*46135d6fSLorenzo Pieralisi 1186d31b6ffSMarc Zyngier static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx) 1196d31b6ffSMarc Zyngier { 1206d31b6ffSMarc Zyngier char *name; 1216d31b6ffSMarc Zyngier int sgi_base; 1226d31b6ffSMarc Zyngier 123*46135d6fSLorenzo Pieralisi if (!has_v4_1_sgi()) 1246d31b6ffSMarc Zyngier return 0; 1256d31b6ffSMarc Zyngier 1266d31b6ffSMarc Zyngier name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current)); 1276d31b6ffSMarc Zyngier if (!name) 1286d31b6ffSMarc Zyngier goto err; 1296d31b6ffSMarc Zyngier 1306d31b6ffSMarc Zyngier vpe->fwnode = irq_domain_alloc_named_id_fwnode(name, idx); 1316d31b6ffSMarc Zyngier if (!vpe->fwnode) 1326d31b6ffSMarc Zyngier goto err; 1336d31b6ffSMarc Zyngier 1346d31b6ffSMarc Zyngier kfree(name); 1356d31b6ffSMarc Zyngier name = NULL; 1366d31b6ffSMarc Zyngier 1376d31b6ffSMarc Zyngier vpe->sgi_domain = irq_domain_create_linear(vpe->fwnode, 16, 1386d31b6ffSMarc Zyngier sgi_domain_ops, vpe); 1396d31b6ffSMarc Zyngier if (!vpe->sgi_domain) 1406d31b6ffSMarc Zyngier goto err; 1416d31b6ffSMarc Zyngier 1426d31b6ffSMarc Zyngier sgi_base = __irq_domain_alloc_irqs(vpe->sgi_domain, -1, 16, 1436d31b6ffSMarc Zyngier NUMA_NO_NODE, vpe, 1446d31b6ffSMarc Zyngier false, NULL); 1456d31b6ffSMarc Zyngier if (sgi_base <= 0) 1466d31b6ffSMarc Zyngier goto err; 1476d31b6ffSMarc Zyngier 1486d31b6ffSMarc Zyngier return 0; 1496d31b6ffSMarc Zyngier 1506d31b6ffSMarc Zyngier err: 1516d31b6ffSMarc Zyngier if (vpe->sgi_domain) 1526d31b6ffSMarc Zyngier irq_domain_remove(vpe->sgi_domain); 1536d31b6ffSMarc Zyngier if (vpe->fwnode) 1546d31b6ffSMarc Zyngier irq_domain_free_fwnode(vpe->fwnode); 1556d31b6ffSMarc Zyngier kfree(name); 1566d31b6ffSMarc Zyngier return -ENOMEM; 1576d31b6ffSMarc Zyngier } 1586d31b6ffSMarc Zyngier 1597de5c0afSMarc Zyngier int its_alloc_vcpu_irqs(struct its_vm *vm) 1607de5c0afSMarc Zyngier { 1617de5c0afSMarc Zyngier int vpe_base_irq, i; 1627de5c0afSMarc Zyngier 1637de5c0afSMarc Zyngier vm->fwnode = irq_domain_alloc_named_id_fwnode("GICv4-vpe", 1647de5c0afSMarc Zyngier task_pid_nr(current)); 1657de5c0afSMarc Zyngier if (!vm->fwnode) 1667de5c0afSMarc Zyngier goto err; 1677de5c0afSMarc Zyngier 1687de5c0afSMarc Zyngier vm->domain = irq_domain_create_hierarchy(gic_domain, 0, vm->nr_vpes, 1697de5c0afSMarc Zyngier vm->fwnode, vpe_domain_ops, 1707de5c0afSMarc Zyngier vm); 1717de5c0afSMarc Zyngier if (!vm->domain) 1727de5c0afSMarc Zyngier goto err; 1737de5c0afSMarc Zyngier 1747de5c0afSMarc Zyngier for (i = 0; i < vm->nr_vpes; i++) { 1757de5c0afSMarc Zyngier vm->vpes[i]->its_vm = vm; 1767de5c0afSMarc Zyngier vm->vpes[i]->idai = true; 1777de5c0afSMarc Zyngier } 1787de5c0afSMarc Zyngier 1797de5c0afSMarc Zyngier vpe_base_irq = __irq_domain_alloc_irqs(vm->domain, -1, vm->nr_vpes, 1807de5c0afSMarc Zyngier NUMA_NO_NODE, vm, 1817de5c0afSMarc Zyngier false, NULL); 1827de5c0afSMarc Zyngier if (vpe_base_irq <= 0) 1837de5c0afSMarc Zyngier goto err; 1847de5c0afSMarc Zyngier 1856d31b6ffSMarc Zyngier for (i = 0; i < vm->nr_vpes; i++) { 1866d31b6ffSMarc Zyngier int ret; 1877de5c0afSMarc Zyngier vm->vpes[i]->irq = vpe_base_irq + i; 1886d31b6ffSMarc Zyngier ret = its_alloc_vcpu_sgis(vm->vpes[i], i); 1896d31b6ffSMarc Zyngier if (ret) 1906d31b6ffSMarc Zyngier goto err; 1916d31b6ffSMarc Zyngier } 1927de5c0afSMarc Zyngier 1937de5c0afSMarc Zyngier return 0; 1947de5c0afSMarc Zyngier 1957de5c0afSMarc Zyngier err: 1967de5c0afSMarc Zyngier if (vm->domain) 1977de5c0afSMarc Zyngier irq_domain_remove(vm->domain); 1987de5c0afSMarc Zyngier if (vm->fwnode) 1997de5c0afSMarc Zyngier irq_domain_free_fwnode(vm->fwnode); 2007de5c0afSMarc Zyngier 2017de5c0afSMarc Zyngier return -ENOMEM; 2027de5c0afSMarc Zyngier } 2037de5c0afSMarc Zyngier 2046d31b6ffSMarc Zyngier static void its_free_sgi_irqs(struct its_vm *vm) 2056d31b6ffSMarc Zyngier { 2066d31b6ffSMarc Zyngier int i; 2076d31b6ffSMarc Zyngier 208*46135d6fSLorenzo Pieralisi if (!has_v4_1_sgi()) 2096d31b6ffSMarc Zyngier return; 2106d31b6ffSMarc Zyngier 2116d31b6ffSMarc Zyngier for (i = 0; i < vm->nr_vpes; i++) { 2126d31b6ffSMarc Zyngier unsigned int irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0); 2136d31b6ffSMarc Zyngier 2146d31b6ffSMarc Zyngier if (WARN_ON(!irq)) 2156d31b6ffSMarc Zyngier continue; 2166d31b6ffSMarc Zyngier 2176d31b6ffSMarc Zyngier irq_domain_free_irqs(irq, 16); 2186d31b6ffSMarc Zyngier irq_domain_remove(vm->vpes[i]->sgi_domain); 2196d31b6ffSMarc Zyngier irq_domain_free_fwnode(vm->vpes[i]->fwnode); 2206d31b6ffSMarc Zyngier } 2216d31b6ffSMarc Zyngier } 2226d31b6ffSMarc Zyngier 2237de5c0afSMarc Zyngier void its_free_vcpu_irqs(struct its_vm *vm) 2247de5c0afSMarc Zyngier { 2256d31b6ffSMarc Zyngier its_free_sgi_irqs(vm); 2267de5c0afSMarc Zyngier irq_domain_free_irqs(vm->vpes[0]->irq, vm->nr_vpes); 2277de5c0afSMarc Zyngier irq_domain_remove(vm->domain); 2287de5c0afSMarc Zyngier irq_domain_free_fwnode(vm->fwnode); 2297de5c0afSMarc Zyngier } 230eab84318SMarc Zyngier 231eab84318SMarc Zyngier static int its_send_vpe_cmd(struct its_vpe *vpe, struct its_cmd_info *info) 232eab84318SMarc Zyngier { 233eab84318SMarc Zyngier return irq_set_vcpu_affinity(vpe->irq, info); 234eab84318SMarc Zyngier } 235eab84318SMarc Zyngier 236ae699ad3SMarc Zyngier int its_make_vpe_non_resident(struct its_vpe *vpe, bool db) 237eab84318SMarc Zyngier { 238ae699ad3SMarc Zyngier struct irq_desc *desc = irq_to_desc(vpe->irq); 239ae699ad3SMarc Zyngier struct its_cmd_info info = { }; 2408e01d9a3SMarc Zyngier int ret; 241eab84318SMarc Zyngier 242eab84318SMarc Zyngier WARN_ON(preemptible()); 243eab84318SMarc Zyngier 244ae699ad3SMarc Zyngier info.cmd_type = DESCHEDULE_VPE; 245ae699ad3SMarc Zyngier if (has_v4_1()) { 246ae699ad3SMarc Zyngier /* GICv4.1 can directly deal with doorbells */ 247ae699ad3SMarc Zyngier info.req_db = db; 248ae699ad3SMarc Zyngier } else { 249ae699ad3SMarc Zyngier /* Undo the nested disable_irq() calls... */ 250ae699ad3SMarc Zyngier while (db && irqd_irq_disabled(&desc->irq_data)) 251ae699ad3SMarc Zyngier enable_irq(vpe->irq); 252ae699ad3SMarc Zyngier } 253eab84318SMarc Zyngier 2548e01d9a3SMarc Zyngier ret = its_send_vpe_cmd(vpe, &info); 2558e01d9a3SMarc Zyngier if (!ret) 256ae699ad3SMarc Zyngier vpe->resident = false; 257ae699ad3SMarc Zyngier 25857e3cebdSShenming Lu vpe->ready = false; 25957e3cebdSShenming Lu 260ae699ad3SMarc Zyngier return ret; 261ae699ad3SMarc Zyngier } 262ae699ad3SMarc Zyngier 263ae699ad3SMarc Zyngier int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en) 264ae699ad3SMarc Zyngier { 265ae699ad3SMarc Zyngier struct its_cmd_info info = { }; 266ae699ad3SMarc Zyngier int ret; 267ae699ad3SMarc Zyngier 268ae699ad3SMarc Zyngier WARN_ON(preemptible()); 269ae699ad3SMarc Zyngier 270ae699ad3SMarc Zyngier info.cmd_type = SCHEDULE_VPE; 271ae699ad3SMarc Zyngier if (has_v4_1()) { 272ae699ad3SMarc Zyngier info.g0en = g0en; 273ae699ad3SMarc Zyngier info.g1en = g1en; 274ae699ad3SMarc Zyngier } else { 275ae699ad3SMarc Zyngier /* Disabled the doorbell, as we're about to enter the guest */ 276ae699ad3SMarc Zyngier disable_irq_nosync(vpe->irq); 277ae699ad3SMarc Zyngier } 278ae699ad3SMarc Zyngier 279ae699ad3SMarc Zyngier ret = its_send_vpe_cmd(vpe, &info); 280ae699ad3SMarc Zyngier if (!ret) 281ae699ad3SMarc Zyngier vpe->resident = true; 2828e01d9a3SMarc Zyngier 2838e01d9a3SMarc Zyngier return ret; 284eab84318SMarc Zyngier } 285eab84318SMarc Zyngier 28657e3cebdSShenming Lu int its_commit_vpe(struct its_vpe *vpe) 28757e3cebdSShenming Lu { 28857e3cebdSShenming Lu struct its_cmd_info info = { 28957e3cebdSShenming Lu .cmd_type = COMMIT_VPE, 29057e3cebdSShenming Lu }; 29157e3cebdSShenming Lu int ret; 29257e3cebdSShenming Lu 29357e3cebdSShenming Lu WARN_ON(preemptible()); 29457e3cebdSShenming Lu 29557e3cebdSShenming Lu ret = its_send_vpe_cmd(vpe, &info); 29657e3cebdSShenming Lu if (!ret) 29757e3cebdSShenming Lu vpe->ready = true; 29857e3cebdSShenming Lu 29957e3cebdSShenming Lu return ret; 30057e3cebdSShenming Lu } 30157e3cebdSShenming Lu 30257e3cebdSShenming Lu 303eab84318SMarc Zyngier int its_invall_vpe(struct its_vpe *vpe) 304eab84318SMarc Zyngier { 305eab84318SMarc Zyngier struct its_cmd_info info = { 306eab84318SMarc Zyngier .cmd_type = INVALL_VPE, 307eab84318SMarc Zyngier }; 308eab84318SMarc Zyngier 309eab84318SMarc Zyngier return its_send_vpe_cmd(vpe, &info); 310eab84318SMarc Zyngier } 311f2eac75dSMarc Zyngier 312f2eac75dSMarc Zyngier int its_map_vlpi(int irq, struct its_vlpi_map *map) 313f2eac75dSMarc Zyngier { 314f2eac75dSMarc Zyngier struct its_cmd_info info = { 315f2eac75dSMarc Zyngier .cmd_type = MAP_VLPI, 3166c09ffd0SArnd Bergmann { 317f2eac75dSMarc Zyngier .map = map, 3186c09ffd0SArnd Bergmann }, 319f2eac75dSMarc Zyngier }; 32090dc7122SMarc Zyngier int ret; 321f2eac75dSMarc Zyngier 322f2eac75dSMarc Zyngier /* 323f2eac75dSMarc Zyngier * The host will never see that interrupt firing again, so it 324f2eac75dSMarc Zyngier * is vital that we don't do any lazy masking. 325f2eac75dSMarc Zyngier */ 326f2eac75dSMarc Zyngier irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); 327f2eac75dSMarc Zyngier 32890dc7122SMarc Zyngier ret = irq_set_vcpu_affinity(irq, &info); 32990dc7122SMarc Zyngier if (ret) 33090dc7122SMarc Zyngier irq_clear_status_flags(irq, IRQ_DISABLE_UNLAZY); 33190dc7122SMarc Zyngier 33290dc7122SMarc Zyngier return ret; 333f2eac75dSMarc Zyngier } 334f2eac75dSMarc Zyngier 335f2eac75dSMarc Zyngier int its_get_vlpi(int irq, struct its_vlpi_map *map) 336f2eac75dSMarc Zyngier { 337f2eac75dSMarc Zyngier struct its_cmd_info info = { 338f2eac75dSMarc Zyngier .cmd_type = GET_VLPI, 3396c09ffd0SArnd Bergmann { 340f2eac75dSMarc Zyngier .map = map, 3416c09ffd0SArnd Bergmann }, 342f2eac75dSMarc Zyngier }; 343f2eac75dSMarc Zyngier 344f2eac75dSMarc Zyngier return irq_set_vcpu_affinity(irq, &info); 345f2eac75dSMarc Zyngier } 346f2eac75dSMarc Zyngier 347f2eac75dSMarc Zyngier int its_unmap_vlpi(int irq) 348f2eac75dSMarc Zyngier { 349f2eac75dSMarc Zyngier irq_clear_status_flags(irq, IRQ_DISABLE_UNLAZY); 350f2eac75dSMarc Zyngier return irq_set_vcpu_affinity(irq, NULL); 351f2eac75dSMarc Zyngier } 352f2eac75dSMarc Zyngier 353f2eac75dSMarc Zyngier int its_prop_update_vlpi(int irq, u8 config, bool inv) 354f2eac75dSMarc Zyngier { 355f2eac75dSMarc Zyngier struct its_cmd_info info = { 356f2eac75dSMarc Zyngier .cmd_type = inv ? PROP_UPDATE_AND_INV_VLPI : PROP_UPDATE_VLPI, 3576c09ffd0SArnd Bergmann { 358f2eac75dSMarc Zyngier .config = config, 3596c09ffd0SArnd Bergmann }, 360f2eac75dSMarc Zyngier }; 361f2eac75dSMarc Zyngier 362f2eac75dSMarc Zyngier return irq_set_vcpu_affinity(irq, &info); 363f2eac75dSMarc Zyngier } 3643d63cb53SMarc Zyngier 365d50676f5SMarc Zyngier int its_prop_update_vsgi(int irq, u8 priority, bool group) 366d50676f5SMarc Zyngier { 367d50676f5SMarc Zyngier struct its_cmd_info info = { 368d50676f5SMarc Zyngier .cmd_type = PROP_UPDATE_VSGI, 369d50676f5SMarc Zyngier { 370d50676f5SMarc Zyngier .priority = priority, 371d50676f5SMarc Zyngier .group = group, 372d50676f5SMarc Zyngier }, 373d50676f5SMarc Zyngier }; 374d50676f5SMarc Zyngier 375d50676f5SMarc Zyngier return irq_set_vcpu_affinity(irq, &info); 376d50676f5SMarc Zyngier } 377d50676f5SMarc Zyngier 378166cba71SMarc Zyngier int its_init_v4(struct irq_domain *domain, 379166cba71SMarc Zyngier const struct irq_domain_ops *vpe_ops, 380166cba71SMarc Zyngier const struct irq_domain_ops *sgi_ops) 3813d63cb53SMarc Zyngier { 3823d63cb53SMarc Zyngier if (domain) { 3833d63cb53SMarc Zyngier pr_info("ITS: Enabling GICv4 support\n"); 3843d63cb53SMarc Zyngier gic_domain = domain; 385166cba71SMarc Zyngier vpe_domain_ops = vpe_ops; 386166cba71SMarc Zyngier sgi_domain_ops = sgi_ops; 3873d63cb53SMarc Zyngier return 0; 3883d63cb53SMarc Zyngier } 3893d63cb53SMarc Zyngier 3903d63cb53SMarc Zyngier pr_err("ITS: No GICv4 VPE domain allocated\n"); 3913d63cb53SMarc Zyngier return -ENODEV; 3923d63cb53SMarc Zyngier } 393