* Re: [PATCH 3/4] clk/soc: mediatek: mt6779: Bind clock driver from platform device
From: Chun-Kuang Hu @ 2020-05-19 15:10 UTC (permalink / raw)
To: matthias.bgg
Cc: Kate Stewart, devicetree, Stephen Boyd, Greg Kroah-Hartman,
Michael Turquette, linux-kernel, Rob Herring,
moderated list:ARM/Mediatek SoC support, Allison Randal,
Matthias Brugger, mtk01761, Thomas Gleixner, linux-clk, Linux ARM
In-Reply-To: <20200518113156.25009-3-matthias.bgg@kernel.org>
Hi, Matthias:
<matthias.bgg@kernel.org> 於 2020年5月18日 週一 下午7:33寫道:
>
> From: Matthias Brugger <matthias.bgg@gmail.com>
>
> The mmsys driver is now the top level entry point for the multimedia
> system (mmsys), we bind the clock driver by creating a platform device.
> We also bind the MediaTek DRM driver which is not yet implement and
> therefor will errror out for now.
>
> Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
> ---
>
> drivers/clk/mediatek/clk-mt6779-mm.c | 9 ++-------
> drivers/soc/mediatek/mtk-mmsys.c | 8 ++++++++
> 2 files changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/clk/mediatek/clk-mt6779-mm.c b/drivers/clk/mediatek/clk-mt6779-mm.c
> index fb5fbb8e3e41..059c1a41ac7a 100644
> --- a/drivers/clk/mediatek/clk-mt6779-mm.c
> +++ b/drivers/clk/mediatek/clk-mt6779-mm.c
> @@ -84,15 +84,11 @@ static const struct mtk_gate mm_clks[] = {
> GATE_MM1(CLK_MM_DISP_OVL_FBDC, "mm_disp_ovl_fbdc", "mm_sel", 16),
> };
>
> -static const struct of_device_id of_match_clk_mt6779_mm[] = {
> - { .compatible = "mediatek,mt6779-mmsys", },
> - {}
> -};
> -
> static int clk_mt6779_mm_probe(struct platform_device *pdev)
> {
> + struct device *dev = &pdev->dev;
> + struct device_node *node = dev->parent->of_node;
> struct clk_onecell_data *clk_data;
> - struct device_node *node = pdev->dev.of_node;
>
> clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK);
>
> @@ -106,7 +102,6 @@ static struct platform_driver clk_mt6779_mm_drv = {
> .probe = clk_mt6779_mm_probe,
> .driver = {
> .name = "clk-mt6779-mm",
> - .of_match_table = of_match_clk_mt6779_mm,
> },
> };
>
> diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
> index fee64c8d3020..dc15808cf3a3 100644
> --- a/drivers/soc/mediatek/mtk-mmsys.c
> +++ b/drivers/soc/mediatek/mtk-mmsys.c
> @@ -88,6 +88,10 @@ static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = {
> .clk_driver = "clk-mt2712-mm",
> };
>
> +static const struct mtk_mmsys_driver_data mt6779_mmsys_driver_data = {
> + .clk_driver = "clk-mt6779-mm",
This patch looks good to me, but I've one question: why drm driver
just use single "mediatek-drm" for sub driver name, but clock driver
has different name for each SoC?
Could we just use single name for clock driver such as "mediatek-clk-mm"?
Regards,
Chun-Kuang.
> +};
> +
> static const struct mtk_mmsys_driver_data mt6797_mmsys_driver_data = {
> .clk_driver = "clk-mt6797-mm",
> };
> @@ -343,6 +347,10 @@ static const struct of_device_id of_match_mtk_mmsys[] = {
> .compatible = "mediatek,mt2712-mmsys",
> .data = &mt2712_mmsys_driver_data,
> },
> + {
> + .compatible = "mediatek,mt6779-mmsys",
> + .data = &mt6779_mmsys_driver_data,
> + },
> {
> .compatible = "mediatek,mt6797-mmsys",
> .data = &mt6797_mmsys_driver_data,
> --
> 2.26.2
>
>
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] iomm/arm-smmu: Add stall implementation hook
From: Rob Clark @ 2020-05-19 15:11 UTC (permalink / raw)
To: Sai Prakash Ranjan
Cc: Will Deacon, Joerg Roedel, Linux Kernel Mailing List,
list@263.net:IOMMU DRIVERS , Joerg Roedel <joro@8bytes.org>, ,
linux-arm-msm, Robin Murphy,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <5a0ad639e272026c8be57393937cda22@codeaurora.org>
On Tue, May 19, 2020 at 2:26 AM Sai Prakash Ranjan
<saiprakash.ranjan@codeaurora.org> wrote:
>
> Hi Will,
>
> On 2020-05-18 21:15, Will Deacon wrote:
> > On Mon, May 11, 2020 at 11:30:08AM -0600, Jordan Crouse wrote:
> >> On Fri, May 08, 2020 at 08:40:40AM -0700, Rob Clark wrote:
> >> > On Fri, May 8, 2020 at 8:32 AM Rob Clark <robdclark@gmail.com> wrote:
> >> > >
> >> > > On Thu, May 7, 2020 at 5:54 AM Will Deacon <will@kernel.org> wrote:
> >> > > >
> >> > > > On Thu, May 07, 2020 at 11:55:54AM +0100, Robin Murphy wrote:
> >> > > > > On 2020-05-07 11:14 am, Sai Prakash Ranjan wrote:
> >> > > > > > On 2020-04-22 01:50, Sai Prakash Ranjan wrote:
> >> > > > > > > Add stall implementation hook to enable stalling
> >> > > > > > > faults on QCOM platforms which supports it without
> >> > > > > > > causing any kind of hardware mishaps. Without this
> >> > > > > > > on QCOM platforms, GPU faults can cause unrelated
> >> > > > > > > GPU memory accesses to return zeroes. This has the
> >> > > > > > > unfortunate result of command-stream reads from CP
> >> > > > > > > getting invalid data, causing a cascade of fail.
> >> > > > >
> >> > > > > I think this came up before, but something about this rationale doesn't add
> >> > > > > up - we're not *using* stalls at all, we're still terminating faulting
> >> > > > > transactions unconditionally; we're just using CFCFG to terminate them with
> >> > > > > a slight delay, rather than immediately. It's really not clear how or why
> >> > > > > that makes a difference. Is it a GPU bug? Or an SMMU bug? Is this reliable
> >> > > > > (or even a documented workaround for something), or might things start
> >> > > > > blowing up again if any other behaviour subtly changes? I'm not dead set
> >> > > > > against adding this, but I'd *really* like to have a lot more confidence in
> >> > > > > it.
> >> > > >
> >> > > > Rob mentioned something about the "bus returning zeroes" before, but I agree
> >> > > > that we need more information so that we can reason about this and maintain
> >> > > > the code as the driver continues to change. That needs to be a comment in
> >> > > > the driver, and I don't think "but android seems to work" is a good enough
> >> > > > justification. There was some interaction with HUPCF as well.
> >> > >
> >> > > The issue is that there are multiple parallel memory accesses
> >> > > happening at the same time, for example CP (the cmdstream processor)
> >> > > will be reading ahead and setting things up for the next draw or
> >> > > compute grid, in parallel with some memory accesses from the shader
> >> > > which could trigger a fault. (And with faults triggered by something
> >> > > in the shader, there are *many* shader threads running in parallel so
> >> > > those tend to generate a big number of faults at the same time.)
> >> > >
> >> > > We need either CFCFG or HUPCF, otherwise what I have observed is that
> >> > > while the fault happens, CP's memory access will start returning
> >> > > zero's instead of valid cmdstream data, which triggers a GPU hang. I
> >> > > can't say whether this is something unique to qcom's implementation of
> >> > > the smmu spec or not.
> >> > >
> >> > > *Often* a fault is the result of the usermode gl/vk/cl driver bug,
> >> > > although I don't think that is an argument against fixing this in the
> >> > > smmu driver.. I've been carrying around a local patch to set HUPCF for
> >> > > *years* because debugging usermode driver issues is so much harder
> >> > > without. But there are some APIs where faults can be caused by the
> >> > > user's app on top of the usermode driver.
> >> > >
> >> >
> >> > Also, I'll add to that, a big wish of mine is to have stall with the
> >> > ability to resume later from a wq context. That would enable me to
> >> > hook in the gpu crash dump handling for faults, which would make
> >> > debugging these sorts of issues much easier. I think I posted a
> >> > prototype of this quite some time back, which would schedule a worker
> >> > on the first fault (since there are cases where you see 1000's of
> >> > faults at once), which grabbed some information about the currently
> >> > executing submit and some gpu registers to indicate *where* in the
> >> > submit (a single submit could have 100's or 1000's of draws), and then
> >> > resumed the iommu cb.
> >> >
> >> > (This would ofc eventually be useful for svm type things.. I expect
> >> > we'll eventually care about that too.)
> >>
> >> Rob is right about HUPCF. Due to the parallel nature of the command
> >> processor
> >> there is always a very good chance that a CP access is somewhere in
> >> the bus so
> >> any pagefault is usually a death sentence. The GPU context bank would
> >> always
> >> want HUPCF set to 1.
> >
> > So this sounds like an erratum to me, and I'm happy to set HUPCF if we
> > detect the broken implementation. However, it will need an entry in
> > Documentation/arm64/silicon-errata.rst and a decent comment in the
> > driver
> > to explain what we're doing and why.
> >
>
> AFAIK there is no erratum documented internally for this behaviour and
> this
> exists from MSM8996 SoC time and errata usually don't survive this long
> across generation of SoCs and there is no point for us in disguising it.
possibly longer, qcom_iommu sets CFCFG..
> Is it OK if we clearly mention it as the "design limitation" or some
> other
> term which we can agree upon along with the description which Rob and
> Jordan
> provided for setting HUPCF in the driver when we add the set_hupcf
> callback?
I'm not too picky on what we call it, but afaict it has been this way
since the beginning of time, rather than specific to a certain SoC or
generation of SoCs. So it doesn't seem like the hw designers consider
it a bug.
(I'm not sure what the expected behavior is.. nor if any other SMMU
implementation encounters this sort of situation..)
BR,
-R
>
> Thanks,
> Sai
>
> --
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a
> member
> of Code Aurora Forum, hosted by The Linux Foundation
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] drm/mediatek: mtk_mt8173_hdmi_phy: Remove unnused const variables
From: Chun-Kuang Hu @ 2020-05-19 15:12 UTC (permalink / raw)
To: Enric Balletbo i Serra
Cc: Chun-Kuang Hu, Nicolas Boichat, Philipp Zabel, David Airlie,
linux-kernel, DRI Development,
moderated list:ARM/Mediatek SoC support, Daniel Vetter,
Hsin-Yi Wang, Matthias Brugger, Collabora Kernel ML, Linux ARM
In-Reply-To: <20200519094045.2447940-1-enric.balletbo@collabora.com>
Hi, Enric:
Enric Balletbo i Serra <enric.balletbo@collabora.com> 於 2020年5月19日 週二 下午5:40寫道:
>
> There are some `static const u8` variables that are not used, this
> triggers a warning building with `make W=1`, it is safe to remove them,
> so do it and make the compiler more happy.
>
Reviewed-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
>
> .../gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 48 -------------------
> 1 file changed, 48 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> index 1c3575372230..827b93786fac 100644
> --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> +++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> @@ -107,54 +107,6 @@
> #define RGS_HDMITX_5T1_EDG (0xf << 4)
> #define RGS_HDMITX_PLUG_TST BIT(0)
>
> -static const u8 PREDIV[3][4] = {
> - {0x0, 0x0, 0x0, 0x0}, /* 27Mhz */
> - {0x1, 0x1, 0x1, 0x1}, /* 74Mhz */
> - {0x1, 0x1, 0x1, 0x1} /* 148Mhz */
> -};
> -
> -static const u8 TXDIV[3][4] = {
> - {0x3, 0x3, 0x3, 0x2}, /* 27Mhz */
> - {0x2, 0x1, 0x1, 0x1}, /* 74Mhz */
> - {0x1, 0x0, 0x0, 0x0} /* 148Mhz */
> -};
> -
> -static const u8 FBKSEL[3][4] = {
> - {0x1, 0x1, 0x1, 0x1}, /* 27Mhz */
> - {0x1, 0x0, 0x1, 0x1}, /* 74Mhz */
> - {0x1, 0x0, 0x1, 0x1} /* 148Mhz */
> -};
> -
> -static const u8 FBKDIV[3][4] = {
> - {19, 24, 29, 19}, /* 27Mhz */
> - {19, 24, 14, 19}, /* 74Mhz */
> - {19, 24, 14, 19} /* 148Mhz */
> -};
> -
> -static const u8 DIVEN[3][4] = {
> - {0x2, 0x1, 0x1, 0x2}, /* 27Mhz */
> - {0x2, 0x2, 0x2, 0x2}, /* 74Mhz */
> - {0x2, 0x2, 0x2, 0x2} /* 148Mhz */
> -};
> -
> -static const u8 HTPLLBP[3][4] = {
> - {0xc, 0xc, 0x8, 0xc}, /* 27Mhz */
> - {0xc, 0xf, 0xf, 0xc}, /* 74Mhz */
> - {0xc, 0xf, 0xf, 0xc} /* 148Mhz */
> -};
> -
> -static const u8 HTPLLBC[3][4] = {
> - {0x2, 0x3, 0x3, 0x2}, /* 27Mhz */
> - {0x2, 0x3, 0x3, 0x2}, /* 74Mhz */
> - {0x2, 0x3, 0x3, 0x2} /* 148Mhz */
> -};
> -
> -static const u8 HTPLLBR[3][4] = {
> - {0x1, 0x1, 0x0, 0x1}, /* 27Mhz */
> - {0x1, 0x2, 0x2, 0x1}, /* 74Mhz */
> - {0x1, 0x2, 0x2, 0x1} /* 148Mhz */
> -};
> -
> static int mtk_hdmi_pll_prepare(struct clk_hw *hw)
> {
> struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
> --
> 2.26.2
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] drm/mediatek: mtk_hdmi: Remove debug messages for function calls
From: Chun-Kuang Hu @ 2020-05-19 15:13 UTC (permalink / raw)
To: Enric Balletbo i Serra
Cc: Chun-Kuang Hu, Nicolas Boichat, Philipp Zabel, David Airlie,
linux-kernel, DRI Development,
moderated list:ARM/Mediatek SoC support, Daniel Vetter,
Hsin-Yi Wang, Matthias Brugger, Collabora Kernel ML, Linux ARM
In-Reply-To: <20200519094115.2448092-1-enric.balletbo@collabora.com>
Hi, Enric:
Enric Balletbo i Serra <enric.balletbo@collabora.com> 於 2020年5月19日 週二 下午5:41寫道:
>
> Equivalent information can be nowadays obtained using function tracer
>
Reviewed-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
>
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 12 +-----------
> drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 4 ----
> 2 files changed, 1 insertion(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index b0555a7cb3b4..172d67294435 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -1634,8 +1634,6 @@ static int mtk_hdmi_audio_startup(struct device *dev, void *data)
> {
> struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> mtk_hdmi_audio_enable(hdmi);
>
> return 0;
> @@ -1645,8 +1643,6 @@ static void mtk_hdmi_audio_shutdown(struct device *dev, void *data)
> {
> struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> mtk_hdmi_audio_disable(hdmi);
> }
>
> @@ -1655,8 +1651,6 @@ mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable)
> {
> struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
>
> - dev_dbg(dev, "%s(%d)\n", __func__, enable);
> -
> if (enable)
> mtk_hdmi_hw_aud_mute(hdmi);
> else
> @@ -1669,8 +1663,6 @@ static int mtk_hdmi_audio_get_eld(struct device *dev, void *data, uint8_t *buf,
> {
> struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
>
> - dev_dbg(dev, "%s\n", __func__);
> -
> memcpy(buf, hdmi->conn.eld, min(sizeof(hdmi->conn.eld), len));
>
> return 0;
> @@ -1770,7 +1762,6 @@ static int mtk_drm_hdmi_probe(struct platform_device *pdev)
> goto err_bridge_remove;
> }
>
> - dev_dbg(dev, "mediatek hdmi probe success\n");
> return 0;
>
> err_bridge_remove:
> @@ -1793,7 +1784,7 @@ static int mtk_hdmi_suspend(struct device *dev)
> struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
>
> mtk_hdmi_clk_disable_audio(hdmi);
> - dev_dbg(dev, "hdmi suspend success!\n");
> +
> return 0;
> }
>
> @@ -1808,7 +1799,6 @@ static int mtk_hdmi_resume(struct device *dev)
> return ret;
> }
>
> - dev_dbg(dev, "hdmi resume success!\n");
> return 0;
> }
> #endif
> diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> index b55f51675205..1c3575372230 100644
> --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> +++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c
> @@ -159,8 +159,6 @@ static int mtk_hdmi_pll_prepare(struct clk_hw *hw)
> {
> struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
>
> - dev_dbg(hdmi_phy->dev, "%s\n", __func__);
> -
> mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_AUTOK_EN);
> mtk_hdmi_phy_set_bits(hdmi_phy, HDMI_CON0, RG_HDMITX_PLL_POSDIV);
> mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON3, RG_HDMITX_MHLCK_EN);
> @@ -178,8 +176,6 @@ static void mtk_hdmi_pll_unprepare(struct clk_hw *hw)
> {
> struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
>
> - dev_dbg(hdmi_phy->dev, "%s\n", __func__);
> -
> mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_TXDIV_EN);
> mtk_hdmi_phy_clear_bits(hdmi_phy, HDMI_CON1, RG_HDMITX_PLL_BIAS_LPF_EN);
> usleep_range(100, 150);
> --
> 2.26.2
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 3/3] arm64: vdso: Fix CFI directives in sigreturn trampoline
From: Will Deacon @ 2020-05-19 15:24 UTC (permalink / raw)
To: Dave Martin
Cc: Tamas Zsoldos, Mark Brown, kernel-team@android.com,
linux-arm-kernel@lists.infradead.org, Daniel Kiss
In-Reply-To: <20200519135537.GG5031@arm.com>
On Tue, May 19, 2020 at 02:55:37PM +0100, Dave Martin wrote:
> On Tue, May 19, 2020 at 02:39:41PM +0100, Will Deacon wrote:
> > The gas docs say:
> >
> > "Mark current function as signal trampoline."
> >
> > which is really informative.
>
> Well, we've demonstrated that identifying the signal frame is a gross
> bodge. The cfi annotation should provide a reliable way to identify the
> signal frame, but I guess it was too poorly specified or came too late
> to prevent the bodges from spreading.
>
> Since this seems to be a nonstandard invention, I wouldn't hold out
> much hope of finding a usable spec.
>
> Of course, something might be using it now, so I guess we have to leave
> it.
I had a quick look at libstdc++ (the horror!) and it looks like the DWARF
backend in there /does/ make use of this information as part of the
_Unwind_GetIPInfo() function:
https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib--unwind-getipinfo.html
*ip_before_insn is set to 1 or 0 depending on whether or not the PC
corresponds to a function annotated with .cfi_signal_frame. So I think
the code in libstdc++-v3/libsupc++/eh_personality.cc doesn't need the
mysterious NOP at all!
Unfortunately, it looks like the LLVM libc++ doesn't use this, and instead
calls _Unwind_GetIP():
https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib--unwind-getip.html
and unconditionally subtracts 1 in libcxxabi/src/cxa_personality.cpp,
meaning that the NOP is necessary.
So, after giving myself a splitting headache, it looks like:
1. We need the mysterious NOP for LLVM
2. We could drop .cfi_signal_frame but it's harmless to keep it
3. We need the .cfi_def_cfa directive to locate the frame record, as
.cfi_signal_frame doesn't do very much at all.
Make sense? If so, I'll spin a v2 of the patches along with a comment
trying to summarise some of this.
Cheers,
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/3] arm64: vdso: Don't prefix sigreturn trampoline with a BTI C instruction
From: Will Deacon @ 2020-05-19 15:26 UTC (permalink / raw)
To: Mark Brown
Cc: Tamas Zsoldos, kernel-team, Dave Martin, linux-arm-kernel,
Daniel Kiss
In-Reply-To: <20200519123843.GJ4611@sirena.org.uk>
On Tue, May 19, 2020 at 01:38:43PM +0100, Mark Brown wrote:
> On Tue, May 19, 2020 at 01:18:16PM +0100, Will Deacon wrote:
>
> > Fixes: 714a8d02ca4d ("arm64: asm: Override SYM_FUNC_START when building the kernel with BTI")
>
> I'd say it's the annotation conversion not this, and also that the
> bikeshed would be most fetching in orange.
>
> c91db232da484851 (arm64: vdso: Convert to modern assembler annotations)
I initially had both, but that felt weird so I dropped this one. However,
I'm happy to switch it for v2.
> > -SYM_FUNC_START(__kernel_rt_sigreturn)
> > +/*
> > + * GDB relies on being able to identify the sigreturn instruction sequence to
> > + * unwind from signal handlers. We cannot, therefore, use SYM_FUNC_START()
> > + * here, as it will emit a BTI C instruction and break the unwinder. Thankfully,
> > + * this function is only ever called from a RET and so omitting the landing pad
> > + * is perfectly fine.
> > + */
> > +SYM_START(__kernel_rt_sigreturn, SYM_L_GLOBAL, SYM_A_ALIGN)
>
> Shouldn't this be a SYM_CODE_START()? It's the same thing as above
> currently and we'll break an awful lot more if we change what it does in
> a way that affects the code, plus the use of CODE basically says the
> above - it's a "this is non-standard and we know exactly what we're
> doing, don't mess with it" annotation. If not then it'd be good to
> cover that in the comment since otherwise this seems like it's asking
> for a cleanup, we shouldn't really have raw SYM_START() in code.
>
> I guess we also ought to annotate the 32 bit sigreturns as CODE too,
> though it's academic there without BTI.
Yes, that's much better, I'll use SYM_CODE_START() and update the compat
code too (I'd forgotten it wasn't an array of hex anymore).
Thanks,
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 2/2] ARM: Allow either FLATMEM or SPARSEMEM on the multiplatform build
From: Mike Rapoport @ 2020-05-19 15:27 UTC (permalink / raw)
To: Russell King - ARM Linux admin
Cc: Doug Berger, Arnd Bergmann, Stephen Boyd, Kevin Cernekee,
Florian Fainelli, Gregory Fong, Linux ARM
In-Reply-To: <20200519150452.GH1551@shell.armlinux.org.uk>
On Tue, May 19, 2020 at 04:04:52PM +0100, Russell King - ARM Linux admin wrote:
> On Tue, May 19, 2020 at 05:43:06PM +0300, Mike Rapoport wrote:
> > On Tue, May 19, 2020 at 09:59:48AM +0200, Arnd Bergmann wrote:
> > > On Mon, May 18, 2020 at 9:45 PM Mike Rapoport <rppt@linux.ibm.com> wrote:
> > > > On Mon, May 18, 2020 at 08:58:36AM -0700, Florian Fainelli wrote:
> > > > >
> > > > > Mike, do you want to make a formal submission to Russell's patch
> > > > > tracker? If so, feel free to add:
> > > >
> > > > I actually hoped to hear from people what do they think about switching
> > > > over to SPARSEMEM for the multiplatform builds. I think at least v7 CPUs
> > > > it would make sense.
> > >
> > > It seems that at least s5p/exynos and clps711x (armv4) used to default to
> > > sparsemem, and that got lost in the multiplatform conversion.
> > >
> > > I also see discontiguous memory ranges in multiple broadcom chips,
> > > on TI dm8168, ecx-2000 and imx.
> > >
> > > > Russel, Arnd, can you comment please?
> > >
> > > I see no problem with giving users the choice for all multiplatform
> > > builds. No idea on what the default should be really, i.e. whether
> > > only v7 configurations should make it the default, or rather none of
> > > them or all of them.
> >
> > Me neither :)
> >
> > I'd say let's move forward with letting user select the memory model for
> > all multiplaform builds and keep flatmem the default.
> >
> > Enabling sparsemem (with SPARSEMEM_STATIC) for defconfig build increases
> > the kernel nearly by 8k and most probably will make things slower.
>
> I think when selecting the default, you need to consider whether
> platforms can boot with that default configuration or not.
>
> There are cases where the reason to use sparsemem is not an optional
> one but is out of necessity - they require the page array to be split
> up in order to boot successfully.
>
> With that in mind, flatmem becomes an "optimisation" over sparsemem.
At the moment, there are three platforms that enable SPARSEMEM: ARCH_EP93XX,
ARCH_RPC and ARCH_SA1100. All the rest have FLATMEM implcitly selected.
I do not intend to change that, I am only going add an ability to select
the memory model for ARCH_MULTIPLATFORM.
I'll respin the series on the list before adding the patches to the
patch system.
> --
> RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
> FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up
--
Sincerely yours,
Mike.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 3/3] arm64: vdso: Fix CFI directives in sigreturn trampoline
From: Daniel Kiss @ 2020-05-19 15:30 UTC (permalink / raw)
To: Dave P Martin, Will Deacon
Cc: Tamas Zsoldos, Mark Brown, kernel-team@android.com,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20200519135537.GG5031@arm.com>
> On 19 May 2020, at 15:55, Dave Martin <Dave.Martin@arm.com> wrote:
>
> On Tue, May 19, 2020 at 02:39:41PM +0100, Will Deacon wrote:
>> On Tue, May 19, 2020 at 02:09:31PM +0100, Dave P Martin wrote:
>>> On Tue, May 19, 2020 at 01:18:18PM +0100, Will Deacon wrote:
>>>> Daniel reports that the .cfi_startproc is misplaced for the sigreturn
>>>> trampoline, which causes LLVM's unwinder to misbehave:
>>>>
>>>> | I run into this with LLVM’s unwinder.
>>>> | This combination was always broken.
>>>>
>>>> This prompted Dave to realise that our CFI directives are contradictory,
>>>> as we specify both .cfi_signal_frame *and* .cfi_def_cfa, with the latter
>>>> unconditionally identifying the interrupted context as opposed to the
>>>> values in the sigcontext.
>>>>
>>>> Rework the CFI directives so that we only use .cfi_signal_frame, and
>>>> include the "mysterious NOP" as part of the .cfi_{start,end}proc block.
>>>>
>>>> Cc: Tamas Zsoldos <tamas.zsoldos@arm.com>
>>>> Reported-by: Dave Martin <dave.martin@arm.com>
>>>> Reported-by: Daniel Kiss <daniel.kiss@arm.com>
>>>> Signed-off-by: Will Deacon <will@kernel.org>
>>>> ---
>>>> arch/arm64/kernel/vdso/sigreturn.S | 8 +++-----
>>>> 1 file changed, 3 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/kernel/vdso/sigreturn.S b/arch/arm64/kernel/vdso/sigreturn.S
>>>> index 7853fa9692f6..28b33f7d0604 100644
>>>> --- a/arch/arm64/kernel/vdso/sigreturn.S
>>>> +++ b/arch/arm64/kernel/vdso/sigreturn.S
>>>> @@ -14,6 +14,9 @@
>>>>
>>>> .text
>>>>
>>>> +/* Ensure that the mysterious NOP can be associated with a function. */
>>>> + .cfi_startproc
>>>> + .cfi_signal_frame
>>>> /*
>>>> * This mysterious NOP is required for some unwinders that subtract one from
>>>> * the return address in order to identify the calling function.
>>>> @@ -28,11 +31,6 @@
>>>> * is perfectly fine.
>>>> */
>>>> SYM_START(__kernel_rt_sigreturn, SYM_L_GLOBAL, SYM_A_ALIGN)
>>>> - .cfi_startproc
>>>> - .cfi_signal_frame
>>>> - .cfi_def_cfa x29, 0
>>>> - .cfi_offset x29, 0 * 8
>>>> - .cfi_offset x30, 1 * 8
LLVM’s unwinder does not like this version of the CFI. It needs a bit more information,
the cfi_signal_frame is not used for finding the frame.
>>>
>>> Having thought about this again, I think it might be better to stick to
>>> the original version.
>>>
>>> If the signal handler is halfway through mungeing the sigcontext then
>>> backtracing using sigcontext won't be reliable.
>>
>> I suppose, but then what does .cfi_signal_frame do? I'll see if I can
>> find something that uses it. The frame record is still sitting on the
>> stack, so it does feel redundant to say both '.cfi_signal_frame' and
>> '.cfi_def_cfa' (and other architectures, e.g. riscv don't do this).
>>
>> But I'm also happy to play it safe if I can stick a comment in here
>> saying what it does.
Sounds good to me.
>>
>>> Plus, in the absence of any spec that says exactly what
>>> .cfi_signal_frame means*, we probably don't want to rock the boat.
>>
>> The gas docs say:
>>
>> "Mark current function as signal trampoline."
>>
>> which is really informative.
>
> Well, we've demonstrated that identifying the signal frame is a gross
> bodge. The cfi annotation should provide a reliable way to identify the
> signal frame, but I guess it was too poorly specified or came too late
> to prevent the bodges from spreading.
>
> Since this seems to be a nonstandard invention, I wouldn't hold out
> much hope of finding a usable spec.
>
> Of course, something might be using it now, so I guess we have to leave
> it.
>
> ---Dave
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v8 3/3] PM / AVS: SVS: Introduce SVS engine
From: Enric Balletbo Serra @ 2020-05-19 15:30 UTC (permalink / raw)
To: Roger Lu
Cc: Mark Rutland, Nicolas Boichat, Nishanth Menon, Kevin Hilman,
Stephen Boyd, Linux PM list, Angus Lin, Xiaoqing Liu,
linux-kernel, Fan Chen, devicetree@vger.kernel.org, Rob Herring,
moderated list:ARM/Mediatek SoC support, HenryC Chen,
Charles Yang, Matthias Brugger, YT Lee, Linux ARM
In-Reply-To: <20200518092403.22647-4-roger.lu@mediatek.com>
Hi Roger,
Thank you for your patch. I have the feeling that this driver is
complex and difficult to follow and I am wondering if it wouldn't be
better if you can send a version that simply adds basic functionality
for now. Some comments below.
Missatge de Roger Lu <roger.lu@mediatek.com> del dia dl., 18 de maig
2020 a les 11:25:
>
> The SVS (Smart Voltage Scaling) engine is a piece
> of hardware which is used to calculate optimized
> voltage values of several power domains,
> e.g. CPU/GPU/CCI, according to chip process corner,
> temperatures, and other factors. Then DVFS driver
> could apply those optimized voltage values to reduce
> power consumption.
>
> Signed-off-by: Roger Lu <roger.lu@mediatek.com>
> ---
> drivers/power/avs/Kconfig | 10 +
> drivers/power/avs/Makefile | 1 +
> drivers/power/avs/mtk_svs.c | 2119 +++++++++++++++++++++++++++++++++
> include/linux/power/mtk_svs.h | 23 +
> 4 files changed, 2153 insertions(+)
> create mode 100644 drivers/power/avs/mtk_svs.c
> create mode 100644 include/linux/power/mtk_svs.h
>
> diff --git a/drivers/power/avs/Kconfig b/drivers/power/avs/Kconfig
> index cdb4237bfd02..67089ac6040e 100644
> --- a/drivers/power/avs/Kconfig
> +++ b/drivers/power/avs/Kconfig
> @@ -35,3 +35,13 @@ config ROCKCHIP_IODOMAIN
> Say y here to enable support io domains on Rockchip SoCs. It is
> necessary for the io domain setting of the SoC to match the
> voltage supplied by the regulators.
> +
> +config MTK_SVS
> + bool "MediaTek Smart Voltage Scaling(SVS)"
Can't be this a module? Why? In such case, you should use tristate option
> + depends on POWER_AVS && MTK_EFUSE && NVMEM
> + help
> + The SVS engine is a piece of hardware which is used to calculate
> + optimized voltage values of several power domains, e.g.
> + CPU clusters/GPU/CCI, according to chip process corner, temperatures,
> + and other factors. Then DVFS driver could apply those optimized voltage
> + values to reduce power consumption.
> diff --git a/drivers/power/avs/Makefile b/drivers/power/avs/Makefile
> index 9007d05853e2..231adf078582 100644
> --- a/drivers/power/avs/Makefile
> +++ b/drivers/power/avs/Makefile
> @@ -2,3 +2,4 @@
> obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
> obj-$(CONFIG_QCOM_CPR) += qcom-cpr.o
> obj-$(CONFIG_ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
> +obj-$(CONFIG_MTK_SVS) += mtk_svs.o
Will this driver be SoC specific or the idea is to support different
SoCs? If the answer to the first question is yes, please name the file
with the SoC prefix (i.e mt8183_svs). However, If the answer to the
second question is yes, make sure you prefix common
functions/structs/defines with a generic prefix mtk_svs but use the
SoC prefix for the ones you expect will be different between SoC, i.e
mt8183_svs_. This helps the readability of the driver. Also, try to
avoid too generic names.
> diff --git a/drivers/power/avs/mtk_svs.c b/drivers/power/avs/mtk_svs.c
> new file mode 100644
> index 000000000000..a4083b3ef175
> --- /dev/null
> +++ b/drivers/power/avs/mtk_svs.c
> @@ -0,0 +1,2119 @@
> +// SPDX-License-Identifier: GPL-2.0
I suspect you want this only GPLv2 compliant. Use GPL-2.0-only
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + */
> +
> +#define pr_fmt(fmt) "[mtk_svs] " fmt
I don't see any reason to use pr_fmt in this driver. Use dev_*
functions instead and remove the above.
> +
> +#include <linux/bits.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_domain.h>
> +#include <linux/pm_opp.h>
> +#include <linux/pm_qos.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/power/mtk_svs.h>
> +#include <linux/proc_fs.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/reset.h>
> +#include <linux/seq_file.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/thermal.h>
> +#include <linux/uaccess.h>
> +
> +/* svs 1-line sw id */
> +#define SVS_CPU_LITTLE BIT(0)
> +#define SVS_CPU_BIG BIT(1)
> +#define SVS_CCI BIT(2)
> +#define SVS_GPU BIT(3)
> +
> +/* svs bank mode support */
> +#define SVSB_MODE_ALL_DISABLE (0)
nit: SVS_BMODE_?
> +#define SVSB_MODE_INIT01 BIT(1)
> +#define SVSB_MODE_INIT02 BIT(2)
> +#define SVSB_MODE_MON BIT(3)
> +
> +/* svs bank init01 condition */
> +#define SVSB_INIT01_VOLT_IGNORE BIT(1)
> +#define SVSB_INIT01_VOLT_INC_ONLY BIT(2)
> +
> +/* svs bank common setting */
> +#define HIGH_TEMP_MAX (U32_MAX)
nit: SVS_*
> +#define RUNCONFIG_DEFAULT (0x80000000)
Btw, there is any public datasheet where I can see those addresses and
registers and bit fields?
> +#define DC_SIGNED_BIT (0x8000)
> +#define INTEN_INIT0x (0x00005f01)
> +#define INTEN_MONVOPEN (0x00ff0000)
> +#define SVSEN_OFF (0x0)
> +#define SVSEN_MASK (0x7)
> +#define SVSEN_INIT01 (0x1)
> +#define SVSEN_INIT02 (0x5)
> +#define SVSEN_MON (0x2)
> +#define INTSTS_MONVOP (0x00ff0000)
> +#define INTSTS_COMPLETE (0x1)
> +#define INTSTS_CLEAN (0x00ffffff)
> +
> +#define proc_fops_rw(name) \
> + static int name ## _proc_open(struct inode *inode, \
> + struct file *file) \
> + { \
> + return single_open(file, name ## _proc_show, \
> + PDE_DATA(inode)); \
> + } \
> + static const struct proc_ops name ## _proc_fops = { \
> + .proc_open = name ## _proc_open, \
> + .proc_read = seq_read, \
> + .proc_lseek = seq_lseek, \
> + .proc_release = single_release, \
> + .proc_write = name ## _proc_write, \
> + }
> +
> +#define proc_fops_ro(name) \
> + static int name ## _proc_open(struct inode *inode, \
> + struct file *file) \
> + { \
> + return single_open(file, name ## _proc_show, \
> + PDE_DATA(inode)); \
> + } \
> + static const struct proc_ops name ## _proc_fops = { \
> + .proc_open = name ## _proc_open, \
> + .proc_read = seq_read, \
> + .proc_lseek = seq_lseek, \
> + .proc_release = single_release, \
> + }
> +
> +#define proc_entry(name) {__stringify(name), &name ## _proc_fops}
> +
/proc is usually the old way of exporting files to userspace, so
unless you have a really good reason use sysfs instead, or even
better, if it is only for debug purposes use debugfs. Also, you should
document the entries in Documentation.
> +static DEFINE_SPINLOCK(mtk_svs_lock);
> +struct mtk_svs;
> +
> +enum svsb_phase {
nit: mtk_svs_bphase?
> + SVSB_PHASE_INIT01 = 0,
nit: SVS_BPHASE_?
> + SVSB_PHASE_INIT02,
> + SVSB_PHASE_MON,
> + SVSB_PHASE_ERROR,
> +};
> +
> +enum reg_index {
nit: svs_reg_index?
> + TEMPMONCTL0 = 0,
> + TEMPMONCTL1,
> + TEMPMONCTL2,
> + TEMPMONINT,
> + TEMPMONINTSTS,
> + TEMPMONIDET0,
> + TEMPMONIDET1,
> + TEMPMONIDET2,
> + TEMPH2NTHRE,
> + TEMPHTHRE,
> + TEMPCTHRE,
> + TEMPOFFSETH,
> + TEMPOFFSETL,
> + TEMPMSRCTL0,
> + TEMPMSRCTL1,
> + TEMPAHBPOLL,
> + TEMPAHBTO,
> + TEMPADCPNP0,
> + TEMPADCPNP1,
> + TEMPADCPNP2,
> + TEMPADCMUX,
> + TEMPADCEXT,
> + TEMPADCEXT1,
> + TEMPADCEN,
> + TEMPPNPMUXADDR,
> + TEMPADCMUXADDR,
> + TEMPADCEXTADDR,
> + TEMPADCEXT1ADDR,
> + TEMPADCENADDR,
> + TEMPADCVALIDADDR,
> + TEMPADCVOLTADDR,
> + TEMPRDCTRL,
> + TEMPADCVALIDMASK,
> + TEMPADCVOLTAGESHIFT,
> + TEMPADCWRITECTRL,
> + TEMPMSR0,
> + TEMPMSR1,
> + TEMPMSR2,
> + TEMPADCHADDR,
> + TEMPIMMD0,
> + TEMPIMMD1,
> + TEMPIMMD2,
> + TEMPMONIDET3,
> + TEMPADCPNP3,
> + TEMPMSR3,
> + TEMPIMMD3,
> + TEMPPROTCTL,
> + TEMPPROTTA,
> + TEMPPROTTB,
> + TEMPPROTTC,
> + TEMPSPARE0,
> + TEMPSPARE1,
> + TEMPSPARE2,
> + TEMPSPARE3,
> + TEMPMSR0_1,
> + TEMPMSR1_1,
> + TEMPMSR2_1,
> + TEMPMSR3_1,
> + DESCHAR,
> + TEMPCHAR,
> + DETCHAR,
> + AGECHAR,
> + DCCONFIG,
> + AGECONFIG,
> + FREQPCT30,
> + FREQPCT74,
> + LIMITVALS,
> + VBOOT,
> + DETWINDOW,
> + CONFIG,
> + TSCALCS,
> + RUNCONFIG,
> + SVSEN,
> + INIT2VALS,
> + DCVALUES,
> + AGEVALUES,
> + VOP30,
> + VOP74,
> + TEMP,
> + INTSTS,
> + INTSTSRAW,
> + INTEN,
> + CHKINT,
> + CHKSHIFT,
> + STATUS,
> + VDESIGN30,
> + VDESIGN74,
> + DVT30,
> + DVT74,
> + AGECOUNT,
> + SMSTATE0,
> + SMSTATE1,
> + CTL0,
> + DESDETSEC,
> + TEMPAGESEC,
> + CTRLSPARE0,
> + CTRLSPARE1,
> + CTRLSPARE2,
> + CTRLSPARE3,
> + CORESEL,
> + THERMINTST,
> + INTST,
> + THSTAGE0ST,
> + THSTAGE1ST,
> + THSTAGE2ST,
> + THAHBST0,
> + THAHBST1,
> + SPARE0,
> + SPARE1,
> + SPARE2,
> + SPARE3,
> + THSLPEVEB,
> + reg_num,
> +};
> +
> +static const u32 svs_regs_v2[] = {
Is this SoC specific or shared between SoCs?
> + [TEMPMONCTL0] = 0x000,
> + [TEMPMONCTL1] = 0x004,
> + [TEMPMONCTL2] = 0x008,
> + [TEMPMONINT] = 0x00c,
> + [TEMPMONINTSTS] = 0x010,
> + [TEMPMONIDET0] = 0x014,
> + [TEMPMONIDET1] = 0x018,
> + [TEMPMONIDET2] = 0x01c,
> + [TEMPH2NTHRE] = 0x024,
> + [TEMPHTHRE] = 0x028,
> + [TEMPCTHRE] = 0x02c,
> + [TEMPOFFSETH] = 0x030,
> + [TEMPOFFSETL] = 0x034,
> + [TEMPMSRCTL0] = 0x038,
> + [TEMPMSRCTL1] = 0x03c,
> + [TEMPAHBPOLL] = 0x040,
> + [TEMPAHBTO] = 0x044,
> + [TEMPADCPNP0] = 0x048,
> + [TEMPADCPNP1] = 0x04c,
> + [TEMPADCPNP2] = 0x050,
> + [TEMPADCMUX] = 0x054,
> + [TEMPADCEXT] = 0x058,
> + [TEMPADCEXT1] = 0x05c,
> + [TEMPADCEN] = 0x060,
> + [TEMPPNPMUXADDR] = 0x064,
> + [TEMPADCMUXADDR] = 0x068,
> + [TEMPADCEXTADDR] = 0x06c,
> + [TEMPADCEXT1ADDR] = 0x070,
> + [TEMPADCENADDR] = 0x074,
> + [TEMPADCVALIDADDR] = 0x078,
> + [TEMPADCVOLTADDR] = 0x07c,
> + [TEMPRDCTRL] = 0x080,
> + [TEMPADCVALIDMASK] = 0x084,
> + [TEMPADCVOLTAGESHIFT] = 0x088,
> + [TEMPADCWRITECTRL] = 0x08c,
> + [TEMPMSR0] = 0x090,
> + [TEMPMSR1] = 0x094,
> + [TEMPMSR2] = 0x098,
> + [TEMPADCHADDR] = 0x09c,
> + [TEMPIMMD0] = 0x0a0,
> + [TEMPIMMD1] = 0x0a4,
> + [TEMPIMMD2] = 0x0a8,
> + [TEMPMONIDET3] = 0x0b0,
> + [TEMPADCPNP3] = 0x0b4,
> + [TEMPMSR3] = 0x0b8,
> + [TEMPIMMD3] = 0x0bc,
> + [TEMPPROTCTL] = 0x0c0,
> + [TEMPPROTTA] = 0x0c4,
> + [TEMPPROTTB] = 0x0c8,
> + [TEMPPROTTC] = 0x0cc,
> + [TEMPSPARE0] = 0x0f0,
> + [TEMPSPARE1] = 0x0f4,
> + [TEMPSPARE2] = 0x0f8,
> + [TEMPSPARE3] = 0x0fc,
> + [TEMPMSR0_1] = 0x190,
> + [TEMPMSR1_1] = 0x194,
> + [TEMPMSR2_1] = 0x198,
> + [TEMPMSR3_1] = 0x1b8,
> + [DESCHAR] = 0xc00,
> + [TEMPCHAR] = 0xc04,
> + [DETCHAR] = 0xc08,
> + [AGECHAR] = 0xc0c,
> + [DCCONFIG] = 0xc10,
> + [AGECONFIG] = 0xc14,
> + [FREQPCT30] = 0xc18,
> + [FREQPCT74] = 0xc1c,
> + [LIMITVALS] = 0xc20,
> + [VBOOT] = 0xc24,
> + [DETWINDOW] = 0xc28,
> + [CONFIG] = 0xc2c,
> + [TSCALCS] = 0xc30,
> + [RUNCONFIG] = 0xc34,
> + [SVSEN] = 0xc38,
> + [INIT2VALS] = 0xc3c,
> + [DCVALUES] = 0xc40,
> + [AGEVALUES] = 0xc44,
> + [VOP30] = 0xc48,
> + [VOP74] = 0xc4c,
> + [TEMP] = 0xc50,
> + [INTSTS] = 0xc54,
> + [INTSTSRAW] = 0xc58,
> + [INTEN] = 0xc5c,
> + [CHKINT] = 0xc60,
> + [CHKSHIFT] = 0xc64,
> + [STATUS] = 0xc68,
> + [VDESIGN30] = 0xc6c,
> + [VDESIGN74] = 0xc70,
> + [DVT30] = 0xc74,
> + [DVT74] = 0xc78,
> + [AGECOUNT] = 0xc7c,
> + [SMSTATE0] = 0xc80,
> + [SMSTATE1] = 0xc84,
> + [CTL0] = 0xc88,
> + [DESDETSEC] = 0xce0,
> + [TEMPAGESEC] = 0xce4,
> + [CTRLSPARE0] = 0xcf0,
> + [CTRLSPARE1] = 0xcf4,
> + [CTRLSPARE2] = 0xcf8,
> + [CTRLSPARE3] = 0xcfc,
> + [CORESEL] = 0xf00,
> + [THERMINTST] = 0xf04,
> + [INTST] = 0xf08,
> + [THSTAGE0ST] = 0xf0c,
> + [THSTAGE1ST] = 0xf10,
> + [THSTAGE2ST] = 0xf14,
> + [THAHBST0] = 0xf18,
> + [THAHBST1] = 0xf1c,
> + [SPARE0] = 0xf20,
> + [SPARE1] = 0xf24,
> + [SPARE2] = 0xf28,
> + [SPARE3] = 0xf2c,
> + [THSLPEVEB] = 0xf30,
> +};
> +
> +struct thermal_parameter {
In general, not only in this struct, would be good have some
documentation to have a better undestanding of the fields. That makes
the job of the reviewer a bit easier.
> + int adc_ge_t;
> + int adc_oe_t;
> + int ge;
> + int oe;
> + int gain;
> + int o_vtsabb;
> + int o_vtsmcu1;
> + int o_vtsmcu2;
> + int o_vtsmcu3;
> + int o_vtsmcu4;
> + int o_vtsmcu5;
> + int degc_cali;
> + int adc_cali_en_t;
> + int o_slope;
> + int o_slope_sign;
> + int ts_id;
> +};
> +
> +struct svs_bank_ops {
> + void (*set_freqs_pct)(struct mtk_svs *svs);
> + void (*get_vops)(struct mtk_svs *svs);
> +};
> +
> +struct svs_bank {
> + struct svs_bank_ops *ops;
> + struct completion init_completion;
> + struct device *dev;
> + struct regulator *buck;
> + struct mutex lock; /* Lock to protect update voltage process */
> + bool suspended;
> + bool mtcmos_request;
> + s32 volt_offset;
> + u32 mode_support;
> + u32 opp_freqs[16];
> + u32 freqs_pct[16];
> + u32 opp_volts[16];
> + u32 init02_volts[16];
> + u32 volts[16];
> + u32 reg_data[3][reg_num];
> + u32 freq_base;
> + u32 vboot;
> + u32 volt_step;
> + u32 volt_base;
> + u32 init01_volt_flag;
> + u32 phase;
> + u32 vmax;
> + u32 vmin;
> + u32 bts;
> + u32 mts;
> + u32 bdes;
> + u32 mdes;
> + u32 mtdes;
> + u32 dcbdet;
> + u32 dcmdet;
> + u32 dthi;
> + u32 dtlo;
> + u32 det_window;
> + u32 det_max;
> + u32 age_config;
> + u32 age_voffset_in;
> + u32 agem;
> + u32 dc_config;
> + u32 dc_voffset_in;
> + u32 dvt_fixed;
> + u32 vco;
> + u32 chk_shift;
> + u32 svs_temp;
> + u32 upper_temp_bound;
> + u32 lower_temp_bound;
> + u32 high_temp_threashold;
> + u32 high_temp_offset;
> + u32 low_temp_threashold;
> + u32 low_temp_offset;
> + u32 core_sel;
> + u32 opp_count;
> + u32 int_st;
> + u32 systemclk_en;
> + u32 sw_id;
> + u32 bank_id;
> + u32 ctl0;
> + u8 *of_compatible;
> + u8 *name;
> + u8 *tzone_name;
> + u8 *buck_name;
> +};
> +
> +struct svs_platform {
> + struct svs_bank *banks;
> + bool (*efuse_parsing)(struct mtk_svs *svs);
> + bool fake_efuse;
> + bool need_hw_reset;
> + const u32 *regs;
> + unsigned long irqflags;
> + u32 bank_num;
> + u32 efuse_num;
> + u32 efuse_check;
> + u32 thermal_efuse_num;
> + u8 *name;
> +};
> +
> +struct mtk_svs {
> + const struct svs_platform *platform;
> + struct svs_bank *bank;
> + struct device *dev;
> + void __iomem *base;
> + struct clk *main_clk;
> + u32 *efuse;
> + u32 *thermal_efuse;
> +};
> +
> +unsigned long claim_mtk_svs_lock(void)
> + __acquires(&mtk_svs_lock)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&mtk_svs_lock, flags);
> +
> + return flags;
> +}
> +EXPORT_SYMBOL_GPL(claim_mtk_svs_lock);
Is this used for an external module? AFAICS no, so no need to export
and you can replace directly the callers of this with the
spin_lock_irqsave directly. If you plan to use this in the future for
other modules, export when is really needed to be exported.
> +
> +void release_mtk_svs_lock(unsigned long flags)
> + __releases(&mtk_svs_lock)
> +{
> + spin_unlock_irqrestore(&mtk_svs_lock, flags);
> +}
> +EXPORT_SYMBOL_GPL(release_mtk_svs_lock);
> +
ditto
> +static u32 percent(u32 numerator, u32 denominator)
> +{
> + u32 pct;
> +
> + /* If not divide 1000, "numerator * 100" would be data overflow. */
> + numerator /= 1000;
> + denominator /= 1000;
> + pct = ((numerator * 100) + denominator - 1) / denominator;
> + pct &= GENMASK(7, 0);
> +
> + return pct;
> +}
> +
> +static u32 svs_readl(struct mtk_svs *svs, enum reg_index rg_i)
> +{
> + return readl(svs->base + svs->platform->regs[rg_i]);
> +}
> +
> +static void svs_writel(struct mtk_svs *svs, u32 val, enum reg_index rg_i)
> +{
> + writel(val, svs->base + svs->platform->regs[rg_i]);
> +}
> +
> +static void svs_switch_bank(struct mtk_svs *svs)
> +{
> + struct svs_bank *svsb = svs->bank;
> +
> + svs_writel(svs, svsb->core_sel, CORESEL);
> +}
> +
> +static u32 svsb_volt_to_opp_volt(u32 svsb_volt, u32 svsb_volt_step,
> + u32 svsb_volt_base)
> +{
> + u32 u_volt;
> +
> + u_volt = (svsb_volt * svsb_volt_step) + svsb_volt_base;
> +
> + return u_volt;
> +}
> +
> +static int svsb_get_zone_temperature(struct svs_bank *svsb, int *tzone_temp)
> +{
> + struct thermal_zone_device *tzd;
> +
> + tzd = thermal_zone_get_zone_by_name(svsb->tzone_name);
> + if (IS_ERR(tzd))
> + return PTR_ERR(tzd);
> +
> + return thermal_zone_get_temp(tzd, tzone_temp);
> +}
> +
> +static int svsb_set_volts(struct svs_bank *svsb, bool force_update)
> +{
> + u32 i, svsb_volt, opp_volt, temp_offset = 0;
> + int tzone_temp, ret;
> +
> + mutex_lock(&svsb->lock);
> +
> + /*
> + * If bank is suspended, it means signed-off voltages are applied.
> + * Don't need to update opp voltage anymore.
> + */
> + if (svsb->suspended && !force_update) {
> + pr_notice("%s: bank is suspended\n", svsb->name);
Replace all pr_* for dev_* and Its better to be quiet, this messages
looks to me for a dev_dbg candidate, not a notice.
> + mutex_unlock(&svsb->lock);
> + return -EPERM;
> + }
> +
> + /* Get thermal effect */
> + if (svsb->phase == SVSB_PHASE_MON) {
> + if (svsb->svs_temp > svsb->upper_temp_bound &&
> + svsb->svs_temp < svsb->lower_temp_bound) {
> + pr_err("%s: svs_temp is abnormal (0x%x)?\n",
> + svsb->name, svsb->svs_temp);
dev_err and I am not sure if the error level is appropriate here
> + mutex_unlock(&svsb->lock);
> + return -EINVAL;
> + }
> +
> + ret = svsb_get_zone_temperature(svsb, &tzone_temp);
> + if (ret) {
> + pr_err("%s: cannot get zone \"%s\" temperature(%d)\n",
> + svsb->name, svsb->tzone_name, ret);
> + pr_err("%s: set signed-off voltage this time.\n",
> + svsb->name);
> + svsb->phase = SVSB_PHASE_ERROR;
> + }
> +
> + if (tzone_temp >= svsb->high_temp_threashold)
> + temp_offset += svsb->high_temp_offset;
> +
> + if (tzone_temp <= svsb->low_temp_threashold)
> + temp_offset += svsb->low_temp_offset;
> + }
> +
> + /* vmin <= svsb_volt (opp_volt) <= signed-off voltage */
> + for (i = 0; i < svsb->opp_count; i++) {
> + if (svsb->phase == SVSB_PHASE_MON) {
> + svsb_volt = max((svsb->volts[i] + svsb->volt_offset +
> + temp_offset), svsb->vmin);
> + opp_volt = svsb_volt_to_opp_volt(svsb_volt,
> + svsb->volt_step,
> + svsb->volt_base);
> + } else if (svsb->phase == SVSB_PHASE_INIT02) {
> + svsb_volt = max((svsb->init02_volts[i] +
> + svsb->volt_offset), svsb->vmin);
> + opp_volt = svsb_volt_to_opp_volt(svsb_volt,
> + svsb->volt_step,
> + svsb->volt_base);
> + } else if (svsb->phase == SVSB_PHASE_ERROR) {
> + opp_volt = svsb->opp_volts[i];
> + } else {
> + pr_err("%s: unknown phase: %u?\n",
> + svsb->name, svsb->phase);
I think that using a goto here and some places below will help the readability.
ret = -EINVAL;
goto unlock_mutex
[...]
unlock_mutex:
mutex_unlock(&svsb->lock);
return ret;
> + mutex_unlock(&svsb->lock);
> + return -EINVAL;
> + }
> +
> + opp_volt = min(opp_volt, svsb->opp_volts[i]);
> + ret = dev_pm_opp_adjust_voltage(svsb->dev, svsb->opp_freqs[i],
> + opp_volt, opp_volt,
> + svsb->opp_volts[i]);
> + if (ret) {
> + pr_err("%s: set voltage failed: %d\n", svsb->name, ret);
> + mutex_unlock(&svsb->lock);
> + return ret;
> + }
> + }
> +
> + mutex_unlock(&svsb->lock);
> +
> + return 0;
> +}
> +
> +static u32 interpolate(u32 f0, u32 f1, u32 v0, u32 v1, u32 fx)
> +{
> + u32 vy;
> +
> + if (v0 == v1 || f0 == f1)
> + return v0;
> +
> + /* *100 to have decimal fraction factor, +99 for rounding up. */
> + vy = (v0 * 100) - ((((v0 - v1) * 100) / (f0 - f1)) * (f0 - fx));
> + vy = (vy + 99) / 100;
> +
> + return vy;
> +}
> +
> +static void svs_get_vops_v2(struct mtk_svs *svs)
> +{
> + struct svs_bank *svsb = svs->bank;
> + u32 temp, i;
> +
> + temp = svs_readl(svs, VOP30);
> + svsb->volts[6] = (temp >> 24) & GENMASK(7, 0);
> + svsb->volts[4] = (temp >> 16) & GENMASK(7, 0);
> + svsb->volts[2] = (temp >> 8) & GENMASK(7, 0);
> + svsb->volts[0] = (temp & GENMASK(7, 0));
> +
> + temp = svs_readl(svs, VOP74);
> + svsb->volts[14] = (temp >> 24) & GENMASK(7, 0);
> + svsb->volts[12] = (temp >> 16) & GENMASK(7, 0);
> + svsb->volts[10] = (temp >> 8) & GENMASK(7, 0);
> + svsb->volts[8] = (temp & GENMASK(7, 0));
> +
> + for (i = 0; i <= 7; i++) {
> + if (i < 7) {
> + svsb->volts[(i * 2) + 1] =
> + interpolate(svsb->freqs_pct[i * 2],
> + svsb->freqs_pct[(i + 1) * 2],
> + svsb->volts[i * 2],
> + svsb->volts[(i + 1) * 2],
> + svsb->freqs_pct[(i * 2) + 1]);
> + } else if (i == 7) {
> + svsb->volts[(i * 2) + 1] =
> + interpolate(svsb->freqs_pct[(i - 1) * 2],
> + svsb->freqs_pct[i * 2],
> + svsb->volts[(i - 1) * 2],
> + svsb->volts[i * 2],
> + svsb->freqs_pct[(i * 2) + 1]);
> + }
> + }
> +}
> +
> +static void svs_set_freqs_pct_v2(struct mtk_svs *svs)
> +{
> + struct svs_bank *svsb = svs->bank;
> +
> + svs_writel(svs,
> + ((svsb->freqs_pct[6] << 24) & GENMASK(31, 24)) |
> + ((svsb->freqs_pct[4] << 16) & GENMASK(23, 16)) |
> + ((svsb->freqs_pct[2] << 8) & GENMASK(15, 8)) |
> + (svsb->freqs_pct[0] & GENMASK(7, 0)),
> + FREQPCT30);
> + svs_writel(svs,
> + ((svsb->freqs_pct[14] << 24) & GENMASK(31, 24)) |
> + ((svsb->freqs_pct[12] << 16) & GENMASK(23, 16)) |
> + ((svsb->freqs_pct[10] << 8) & GENMASK(15, 8)) |
> + ((svsb->freqs_pct[8]) & GENMASK(7, 0)),
> + FREQPCT74);
> +}
> +
> +static void svs_set_phase(struct mtk_svs *svs, u32 target_phase)
> +{
> + struct svs_bank *svsb = svs->bank;
> + u32 des_char, temp_char, det_char, limit_vals;
> + u32 init2vals, ts_calcs, val, filter, i;
> +
> + svs_switch_bank(svs);
> +
> + des_char = ((svsb->bdes << 8) & GENMASK(15, 8)) |
> + (svsb->mdes & GENMASK(7, 0));
> + svs_writel(svs, des_char, DESCHAR);
> +
> + temp_char = ((svsb->vco << 16) & GENMASK(23, 16)) |
> + ((svsb->mtdes << 8) & GENMASK(15, 8)) |
> + (svsb->dvt_fixed & GENMASK(7, 0));
> + svs_writel(svs, temp_char, TEMPCHAR);
> +
> + det_char = ((svsb->dcbdet << 8) & GENMASK(15, 8)) |
> + (svsb->dcmdet & GENMASK(7, 0));
> + svs_writel(svs, det_char, DETCHAR);
> +
> + svs_writel(svs, svsb->dc_config, DCCONFIG);
> + svs_writel(svs, svsb->age_config, AGECONFIG);
> +
> + if (!svsb->agem) {
> + svs_writel(svs, RUNCONFIG_DEFAULT, RUNCONFIG);
> + } else {
> + val = 0x0;
> +
> + for (i = 0; i < 24; i += 2) {
> + filter = 0x3 << i;
> +
> + if (!(svsb->age_config & filter))
> + val |= (0x1 << i);
> + else
> + val |= (svsb->age_config & filter);
> + }
> + svs_writel(svs, val, RUNCONFIG);
> + }
> +
> + svsb->ops->set_freqs_pct(svs);
> +
> + limit_vals = ((svsb->vmax << 24) & GENMASK(31, 24)) |
> + ((svsb->vmin << 16) & GENMASK(23, 16)) |
> + ((svsb->dthi << 8) & GENMASK(15, 8)) |
> + (svsb->dtlo & GENMASK(7, 0));
> + svs_writel(svs, limit_vals, LIMITVALS);
> + svs_writel(svs, (svsb->vboot & GENMASK(7, 0)), VBOOT);
> + svs_writel(svs, (svsb->det_window & GENMASK(15, 0)), DETWINDOW);
> + svs_writel(svs, (svsb->det_max & GENMASK(15, 0)), CONFIG);
> +
> + if (svsb->chk_shift)
> + svs_writel(svs, (svsb->chk_shift & GENMASK(7, 0)), CHKSHIFT);
> +
> + if (svsb->ctl0)
> + svs_writel(svs, svsb->ctl0, CTL0);
> +
> + svs_writel(svs, INTSTS_CLEAN, INTSTS);
> +
> + switch (target_phase) {
> + case SVSB_PHASE_INIT01:
> + svs_writel(svs, INTEN_INIT0x, INTEN);
> + svs_writel(svs, SVSEN_INIT01, SVSEN);
> + break;
> + case SVSB_PHASE_INIT02:
> + svs_writel(svs, INTEN_INIT0x, INTEN);
> + init2vals = ((svsb->age_voffset_in << 16) & GENMASK(31, 16)) |
> + (svsb->dc_voffset_in & GENMASK(15, 0));
> + svs_writel(svs, init2vals, INIT2VALS);
> + svs_writel(svs, SVSEN_INIT02, SVSEN);
> + break;
> + case SVSB_PHASE_MON:
> + ts_calcs = ((svsb->bts << 12) & GENMASK(23, 12)) |
> + (svsb->mts & GENMASK(11, 0));
> + svs_writel(svs, ts_calcs, TSCALCS);
> + svs_writel(svs, INTEN_MONVOPEN, INTEN);
> + svs_writel(svs, SVSEN_MON, SVSEN);
> + break;
> + default:
> + WARN_ON(1);
> + break;
> + }
> +}
> +
> +static inline void svs_init01_isr_handler(struct mtk_svs *svs)
> +{
> + struct svs_bank *svsb = svs->bank;
> + enum reg_index rg_i;
> +
> + pr_notice("%s: %s: VDN74:0x%08x, VDN30:0x%08x, DCVALUES:0x%08x\n",
> + svsb->name, __func__, svs_readl(svs, VDESIGN74),
> + svs_readl(svs, VDESIGN30), svs_readl(svs, DCVALUES));
> +
> + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
> + svsb->reg_data[SVSB_PHASE_INIT01][rg_i] = svs_readl(svs, rg_i);
> +
> + svsb->phase = SVSB_PHASE_INIT01;
> + svsb->dc_voffset_in = ~(svs_readl(svs, DCVALUES) & GENMASK(15, 0)) + 1;
> + if (svsb->init01_volt_flag == SVSB_INIT01_VOLT_IGNORE)
> + svsb->dc_voffset_in = 0;
> + else if ((svsb->dc_voffset_in & DC_SIGNED_BIT) &&
> + (svsb->init01_volt_flag == SVSB_INIT01_VOLT_INC_ONLY))
> + svsb->dc_voffset_in = 0;
> +
> + svsb->age_voffset_in = svs_readl(svs, AGEVALUES) & GENMASK(15, 0);
> +
> + svs_writel(svs, SVSEN_OFF, SVSEN);
> + svs_writel(svs, INTSTS_COMPLETE, INTSTS);
> +
> + /* svs init01 clock gating */
> + svsb->core_sel &= ~svsb->systemclk_en;
> + complete(&svsb->init_completion);
> +}
> +
> +static inline void svs_init02_isr_handler(struct mtk_svs *svs)
> +{
> + struct svs_bank *svsb = svs->bank;
> + enum reg_index rg_i;
> +
> + pr_notice("%s: %s: VOP74:0x%08x, VOP30:0x%08x, DCVALUES:0x%08x\n",
> + svsb->name, __func__, svs_readl(svs, VOP74),
> + svs_readl(svs, VOP30), svs_readl(svs, DCVALUES));
> +
> + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
> + svsb->reg_data[SVSB_PHASE_INIT02][rg_i] = svs_readl(svs, rg_i);
> +
> + svsb->phase = SVSB_PHASE_INIT02;
> + svsb->ops->get_vops(svs);
> + memcpy(svsb->init02_volts, svsb->volts, sizeof(u32) * svsb->opp_count);
> +
> + svs_writel(svs, SVSEN_OFF, SVSEN);
> + svs_writel(svs, INTSTS_COMPLETE, INTSTS);
> +
> + complete(&svsb->init_completion);
> +}
> +
> +static inline void svs_mon_mode_isr_handler(struct mtk_svs *svs)
> +{
> + struct svs_bank *svsb = svs->bank;
> + enum reg_index rg_i;
> +
> + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
> + svsb->reg_data[SVSB_PHASE_MON][rg_i] = svs_readl(svs, rg_i);
> +
> + svsb->phase = SVSB_PHASE_MON;
> + svsb->svs_temp = svs_readl(svs, TEMP) & GENMASK(7, 0);
> + svsb->ops->get_vops(svs);
> +
> + svs_writel(svs, INTSTS_MONVOP, INTSTS);
> +}
> +
> +static inline void svs_error_isr_handler(struct mtk_svs *svs)
> +{
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb = svs->bank;
> + enum reg_index rg_i;
> +
> + pr_err("%s(): %s(%s)", __func__, svsp->name, svsb->name);
> + pr_err("CORESEL(0x%x) = 0x%08x\n",
> + svsp->regs[CORESEL], svs_readl(svs, CORESEL)),
> + pr_err("SVSEN(0x%x) = 0x%08x, INTSTS(0x%x) = 0x%08x\n",
> + svsp->regs[SVSEN], svs_readl(svs, SVSEN),
> + svsp->regs[INTSTS], svs_readl(svs, INTSTS));
> + pr_err("SMSTATE0(0x%x) = 0x%08x, SMSTATE1(0x%x) = 0x%08x\n",
> + svsp->regs[SMSTATE0], svs_readl(svs, SMSTATE0),
> + svsp->regs[SMSTATE1], svs_readl(svs, SMSTATE1));
> + pr_err("TEMP(0x%x) = 0x%08x, TEMPMSR0(0x%x) = 0x%08x\n",
> + svsp->regs[TEMP], svs_readl(svs, TEMP),
> + svsp->regs[TEMPMSR0], svs_readl(svs, TEMPMSR0));
> + pr_err("TEMPMSR1(0x%x) = 0x%08x, TEMPMSR2(0x%x) = 0x%08x\n",
> + svsp->regs[TEMPMSR1], svs_readl(svs, TEMPMSR1),
> + svsp->regs[TEMPMSR2], svs_readl(svs, TEMPMSR2));
> + pr_err("TEMPMONCTL0(0x%x) = 0x%08x, TEMPMSRCTL1(0x%x) = 0x%08x\n",
> + svsp->regs[TEMPMONCTL0], svs_readl(svs, TEMPMONCTL0),
> + svsp->regs[TEMPMSRCTL1], svs_readl(svs, TEMPMSRCTL1));
> +
> + for (rg_i = TEMPMONCTL0; rg_i < reg_num; rg_i++)
> + svsb->reg_data[SVSB_PHASE_MON][rg_i] = svs_readl(svs, rg_i);
> +
> + svsb->mode_support = SVSB_MODE_ALL_DISABLE;
> +
> + if (svsb->phase != SVSB_PHASE_INIT01)
> + svsb->phase = SVSB_PHASE_ERROR;
> +
> + svs_writel(svs, SVSEN_OFF, SVSEN);
> + svs_writel(svs, INTSTS_CLEAN, INTSTS);
> +}
> +
> +static irqreturn_t svs_isr(int irq, void *data)
> +{
> + struct mtk_svs *svs = (struct mtk_svs *)data;
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb = NULL;
> + unsigned long flags;
> + u32 idx, int_sts, svs_en;
> +
> + flags = claim_mtk_svs_lock();
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svs->bank = svsb;
> +
> + if (svsb->int_st & svs_readl(svs, INTST))
> + continue;
> +
> + if (!svsb->suspended) {
> + svs_switch_bank(svs);
> + int_sts = svs_readl(svs, INTSTS);
> + svs_en = svs_readl(svs, SVSEN);
> +
> + if (int_sts == INTSTS_COMPLETE &&
> + ((svs_en & SVSEN_MASK) == SVSEN_INIT01))
> + svs_init01_isr_handler(svs);
> + else if ((int_sts == INTSTS_COMPLETE) &&
> + ((svs_en & SVSEN_MASK) == SVSEN_INIT02))
> + svs_init02_isr_handler(svs);
> + else if (!!(int_sts & INTSTS_MONVOP))
> + svs_mon_mode_isr_handler(svs);
> + else
> + svs_error_isr_handler(svs);
> + }
> +
> + break;
> + }
> + release_mtk_svs_lock(flags);
> +
> + if (svsb->phase != SVSB_PHASE_INIT01)
> + svsb_set_volts(svsb, false);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void svs_mon_mode(struct mtk_svs *svs)
> +{
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb;
> + unsigned long flags;
> + u32 idx;
> +
> + flags = claim_mtk_svs_lock();
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svs->bank = svsb;
> +
> + if (!(svsb->mode_support & SVSB_MODE_MON))
> + continue;
> +
> + svs_set_phase(svs, SVSB_PHASE_MON);
> + }
> + release_mtk_svs_lock(flags);
> +}
> +
> +static int svs_init02(struct mtk_svs *svs)
> +{
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb;
> + unsigned long flags, time_left;
> + u32 idx;
> +
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svs->bank = svsb;
> +
> + if (!(svsb->mode_support & SVSB_MODE_INIT02))
> + continue;
> +
> + reinit_completion(&svsb->init_completion);
> + flags = claim_mtk_svs_lock();
> + svs_set_phase(svs, SVSB_PHASE_INIT02);
> + release_mtk_svs_lock(flags);
> + time_left =
> + wait_for_completion_timeout(&svsb->init_completion,
> + msecs_to_jiffies(2000));
> + if (!time_left) {
> + pr_err("%s: init02 completion timeout\n", svsb->name);
> + return -EBUSY;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int svs_init01(struct mtk_svs *svs)
> +{
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb;
> + struct pm_qos_request *qos_request;
> + unsigned long flags, time_left;
> + bool search_done;
> + int ret = -EPERM;
> + u32 opp_freqs, opp_vboot, buck_volt, idx, i;
> +
> + qos_request = kzalloc(sizeof(*qos_request), GFP_KERNEL);
> + if (!qos_request)
> + return -ENOMEM;
> +
> + /* Let CPUs leave idle-off state for initializing svs_init01. */
> + cpu_latency_qos_add_request(qos_request, 0);
> +
> + /*
> + * Sometimes two svs banks use the same buck.
> + * Therefore, we set each svs bank to vboot voltage first.
> + */
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + search_done = false;
> +
> + ret = regulator_set_mode(svsb->buck, REGULATOR_MODE_FAST);
> + if (ret)
> + pr_notice("%s: fail to set fast mode: %d\n",
> + svsb->name, ret);
> +
> + if (svsb->mtcmos_request) {
> + ret = regulator_enable(svsb->buck);
> + if (ret) {
> + pr_err("%s: fail to enable %s power: %d\n",
> + svsb->name, svsb->buck_name, ret);
> + goto init01_finish;
> + }
> +
> + ret = dev_pm_domain_attach(svsb->dev, false);
> + if (ret) {
> + pr_err("%s: attach pm domain fail: %d\n",
> + svsb->name, ret);
> + goto init01_finish;
> + }
> +
> + pm_runtime_enable(svsb->dev);
> + ret = pm_runtime_get_sync(svsb->dev);
> + if (ret < 0) {
> + pr_err("%s: turn mtcmos on fail: %d\n",
> + svsb->name, ret);
> + goto init01_finish;
> + }
> + }
> +
> + /*
> + * Find the fastest freq that can be run at vboot and
> + * fix to that freq until svs_init01 is done.
> + */
> + opp_vboot = svsb_volt_to_opp_volt(svsb->vboot,
> + svsb->volt_step,
> + svsb->volt_base);
> +
> + for (i = 0; i < svsb->opp_count; i++) {
> + opp_freqs = svsb->opp_freqs[i];
> + if (!search_done && svsb->opp_volts[i] <= opp_vboot) {
> + ret = dev_pm_opp_adjust_voltage(svsb->dev,
> + opp_freqs,
> + opp_vboot,
> + opp_vboot,
> + opp_vboot);
> + if (ret) {
> + pr_err("%s: set voltage failed: %d\n",
> + svsb->name, ret);
> + goto init01_finish;
> + }
> +
> + search_done = true;
> + } else {
> + dev_pm_opp_disable(svsb->dev,
> + svsb->opp_freqs[i]);
> + }
> + }
> + }
> +
> + /* svs bank init01 begins */
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svs->bank = svsb;
> +
> + if (!(svsb->mode_support & SVSB_MODE_INIT01))
> + continue;
> +
> + opp_vboot = svsb_volt_to_opp_volt(svsb->vboot,
> + svsb->volt_step,
> + svsb->volt_base);
> +
> + buck_volt = regulator_get_voltage(svsb->buck);
> + if (buck_volt != opp_vboot) {
> + pr_err("%s: buck voltage: %u, expected vboot: %u\n",
> + svsb->name, buck_volt, opp_vboot);
> + ret = -EPERM;
> + goto init01_finish;
> + }
> +
> + init_completion(&svsb->init_completion);
> + flags = claim_mtk_svs_lock();
> + svs_set_phase(svs, SVSB_PHASE_INIT01);
> + release_mtk_svs_lock(flags);
> + time_left =
> + wait_for_completion_timeout(&svsb->init_completion,
> + msecs_to_jiffies(2000));
> + if (!time_left) {
> + pr_err("%s: init01 completion timeout\n", svsb->name);
> + ret = -EBUSY;
> + goto init01_finish;
> + }
> + }
> +
> +init01_finish:
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> +
> + for (i = 0; i < svsb->opp_count; i++)
> + dev_pm_opp_enable(svsb->dev, svsb->opp_freqs[i]);
> +
> + if (regulator_set_mode(svsb->buck, REGULATOR_MODE_NORMAL))
> + pr_notice("%s: fail to set normal mode: %d\n",
> + svsb->name, ret);
> +
> + if (svsb->mtcmos_request) {
> + if (pm_runtime_put_sync(svsb->dev))
> + pr_err("%s: turn mtcmos off fail: %d\n",
> + svsb->name, ret);
> + pm_runtime_disable(svsb->dev);
> + dev_pm_domain_detach(svsb->dev, 0);
> + if (regulator_disable(svsb->buck))
> + pr_err("%s: fail to disable %s power: %d\n",
> + svsb->name, svsb->buck_name, ret);
> + }
> + }
> +
> + cpu_latency_qos_remove_request(qos_request);
> + kfree(qos_request);
> +
> + return ret;
> +}
> +
> +static int svs_start(struct mtk_svs *svs)
> +{
> + int ret;
> +
> + ret = svs_init01(svs);
> + if (ret)
> + return ret;
> +
> + ret = svs_init02(svs);
> + if (ret)
> + return ret;
> +
> + svs_mon_mode(svs);
> +
> + return ret;
> +}
> +
> +static bool svs_mt8183_efuse_parsing(struct mtk_svs *svs)
> +{
> + const struct svs_platform *svsp = svs->platform;
> + struct thermal_parameter tp;
> + struct svs_bank *svsb;
> + bool mon_mode_support = true;
> + int format[6], x_roomt[6], tb_roomt = 0;
> + struct nvmem_cell *cell;
> + size_t len;
> + u32 idx, i, ft_pgm, mts, temp0, temp1, temp2;
> +
> + if (svsp->fake_efuse) {
> + pr_notice("fake efuse\n");
> + svs->efuse[0] = 0x00310080;
> + svs->efuse[1] = 0xabfbf757;
> + svs->efuse[2] = 0x47c747c7;
> + svs->efuse[3] = 0xabfbf757;
> + svs->efuse[4] = 0xe7fca0ec;
> + svs->efuse[5] = 0x47bf4b88;
> + svs->efuse[6] = 0xabfb8fa5;
> + svs->efuse[7] = 0xabfb217b;
> + svs->efuse[8] = 0x4bf34be1;
> + svs->efuse[9] = 0xabfb670d;
> + svs->efuse[16] = 0xabfbc653;
> + svs->efuse[17] = 0x47f347e1;
> + svs->efuse[18] = 0xabfbd848;
> + }
> +
> + for (i = 0; i < svsp->efuse_num; i++)
> + if (svs->efuse[i])
> + pr_notice("M_HW_RES%d: 0x%08x\n", i, svs->efuse[i]);
> +
> + /* svs efuse parsing */
> + ft_pgm = (svs->efuse[0] >> 4) & GENMASK(3, 0);
> +
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + if (ft_pgm <= 1)
> + svsb->init01_volt_flag = SVSB_INIT01_VOLT_IGNORE;
> +
> + switch (svsb->sw_id) {
> + case SVS_CPU_LITTLE:
> + svsb->bdes = svs->efuse[16] & GENMASK(7, 0);
> + svsb->mdes = (svs->efuse[16] >> 8) & GENMASK(7, 0);
> + svsb->dcbdet = (svs->efuse[16] >> 16) & GENMASK(7, 0);
> + svsb->dcmdet = (svs->efuse[16] >> 24) & GENMASK(7, 0);
> + svsb->mtdes = (svs->efuse[17] >> 16) & GENMASK(7, 0);
> +
> + if (ft_pgm <= 3)
> + svsb->volt_offset += 10;
> + else
> + svsb->volt_offset += 2;
> + break;
> + case SVS_CPU_BIG:
> + svsb->bdes = svs->efuse[18] & GENMASK(7, 0);
> + svsb->mdes = (svs->efuse[18] >> 8) & GENMASK(7, 0);
> + svsb->dcbdet = (svs->efuse[18] >> 16) & GENMASK(7, 0);
> + svsb->dcmdet = (svs->efuse[18] >> 24) & GENMASK(7, 0);
> + svsb->mtdes = svs->efuse[17] & GENMASK(7, 0);
> +
> + if (ft_pgm <= 3)
> + svsb->volt_offset += 15;
> + else
> + svsb->volt_offset += 12;
> + break;
> + case SVS_CCI:
> + svsb->bdes = svs->efuse[4] & GENMASK(7, 0);
> + svsb->mdes = (svs->efuse[4] >> 8) & GENMASK(7, 0);
> + svsb->dcbdet = (svs->efuse[4] >> 16) & GENMASK(7, 0);
> + svsb->dcmdet = (svs->efuse[4] >> 24) & GENMASK(7, 0);
> + svsb->mtdes = (svs->efuse[5] >> 16) & GENMASK(7, 0);
> +
> + if (ft_pgm <= 3)
> + svsb->volt_offset += 10;
> + else
> + svsb->volt_offset += 2;
> + break;
> + case SVS_GPU:
> + svsb->bdes = svs->efuse[6] & GENMASK(7, 0);
> + svsb->mdes = (svs->efuse[6] >> 8) & GENMASK(7, 0);
> + svsb->dcbdet = (svs->efuse[6] >> 16) & GENMASK(7, 0);
> + svsb->dcmdet = (svs->efuse[6] >> 24) & GENMASK(7, 0);
> + svsb->mtdes = svs->efuse[5] & GENMASK(7, 0);
> +
> + if (ft_pgm >= 2) {
> + svsb->freq_base = 800000000; /* 800MHz */
> + svsb->dvt_fixed = 2;
> + }
> + break;
> + default:
> + break;
> + }
> + }
> +
> + if (svsp->fake_efuse) {
> + svs->thermal_efuse[0] = 0x02873f69;
> + svs->thermal_efuse[1] = 0xa11d9142;
> + svs->thermal_efuse[2] = 0xa2526900;
> + } else {
> + /* Get thermal efuse by nvmem */
> + cell = nvmem_cell_get(svs->dev, "calibration-data");
> + if (IS_ERR(cell)) {
> + pr_err("no thermal efuse? disable mon mode\n");
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svsb->mode_support &= ~SVSB_MODE_MON;
> + }
> +
> + return true;
> + }
> +
> + svs->thermal_efuse = (u32 *)nvmem_cell_read(cell, &len);
> + nvmem_cell_put(cell);
> + }
> +
> + /* Thermal efuse parsing */
> + tp.adc_ge_t = (svs->thermal_efuse[1] >> 22) & GENMASK(9, 0);
> + tp.adc_oe_t = (svs->thermal_efuse[1] >> 12) & GENMASK(9, 0);
> +
> + tp.o_vtsmcu1 = (svs->thermal_efuse[0] >> 17) & GENMASK(8, 0);
> + tp.o_vtsmcu2 = (svs->thermal_efuse[0] >> 8) & GENMASK(8, 0);
> + tp.o_vtsmcu3 = svs->thermal_efuse[1] & GENMASK(8, 0);
> + tp.o_vtsmcu4 = (svs->thermal_efuse[2] >> 23) & GENMASK(8, 0);
> + tp.o_vtsmcu5 = (svs->thermal_efuse[2] >> 5) & GENMASK(8, 0);
> + tp.o_vtsabb = (svs->thermal_efuse[2] >> 14) & GENMASK(8, 0);
> +
> + tp.degc_cali = (svs->thermal_efuse[0] >> 1) & GENMASK(5, 0);
> + tp.adc_cali_en_t = svs->thermal_efuse[0] & BIT(0);
> + tp.o_slope_sign = (svs->thermal_efuse[0] >> 7) & BIT(0);
> +
> + tp.ts_id = (svs->thermal_efuse[1] >> 9) & BIT(0);
> + tp.o_slope = (svs->thermal_efuse[0] >> 26) & GENMASK(5, 0);
> +
> + if (tp.adc_cali_en_t == 1) {
> + if (!tp.ts_id)
> + tp.o_slope = 0;
> +
> + if ((tp.adc_ge_t < 265 || tp.adc_ge_t > 758) ||
> + (tp.adc_oe_t < 265 || tp.adc_oe_t > 758) ||
> + (tp.o_vtsmcu1 < -8 || tp.o_vtsmcu1 > 484) ||
> + (tp.o_vtsmcu2 < -8 || tp.o_vtsmcu2 > 484) ||
> + (tp.o_vtsmcu3 < -8 || tp.o_vtsmcu3 > 484) ||
> + (tp.o_vtsmcu4 < -8 || tp.o_vtsmcu4 > 484) ||
> + (tp.o_vtsmcu5 < -8 || tp.o_vtsmcu5 > 484) ||
> + (tp.o_vtsabb < -8 || tp.o_vtsabb > 484) ||
> + (tp.degc_cali < 1 || tp.degc_cali > 63)) {
> + pr_err("bad thermal efuse data, disable mon mode\n");
> + mon_mode_support = false;
> + }
> + } else {
> + pr_err("no thermal efuse data, disable mon mode\n");
> + mon_mode_support = false;
> + }
> +
> + if (!mon_mode_support) {
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svsb->mode_support &= ~SVSB_MODE_MON;
> + }
> +
> + return true;
> + }
> +
> + tp.ge = ((tp.adc_ge_t - 512) * 10000) / 4096;
> + tp.oe = (tp.adc_oe_t - 512);
> + tp.gain = (10000 + tp.ge);
> +
> + format[0] = (tp.o_vtsmcu1 + 3350 - tp.oe);
> + format[1] = (tp.o_vtsmcu2 + 3350 - tp.oe);
> + format[2] = (tp.o_vtsmcu3 + 3350 - tp.oe);
> + format[3] = (tp.o_vtsmcu4 + 3350 - tp.oe);
> + format[4] = (tp.o_vtsmcu5 + 3350 - tp.oe);
> + format[5] = (tp.o_vtsabb + 3350 - tp.oe);
> +
> + for (i = 0; i < 6; i++)
> + x_roomt[i] = (((format[i] * 10000) / 4096) * 10000) / tp.gain;
> +
> + temp0 = (10000 * 100000 / tp.gain) * 15 / 18;
> +
> + if (!tp.o_slope_sign)
> + mts = (temp0 * 10) / (1534 + tp.o_slope * 10);
> + else
> + mts = (temp0 * 10) / (1534 - tp.o_slope * 10);
> +
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svsb->mts = mts;
> +
> + switch (svsb->sw_id) {
> + case SVS_CPU_LITTLE:
> + tb_roomt = x_roomt[3];
> + break;
> + case SVS_CPU_BIG:
> + tb_roomt = x_roomt[4];
> + break;
> + case SVS_CCI:
> + tb_roomt = x_roomt[3];
> + break;
> + case SVS_GPU:
> + tb_roomt = x_roomt[1];
> + break;
> + default:
> + break;
> + }
> +
> + temp0 = (tp.degc_cali * 10 / 2);
> + temp1 = ((10000 * 100000 / 4096 / tp.gain) *
> + tp.oe + tb_roomt * 10) * 15 / 18;
> +
> + if (!tp.o_slope_sign)
> + temp2 = temp1 * 100 / (1534 + tp.o_slope * 10);
> + else
> + temp2 = temp1 * 100 / (1534 - tp.o_slope * 10);
> +
> + svsb->bts = (temp0 + temp2 - 250) * 4 / 10;
> + }
> +
> + return true;
> +}
> +
> +static bool svs_is_supported(struct mtk_svs *svs)
> +{
> + const struct svs_platform *svsp = svs->platform;
> + struct nvmem_cell *cell;
> + size_t len;
> + bool ret;
> +
> + if (svsp->fake_efuse) {
> + len = svsp->efuse_num * sizeof(u32);
> + svs->efuse = devm_kzalloc(svs->dev, len, GFP_KERNEL);
> + if (!svs->efuse) {
> + pr_err("no memory for allocating svs_efuse\n");
> + return false;
> + }
> +
> + len = svsp->thermal_efuse_num * sizeof(u32);
> + svs->thermal_efuse = devm_kzalloc(svs->dev, len, GFP_KERNEL);
> + if (!svs->thermal_efuse) {
> + pr_err("no memory for allocating svs_thermal_efuse\n");
> + return false;
> + }
> +
> + goto svsp_efuse_parsing;
> + }
> +
> + /* Get svs efuse by nvmem */
> + cell = nvmem_cell_get(svs->dev, "svs-calibration-data");
> + if (IS_ERR(cell)) {
> + pr_err("no \"svs-calibration-data\" from dts? disable svs\n");
> + return false;
> + }
> +
> + svs->efuse = (u32 *)nvmem_cell_read(cell, &len);
> + nvmem_cell_put(cell);
> +
> + if (!svs->efuse[svsp->efuse_check]) {
> + pr_err("svs_efuse[%u] = 0x%x?\n",
> + svsp->efuse_check, svs->efuse[svsp->efuse_check]);
> + return false;
> + }
> +
> +svsp_efuse_parsing:
> + ret = svsp->efuse_parsing(svs);
> +
> + return ret;
> +}
> +
> +static int svs_resource_setup(struct mtk_svs *svs)
> +{
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb;
> + struct platform_device *pdev;
> + struct device_node *np = NULL;
> + struct dev_pm_opp *opp;
> + unsigned long freq;
> + int count, ret;
> + u32 idx, i;
> +
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> +
> + switch (svsb->sw_id) {
> + case SVS_CPU_LITTLE:
> + svsb->name = "SVS_CPU_LITTLE";
> + break;
> + case SVS_CPU_BIG:
> + svsb->name = "SVS_CPU_BIG";
> + break;
> + case SVS_CCI:
> + svsb->name = "SVS_CCI";
> + break;
> + case SVS_GPU:
> + svsb->name = "SVS_GPU";
> + break;
> + default:
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + /* Add svs bank device for opp-table/mtcmos/buck control */
> + pdev = platform_device_alloc(svsb->name, 0);
> + if (!pdev) {
> + pr_err("%s: fail to alloc pdev for svs_bank\n",
> + svsb->name);
> + return -ENOMEM;
> + }
> +
> + for_each_child_of_node(svs->dev->of_node, np) {
> + if (of_device_is_compatible(np, svsb->of_compatible)) {
> + pdev->dev.of_node = np;
> + break;
> + }
> + }
> +
> + ret = platform_device_add(pdev);
> + if (ret) {
> + pr_err("%s: fail to add svs_bank device: %d\n",
> + svsb->name, ret);
> + return ret;
> + }
> +
> + svsb->dev = &pdev->dev;
> + dev_set_drvdata(svsb->dev, svs);
> + ret = dev_pm_opp_of_add_table(svsb->dev);
> + if (ret) {
> + pr_err("%s: fail to add opp table: %d\n",
> + svsb->name, ret);
> + return ret;
> + }
> +
> + mutex_init(&svsb->lock);
> +
> + svsb->buck = devm_regulator_get_optional(svsb->dev,
> + svsb->buck_name);
> + if (IS_ERR(svsb->buck)) {
> + pr_err("%s: cannot get regulator \"%s-supply\"\n",
> + svsb->name, svsb->buck_name);
> + return PTR_ERR(svsb->buck);
> + }
> +
> + count = dev_pm_opp_get_opp_count(svsb->dev);
> + if (svsb->opp_count != count) {
> + pr_err("%s: opp_count not \"%u\" but get \"%d\"?\n",
> + svsb->name, svsb->opp_count, count);
> + return count;
> + }
> +
> + for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
> + opp = dev_pm_opp_find_freq_floor(svsb->dev, &freq);
> + if (IS_ERR(opp)) {
> + pr_err("%s: error opp entry!!, err = %ld\n",
> + svsb->name, PTR_ERR(opp));
> + return PTR_ERR(opp);
> + }
> +
> + svsb->opp_freqs[i] = freq;
> + svsb->opp_volts[i] = dev_pm_opp_get_voltage(opp);
> + svsb->freqs_pct[i] = percent(svsb->opp_freqs[i],
> + svsb->freq_base);
> + dev_pm_opp_put(opp);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int svs_suspend(struct device *dev)
> +{
> + struct mtk_svs *svs = dev_get_drvdata(dev);
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb;
> + unsigned long flags;
> + int ret;
> + u32 idx;
> +
> + /* Wait if there is processing svs_isr(). Suspend all banks. */
> + flags = claim_mtk_svs_lock();
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svs->bank = svsb;
> + svs_switch_bank(svs);
> + svs_writel(svs, SVSEN_OFF, SVSEN);
> + svs_writel(svs, INTSTS_CLEAN, INTSTS);
> + svsb->suspended = true;
> + }
> + release_mtk_svs_lock(flags);
> +
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + if (svsb->phase != SVSB_PHASE_INIT01) {
> + svsb->phase = SVSB_PHASE_ERROR;
> + svsb_set_volts(svsb, true);
> + }
> + }
> +
> + if (svsp->need_hw_reset) {
> + ret = device_reset(svs->dev);
> + if (ret) {
> + pr_err("%s: ret = %d\n", __func__, ret);
> + return ret;
> + }
> + }
> +
> + clk_disable_unprepare(svs->main_clk);
> +
> + return 0;
> +}
> +
> +static int svs_resume(struct device *dev)
> +{
> + struct mtk_svs *svs = dev_get_drvdata(dev);
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb;
> + int ret;
> + u32 idx;
> +
> + ret = clk_prepare_enable(svs->main_clk);
> + if (ret) {
> + pr_err("cannot enable main_clk, disable svs\n");
> + return ret;
> + }
> +
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> + svsb->suspended = false;
> + }
> +
> + ret = svs_init02(svs);
> + if (ret)
> + return ret;
> +
> + svs_mon_mode(svs);
> +
> + return 0;
> +}
> +
> +static int svs_debug_proc_show(struct seq_file *m, void *v)
> +{
> + struct svs_bank *svsb = (struct svs_bank *)m->private;
> +
> + if (svsb->phase == SVSB_PHASE_INIT01)
> + seq_puts(m, "init1\n");
> + else if (svsb->phase == SVSB_PHASE_INIT02)
> + seq_puts(m, "init2\n");
> + else if (svsb->phase == SVSB_PHASE_MON)
> + seq_puts(m, "mon mode\n");
> + else if (svsb->phase == SVSB_PHASE_ERROR)
> + seq_puts(m, "disabled\n");
> + else
> + seq_puts(m, "unknown\n");
> +
> + return 0;
> +}
> +
> +static ssize_t svs_debug_proc_write(struct file *file,
> + const char __user *buffer,
> + size_t count, loff_t *pos)
> +{
> + struct svs_bank *svsb = (struct svs_bank *)PDE_DATA(file_inode(file));
> + struct mtk_svs *svs = dev_get_drvdata(svsb->dev);
> + unsigned long flags;
> + int enabled, ret;
> + char *buf = NULL;
> +
> + if (count >= PAGE_SIZE)
> + return -EINVAL;
> +
> + buf = (char *)memdup_user_nul(buffer, count);
> + if (IS_ERR(buf))
> + return PTR_ERR(buf);
> +
> + ret = kstrtoint(buf, 10, &enabled);
> + if (ret)
> + return ret;
> +
> + if (!enabled) {
> + flags = claim_mtk_svs_lock();
> + svs->bank = svsb;
> + svsb->mode_support = SVSB_MODE_ALL_DISABLE;
> + svs_switch_bank(svs);
> + svs_writel(svs, SVSEN_OFF, SVSEN);
> + svs_writel(svs, INTSTS_CLEAN, INTSTS);
> + release_mtk_svs_lock(flags);
> +
> + svsb->phase = SVSB_PHASE_ERROR;
> + svsb_set_volts(svsb, true);
> + }
> +
> + kfree(buf);
> +
> + return count;
> +}
> +
> +proc_fops_rw(svs_debug);
> +
> +static int svs_dump_proc_show(struct seq_file *m, void *v)
> +{
> + struct mtk_svs *svs = (struct mtk_svs *)m->private;
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb;
> + unsigned long svs_reg_addr;
> + u32 idx, i, j;
> +
> + for (i = 0; i < svsp->efuse_num; i++)
> + if (svs->efuse && svs->efuse[i])
> + seq_printf(m, "M_HW_RES%d = 0x%08x\n",
> + i, svs->efuse[i]);
> +
> + for (i = 0; i < svsp->thermal_efuse_num; i++)
> + if (svs->thermal_efuse)
> + seq_printf(m, "THERMAL_EFUSE%d = 0x%08x\n",
> + i, svs->thermal_efuse[i]);
> +
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> +
> + for (i = SVSB_PHASE_INIT01; i <= SVSB_PHASE_MON; i++) {
> + seq_printf(m, "Bank_number = %u\n", svsb->bank_id);
> +
> + if (i < SVSB_PHASE_MON)
> + seq_printf(m, "mode = init%d\n", i + 1);
> + else
> + seq_puts(m, "mode = mon\n");
> +
> + for (j = TEMPMONCTL0; j < reg_num; j++) {
> + svs_reg_addr = (unsigned long)(svs->base +
> + svsp->regs[j]);
> + seq_printf(m, "0x%08lx = 0x%08x\n",
> + svs_reg_addr, svsb->reg_data[i][j]);
> + }
> + }
> + }
> +
> + return 0;
> +}
> +
> +proc_fops_ro(svs_dump);
> +
> +static int svs_status_proc_show(struct seq_file *m, void *v)
> +{
> + struct svs_bank *svsb = (struct svs_bank *)m->private;
> + struct dev_pm_opp *opp;
> + unsigned long freq;
> + int tzone_temp, ret;
> + u32 i;
> +
> + ret = svsb_get_zone_temperature(svsb, &tzone_temp);
> + if (ret)
> + seq_printf(m, "%s: cannot get zone \"%s\" temperature\n",
> + svsb->name, svsb->tzone_name);
> + else
> + seq_printf(m, "%s: temperature = %d\n", svsb->name, tzone_temp);
> +
> + for (i = 0, freq = U32_MAX; i < svsb->opp_count; i++, freq--) {
> + opp = dev_pm_opp_find_freq_floor(svsb->dev, &freq);
> + if (IS_ERR(opp)) {
> + seq_printf(m, "%s: error opp entry!!, err = %ld\n",
> + svsb->name, PTR_ERR(opp));
> + return PTR_ERR(opp);
> + }
> +
> + seq_printf(m, "opp_freqs[%02u]: %lu, volts[%02u]: %lu, ",
> + i, freq, i, dev_pm_opp_get_voltage(opp));
> + seq_printf(m, "svsb_volts[%02u]: 0x%x, freqs_pct[%02u]: %u\n",
> + i, svsb->volts[i], i, svsb->freqs_pct[i]);
> + dev_pm_opp_put(opp);
> + }
> +
> + return 0;
> +}
> +
> +proc_fops_ro(svs_status);
> +
> +static int svs_volt_offset_proc_show(struct seq_file *m, void *v)
> +{
> + struct svs_bank *svsb = (struct svs_bank *)m->private;
> +
> + seq_printf(m, "%d\n", svsb->volt_offset);
> +
> + return 0;
> +}
> +
> +static ssize_t svs_volt_offset_proc_write(struct file *file,
> + const char __user *buffer,
> + size_t count, loff_t *pos)
> +{
> + struct svs_bank *svsb = (struct svs_bank *)PDE_DATA(file_inode(file));
> + char *buf = NULL;
> + s32 volt_offset;
> +
> + if (count >= PAGE_SIZE)
> + return -EINVAL;
> +
> + buf = (char *)memdup_user_nul(buffer, count);
> + if (IS_ERR(buf))
> + return PTR_ERR(buf);
> +
> + if (!kstrtoint(buf, 10, &volt_offset)) {
> + svsb->volt_offset = volt_offset;
> + svsb_set_volts(svsb, true);
> + }
> +
> + kfree(buf);
> +
> + return count;
> +}
> +
> +proc_fops_rw(svs_volt_offset);
> +
> +static int svs_create_svs_procfs(struct mtk_svs *svs)
> +{
> + const struct svs_platform *svsp = svs->platform;
> + struct svs_bank *svsb;
> + struct proc_dir_entry *svs_dir, *bank_dir;
> + u32 idx, i;
> +
> + struct pentry {
> + const char *name;
> + const struct proc_ops *fops;
> + };
> +
> + struct pentry svs_entries[] = {
> + proc_entry(svs_dump),
> + };
> +
> + struct pentry bank_entries[] = {
> + proc_entry(svs_debug),
> + proc_entry(svs_status),
> + proc_entry(svs_volt_offset),
> + };
> +
> + svs_dir = proc_mkdir("svs", NULL);
> + if (!svs_dir) {
> + pr_err("mkdir /proc/svs failed\n");
> + return -EPERM;
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(svs_entries); i++) {
> + if (!proc_create_data(svs_entries[i].name, 0664,
> + svs_dir, svs_entries[i].fops, svs)) {
> + pr_err("create /proc/svs/%s failed\n",
> + svs_entries[i].name);
> + return -EPERM;
> + }
> + }
> +
> + for (idx = 0; idx < svsp->bank_num; idx++) {
> + svsb = &svsp->banks[idx];
> +
> + if (svsb->mode_support == SVSB_MODE_ALL_DISABLE)
> + continue;
> +
> + bank_dir = proc_mkdir(svsb->name, svs_dir);
> + if (!bank_dir) {
> + pr_err("mkdir /proc/svs/%s failed\n", svsb->name);
> + return -EPERM;
> + }
> +
> + for (i = 0; i < ARRAY_SIZE(bank_entries); i++) {
> + if (!proc_create_data(bank_entries[i].name, 0664,
> + bank_dir, bank_entries[i].fops,
> + svsb)) {
> + pr_err("create /proc/svs/%s/%s failed\n",
> + svsb->name, bank_entries[i].name);
> + return -EPERM;
> + }
> + }
> + }
> +
> + return 0;
> +}
> +
> +static struct svs_bank_ops svs_mt8183_banks_ops = {
> + .set_freqs_pct = svs_set_freqs_pct_v2,
> + .get_vops = svs_get_vops_v2,
> +};
> +
> +static struct svs_bank svs_mt8183_banks[4] = {
> + {
> + .of_compatible = "mediatek,mt8183-svs-cpu-little",
> + .sw_id = SVS_CPU_LITTLE,
> + .bank_id = 0,
> + .ops = &svs_mt8183_banks_ops,
> + .tzone_name = "tzts4",
> + .buck_name = "vcpu-little",
> + .mtcmos_request = false,
> + .init01_volt_flag = SVSB_INIT01_VOLT_INC_ONLY,
> + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> + .opp_count = 16,
> + .freq_base = 1989000000,
> + .vboot = 0x30,
> + .volt_step = 6250,
> + .volt_base = 500000,
> + .volt_offset = 0,
> + .vmax = 0x64,
> + .vmin = 0x18,
> + .dthi = 0x1,
> + .dtlo = 0xfe,
> + .det_window = 0xa28,
> + .det_max = 0xffff,
> + .age_config = 0x555555,
> + .agem = 0,
> + .dc_config = 0x555555,
> + .dvt_fixed = 0x7,
> + .vco = 0x10,
> + .chk_shift = 0x77,
> + .upper_temp_bound = 0x64,
> + .lower_temp_bound = 0xb2,
> + .high_temp_threashold = HIGH_TEMP_MAX,
> + .low_temp_threashold = 25000,
> + .low_temp_offset = 0,
> + .core_sel = 0x8fff0000,
> + .systemclk_en = BIT(31),
> + .int_st = BIT(0),
> + .ctl0 = 0x00010001,
> + },
> + {
> + .of_compatible = "mediatek,mt8183-svs-cpu-big",
> + .sw_id = SVS_CPU_BIG,
> + .bank_id = 1,
> + .ops = &svs_mt8183_banks_ops,
> + .tzone_name = "tzts5",
> + .buck_name = "vcpu-big",
> + .mtcmos_request = false,
> + .init01_volt_flag = SVSB_INIT01_VOLT_INC_ONLY,
> + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> + .opp_count = 16,
> + .freq_base = 1989000000,
> + .vboot = 0x30,
> + .volt_step = 6250,
> + .volt_base = 500000,
> + .volt_offset = 0,
> + .vmax = 0x58,
> + .vmin = 0x10,
> + .dthi = 0x1,
> + .dtlo = 0xfe,
> + .det_window = 0xa28,
> + .det_max = 0xffff,
> + .age_config = 0x555555,
> + .agem = 0,
> + .dc_config = 0x555555,
> + .dvt_fixed = 0x7,
> + .vco = 0x10,
> + .chk_shift = 0x77,
> + .upper_temp_bound = 0x64,
> + .lower_temp_bound = 0xb2,
> + .high_temp_threashold = HIGH_TEMP_MAX,
> + .low_temp_threashold = 25000,
> + .low_temp_offset = 0,
> + .core_sel = 0x8fff0001,
> + .systemclk_en = BIT(31),
> + .int_st = BIT(1),
> + .ctl0 = 0x00000001,
> + },
> + {
> + .of_compatible = "mediatek,mt8183-svs-cci",
> + .sw_id = SVS_CCI,
> + .bank_id = 2,
> + .ops = &svs_mt8183_banks_ops,
> + .tzone_name = "tzts4",
> + .buck_name = "vcci",
> + .mtcmos_request = false,
> + .init01_volt_flag = SVSB_INIT01_VOLT_INC_ONLY,
> + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02,
> + .opp_count = 16,
> + .freq_base = 1196000000,
> + .vboot = 0x30,
> + .volt_step = 6250,
> + .volt_base = 500000,
> + .volt_offset = 0,
> + .vmax = 0x64,
> + .vmin = 0x18,
> + .dthi = 0x1,
> + .dtlo = 0xfe,
> + .det_window = 0xa28,
> + .det_max = 0xffff,
> + .age_config = 0x555555,
> + .agem = 0,
> + .dc_config = 0x555555,
> + .dvt_fixed = 0x7,
> + .vco = 0x10,
> + .chk_shift = 0x77,
> + .upper_temp_bound = 0x64,
> + .lower_temp_bound = 0xb2,
> + .high_temp_threashold = HIGH_TEMP_MAX,
> + .low_temp_threashold = 25000,
> + .low_temp_offset = 0,
> + .core_sel = 0x8fff0002,
> + .systemclk_en = BIT(31),
> + .int_st = BIT(2),
> + .ctl0 = 0x00100003,
> + },
> + {
> + .of_compatible = "mediatek,mt8183-svs-gpu",
> + .sw_id = SVS_GPU,
> + .bank_id = 3,
> + .ops = &svs_mt8183_banks_ops,
> + .tzone_name = "tzts2",
> + .buck_name = "vgpu",
> + .mtcmos_request = true,
> + .init01_volt_flag = SVSB_INIT01_VOLT_INC_ONLY,
> + .mode_support = SVSB_MODE_INIT01 | SVSB_MODE_INIT02 |
> + SVSB_MODE_MON,
> + .opp_count = 16,
> + .freq_base = 900000000,
> + .vboot = 0x30,
> + .volt_step = 6250,
> + .volt_base = 500000,
> + .volt_offset = 0,
> + .vmax = 0x40,
> + .vmin = 0x14,
> + .dthi = 0x1,
> + .dtlo = 0xfe,
> + .det_window = 0xa28,
> + .det_max = 0xffff,
> + .age_config = 0x555555,
> + .agem = 0,
> + .dc_config = 0x555555,
> + .dvt_fixed = 0x3,
> + .vco = 0x10,
> + .chk_shift = 0x77,
> + .upper_temp_bound = 0x64,
> + .lower_temp_bound = 0xb2,
> + .high_temp_threashold = HIGH_TEMP_MAX,
> + .low_temp_threashold = 25000,
> + .low_temp_offset = 3,
> + .core_sel = 0x8fff0003,
> + .systemclk_en = BIT(31),
> + .int_st = BIT(3),
> + .ctl0 = 0x00050001,
> + },
> +};
> +
> +static const struct svs_platform svs_mt8183_platform = {
> + .name = "mt8183-svs",
> + .banks = svs_mt8183_banks,
> + .efuse_parsing = svs_mt8183_efuse_parsing,
> + .regs = svs_regs_v2,
> + .irqflags = IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> + .need_hw_reset = false,
> + .fake_efuse = false,
> + .bank_num = 4,
> + .efuse_num = 25,
> + .efuse_check = 2,
> + .thermal_efuse_num = 3,
> +};
> +
> +static const struct of_device_id mtk_svs_of_match[] = {
> + {
> + .compatible = "mediatek,mt8183-svs",
> + .data = &svs_mt8183_platform,
> + }, {
> + /* Sentinel */
> + },
> +};
> +
> +static int svs_add_thermal_device_link(struct platform_device *svs_pdev)
> +{
> + struct device_node *therm_node;
> + struct platform_device *therm_pdev;
> + struct device_link *sup_link;
> + char const *therm_node_name[] = {"thermal"};
> + u32 i;
> +
> + for (i = 0; i < ARRAY_SIZE(therm_node_name); i++) {
> + therm_node = of_find_node_by_name(NULL, therm_node_name[i]);
> + if (therm_node)
> + break;
> + }
> +
> + if (!therm_node) {
> + pr_err("no available thermal node? pass device link\n");
> + return 0;
> + }
> +
> + therm_pdev = of_find_device_by_node(therm_node);
> + if (!therm_pdev) {
> + pr_err("no \"%pOF\" platform device? pass device link\n",
> + therm_node);
> + of_node_put(therm_node);
> + return 0;
> + }
> +
> + of_node_put(therm_node);
> +
> + sup_link = device_link_add(&svs_pdev->dev, &therm_pdev->dev,
> + DL_FLAG_AUTOREMOVE_CONSUMER);
> +
> + if (sup_link->status == DL_STATE_DORMANT)
> + return -EPROBE_DEFER;
> +
> + return 0;
> +}
> +
> +static int svs_probe(struct platform_device *pdev)
> +{
> + const struct of_device_id *of_dev_id;
> + struct mtk_svs *svs;
> + int ret;
> + u32 svs_irq;
> +
> + ret = svs_add_thermal_device_link(pdev);
> + if (ret)
> + return ret;
> +
> + svs = devm_kzalloc(&pdev->dev, sizeof(*svs), GFP_KERNEL);
> + if (!svs)
> + return -ENOMEM;
> +
> + svs->dev = &pdev->dev;
> + if (!svs->dev->of_node) {
> + pr_err("cannot find device node\n");
> + return -ENODEV;
> + }
> +
> + svs->base = of_iomap(svs->dev->of_node, 0);
> + if (IS_ERR(svs->base)) {
> + pr_err("cannot find svs register base\n");
> + return PTR_ERR(svs->base);
> + }
> +
> + of_dev_id = of_match_node(mtk_svs_of_match, svs->dev->of_node);
> + if (!of_dev_id || !of_dev_id->data)
> + return -EINVAL;
> +
> + svs->platform = of_dev_id->data;
> + dev_set_drvdata(svs->dev, svs);
> +
> + svs_irq = irq_of_parse_and_map(svs->dev->of_node, 0);
> + ret = devm_request_threaded_irq(svs->dev, svs_irq, NULL, svs_isr,
> + svs->platform->irqflags, "mtk-svs",
> + svs);
> + if (ret) {
> + pr_err("register irq(%d) failed: %d\n", svs_irq, ret);
> + return ret;
> + }
> +
> + svs->main_clk = devm_clk_get(svs->dev, "main");
> + if (IS_ERR(svs->main_clk)) {
> + pr_err("failed to get clock: %ld\n", PTR_ERR(svs->main_clk));
> + return PTR_ERR(svs->main_clk);
> + }
> +
> + ret = clk_prepare_enable(svs->main_clk);
> + if (ret) {
> + pr_err("cannot enable main clk: %d\n", ret);
> + return ret;
> + }
> +
> + if (!svs_is_supported(svs)) {
> + pr_notice("svs is not supported\n");
> + ret = -EPERM;
> + goto svs_probe_fail;
> + }
> +
> + ret = svs_resource_setup(svs);
> + if (ret)
> + goto svs_probe_fail;
> +
> + ret = svs_start(svs);
> + if (ret)
> + goto svs_probe_fail;
> +
> + ret = svs_create_svs_procfs(svs);
> + if (ret)
> + goto svs_probe_fail;
> +
> + return 0;
> +
> +svs_probe_fail:
> + clk_disable_unprepare(svs->main_clk);
> +
> + return ret;
> +}
> +
> +static const struct dev_pm_ops svs_pm_ops = {
> + .suspend = svs_suspend,
> + .resume = svs_resume,
> +};
Better use the PM macros to define that struct
> +
> +static struct platform_driver svs_driver = {
> + .probe = svs_probe,
> + .driver = {
> + .name = "mtk-svs",
> + .pm = &svs_pm_ops,
> + .of_match_table = of_match_ptr(mtk_svs_of_match),
> + },
> +};
> +
> +static int __init svs_init(void)
> +{
> + int ret;
> +
> + ret = platform_driver_register(&svs_driver);
> + if (ret) {
> + pr_err("svs platform driver register failed: %d\n", ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +late_initcall_sync(svs_init);
Why? Can't be this a module_platform_driver?
> +
> +MODULE_DESCRIPTION("MediaTek SVS Driver v1.0");
Don't put the version in the description, there is a MODULE_VERSION
for that purpose.
Also would be good have the MODULE_AUTHOR
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/power/mtk_svs.h b/include/linux/power/mtk_svs.h
> new file mode 100644
> index 000000000000..5c03982e3576
> --- /dev/null
> +++ b/include/linux/power/mtk_svs.h
I don't think this file is needed just remove it.
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * Copyright (C) 2020 MediaTek Inc.
> + */
> +
> +#ifndef __MTK_SVS_H__
> +#define __MTK_SVS_H__
> +
> +#if IS_ENABLED(CONFIG_MTK_SVS)
> +unsigned long claim_mtk_svs_lock(void);
> +void release_mtk_svs_lock(unsigned long flags);
> +#else
> +static inline unsigned long claim_mtk_svs_lock(void)
> +{
> + return 0;
> +}
> +
> +static inline void release_mtk_svs_lock(unsigned long flags)
> +{
> +}
> +#endif /* CONFIG_MTK_SVS */
> +
> +#endif /* __MTK_SVS_H__ */
> --
> 2.18.0
> _______________________________________________
> Linux-mediatek mailing list
> Linux-mediatek@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-mediatek
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 2/2] ARM: Allow either FLATMEM or SPARSEMEM on the multiplatform build
From: Arnd Bergmann @ 2020-05-19 15:32 UTC (permalink / raw)
To: Mike Rapoport
Cc: Doug Berger, Stephen Boyd, Kevin Cernekee,
Russell King - ARM Linux admin, Florian Fainelli, Gregory Fong,
Linux ARM
In-Reply-To: <20200519152714.GF1059226@linux.ibm.com>
On Tue, May 19, 2020 at 5:27 PM Mike Rapoport <rppt@linux.ibm.com> wrote:
> On Tue, May 19, 2020 at 04:04:52PM +0100, Russell King - ARM Linux admin wrote:
> > There are cases where the reason to use sparsemem is not an optional
> > one but is out of necessity - they require the page array to be split
> > up in order to boot successfully.
> >
> > With that in mind, flatmem becomes an "optimisation" over sparsemem.
>
> At the moment, there are three platforms that enable SPARSEMEM: ARCH_EP93XX,
> ARCH_RPC and ARCH_SA1100. All the rest have FLATMEM implcitly selected.
>
> I do not intend to change that, I am only going add an ability to select
> the memory model for ARCH_MULTIPLATFORM.
>
> I'll respin the series on the list before adding the patches to the
> patch system.
I think we'll make EP93xx part of multiplatform at some point, IIRC
only the missing clock driver is stopping us at the moment, and I already
discussed with Linus Walleij how that can be done.
My guess is that ep93xx is one platform on which sparsemem is
just an optimization to reduce the initial memory consumption, but
we should verify that when we get there.
Arnd
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 1/3] arm64: vdso: Don't prefix sigreturn trampoline with a BTI C instruction
From: Mark Brown @ 2020-05-19 15:42 UTC (permalink / raw)
To: Dave Martin
Cc: Tamas Zsoldos, Will Deacon, kernel-team, linux-arm-kernel,
Daniel Kiss
In-Reply-To: <20200519145514.GH5031@arm.com>
[-- Attachment #1.1: Type: text/plain, Size: 1172 bytes --]
On Tue, May 19, 2020 at 03:55:15PM +0100, Dave Martin wrote:
> On Tue, May 19, 2020 at 03:35:00PM +0100, Mark Brown wrote:
> > On Tue, May 19, 2020 at 02:25:38PM +0100, Dave Martin wrote:
> > > Rather, the "ret lr" that jumps here is supposed to be authenticated via
> > > pointer auth in the caller.
> > In which case there was an issue anyway...
> What issue?
None, I was confused.
> > > If BTI {nothing} allows this while disallowing all BR/BLR then we could
> > > use that (I can't remember what BTI {nothing} is useful for, if anything).
> > > Otherwise, it's less clear what we should have here.
> > I can't remember anything that distinguishes it from an explicit NOP.
> I think it rejects everything other then fallthrough execution
> (BTYPE==0, which includes RET). I might have misunderstood something
Right, but since BTI only generates an exception when BTYPE != 0 I'm
having trouble differentiating this from a NOP in practical terms.
> somewhere, but sort of feels like the right thing here. I never put a
> lot of effort into trying to understand BTI {nothing} though. It
> seemed a weird, possibly useless special case.
That was my read too.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] firmware: arm_sdei: remove unused interfaces
From: James Morse @ 2020-05-19 15:47 UTC (permalink / raw)
To: Xiongfeng Wang, Christoph Hellwig; +Cc: linux-kernel, linux-arm-kernel
In-Reply-To: <6d0adc02-bcd8-2217-c145-d609528fbe77@huawei.com>
Hi Xiongfeng,
On 05/05/2020 03:08, Xiongfeng Wang wrote:
> On 2020/5/5 1:14, James Morse wrote:
>> Hi Christoph,
>>
>> (CC: +Xiongfeng)
>>
>> Thanks for the reminder - I was just searching for who was using this.
>
> Thanks for CC me. We do have a driver that are using it.
>> On 04/05/2020 17:42, Christoph Hellwig wrote:
>>> The export symbols to register/unregister and enable/disable events
>>> aren't ever used outside of arm_sdei.c, so mark them static.
>>
>> Xiongfeng, you have drivers using this, could they be posted upstream. Or can we stop
>> exporting these?
>
> It's the SDEI Wathchdog which is used for hardlockup detection. But I wasn't
> able to push it upstream because we have Pseudo-NMI in mainline.
Hmm, that shouldn't be directly relevant, unless your SDEI watchdog is using the
bindable-irq thing?
If your firmware offers an event-id for the watchdog, please upstream the driver. Half of
the event-id space is reserved for vendor stuff like this.
If firmware needs to be told to re-configure the watchdog irq to make this work, then pNMI
is a much better fit. Having firmware and linux modifying the irqchip hardware is a
nightmare best avoided.
>> (they were originally added for the GHES RAS thing, but by the time it was all merged
>> upstream, it wasn't possible to build it as a module)
>
> The SDEI Watchdog driver also can't be built as a module. We still need to
> modify the origin kernel. So I think this patch doesn't affect me. Thanks for CC me.
Okay, I'll pick this up to drop the module exports.
I'd prefer not to make all this static as these register/unregister calls are the
interface that is supposed to be used. If we are going to gut it, we should do it completely.
Thanks,
James
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 1/4] rcu/kasan: record and print call_rcu() call stack
From: Paul E. McKenney @ 2020-05-19 15:48 UTC (permalink / raw)
To: Walter Wu
Cc: wsd_upstream, linux-mm, Lai Jiangshan, Josh Triplett, kasan-dev,
linux-kernel, Joel Fernandes, linux-mediatek, Alexander Potapenko,
linux-arm-kernel, Matthias Brugger, Andrey Ryabinin,
Andrew Morton, Dmitry Vyukov, Mathieu Desnoyers
In-Reply-To: <20200519022359.24115-1-walter-zh.wu@mediatek.com>
On Tue, May 19, 2020 at 10:23:59AM +0800, Walter Wu wrote:
> This feature will record the last two call_rcu() call stacks and
> prints up to 2 call_rcu() call stacks in KASAN report.
>
> When call_rcu() is called, we store the call_rcu() call stack into
> slub alloc meta-data, so that the KASAN report can print rcu stack.
>
> [1]https://bugzilla.kernel.org/show_bug.cgi?id=198437
> [2]https://groups.google.com/forum/#!searchin/kasan-dev/better$20stack$20traces$20for$20rcu%7Csort:date/kasan-dev/KQsjT_88hDE/7rNUZprRBgAJ
>
> Signed-off-by: Walter Wu <walter-zh.wu@mediatek.com>
> Suggested-by: Dmitry Vyukov <dvyukov@google.com>
> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
> Cc: Dmitry Vyukov <dvyukov@google.com>
> Cc: Alexander Potapenko <glider@google.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Paul E. McKenney <paulmck@kernel.org>
> Cc: Josh Triplett <josh@joshtriplett.org>
> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: Lai Jiangshan <jiangshanlai@gmail.com>
> Cc: Joel Fernandes <joel@joelfernandes.org>
From an RCU perspective:
Acked-by: Paul E. McKenney <paulmck@kernel.org>
> ---
> include/linux/kasan.h | 2 ++
> kernel/rcu/tree.c | 2 ++
> lib/Kconfig.kasan | 2 ++
> mm/kasan/common.c | 4 ++--
> mm/kasan/generic.c | 19 +++++++++++++++++++
> mm/kasan/kasan.h | 10 ++++++++++
> mm/kasan/report.c | 24 ++++++++++++++++++++++++
> 7 files changed, 61 insertions(+), 2 deletions(-)
>
> diff --git a/include/linux/kasan.h b/include/linux/kasan.h
> index 31314ca7c635..23b7ee00572d 100644
> --- a/include/linux/kasan.h
> +++ b/include/linux/kasan.h
> @@ -174,11 +174,13 @@ static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; }
>
> void kasan_cache_shrink(struct kmem_cache *cache);
> void kasan_cache_shutdown(struct kmem_cache *cache);
> +void kasan_record_aux_stack(void *ptr);
>
> #else /* CONFIG_KASAN_GENERIC */
>
> static inline void kasan_cache_shrink(struct kmem_cache *cache) {}
> static inline void kasan_cache_shutdown(struct kmem_cache *cache) {}
> +static inline void kasan_record_aux_stack(void *ptr) {}
>
> #endif /* CONFIG_KASAN_GENERIC */
>
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index 06548e2ebb72..36a4ff7f320b 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -57,6 +57,7 @@
> #include <linux/slab.h>
> #include <linux/sched/isolation.h>
> #include <linux/sched/clock.h>
> +#include <linux/kasan.h>
> #include "../time/tick-internal.h"
>
> #include "tree.h"
> @@ -2668,6 +2669,7 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func)
> head->func = func;
> head->next = NULL;
> local_irq_save(flags);
> + kasan_record_aux_stack(head);
> rdp = this_cpu_ptr(&rcu_data);
>
> /* Add the callback to our list. */
> diff --git a/lib/Kconfig.kasan b/lib/Kconfig.kasan
> index 81f5464ea9e1..4e83cf6e3caa 100644
> --- a/lib/Kconfig.kasan
> +++ b/lib/Kconfig.kasan
> @@ -58,6 +58,8 @@ config KASAN_GENERIC
> For better error detection enable CONFIG_STACKTRACE.
> Currently CONFIG_KASAN_GENERIC doesn't work with CONFIG_DEBUG_SLAB
> (the resulting kernel does not boot).
> + In generic mode KASAN prints the last two call_rcu() call stacks in
> + reports.
>
> config KASAN_SW_TAGS
> bool "Software tag-based mode"
> diff --git a/mm/kasan/common.c b/mm/kasan/common.c
> index 2906358e42f0..8bc618289bb1 100644
> --- a/mm/kasan/common.c
> +++ b/mm/kasan/common.c
> @@ -41,7 +41,7 @@
> #include "kasan.h"
> #include "../slab.h"
>
> -static inline depot_stack_handle_t save_stack(gfp_t flags)
> +depot_stack_handle_t kasan_save_stack(gfp_t flags)
> {
> unsigned long entries[KASAN_STACK_DEPTH];
> unsigned int nr_entries;
> @@ -54,7 +54,7 @@ static inline depot_stack_handle_t save_stack(gfp_t flags)
> static inline void set_track(struct kasan_track *track, gfp_t flags)
> {
> track->pid = current->pid;
> - track->stack = save_stack(flags);
> + track->stack = kasan_save_stack(flags);
> }
>
> void kasan_enable_current(void)
> diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
> index 56ff8885fe2e..3372bdcaf92a 100644
> --- a/mm/kasan/generic.c
> +++ b/mm/kasan/generic.c
> @@ -325,3 +325,22 @@ DEFINE_ASAN_SET_SHADOW(f2);
> DEFINE_ASAN_SET_SHADOW(f3);
> DEFINE_ASAN_SET_SHADOW(f5);
> DEFINE_ASAN_SET_SHADOW(f8);
> +
> +void kasan_record_aux_stack(void *addr)
> +{
> + struct page *page = kasan_addr_to_page(addr);
> + struct kmem_cache *cache;
> + struct kasan_alloc_meta *alloc_info;
> + void *object;
> +
> + if (!(page && PageSlab(page)))
> + return;
> +
> + cache = page->slab_cache;
> + object = nearest_obj(cache, page, addr);
> + alloc_info = get_alloc_info(cache, object);
> +
> + /* record the last two call_rcu() call stacks */
> + alloc_info->aux_stack[1] = alloc_info->aux_stack[0];
> + alloc_info->aux_stack[0] = kasan_save_stack(GFP_NOWAIT);
> +}
> diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h
> index e8f37199d885..a7391bc83070 100644
> --- a/mm/kasan/kasan.h
> +++ b/mm/kasan/kasan.h
> @@ -104,7 +104,15 @@ struct kasan_track {
>
> struct kasan_alloc_meta {
> struct kasan_track alloc_track;
> +#ifdef CONFIG_KASAN_GENERIC
> + /*
> + * call_rcu() call stack is stored into struct kasan_alloc_meta.
> + * The free stack is stored into struct kasan_free_meta.
> + */
> + depot_stack_handle_t aux_stack[2];
> +#else
> struct kasan_track free_track[KASAN_NR_FREE_STACKS];
> +#endif
> #ifdef CONFIG_KASAN_SW_TAGS_IDENTIFY
> u8 free_pointer_tag[KASAN_NR_FREE_STACKS];
> u8 free_track_idx;
> @@ -159,6 +167,8 @@ void kasan_report_invalid_free(void *object, unsigned long ip);
>
> struct page *kasan_addr_to_page(const void *addr);
>
> +depot_stack_handle_t kasan_save_stack(gfp_t flags);
> +
> #if defined(CONFIG_KASAN_GENERIC) && \
> (defined(CONFIG_SLAB) || defined(CONFIG_SLUB))
> void quarantine_put(struct kasan_free_meta *info, struct kmem_cache *cache);
> diff --git a/mm/kasan/report.c b/mm/kasan/report.c
> index 80f23c9da6b0..6f8f2bf8f53b 100644
> --- a/mm/kasan/report.c
> +++ b/mm/kasan/report.c
> @@ -179,6 +179,17 @@ static struct kasan_track *kasan_get_free_track(struct kmem_cache *cache,
> return &alloc_meta->free_track[i];
> }
>
> +#ifdef CONFIG_KASAN_GENERIC
> +static void print_stack(depot_stack_handle_t stack)
> +{
> + unsigned long *entries;
> + unsigned int nr_entries;
> +
> + nr_entries = stack_depot_fetch(stack, &entries);
> + stack_trace_print(entries, nr_entries, 0);
> +}
> +#endif
> +
> static void describe_object(struct kmem_cache *cache, void *object,
> const void *addr, u8 tag)
> {
> @@ -192,6 +203,19 @@ static void describe_object(struct kmem_cache *cache, void *object,
> free_track = kasan_get_free_track(cache, object, tag);
> print_track(free_track, "Freed");
> pr_err("\n");
> +
> +#ifdef CONFIG_KASAN_GENERIC
> + if (alloc_info->aux_stack[0]) {
> + pr_err("Last one call_rcu() call stack:\n");
> + print_stack(alloc_info->aux_stack[0]);
> + pr_err("\n");
> + }
> + if (alloc_info->aux_stack[1]) {
> + pr_err("Second to last call_rcu() call stack:\n");
> + print_stack(alloc_info->aux_stack[1]);
> + pr_err("\n");
> + }
> +#endif
> }
>
> describe_object_addr(cache, object, addr);
> --
> 2.18.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] clocksource/drivers/timer-ti-dm: Fix warning for set but not used
From: Tony Lindgren @ 2020-05-19 15:51 UTC (permalink / raw)
To: Daniel Lezcano, Thomas Gleixner
Cc: linux-omap, linux-kernel, linux-arm-kernel, kbuild test robot
We can get a warning for dmtimer_clocksource_init() with 'pa' set but
not used. This was used in the earlier revisions of the code but no
longer needed, so let's remove the unused pa and of_translate_address().
Let's also do it for dmtimer_clockevent_init() that has a similar issue.
Reported-by: kbuild test robot <lkp@intel.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
---
drivers/clocksource/timer-ti-dm-systimer.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/clocksource/timer-ti-dm-systimer.c b/drivers/clocksource/timer-ti-dm-systimer.c
--- a/drivers/clocksource/timer-ti-dm-systimer.c
+++ b/drivers/clocksource/timer-ti-dm-systimer.c
@@ -514,7 +514,6 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
struct clock_event_device *dev;
struct dmtimer_systimer *t;
int error;
- u32 pa;
clkevt = kzalloc(sizeof(*clkevt), GFP_KERNEL);
if (!clkevt)
@@ -563,7 +562,6 @@ static int __init dmtimer_clockevent_init(struct device_node *np)
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->irq_ena);
writel_relaxed(OMAP_TIMER_INT_OVERFLOW, t->base + t->wakeup);
- pa = of_translate_address(np, of_get_address(np, 0, NULL, NULL));
pr_info("TI gptimer clockevent: %s%lu Hz at %pOF\n",
of_find_property(np, "ti,timer-alwon", NULL) ?
"always-on " : "", t->rate, np->parent);
@@ -637,7 +635,6 @@ static int __init dmtimer_clocksource_init(struct device_node *np)
struct dmtimer_systimer *t;
struct clocksource *dev;
int error;
- u32 pa;
clksrc = kzalloc(sizeof(*clksrc), GFP_KERNEL);
if (!clksrc)
@@ -666,7 +663,6 @@ static int __init dmtimer_clocksource_init(struct device_node *np)
writel_relaxed(OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR,
t->base + t->ctrl);
- pa = of_translate_address(np, of_get_address(np, 0, NULL, NULL));
pr_info("TI gptimer clocksource: %s%pOF\n",
of_find_property(np, "ti,timer-alwon", NULL) ?
"always-on " : "", np->parent);
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 3/3] arm64: vdso: Fix CFI directives in sigreturn trampoline
From: Will Deacon @ 2020-05-19 15:55 UTC (permalink / raw)
To: Daniel Kiss
Cc: Tamas Zsoldos, Mark Brown, kernel-team@android.com, Dave P Martin,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <65A3D0F6-5B38-4624-B2DC-BD21EC2BCB25@arm.com>
On Tue, May 19, 2020 at 03:30:57PM +0000, Daniel Kiss wrote:
> > On 19 May 2020, at 15:55, Dave Martin <Dave.Martin@arm.com> wrote:
> > On Tue, May 19, 2020 at 02:39:41PM +0100, Will Deacon wrote:
> >> On Tue, May 19, 2020 at 02:09:31PM +0100, Dave P Martin wrote:
> >>> On Tue, May 19, 2020 at 01:18:18PM +0100, Will Deacon wrote:
> >>>> Daniel reports that the .cfi_startproc is misplaced for the sigreturn
> >>>> trampoline, which causes LLVM's unwinder to misbehave:
> >>>>
> >>>> | I run into this with LLVM’s unwinder.
> >>>> | This combination was always broken.
> >>>>
> >>>> This prompted Dave to realise that our CFI directives are contradictory,
> >>>> as we specify both .cfi_signal_frame *and* .cfi_def_cfa, with the latter
> >>>> unconditionally identifying the interrupted context as opposed to the
> >>>> values in the sigcontext.
> >>>>
> >>>> Rework the CFI directives so that we only use .cfi_signal_frame, and
> >>>> include the "mysterious NOP" as part of the .cfi_{start,end}proc block.
> >>>>
> >>>> Cc: Tamas Zsoldos <tamas.zsoldos@arm.com>
> >>>> Reported-by: Dave Martin <dave.martin@arm.com>
> >>>> Reported-by: Daniel Kiss <daniel.kiss@arm.com>
> >>>> Signed-off-by: Will Deacon <will@kernel.org>
> >>>> ---
> >>>> arch/arm64/kernel/vdso/sigreturn.S | 8 +++-----
> >>>> 1 file changed, 3 insertions(+), 5 deletions(-)
> >>>>
> >>>> diff --git a/arch/arm64/kernel/vdso/sigreturn.S b/arch/arm64/kernel/vdso/sigreturn.S
> >>>> index 7853fa9692f6..28b33f7d0604 100644
> >>>> --- a/arch/arm64/kernel/vdso/sigreturn.S
> >>>> +++ b/arch/arm64/kernel/vdso/sigreturn.S
> >>>> @@ -14,6 +14,9 @@
> >>>>
> >>>> .text
> >>>>
> >>>> +/* Ensure that the mysterious NOP can be associated with a function. */
> >>>> + .cfi_startproc
> >>>> + .cfi_signal_frame
> >>>> /*
> >>>> * This mysterious NOP is required for some unwinders that subtract one from
> >>>> * the return address in order to identify the calling function.
> >>>> @@ -28,11 +31,6 @@
> >>>> * is perfectly fine.
> >>>> */
> >>>> SYM_START(__kernel_rt_sigreturn, SYM_L_GLOBAL, SYM_A_ALIGN)
> >>>> - .cfi_startproc
> >>>> - .cfi_signal_frame
> >>>> - .cfi_def_cfa x29, 0
> >>>> - .cfi_offset x29, 0 * 8
> >>>> - .cfi_offset x30, 1 * 8
> LLVM’s unwinder does not like this version of the CFI. It needs a bit more information,
> the cfi_signal_frame is not used for finding the frame.
Thanks, Daniel. That is, at least, aligned with my current understanding
of how this is supposed to work.
I'll send out a v2 in a bit.
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] clocksource/drivers/timer-ti-dm: Fix warning for set but not used
From: Daniel Lezcano @ 2020-05-19 16:00 UTC (permalink / raw)
To: Tony Lindgren, Thomas Gleixner
Cc: linux-omap, linux-kernel, linux-arm-kernel, kbuild test robot
In-Reply-To: <20200519155157.12804-1-tony@atomide.com>
On 19/05/2020 17:51, Tony Lindgren wrote:
> We can get a warning for dmtimer_clocksource_init() with 'pa' set but
> not used. This was used in the earlier revisions of the code but no
> longer needed, so let's remove the unused pa and of_translate_address().
> Let's also do it for dmtimer_clockevent_init() that has a similar issue.
>
> Reported-by: kbuild test robot <lkp@intel.com>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
Applied, thanks
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] clocksource/drivers/timer-ti-dm: Fix warning for set but not used
From: Tony Lindgren @ 2020-05-19 16:06 UTC (permalink / raw)
To: Daniel Lezcano
Cc: Thomas Gleixner, linux-omap, linux-kernel, linux-arm-kernel,
kbuild test robot
In-Reply-To: <2f67a110-e52f-94fc-fae2-c3171a67bb8a@linaro.org>
* Daniel Lezcano <daniel.lezcano@linaro.org> [200519 16:01]:
> On 19/05/2020 17:51, Tony Lindgren wrote:
> > We can get a warning for dmtimer_clocksource_init() with 'pa' set but
> > not used. This was used in the earlier revisions of the code but no
> > longer needed, so let's remove the unused pa and of_translate_address().
> > Let's also do it for dmtimer_clockevent_init() that has a similar issue.
> >
> > Reported-by: kbuild test robot <lkp@intel.com>
> > Signed-off-by: Tony Lindgren <tony@atomide.com>
> > ---
>
> Applied, thanks
Thanks! Do you already have some immutable commit I can use
as the base for the SoC and dts changes? Or do you want to
wait a bit for that?
Regards,
Tony
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v3 19/23] arm64: mte: Add PTRACE_{PEEK,POKE}MTETAGS support
From: Catalin Marinas @ 2020-05-19 16:10 UTC (permalink / raw)
To: Luis Machado
Cc: linux-arch, Richard Earnshaw, Omair Javaid, Szabolcs Nagy,
Andrey Konovalov, Kevin Brodsky, Peter Collingbourne, linux-mm,
Alan Hayward, Vincenzo Frascino, Will Deacon, Dave Martin,
linux-arm-kernel
In-Reply-To: <55fe4d37-23ae-a6b7-8db1-884aaf4a9b9c@linaro.org>
On Mon, May 18, 2020 at 02:12:24PM -0300, Luis Machado wrote:
> On 5/18/20 1:47 PM, Dave Martin wrote:
> > Wrinkle: just because MTE is "off", pages might still be mapped with
> > PROT_MTE and have arbitrary tags set on them, and the debugger perhaps
> > needs a way to know that. Currently grubbing around in /proc is the
> > only way to discover that. Dunno whether it matters.
>
> That is the sort of thing that may confused the debugger.
>
> If MTE is "off" (and thus the debugger doesn't need to validate tags), then
> the pages mapped with PROT_MTE that show up in /proc/<pid>/smaps should be
> ignored?
There is no such thing as global MTE "off". If the HWCAP is present, a
user program can map an address with PROT_MTE and access tags. Maybe it
uses it for extra storage, you never know, doesn't have to be heap
allocation related.
> I'm looking for a precise way to tell if MTE is being used or not for a
> particular process/thread. This, in turn, will tell debuggers when to look
> for PROT_MTE mappings in /proc/<pid>/smaps and when to validate tagged
> addresses.
>
> So far my assumption was that MTE will always be "on" when HWCAP2_MTE is
> present. So having HWCAP2_MTE means we have the NT_ARM_MTE regset and that
> PROT_MTE pages have to be checked.
Yes. I haven't figured out what to put in the regset yet, most likely
the prctl value as it has other software-only controls like the tagged
address ABI.
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v4 24/26] arm64: mte: Introduce early param to disable MTE support
From: Catalin Marinas @ 2020-05-19 16:14 UTC (permalink / raw)
To: Vladimir Murzin
Cc: linux-arch, Will Deacon, Szabolcs Nagy, Andrey Konovalov,
Kevin Brodsky, linux-mm, Vincenzo Frascino, Peter Collingbourne,
Dave P Martin, linux-arm-kernel
In-Reply-To: <a2ad6cbf-2632-3cda-eb49-74ddfbed2cec@arm.com>
On Mon, May 18, 2020 at 12:26:30PM +0100, Vladimir Murzin wrote:
> On 5/15/20 6:16 PM, Catalin Marinas wrote:
> > For performance analysis it may be desirable to disable MTE altogether
> > via an early param. Introduce arm64.mte_disable and, if true, filter out
> > the sanitised ID_AA64PFR1_EL1.MTE field to avoid exposing the HWCAP to
> > user.
> >
> > Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
> > Cc: Will Deacon <will@kernel.org>
> > ---
> >
> > Notes:
> > New in v4.
> >
> > Documentation/admin-guide/kernel-parameters.txt | 4 ++++
> > arch/arm64/kernel/cpufeature.c | 11 +++++++++++
> > 2 files changed, 15 insertions(+)
> >
> > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> > index f2a93c8679e8..7436e7462b85 100644
> > --- a/Documentation/admin-guide/kernel-parameters.txt
> > +++ b/Documentation/admin-guide/kernel-parameters.txt
> > @@ -373,6 +373,10 @@
> > arcrimi= [HW,NET] ARCnet - "RIM I" (entirely mem-mapped) cards
> > Format: <io>,<irq>,<nodeID>
> >
> > + arm64.mte_disable=
> > + [ARM64] Disable Linux support for the Memory
> > + Tagging Extension (both user and in-kernel).
> > +
>
> Should it really to take parameter (on/off/true/false)? It may lead to expectation
> that arm64.mte_disable=false should enable MT and, yes, double negatives make it
> look ugly, so if we do need parameter, can it be arm64.mte=on/off/true/false?
My reasoning about arm64.mte= was that 'on' may lead people to think it
does something even when MTE isn't available on the SoC. So I ended up
with an explicit 'disable' in the name. Happy to change it if we don't
drop this parameter altogether (in the absence of valid use-cases).
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [v2] ARM: dts: ls1021a: output PPS signal on FIPER2
From: Richard Cochran @ 2020-05-19 16:15 UTC (permalink / raw)
To: Yangbo Lu; +Cc: Shawn Guo, linux-arm-kernel, Li Yang
In-Reply-To: <20200519025307.628-1-yangbo.lu@nxp.com>
On Tue, May 19, 2020 at 10:53:07AM +0800, Yangbo Lu wrote:
> The timer fixed interval period pulse generator register
> is used to generate periodic pulses. The down count
> register loads the value programmed in the fixed period
> interval (FIPER). At every tick of the timer accumulator
> overflow, the counter decrements by the value of
> TMR_CTRL[TCLK_PERIOD]. It generates a pulse when the down
> counter value reaches zero. It reloads the down counter
> in the cycle following a pulse. To use the TMR_FIPER
> register to generate a 1 PPS event, the value
> (10^9 nanoseconds) - TCLK_PERIOD should be programmed.
> It should be 999999995 since TCLK_PERIOD is 5.
>
> This patch is to output PPS signal on FIPER2 which is more
> desired by user.
I think it wouldn't hurt to spell out the effect of this change:
Before, the period of FIPER2 was 100 microseconds.
Now, the period of FIPER2 is one second.
Thanks,
Richard
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 2/4] dt-bindings: sram: add documentation for reserved-only flag
From: Stephen Warren @ 2020-05-19 16:16 UTC (permalink / raw)
To: Mian Yousaf Kaukab
Cc: devicetree, arnd, gregkh, linux-kernel, robh+dt, jonathanh, talho,
thierry.reding, linux-tegra, robin.murphy, afaerber,
linux-arm-kernel
In-Reply-To: <20200513104127.GA2309@suse.de>
On 5/13/20 4:41 AM, Mian Yousaf Kaukab wrote:
> On Tue, May 12, 2020 at 01:45:28PM -0600, Stephen Warren wrote:
>> On 5/12/20 8:48 AM, Mian Yousaf Kaukab wrote:
>>> Add documentation for the new optional flag added for SRAM driver.
>>
>>> diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml
>>
>>> + reserved-only:
>>> + description:
>>> + The flag indicating, that only SRAM reserved regions have to be remapped.
>>> + remapping type is selected depending upon no-memory-wc as usual.
>>> + type: boolean
>>
>> This feels a bit like a SW flag rather than a HW description, so I'm not
>> sure it's appropriate to put it into DT.
>
> Reserved regions themselves are software descriptions, no? Then we have 'pool'
> flag which is again a software flag and so on. This flag falls into same
> category and nothing out of ordinary.
I suppose that's true to some extent. This is indeed a description of
the system environment presented to the SW that consumes the DT, which
is a bit more than pure HW description but still a description of
something imposed externally rather than describing something that's up
to the discretion of the consuming SW. So, go ahead.
>> Are there any cases where the SW should map all of the SRAM, i.e. where
>> we wouldn't expect to set reserved-only? [...]
>
> Yes, here are a few examples:
> arch/arm/boot/dts/aspeed-g*.dtsi
> arch/arm/boot/dts/at91*.dtsi
> arch/arm/boot/dts/bcm7445.dtsi
> Then arch/arm/boot/dts/dra7.dtsi is an example where we should map everything
> except the reserved region.
>
>> [...] I'd expect reserved-only to be
>> the default, and perhaps only, mode of operation for the SRAM driver.
>
> It will break compatibility with existing dtbs.
>
>> If we can't do that because some SW currently expects to be able to map
>> arbitrary portions of the SRAM, shouldn't that SW be fixed to tell the
>> SRAM driver which parts it's using, hence still allowing the driver to
>> only map in-use portions?
>
> User doesn’t need sram driver in that case. It can use genalloc api directly.
This sounds a bit odd. Without a driver for the reserved region, nothing
should be touching it, since otherwise there's no code that owns an
manages the region. If any code needs to consume the region, it should
obtain info about the region from some form of provider code that can
handle both the allocation and mapping. Anything else sounds like some
consumer code directly making use of DT nodes it doesn't own. But since
I'm not familiar enough with the SRAM driver and genalloc code that you
mention to fully understand the allocation paths I guess I won't object
for now, although it does still sound fishy.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 00/11] arm/arm64: Turning IPIs into normal interrupts
From: Marc Zyngier @ 2020-05-19 16:17 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: Sumit Garg, kernel-team, Russell King, Jason Cooper,
Catalin Marinas, Thomas Gleixner, Will Deacon
For as long as SMP ARM has existed, IPIs have been handled as
something special. The arch code and the interrupt controller exchange
a couple of hooks (one to generate an IPI, another to handle it).
Although this is perfectly manageable, it prevents the use of features
that we could use if IPIs were Linux IRQs (such as pseudo-NMIs). It
also means that each interrupt controller driver has to follow an
architecture-specific interface instead of just implementing the base
irqchip functionnalities. The arch code also duplicates a number of
things that the core irq code already does (such as calling
set_irq_regs(), irq_enter()...).
This series tries to remedy this on arm/arm64 by offering a new
registration interface where the irqchip gives the arch code a range
of interrupts to use for IPIs. The arch code requests these as normal
interrupts.
The bulk of the work is at the interrupt controller level, where all 3
irqchips used on arm64 get converted.
Finally, the arm64 code drops the legacy registration interface. The
same thing could be done on 32bit as well once the two remaining
irqchips using that interface get converted.
There is probably more that could be done: statistics are still
architecture-private code, for example, and no attempt is made to
solve that (apart from hidding the IRQs from /proc/interrupt).
This has been tested on a bunch of 32 and 64bit guests.
Marc Zyngier (11):
genirq: Add fasteoi IPI flow
genirq: Allow interrupts to be excluded from /proc/interrupts
arm64: Allow IPIs to be handled as normal interrupts
ARM: Allow IPIs to be handled as normal interrupts
irqchip/gic-v3: Describe the SGI range
irqchip/gic-v3: Configure SGIs as standard interrupts
irqchip/gic: Refactor SMP configuration
irqchip/gic: Configure SGIs as standard interrupts
irqchip/gic-common: Don't enable SGIs by default
irqchip/bcm2836: Configure mailbox interrupts as standard interrupts
arm64: Kill __smp_cross_call and co
arch/arm/Kconfig | 1 +
arch/arm/include/asm/smp.h | 5 +
arch/arm/kernel/smp.c | 97 +++++++++++---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/irq_work.h | 4 +-
arch/arm64/include/asm/smp.h | 6 +-
arch/arm64/kernel/smp.c | 98 +++++++++++----
drivers/irqchip/irq-bcm2836.c | 151 ++++++++++++++++++----
drivers/irqchip/irq-gic-common.c | 3 -
drivers/irqchip/irq-gic-v3.c | 109 ++++++++++------
drivers/irqchip/irq-gic.c | 203 ++++++++++++++++++------------
include/linux/irq.h | 4 +-
kernel/irq/chip.c | 26 ++++
kernel/irq/debugfs.c | 1 +
kernel/irq/proc.c | 2 +-
kernel/irq/settings.h | 7 ++
16 files changed, 515 insertions(+), 203 deletions(-)
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 01/11] genirq: Add fasteoi IPI flow
From: Marc Zyngier @ 2020-05-19 16:17 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: Sumit Garg, kernel-team, Russell King, Jason Cooper,
Catalin Marinas, Thomas Gleixner, Will Deacon
In-Reply-To: <20200519161755.209565-1-maz@kernel.org>
For irqchips using the fasteoi flow, IPIs are a bit special.
They need to be EOId early (before calling the handler), as
funny things may happen in the handler (they do not necessarily
behave like a normal interrupt), and that the arch code is
already handling the stats.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
include/linux/irq.h | 1 +
kernel/irq/chip.c | 26 ++++++++++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 8d5bc2c237d7..726f94d8b8cc 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -621,6 +621,7 @@ static inline int irq_set_parent(int irq, int parent_irq)
*/
extern void handle_level_irq(struct irq_desc *desc);
extern void handle_fasteoi_irq(struct irq_desc *desc);
+extern void handle_percpu_devid_fasteoi_ipi(struct irq_desc *desc);
extern void handle_edge_irq(struct irq_desc *desc);
extern void handle_edge_eoi_irq(struct irq_desc *desc);
extern void handle_simple_irq(struct irq_desc *desc);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 41e7e37a0928..7b0b789cfed4 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -955,6 +955,32 @@ void handle_percpu_devid_irq(struct irq_desc *desc)
chip->irq_eoi(&desc->irq_data);
}
+/**
+ * handle_percpu_devid_fasteoi_ipi - Per CPU local IPI handler with per cpu
+ * dev ids
+ * @desc: the interrupt description structure for this irq
+ *
+ * The biggest differences with the IRQ version are that:
+ * - the interrupt is EOIed early, as the IPI could result in a context
+ * switch, and we need to make sure the IPI can fire again
+ * - Stats are usually handled at the architecture level, so we ignore them
+ * here
+ */
+void handle_percpu_devid_fasteoi_ipi(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irqaction *action = desc->action;
+ unsigned int irq = irq_desc_get_irq(desc);
+ irqreturn_t res;
+
+ if (chip->irq_eoi)
+ chip->irq_eoi(&desc->irq_data);
+
+ trace_irq_handler_entry(irq, action);
+ res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id));
+ trace_irq_handler_exit(irq, action, res);
+}
+
/**
* handle_percpu_devid_fasteoi_nmi - Per CPU local NMI handler with per cpu
* dev ids
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 02/11] genirq: Allow interrupts to be excluded from /proc/interrupts
From: Marc Zyngier @ 2020-05-19 16:17 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: Sumit Garg, kernel-team, Russell King, Jason Cooper,
Catalin Marinas, Thomas Gleixner, Will Deacon
In-Reply-To: <20200519161755.209565-1-maz@kernel.org>
A number of architectures implement IPI statistics directly,
bypassing the core kstat_irqs accounting. As we move IPIs to
being actual IRQs, we would end-up with a confusing display
in /proc/interrupts (where the IPIs would appear twice).
In order to solve this, allow interrupts to be flagged as
"no accounting", which excludes them from /proc/interrupts.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
include/linux/irq.h | 3 ++-
kernel/irq/debugfs.c | 1 +
kernel/irq/proc.c | 2 +-
kernel/irq/settings.h | 7 +++++++
4 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 726f94d8b8cc..4433c8e765c8 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -97,13 +97,14 @@ enum {
IRQ_PER_CPU_DEVID = (1 << 17),
IRQ_IS_POLLED = (1 << 18),
IRQ_DISABLE_UNLAZY = (1 << 19),
+ IRQ_NO_ACCOUNTING = (1 << 20),
};
#define IRQF_MODIFY_MASK \
(IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \
IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \
- IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY)
+ IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY | IRQ_NO_ACCOUNTING)
#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c
index 4f9f844074db..9a22eab5537f 100644
--- a/kernel/irq/debugfs.c
+++ b/kernel/irq/debugfs.c
@@ -131,6 +131,7 @@ static const struct irq_bit_descr irqdesc_states[] = {
BIT_MASK_DESCR(_IRQ_PER_CPU_DEVID),
BIT_MASK_DESCR(_IRQ_IS_POLLED),
BIT_MASK_DESCR(_IRQ_DISABLE_UNLAZY),
+ BIT_MASK_DESCR(_IRQ_NO_ACCOUNTING),
};
static const struct irq_bit_descr irqdesc_istates[] = {
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 32c071d7bc03..87780af13c12 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -485,7 +485,7 @@ int show_interrupts(struct seq_file *p, void *v)
rcu_read_lock();
desc = irq_to_desc(i);
- if (!desc)
+ if (!desc || irq_settings_is_no_accounting(desc))
goto outsparse;
if (desc->kstat_irqs)
diff --git a/kernel/irq/settings.h b/kernel/irq/settings.h
index e43795cd2ccf..732fc3f2c686 100644
--- a/kernel/irq/settings.h
+++ b/kernel/irq/settings.h
@@ -17,6 +17,7 @@ enum {
_IRQ_PER_CPU_DEVID = IRQ_PER_CPU_DEVID,
_IRQ_IS_POLLED = IRQ_IS_POLLED,
_IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY,
+ _IRQ_NO_ACCOUNTING = IRQ_NO_ACCOUNTING,
_IRQF_MODIFY_MASK = IRQF_MODIFY_MASK,
};
@@ -31,6 +32,7 @@ enum {
#define IRQ_PER_CPU_DEVID GOT_YOU_MORON
#define IRQ_IS_POLLED GOT_YOU_MORON
#define IRQ_DISABLE_UNLAZY GOT_YOU_MORON
+#define IRQ_NO_ACCOUNTING GOT_YOU_MORON
#undef IRQF_MODIFY_MASK
#define IRQF_MODIFY_MASK GOT_YOU_MORON
@@ -167,3 +169,8 @@ static inline void irq_settings_clr_disable_unlazy(struct irq_desc *desc)
{
desc->status_use_accessors &= ~_IRQ_DISABLE_UNLAZY;
}
+
+static inline bool irq_settings_is_no_accounting(struct irq_desc *desc)
+{
+ return desc->status_use_accessors & _IRQ_NO_ACCOUNTING;
+}
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 03/11] arm64: Allow IPIs to be handled as normal interrupts
From: Marc Zyngier @ 2020-05-19 16:17 UTC (permalink / raw)
To: linux-arm-kernel, linux-kernel
Cc: Sumit Garg, kernel-team, Russell King, Jason Cooper,
Catalin Marinas, Thomas Gleixner, Will Deacon
In-Reply-To: <20200519161755.209565-1-maz@kernel.org>
In order to deal with IPIs as normal interrupts, let's add
a new way to register them with the architecture code.
set_smp_ipi_range() takes a range of interrupts, and allows
the arch code to request them as if the were normal interrupts.
A standard handler is then called by the core IRQ code to deal
with the IPI.
This means that we don't need to call irq_enter/irq_exit, and
that we don't need to deal with set_irq_regs either. So let's
move the dispatcher into its own function, and leave handle_IPI()
as a compatibility function.
On the sending side, let's make use of ipi_send_mask, which
already exists for this purpose.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/smp.h | 5 ++
arch/arm64/kernel/smp.c | 92 +++++++++++++++++++++++++++++++-----
3 files changed, 86 insertions(+), 12 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 5d513f461957..6a6271281016 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -99,6 +99,7 @@ config ARM64
select GENERIC_CPU_VULNERABILITIES
select GENERIC_EARLY_IOREMAP
select GENERIC_IDLE_POLL_SETUP
+ select GENERIC_IRQ_IPI
select GENERIC_IRQ_MULTI_HANDLER
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 40d5ba029615..42f366ba88bf 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -82,6 +82,11 @@ extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int));
extern void (*__smp_cross_call)(const struct cpumask *, unsigned int);
+/*
+ * Register IPI interrupts with the arch SMP code
+ */
+extern void set_smp_ipi_range(int ipi_base, int nr_ipi);
+
/*
* Called from the secondary holding pen, this is the secondary CPU entry point.
*/
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 061f60fe452f..93ba0025e7b9 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -67,6 +67,13 @@ struct secondary_data secondary_data;
/* Number of CPUs which aren't online, but looping in kernel text. */
int cpus_stuck_in_kernel;
+static int ipi_irq_base;
+static int nr_ipi = NR_IPI;
+static struct irq_desc *ipi_desc[NR_IPI];
+
+static void ipi_setup(int cpu);
+static void ipi_teardown(int cpu);
+
enum ipi_msg_type {
IPI_RESCHEDULE,
IPI_CALL_FUNC,
@@ -247,6 +254,8 @@ asmlinkage notrace void secondary_start_kernel(void)
*/
notify_cpu_starting(cpu);
+ ipi_setup(cpu);
+
store_cpu_topology(cpu);
numa_add_cpu(cpu);
@@ -374,6 +383,8 @@ void cpu_die(void)
local_daif_mask();
+ ipi_teardown(cpu);
+
/* Tell __cpu_die() that this CPU is now safe to dispose of */
(void)cpu_report_death();
@@ -900,10 +911,9 @@ static void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
/*
* Main handler for inter-processor interrupts
*/
-void handle_IPI(int ipinr, struct pt_regs *regs)
+static void do_handle_IPI(int ipinr)
{
unsigned int cpu = smp_processor_id();
- struct pt_regs *old_regs = set_irq_regs(regs);
if ((unsigned)ipinr < NR_IPI) {
trace_ipi_entry_rcuidle(ipi_types[ipinr]);
@@ -916,21 +926,16 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
break;
case IPI_CALL_FUNC:
- irq_enter();
generic_smp_call_function_interrupt();
- irq_exit();
break;
case IPI_CPU_STOP:
- irq_enter();
local_cpu_stop();
- irq_exit();
break;
case IPI_CPU_CRASH_STOP:
if (IS_ENABLED(CONFIG_KEXEC_CORE)) {
- irq_enter();
- ipi_cpu_crash_stop(cpu, regs);
+ ipi_cpu_crash_stop(cpu, get_irq_regs());
unreachable();
}
@@ -938,17 +943,13 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
case IPI_TIMER:
- irq_enter();
tick_receive_broadcast();
- irq_exit();
break;
#endif
#ifdef CONFIG_IRQ_WORK
case IPI_IRQ_WORK:
- irq_enter();
irq_work_run();
- irq_exit();
break;
#endif
@@ -967,9 +968,76 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
if ((unsigned)ipinr < NR_IPI)
trace_ipi_exit_rcuidle(ipi_types[ipinr]);
+}
+
+/* Legacy version, should go away once all irqchips have been converted */
+void handle_IPI(int ipinr, struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ irq_enter();
+ do_handle_IPI(ipinr);
+ irq_exit();
+
set_irq_regs(old_regs);
}
+static irqreturn_t ipi_handler(int irq, void *data)
+{
+ do_handle_IPI(irq - ipi_irq_base);
+ return IRQ_HANDLED;
+}
+
+static void ipi_send(const struct cpumask *target, unsigned int ipi)
+{
+ __ipi_send_mask(ipi_desc[ipi], target);
+}
+
+static void ipi_setup(int cpu)
+{
+ if (ipi_irq_base) {
+ int i;
+
+ for (i = 0; i < nr_ipi; i++)
+ enable_percpu_irq(ipi_irq_base + i, 0);
+ }
+}
+
+static void ipi_teardown(int cpu)
+{
+ if (ipi_irq_base) {
+ int i;
+
+ for (i = 0; i < nr_ipi; i++)
+ disable_percpu_irq(ipi_irq_base + i);
+ }
+}
+
+void __init set_smp_ipi_range(int ipi_base, int n)
+{
+ int i;
+
+ WARN_ON(n < NR_IPI);
+ nr_ipi = min(n, NR_IPI);
+
+ for (i = 0; i < nr_ipi; i++) {
+ int err;
+
+ err = request_percpu_irq(ipi_base + i, ipi_handler,
+ "IPI", &irq_stat);
+ WARN_ON(err);
+
+ ipi_desc[i] = irq_to_desc(ipi_base + i);
+ irq_set_status_flags(ipi_base + i, IRQ_NO_ACCOUNTING);
+ }
+
+ ipi_irq_base = ipi_base;
+ __smp_cross_call = ipi_send;
+
+ /* Setup the boot CPU immediately */
+ ipi_setup(smp_processor_id());
+}
+
void smp_send_reschedule(int cpu)
{
smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox