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 #define ITS_LIST_MAX 16 149 150 static unsigned long its_list_map; 151 static DEFINE_IDA(its_vpeid_ida); 152 153 #define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist)) ··· 241 u32 event_id; 242 bool db_enabled; 243 } its_vmovi_cmd; 244 }; 245 }; 246 ··· 337 static void its_encode_db_valid(struct its_cmd_block *cmd, bool db_valid) 338 { 339 its_mask_encode(&cmd->raw_cmd[2], db_valid, 0, 0); 340 } 341 342 static void its_encode_vpt_addr(struct its_cmd_block *cmd, u64 vpt_pa) ··· 589 its_fixup_cmd(cmd); 590 591 return desc->its_vmovi_cmd.vpe; 592 } 593 594 static u64 its_cmd_ptr_to_offset(struct its_node *its, ··· 903 desc.its_vmapp_cmd.col = &its->collections[vpe->col_idx]; 904 its_send_single_vcommand(its, its_build_vmapp_cmd, &desc); 905 } 906 } 907 908 static void its_send_vinvall(struct its_vpe *vpe) ··· 2230 .deactivate = its_irq_domain_deactivate, 2231 }; 2232 2233 static void its_vpe_schedule(struct its_vpe *vpe) 2234 { 2235 void * __iomem vlpi_base = gic_data_rdist_vlpi_base(); ··· 2338 2339 static struct irq_chip its_vpe_irq_chip = { 2340 .name = "GICv4-vpe", 2341 .irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity, 2342 }; 2343
··· 148 #define ITS_LIST_MAX 16 149 150 static unsigned long its_list_map; 151 + static u16 vmovp_seq_num; 152 + static DEFINE_RAW_SPINLOCK(vmovp_lock); 153 + 154 static DEFINE_IDA(its_vpeid_ida); 155 156 #define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist)) ··· 238 u32 event_id; 239 bool db_enabled; 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; 248 }; 249 }; 250 ··· 327 static void its_encode_db_valid(struct its_cmd_block *cmd, bool db_valid) 328 { 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 } 341 342 static void its_encode_vpt_addr(struct its_cmd_block *cmd, u64 vpt_pa) ··· 569 its_fixup_cmd(cmd); 570 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; 586 } 587 588 static u64 its_cmd_ptr_to_offset(struct its_node *its, ··· 869 desc.its_vmapp_cmd.col = &its->collections[vpe->col_idx]; 870 its_send_single_vcommand(its, its_build_vmapp_cmd, &desc); 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); 914 } 915 916 static void its_send_vinvall(struct its_vpe *vpe) ··· 2154 .deactivate = its_irq_domain_deactivate, 2155 }; 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 + 2176 static void its_vpe_schedule(struct its_vpe *vpe) 2177 { 2178 void * __iomem vlpi_base = gic_data_rdist_vlpi_base(); ··· 2243 2244 static struct irq_chip its_vpe_irq_chip = { 2245 .name = "GICv4-vpe", 2246 + .irq_set_affinity = its_vpe_set_affinity, 2247 .irq_set_vcpu_affinity = its_vpe_set_vcpu_affinity, 2248 }; 2249