diff mbox series

[v2,12/12] irqchip/gic-v3: Add quirks for HIP06/07 invalid GICD_TYPER erratum 161010803

Message ID 20190806100121.240767-13-maz@kernel.org (mailing list archive)
State New, archived
Headers show
Series irqchip/gic-v3: Add support for GICv3.1 extended PPI/SPI ranges | expand

Commit Message

Marc Zyngier Aug. 6, 2019, 10:01 a.m. UTC
It looks like the HIP06/07 SoCs have extra bits in their GICD_TYPER
registers, which confuse the GICv3.1 code (these systems appear to
expose ESPIs while they actually don't).

Detect these systems as early as possible and wipe the fields that
should be RES0 in the register.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 Documentation/arm64/silicon-errata.rst |  2 +
 drivers/irqchip/irq-gic-v3.c           | 54 +++++++++++++++++++++-----
 2 files changed, 46 insertions(+), 10 deletions(-)

Comments

John Garry Aug. 6, 2019, 11:07 a.m. UTC | #1
On 06/08/2019 11:01, Marc Zyngier wrote:
> It looks like the HIP06/07 SoCs have extra bits in their GICD_TYPER
> registers, which confuse the GICv3.1 code (these systems appear to
> expose ESPIs while they actually don't).
>
> Detect these systems as early as possible and wipe the fields that
> should be RES0 in the register.
>

thanks,

Tested-by: John Garry <john.garry@huawei.com>

> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  Documentation/arm64/silicon-errata.rst |  2 +
>  drivers/irqchip/irq-gic-v3.c           | 54 +++++++++++++++++++++-----
>  2 files changed, 46 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst
> index 3e57d09246e6..17ea3fecddaa 100644
> --- a/Documentation/arm64/silicon-errata.rst
> +++ b/Documentation/arm64/silicon-errata.rst
> @@ -115,6 +115,8 @@ stable kernels.
>  +----------------+-----------------+-----------------+-----------------------------+
>  | Hisilicon      | Hip0{6,7}       | #161010701      | N/A                         |
>  +----------------+-----------------+-----------------+-----------------------------+
> +| Hisilicon      | Hip0{6,7}       | #161010803      | N/A                         |
> ++----------------+-----------------+-----------------+-----------------------------+
>  | Hisilicon      | Hip07           | #161600802      | HISILICON_ERRATUM_161600802 |
>  +----------------+-----------------+-----------------+-----------------------------+
>  | Hisilicon      | Hip08 SMMU PMCG | #162001800      | N/A                         |
> diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
> index 334a10d9dbfb..bee141613b67 100644
> --- a/drivers/irqchip/irq-gic-v3.c
> +++ b/drivers/irqchip/irq-gic-v3.c
> @@ -1441,6 +1441,46 @@ static bool gic_enable_quirk_msm8996(void *data)
>  	return true;
>  }
>
> +static bool gic_enable_quirk_hip06_07(void *data)
> +{
> +	struct gic_chip_data *d = data;
> +
> +	/*
> +	 * HIP06 GICD_IIDR clashes with GIC-600 product number (despite
> +	 * not being an actual ARM implementation). The saving grace is
> +	 * that GIC-600 doesn't have ESPI, so nothing to do in that case.
> +	 * HIP07 doesn't even have a proper IIDR, and still pretends to
> +	 * have ESPI. In both cases, put them right.
> +	 */
> +	if (d->rdists.gicd_typer & GICD_TYPER_ESPI) {
> +		/* Zero both ESPI and the RES0 field next to it... */
> +		d->rdists.gicd_typer &= ~GENMASK(9, 8);
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +static const struct gic_quirk gic_quirks[] = {
> +	{
> +		.desc	= "GICv3: Qualcomm MSM8996 broken firmware",
> +		.compatible = "qcom,msm8996-gic-v3",
> +		.init	= gic_enable_quirk_msm8996,
> +	},
> +	{
> +		.desc	= "GICv3: HIP06 erratum 161010803",
> +		.iidr	= 0x0204043b,
> +		.init	= gic_enable_quirk_hip06_07,
> +	},
> +	{
> +		.desc	= "GICv3: HIP07 erratum 161010803",
> +		.iidr	= 0x00000000,
> +		.init	= gic_enable_quirk_hip06_07,
> +	},
> +	{
> +	}
> +};
> +
>  static void gic_enable_nmi_support(void)
>  {
>  	int i;
> @@ -1494,6 +1534,10 @@ static int __init gic_init_bases(void __iomem *dist_base,
>  	 */
>  	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
>  	gic_data.rdists.gicd_typer = typer;
> +
> +	gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR),
> +			  gic_quirks, &gic_data);
> +
>  	pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);
>  	pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);
>  	gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
> @@ -1676,16 +1720,6 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
>  	gic_set_kvm_info(&gic_v3_kvm_info);
>  }
>
> -static const struct gic_quirk gic_quirks[] = {
> -	{
> -		.desc	= "GICv3: Qualcomm MSM8996 broken firmware",
> -		.compatible = "qcom,msm8996-gic-v3",
> -		.init	= gic_enable_quirk_msm8996,
> -	},
> -	{
> -	}
> -};
> -
>  static int __init gic_of_init(struct device_node *node, struct device_node *parent)
>  {
>  	void __iomem *dist_base;
>
diff mbox series

Patch

diff --git a/Documentation/arm64/silicon-errata.rst b/Documentation/arm64/silicon-errata.rst
index 3e57d09246e6..17ea3fecddaa 100644
--- a/Documentation/arm64/silicon-errata.rst
+++ b/Documentation/arm64/silicon-errata.rst
@@ -115,6 +115,8 @@  stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | Hisilicon      | Hip0{6,7}       | #161010701      | N/A                         |
 +----------------+-----------------+-----------------+-----------------------------+
+| Hisilicon      | Hip0{6,7}       | #161010803      | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 | Hisilicon      | Hip07           | #161600802      | HISILICON_ERRATUM_161600802 |
 +----------------+-----------------+-----------------+-----------------------------+
 | Hisilicon      | Hip08 SMMU PMCG | #162001800      | N/A                         |
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 334a10d9dbfb..bee141613b67 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1441,6 +1441,46 @@  static bool gic_enable_quirk_msm8996(void *data)
 	return true;
 }
 
+static bool gic_enable_quirk_hip06_07(void *data)
+{
+	struct gic_chip_data *d = data;
+
+	/*
+	 * HIP06 GICD_IIDR clashes with GIC-600 product number (despite
+	 * not being an actual ARM implementation). The saving grace is
+	 * that GIC-600 doesn't have ESPI, so nothing to do in that case.
+	 * HIP07 doesn't even have a proper IIDR, and still pretends to
+	 * have ESPI. In both cases, put them right.
+	 */
+	if (d->rdists.gicd_typer & GICD_TYPER_ESPI) {
+		/* Zero both ESPI and the RES0 field next to it... */
+		d->rdists.gicd_typer &= ~GENMASK(9, 8);
+		return true;
+	}
+
+	return false;
+}
+
+static const struct gic_quirk gic_quirks[] = {
+	{
+		.desc	= "GICv3: Qualcomm MSM8996 broken firmware",
+		.compatible = "qcom,msm8996-gic-v3",
+		.init	= gic_enable_quirk_msm8996,
+	},
+	{
+		.desc	= "GICv3: HIP06 erratum 161010803",
+		.iidr	= 0x0204043b,
+		.init	= gic_enable_quirk_hip06_07,
+	},
+	{
+		.desc	= "GICv3: HIP07 erratum 161010803",
+		.iidr	= 0x00000000,
+		.init	= gic_enable_quirk_hip06_07,
+	},
+	{
+	}
+};
+
 static void gic_enable_nmi_support(void)
 {
 	int i;
@@ -1494,6 +1534,10 @@  static int __init gic_init_bases(void __iomem *dist_base,
 	 */
 	typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
 	gic_data.rdists.gicd_typer = typer;
+
+	gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR),
+			  gic_quirks, &gic_data);
+
 	pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);
 	pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);
 	gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
@@ -1676,16 +1720,6 @@  static void __init gic_of_setup_kvm_info(struct device_node *node)
 	gic_set_kvm_info(&gic_v3_kvm_info);
 }
 
-static const struct gic_quirk gic_quirks[] = {
-	{
-		.desc	= "GICv3: Qualcomm MSM8996 broken firmware",
-		.compatible = "qcom,msm8996-gic-v3",
-		.init	= gic_enable_quirk_msm8996,
-	},
-	{
-	}
-};
-
 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
 {
 	void __iomem *dist_base;