summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJae Hyun Yoo <jae.hyun.yoo@intel.com>2019-03-14 01:36:34 +0300
committerJae Hyun Yoo <jae.hyun.yoo@linux.intel.com>2021-11-05 10:22:07 +0300
commit3c73debcb0788e56e318bcb582b45c05fa57380b (patch)
treed9eb06d2c85cbbf199bebb28e06ca458f5140bf8
parent6fb39e7bfaf427c315d157deb78406fa0f6736de (diff)
downloadlinux-3c73debcb0788e56e318bcb582b45c05fa57380b.tar.xz
char: ipmi: Add clock control logic into Aspeed LPC KCS driver
If LPC KCS driver is registered ahead of lpc-ctrl module, LPC KCS block will be enabled without heart beating of LCLK until lpc-ctrl enables the LCLK. This issue causes improper handling on host interrupts when the host sends interrupt in that time frame. Then kernel eventually forcibly disables the interrupt with dumping stack and printing a 'nobody cared this irq' message out. To prevent this issue, all LPC sub-nodes should enable LCLK individually so this patch adds clock control logic into the LPC KCS driver. Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
-rw-r--r--Documentation/devicetree/bindings/ipmi/aspeed,ast2400-kcs-bmc.yaml5
-rw-r--r--arch/arm/boot/dts/aspeed-g5.dtsi6
-rw-r--r--arch/arm/boot/dts/aspeed-g6.dtsi4
-rw-r--r--drivers/char/ipmi/kcs_bmc_aspeed.c31
4 files changed, 38 insertions, 8 deletions
diff --git a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-kcs-bmc.yaml b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-kcs-bmc.yaml
index 4ff6fabfcb30..6a6e4f6a772c 100644
--- a/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-kcs-bmc.yaml
+++ b/Documentation/devicetree/bindings/ipmi/aspeed,ast2400-kcs-bmc.yaml
@@ -40,6 +40,9 @@ properties:
- description: ODR register
- description: STR register
+ clocks:
+ minItems: 1
+
aspeed,lpc-io-reg:
$ref: '/schemas/types.yaml#/definitions/uint32-array'
minItems: 1
@@ -74,6 +77,7 @@ properties:
required:
- compatible
- interrupts
+ - clocks
additionalProperties: false
@@ -103,4 +107,5 @@ examples:
aspeed,lpc-io-reg = <0xca2>;
aspeed,lpc-interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupts = <8>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
};
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
index 8142d24edfb0..4c21045e8e02 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -128,7 +128,7 @@
};
vic: interrupt-controller@1e6c0080 {
- compatible = "aspeed,ast2400-vic";
+ compatible = "aspeed,ast2500-vic";
interrupt-controller;
#interrupt-cells = <1>;
valid-sources = <0xfefff7ff 0x0807ffff>;
@@ -453,6 +453,7 @@
compatible = "aspeed,ast2500-kcs-bmc-v2";
reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>;
interrupts = <8>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
status = "disabled";
};
@@ -460,6 +461,7 @@
compatible = "aspeed,ast2500-kcs-bmc-v2";
reg = <0x28 0x1>, <0x34 0x1>, <0x40 0x1>;
interrupts = <8>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
status = "disabled";
};
@@ -467,6 +469,7 @@
compatible = "aspeed,ast2500-kcs-bmc-v2";
reg = <0x2c 0x1>, <0x38 0x1>, <0x44 0x1>;
interrupts = <8>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
status = "disabled";
};
@@ -474,6 +477,7 @@
compatible = "aspeed,ast2500-kcs-bmc-v2";
reg = <0x114 0x1>, <0x118 0x1>, <0x11c 0x1>;
interrupts = <8>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
index 502205ceffdc..d2bf333aa834 100644
--- a/arch/arm/boot/dts/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed-g6.dtsi
@@ -540,6 +540,7 @@
compatible = "aspeed,ast2500-kcs-bmc-v2";
reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>;
interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
kcs_chan = <1>;
status = "disabled";
};
@@ -548,6 +549,7 @@
compatible = "aspeed,ast2500-kcs-bmc-v2";
reg = <0x28 0x1>, <0x34 0x1>, <0x40 0x1>;
interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
status = "disabled";
};
@@ -555,6 +557,7 @@
compatible = "aspeed,ast2500-kcs-bmc-v2";
reg = <0x2c 0x1>, <0x38 0x1>, <0x44 0x1>;
interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
status = "disabled";
};
@@ -562,6 +565,7 @@
compatible = "aspeed,ast2500-kcs-bmc-v2";
reg = <0x114 0x1>, <0x118 0x1>, <0x11c 0x1>;
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
status = "disabled";
};
diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
index b555286016b1..fc09e9c164ce 100644
--- a/drivers/char/ipmi/kcs_bmc_aspeed.c
+++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
@@ -1,11 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (c) 2015-2018, Intel Corporation.
- */
+// Copyright (c) 2015-2019, Intel Corporation.
#define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt
#include <linux/atomic.h>
+#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -115,6 +114,7 @@ struct aspeed_kcs_bmc {
struct kcs_bmc_device kcs_bmc;
struct regmap *map;
+ struct clk *clk;
struct {
enum aspeed_kcs_irq_mode mode;
@@ -620,24 +620,34 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
return -ENODEV;
}
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk),
+ "couldn't get clock\n");
+ rc = clk_prepare_enable(priv->clk);
+ if (rc) {
+ dev_err(&pdev->dev, "couldn't enable clock\n");
+ return rc;
+ }
+
spin_lock_init(&priv->obe.lock);
priv->obe.remove = false;
timer_setup(&priv->obe.timer, aspeed_kcs_check_obe, 0);
rc = aspeed_kcs_set_address(kcs_bmc, addrs, nr_addrs);
if (rc)
- return rc;
+ goto err;
/* Host to BMC IRQ */
rc = aspeed_kcs_config_downstream_irq(kcs_bmc, pdev);
if (rc)
- return rc;
+ goto err;
/* BMC to Host IRQ */
if (have_upstream_irq) {
rc = aspeed_kcs_config_upstream_irq(priv, upstream_irq[0], upstream_irq[1]);
if (rc < 0)
- return rc;
+ goto err;
} else {
priv->upstream_irq.mode = aspeed_kcs_irq_none;
}
@@ -650,13 +660,19 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
rc = kcs_bmc_add_device(&priv->kcs_bmc);
if (rc) {
dev_warn(&pdev->dev, "Failed to register channel %d: %d\n", kcs_bmc->channel, rc);
- return rc;
+ goto err;
}
dev_info(&pdev->dev, "Initialised channel %d at 0x%x\n",
kcs_bmc->channel, addrs[0]);
return 0;
+
+err:
+ aspeed_kcs_enable_channel(kcs_bmc, false);
+ clk_disable_unprepare(priv->clk);
+
+ return rc;
}
static int aspeed_kcs_remove(struct platform_device *pdev)
@@ -664,6 +680,7 @@ static int aspeed_kcs_remove(struct platform_device *pdev)
struct aspeed_kcs_bmc *priv = platform_get_drvdata(pdev);
struct kcs_bmc_device *kcs_bmc = &priv->kcs_bmc;
+ clk_disable_unprepare(priv->clk);
kcs_bmc_remove_device(kcs_bmc);
aspeed_kcs_enable_channel(kcs_bmc, false);