2020-06-25 09:59:39 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* Copyright 2020 Arm Limited
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) "SMCCC: SOC_ID: " fmt
|
|
|
|
|
|
|
|
#include <linux/arm-smccc.h>
|
|
|
|
#include <linux/bitfield.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/sys_soc.h>
|
|
|
|
|
|
|
|
#define SMCCC_SOC_ID_JEP106_BANK_IDX_MASK GENMASK(30, 24)
|
|
|
|
/*
|
|
|
|
* As per the SMC Calling Convention specification v1.2 (ARM DEN 0028C)
|
|
|
|
* Section 7.4 SMCCC_ARCH_SOC_ID bits[23:16] are JEP-106 identification
|
|
|
|
* code with parity bit for the SiP. We can drop the parity bit.
|
|
|
|
*/
|
|
|
|
#define SMCCC_SOC_ID_JEP106_ID_CODE_MASK GENMASK(22, 16)
|
|
|
|
#define SMCCC_SOC_ID_IMP_DEF_SOC_ID_MASK GENMASK(15, 0)
|
|
|
|
|
|
|
|
#define JEP106_BANK_CONT_CODE(x) \
|
|
|
|
(u8)(FIELD_GET(SMCCC_SOC_ID_JEP106_BANK_IDX_MASK, (x)))
|
|
|
|
#define JEP106_ID_CODE(x) \
|
|
|
|
(u8)(FIELD_GET(SMCCC_SOC_ID_JEP106_ID_CODE_MASK, (x)))
|
|
|
|
#define IMP_DEF_SOC_ID(x) \
|
|
|
|
(u16)(FIELD_GET(SMCCC_SOC_ID_IMP_DEF_SOC_ID_MASK, (x)))
|
|
|
|
|
|
|
|
static struct soc_device *soc_dev;
|
|
|
|
static struct soc_device_attribute *soc_dev_attr;
|
|
|
|
|
|
|
|
static int __init smccc_soc_init(void)
|
|
|
|
{
|
|
|
|
int soc_id_rev, soc_id_version;
|
|
|
|
static char soc_id_str[20], soc_id_rev_str[12];
|
|
|
|
static char soc_id_jep106_id_str[12];
|
|
|
|
|
|
|
|
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
|
|
|
return 0;
|
|
|
|
|
irqchip/gicv3: Workaround for NVIDIA erratum T241-FABRIC-4
The T241 platform suffers from the T241-FABRIC-4 erratum which causes
unexpected behavior in the GIC when multiple transactions are received
simultaneously from different sources. This hardware issue impacts
NVIDIA server platforms that use more than two T241 chips
interconnected. Each chip has support for 320 {E}SPIs.
This issue occurs when multiple packets from different GICs are
incorrectly interleaved at the target chip. The erratum text below
specifies exactly what can cause multiple transfer packets susceptible
to interleaving and GIC state corruption. GIC state corruption can
lead to a range of problems, including kernel panics, and unexpected
behavior.
>From the erratum text:
"In some cases, inter-socket AXI4 Stream packets with multiple
transfers, may be interleaved by the fabric when presented to ARM
Generic Interrupt Controller. GIC expects all transfers of a packet
to be delivered without any interleaving.
The following GICv3 commands may result in multiple transfer packets
over inter-socket AXI4 Stream interface:
- Register reads from GICD_I* and GICD_N*
- Register writes to 64-bit GICD registers other than GICD_IROUTERn*
- ITS command MOVALL
Multiple commands in GICv4+ utilize multiple transfer packets,
including VMOVP, VMOVI, VMAPP, and 64-bit register accesses."
This issue impacts system configurations with more than 2 sockets,
that require multi-transfer packets to be sent over inter-socket
AXI4 Stream interface between GIC instances on different sockets.
GICv4 cannot be supported. GICv3 SW model can only be supported
with the workaround. Single and Dual socket configurations are not
impacted by this issue and support GICv3 and GICv4."
Link: https://developer.nvidia.com/docs/t241-fabric-4/nvidia-t241-fabric-4-errata.pdf
Writing to the chip alias region of the GICD_In{E} registers except
GICD_ICENABLERn has an equivalent effect as writing to the global
distributor. The SPI interrupt deactivate path is not impacted by
the erratum.
To fix this problem, implement a workaround that ensures read accesses
to the GICD_In{E} registers are directed to the chip that owns the
SPI, and disable GICv4.x features. To simplify code changes, the
gic_configure_irq() function uses the same alias region for both read
and write operations to GICD_ICFGR.
Co-developed-by: Vikram Sethi <vsethi@nvidia.com>
Signed-off-by: Vikram Sethi <vsethi@nvidia.com>
Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com>
Acked-by: Sudeep Holla <sudeep.holla@arm.com> (for SMCCC/SOC ID bits)
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20230319024314.3540573-2-sdonthineni@nvidia.com
2023-03-19 02:43:14 +00:00
|
|
|
soc_id_version = arm_smccc_get_soc_id_version();
|
|
|
|
if (soc_id_version == SMCCC_RET_NOT_SUPPORTED) {
|
2020-06-25 09:59:39 +00:00
|
|
|
pr_info("ARCH_SOC_ID not implemented, skipping ....\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
irqchip/gicv3: Workaround for NVIDIA erratum T241-FABRIC-4
The T241 platform suffers from the T241-FABRIC-4 erratum which causes
unexpected behavior in the GIC when multiple transactions are received
simultaneously from different sources. This hardware issue impacts
NVIDIA server platforms that use more than two T241 chips
interconnected. Each chip has support for 320 {E}SPIs.
This issue occurs when multiple packets from different GICs are
incorrectly interleaved at the target chip. The erratum text below
specifies exactly what can cause multiple transfer packets susceptible
to interleaving and GIC state corruption. GIC state corruption can
lead to a range of problems, including kernel panics, and unexpected
behavior.
>From the erratum text:
"In some cases, inter-socket AXI4 Stream packets with multiple
transfers, may be interleaved by the fabric when presented to ARM
Generic Interrupt Controller. GIC expects all transfers of a packet
to be delivered without any interleaving.
The following GICv3 commands may result in multiple transfer packets
over inter-socket AXI4 Stream interface:
- Register reads from GICD_I* and GICD_N*
- Register writes to 64-bit GICD registers other than GICD_IROUTERn*
- ITS command MOVALL
Multiple commands in GICv4+ utilize multiple transfer packets,
including VMOVP, VMOVI, VMAPP, and 64-bit register accesses."
This issue impacts system configurations with more than 2 sockets,
that require multi-transfer packets to be sent over inter-socket
AXI4 Stream interface between GIC instances on different sockets.
GICv4 cannot be supported. GICv3 SW model can only be supported
with the workaround. Single and Dual socket configurations are not
impacted by this issue and support GICv3 and GICv4."
Link: https://developer.nvidia.com/docs/t241-fabric-4/nvidia-t241-fabric-4-errata.pdf
Writing to the chip alias region of the GICD_In{E} registers except
GICD_ICENABLERn has an equivalent effect as writing to the global
distributor. The SPI interrupt deactivate path is not impacted by
the erratum.
To fix this problem, implement a workaround that ensures read accesses
to the GICD_In{E} registers are directed to the chip that owns the
SPI, and disable GICv4.x features. To simplify code changes, the
gic_configure_irq() function uses the same alias region for both read
and write operations to GICD_ICFGR.
Co-developed-by: Vikram Sethi <vsethi@nvidia.com>
Signed-off-by: Vikram Sethi <vsethi@nvidia.com>
Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com>
Acked-by: Sudeep Holla <sudeep.holla@arm.com> (for SMCCC/SOC ID bits)
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20230319024314.3540573-2-sdonthineni@nvidia.com
2023-03-19 02:43:14 +00:00
|
|
|
if (soc_id_version < 0) {
|
2023-07-17 17:17:02 +00:00
|
|
|
pr_err("Invalid SoC Version: %x\n", soc_id_version);
|
2020-06-25 09:59:39 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
irqchip/gicv3: Workaround for NVIDIA erratum T241-FABRIC-4
The T241 platform suffers from the T241-FABRIC-4 erratum which causes
unexpected behavior in the GIC when multiple transactions are received
simultaneously from different sources. This hardware issue impacts
NVIDIA server platforms that use more than two T241 chips
interconnected. Each chip has support for 320 {E}SPIs.
This issue occurs when multiple packets from different GICs are
incorrectly interleaved at the target chip. The erratum text below
specifies exactly what can cause multiple transfer packets susceptible
to interleaving and GIC state corruption. GIC state corruption can
lead to a range of problems, including kernel panics, and unexpected
behavior.
>From the erratum text:
"In some cases, inter-socket AXI4 Stream packets with multiple
transfers, may be interleaved by the fabric when presented to ARM
Generic Interrupt Controller. GIC expects all transfers of a packet
to be delivered without any interleaving.
The following GICv3 commands may result in multiple transfer packets
over inter-socket AXI4 Stream interface:
- Register reads from GICD_I* and GICD_N*
- Register writes to 64-bit GICD registers other than GICD_IROUTERn*
- ITS command MOVALL
Multiple commands in GICv4+ utilize multiple transfer packets,
including VMOVP, VMOVI, VMAPP, and 64-bit register accesses."
This issue impacts system configurations with more than 2 sockets,
that require multi-transfer packets to be sent over inter-socket
AXI4 Stream interface between GIC instances on different sockets.
GICv4 cannot be supported. GICv3 SW model can only be supported
with the workaround. Single and Dual socket configurations are not
impacted by this issue and support GICv3 and GICv4."
Link: https://developer.nvidia.com/docs/t241-fabric-4/nvidia-t241-fabric-4-errata.pdf
Writing to the chip alias region of the GICD_In{E} registers except
GICD_ICENABLERn has an equivalent effect as writing to the global
distributor. The SPI interrupt deactivate path is not impacted by
the erratum.
To fix this problem, implement a workaround that ensures read accesses
to the GICD_In{E} registers are directed to the chip that owns the
SPI, and disable GICv4.x features. To simplify code changes, the
gic_configure_irq() function uses the same alias region for both read
and write operations to GICD_ICFGR.
Co-developed-by: Vikram Sethi <vsethi@nvidia.com>
Signed-off-by: Vikram Sethi <vsethi@nvidia.com>
Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com>
Acked-by: Sudeep Holla <sudeep.holla@arm.com> (for SMCCC/SOC ID bits)
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20230319024314.3540573-2-sdonthineni@nvidia.com
2023-03-19 02:43:14 +00:00
|
|
|
soc_id_rev = arm_smccc_get_soc_id_revision();
|
|
|
|
if (soc_id_rev < 0) {
|
2023-07-17 17:17:02 +00:00
|
|
|
pr_err("Invalid SoC Revision: %x\n", soc_id_rev);
|
2020-06-25 09:59:39 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
|
|
|
if (!soc_dev_attr)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
sprintf(soc_id_rev_str, "0x%08x", soc_id_rev);
|
|
|
|
sprintf(soc_id_jep106_id_str, "jep106:%02x%02x",
|
|
|
|
JEP106_BANK_CONT_CODE(soc_id_version),
|
|
|
|
JEP106_ID_CODE(soc_id_version));
|
|
|
|
sprintf(soc_id_str, "%s:%04x", soc_id_jep106_id_str,
|
|
|
|
IMP_DEF_SOC_ID(soc_id_version));
|
|
|
|
|
|
|
|
soc_dev_attr->soc_id = soc_id_str;
|
|
|
|
soc_dev_attr->revision = soc_id_rev_str;
|
|
|
|
soc_dev_attr->family = soc_id_jep106_id_str;
|
|
|
|
|
|
|
|
soc_dev = soc_device_register(soc_dev_attr);
|
|
|
|
if (IS_ERR(soc_dev)) {
|
|
|
|
kfree(soc_dev_attr);
|
|
|
|
return PTR_ERR(soc_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("ID = %s Revision = %s\n", soc_dev_attr->soc_id,
|
|
|
|
soc_dev_attr->revision);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
module_init(smccc_soc_init);
|
|
|
|
|
|
|
|
static void __exit smccc_soc_exit(void)
|
|
|
|
{
|
|
|
|
if (soc_dev)
|
|
|
|
soc_device_unregister(soc_dev);
|
|
|
|
kfree(soc_dev_attr);
|
|
|
|
}
|
|
|
|
module_exit(smccc_soc_exit);
|