Merge branch irq/gic-6.4 into irq/irqchip-next

* irq/gic-6.4:
  : .
  : Collection of GIC/GICv3 fixes and cleanups
  :
  : - Workaround for the nvidia T241 chip that gets confused
  :   in 3 and 4 socket configurations, leading to the GIC
  :   malfunctionning in some contexts
  :
  : - Drop support for non-firmware driven GIC configurarations
  :   now that the old ARM11MP Cavium board is gone
  :
  : - Workaround for the Rockchip 3588 chip that doesn't
  :   correctly deal with the shareability attributes.
  : .
  irqchip/gic-v3: Add Rockchip 3588001 erratum workaround
  irqchip/gicv3: Workaround for NVIDIA erratum T241-FABRIC-4
  irqchip/gic: Drop support for board files

Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Marc Zyngier 2023-04-21 14:05:08 +01:00
commit f39157b3c0
10 changed files with 208 additions and 97 deletions

View file

@ -172,6 +172,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| NVIDIA | Carmel Core | N/A | NVIDIA_CARMEL_CNP_ERRATUM |
+----------------+-----------------+-----------------+-----------------------------+
| NVIDIA | T241 GICv3/4.x | T241-FABRIC-4 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| Freescale/NXP | LS2080A/LS1043A | A-008585 | FSL_ERRATUM_A008585 |
+----------------+-----------------+-----------------+-----------------------------+
@ -205,6 +207,9 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| Qualcomm Tech. | Kryo4xx Gold | N/A | ARM64_ERRATUM_1286807 |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| Rockchip | RK3588 | #3588001 | ROCKCHIP_ERRATUM_3588001 |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| Fujitsu | A64FX | E#010001 | FUJITSU_ERRATUM_010001 |

View file

@ -1150,6 +1150,16 @@ config NVIDIA_CARMEL_CNP_ERRATUM
If unsure, say Y.
config ROCKCHIP_ERRATUM_3588001
bool "Rockchip 3588001: GIC600 can not support shareability attributes"
default y
help
The Rockchip RK3588 GIC600 SoC integration does not support ACE/ACE-lite.
This means, that its sharability feature may not be used, even though it
is supported by the IP itself.
If unsure, say Y.
config SOCIONEXT_SYNQUACER_PREITS
bool "Socionext Synquacer: Workaround for GICv3 pre-ITS"
default y

View file

@ -17,9 +17,13 @@ static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
bool __ro_after_init smccc_trng_available = false;
u64 __ro_after_init smccc_has_sve_hint = false;
s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED;
s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED;
void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
{
struct arm_smccc_res res;
smccc_version = version;
smccc_conduit = conduit;
@ -27,6 +31,18 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
if (IS_ENABLED(CONFIG_ARM64_SVE) &&
smccc_version >= ARM_SMCCC_VERSION_1_3)
smccc_has_sve_hint = true;
if ((smccc_version >= ARM_SMCCC_VERSION_1_2) &&
(smccc_conduit != SMCCC_CONDUIT_NONE)) {
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
ARM_SMCCC_ARCH_SOC_ID, &res);
if ((s32)res.a0 >= 0) {
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res);
smccc_soc_id_version = (s32)res.a0;
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res);
smccc_soc_id_revision = (s32)res.a0;
}
}
}
enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void)
@ -44,6 +60,16 @@ u32 arm_smccc_get_version(void)
}
EXPORT_SYMBOL_GPL(arm_smccc_get_version);
s32 arm_smccc_get_soc_id_version(void)
{
return smccc_soc_id_version;
}
s32 arm_smccc_get_soc_id_revision(void)
{
return smccc_soc_id_revision;
}
static int __init smccc_devices_init(void)
{
struct platform_device *pdev;

View file

@ -42,41 +42,23 @@ static int __init smccc_soc_init(void)
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
return 0;
if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) {
pr_err("%s: invalid SMCCC conduit\n", __func__);
return -EOPNOTSUPP;
}
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
ARM_SMCCC_ARCH_SOC_ID, &res);
if ((int)res.a0 == SMCCC_RET_NOT_SUPPORTED) {
soc_id_version = arm_smccc_get_soc_id_version();
if (soc_id_version == SMCCC_RET_NOT_SUPPORTED) {
pr_info("ARCH_SOC_ID not implemented, skipping ....\n");
return 0;
}
if ((int)res.a0 < 0) {
pr_info("ARCH_FEATURES(ARCH_SOC_ID) returned error: %lx\n",
res.a0);
return -EINVAL;
}
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 0, &res);
if ((int)res.a0 < 0) {
if (soc_id_version < 0) {
pr_err("ARCH_SOC_ID(0) returned error: %lx\n", res.a0);
return -EINVAL;
}
soc_id_version = res.a0;
arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_SOC_ID, 1, &res);
if ((int)res.a0 < 0) {
soc_id_rev = arm_smccc_get_soc_id_revision();
if (soc_id_rev < 0) {
pr_err("ARCH_SOC_ID(1) returned error: %lx\n", res.a0);
return -EINVAL;
}
soc_id_rev = res.a0;
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
if (!soc_dev_attr)
return -ENOMEM;

View file

@ -7,6 +7,7 @@ config IRQCHIP
config ARM_GIC
bool
depends on OF
select IRQ_DOMAIN_HIERARCHY
select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
@ -35,6 +36,7 @@ config ARM_GIC_V3
select IRQ_DOMAIN_HIERARCHY
select PARTITION_PERCPU
select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
select HAVE_ARM_SMCCC_DISCOVERY
config ARM_GIC_V3_ITS
bool

View file

@ -42,9 +42,11 @@
#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0)
#define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1)
#define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2)
#define ITS_FLAGS_FORCE_NON_SHAREABLE (1ULL << 3)
#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0)
#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
#define RDIST_FLAGS_FORCE_NON_SHAREABLE (1 << 2)
#define RD_LOCAL_LPI_ENABLED BIT(0)
#define RD_LOCAL_PENDTABLE_PREALLOCATED BIT(1)
@ -2359,6 +2361,9 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
its_write_baser(its, baser, val);
tmp = baser->val;
if (its->flags & ITS_FLAGS_FORCE_NON_SHAREABLE)
tmp &= ~GITS_BASER_SHAREABILITY_MASK;
if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) {
/*
* Shareability didn't stick. Just use
@ -3096,6 +3101,9 @@ static void its_cpu_init_lpis(void)
gicr_write_propbaser(val, rbase + GICR_PROPBASER);
tmp = gicr_read_propbaser(rbase + GICR_PROPBASER);
if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE)
tmp &= ~GICR_PROPBASER_SHAREABILITY_MASK;
if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) {
/*
@ -3120,6 +3128,9 @@ static void its_cpu_init_lpis(void)
gicr_write_pendbaser(val, rbase + GICR_PENDBASER);
tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER);
if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE)
tmp &= ~GICR_PENDBASER_SHAREABILITY_MASK;
if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) {
/*
* The HW reports non-shareable, we must remove the
@ -4710,6 +4721,19 @@ static bool __maybe_unused its_enable_quirk_hip07_161600802(void *data)
return true;
}
static bool __maybe_unused its_enable_rk3588001(void *data)
{
struct its_node *its = data;
if (!of_machine_is_compatible("rockchip,rk3588"))
return false;
its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE;
gic_rdists->flags |= RDIST_FLAGS_FORCE_NON_SHAREABLE;
return true;
}
static const struct gic_quirk its_quirks[] = {
#ifdef CONFIG_CAVIUM_ERRATUM_22375
{
@ -4755,6 +4779,14 @@ static const struct gic_quirk its_quirks[] = {
.mask = 0xffffffff,
.init = its_enable_quirk_hip07_161600802,
},
#endif
#ifdef CONFIG_ROCKCHIP_ERRATUM_3588001
{
.desc = "ITS: Rockchip erratum RK3588001",
.iidr = 0x0201743b,
.mask = 0xffffffff,
.init = its_enable_rk3588001,
},
#endif
{
}
@ -5096,6 +5128,9 @@ static int __init its_probe_one(struct resource *res,
gits_write_cbaser(baser, its->base + GITS_CBASER);
tmp = gits_read_cbaser(its->base + GITS_CBASER);
if (its->flags & ITS_FLAGS_FORCE_NON_SHAREABLE)
tmp &= ~GITS_CBASER_SHAREABILITY_MASK;
if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) {
if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) {
/*

View file

@ -24,6 +24,9 @@
#include <linux/irqchip/arm-gic-common.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <linux/irqchip/irq-partition-percpu.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/arm-smccc.h>
#include <asm/cputype.h>
#include <asm/exception.h>
@ -47,6 +50,7 @@ struct redist_region {
struct gic_chip_data {
struct fwnode_handle *fwnode;
phys_addr_t dist_phys_base;
void __iomem *dist_base;
struct redist_region *redist_regions;
struct rdists rdists;
@ -59,6 +63,10 @@ struct gic_chip_data {
struct partition_desc **ppi_descs;
};
#define T241_CHIPS_MAX 4
static void __iomem *t241_dist_base_alias[T241_CHIPS_MAX] __read_mostly;
static DEFINE_STATIC_KEY_FALSE(gic_nvidia_t241_erratum);
static struct gic_chip_data gic_data __read_mostly;
static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key);
@ -179,6 +187,39 @@ static inline bool gic_irq_in_rdist(struct irq_data *d)
}
}
static inline void __iomem *gic_dist_base_alias(struct irq_data *d)
{
if (static_branch_unlikely(&gic_nvidia_t241_erratum)) {
irq_hw_number_t hwirq = irqd_to_hwirq(d);
u32 chip;
/*
* For the erratum T241-FABRIC-4, read accesses to GICD_In{E}
* registers are directed to the chip that owns the SPI. The
* the alias region can also be used for writes to the
* GICD_In{E} except GICD_ICENABLERn. Each chip has support
* for 320 {E}SPIs. Mappings for all 4 chips:
* Chip0 = 32-351
* Chip1 = 352-671
* Chip2 = 672-991
* Chip3 = 4096-4415
*/
switch (__get_intid_range(hwirq)) {
case SPI_RANGE:
chip = (hwirq - 32) / 320;
break;
case ESPI_RANGE:
chip = 3;
break;
default:
unreachable();
}
return t241_dist_base_alias[chip];
}
return gic_data.dist_base;
}
static inline void __iomem *gic_dist_base(struct irq_data *d)
{
switch (get_intid_range(d)) {
@ -337,7 +378,7 @@ static int gic_peek_irq(struct irq_data *d, u32 offset)
if (gic_irq_in_rdist(d))
base = gic_data_rdist_sgi_base();
else
base = gic_data.dist_base;
base = gic_dist_base_alias(d);
return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask);
}
@ -588,7 +629,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
if (gic_irq_in_rdist(d))
base = gic_data_rdist_sgi_base();
else
base = gic_data.dist_base;
base = gic_dist_base_alias(d);
offset = convert_offset_index(d, GICD_ICFGR, &index);
@ -1708,6 +1749,43 @@ static bool gic_enable_quirk_hip06_07(void *data)
return false;
}
#define T241_CHIPN_MASK GENMASK_ULL(45, 44)
#define T241_CHIP_GICDA_OFFSET 0x1580000
#define SMCCC_SOC_ID_T241 0x036b0241
static bool gic_enable_quirk_nvidia_t241(void *data)
{
s32 soc_id = arm_smccc_get_soc_id_version();
unsigned long chip_bmask = 0;
phys_addr_t phys;
u32 i;
/* Check JEP106 code for NVIDIA T241 chip (036b:0241) */
if ((soc_id < 0) || (soc_id != SMCCC_SOC_ID_T241))
return false;
/* Find the chips based on GICR regions PHYS addr */
for (i = 0; i < gic_data.nr_redist_regions; i++) {
chip_bmask |= BIT(FIELD_GET(T241_CHIPN_MASK,
(u64)gic_data.redist_regions[i].phys_base));
}
if (hweight32(chip_bmask) < 3)
return false;
/* Setup GICD alias regions */
for (i = 0; i < ARRAY_SIZE(t241_dist_base_alias); i++) {
if (chip_bmask & BIT(i)) {
phys = gic_data.dist_phys_base + T241_CHIP_GICDA_OFFSET;
phys |= FIELD_PREP(T241_CHIPN_MASK, i);
t241_dist_base_alias[i] = ioremap(phys, SZ_64K);
WARN_ON_ONCE(!t241_dist_base_alias[i]);
}
}
static_branch_enable(&gic_nvidia_t241_erratum);
return true;
}
static const struct gic_quirk gic_quirks[] = {
{
.desc = "GICv3: Qualcomm MSM8996 broken firmware",
@ -1739,6 +1817,12 @@ static const struct gic_quirk gic_quirks[] = {
.mask = 0xe8f00fff,
.init = gic_enable_quirk_cavium_38539,
},
{
.desc = "GICv3: NVIDIA erratum T241-FABRIC-4",
.iidr = 0x0402043b,
.mask = 0xffffffff,
.init = gic_enable_quirk_nvidia_t241,
},
{
}
};
@ -1798,7 +1882,8 @@ static void gic_enable_nmi_support(void)
gic_chip.flags |= IRQCHIP_SUPPORTS_NMI;
}
static int __init gic_init_bases(void __iomem *dist_base,
static int __init gic_init_bases(phys_addr_t dist_phys_base,
void __iomem *dist_base,
struct redist_region *rdist_regs,
u32 nr_redist_regions,
u64 redist_stride,
@ -1814,6 +1899,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
pr_info("GIC: Using split EOI/Deactivate mode\n");
gic_data.fwnode = handle;
gic_data.dist_phys_base = dist_phys_base;
gic_data.dist_base = dist_base;
gic_data.redist_regions = rdist_regs;
gic_data.nr_redist_regions = nr_redist_regions;
@ -1841,10 +1927,13 @@ static int __init gic_init_bases(void __iomem *dist_base,
gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
&gic_data);
gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
gic_data.rdists.has_rvpeid = true;
gic_data.rdists.has_vlpis = true;
gic_data.rdists.has_direct_lpi = true;
gic_data.rdists.has_vpend_valid_dirty = true;
if (!static_branch_unlikely(&gic_nvidia_t241_erratum)) {
/* Disable GICv4.x features for the erratum T241-FABRIC-4 */
gic_data.rdists.has_rvpeid = true;
gic_data.rdists.has_vlpis = true;
gic_data.rdists.has_direct_lpi = true;
gic_data.rdists.has_vpend_valid_dirty = true;
}
if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
err = -ENOMEM;
@ -2050,6 +2139,7 @@ static void __iomem *gic_of_iomap(struct device_node *node, int idx,
static int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
phys_addr_t dist_phys_base;
void __iomem *dist_base;
struct redist_region *rdist_regs;
struct resource res;
@ -2063,6 +2153,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
return PTR_ERR(dist_base);
}
dist_phys_base = res.start;
err = gic_validate_dist_version(dist_base);
if (err) {
pr_err("%pOF: no distributor detected, giving up\n", node);
@ -2094,8 +2186,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
gic_enable_of_quirks(node, gic_quirks, &gic_data);
err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
redist_stride, &node->fwnode);
err = gic_init_bases(dist_phys_base, dist_base, rdist_regs,
nr_redist_regions, redist_stride, &node->fwnode);
if (err)
goto out_unmap_rdist;
@ -2411,8 +2503,9 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
goto out_redist_unmap;
}
err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs,
acpi_data.nr_redist_regions, 0, gsi_domain_handle);
err = gic_init_bases(dist->base_address, acpi_data.dist_base,
acpi_data.redist_regs, acpi_data.nr_redist_regions,
0, gsi_domain_handle);
if (err)
goto out_fwhandle_free;

View file

@ -1081,10 +1081,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
return 0;
}
static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
{
}
static int gic_irq_domain_translate(struct irq_domain *d,
struct irq_fwspec *fwspec,
unsigned long *hwirq,
@ -1167,11 +1163,6 @@ static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = {
.free = irq_domain_free_irqs_top,
};
static const struct irq_domain_ops gic_irq_domain_ops = {
.map = gic_irq_domain_map,
.unmap = gic_irq_domain_unmap,
};
static int gic_init_bases(struct gic_chip_data *gic,
struct fwnode_handle *handle)
{
@ -1219,30 +1210,9 @@ static int gic_init_bases(struct gic_chip_data *gic,
gic_irqs = 1020;
gic->gic_irqs = gic_irqs;
if (handle) { /* DT/ACPI */
gic->domain = irq_domain_create_linear(handle, gic_irqs,
&gic_irq_domain_hierarchy_ops,
gic);
} else { /* Legacy support */
/*
* For primary GICs, skip over SGIs.
* No secondary GIC support whatsoever.
*/
int irq_base;
gic_irqs -= 16; /* calculate # of irqs to allocate */
irq_base = irq_alloc_descs(16, 16, gic_irqs,
numa_node_id());
if (irq_base < 0) {
WARN(1, "Cannot allocate irq_descs @ IRQ16, assuming pre-allocated\n");
irq_base = 16;
}
gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base,
16, &gic_irq_domain_ops, gic);
}
gic->domain = irq_domain_create_linear(handle, gic_irqs,
&gic_irq_domain_hierarchy_ops,
gic);
if (WARN_ON(!gic->domain)) {
ret = -ENODEV;
goto error;
@ -1297,23 +1267,6 @@ static int __init __gic_init_bases(struct gic_chip_data *gic,
return ret;
}
void __init gic_init(void __iomem *dist_base, void __iomem *cpu_base)
{
struct gic_chip_data *gic;
/*
* Non-DT/ACPI systems won't run a hypervisor, so let's not
* bother with these...
*/
static_branch_disable(&supports_deactivate_key);
gic = &gic_data[0];
gic->raw_dist_base = dist_base;
gic->raw_cpu_base = cpu_base;
__gic_init_bases(gic, NULL);
}
static void gic_teardown(struct gic_chip_data *gic)
{
if (WARN_ON(!gic))
@ -1325,7 +1278,6 @@ static void gic_teardown(struct gic_chip_data *gic)
iounmap(gic->raw_cpu_base);
}
#ifdef CONFIG_OF
static int gic_cnt __initdata;
static bool gicv2_force_probe;
@ -1570,12 +1522,6 @@ IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init);
#else
int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq)
{
return -ENOTSUPP;
}
#endif
#ifdef CONFIG_ACPI
static struct

View file

@ -226,6 +226,24 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit);
extern u64 smccc_has_sve_hint;
/**
* arm_smccc_get_soc_id_version()
*
* Returns the SOC ID version.
*
* When ARM_SMCCC_ARCH_SOC_ID is not present, returns SMCCC_RET_NOT_SUPPORTED.
*/
s32 arm_smccc_get_soc_id_version(void);
/**
* arm_smccc_get_soc_id_revision()
*
* Returns the SOC ID revision.
*
* When ARM_SMCCC_ARCH_SOC_ID is not present, returns SMCCC_RET_NOT_SUPPORTED.
*/
s32 arm_smccc_get_soc_id_revision(void);
/**
* struct arm_smccc_res - Result from SMC/HVC call
* @a0-a3 result values from registers 0 to 3

View file

@ -151,12 +151,6 @@ int gic_of_init(struct device_node *node, struct device_node *parent);
*/
int gic_of_init_child(struct device *dev, struct gic_chip_data **gic, int irq);
/*
* Legacy platforms not converted to DT yet must use this to init
* their GIC
*/
void gic_init(void __iomem *dist , void __iomem *cpu);
void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
int gic_get_cpu_id(unsigned int cpu);
void gic_migrate_target(unsigned int new_cpu_id);