From cd62ca008a771bd6b7aeb06526c37d8435f86648 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Wed, 13 Mar 2019 15:36:34 -0700 Subject: [PATCH] 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 Signed-off-by: Vernon Mauery --- .../devicetree/bindings/ipmi/aspeed-kcs-bmc.txt | 3 ++ arch/arm/boot/dts/aspeed-g4.dtsi | 35 ++++++++++++++++++++ arch/arm/boot/dts/aspeed-g5.dtsi | 6 +++- arch/arm/boot/dts/aspeed-g6.dtsi | 6 ++++ drivers/char/ipmi/kcs_bmc_aspeed.c | 37 ++++++++++++++++++---- 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt index d98a9bf45d6c..3453eb0bf8f2 100644 --- a/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt +++ b/Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt @@ -9,6 +9,8 @@ Required properties: "aspeed,ast2400-kcs-bmc" "aspeed,ast2500-kcs-bmc" - interrupts : interrupt generated by the controller +- clocks: contains a phandle to the syscon node describing the clocks. + There should then be one cell representing the clock to use. - kcs_chan : The LPC channel number in the controller - kcs_addr : The host CPU IO map address @@ -19,6 +21,7 @@ Example: compatible = "aspeed,ast2500-kcs-bmc"; reg = <0x0 0x80>; interrupts = <8>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; kcs_chan = <3>; kcs_addr = <0xCA2>; status = "okay"; diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi index 24a20384b5e8..fc6f4e009db7 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi @@ -347,6 +347,33 @@ lpc_bmc: lpc-bmc@0 { compatible = "aspeed,ast2400-lpc-bmc"; reg = <0x0 0x80>; + reg-io-width = <4>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x80>; + + kcs1: kcs1@0 { + compatible = "aspeed,ast2400-kcs-bmc"; + interrupts = <8>; + kcs_chan = <1>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + kcs2: kcs2@0 { + compatible = "aspeed,ast2400-kcs-bmc"; + interrupts = <8>; + kcs_chan = <2>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + kcs3: kcs3@0 { + compatible = "aspeed,ast2400-kcs-bmc"; + interrupts = <8>; + kcs_chan = <3>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; }; lpc_host: lpc-host@80 { @@ -358,6 +385,14 @@ #size-cells = <1>; ranges = <0x0 0x80 0x1e0>; + kcs4: kcs4@0 { + compatible = "aspeed,ast2400-kcs-bmc"; + interrupts = <8>; + kcs_chan = <4>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + status = "disabled"; + }; + lpc_ctrl: lpc-ctrl@0 { compatible = "aspeed,ast2400-lpc-ctrl"; reg = <0x0 0x80>; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index 18d2a465c0ed..751a8f0316d6 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -134,7 +134,7 @@ }; vic: interrupt-controller@1e6c0080 { - compatible = "aspeed,ast2400-vic"; + compatible = "aspeed,ast2500-vic"; interrupt-controller; #interrupt-cells = <1>; valid-sources = <0xfefff7ff 0x0807ffff>; @@ -439,18 +439,21 @@ compatible = "aspeed,ast2500-kcs-bmc"; interrupts = <8>; kcs_chan = <1>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; status = "disabled"; }; kcs2: kcs2@0 { compatible = "aspeed,ast2500-kcs-bmc"; interrupts = <8>; kcs_chan = <2>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; status = "disabled"; }; kcs3: kcs3@0 { compatible = "aspeed,ast2500-kcs-bmc"; interrupts = <8>; kcs_chan = <3>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; status = "disabled"; }; }; @@ -468,6 +471,7 @@ compatible = "aspeed,ast2500-kcs-bmc"; interrupts = <8>; kcs_chan = <4>; + 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 4035d7bd647e..0e35c4598df5 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -463,18 +463,23 @@ kcs1: kcs1@0 { compatible = "aspeed,ast2600-kcs-bmc"; interrupts = ; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; kcs_chan = <1>; status = "disabled"; }; + kcs2: kcs2@0 { compatible = "aspeed,ast2600-kcs-bmc"; interrupts = ; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; kcs_chan = <2>; status = "disabled"; }; + kcs3: kcs3@0 { compatible = "aspeed,ast2600-kcs-bmc"; interrupts = ; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; kcs_chan = <3>; status = "disabled"; }; @@ -492,6 +497,7 @@ kcs4: kcs4@0 { compatible = "aspeed,ast2600-kcs-bmc"; interrupts = ; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; kcs_chan = <4>; status = "disabled"; }; diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c index a0a8bb89c9b3..94cfb879f520 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 +#include #include #include #include @@ -63,6 +62,7 @@ struct aspeed_kcs_bmc { struct regmap *map; + struct clk *clk; }; @@ -264,36 +264,59 @@ static int aspeed_kcs_probe(struct platform_device *pdev) return -ENODEV; } + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + rc = PTR_ERR(priv->clk); + if (rc != -EPROBE_DEFER) + dev_err(dev, "couldn't get clock\n"); + return rc; + } + rc = clk_prepare_enable(priv->clk); + if (rc) { + dev_err(dev, "couldn't enable clock\n"); + return rc; + } + kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1]; kcs_bmc->io_inputb = aspeed_kcs_inb; kcs_bmc->io_outputb = aspeed_kcs_outb; dev_set_drvdata(dev, kcs_bmc); - aspeed_kcs_set_address(kcs_bmc, addr); - aspeed_kcs_enable_channel(kcs_bmc, true); rc = aspeed_kcs_config_irq(kcs_bmc, pdev); if (rc) - return rc; + goto err; rc = misc_register(&kcs_bmc->miscdev); if (rc) { dev_err(dev, "Unable to register device\n"); - return rc; + goto err; } + aspeed_kcs_set_address(kcs_bmc, addr); + aspeed_kcs_enable_channel(kcs_bmc, true); + pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n", chan, addr, kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str); 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) { struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev); + struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc); misc_deregister(&kcs_bmc->miscdev); + aspeed_kcs_enable_channel(kcs_bmc, false); + clk_disable_unprepare(priv->clk); return 0; } -- 2.7.4