Merge tag 'kvm-4.15-1' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[sfrench/cifs-2.6.git] / drivers / irqchip / irq-gic-v3.c
index 854334a6f225488f2cd4dd89f47e61e1fd086a40..17221143f5057ce35f84f6021bf972f32b61bc48 100644 (file)
@@ -55,6 +55,7 @@ struct gic_chip_data {
        struct irq_domain       *domain;
        u64                     redist_stride;
        u32                     nr_redist_regions;
+       bool                    has_rss;
        unsigned int            irq_nr;
        struct partition_desc   *ppi_descs[16];
 };
@@ -63,7 +64,9 @@ static struct gic_chip_data gic_data __read_mostly;
 static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
 
 static struct gic_kvm_info gic_v3_kvm_info;
+static DEFINE_PER_CPU(bool, has_rss);
 
+#define MPIDR_RS(mpidr)                        (((mpidr) & 0xF0UL) >> 4)
 #define gic_data_rdist()               (this_cpu_ptr(gic_data.rdists.rdist))
 #define gic_data_rdist_rd_base()       (gic_data_rdist()->rd_base)
 #define gic_data_rdist_sgi_base()      (gic_data_rdist_rd_base() + SZ_64K)
@@ -526,6 +529,10 @@ static void gic_update_vlpi_properties(void)
 
 static void gic_cpu_sys_reg_init(void)
 {
+       int i, cpu = smp_processor_id();
+       u64 mpidr = cpu_logical_map(cpu);
+       u64 need_rss = MPIDR_RS(mpidr);
+
        /*
         * Need to check that the SRE bit has actually been set. If
         * not, it means that SRE is disabled at EL2. We're going to
@@ -557,6 +564,30 @@ static void gic_cpu_sys_reg_init(void)
 
        /* ... and let's hit the road... */
        gic_write_grpen1(1);
+
+       /* Keep the RSS capability status in per_cpu variable */
+       per_cpu(has_rss, cpu) = !!(gic_read_ctlr() & ICC_CTLR_EL1_RSS);
+
+       /* Check all the CPUs have capable of sending SGIs to other CPUs */
+       for_each_online_cpu(i) {
+               bool have_rss = per_cpu(has_rss, i) && per_cpu(has_rss, cpu);
+
+               need_rss |= MPIDR_RS(cpu_logical_map(i));
+               if (need_rss && (!have_rss))
+                       pr_crit("CPU%d (%lx) can't SGI CPU%d (%lx), no RSS\n",
+                               cpu, (unsigned long)mpidr,
+                               i, (unsigned long)cpu_logical_map(i));
+       }
+
+       /**
+        * GIC spec says, when ICC_CTLR_EL1.RSS==1 and GICD_TYPER.RSS==0,
+        * writing ICC_ASGI1R_EL1 register with RS != 0 is a CONSTRAINED
+        * UNPREDICTABLE choice of :
+        *   - The write is ignored.
+        *   - The RS field is treated as 0.
+        */
+       if (need_rss && (!gic_data.has_rss))
+               pr_crit_once("RSS is required but GICD doesn't support it\n");
 }
 
 static int gic_dist_supports_lpis(void)
@@ -591,6 +622,9 @@ static void gic_cpu_init(void)
 
 #ifdef CONFIG_SMP
 
+#define MPIDR_TO_SGI_RS(mpidr) (MPIDR_RS(mpidr) << ICC_SGI1R_RS_SHIFT)
+#define MPIDR_TO_SGI_CLUSTER_ID(mpidr) ((mpidr) & ~0xFUL)
+
 static int gic_starting_cpu(unsigned int cpu)
 {
        gic_cpu_init();
@@ -605,13 +639,6 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
        u16 tlist = 0;
 
        while (cpu < nr_cpu_ids) {
-               /*
-                * If we ever get a cluster of more than 16 CPUs, just
-                * scream and skip that CPU.
-                */
-               if (WARN_ON((mpidr & 0xff) >= 16))
-                       goto out;
-
                tlist |= 1 << (mpidr & 0xf);
 
                next_cpu = cpumask_next(cpu, mask);
@@ -621,7 +648,7 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
 
                mpidr = cpu_logical_map(cpu);
 
-               if (cluster_id != (mpidr & ~0xffUL)) {
+               if (cluster_id != MPIDR_TO_SGI_CLUSTER_ID(mpidr)) {
                        cpu--;
                        goto out;
                }
@@ -643,6 +670,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
               MPIDR_TO_SGI_AFFINITY(cluster_id, 2)     |
               irq << ICC_SGI1R_SGI_ID_SHIFT            |
               MPIDR_TO_SGI_AFFINITY(cluster_id, 1)     |
+              MPIDR_TO_SGI_RS(cluster_id)              |
               tlist << ICC_SGI1R_TARGET_LIST_SHIFT);
 
        pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
@@ -663,7 +691,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
        smp_wmb();
 
        for_each_cpu(cpu, mask) {
-               unsigned long cluster_id = cpu_logical_map(cpu) & ~0xffUL;
+               u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(cpu_logical_map(cpu));
                u16 tlist;
 
                tlist = gic_compute_target_list(&cpu, mask, cluster_id);
@@ -1007,6 +1035,10 @@ static int __init gic_init_bases(void __iomem *dist_base,
                goto out_free;
        }
 
+       gic_data.has_rss = !!(typer & GICD_TYPER_RSS);
+       pr_info("Distributor has %sRange Selector support\n",
+               gic_data.has_rss ? "" : "no ");
+
        set_handle_irq(gic_handle_irq);
 
        gic_update_vlpi_properties();