irqchip/gic-v3-its: Add VPE affinity changes

When we're about to run a vcpu, it is crucial that the redistributor
associated with the physical CPU is being told about the new residency.

This is abstracted by hijacking the irq_set_affinity method for the
doorbell interrupt associated with the VPE. It is expected that the
hypervisor will call this method before scheduling the VPE.

Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

+96
+96
drivers/irqchip/irq-gic-v3-its.c
··· 148 148 #define ITS_LIST_MAX 16 149 149 150 150 static unsigned long its_list_map; 151 + static u16 vmovp_seq_num; 152 + static DEFINE_RAW_SPINLOCK(vmovp_lock); 153 + 151 154 static DEFINE_IDA(its_vpeid_ida); 152 155 153 156 #define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist)) ··· 241 238 u32 event_id; 242 239 bool db_enabled; 243 240 } its_vmovi_cmd; 241 + 242 + struct { 243 + struct its_vpe *vpe; 244 + struct its_collection *col; 245 + u16 seq_num; 246 + u16 its_list; 247 + } its_vmovp_cmd; 244 248 }; 245 249 }; 246 250 ··· 337 327 static void its_encode_db_valid(struct its_cmd_block *cmd, bool db_valid) 338 328 { 339 329 its_mask_encode(&cmd->raw_cmd[2], db_valid, 0, 0); 330 + } 331 + 332 + static void its_encode_seq_num(struct its_cmd_block *cmd, u16 seq_num) 333 + { 334 + its_mask_encode(&cmd->raw_cmd[0], seq_num, 47, 32); 335 + } 336 + 337 + static void its_encode_its_list(struct its_cmd_block *cmd, u16 its_list) 338 + { 339 + its_mask_encode(&cmd->raw_cmd[1], its_list, 15, 0); 340 340 } 341 341 342 342 static void its_encode_vpt_addr(struct its_cmd_block *cmd, u64 vpt_pa) ··· 589 569 its_fixup_cmd(cmd); 590 570 591 571 return desc->its_vmovi_cmd.vpe; 572 + } 573 + 574 + static struct its_vpe *its_build_vmovp_cmd(struct its_cmd_block *cmd, 575 + struct its_cmd_desc *desc) 576 + { 577 + its_encode_cmd(cmd, GITS_CMD_VMOVP); 578 + its_encode_seq_num(cmd, desc->its_vmovp_cmd.seq_num); 579 + its_encode_its_list(cmd, desc->its_vmovp_cmd.its_list); 580 + its_encode_vpeid(cmd, desc->its_vmovp_cmd.vpe->vpe_id); 581 + its_encode_target(cmd, desc->its_vmovp_cmd.col->target_address); 582 + 583 + its_fixup_cmd(cmd); 584 + 585 + return desc->its_vmovp_cmd.vpe; 592 586 } 593 587 594 588 static u64 its_cmd_ptr_to_offset(struct its_node *its, ··· 903 869 desc.its_vmapp_cmd.col = &its->collections[vpe->col_idx]; 904 870 its_send_single_vcommand(its, its_build_vmapp_cmd, &desc); 905 871 } 872 + } 873 + 874 + static void its_send_vmovp(struct its_vpe *vpe) 875 + { 876 + struct its_cmd_desc desc; 877 + struct its_node *its; 878 + unsigned long flags; 879 + int col_id = vpe->col_idx; 880 + 881 + desc.its_vmovp_cmd.vpe = vpe; 882 + desc.its_vmovp_cmd.its_list = (u16)its_list_map; 883 + 884 + if (!its_list_map) { 885 + its = list_first_entry(&its_nodes, struct its_node, entry); 886 + desc.its_vmovp_cmd.seq_num = 0; 887 + desc.its_vmovp_cmd.col = &its->collections[col_id]; 888 + its_send_single_vcommand(its, its_build_vmovp_cmd, &desc); 889 + return; 890 + } 891 + 892 + /* 893 + * Yet another marvel of the architecture. If using the 894 + * its_list "feature", we need to make sure that all ITSs 895 + * receive all VMOVP commands in the same order. The only way 896 + * to guarantee this is to make vmovp a serialization point. 897 + * 898 + * Wall <-- Head. 899 + */ 900 + raw_spin_lock_irqsave(&vmovp_lock, flags); 901 + 902 + desc.its_vmovp_cmd.seq_num = vmovp_seq_num++; 903 + 904 + /* Emit VMOVPs */ 905 + list_for_each_entry(its, &its_nodes, entry) { 906 + if (!its->is_v4) 907 + continue; 908 + 909 + desc.its_vmovp_cmd.col = &its->collections[col_id]; 910 + its_send_single_vcommand(its, its_build_vmovp_cmd, &desc); 911 + } 912 + 913 + raw_spin_unlock_irqrestore(&vmovp_lock, flags); 906 914 } 907 915 908 916 static void its_send_vinvall(struct its_vpe *vpe) ··· 2230 2154 .deactivate = its_irq_domain_deactivate, 2231 2155 }; 2232 2156 2157 + static int its_vpe_set_affinity(struct irq_data *d, 2158 + const struct cpumask *mask_val, 2159 + bool force) 2160 + { 2161 + struct its_vpe *vpe = irq_data_get_irq_chip_data(d); 2162 + int cpu = cpumask_first(mask_val); 2163 + 2164 + /* 2165 + * Changing affinity is mega expensive, so let's be as lazy as 2166 + * we can and only do it if we really have to. 2167 + */ 2168 + if (vpe->col_idx != cpu) { 2169 + vpe->col_idx = cpu; 2170 + its_send_vmovp(vpe); 2171 + } 2172 + 2173 + return IRQ_SET_MASK_OK_DONE; 2174 + } 2175 + 2233 2176 static void its_vpe_schedule(struct its_vpe *vpe) 2234 2177 { 2235 2178 void * __iomem vlpi_base = gic_data_rdist_vlpi_base(); ··· 2338 2243 2339 2244 static struct irq_chip its_vpe_irq_chip = { 2340 2245 .name = "GICv4-vpe", 2246 + .irq_set_affinity = its_vpe_set_affinity, 2341 2247 .irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity, 2342 2248 }; 2343 2249