--- /dev/null
+From 1e4e0bf136aa4b4aa59c1e6af19844bd6d807794 Mon Sep 17 00:00:00 2001
+From: Sowjanya Komatineni <skomatineni@nvidia.com>
+Date: Mon, 13 Jan 2020 23:24:23 -0800
+Subject: ASoC: tegra: Add audio mclk parent configuration
+
+From: Sowjanya Komatineni <skomatineni@nvidia.com>
+
+commit 1e4e0bf136aa4b4aa59c1e6af19844bd6d807794 upstream.
+
+Tegra PMC clock clk_out_1 is dedicated for audio mclk from Tegra30
+through Tegra210 and currently Tegra clock driver does the initial
+parent configuration for audio mclk and keeps it enabled by default.
+
+With the move of PMC clocks from clock driver into PMC driver, audio
+clocks parent configuration can be specified through the device tree
+using assigned-clock-parents property and audio mclk control should be
+taken care of by the audio driver.
+
+This patch has implementation for parent configuration when default
+parent configuration through assigned-clock-parents property is not
+specified in the device tree.
+
+Tested-by: Dmitry Osipenko <digetx@gmail.com>
+Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
+Reviewed-by: Sameer Pujar <spujar@nvidia.com>
+Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/soc/tegra/tegra_asoc_utils.c | 68 +++++++++++++++++++++----------------
+ 1 file changed, 40 insertions(+), 28 deletions(-)
+
+--- a/sound/soc/tegra/tegra_asoc_utils.c
++++ b/sound/soc/tegra/tegra_asoc_utils.c
+@@ -60,8 +60,6 @@ int tegra_asoc_utils_set_rate(struct teg
+ data->set_mclk = 0;
+
+ clk_disable_unprepare(data->clk_cdev1);
+- clk_disable_unprepare(data->clk_pll_a_out0);
+- clk_disable_unprepare(data->clk_pll_a);
+
+ err = clk_set_rate(data->clk_pll_a, new_baseclock);
+ if (err) {
+@@ -77,18 +75,6 @@ int tegra_asoc_utils_set_rate(struct teg
+
+ /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
+
+- err = clk_prepare_enable(data->clk_pll_a);
+- if (err) {
+- dev_err(data->dev, "Can't enable pll_a: %d\n", err);
+- return err;
+- }
+-
+- err = clk_prepare_enable(data->clk_pll_a_out0);
+- if (err) {
+- dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err);
+- return err;
+- }
+-
+ err = clk_prepare_enable(data->clk_cdev1);
+ if (err) {
+ dev_err(data->dev, "Can't enable cdev1: %d\n", err);
+@@ -109,8 +95,6 @@ int tegra_asoc_utils_set_ac97_rate(struc
+ int err;
+
+ clk_disable_unprepare(data->clk_cdev1);
+- clk_disable_unprepare(data->clk_pll_a_out0);
+- clk_disable_unprepare(data->clk_pll_a);
+
+ /*
+ * AC97 rate is fixed at 24.576MHz and is used for both the host
+@@ -130,18 +114,6 @@ int tegra_asoc_utils_set_ac97_rate(struc
+
+ /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
+
+- err = clk_prepare_enable(data->clk_pll_a);
+- if (err) {
+- dev_err(data->dev, "Can't enable pll_a: %d\n", err);
+- return err;
+- }
+-
+- err = clk_prepare_enable(data->clk_pll_a_out0);
+- if (err) {
+- dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err);
+- return err;
+- }
+-
+ err = clk_prepare_enable(data->clk_cdev1);
+ if (err) {
+ dev_err(data->dev, "Can't enable cdev1: %d\n", err);
+@@ -158,6 +130,7 @@ EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_a
+ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
+ struct device *dev)
+ {
++ struct clk *clk_out_1, *clk_extern1;
+ int ret;
+
+ data->dev = dev;
+@@ -193,6 +166,45 @@ int tegra_asoc_utils_init(struct tegra_a
+ return PTR_ERR(data->clk_cdev1);
+ }
+
++ /*
++ * If clock parents are not set in DT, configure here to use clk_out_1
++ * as mclk and extern1 as parent for Tegra30 and higher.
++ */
++ if (!of_find_property(dev->of_node, "assigned-clock-parents", NULL) &&
++ data->soc > TEGRA_ASOC_UTILS_SOC_TEGRA20) {
++ dev_warn(data->dev,
++ "Configuring clocks for a legacy device-tree\n");
++ dev_warn(data->dev,
++ "Please update DT to use assigned-clock-parents\n");
++ clk_extern1 = devm_clk_get(dev, "extern1");
++ if (IS_ERR(clk_extern1)) {
++ dev_err(data->dev, "Can't retrieve clk extern1\n");
++ return PTR_ERR(clk_extern1);
++ }
++
++ ret = clk_set_parent(clk_extern1, data->clk_pll_a_out0);
++ if (ret < 0) {
++ dev_err(data->dev,
++ "Set parent failed for clk extern1\n");
++ return ret;
++ }
++
++ clk_out_1 = devm_clk_get(dev, "pmc_clk_out_1");
++ if (IS_ERR(clk_out_1)) {
++ dev_err(data->dev, "Can't retrieve pmc_clk_out_1\n");
++ return PTR_ERR(clk_out_1);
++ }
++
++ ret = clk_set_parent(clk_out_1, clk_extern1);
++ if (ret < 0) {
++ dev_err(data->dev,
++ "Set parent failed for pmc_clk_out_1\n");
++ return ret;
++ }
++
++ data->clk_cdev1 = clk_out_1;
++ }
++
+ ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
+ if (ret)
+ return ret;
--- /dev/null
+From ff5d18cb04f4ecccbcf05b7f83ab6df2a0d95c16 Mon Sep 17 00:00:00 2001
+From: Sowjanya Komatineni <skomatineni@nvidia.com>
+Date: Mon, 13 Jan 2020 23:24:24 -0800
+Subject: ASoC: tegra: Enable audio mclk during tegra_asoc_utils_init()
+
+From: Sowjanya Komatineni <skomatineni@nvidia.com>
+
+commit ff5d18cb04f4ecccbcf05b7f83ab6df2a0d95c16 upstream.
+
+Tegra PMC clock clk_out_1 is dedicated for audio mclk from Tegra30
+through Tegra210 and currently Tegra clock driver keeps the audio mclk
+enabled.
+
+With the move of PMC clocks from clock driver into pmc driver, audio
+mclk enable from clock driver is removed and this should be taken care
+of by the audio driver.
+
+tegra_asoc_utils_init() calls tegra_asoc_utils_set_rate() and audio mclk
+rate configuration is not needed during init and the rate is actually
+set during the ->hw_params() callback.
+
+So, this patch removes tegra_asoc_utils_set_rate() call and just leaves
+the audio mclk enabled.
+
+Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
+Tested-by: Dmitry Osipenko <digetx@gmail.com>
+Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/soc/tegra/tegra_asoc_utils.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/tegra/tegra_asoc_utils.c
++++ b/sound/soc/tegra/tegra_asoc_utils.c
+@@ -205,9 +205,16 @@ int tegra_asoc_utils_init(struct tegra_a
+ data->clk_cdev1 = clk_out_1;
+ }
+
+- ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
+- if (ret)
++ /*
++ * FIXME: There is some unknown dependency between audio mclk disable
++ * and suspend-resume functionality on Tegra30, although audio mclk is
++ * only needed for audio.
++ */
++ ret = clk_prepare_enable(data->clk_cdev1);
++ if (ret) {
++ dev_err(data->dev, "Can't enable cdev1: %d\n", ret);
+ return ret;
++ }
+
+ return 0;
+ }
--- /dev/null
+From 0de6db30ef79b391cedd749801a49c485d2daf4b Mon Sep 17 00:00:00 2001
+From: Sowjanya Komatineni <skomatineni@nvidia.com>
+Date: Mon, 13 Jan 2020 23:24:17 -0800
+Subject: ASoC: tegra: Use device managed resource APIs to get the clock
+
+From: Sowjanya Komatineni <skomatineni@nvidia.com>
+
+commit 0de6db30ef79b391cedd749801a49c485d2daf4b upstream.
+
+tegra_asoc_utils uses clk_get() to get the clock and clk_put() to free
+them explicitly.
+
+This patch updates it to use device managed resource API devm_clk_get()
+so the clock will be automatically released and freed when the device is
+unbound and removes tegra_asoc_utils_fini() as its no longer needed.
+
+Tested-by: Dmitry Osipenko <digetx@gmail.com>
+Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
+Reviewed-by: Sameer Pujar <spujar@nvidia.com>
+Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
+Signed-off-by: Thierry Reding <treding@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/soc/tegra/tegra_alc5632.c | 7 +------
+ sound/soc/tegra/tegra_asoc_utils.c | 34 +++++++---------------------------
+ sound/soc/tegra/tegra_asoc_utils.h | 1 -
+ sound/soc/tegra/tegra_max98090.c | 22 ++++++----------------
+ sound/soc/tegra/tegra_rt5640.c | 22 ++++++----------------
+ sound/soc/tegra/tegra_rt5677.c | 7 +------
+ sound/soc/tegra/tegra_sgtl5000.c | 7 +------
+ sound/soc/tegra/tegra_wm8753.c | 22 ++++++----------------
+ sound/soc/tegra/tegra_wm8903.c | 22 ++++++----------------
+ sound/soc/tegra/tegra_wm9712.c | 8 ++------
+ sound/soc/tegra/trimslice.c | 18 ++++--------------
+ 11 files changed, 40 insertions(+), 130 deletions(-)
+
+--- a/sound/soc/tegra/tegra_alc5632.c
++++ b/sound/soc/tegra/tegra_alc5632.c
+@@ -205,13 +205,11 @@ static int tegra_alc5632_probe(struct pl
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto err_fini_utils;
++ goto err_put_cpu_of_node;
+ }
+
+ return 0;
+
+-err_fini_utils:
+- tegra_asoc_utils_fini(&alc5632->util_data);
+ err_put_cpu_of_node:
+ of_node_put(tegra_alc5632_dai.cpus->of_node);
+ tegra_alc5632_dai.cpus->of_node = NULL;
+@@ -226,12 +224,9 @@ err:
+ static int tegra_alc5632_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&machine->util_data);
+-
+ of_node_put(tegra_alc5632_dai.cpus->of_node);
+ tegra_alc5632_dai.cpus->of_node = NULL;
+ tegra_alc5632_dai.platforms->of_node = NULL;
+--- a/sound/soc/tegra/tegra_asoc_utils.c
++++ b/sound/soc/tegra/tegra_asoc_utils.c
+@@ -175,52 +175,32 @@ int tegra_asoc_utils_init(struct tegra_a
+ return -EINVAL;
+ }
+
+- data->clk_pll_a = clk_get(dev, "pll_a");
++ data->clk_pll_a = devm_clk_get(dev, "pll_a");
+ if (IS_ERR(data->clk_pll_a)) {
+ dev_err(data->dev, "Can't retrieve clk pll_a\n");
+- ret = PTR_ERR(data->clk_pll_a);
+- goto err;
++ return PTR_ERR(data->clk_pll_a);
+ }
+
+- data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
++ data->clk_pll_a_out0 = devm_clk_get(dev, "pll_a_out0");
+ if (IS_ERR(data->clk_pll_a_out0)) {
+ dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
+- ret = PTR_ERR(data->clk_pll_a_out0);
+- goto err_put_pll_a;
++ return PTR_ERR(data->clk_pll_a_out0);
+ }
+
+- data->clk_cdev1 = clk_get(dev, "mclk");
++ data->clk_cdev1 = devm_clk_get(dev, "mclk");
+ if (IS_ERR(data->clk_cdev1)) {
+ dev_err(data->dev, "Can't retrieve clk cdev1\n");
+- ret = PTR_ERR(data->clk_cdev1);
+- goto err_put_pll_a_out0;
++ return PTR_ERR(data->clk_cdev1);
+ }
+
+ ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
+ if (ret)
+- goto err_put_cdev1;
++ return ret;
+
+ return 0;
+-
+-err_put_cdev1:
+- clk_put(data->clk_cdev1);
+-err_put_pll_a_out0:
+- clk_put(data->clk_pll_a_out0);
+-err_put_pll_a:
+- clk_put(data->clk_pll_a);
+-err:
+- return ret;
+ }
+ EXPORT_SYMBOL_GPL(tegra_asoc_utils_init);
+
+-void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data)
+-{
+- clk_put(data->clk_cdev1);
+- clk_put(data->clk_pll_a_out0);
+- clk_put(data->clk_pll_a);
+-}
+-EXPORT_SYMBOL_GPL(tegra_asoc_utils_fini);
+-
+ MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+ MODULE_DESCRIPTION("Tegra ASoC utility code");
+ MODULE_LICENSE("GPL");
+--- a/sound/soc/tegra/tegra_asoc_utils.h
++++ b/sound/soc/tegra/tegra_asoc_utils.h
+@@ -34,6 +34,5 @@ int tegra_asoc_utils_set_rate(struct teg
+ int tegra_asoc_utils_set_ac97_rate(struct tegra_asoc_utils_data *data);
+ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
+ struct device *dev);
+-void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
+
+ #endif
+--- a/sound/soc/tegra/tegra_max98090.c
++++ b/sound/soc/tegra/tegra_max98090.c
+@@ -218,19 +218,18 @@ static int tegra_max98090_probe(struct p
+
+ ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+ if (ret)
+- goto err;
++ return ret;
+
+ tegra_max98090_dai.codecs->of_node = of_parse_phandle(np,
+ "nvidia,audio-codec", 0);
+ if (!tegra_max98090_dai.codecs->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ tegra_max98090_dai.cpus->of_node = of_parse_phandle(np,
+@@ -238,40 +237,31 @@ static int tegra_max98090_probe(struct p
+ if (!tegra_max98090_dai.cpus->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ tegra_max98090_dai.platforms->of_node = tegra_max98090_dai.cpus->of_node;
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto err_fini_utils;
++ return ret;
+ }
+
+ return 0;
+-
+-err_fini_utils:
+- tegra_asoc_utils_fini(&machine->util_data);
+-err:
+- return ret;
+ }
+
+ static int tegra_max98090_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&machine->util_data);
+-
+ return 0;
+ }
+
+--- a/sound/soc/tegra/tegra_rt5640.c
++++ b/sound/soc/tegra/tegra_rt5640.c
+@@ -164,19 +164,18 @@ static int tegra_rt5640_probe(struct pla
+
+ ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+ if (ret)
+- goto err;
++ return ret;
+
+ tegra_rt5640_dai.codecs->of_node = of_parse_phandle(np,
+ "nvidia,audio-codec", 0);
+ if (!tegra_rt5640_dai.codecs->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ tegra_rt5640_dai.cpus->of_node = of_parse_phandle(np,
+@@ -184,40 +183,31 @@ static int tegra_rt5640_probe(struct pla
+ if (!tegra_rt5640_dai.cpus->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ tegra_rt5640_dai.platforms->of_node = tegra_rt5640_dai.cpus->of_node;
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto err_fini_utils;
++ return ret;
+ }
+
+ return 0;
+-
+-err_fini_utils:
+- tegra_asoc_utils_fini(&machine->util_data);
+-err:
+- return ret;
+ }
+
+ static int tegra_rt5640_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&machine->util_data);
+-
+ return 0;
+ }
+
+--- a/sound/soc/tegra/tegra_rt5677.c
++++ b/sound/soc/tegra/tegra_rt5677.c
+@@ -270,13 +270,11 @@ static int tegra_rt5677_probe(struct pla
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto err_fini_utils;
++ goto err_put_cpu_of_node;
+ }
+
+ return 0;
+
+-err_fini_utils:
+- tegra_asoc_utils_fini(&machine->util_data);
+ err_put_cpu_of_node:
+ of_node_put(tegra_rt5677_dai.cpus->of_node);
+ tegra_rt5677_dai.cpus->of_node = NULL;
+@@ -291,12 +289,9 @@ err:
+ static int tegra_rt5677_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&machine->util_data);
+-
+ tegra_rt5677_dai.platforms->of_node = NULL;
+ of_node_put(tegra_rt5677_dai.codecs->of_node);
+ tegra_rt5677_dai.codecs->of_node = NULL;
+--- a/sound/soc/tegra/tegra_sgtl5000.c
++++ b/sound/soc/tegra/tegra_sgtl5000.c
+@@ -156,13 +156,11 @@ static int tegra_sgtl5000_driver_probe(s
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto err_fini_utils;
++ goto err_put_cpu_of_node;
+ }
+
+ return 0;
+
+-err_fini_utils:
+- tegra_asoc_utils_fini(&machine->util_data);
+ err_put_cpu_of_node:
+ of_node_put(tegra_sgtl5000_dai.cpus->of_node);
+ tegra_sgtl5000_dai.cpus->of_node = NULL;
+@@ -177,13 +175,10 @@ err:
+ static int tegra_sgtl5000_driver_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ ret = snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&machine->util_data);
+-
+ of_node_put(tegra_sgtl5000_dai.cpus->of_node);
+ tegra_sgtl5000_dai.cpus->of_node = NULL;
+ tegra_sgtl5000_dai.platforms->of_node = NULL;
+--- a/sound/soc/tegra/tegra_wm8753.c
++++ b/sound/soc/tegra/tegra_wm8753.c
+@@ -127,19 +127,18 @@ static int tegra_wm8753_driver_probe(str
+
+ ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+ if (ret)
+- goto err;
++ return ret;
+
+ tegra_wm8753_dai.codecs->of_node = of_parse_phandle(np,
+ "nvidia,audio-codec", 0);
+ if (!tegra_wm8753_dai.codecs->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ tegra_wm8753_dai.cpus->of_node = of_parse_phandle(np,
+@@ -147,40 +146,31 @@ static int tegra_wm8753_driver_probe(str
+ if (!tegra_wm8753_dai.cpus->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ tegra_wm8753_dai.platforms->of_node = tegra_wm8753_dai.cpus->of_node;
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto err_fini_utils;
++ return ret;
+ }
+
+ return 0;
+-
+-err_fini_utils:
+- tegra_asoc_utils_fini(&machine->util_data);
+-err:
+- return ret;
+ }
+
+ static int tegra_wm8753_driver_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&machine->util_data);
+-
+ return 0;
+ }
+
+--- a/sound/soc/tegra/tegra_wm8903.c
++++ b/sound/soc/tegra/tegra_wm8903.c
+@@ -323,19 +323,18 @@ static int tegra_wm8903_driver_probe(str
+
+ ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+ if (ret)
+- goto err;
++ return ret;
+
+ tegra_wm8903_dai.codecs->of_node = of_parse_phandle(np,
+ "nvidia,audio-codec", 0);
+ if (!tegra_wm8903_dai.codecs->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ tegra_wm8903_dai.cpus->of_node = of_parse_phandle(np,
+@@ -343,40 +342,31 @@ static int tegra_wm8903_driver_probe(str
+ if (!tegra_wm8903_dai.cpus->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ tegra_wm8903_dai.platforms->of_node = tegra_wm8903_dai.cpus->of_node;
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto err_fini_utils;
++ return ret;
+ }
+
+ return 0;
+-
+-err_fini_utils:
+- tegra_asoc_utils_fini(&machine->util_data);
+-err:
+- return ret;
+ }
+
+ static int tegra_wm8903_driver_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&machine->util_data);
+-
+ return 0;
+ }
+
+--- a/sound/soc/tegra/tegra_wm9712.c
++++ b/sound/soc/tegra/tegra_wm9712.c
+@@ -113,19 +113,17 @@ static int tegra_wm9712_driver_probe(str
+
+ ret = tegra_asoc_utils_set_ac97_rate(&machine->util_data);
+ if (ret)
+- goto asoc_utils_fini;
++ goto codec_unregister;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto asoc_utils_fini;
++ goto codec_unregister;
+ }
+
+ return 0;
+
+-asoc_utils_fini:
+- tegra_asoc_utils_fini(&machine->util_data);
+ codec_unregister:
+ platform_device_del(machine->codec);
+ codec_put:
+@@ -140,8 +138,6 @@ static int tegra_wm9712_driver_remove(st
+
+ snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&machine->util_data);
+-
+ platform_device_unregister(machine->codec);
+
+ return 0;
+--- a/sound/soc/tegra/trimslice.c
++++ b/sound/soc/tegra/trimslice.c
+@@ -125,8 +125,7 @@ static int tegra_snd_trimslice_probe(str
+ if (!trimslice_tlv320aic23_dai.codecs->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ trimslice_tlv320aic23_dai.cpus->of_node = of_parse_phandle(np,
+@@ -134,8 +133,7 @@ static int tegra_snd_trimslice_probe(str
+ if (!trimslice_tlv320aic23_dai.cpus->of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+- ret = -EINVAL;
+- goto err;
++ return -EINVAL;
+ }
+
+ trimslice_tlv320aic23_dai.platforms->of_node =
+@@ -143,32 +141,24 @@ static int tegra_snd_trimslice_probe(str
+
+ ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
+ if (ret)
+- goto err;
++ return ret;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+- goto err_fini_utils;
++ return ret;
+ }
+
+ return 0;
+-
+-err_fini_utils:
+- tegra_asoc_utils_fini(&trimslice->util_data);
+-err:
+- return ret;
+ }
+
+ static int tegra_snd_trimslice_remove(struct platform_device *pdev)
+ {
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+- struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+- tegra_asoc_utils_fini(&trimslice->util_data);
+-
+ return 0;
+ }
+
--- /dev/null
+From b5ac98cbb8e5e30c34ebc837d1e5a3982d2b5f5c Mon Sep 17 00:00:00 2001
+From: Marius Iacob <themariusus@gmail.com>
+Date: Sat, 1 Aug 2020 15:34:46 +0300
+Subject: drm: Added orientation quirk for ASUS tablet model T103HAF
+
+From: Marius Iacob <themariusus@gmail.com>
+
+commit b5ac98cbb8e5e30c34ebc837d1e5a3982d2b5f5c upstream.
+
+Signed-off-by: Marius Iacob <themariusus@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Link: https://patchwork.freedesktop.org/patch/msgid/20200801123445.1514567-1-themariusus@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/drm_panel_orientation_quirks.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/gpu/drm/drm_panel_orientation_quirks.c
++++ b/drivers/gpu/drm/drm_panel_orientation_quirks.c
+@@ -121,6 +121,12 @@ static const struct dmi_system_id orient
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T101HA"),
+ },
+ .driver_data = (void *)&lcd800x1280_rightside_up,
++ }, { /* Asus T103HAF */
++ .matches = {
++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T103HAF"),
++ },
++ .driver_data = (void *)&lcd800x1280_rightside_up,
+ }, { /* GPD MicroPC (generic strings, also match on bios date) */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Default string"),
--- /dev/null
+From 8b0379a85762b516c7b46aed7dbf2a4947c00564 Mon Sep 17 00:00:00 2001
+From: hersen wu <hersenxs.wu@amd.com>
+Date: Sun, 19 Jul 2020 17:21:59 -0400
+Subject: drm/amd/display: dchubbub p-state warning during surface planes switch
+
+From: hersen wu <hersenxs.wu@amd.com>
+
+commit 8b0379a85762b516c7b46aed7dbf2a4947c00564 upstream.
+
+[Why]
+ramp_up_dispclk_with_dpp is to change dispclk, dppclk and dprefclk
+according to bandwidth requirement. call stack: rv1_update_clocks -->
+update_clocks --> dcn10_prepare_bandwidth / dcn10_optimize_bandwidth
+--> prepare_bandwidth / optimize_bandwidth. before change dcn hw,
+prepare_bandwidth will be called first to allow enough clock,
+watermark for change, after end of dcn hw change, optimize_bandwidth
+is executed to lower clock to save power for new dcn hw settings.
+
+below is sequence of commit_planes_for_stream:
+step 1: prepare_bandwidth - raise clock to have enough bandwidth
+step 2: lock_doublebuffer_enable
+step 3: pipe_control_lock(true) - make dchubp register change will
+not take effect right way
+step 4: apply_ctx_for_surface - program dchubp
+step 5: pipe_control_lock(false) - dchubp register change take effect
+step 6: optimize_bandwidth --> dc_post_update_surfaces_to_stream
+for full_date, optimize clock to save power
+
+at end of step 1, dcn clocks (dprefclk, dispclk, dppclk) may be
+changed for new dchubp configuration. but real dcn hub dchubps are
+still running with old configuration until end of step 5. this need
+clocks settings at step 1 should not less than that before step 1.
+this is checked by two conditions: 1. if (should_set_clock(safe_to_lower
+, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) ||
+new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz)
+2. request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz
+
+the second condition is based on new dchubp configuration. dppclk
+for new dchubp may be different from dppclk before step 1.
+for example, before step 1, dchubps are as below:
+pipe 0: recout=(0,40,1920,980) viewport=(0,0,1920,979)
+pipe 1: recout=(0,0,1920,1080) viewport=(0,0,1920,1080)
+for dppclk for pipe0 need dppclk = dispclk
+
+new dchubp pipe split configuration:
+pipe 0: recout=(0,0,960,1080) viewport=(0,0,960,1080)
+pipe 1: recout=(960,0,960,1080) viewport=(960,0,960,1080)
+dppclk only needs dppclk = dispclk /2.
+
+dispclk, dppclk are not lock by otg master lock. they take effect
+after step 1. during this transition, dispclk are the same, but
+dppclk is changed to half of previous clock for old dchubp
+configuration between step 1 and step 6. This may cause p-state
+warning intermittently.
+
+[How]
+for new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz, we
+need make sure dppclk are not changed to less between step 1 and 6.
+for new_clocks->dispclk_khz > clk_mgr_base->clks.dispclk_khz,
+new display clock is raised, but we do not know ratio of
+new_clocks->dispclk_khz and clk_mgr_base->clks.dispclk_khz,
+new_clocks->dispclk_khz /2 does not guarantee equal or higher than
+old dppclk. we could ignore power saving different between
+dppclk = displck and dppclk = dispclk / 2 between step 1 and step 6.
+as long as safe_to_lower = false, set dpclk = dispclk to simplify
+condition check.
+
+CC: Stable <stable@vger.kernel.org>
+Signed-off-by: Hersen Wu <hersenxs.wu@amd.com>
+Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
+Acked-by: Eryk Brol <eryk.brol@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c | 69 ++++++++++++-
+ 1 file changed, 67 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr.c
+@@ -85,12 +85,77 @@ static int rv1_determine_dppclk_threshol
+ return disp_clk_threshold;
+ }
+
+-static void ramp_up_dispclk_with_dpp(struct clk_mgr_internal *clk_mgr, struct dc *dc, struct dc_clocks *new_clocks)
++static void ramp_up_dispclk_with_dpp(
++ struct clk_mgr_internal *clk_mgr,
++ struct dc *dc,
++ struct dc_clocks *new_clocks,
++ bool safe_to_lower)
+ {
+ int i;
+ int dispclk_to_dpp_threshold = rv1_determine_dppclk_threshold(clk_mgr, new_clocks);
+ bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz;
+
++ /* this function is to change dispclk, dppclk and dprefclk according to
++ * bandwidth requirement. Its call stack is rv1_update_clocks -->
++ * update_clocks --> dcn10_prepare_bandwidth / dcn10_optimize_bandwidth
++ * --> prepare_bandwidth / optimize_bandwidth. before change dcn hw,
++ * prepare_bandwidth will be called first to allow enough clock,
++ * watermark for change, after end of dcn hw change, optimize_bandwidth
++ * is executed to lower clock to save power for new dcn hw settings.
++ *
++ * below is sequence of commit_planes_for_stream:
++ *
++ * step 1: prepare_bandwidth - raise clock to have enough bandwidth
++ * step 2: lock_doublebuffer_enable
++ * step 3: pipe_control_lock(true) - make dchubp register change will
++ * not take effect right way
++ * step 4: apply_ctx_for_surface - program dchubp
++ * step 5: pipe_control_lock(false) - dchubp register change take effect
++ * step 6: optimize_bandwidth --> dc_post_update_surfaces_to_stream
++ * for full_date, optimize clock to save power
++ *
++ * at end of step 1, dcn clocks (dprefclk, dispclk, dppclk) may be
++ * changed for new dchubp configuration. but real dcn hub dchubps are
++ * still running with old configuration until end of step 5. this need
++ * clocks settings at step 1 should not less than that before step 1.
++ * this is checked by two conditions: 1. if (should_set_clock(safe_to_lower
++ * , new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) ||
++ * new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz)
++ * 2. request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz
++ *
++ * the second condition is based on new dchubp configuration. dppclk
++ * for new dchubp may be different from dppclk before step 1.
++ * for example, before step 1, dchubps are as below:
++ * pipe 0: recout=(0,40,1920,980) viewport=(0,0,1920,979)
++ * pipe 1: recout=(0,0,1920,1080) viewport=(0,0,1920,1080)
++ * for dppclk for pipe0 need dppclk = dispclk
++ *
++ * new dchubp pipe split configuration:
++ * pipe 0: recout=(0,0,960,1080) viewport=(0,0,960,1080)
++ * pipe 1: recout=(960,0,960,1080) viewport=(960,0,960,1080)
++ * dppclk only needs dppclk = dispclk /2.
++ *
++ * dispclk, dppclk are not lock by otg master lock. they take effect
++ * after step 1. during this transition, dispclk are the same, but
++ * dppclk is changed to half of previous clock for old dchubp
++ * configuration between step 1 and step 6. This may cause p-state
++ * warning intermittently.
++ *
++ * for new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz, we
++ * need make sure dppclk are not changed to less between step 1 and 6.
++ * for new_clocks->dispclk_khz > clk_mgr_base->clks.dispclk_khz,
++ * new display clock is raised, but we do not know ratio of
++ * new_clocks->dispclk_khz and clk_mgr_base->clks.dispclk_khz,
++ * new_clocks->dispclk_khz /2 does not guarantee equal or higher than
++ * old dppclk. we could ignore power saving different between
++ * dppclk = displck and dppclk = dispclk / 2 between step 1 and step 6.
++ * as long as safe_to_lower = false, set dpclk = dispclk to simplify
++ * condition check.
++ * todo: review this change for other asic.
++ **/
++ if (!safe_to_lower)
++ request_dpp_div = false;
++
+ /* set disp clk to dpp clk threshold */
+
+ clk_mgr->funcs->set_dispclk(clk_mgr, dispclk_to_dpp_threshold);
+@@ -209,7 +274,7 @@ static void rv1_update_clocks(struct clk
+ /* program dispclk on = as a w/a for sleep resume clock ramping issues */
+ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)
+ || new_clocks->dispclk_khz == clk_mgr_base->clks.dispclk_khz) {
+- ramp_up_dispclk_with_dpp(clk_mgr, dc, new_clocks);
++ ramp_up_dispclk_with_dpp(clk_mgr, dc, new_clocks, safe_to_lower);
+ clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
+ send_request_to_lower = true;
+ }
--- /dev/null
+From c5892a10218214d729699ab61bad6fc109baf0ce Mon Sep 17 00:00:00 2001
+From: Stylon Wang <stylon.wang@amd.com>
+Date: Tue, 30 Jun 2020 17:55:29 +0800
+Subject: drm/amd/display: Fix dmesg warning from setting abm level
+
+From: Stylon Wang <stylon.wang@amd.com>
+
+commit c5892a10218214d729699ab61bad6fc109baf0ce upstream.
+
+[Why]
+Setting abm level does not correctly update CRTC state. As a result
+no surface update is added to dc stream state and triggers warning.
+
+[How]
+Correctly update CRTC state when setting abm level property.
+
+CC: Stable <stable@vger.kernel.org>
+Signed-off-by: Stylon Wang <stylon.wang@amd.com>
+Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
+Acked-by: Eryk Brol <eryk.brol@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 23 ++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -8458,6 +8458,29 @@ static int amdgpu_dm_atomic_check(struct
+ if (ret)
+ goto fail;
+
++ /* Check connector changes */
++ for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
++ struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
++ struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
++
++ /* Skip connectors that are disabled or part of modeset already. */
++ if (!old_con_state->crtc && !new_con_state->crtc)
++ continue;
++
++ if (!new_con_state->crtc)
++ continue;
++
++ new_crtc_state = drm_atomic_get_crtc_state(state, new_con_state->crtc);
++ if (IS_ERR(new_crtc_state)) {
++ ret = PTR_ERR(new_crtc_state);
++ goto fail;
++ }
++
++ if (dm_old_con_state->abm_level !=
++ dm_new_con_state->abm_level)
++ new_crtc_state->connectors_changed = true;
++ }
++
+ #if defined(CONFIG_DRM_AMD_DC_DCN)
+ if (!compute_mst_dsc_configs_for_state(state, dm_state->context))
+ goto fail;
--- /dev/null
+From f87812284172a9809820d10143b573d833cd3f75 Mon Sep 17 00:00:00 2001
+From: Sandeep Raghuraman <sandy.8925@gmail.com>
+Date: Thu, 6 Aug 2020 22:52:20 +0530
+Subject: drm/amdgpu: Fix bug where DPM is not enabled after hibernate and resume
+
+From: Sandeep Raghuraman <sandy.8925@gmail.com>
+
+commit f87812284172a9809820d10143b573d833cd3f75 upstream.
+
+Reproducing bug report here:
+After hibernating and resuming, DPM is not enabled. This remains the case
+even if you test hibernate using the steps here:
+https://www.kernel.org/doc/html/latest/power/basic-pm-debugging.html
+
+I debugged the problem, and figured out that in the file hardwaremanager.c,
+in the function, phm_enable_dynamic_state_management(), the check
+'if (!hwmgr->pp_one_vf && smum_is_dpm_running(hwmgr) && !amdgpu_passthrough(adev) && adev->in_suspend)'
+returns true for the hibernate case, and false for the suspend case.
+
+This means that for the hibernate case, the AMDGPU driver doesn't enable DPM
+(even though it should) and simply returns from that function.
+In the suspend case, it goes ahead and enables DPM, even though it doesn't need to.
+
+I debugged further, and found out that in the case of suspend, for the
+CIK/Hawaii GPUs, smum_is_dpm_running(hwmgr) returns false, while in the case of
+hibernate, smum_is_dpm_running(hwmgr) returns true.
+
+For CIK, the ci_is_dpm_running() function calls the ci_is_smc_ram_running() function,
+which is ultimately used to determine if DPM is currently enabled or not,
+and this seems to provide the wrong answer.
+
+I've changed the ci_is_dpm_running() function to instead use the same method that
+some other AMD GPU chips do (e.g Fiji), which seems to read the voltage controller.
+I've tested on my R9 390 and it seems to work correctly for both suspend and
+hibernate use cases, and has been stable so far.
+
+Bug: https://bugzilla.kernel.org/show_bug.cgi?id=208839
+Signed-off-by: Sandeep Raghuraman <sandy.8925@gmail.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c
++++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c
+@@ -2725,7 +2725,10 @@ static int ci_initialize_mc_reg_table(st
+
+ static bool ci_is_dpm_running(struct pp_hwmgr *hwmgr)
+ {
+- return ci_is_smc_ram_running(hwmgr);
++ return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device,
++ CGS_IND_REG__SMC, FEATURE_STATUS,
++ VOLTAGE_CONTROLLER_ON))
++ ? true : false;
+ }
+
+ static int ci_smu_init(struct pp_hwmgr *hwmgr)
--- /dev/null
+From alexdeucher@gmail.com Thu Aug 20 10:36:01 2020
+From: Alex Deucher <alexdeucher@gmail.com>
+Date: Thu, 6 Aug 2020 10:49:39 -0400
+Subject: drm/amdgpu: fix ordering of psp suspend
+To: stable@vger.kernel.org
+Cc: Alex Deucher <alexander.deucher@amd.com>, Huang Rui <ray.huang@amd.com>
+Message-ID: <20200806144939.466297-1-alexander.deucher@amd.com>
+
+From: Alex Deucher <alexdeucher@gmail.com>
+
+The ordering of psp_tmr_terminate() and psp_asd_unload()
+got reversed when the patches were applied to stable.
+
+This patch does not exist in Linus' tree because the ordering
+is correct there. It got reversed when the patches were applied
+to stable. This patch is for stable only.
+
+Fixes: 22ff658396b446 ("drm/amdgpu: asd function needs to be unloaded in suspend phase")
+Fixes: 2c41c968c6f648 ("drm/amdgpu: add TMR destory function for psp")
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org # 5.7.x
+Cc: Huang Rui <ray.huang@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
+@@ -1679,15 +1679,15 @@ static int psp_suspend(void *handle)
+ }
+ }
+
+- ret = psp_tmr_terminate(psp);
++ ret = psp_asd_unload(psp);
+ if (ret) {
+- DRM_ERROR("Falied to terminate tmr\n");
++ DRM_ERROR("Failed to unload asd\n");
+ return ret;
+ }
+
+- ret = psp_asd_unload(psp);
++ ret = psp_tmr_terminate(psp);
+ if (ret) {
+- DRM_ERROR("Failed to unload asd\n");
++ DRM_ERROR("Falied to terminate tmr\n");
+ return ret;
+ }
+
--- /dev/null
+From d8bd15b37d328a935a4fc695fed8b19157503950 Mon Sep 17 00:00:00 2001
+From: Imre Deak <imre.deak@intel.com>
+Date: Mon, 8 Jun 2020 00:25:21 +0300
+Subject: drm/dp_mst: Fix the DDC I2C device registration of an MST port
+
+From: Imre Deak <imre.deak@intel.com>
+
+commit d8bd15b37d328a935a4fc695fed8b19157503950 upstream.
+
+During the initial MST probing an MST port's I2C device will be
+registered using the kdev of the DRM device as a parent. Later after MST
+Connection Status Notifications this I2C device will be re-registered
+with the kdev of the port's connector. This will also move
+inconsistently the I2C device's sysfs entry from the DRM device's sysfs
+dir to the connector's dir.
+
+Fix the above by keeping the DRM kdev as the parent of the I2C device.
+
+Ideally the connector's kdev would be used as a parent, similarly to
+non-MST connectors, however that needs some more refactoring to ensure
+the connector's kdev is already available early enough. So keep the
+existing (initial) behavior for now.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Imre Deak <imre.deak@intel.com>
+Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
+Reviewed-by: Lyude Paul <lyude@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20200607212522.16935-2-imre.deak@intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/drm_dp_mst_topology.c | 28 ++++++++++++++++------------
+ 1 file changed, 16 insertions(+), 12 deletions(-)
+
+--- a/drivers/gpu/drm/drm_dp_mst_topology.c
++++ b/drivers/gpu/drm/drm_dp_mst_topology.c
+@@ -88,8 +88,8 @@ static int drm_dp_send_enum_path_resourc
+ static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
+ u8 *guid);
+
+-static int drm_dp_mst_register_i2c_bus(struct drm_dp_aux *aux);
+-static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_aux *aux);
++static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port);
++static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port);
+ static void drm_dp_mst_kick_tx(struct drm_dp_mst_topology_mgr *mgr);
+
+ #define DBG_PREFIX "[dp_mst]"
+@@ -1981,7 +1981,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_po
+ }
+
+ /* remove i2c over sideband */
+- drm_dp_mst_unregister_i2c_bus(&port->aux);
++ drm_dp_mst_unregister_i2c_bus(port);
+ } else {
+ mutex_lock(&mgr->lock);
+ drm_dp_mst_topology_put_mstb(port->mstb);
+@@ -1996,7 +1996,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_po
+ if (port->pdt != DP_PEER_DEVICE_NONE) {
+ if (drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
+ /* add i2c over sideband */
+- ret = drm_dp_mst_register_i2c_bus(&port->aux);
++ ret = drm_dp_mst_register_i2c_bus(port);
+ } else {
+ lct = drm_dp_calculate_rad(port, rad);
+ mstb = drm_dp_add_mst_branch_device(lct, rad);
+@@ -5406,22 +5406,26 @@ static const struct i2c_algorithm drm_dp
+
+ /**
+ * drm_dp_mst_register_i2c_bus() - register an I2C adapter for I2C-over-AUX
+- * @aux: DisplayPort AUX channel
++ * @port: The port to add the I2C bus on
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+-static int drm_dp_mst_register_i2c_bus(struct drm_dp_aux *aux)
++static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port)
+ {
++ struct drm_dp_aux *aux = &port->aux;
++ struct device *parent_dev = port->mgr->dev->dev;
++
+ aux->ddc.algo = &drm_dp_mst_i2c_algo;
+ aux->ddc.algo_data = aux;
+ aux->ddc.retries = 3;
+
+ aux->ddc.class = I2C_CLASS_DDC;
+ aux->ddc.owner = THIS_MODULE;
+- aux->ddc.dev.parent = aux->dev;
+- aux->ddc.dev.of_node = aux->dev->of_node;
++ /* FIXME: set the kdev of the port's connector as parent */
++ aux->ddc.dev.parent = parent_dev;
++ aux->ddc.dev.of_node = parent_dev->of_node;
+
+- strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
++ strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(parent_dev),
+ sizeof(aux->ddc.name));
+
+ return i2c_add_adapter(&aux->ddc);
+@@ -5429,11 +5433,11 @@ static int drm_dp_mst_register_i2c_bus(s
+
+ /**
+ * drm_dp_mst_unregister_i2c_bus() - unregister an I2C-over-AUX adapter
+- * @aux: DisplayPort AUX channel
++ * @port: The port to remove the I2C bus from
+ */
+-static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_aux *aux)
++static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port)
+ {
+- i2c_del_adapter(&aux->ddc);
++ i2c_del_adapter(&port->aux.ddc);
+ }
+
+ /**
--- /dev/null
+From a34a0a632dd991a371fec56431d73279f9c54029 Mon Sep 17 00:00:00 2001
+From: Xin Xiong <xiongx18@fudan.edu.cn>
+Date: Sun, 19 Jul 2020 23:45:45 +0800
+Subject: drm: fix drm_dp_mst_port refcount leaks in drm_dp_mst_allocate_vcpi
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Xin Xiong <xiongx18@fudan.edu.cn>
+
+commit a34a0a632dd991a371fec56431d73279f9c54029 upstream.
+
+drm_dp_mst_allocate_vcpi() invokes
+drm_dp_mst_topology_get_port_validated(), which increases the refcount
+of the "port".
+
+These reference counting issues take place in two exception handling
+paths separately. Either when “slots” is less than 0 or when
+drm_dp_init_vcpi() returns a negative value, the function forgets to
+reduce the refcnt increased drm_dp_mst_topology_get_port_validated(),
+which results in a refcount leak.
+
+Fix these issues by pulling up the error handling when "slots" is less
+than 0, and calling drm_dp_mst_topology_put_port() before termination
+when drm_dp_init_vcpi() returns a negative value.
+
+Fixes: 1e797f556c61 ("drm/dp: Split drm_dp_mst_allocate_vcpi")
+Cc: <stable@vger.kernel.org> # v4.12+
+Signed-off-by: Xiyu Yang <xiyuyang19@fudan.edu.cn>
+Signed-off-by: Xin Tan <tanxin.ctf@gmail.com>
+Signed-off-by: Xin Xiong <xiongx18@fudan.edu.cn>
+Reviewed-by: Lyude Paul <lyude@redhat.com>
+Signed-off-by: Lyude Paul <lyude@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20200719154545.GA41231@xin-virtual-machine
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/drm_dp_mst_topology.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/drivers/gpu/drm/drm_dp_mst_topology.c
++++ b/drivers/gpu/drm/drm_dp_mst_topology.c
+@@ -4319,11 +4319,11 @@ bool drm_dp_mst_allocate_vcpi(struct drm
+ {
+ int ret;
+
+- port = drm_dp_mst_topology_get_port_validated(mgr, port);
+- if (!port)
++ if (slots < 0)
+ return false;
+
+- if (slots < 0)
++ port = drm_dp_mst_topology_get_port_validated(mgr, port);
++ if (!port)
+ return false;
+
+ if (port->vcpi.vcpi > 0) {
+@@ -4339,6 +4339,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm
+ if (ret) {
+ DRM_DEBUG_KMS("failed to init vcpi slots=%d max=63 ret=%d\n",
+ DIV_ROUND_UP(pbn, mgr->pbn_div), ret);
++ drm_dp_mst_topology_put_port(port);
+ goto out;
+ }
+ DRM_DEBUG_KMS("initing vcpi for pbn=%d slots=%d\n",
--- /dev/null
+From 7c4541a37bbbf83c0f16f779e85eb61d9348ed29 Mon Sep 17 00:00:00 2001
+From: Chris Wilson <chris@chris-wilson.co.uk>
+Date: Mon, 25 May 2020 16:14:59 +0100
+Subject: drm/i915/gt: Force the GT reset on shutdown
+
+From: Chris Wilson <chris@chris-wilson.co.uk>
+
+commit 7c4541a37bbbf83c0f16f779e85eb61d9348ed29 upstream.
+
+Before we return control to the system, and letting it reuse all the
+pages being accessed by HW, we must disable the HW. At the moment, we
+dare not reset the GPU if it will clobber the display, but once we know
+the display has been disabled, we can proceed with the reset as we
+shutdown the module. We know the next user must reinitialise the HW for
+their purpose.
+
+Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/489
+Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
+Cc: stable@kernel.org
+Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20200525151459.12083-1-chris@chris-wilson.co.uk
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/i915/gt/intel_gt.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/gpu/drm/i915/gt/intel_gt.c
++++ b/drivers/gpu/drm/i915/gt/intel_gt.c
+@@ -656,6 +656,11 @@ void intel_gt_driver_unregister(struct i
+ void intel_gt_driver_release(struct intel_gt *gt)
+ {
+ struct i915_address_space *vm;
++ intel_wakeref_t wakeref;
++
++ /* Scrub all HW state upon release */
++ with_intel_runtime_pm(gt->uncore->rpm, wakeref)
++ __intel_gt_reset(gt, ALL_ENGINES);
+
+ vm = fetch_and_zero(>->vm);
+ if (vm) /* FIXME being called twice on error paths :( */
--- /dev/null
+From ecfdedd7da5d54416db5ca0f851264dca8736f59 Mon Sep 17 00:00:00 2001
+From: Tomi Valkeinen <tomi.valkeinen@ti.com>
+Date: Thu, 18 Jun 2020 12:51:52 +0300
+Subject: drm/omap: force runtime PM suspend on system suspend
+
+From: Tomi Valkeinen <tomi.valkeinen@ti.com>
+
+commit ecfdedd7da5d54416db5ca0f851264dca8736f59 upstream.
+
+Use SET_LATE_SYSTEM_SLEEP_PM_OPS in DSS submodules to force runtime PM
+suspend and resume.
+
+We use suspend late version so that omapdrm's system suspend callback is
+called first, as that will disable all the display outputs after which
+it's safe to force DSS into suspend.
+
+Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20200618095153.611071-1-tomi.valkeinen@ti.com
+Acked-by: Tony Lindgren <tony@atomide.com>
+Fixes: cef766300353 ("drm/omap: Prepare DSS for probing without legacy platform data")
+Cc: stable@vger.kernel.org # v5.7+
+Tested-by: Tony Lindgren <tony@atomide.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/omapdrm/dss/dispc.c | 1 +
+ drivers/gpu/drm/omapdrm/dss/dsi.c | 1 +
+ drivers/gpu/drm/omapdrm/dss/dss.c | 1 +
+ drivers/gpu/drm/omapdrm/dss/venc.c | 1 +
+ 4 files changed, 4 insertions(+)
+
+--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
++++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
+@@ -4936,6 +4936,7 @@ static int dispc_runtime_resume(struct d
+ static const struct dev_pm_ops dispc_pm_ops = {
+ .runtime_suspend = dispc_runtime_suspend,
+ .runtime_resume = dispc_runtime_resume,
++ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ };
+
+ struct platform_driver omap_dispchw_driver = {
+--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
++++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
+@@ -5467,6 +5467,7 @@ static int dsi_runtime_resume(struct dev
+ static const struct dev_pm_ops dsi_pm_ops = {
+ .runtime_suspend = dsi_runtime_suspend,
+ .runtime_resume = dsi_runtime_resume,
++ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ };
+
+ struct platform_driver omap_dsihw_driver = {
+--- a/drivers/gpu/drm/omapdrm/dss/dss.c
++++ b/drivers/gpu/drm/omapdrm/dss/dss.c
+@@ -1614,6 +1614,7 @@ static int dss_runtime_resume(struct dev
+ static const struct dev_pm_ops dss_pm_ops = {
+ .runtime_suspend = dss_runtime_suspend,
+ .runtime_resume = dss_runtime_resume,
++ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ };
+
+ struct platform_driver omap_dsshw_driver = {
+--- a/drivers/gpu/drm/omapdrm/dss/venc.c
++++ b/drivers/gpu/drm/omapdrm/dss/venc.c
+@@ -945,6 +945,7 @@ static int venc_runtime_resume(struct de
+ static const struct dev_pm_ops venc_pm_ops = {
+ .runtime_suspend = venc_runtime_suspend,
+ .runtime_resume = venc_runtime_resume,
++ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ };
+
+ static const struct of_device_id venc_of_match[] = {
--- /dev/null
+From 114427b8927a4def2942b2b886f7e4aeae289ccb Mon Sep 17 00:00:00 2001
+From: Denis Efremov <efremov@linux.com>
+Date: Mon, 8 Jun 2020 18:17:28 +0300
+Subject: drm/panfrost: Use kvfree() to free bo->sgts
+
+From: Denis Efremov <efremov@linux.com>
+
+commit 114427b8927a4def2942b2b886f7e4aeae289ccb upstream.
+
+Use kvfree() to free bo->sgts, because the memory is allocated with
+kvmalloc_array() in panfrost_mmu_map_fault_addr().
+
+Fixes: 187d2929206e ("drm/panfrost: Add support for GPU heap allocations")
+Cc: stable@vger.kernel.org
+Signed-off-by: Denis Efremov <efremov@linux.com>
+Reviewed-by: Steven Price <steven.price@arm.com>
+Signed-off-by: Steven Price <steven.price@arm.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20200608151728.234026-1-efremov@linux.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/panfrost/panfrost_gem.c | 2 +-
+ drivers/gpu/drm/panfrost/panfrost_mmu.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/gpu/drm/panfrost/panfrost_gem.c
++++ b/drivers/gpu/drm/panfrost/panfrost_gem.c
+@@ -46,7 +46,7 @@ static void panfrost_gem_free_object(str
+ sg_free_table(&bo->sgts[i]);
+ }
+ }
+- kfree(bo->sgts);
++ kvfree(bo->sgts);
+ }
+
+ drm_gem_shmem_free_object(obj);
+--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
++++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
+@@ -486,7 +486,7 @@ static int panfrost_mmu_map_fault_addr(s
+ pages = kvmalloc_array(bo->base.base.size >> PAGE_SHIFT,
+ sizeof(struct page *), GFP_KERNEL | __GFP_ZERO);
+ if (!pages) {
+- kfree(bo->sgts);
++ kvfree(bo->sgts);
+ bo->sgts = NULL;
+ mutex_unlock(&bo->base.pages_lock);
+ ret = -ENOMEM;
--- /dev/null
+From f29aa08852e1953e461f2d47ab13c34e14bc08b3 Mon Sep 17 00:00:00 2001
+From: Denis Efremov <efremov@linux.com>
+Date: Mon, 22 Jun 2020 23:31:22 +0300
+Subject: drm/radeon: fix fb_div check in ni_init_smc_spll_table()
+
+From: Denis Efremov <efremov@linux.com>
+
+commit f29aa08852e1953e461f2d47ab13c34e14bc08b3 upstream.
+
+clk_s is checked twice in a row in ni_init_smc_spll_table().
+fb_div should be checked instead.
+
+Fixes: 69e0b57a91ad ("drm/radeon/kms: add dpm support for cayman (v5)")
+Cc: stable@vger.kernel.org
+Signed-off-by: Denis Efremov <efremov@linux.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/radeon/ni_dpm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/radeon/ni_dpm.c
++++ b/drivers/gpu/drm/radeon/ni_dpm.c
+@@ -2124,7 +2124,7 @@ static int ni_init_smc_spll_table(struct
+ if (p_div & ~(SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT))
+ ret = -EINVAL;
+
+- if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
++ if (fb_div & ~(SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT))
+ ret = -EINVAL;
+
+ if (fb_div & ~(SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT))
--- /dev/null
+From a72a6a16d51034045cb6355924b62221a8221ca3 Mon Sep 17 00:00:00 2001
+From: Tomi Valkeinen <tomi.valkeinen@ti.com>
+Date: Thu, 4 Jun 2020 11:02:14 +0300
+Subject: drm/tidss: fix modeset init for DPI panels
+
+From: Tomi Valkeinen <tomi.valkeinen@ti.com>
+
+commit a72a6a16d51034045cb6355924b62221a8221ca3 upstream.
+
+The connector type for DISPC's DPI videoport was set the LVDS instead of
+DPI. This causes any DPI panel setup to fail with tidss, making all DPI
+panels unusable.
+
+Fix this by using correct connector type.
+
+Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
+Fixes: 32a1795f57eecc39749017 ("drm/tidss: New driver for TI Keystone platform Display SubSystem")
+Cc: stable@vger.kernel.org # v5.7+
+Link: https://patchwork.freedesktop.org/patch/msgid/20200604080214.107159-1-tomi.valkeinen@ti.com
+Reviewed-by: Jyri Sarha <jsarha@ti.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/gpu/drm/tidss/tidss_kms.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/gpu/drm/tidss/tidss_kms.c
++++ b/drivers/gpu/drm/tidss/tidss_kms.c
+@@ -154,7 +154,7 @@ static int tidss_dispc_modeset_init(stru
+ break;
+ case DISPC_VP_DPI:
+ enc_type = DRM_MODE_ENCODER_DPI;
+- conn_type = DRM_MODE_CONNECTOR_LVDS;
++ conn_type = DRM_MODE_CONNECTOR_DPI;
+ break;
+ default:
+ WARN_ON(1);
--- /dev/null
+From 18e77600f7a1ed69f8ce46c9e11cad0985712dfa Mon Sep 17 00:00:00 2001
+From: Hugh Dickins <hughd@google.com>
+Date: Thu, 6 Aug 2020 23:26:22 -0700
+Subject: khugepaged: retract_page_tables() remember to test exit
+
+From: Hugh Dickins <hughd@google.com>
+
+commit 18e77600f7a1ed69f8ce46c9e11cad0985712dfa upstream.
+
+Only once have I seen this scenario (and forgot even to notice what forced
+the eventual crash): a sequence of "BUG: Bad page map" alerts from
+vm_normal_page(), from zap_pte_range() servicing exit_mmap();
+pmd:00000000, pte values corresponding to data in physical page 0.
+
+The pte mappings being zapped in this case were supposed to be from a huge
+page of ext4 text (but could as well have been shmem): my belief is that
+it was racing with collapse_file()'s retract_page_tables(), found *pmd
+pointing to a page table, locked it, but *pmd had become 0 by the time
+start_pte was decided.
+
+In most cases, that possibility is excluded by holding mmap lock; but
+exit_mmap() proceeds without mmap lock. Most of what's run by khugepaged
+checks khugepaged_test_exit() after acquiring mmap lock:
+khugepaged_collapse_pte_mapped_thps() and hugepage_vma_revalidate() do so,
+for example. But retract_page_tables() did not: fix that.
+
+The fix is for retract_page_tables() to check khugepaged_test_exit(),
+after acquiring mmap lock, before doing anything to the page table.
+Getting the mmap lock serializes with __mmput(), which briefly takes and
+drops it in __khugepaged_exit(); then the khugepaged_test_exit() check on
+mm_users makes sure we don't touch the page table once exit_mmap() might
+reach it, since exit_mmap() will be proceeding without mmap lock, not
+expecting anyone to be racing with it.
+
+Fixes: f3f0e1d2150b ("khugepaged: add support of collapse for tmpfs/shmem pages")
+Signed-off-by: Hugh Dickins <hughd@google.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Mike Kravetz <mike.kravetz@oracle.com>
+Cc: Song Liu <songliubraving@fb.com>
+Cc: <stable@vger.kernel.org> [4.8+]
+Link: http://lkml.kernel.org/r/alpine.LSU.2.11.2008021215400.27773@eggly.anvils
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ mm/khugepaged.c | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+--- a/mm/khugepaged.c
++++ b/mm/khugepaged.c
+@@ -1433,6 +1433,7 @@ out:
+ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
+ {
+ struct vm_area_struct *vma;
++ struct mm_struct *mm;
+ unsigned long addr;
+ pmd_t *pmd, _pmd;
+
+@@ -1461,7 +1462,8 @@ static void retract_page_tables(struct a
+ continue;
+ if (vma->vm_end < addr + HPAGE_PMD_SIZE)
+ continue;
+- pmd = mm_find_pmd(vma->vm_mm, addr);
++ mm = vma->vm_mm;
++ pmd = mm_find_pmd(mm, addr);
+ if (!pmd)
+ continue;
+ /*
+@@ -1471,17 +1473,19 @@ static void retract_page_tables(struct a
+ * mmap_sem while holding page lock. Fault path does it in
+ * reverse order. Trylock is a way to avoid deadlock.
+ */
+- if (down_write_trylock(&vma->vm_mm->mmap_sem)) {
+- spinlock_t *ptl = pmd_lock(vma->vm_mm, pmd);
+- /* assume page table is clear */
+- _pmd = pmdp_collapse_flush(vma, addr, pmd);
+- spin_unlock(ptl);
+- up_write(&vma->vm_mm->mmap_sem);
+- mm_dec_nr_ptes(vma->vm_mm);
+- pte_free(vma->vm_mm, pmd_pgtable(_pmd));
++ if (down_write_trylock(&mm->mmap_sem)) {
++ if (!khugepaged_test_exit(mm)) {
++ spinlock_t *ptl = pmd_lock(mm, pmd);
++ /* assume page table is clear */
++ _pmd = pmdp_collapse_flush(vma, addr, pmd);
++ spin_unlock(ptl);
++ mm_dec_nr_ptes(mm);
++ pte_free(mm, pmd_pgtable(_pmd));
++ }
++ up_write(&mm->mmap_sem);
+ } else {
+ /* Try again later */
+- khugepaged_add_pte_mapped_thp(vma->vm_mm, addr);
++ khugepaged_add_pte_mapped_thp(mm, addr);
+ }
+ }
+ i_mmap_unlock_write(mapping);
tools-build-feature-quote-cc-and-cxx-for-their-argum.patch
perf-x86-rapl-fix-missing-psys-sysfs-attributes.patch
sh-landisk-add-missing-initialization-of-sh_io_port_.patch
+khugepaged-retract_page_tables-remember-to-test-exit.patch
+asoc-tegra-use-device-managed-resource-apis-to-get-the-clock.patch
+asoc-tegra-add-audio-mclk-parent-configuration.patch
+asoc-tegra-enable-audio-mclk-during-tegra_asoc_utils_init.patch
+drm-radeon-fix-fb_div-check-in-ni_init_smc_spll_table.patch
+drm-i915-gt-force-the-gt-reset-on-shutdown.patch
+drm-panfrost-use-kvfree-to-free-bo-sgts.patch
+drm-dp_mst-fix-the-ddc-i2c-device-registration-of-an-mst-port.patch
+drm-amdgpu-fix-ordering-of-psp-suspend.patch
+drm-omap-force-runtime-pm-suspend-on-system-suspend.patch
+drm-tidss-fix-modeset-init-for-dpi-panels.patch
+drm-added-orientation-quirk-for-asus-tablet-model-t103haf.patch
+drm-fix-drm_dp_mst_port-refcount-leaks-in-drm_dp_mst_allocate_vcpi.patch
+drm-amdgpu-fix-bug-where-dpm-is-not-enabled-after-hibernate-and-resume.patch
+drm-amd-display-fix-dmesg-warning-from-setting-abm-level.patch
+drm-amd-display-dchubbub-p-state-warning-during-surface-planes-switch.patch