irqchip/gic-v3: Add support for Range Selector (RS) feature
authorShanker Donthineni <shankerd@codeaurora.org>
Fri, 6 Oct 2017 15:24:00 +0000 (10:24 -0500)
committerMarc Zyngier <marc.zyngier@arm.com>
Thu, 19 Oct 2017 10:22:34 +0000 (11:22 +0100)
A new feature Range Selector (RS) has been added to GIC specification
in order to support more than 16 CPUs at affinity level 0. New fields
are introduced in SGI system registers (ICC_SGI0R_EL1, ICC_SGI1R_EL1
and ICC_ASGI1R_EL1) to relax an artificial limit of 16 at level 0.

- A new RSS field in ICC_CTLR_EL3, ICC_CTLR_EL1 and ICV_CTLR_EL1:
  [18] - Range Selector Support (RSS)
  0b0 = Targeted SGIs with affinity level 0 values of 0-15 are supported.
  0b1 = Targeted SGIs with affinity level 0 values of 0-255 are supported.

- A new RS field in ICC_SGI0R_EL1, ICC_SGI1R_EL1 and ICC_ASGI1R_EL1:
  [47:44] - RangeSelector (RS) which group of 16 TargetList[n] field
            TargetList[n] represents aff0 value ((RS*16)+n)
            When ICC_CTLR_EL3.RSS==0 or ICC_CTLR_EL1.RSS==0, RS is RES0.

- A new RSS field in GICD_TYPER:
  [26] - Range Selector Support (RSS)
  0b0 = Targeted SGIs with affinity level 0 values of 0-15 are supported.
  0b1 = Targeted SGIs with affinity level 0 values of 0-255 are supported.

Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm/include/asm/arch_gicv3.h
arch/arm64/include/asm/arch_gicv3.h
drivers/irqchip/irq-gic-v3.c
include/linux/irqchip/arm-gic-v3.h

index eee269321923b8375e043ad50148031aa00407db..1070044f5c3f4926efc7a8d2a2e1be4cff01b4f1 100644 (file)
@@ -196,6 +196,11 @@ static inline void gic_write_ctlr(u32 val)
        isb();
 }
 
+static inline u32 gic_read_ctlr(void)
+{
+       return read_sysreg(ICC_CTLR);
+}
+
 static inline void gic_write_grpen1(u32 val)
 {
        write_sysreg(val, ICC_IGRPEN1);
index b7e3f74822dafa6525558d356068958acd58c949..9becba9ab392f531a1c9aee64acc316792cb8003 100644 (file)
@@ -87,6 +87,11 @@ static inline void gic_write_ctlr(u32 val)
        isb();
 }
 
+static inline u32 gic_read_ctlr(void)
+{
+       return read_sysreg_s(SYS_ICC_CTLR_EL1);
+}
+
 static inline void gic_write_grpen1(u32 val)
 {
        write_sysreg_s(val, SYS_ICC_IGRPEN1_EL1);
index b5df99c6f680f940a48223455a377a1ef8e07cb2..b54b55597ffb9c8351ff98e97dc05535503ec493 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();
index 1ea576c8126f8b8c467f1ea3ab2623826efde0af..b8b59989bd73dfd5e7a5b3331d689a8456d94272 100644 (file)
@@ -68,6 +68,7 @@
 #define GICD_CTLR_ENABLE_SS_G1         (1U << 1)
 #define GICD_CTLR_ENABLE_SS_G0         (1U << 0)
 
+#define GICD_TYPER_RSS                 (1U << 26)
 #define GICD_TYPER_LPIS                        (1U << 17)
 #define GICD_TYPER_MBIS                        (1U << 16)
 
 #define ICC_CTLR_EL1_SEIS_MASK         (0x1 << ICC_CTLR_EL1_SEIS_SHIFT)
 #define ICC_CTLR_EL1_A3V_SHIFT         15
 #define ICC_CTLR_EL1_A3V_MASK          (0x1 << ICC_CTLR_EL1_A3V_SHIFT)
+#define ICC_CTLR_EL1_RSS               (0x1 << 18)
 #define ICC_PMR_EL1_SHIFT              0
 #define ICC_PMR_EL1_MASK               (0xff << ICC_PMR_EL1_SHIFT)
 #define ICC_BPR0_EL1_SHIFT             0
 #define ICC_SGI1R_AFFINITY_2_SHIFT     32
 #define ICC_SGI1R_AFFINITY_2_MASK      (0xffULL << ICC_SGI1R_AFFINITY_2_SHIFT)
 #define ICC_SGI1R_IRQ_ROUTING_MODE_BIT 40
+#define ICC_SGI1R_RS_SHIFT             44
+#define ICC_SGI1R_RS_MASK              (0xfULL << ICC_SGI1R_RS_SHIFT)
 #define ICC_SGI1R_AFFINITY_3_SHIFT     48
 #define ICC_SGI1R_AFFINITY_3_MASK      (0xffULL << ICC_SGI1R_AFFINITY_3_SHIFT)