|
@@ -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();
|