From: Changcheng Deng deng.changcheng@zte.com.cn
[ Upstream commit c1b6ad9a902539f9c037b6b3c35cb134c5724022 ]
do_div() does a 64-by-32 division. Here the divisor is an unsigned long which on some platforms is 64 bit wide. So use div64_ul instead of do_div to avoid a possible truncation.
Reported-by: Zeal Robot zealci@zte.com.cn Signed-off-by: Changcheng Deng deng.changcheng@zte.com.cn Reviewed-by: Abel Vesa abel.vesa@nxp.com Link: https://lore.kernel.org/r/20211118080634.165275-1-deng.changcheng@zte.com.cn Signed-off-by: Abel Vesa abel.vesa@nxp.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/clk/imx/clk-pllv3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index 20ee9611ba6e3..eea32f87c60aa 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -247,7 +247,7 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate, div = rate / parent_rate; temp64 = (u64) (rate - div * parent_rate); temp64 *= mfd; - do_div(temp64, parent_rate); + temp64 = div64_ul(temp64, parent_rate); mfn = temp64;
temp64 = (u64)parent_rate; @@ -277,7 +277,7 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate, div = rate / parent_rate; temp64 = (u64) (rate - div * parent_rate); temp64 *= mfd; - do_div(temp64, parent_rate); + temp64 = div64_ul(temp64, parent_rate); mfn = temp64;
val = readl_relaxed(pll->base); @@ -334,7 +334,7 @@ static struct clk_pllv3_vf610_mf clk_pllv3_vf610_rate_to_mf( /* rate = parent_rate * (mfi + mfn/mfd) */ temp64 = rate - parent_rate * mf.mfi; temp64 *= mf.mfd; - do_div(temp64, parent_rate); + temp64 = div64_ul(temp64, parent_rate); mf.mfn = temp64; }
From: Julia Lawall Julia.Lawall@lip6.fr
[ Upstream commit f6e82647ff71d427d4148964b71f239fba9d7937 ]
for_each_compatible_node performs an of_node_get on each iteration, so a break out of the loop requires an of_node_put.
A simplified version of the semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr):
// <smpl> @@ expression e; local idexpression n; @@
@@ local idexpression n; expression e; @@
for_each_compatible_node(n,...) { ... ( of_node_put(n); | e = n | + of_node_put(n); ? break; ) ... } ... when != n // </smpl>
Signed-off-by: Julia Lawall Julia.Lawall@lip6.fr Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/1448051604-25256-2-git-send-email-Julia.Lawall@lip... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/platforms/embedded6xx/hlwd-pic.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c index 15396333a90bd..a4b020e4b6af0 100644 --- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c +++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c @@ -214,6 +214,7 @@ void hlwd_pic_probe(void) irq_set_chained_handler(cascade_virq, hlwd_pic_irq_cascade); hlwd_irq_host = host; + of_node_put(np); break; } }
From: Julia Lawall Julia.Lawall@lip6.fr
[ Upstream commit 7d405a939ca960162eb30c1475759cb2fdf38f8c ]
for_each_compatible_node performs an of_node_get on each iteration, so a break out of the loop requires an of_node_put.
A simplified version of the semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr):
// <smpl> @@ local idexpression n; expression e; @@
for_each_compatible_node(n,...) { ... ( of_node_put(n); | e = n | + of_node_put(n); ? break; ) ... } ... when != n // </smpl>
Signed-off-by: Julia Lawall Julia.Lawall@lip6.fr Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/1448051604-25256-4-git-send-email-Julia.Lawall@lip... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/platforms/powernv/opal-lpc.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/platforms/powernv/opal-lpc.c b/arch/powerpc/platforms/powernv/opal-lpc.c index 1e5d51db40f84..5390c888db162 100644 --- a/arch/powerpc/platforms/powernv/opal-lpc.c +++ b/arch/powerpc/platforms/powernv/opal-lpc.c @@ -396,6 +396,7 @@ void __init opal_lpc_init(void) if (!of_get_property(np, "primary", NULL)) continue; opal_lpc_chip_id = of_get_ibm_chip_id(np); + of_node_put(np); break; } if (opal_lpc_chip_id < 0)
From: Julia Lawall Julia.Lawall@lip6.fr
[ Upstream commit a841fd009e51c8c0a8f07c942e9ab6bb48da8858 ]
for_each_node_by_name performs an of_node_get on each iteration, so a break out of the loop requires an of_node_put.
A simplified version of the semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr):
// <smpl> @@ expression e,e1; local idexpression n; @@
for_each_node_by_name(n, e1) { ... when != of_node_put(n) when != e = n ( return n; | + of_node_put(n); ? return ...; ) ... } // </smpl>
Signed-off-by: Julia Lawall Julia.Lawall@lip6.fr Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/1448051604-25256-7-git-send-email-Julia.Lawall@lip... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/platforms/cell/iommu.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index fa08699aedeb8..d32f24de84798 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -977,6 +977,7 @@ static int __init cell_iommu_fixed_mapping_init(void) if (hbase < dbase || (hend > (dbase + dsize))) { pr_debug("iommu: hash window doesn't fit in" "real DMA window\n"); + of_node_put(np); return -1; } }
From: Julia Lawall Julia.Lawall@lip6.fr
[ Upstream commit a1d2b210ffa52d60acabbf7b6af3ef7e1e69cda0 ]
for_each_node_by_type performs an of_node_get on each iteration, so a break out of the loop requires an of_node_put.
A simplified version of the semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr):
// <smpl> @@ local idexpression n; expression e; @@
for_each_node_by_type(n,...) { ... ( of_node_put(n); | e = n | + of_node_put(n); ? break; ) ... } ... when != n // </smpl>
Signed-off-by: Julia Lawall Julia.Lawall@lip6.fr Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/1448051604-25256-6-git-send-email-Julia.Lawall@lip... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/kernel/btext.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c index 803c2a45b22ac..1cffb5e7c38d6 100644 --- a/arch/powerpc/kernel/btext.c +++ b/arch/powerpc/kernel/btext.c @@ -241,8 +241,10 @@ int __init btext_find_display(int allow_nonstdout) rc = btext_initialize(np); printk("result: %d\n", rc); } - if (rc == 0) + if (rc == 0) { + of_node_put(np); break; + } } return rc; }
From: Nicholas Piggin npiggin@gmail.com
[ Upstream commit 5dad4ba68a2483fc80d70b9dc90bbe16e1f27263 ]
It is possible for all CPUs to miss the pending cpumask becoming clear, and then nobody resetting it, which will cause the lockup detector to stop working. It will eventually expire, but watchdog_smp_panic will avoid doing anything if the pending mask is clear and it will never be reset.
Order the cpumask clear vs the subsequent test to close this race.
Add an extra check for an empty pending mask when the watchdog fires and finds its bit still clear, to try to catch any other possible races or bugs here and keep the watchdog working. The extra test in arch_touch_nmi_watchdog is required to prevent the new warning from firing off.
Signed-off-by: Nicholas Piggin npiggin@gmail.com Reviewed-by: Laurent Dufour ldufour@linux.ibm.com Debugged-by: Laurent Dufour ldufour@linux.ibm.com Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/20211110025056.2084347-2-npiggin@gmail.com Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/kernel/watchdog.c | 41 +++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c index 3fa6d240bade2..ad94a2c6b7337 100644 --- a/arch/powerpc/kernel/watchdog.c +++ b/arch/powerpc/kernel/watchdog.c @@ -135,6 +135,10 @@ static void set_cpumask_stuck(const struct cpumask *cpumask, u64 tb) { cpumask_or(&wd_smp_cpus_stuck, &wd_smp_cpus_stuck, cpumask); cpumask_andnot(&wd_smp_cpus_pending, &wd_smp_cpus_pending, cpumask); + /* + * See wd_smp_clear_cpu_pending() + */ + smp_mb(); if (cpumask_empty(&wd_smp_cpus_pending)) { wd_smp_last_reset_tb = tb; cpumask_andnot(&wd_smp_cpus_pending, @@ -221,13 +225,44 @@ static void wd_smp_clear_cpu_pending(int cpu, u64 tb)
cpumask_clear_cpu(cpu, &wd_smp_cpus_stuck); wd_smp_unlock(&flags); + } else { + /* + * The last CPU to clear pending should have reset the + * watchdog so we generally should not find it empty + * here if our CPU was clear. However it could happen + * due to a rare race with another CPU taking the + * last CPU out of the mask concurrently. + * + * We can't add a warning for it. But just in case + * there is a problem with the watchdog that is causing + * the mask to not be reset, try to kick it along here. + */ + if (unlikely(cpumask_empty(&wd_smp_cpus_pending))) + goto none_pending; } return; } + cpumask_clear_cpu(cpu, &wd_smp_cpus_pending); + + /* + * Order the store to clear pending with the load(s) to check all + * words in the pending mask to check they are all empty. This orders + * with the same barrier on another CPU. This prevents two CPUs + * clearing the last 2 pending bits, but neither seeing the other's + * store when checking if the mask is empty, and missing an empty + * mask, which ends with a false positive. + */ + smp_mb(); if (cpumask_empty(&wd_smp_cpus_pending)) { unsigned long flags;
+none_pending: + /* + * Double check under lock because more than one CPU could see + * a clear mask with the lockless check after clearing their + * pending bits. + */ wd_smp_lock(&flags); if (cpumask_empty(&wd_smp_cpus_pending)) { wd_smp_last_reset_tb = tb; @@ -318,8 +353,12 @@ void arch_touch_nmi_watchdog(void) { unsigned long ticks = tb_ticks_per_usec * wd_timer_period_ms * 1000; int cpu = smp_processor_id(); - u64 tb = get_tb(); + u64 tb;
+ if (!cpumask_test_cpu(cpu, &watchdog_cpumask)) + return; + + tb = get_tb(); if (tb - per_cpu(wd_timer_tb, cpu) >= ticks) { per_cpu(wd_timer_tb, cpu) = tb; wd_smp_clear_cpu_pending(cpu, tb);
From: Ye Guojin ye.guojin@zte.com.cn
[ Upstream commit f670b274f7f6f4b2722d7f08d0fddf606a727e92 ]
This was found by coccicheck: ./sound/soc/fsl/imx-hdmi.c,209,1-7,ERROR missing put_device; call of_find_device_by_node on line 119, but without a corresponding object release within this function.
Reported-by: Zeal Robot zealci@zte.com.cn Signed-off-by: Ye Guojin ye.guojin@zte.com.cn Link: https://lore.kernel.org/r/20211110002910.134915-1-ye.guojin@zte.com.cn Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/fsl/imx-hdmi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/sound/soc/fsl/imx-hdmi.c b/sound/soc/fsl/imx-hdmi.c index 34a0dceae6216..ef8d7a65ebc61 100644 --- a/sound/soc/fsl/imx-hdmi.c +++ b/sound/soc/fsl/imx-hdmi.c @@ -145,6 +145,8 @@ static int imx_hdmi_probe(struct platform_device *pdev) data->dai.capture_only = false; data->dai.init = imx_hdmi_init;
+ put_device(&cpu_pdev->dev); + if (of_node_name_eq(cpu_np, "sai")) { data->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; data->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
From: Heiner Kallweit hkallweit1@gmail.com
[ Upstream commit effa453168a7eeb8a562ff4edc1dbf9067360a61 ]
If an invalid block size is provided, reject it instead of silently changing it to a supported value. Especially critical I see the case of a write transfer with block length 0. In this case we have no guarantee that the byte we would write is valid. When silently reducing a read to 32 bytes then we don't return an error and the caller may falsely assume that we returned the full requested data.
If this change should break any (broken) caller, then I think we should fix the caller.
Signed-off-by: Heiner Kallweit hkallweit1@gmail.com Reviewed-by: Jean Delvare jdelvare@suse.de Signed-off-by: Wolfram Sang wsa@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/i2c/busses/i2c-i801.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 1f929e6c30bea..98e39a17fb830 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -763,6 +763,11 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data * int result = 0; unsigned char hostc;
+ if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA) + data->block[0] = I2C_SMBUS_BLOCK_MAX; + else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) + return -EPROTO; + if (command == I2C_SMBUS_I2C_BLOCK_DATA) { if (read_write == I2C_SMBUS_WRITE) { /* set I2C_EN bit in configuration register */ @@ -776,16 +781,6 @@ static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data * } }
- if (read_write == I2C_SMBUS_WRITE - || command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (data->block[0] < 1) - data->block[0] = 1; - if (data->block[0] > I2C_SMBUS_BLOCK_MAX) - data->block[0] = I2C_SMBUS_BLOCK_MAX; - } else { - data->block[0] = 32; /* max for SMBus block reads */ - } - /* Experience has shown that the block buffer can only be used for SMBus (not I2C) block transactions, even though the datasheet doesn't mention this limitation. */
From: Michael Ellerman mpe@ellerman.id.au
[ Upstream commit a4ac0d249a5db80e79d573db9e4ad29354b643a8 ]
setup_profiling_timer() is only needed when CONFIG_PROFILING is enabled.
Fixes the following W=1 warning when CONFIG_PROFILING=n: linux/arch/powerpc/kernel/smp.c:1638:5: error: no previous prototype for âsetup_profiling_timerâ
Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/20211124093254.1054750-5-mpe@ellerman.id.au Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/kernel/smp.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 605bab448f847..c7ef0739c8640 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -1640,10 +1640,12 @@ void start_secondary(void *unused) BUG(); }
+#ifdef CONFIG_PROFILING int setup_profiling_timer(unsigned int multiplier) { return 0; } +#endif
static void fixup_topology(void) {
From: Joakim Tjernlund joakim.tjernlund@infinera.com
[ Upstream commit ebe82cf92cd4825c3029434cabfcd2f1780e64be ]
Current I2C reset procedure is broken in two ways: 1) It only generate 1 START instead of 9 STARTs and STOP. 2) It leaves the bus Busy so every I2C xfer after the first fixup calls the reset routine again, for every xfer there after.
This fixes both errors.
Signed-off-by: Joakim Tjernlund joakim.tjernlund@infinera.com Acked-by: Scott Wood oss@buserror.net Signed-off-by: Wolfram Sang wsa@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/i2c/busses/i2c-mpc.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index db26cc36e13fe..6c698c10d3cdb 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -119,23 +119,30 @@ static inline void writeccr(struct mpc_i2c *i2c, u32 x) /* Sometimes 9th clock pulse isn't generated, and slave doesn't release * the bus, because it wants to send ACK. * Following sequence of enabling/disabling and sending start/stop generates - * the 9 pulses, so it's all OK. + * the 9 pulses, each with a START then ending with STOP, so it's all OK. */ static void mpc_i2c_fixup(struct mpc_i2c *i2c) { int k; - u32 delay_val = 1000000 / i2c->real_clk + 1; - - if (delay_val < 2) - delay_val = 2; + unsigned long flags;
for (k = 9; k; k--) { writeccr(i2c, 0); - writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN); + writeb(0, i2c->base + MPC_I2C_SR); /* clear any status bits */ + writeccr(i2c, CCR_MEN | CCR_MSTA); /* START */ + readb(i2c->base + MPC_I2C_DR); /* init xfer */ + udelay(15); /* let it hit the bus */ + local_irq_save(flags); /* should not be delayed further */ + writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSTA); /* delay SDA */ readb(i2c->base + MPC_I2C_DR); - writeccr(i2c, CCR_MEN); - udelay(delay_val << 1); + if (k != 1) + udelay(5); + local_irq_restore(flags); } + writeccr(i2c, CCR_MEN); /* Initiate STOP */ + readb(i2c->base + MPC_I2C_DR); + udelay(15); /* Let STOP propagate */ + writeccr(i2c, 0); }
static int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask)
From: Martin Blumenstingl martin.blumenstingl@googlemail.com
[ Upstream commit ff54938dd190d85f740b9bf9dde59b550936b621 ]
There are reports that 48kHz audio does not work on the WeTek Play 2 (which uses a GXBB SoC), while 44.1kHz audio works fine on the same board. There are also reports of 48kHz audio working fine on GXL and GXM SoCs, which are using an (almost) identical AIU (audio controller).
Experimenting has shown that MPLL0 is causing this problem. In the .dts we have by default: assigned-clocks = <&clkc CLKID_MPLL0>, <&clkc CLKID_MPLL1>, <&clkc CLKID_MPLL2>; assigned-clock-rates = <294912000>, <270950400>, <393216000>; The MPLL0 rate is divisible by 48kHz without remainder and the MPLL1 rate is divisible by 44.1kHz without remainder. Swapping these two clock rates "fixes" 48kHz audio but breaks 44.1kHz audio.
Everything looks normal when looking at the info provided by the common clock framework while playing 48kHz audio (via I2S with mclk-fs = 256): mpll_prediv 1 1 0 2000000000 mpll0_div 1 1 0 294909641 mpll0 1 1 0 294909641 cts_amclk_sel 1 1 0 294909641 cts_amclk_div 1 1 0 12287902 cts_amclk 1 1 0 12287902
meson-clk-msr however shows that the actual MPLL0 clock is off by more than 38MHz: mp0_out 333322917 +/-10416Hz
The rate seen by meson-clk-msr is very close to what we would get when SDM (the fractional part) was ignored: (2000000000Hz * 16384) / ((16384 * 6) = 333.33MHz If SDM was considered the we should get close to: (2000000000Hz * 16384) / ((16384 * 6) + 12808) = 294.9MHz
Further experimenting shows that HHI_MPLL_CNTL7[15] does not have any effect on the rate of MPLL0 as seen my meson-clk-msr (regardless of whether that bit is zero or one the rate is always the same according to meson-clk-msr). Using HHI_MPLL_CNTL[25] on the other hand as SDM_EN results in SDM being considered for the rate output by the hardware. The rate - as seen by meson-clk-msr - matches with what we expect when SDM_EN is enabled (fractional part is being considered, resulting in a 294.9MHz output) or disable (fractional part being ignored, resulting in a 333.33MHz output).
Reported-by: Christian Hewitt christianshewitt@gmail.com Tested-by: Christian Hewitt christianshewitt@gmail.com Signed-off-by: Martin Blumenstingl martin.blumenstingl@googlemail.com Signed-off-by: Jerome Brunet jbrunet@baylibre.com Link: https://lore.kernel.org/r/20211031135006.1508796-1-martin.blumenstingl@googl... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/clk/meson/gxbb.c | 44 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index d6eed760327d0..608e0e8ca49a8 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -713,6 +713,35 @@ static struct clk_regmap gxbb_mpll_prediv = { };
static struct clk_regmap gxbb_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxl_mpll0_div = { .data = &(struct meson_clk_mpll_data){ .sdm = { .reg_off = HHI_MPLL_CNTL7, @@ -749,7 +778,16 @@ static struct clk_regmap gxbb_mpll0 = { .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll0_div.hw }, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * GXL and GXBB have different SDM_EN registers. We + * fallback to the global naming string mechanism so + * mpll0_div picks up the appropriate one. + */ + .name = "mpll0_div", + .index = -1, + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -3044,7 +3082,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB] = &gxbb_vapb.hw, - [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, + [CLKID_MPLL0_DIV] = &gxl_mpll0_div.hw, [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, @@ -3439,7 +3477,7 @@ static struct clk_regmap *const gxl_clk_regmaps[] = { &gxbb_mpll0, &gxbb_mpll1, &gxbb_mpll2, - &gxbb_mpll0_div, + &gxl_mpll0_div, &gxbb_mpll1_div, &gxbb_mpll2_div, &gxbb_cts_amclk_div,
From: Christophe Leroy christophe.leroy@csgroup.eu
[ Upstream commit df1f679d19edb9eeb67cc2f96b29375f21991945 ]
KeyWest i2c @0xf8001003 irq 42 /uni-n@f8000000/i2c@f8001000 BUG: key c2d00cbc has not been registered! ------------[ cut here ]------------ DEBUG_LOCKS_WARN_ON(1) WARNING: CPU: 0 PID: 1 at kernel/locking/lockdep.c:4801 lockdep_init_map_type+0x4c0/0xb4c Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.15.5-gentoo-PowerMacG4 #9 NIP: c01a9428 LR: c01a9428 CTR: 00000000 REGS: e1033cf0 TRAP: 0700 Not tainted (5.15.5-gentoo-PowerMacG4) MSR: 00029032 <EE,ME,IR,DR,RI> CR: 24002002 XER: 00000000
GPR00: c01a9428 e1033db0 c2d1cf20 00000016 00000004 00000001 c01c0630 e1033a73 GPR08: 00000000 00000000 00000000 e1033db0 24002004 00000000 f8729377 00000003 GPR16: c1829a9c 00000000 18305357 c1416fc0 c1416f80 c006ac60 c2d00ca8 c1416f00 GPR24: 00000000 c21586f0 c2160000 00000000 c2d00cbc c2170000 c216e1a0 c2160000 NIP [c01a9428] lockdep_init_map_type+0x4c0/0xb4c LR [c01a9428] lockdep_init_map_type+0x4c0/0xb4c Call Trace: [e1033db0] [c01a9428] lockdep_init_map_type+0x4c0/0xb4c (unreliable) [e1033df0] [c1c177b8] kw_i2c_add+0x334/0x424 [e1033e20] [c1c18294] pmac_i2c_init+0x9ec/0xa9c [e1033e80] [c1c1a790] smp_core99_probe+0xbc/0x35c [e1033eb0] [c1c03cb0] kernel_init_freeable+0x190/0x5a4 [e1033f10] [c000946c] kernel_init+0x28/0x154 [e1033f30] [c0035148] ret_from_kernel_thread+0x14/0x1c
Add missing lockdep_register_key()
Reported-by: Erhard Furtner erhard_f@mailbox.org Signed-off-by: Christophe Leroy christophe.leroy@csgroup.eu Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/69e4f55565bb45ebb0843977801b245af0c666fe.163826474... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/platforms/powermac/low_i2c.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index f77a59b5c2e1a..de34fa34c42d8 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -582,6 +582,7 @@ static void __init kw_i2c_add(struct pmac_i2c_host_kw *host, bus->close = kw_i2c_close; bus->xfer = kw_i2c_xfer; mutex_init(&bus->mutex); + lockdep_register_key(&bus->lock_key); lockdep_set_class(&bus->mutex, &bus->lock_key); if (controller == busnode) bus->flags = pmac_i2c_multibus;
From: Alexey Kardashevskiy aik@ozlabs.ru
[ Upstream commit 511d25d6b789fffcb20a3eb71899cf974a31bd9d ]
The userspace can trigger "vmalloc size %lu allocation failure: exceeds total pages" via the KVM_SET_USER_MEMORY_REGION ioctl.
This silences the warning by checking the limit before calling vzalloc() and returns ENOMEM if failed.
This does not call underlying valloc helpers as __vmalloc_node() is only exported when CONFIG_TEST_VMALLOC_MODULE and __vmalloc_node_range() is not exported at all.
Spotted by syzkaller.
Signed-off-by: Alexey Kardashevskiy aik@ozlabs.ru [mpe: Use 'size' for the variable rather than 'cb'] Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/20210901084512.1658628-1-aik@ozlabs.ru Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/kvm/book3s_hv.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 7b74fc0a986b8..94da0d25eb125 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -4861,8 +4861,12 @@ static int kvmppc_core_prepare_memory_region_hv(struct kvm *kvm, unsigned long npages = mem->memory_size >> PAGE_SHIFT;
if (change == KVM_MR_CREATE) { - slot->arch.rmap = vzalloc(array_size(npages, - sizeof(*slot->arch.rmap))); + unsigned long size = array_size(npages, sizeof(*slot->arch.rmap)); + + if ((size >> PAGE_SHIFT) > totalram_pages()) + return -ENOMEM; + + slot->arch.rmap = vzalloc(size); if (!slot->arch.rmap) return -ENOMEM; }
From: Alexey Kardashevskiy aik@ozlabs.ru
[ Upstream commit 792020907b11c6f9246c21977cab3bad985ae4b6 ]
H_COPY_TOFROM_GUEST is an hcall for an upper level VM to access its nested VMs memory. The userspace can trigger WARN_ON_ONCE(!(gfp & __GFP_NOWARN)) in __alloc_pages() by constructing a tiny VM which only does H_COPY_TOFROM_GUEST with a too big GPR9 (number of bytes to copy).
This silences the warning by adding __GFP_NOWARN.
Spotted by syzkaller.
Signed-off-by: Alexey Kardashevskiy aik@ozlabs.ru Reviewed-by: Fabiano Rosas farosas@linux.ibm.com Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/20210901084550.1658699-1-aik@ozlabs.ru Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/kvm/book3s_hv_nested.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index ed8a2c9f56299..89295b52a97c3 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -582,7 +582,7 @@ long kvmhv_copy_tofrom_guest_nested(struct kvm_vcpu *vcpu) if (eaddr & (0xFFFUL << 52)) return H_PARAMETER;
- buf = kzalloc(n, GFP_KERNEL); + buf = kzalloc(n, GFP_KERNEL | __GFP_NOWARN); if (!buf) return H_NO_MEM;
From: Christophe Leroy christophe.leroy@csgroup.eu
[ Upstream commit 33dc3e3e99e626ce51f462d883b05856c6c30b1d ]
sparse warnings: (new ones prefixed by >>)
drivers/w1/slaves/w1_ds28e04.c:342:13: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected char [noderef] __user *_pu_addr @@ got char *buf @@
drivers/w1/slaves/w1_ds28e04.c:342:13: sparse: expected char [noderef] __user *_pu_addr drivers/w1/slaves/w1_ds28e04.c:342:13: sparse: got char *buf
drivers/w1/slaves/w1_ds28e04.c:356:13: sparse: sparse: incorrect type in initializer (different address spaces) @@ expected char const [noderef] __user *_gu_addr @@ got char const *buf @@
drivers/w1/slaves/w1_ds28e04.c:356:13: sparse: expected char const [noderef] __user *_gu_addr drivers/w1/slaves/w1_ds28e04.c:356:13: sparse: got char const *buf
The buffer buf is a failsafe buffer in kernel space, it's not user memory hence doesn't deserve the use of get_user() or put_user().
Access 'buf' content directly.
Link: https://lore.kernel.org/lkml/202111190526.K5vb7NWC-lkp@intel.com/T/ Reported-by: kernel test robot lkp@intel.com Signed-off-by: Christophe Leroy christophe.leroy@csgroup.eu Link: https://lore.kernel.org/r/d14ed8d71ad4372e6839ae427f91441d3ba0e94d.163794631... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/w1/slaves/w1_ds28e04.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-)
diff --git a/drivers/w1/slaves/w1_ds28e04.c b/drivers/w1/slaves/w1_ds28e04.c index e4f336111edc6..6cef6e2edb892 100644 --- a/drivers/w1/slaves/w1_ds28e04.c +++ b/drivers/w1/slaves/w1_ds28e04.c @@ -32,7 +32,7 @@ static int w1_strong_pullup = 1; module_param_named(strong_pullup, w1_strong_pullup, int, 0);
/* enable/disable CRC checking on DS28E04-100 memory accesses */ -static char w1_enable_crccheck = 1; +static bool w1_enable_crccheck = true;
#define W1_EEPROM_SIZE 512 #define W1_PAGE_COUNT 16 @@ -339,32 +339,18 @@ static BIN_ATTR_RW(pio, 1); static ssize_t crccheck_show(struct device *dev, struct device_attribute *attr, char *buf) { - if (put_user(w1_enable_crccheck + 0x30, buf)) - return -EFAULT; - - return sizeof(w1_enable_crccheck); + return sysfs_emit(buf, "%d\n", w1_enable_crccheck); }
static ssize_t crccheck_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - char val; - - if (count != 1 || !buf) - return -EINVAL; + int err = kstrtobool(buf, &w1_enable_crccheck);
- if (get_user(val, buf)) - return -EFAULT; + if (err) + return err;
- /* convert to decimal */ - val = val - 0x30; - if (val != 0 && val != 1) - return -EINVAL; - - /* set the new value */ - w1_enable_crccheck = val; - - return sizeof(w1_enable_crccheck); + return count; }
static DEVICE_ATTR_RW(crccheck);
From: Srinivas Kandagatla srinivas.kandagatla@linaro.org
[ Upstream commit 86192251033308bb42f1e9813c962989d8ed07ec ]
For some reason we never set the size for nvmem sysfs binary file. Set this.
Reported-by: Gilles BULOZ gilles.buloz@kontron.com Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org Link: https://lore.kernel.org/r/20211130133909.6154-1-srinivas.kandagatla@linaro.o... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/nvmem/core.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 8976da38b375a..9aecb83021a2d 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -307,6 +307,8 @@ static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct nvmem_device *nvmem = to_nvmem_device(dev);
+ attr->size = nvmem->size; + return nvmem_bin_attr_get_umode(nvmem); }
From: Christoph Hellwig hch@lst.de
[ Upstream commit d751939235b9b7bc4af15f90a3e99288a8b844a7 ]
Make sure ->dax_dev is NULL on error so that the cleanup path doesn't trip over an ERR_PTR.
Reported-by: Dan Williams dan.j.williams@intel.com Signed-off-by: Christoph Hellwig hch@lst.de Link: https://lore.kernel.org/r/20211129102203.2243509-2-hch@lst.de Signed-off-by: Dan Williams dan.j.williams@intel.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/md/dm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 76d9da49fda75..671bb454f1649 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1794,8 +1794,10 @@ static struct mapped_device *alloc_dev(int minor) if (IS_ENABLED(CONFIG_DAX_DRIVER)) { md->dax_dev = alloc_dax(md, md->disk->disk_name, &dm_dax_ops, 0); - if (IS_ERR(md->dax_dev)) + if (IS_ERR(md->dax_dev)) { + md->dax_dev = NULL; goto bad; + } }
format_dev_t(md->name, MKDEV(_major, minor));
From: Stephan Gerhold stephan@gerhold.net
[ Upstream commit a7d9436a6c85fcb8843c910fd323dcd7f839bf63 ]
Using icc-rpm on ARM32 currently results in clk_set_rate() errors during boot, e.g. "bus clk_set_rate error: -22". This is very similar to commit 7381e27b1e56 ("interconnect: qcom: msm8974: Prevent integer overflow in rate") where the u64 is converted to a signed long during clock rate rounding, resulting in an overflow on 32-bit platforms.
Let's fix it similarly by making sure that the rate does not exceed LONG_MAX. Such high clock rates will surely result in the maximum frequency of the bus anyway.
Signed-off-by: Stephan Gerhold stephan@gerhold.net Link: https://lore.kernel.org/r/20211206114542.45325-1-stephan@gerhold.net Signed-off-by: Georgi Djakov djakov@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/interconnect/qcom/icc-rpm.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c index 54de49ca7808a..ddf1805ded0c0 100644 --- a/drivers/interconnect/qcom/icc-rpm.c +++ b/drivers/interconnect/qcom/icc-rpm.c @@ -68,6 +68,7 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) rate = max(sum_bw, max_peak_bw);
do_div(rate, qn->buswidth); + rate = min_t(u64, rate, LONG_MAX);
if (qn->rate == rate) return 0;
From: Bart Van Assche bvanassche@acm.org
[ Upstream commit 3489c34bd02b73a72646037d673a122a53cee174 ]
Fix the following kernel crash:
Unable to handle kernel paging request at virtual address ffffffc91e735000 Call trace: __queue_work+0x26c/0x624 queue_work_on+0x6c/0xf0 ufshcd_hold+0x12c/0x210 __ufshcd_wl_suspend+0xc0/0x400 ufshcd_wl_shutdown+0xb8/0xcc device_shutdown+0x184/0x224 kernel_restart+0x4c/0x124 __arm64_sys_reboot+0x194/0x264 el0_svc_common+0xc8/0x1d4 do_el0_svc+0x30/0x8c el0_svc+0x20/0x30 el0_sync_handler+0x84/0xe4 el0_sync+0x1bc/0x1c0
Fix this crash by ungating the clock before destroying the work queue on which clock gating work is queued.
Link: https://lore.kernel.org/r/20211203231950.193369-15-bvanassche@acm.org Tested-by: Bean Huo beanhuo@micron.com Reviewed-by: Bean Huo beanhuo@micron.com Signed-off-by: Bart Van Assche bvanassche@acm.org Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/ufs/ufshcd.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 31adf25e57b0d..4d50caa8cbbf5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1657,7 +1657,8 @@ int ufshcd_hold(struct ufs_hba *hba, bool async) bool flush_result; unsigned long flags;
- if (!ufshcd_is_clkgating_allowed(hba)) + if (!ufshcd_is_clkgating_allowed(hba) || + !hba->clk_gating.is_initialized) goto out; spin_lock_irqsave(hba->host->host_lock, flags); hba->clk_gating.active_reqs++; @@ -1817,7 +1818,7 @@ static void __ufshcd_release(struct ufs_hba *hba)
if (hba->clk_gating.active_reqs || hba->clk_gating.is_suspended || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL || - hba->outstanding_tasks || + hba->outstanding_tasks || !hba->clk_gating.is_initialized || hba->active_uic_cmd || hba->uic_async_done || hba->clk_gating.state == CLKS_OFF) return; @@ -1952,11 +1953,15 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) { if (!hba->clk_gating.is_initialized) return; + ufshcd_remove_clk_gating_sysfs(hba); - cancel_work_sync(&hba->clk_gating.ungate_work); - cancel_delayed_work_sync(&hba->clk_gating.gate_work); - destroy_workqueue(hba->clk_gating.clk_gating_workq); + + /* Ungate the clock if necessary. */ + ufshcd_hold(hba, false); hba->clk_gating.is_initialized = false; + ufshcd_release(hba); + + destroy_workqueue(hba->clk_gating.clk_gating_workq); }
/* Must be called with host lock acquired */
From: James Smart jsmart2021@gmail.com
[ Upstream commit f0d3919697492950f57a26a1093aee53880d669d ]
During rmmod testing, messages appeared indicating lpfc_mbuf_pool entries were still busy. This situation was only seen doing rmmod after at least 1 vport (NPIV) instance was created and destroyed. The number of messages scaled with the number of vports created.
When a vport is created, it can receive a PLOGI from another initiator Nport. When this happens, the driver prepares to ack the PLOGI and prepares an RPI for registration (via mbx cmd) which includes an mbuf allocation. During the unsolicited PLOGI processing and after the RPI preparation, the driver recognizes it is one of the vport instances and decides to reject the PLOGI. During the LS_RJT preparation for the PLOGI, the mailbox struct allocated for RPI registration is freed, but the mbuf that was also allocated is not released.
Fix by freeing the mbuf with the mailbox struct in the LS_RJT path.
As part of the code review to figure the issue out a couple of other areas where found that also would not have released the mbuf. Those are cleaned up as well.
Link: https://lore.kernel.org/r/20211204002644.116455-2-jsmart2021@gmail.com Co-developed-by: Justin Tee justin.tee@broadcom.com Signed-off-by: Justin Tee justin.tee@broadcom.com Signed-off-by: James Smart jsmart2021@gmail.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/lpfc/lpfc_els.c | 6 +++++- drivers/scsi/lpfc/lpfc_init.c | 8 ++++++-- drivers/scsi/lpfc/lpfc_nportdisc.c | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f7197b7161d52..6d7b9571f5c03 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -6877,6 +6877,7 @@ static int lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context) { LPFC_MBOXQ_t *mbox = NULL; + struct lpfc_dmabuf *mp; int rc;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -6892,8 +6893,11 @@ lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context) mbox->mbox_cmpl = lpfc_mbx_cmpl_rdp_page_a0; mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + mp = (struct lpfc_dmabuf *)mbox->ctx_buf; + lpfc_mbuf_free(phba, mp->virt, mp->phys); goto issue_mbox_fail; + }
return 0;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 0fee8d590b0c4..2bbd1be6cc5d4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5314,8 +5314,10 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba, */ if (!(phba->hba_flag & HBA_FCOE_MODE)) { rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); goto out_free_dmabuf; + } return; } /* @@ -6266,8 +6268,10 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) }
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); goto out_free_dmabuf; + } return;
out_free_dmabuf: diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 27263f02ab9f6..7d717a4ac14d1 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -322,6 +322,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; + struct lpfc_dmabuf *mp; uint64_t nlp_portwwn = 0; uint32_t *lp; IOCB_t *icmd; @@ -571,6 +572,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * a default RPI. */ if (phba->sli_rev == LPFC_SLI_REV4) { + mp = (struct lpfc_dmabuf *)login_mbox->ctx_buf; + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } mempool_free(login_mbox, phba->mbox_mem_pool); login_mbox = NULL; } else {
From: James Smart jsmart2021@gmail.com
[ Upstream commit 7dd2e2a923173d637c272e483966be8e96a72b64 ]
Extraneous teardown routines are present in the firmware dump path causing altered states in firmware captures.
When a firmware dump is requested via sysfs, trigger the dump immediately without tearing down structures and changing adapter state.
The driver shall rely on pre-existing firmware error state clean up handlers to restore the adapter.
Link: https://lore.kernel.org/r/20211204002644.116455-6-jsmart2021@gmail.com Co-developed-by: Justin Tee justin.tee@broadcom.com Signed-off-by: Justin Tee justin.tee@broadcom.com Signed-off-by: James Smart jsmart2021@gmail.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/lpfc/lpfc.h | 2 +- drivers/scsi/lpfc/lpfc_attr.c | 62 ++++++++++++++++++++------------ drivers/scsi/lpfc/lpfc_hbadisc.c | 8 ++++- drivers/scsi/lpfc/lpfc_sli.c | 6 ---- 4 files changed, 48 insertions(+), 30 deletions(-)
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index befeb7c342903..19fd9d263f47f 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1022,7 +1022,6 @@ struct lpfc_hba { #define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ #define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ #define HBA_IOQ_FLUSH 0x8000 /* FCP/NVME I/O queues being flushed */ -#define HBA_FW_DUMP_OP 0x10000 /* Skips fn reset before FW dump */ #define HBA_RECOVERABLE_UE 0x20000 /* Firmware supports recoverable UE */ #define HBA_FORCED_LINK_SPEED 0x40000 /* * Firmware supports Forced Link Speed @@ -1038,6 +1037,7 @@ struct lpfc_hba { #define HBA_HBEAT_TMO 0x8000000 /* HBEAT initiated after timeout */ #define HBA_FLOGI_OUTSTANDING 0x10000000 /* FLOGI is outstanding */
+ struct completion *fw_dump_cmpl; /* cmpl event tracker for fw_dump */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index ebe417921dac0..f20c4fe1fb8b9 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1709,25 +1709,25 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) before_fc_flag = phba->pport->fc_flag; sriov_nr_virtfn = phba->cfg_sriov_nr_virtfn;
- /* Disable SR-IOV virtual functions if enabled */ - if (phba->cfg_sriov_nr_virtfn) { - pci_disable_sriov(pdev); - phba->cfg_sriov_nr_virtfn = 0; - } + if (opcode == LPFC_FW_DUMP) { + init_completion(&online_compl); + phba->fw_dump_cmpl = &online_compl; + } else { + /* Disable SR-IOV virtual functions if enabled */ + if (phba->cfg_sriov_nr_virtfn) { + pci_disable_sriov(pdev); + phba->cfg_sriov_nr_virtfn = 0; + }
- if (opcode == LPFC_FW_DUMP) - phba->hba_flag |= HBA_FW_DUMP_OP; + status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
- status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); + if (status != 0) + return status;
- if (status != 0) { - phba->hba_flag &= ~HBA_FW_DUMP_OP; - return status; + /* wait for the device to be quiesced before firmware reset */ + msleep(100); }
- /* wait for the device to be quiesced before firmware reset */ - msleep(100); - reg_val = readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);
@@ -1756,24 +1756,42 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "3153 Fail to perform the requested " "access: x%x\n", reg_val); + if (phba->fw_dump_cmpl) + phba->fw_dump_cmpl = NULL; return rc; }
/* keep the original port state */ - if (before_fc_flag & FC_OFFLINE_MODE) - goto out; - - init_completion(&online_compl); - job_posted = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - if (!job_posted) + if (before_fc_flag & FC_OFFLINE_MODE) { + if (phba->fw_dump_cmpl) + phba->fw_dump_cmpl = NULL; goto out; + }
- wait_for_completion(&online_compl); + /* Firmware dump will trigger an HA_ERATT event, and + * lpfc_handle_eratt_s4 routine already handles bringing the port back + * online. + */ + if (opcode == LPFC_FW_DUMP) { + wait_for_completion(phba->fw_dump_cmpl); + } else { + init_completion(&online_compl); + job_posted = lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_ONLINE); + if (!job_posted) + goto out;
+ wait_for_completion(&online_compl); + } out: /* in any case, restore the virtual functions enabled as before */ if (sriov_nr_virtfn) { + /* If fw_dump was performed, first disable to clean up */ + if (opcode == LPFC_FW_DUMP) { + pci_disable_sriov(pdev); + phba->cfg_sriov_nr_virtfn = 0; + } + sriov_err = lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn); if (!sriov_err) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 9ccb904e35fcf..3bb7c2aa949f7 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -869,10 +869,16 @@ lpfc_work_done(struct lpfc_hba *phba) if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) lpfc_sli4_post_async_mbox(phba);
- if (ha_copy & HA_ERATT) + if (ha_copy & HA_ERATT) { /* Handle the error attention event */ lpfc_handle_eratt(phba);
+ if (phba->fw_dump_cmpl) { + complete(phba->fw_dump_cmpl); + phba->fw_dump_cmpl = NULL; + } + } + if (ha_copy & HA_MBATT) lpfc_sli_handle_mb_event(phba);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9c1f485952ef7..e5009f21d97e1 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5043,12 +5043,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) phba->fcf.fcf_flag = 0; spin_unlock_irq(&phba->hbalock);
- /* SLI4 INTF 2: if FW dump is being taken skip INIT_PORT */ - if (phba->hba_flag & HBA_FW_DUMP_OP) { - phba->hba_flag &= ~HBA_FW_DUMP_OP; - return rc; - } - /* Now physically reset the device */ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0389 Performing PCI function reset!\n");
From: Takashi Iwai tiwai@suse.de
[ Upstream commit 6fadb494a638d8b8a55864ecc6ac58194f03f327 ]
Currently ALSA sequencer core tries to process the queued events as much as possible when they become dispatchable. If applications try to queue too massive events to be processed at the very same timing, the sequencer core would still try to process such all events, either in the interrupt context or via some notifier; in either away, it might be a cause of RCU stall or such problems.
As a potential workaround for those problems, this patch adds the upper limit of the amount of events to be processed. The remaining events are processed in the next batch, so they won't be lost.
For the time being, it's limited up to 1000 events per queue, which should be high enough for any normal usages.
Reported-by: Zqiang qiang.zhang1211@gmail.com Reported-by: syzbot+bb950e68b400ab4f65f8@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20211102033222.3849-1-qiang.zhang1211@gmail.com Link: https://lore.kernel.org/r/20211207165146.2888-1-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Sasha Levin sashal@kernel.org --- sound/core/seq/seq_queue.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index d6c02dea976c8..bc933104c3eea 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -235,12 +235,15 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name)
/* -------------------------------------------------------- */
+#define MAX_CELL_PROCESSES_IN_QUEUE 1000 + void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) { unsigned long flags; struct snd_seq_event_cell *cell; snd_seq_tick_time_t cur_tick; snd_seq_real_time_t cur_time; + int processed = 0;
if (q == NULL) return; @@ -263,6 +266,8 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) if (!cell) break; snd_seq_dispatch_event(cell, atomic, hop); + if (++processed >= MAX_CELL_PROCESSES_IN_QUEUE) + goto out; /* the rest processed at the next batch */ }
/* Process time queue... */ @@ -272,14 +277,19 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) if (!cell) break; snd_seq_dispatch_event(cell, atomic, hop); + if (++processed >= MAX_CELL_PROCESSES_IN_QUEUE) + goto out; /* the rest processed at the next batch */ }
+ out: /* free lock */ spin_lock_irqsave(&q->check_lock, flags); if (q->check_again) { q->check_again = 0; - spin_unlock_irqrestore(&q->check_lock, flags); - goto __again; + if (processed < MAX_CELL_PROCESSES_IN_QUEUE) { + spin_unlock_irqrestore(&q->check_lock, flags); + goto __again; + } } q->check_blocked = 0; spin_unlock_irqrestore(&q->check_lock, flags);
From: Nathan Chancellor nathan@kernel.org
[ Upstream commit f2c6c22fa83ab2577619009057b3ebcb5305bb03 ]
LLVM's integrated assembler does not support 'slti <reg>, <imm>':
<instantiation>:16:12: error: invalid operand for instruction slti $12, (0x6300 | 0x0008) ^ arch/mips/kernel/head.S:86:2: note: while in macro instantiation kernel_entry_setup # cpu specific setup ^ <instantiation>:16:12: error: invalid operand for instruction slti $12, (0x6300 | 0x0008) ^ arch/mips/kernel/head.S:150:2: note: while in macro instantiation smp_slave_setup ^
To increase compatibility with LLVM's integrated assembler, use the full form of 'slti <reg>, <reg>, <imm>', which matches the rest of arch/mips/. This does not result in any change for GNU as.
Link: https://github.com/ClangBuiltLinux/linux/issues/1526 Reported-by: Ryutaroh Matsumoto ryutaroh@ict.e.titech.ac.jp Signed-off-by: Nathan Chancellor nathan@kernel.org Signed-off-by: Thomas Bogendoerfer tsbogend@alpha.franken.de Signed-off-by: Sasha Levin sashal@kernel.org --- arch/mips/include/asm/mach-loongson64/kernel-entry-init.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h b/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h index 13373c5144f89..efb41b3519747 100644 --- a/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h +++ b/arch/mips/include/asm/mach-loongson64/kernel-entry-init.h @@ -32,7 +32,7 @@ nop /* Loongson-3A R2/R3 */ andi t0, (PRID_IMP_MASK | PRID_REV_MASK) - slti t0, (PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0) + slti t0, t0, (PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0) bnez t0, 2f nop 1: @@ -63,7 +63,7 @@ nop /* Loongson-3A R2/R3 */ andi t0, (PRID_IMP_MASK | PRID_REV_MASK) - slti t0, (PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0) + slti t0, t0, (PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0) bnez t0, 2f nop 1:
From: Christophe Leroy christophe.leroy@csgroup.eu
[ Upstream commit 06e7cbc29e97b4713b4ea6def04ae8501a7d1a59 ]
As reported by Carlo, 16Mbytes is not enough with modern kernels that tend to be a bit big, so map another 16M page at boot.
Signed-off-by: Christophe Leroy christophe.leroy@csgroup.eu Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/89b5f974a7fa5011206682cd092e2c905530ff46.163275555... Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/kernel/head_40x.S | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index 7d72ee5ab387c..e783860bea838 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S @@ -27,6 +27,7 @@
#include <linux/init.h> #include <linux/pgtable.h> +#include <linux/sizes.h> #include <asm/processor.h> #include <asm/page.h> #include <asm/mmu.h> @@ -650,7 +651,7 @@ start_here: b . /* prevent prefetch past rfi */
/* Set up the initial MMU state so we can do the first level of - * kernel initialization. This maps the first 16 MBytes of memory 1:1 + * kernel initialization. This maps the first 32 MBytes of memory 1:1 * virtual to physical and more importantly sets the cache mode. */ initial_mmu: @@ -687,6 +688,12 @@ initial_mmu: tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */ tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */
+ li r0,62 /* TLB slot 62 */ + addis r4,r4,SZ_16M@h + addis r3,r3,SZ_16M@h + tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */ + tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */ + isync
/* Establish the exception vector base
From: Thadeu Lima de Souza Cascardo cascardo@canonical.com
[ Upstream commit 3c42e9542050d49610077e083c7c3f5fd5e26820 ]
A mis-match between reported and actual mitigation is not restricted to the Vulnerable case. The guest might also report the mitigation as "Software count cache flush" and the host will still mitigate with branch cache disabled.
So, instead of skipping depending on the detected mitigation, simply skip whenever the detected miss_percent is the expected one for a fully mitigated system, that is, above 95%.
Signed-off-by: Thadeu Lima de Souza Cascardo cascardo@canonical.com Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/20211207130557.40566-1-cascardo@canonical.com Signed-off-by: Sasha Levin sashal@kernel.org --- tools/testing/selftests/powerpc/security/spectre_v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/powerpc/security/spectre_v2.c b/tools/testing/selftests/powerpc/security/spectre_v2.c index adc2b7294e5fd..83647b8277e7d 100644 --- a/tools/testing/selftests/powerpc/security/spectre_v2.c +++ b/tools/testing/selftests/powerpc/security/spectre_v2.c @@ -193,7 +193,7 @@ int spectre_v2_test(void) * We are not vulnerable and reporting otherwise, so * missing such a mismatch is safe. */ - if (state == VULNERABLE) + if (miss_percent > 95) return 4;
return 1;
From: Hari Bathini hbathini@linux.ibm.com
[ Upstream commit 219572d2fc4135b5ce65c735d881787d48b10e71 ]
Kdump can be triggered after panic_notifers since commit f06e5153f4ae2 ("kernel/panic.c: add "crash_kexec_post_notifiers" option for kdump after panic_notifers") introduced crash_kexec_post_notifiers option. But using this option would mean smp_send_stop(), that marks all other CPUs as offline, gets called before kdump is triggered. As a result, kdump routines fail to save other CPUs' registers. To fix this, kdump friendly crash_smp_send_stop() function was introduced with kernel commit 0ee59413c967 ("x86/panic: replace smp_send_stop() with kdump friendly version in panic path"). Override this kdump friendly weak function to handle crash_kexec_post_notifiers option appropriately on powerpc.
Reported-by: kernel test robot lkp@intel.com Signed-off-by: Hari Bathini hbathini@linux.ibm.com [Fixed signature of crash_stop_this_cpu() - reported by lkp@intel.com] Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/20211207103719.91117-1-hbathini@linux.ibm.com Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/kernel/smp.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index c7ef0739c8640..d03823aa7e4de 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -620,6 +620,36 @@ void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) } #endif
+#ifdef CONFIG_NMI_IPI +static void crash_stop_this_cpu(struct pt_regs *regs) +#else +static void crash_stop_this_cpu(void *dummy) +#endif +{ + /* + * Just busy wait here and avoid marking CPU as offline to ensure + * register data is captured appropriately. + */ + while (1) + cpu_relax(); +} + +void crash_smp_send_stop(void) +{ + static bool stopped = false; + + if (stopped) + return; + + stopped = true; + +#ifdef CONFIG_NMI_IPI + smp_send_nmi_ipi(NMI_IPI_ALL_OTHERS, crash_stop_this_cpu, 1000000); +#else + smp_call_function(crash_stop_this_cpu, NULL, 0); +#endif /* CONFIG_NMI_IPI */ +} + #ifdef CONFIG_NMI_IPI static void nmi_stop_this_cpu(struct pt_regs *regs) {
From: Hari Bathini hbathini@linux.ibm.com
[ Upstream commit 06e629c25daa519be620a8c17359ae8fc7a2e903 ]
In panic path, fadump is triggered via a panic notifier function. Before calling panic notifier functions, smp_send_stop() gets called, which stops all CPUs except the panic'ing CPU. Commit 8389b37dffdc ("powerpc: stop_this_cpu: remove the cpu from the online map.") and again commit bab26238bbd4 ("powerpc: Offline CPU in stop_this_cpu()") started marking CPUs as offline while stopping them. So, if a kernel has either of the above commits, vmcore captured with fadump via panic path would not process register data for all CPUs except the panic'ing CPU. Sample output of crash-utility with such vmcore:
# crash vmlinux vmcore ... KERNEL: vmlinux DUMPFILE: vmcore [PARTIAL DUMP] CPUS: 1 DATE: Wed Nov 10 09:56:34 EST 2021 UPTIME: 00:00:42 LOAD AVERAGE: 2.27, 0.69, 0.24 TASKS: 183 NODENAME: XXXXXXXXX RELEASE: 5.15.0+ VERSION: #974 SMP Wed Nov 10 04:18:19 CST 2021 MACHINE: ppc64le (2500 Mhz) MEMORY: 8 GB PANIC: "Kernel panic - not syncing: sysrq triggered crash" PID: 3394 COMMAND: "bash" TASK: c0000000150a5f80 [THREAD_INFO: c0000000150a5f80] CPU: 1 STATE: TASK_RUNNING (PANIC)
crash> p -x __cpu_online_mask __cpu_online_mask = $1 = { bits = {0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} } crash> crash> crash> p -x __cpu_active_mask __cpu_active_mask = $2 = { bits = {0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} } crash>
While this has been the case since fadump was introduced, the issue was not identified for two probable reasons:
- In general, the bulk of the vmcores analyzed were from crash due to exception.
- The above did change since commit 8341f2f222d7 ("sysrq: Use panic() to force a crash") started using panic() instead of deferencing NULL pointer to force a kernel crash. But then commit de6e5d38417e ("powerpc: smp_send_stop do not offline stopped CPUs") stopped marking CPUs as offline till kernel commit bab26238bbd4 ("powerpc: Offline CPU in stop_this_cpu()") reverted that change.
To ensure post processing register data of all other CPUs happens as intended, let panic() function take the crash friendly path (read crash_smp_send_stop()) with the help of crash_kexec_post_notifiers option. Also, as register data for all CPUs is captured by f/w, skip IPI callbacks here for fadump, to avoid any complications in finding the right backtraces.
Signed-off-by: Hari Bathini hbathini@linux.ibm.com Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/20211207103719.91117-2-hbathini@linux.ibm.com Signed-off-by: Sasha Levin sashal@kernel.org --- arch/powerpc/kernel/fadump.c | 8 ++++++++ arch/powerpc/kernel/smp.c | 10 ++++++++++ 2 files changed, 18 insertions(+)
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index b7ceb041743c9..60f5fc14aa235 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1641,6 +1641,14 @@ int __init setup_fadump(void) else if (fw_dump.reserve_dump_area_size) fw_dump.ops->fadump_init_mem_struct(&fw_dump);
+ /* + * In case of panic, fadump is triggered via ppc_panic_event() + * panic notifier. Setting crash_kexec_post_notifiers to 'true' + * lets panic() function take crash friendly path before panic + * notifiers are invoked. + */ + crash_kexec_post_notifiers = true; + return 1; } subsys_initcall(setup_fadump); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index d03823aa7e4de..fb95f92dcfac6 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -61,6 +61,7 @@ #include <asm/cpu_has_feature.h> #include <asm/ftrace.h> #include <asm/kup.h> +#include <asm/fadump.h>
#ifdef DEBUG #include <asm/udbg.h> @@ -638,6 +639,15 @@ void crash_smp_send_stop(void) { static bool stopped = false;
+ /* + * In case of fadump, register data for all CPUs is captured by f/w + * on ibm,os-term rtas call. Skip IPI callbacks to other CPUs before + * this rtas call to avoid tricky post processing of those CPUs' + * backtraces. + */ + if (should_fadump_crash()) + return; + if (stopped) return;
From: Jan Kara jack@suse.cz
[ Upstream commit f05f2429eec60851b98bdde213de31dab697c01b ]
When memory allocation of iinfo or block allocation fails, already allocated struct udf_inode_info gets freed with iput() and udf_evict_inode() may look at inode fields which are not properly initialized. Fix it by marking inode bad before dropping reference to it in udf_new_inode().
Reported-by: syzbot+9ca499bb57a2b9e4c652@syzkaller.appspotmail.com Signed-off-by: Jan Kara jack@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org --- fs/udf/ialloc.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 2ecf0e87660e3..b5d611cee749c 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -77,6 +77,7 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode) GFP_KERNEL); } if (!iinfo->i_data) { + make_bad_inode(inode); iput(inode); return ERR_PTR(-ENOMEM); } @@ -86,6 +87,7 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode) dinfo->i_location.partitionReferenceNum, start, &err); if (err) { + make_bad_inode(inode); iput(inode); return ERR_PTR(err); }
From: Ye Guojin ye.guojin@zte.com.cn
[ Upstream commit 858779df1c0787d3fec827fb705708df9ebdb15b ]
This was found by coccicheck: ./arch/mips/cavium-octeon/octeon-platform.c, 332, 1-7, ERROR missing put_device; call of_find_device_by_node on line 324, but without a corresponding object release within this function. ./arch/mips/cavium-octeon/octeon-platform.c, 395, 1-7, ERROR missing put_device; call of_find_device_by_node on line 387, but without a corresponding object release within this function. ./arch/mips/cavium-octeon/octeon-usb.c, 512, 3-9, ERROR missing put_device; call of_find_device_by_node on line 515, but without a corresponding object release within this function. ./arch/mips/cavium-octeon/octeon-usb.c, 543, 1-7, ERROR missing put_device; call of_find_device_by_node on line 515, but without a corresponding object release within this function.
Reported-by: Zeal Robot zealci@zte.com.cn Signed-off-by: Ye Guojin ye.guojin@zte.com.cn Signed-off-by: Thomas Bogendoerfer tsbogend@alpha.franken.de Signed-off-by: Sasha Levin sashal@kernel.org --- arch/mips/cavium-octeon/octeon-platform.c | 2 ++ arch/mips/cavium-octeon/octeon-usb.c | 1 + 2 files changed, 3 insertions(+)
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index d56e9b9d2e434..a994022e32c9f 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -328,6 +328,7 @@ static int __init octeon_ehci_device_init(void)
pd->dev.platform_data = &octeon_ehci_pdata; octeon_ehci_hw_start(&pd->dev); + put_device(&pd->dev);
return ret; } @@ -391,6 +392,7 @@ static int __init octeon_ohci_device_init(void)
pd->dev.platform_data = &octeon_ohci_pdata; octeon_ohci_hw_start(&pd->dev); + put_device(&pd->dev);
return ret; } diff --git a/arch/mips/cavium-octeon/octeon-usb.c b/arch/mips/cavium-octeon/octeon-usb.c index 6e4d3619137af..4df919d26b082 100644 --- a/arch/mips/cavium-octeon/octeon-usb.c +++ b/arch/mips/cavium-octeon/octeon-usb.c @@ -537,6 +537,7 @@ static int __init dwc3_octeon_device_init(void) devm_iounmap(&pdev->dev, base); devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); + put_device(&pdev->dev); } } while (node != NULL);
From: Marc Zyngier maz@kernel.org
[ Upstream commit 79a7f77b9b154d572bd9d2f1eecf58c4d018d8e2 ]
Jay Chen reported that using a kdump kernel on a GICv4.1 system results in a RAS error being delivered when the secondary kernel configures the ITS's view of the new VPE table.
As it turns out, that's because each RD still has a pointer to the previous instance of the VPE table, and that particular implementation is very upset by seeing two bits of the HW that should point to the same table with different values.
To solve this, let's invalidate any reference that any RD has to the VPE table when discovering the RDs. The ITS can then be programmed as expected.
Reported-by: Jay Chen jkchen@linux.alibaba.com Signed-off-by: Marc Zyngier maz@kernel.org Cc: Lorenzo Pieralisi lorenzo.pieralisi@arm.com Link: https://lore.kernel.org/r/20211214064716.21407-1-jkchen@linux.alibaba.com Link: https://lore.kernel.org/r/20211216144804.1578566-1-maz@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/irqchip/irq-gic-v3.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index fd4e9a37fea67..7bbccb13b896b 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -920,6 +920,22 @@ static int __gic_update_rdist_properties(struct redist_region *region, { u64 typer = gic_read_typer(ptr + GICR_TYPER);
+ /* Boot-time cleanip */ + if ((typer & GICR_TYPER_VLPIS) && (typer & GICR_TYPER_RVPEID)) { + u64 val; + + /* Deactivate any present vPE */ + val = gicr_read_vpendbaser(ptr + SZ_128K + GICR_VPENDBASER); + if (val & GICR_VPENDBASER_Valid) + gicr_write_vpendbaser(GICR_VPENDBASER_PendingLast, + ptr + SZ_128K + GICR_VPENDBASER); + + /* Mark the VPE table as invalid */ + val = gicr_read_vpropbaser(ptr + SZ_128K + GICR_VPROPBASER); + val &= ~GICR_VPROPBASER_4_1_VALID; + gicr_write_vpropbaser(val, ptr + SZ_128K + GICR_VPROPBASER); + } + gic_data.rdists.has_vlpis &= !!(typer & GICR_TYPER_VLPIS);
/* RVPEID implies some form of DirectLPI, no matter what the doc says... :-/ */
From: Lakshmi Sowjanya D lakshmi.sowjanya.d@intel.com
[ Upstream commit d52097010078c1844348dc0e467305e5f90fd317 ]
The data type of hcnt and lcnt in the struct dw_i2c_dev is of type u16. It's better to have same data type in struct dw_scl_sda_cfg as well.
Reported-by: Wolfram Sang wsa@kernel.org Signed-off-by: Lakshmi Sowjanya D lakshmi.sowjanya.d@intel.com Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Signed-off-by: Jarkko Nikula jarkko.nikula@linux.intel.com Signed-off-by: Wolfram Sang wsa@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/i2c/busses/i2c-designware-pcidrv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 0f409a4c2da0d..5b45941bcbddc 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -39,10 +39,10 @@ enum dw_pci_ctl_id_t { };
struct dw_scl_sda_cfg { - u32 ss_hcnt; - u32 fs_hcnt; - u32 ss_lcnt; - u32 fs_lcnt; + u16 ss_hcnt; + u16 fs_hcnt; + u16 ss_lcnt; + u16 fs_lcnt; u32 sda_hold; };
From: Thomas Gleixner tglx@linutronix.de
[ Upstream commit 3f35d2cf9fbc656db82579d849cc69c373b1ad0d ]
The MSI core will introduce runtime allocation of MSI related data. This data will be devres managed and has to be set up before enabling PCI/MSI[-X]. This would introduce an ordering issue vs. pcim_release().
The setup order is:
pcim_enable_device() devres_alloc(pcim_release...); ... pci_irq_alloc() msi_setup_device_data() devres_alloc(msi_device_data_release, ...)
and once the device is released these release functions are invoked in the opposite order:
msi_device_data_release() ... pcim_release() pci_disable_msi[x]()
which is obviously wrong, because pci_disable_msi[x]() requires the MSI data to be available to tear down the MSI[-X] interrupts.
Remove the MSI[-X] teardown from pcim_release() and add an explicit action to be installed on the attempt of enabling PCI/MSI[-X].
This allows the MSI core data allocation to be ordered correctly in a subsequent step.
Reported-by: Nishanth Menon nm@ti.com Signed-off-by: Thomas Gleixner tglx@linutronix.de Tested-by: Michael Kelley mikelley@microsoft.com Tested-by: Nishanth Menon nm@ti.com Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Link: https://lore.kernel.org/r/87tuf9rdoj.ffs@tglx Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/pci/msi.c | 33 +++++++++++++++++++++++++++++++++ drivers/pci/pci.c | 5 ----- include/linux/pci.h | 3 ++- 3 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index e11530cb05699..696ce4a2c0d15 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -461,6 +461,31 @@ void pci_restore_msi_state(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_restore_msi_state);
+static void pcim_msi_release(void *pcidev) +{ + struct pci_dev *dev = pcidev; + + dev->is_msi_managed = false; + pci_free_irq_vectors(dev); +} + +/* + * Needs to be separate from pcim_release to prevent an ordering problem + * vs. msi_device_data_release() in the MSI core code. + */ +static int pcim_setup_msi_release(struct pci_dev *dev) +{ + int ret; + + if (!pci_is_managed(dev) || dev->is_msi_managed) + return 0; + + ret = devm_add_action(&dev->dev, pcim_msi_release, dev); + if (!ret) + dev->is_msi_managed = true; + return ret; +} + static struct msi_desc * msi_setup_entry(struct pci_dev *dev, int nvec, struct irq_affinity *affd) { @@ -1028,6 +1053,10 @@ static int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, if (nvec > maxvec) nvec = maxvec;
+ rc = pcim_setup_msi_release(dev); + if (rc) + return rc; + for (;;) { if (affd) { nvec = irq_calc_affinity_vectors(minvec, nvec, affd); @@ -1071,6 +1100,10 @@ static int __pci_enable_msix_range(struct pci_dev *dev, if (WARN_ON_ONCE(dev->msix_enabled)) return -EINVAL;
+ rc = pcim_setup_msi_release(dev); + if (rc) + return rc; + for (;;) { if (affd) { nvec = irq_calc_affinity_vectors(minvec, nvec, affd); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a101faf3e88a9..61fce23a467b9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2005,11 +2005,6 @@ static void pcim_release(struct device *gendev, void *res) struct pci_devres *this = res; int i;
- if (dev->msi_enabled) - pci_disable_msi(dev); - if (dev->msix_enabled) - pci_disable_msix(dev); - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) if (this->region_mask & (1 << i)) pci_release_region(dev, i); diff --git a/include/linux/pci.h b/include/linux/pci.h index 152a4d74f87f0..5f1f3de8c6b79 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -425,7 +425,8 @@ struct pci_dev { unsigned int ats_enabled:1; /* Address Translation Svc */ unsigned int pasid_enabled:1; /* Process Address Space ID */ unsigned int pri_enabled:1; /* Page Request Interface */ - unsigned int is_managed:1; + unsigned int is_managed:1; /* Managed via devres */ + unsigned int is_msi_managed:1; /* MSI release via devres installed */ unsigned int needs_freset:1; /* Requires fundamental reset */ unsigned int state_saved:1; unsigned int is_physfn:1;
From: Michael Ellerman mpe@ellerman.id.au
[ Upstream commit a8968521cfdc3e339fe69473d6632e0aa8d7202a ]
We have a general signal fuzzer, sigfuz, which can modify the MSR & NIP before sigreturn. But the chance of it hitting a kernel address and also clearing MSR_PR is fairly slim.
So add a specific test of sigreturn to a kernel address, both with and without attempting to clear MSR_PR (which the kernel must block).
Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/20211209115944.4062384-1-mpe@ellerman.id.au Signed-off-by: Sasha Levin sashal@kernel.org --- .../selftests/powerpc/signal/.gitignore | 1 + .../testing/selftests/powerpc/signal/Makefile | 1 + .../powerpc/signal/sigreturn_kernel.c | 132 ++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 tools/testing/selftests/powerpc/signal/sigreturn_kernel.c
diff --git a/tools/testing/selftests/powerpc/signal/.gitignore b/tools/testing/selftests/powerpc/signal/.gitignore index ce3375cd8e73e..8f6c816099a48 100644 --- a/tools/testing/selftests/powerpc/signal/.gitignore +++ b/tools/testing/selftests/powerpc/signal/.gitignore @@ -4,3 +4,4 @@ signal_tm sigfuz sigreturn_vdso sig_sc_double_restart +sigreturn_kernel diff --git a/tools/testing/selftests/powerpc/signal/Makefile b/tools/testing/selftests/powerpc/signal/Makefile index d6ae54663aed7..84e201572466d 100644 --- a/tools/testing/selftests/powerpc/signal/Makefile +++ b/tools/testing/selftests/powerpc/signal/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 TEST_GEN_PROGS := signal signal_tm sigfuz sigreturn_vdso sig_sc_double_restart +TEST_GEN_PROGS += sigreturn_kernel
CFLAGS += -maltivec $(OUTPUT)/signal_tm: CFLAGS += -mhtm diff --git a/tools/testing/selftests/powerpc/signal/sigreturn_kernel.c b/tools/testing/selftests/powerpc/signal/sigreturn_kernel.c new file mode 100644 index 0000000000000..0a1b6e591eeed --- /dev/null +++ b/tools/testing/selftests/powerpc/signal/sigreturn_kernel.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test that we can't sigreturn to kernel addresses, or to kernel mode. + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <signal.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "utils.h" + +#define MSR_PR (1ul << 14) + +static volatile unsigned long long sigreturn_addr; +static volatile unsigned long long sigreturn_msr_mask; + +static void sigusr1_handler(int signo, siginfo_t *si, void *uc_ptr) +{ + ucontext_t *uc = (ucontext_t *)uc_ptr; + + if (sigreturn_addr) + UCONTEXT_NIA(uc) = sigreturn_addr; + + if (sigreturn_msr_mask) + UCONTEXT_MSR(uc) &= sigreturn_msr_mask; +} + +static pid_t fork_child(void) +{ + pid_t pid; + + pid = fork(); + if (pid == 0) { + raise(SIGUSR1); + exit(0); + } + + return pid; +} + +static int expect_segv(pid_t pid) +{ + int child_ret; + + waitpid(pid, &child_ret, 0); + FAIL_IF(WIFEXITED(child_ret)); + FAIL_IF(!WIFSIGNALED(child_ret)); + FAIL_IF(WTERMSIG(child_ret) != 11); + + return 0; +} + +int test_sigreturn_kernel(void) +{ + struct sigaction act; + int child_ret, i; + pid_t pid; + + act.sa_sigaction = sigusr1_handler; + act.sa_flags = SA_SIGINFO; + sigemptyset(&act.sa_mask); + + FAIL_IF(sigaction(SIGUSR1, &act, NULL)); + + for (i = 0; i < 2; i++) { + // Return to kernel + sigreturn_addr = 0xcull << 60; + pid = fork_child(); + expect_segv(pid); + + // Return to kernel virtual + sigreturn_addr = 0xc008ull << 48; + pid = fork_child(); + expect_segv(pid); + + // Return out of range + sigreturn_addr = 0xc010ull << 48; + pid = fork_child(); + expect_segv(pid); + + // Return to no-man's land, just below PAGE_OFFSET + sigreturn_addr = (0xcull << 60) - (64 * 1024); + pid = fork_child(); + expect_segv(pid); + + // Return to no-man's land, above TASK_SIZE_4PB + sigreturn_addr = 0x1ull << 52; + pid = fork_child(); + expect_segv(pid); + + // Return to 0xd space + sigreturn_addr = 0xdull << 60; + pid = fork_child(); + expect_segv(pid); + + // Return to 0xe space + sigreturn_addr = 0xeull << 60; + pid = fork_child(); + expect_segv(pid); + + // Return to 0xf space + sigreturn_addr = 0xfull << 60; + pid = fork_child(); + expect_segv(pid); + + // Attempt to set PR=0 for 2nd loop (should be blocked by kernel) + sigreturn_msr_mask = ~MSR_PR; + } + + printf("All children killed as expected\n"); + + // Don't change address, just MSR, should return to user as normal + sigreturn_addr = 0; + sigreturn_msr_mask = ~MSR_PR; + pid = fork_child(); + waitpid(pid, &child_ret, 0); + FAIL_IF(!WIFEXITED(child_ret)); + FAIL_IF(WIFSIGNALED(child_ret)); + FAIL_IF(WEXITSTATUS(child_ret) != 0); + + return 0; +} + +int main(void) +{ + return test_harness(test_sigreturn_kernel, "sigreturn_kernel"); +}
From: Tianjia Zhang tianjia.zhang@linux.alibaba.com
[ Upstream commit 95339b70677dc6f9a2d669c4716058e71b8dc1c7 ]
A large number of the following errors is reported when compiling with clang:
cvmx-bootinfo.h:326:3: error: adding 'int' to a string does not append to the string [-Werror,-Wstring-plus-int] ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NULL) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ cvmx-bootinfo.h:321:20: note: expanded from macro 'ENUM_BRD_TYPE_CASE' case x: return(#x + 16); /* Skip CVMX_BOARD_TYPE_ */ ~~~^~~~ cvmx-bootinfo.h:326:3: note: use array indexing to silence this warning cvmx-bootinfo.h:321:20: note: expanded from macro 'ENUM_BRD_TYPE_CASE' case x: return(#x + 16); /* Skip CVMX_BOARD_TYPE_ */ ^
Follow the prompts to use the address operator '&' to fix this error.
Signed-off-by: Tianjia Zhang tianjia.zhang@linux.alibaba.com Reviewed-by: Nathan Chancellor nathan@kernel.org Reviewed-by: Philippe Mathieu-Daudé f4bug@amsat.org Signed-off-by: Thomas Bogendoerfer tsbogend@alpha.franken.de Signed-off-by: Sasha Levin sashal@kernel.org --- arch/mips/include/asm/octeon/cvmx-bootinfo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h index 0e6bf220db618..6c61e0a639249 100644 --- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h @@ -318,7 +318,7 @@ enum cvmx_chip_types_enum {
/* Functions to return string based on type */ #define ENUM_BRD_TYPE_CASE(x) \ - case x: return(#x + 16); /* Skip CVMX_BOARD_TYPE_ */ + case x: return (&#x[16]); /* Skip CVMX_BOARD_TYPE_ */ static inline const char *cvmx_board_type_to_string(enum cvmx_board_types_enum type) { @@ -410,7 +410,7 @@ static inline const char *cvmx_board_type_to_string(enum }
#define ENUM_CHIP_TYPE_CASE(x) \ - case x: return(#x + 15); /* Skip CVMX_CHIP_TYPE */ + case x: return (&#x[15]); /* Skip CVMX_CHIP_TYPE */ static inline const char *cvmx_chip_type_to_string(enum cvmx_chip_types_enum type) {
From: Christoph Hellwig hch@lst.de
[ Upstream commit d94d94969a4ba07a43d62429c60372320519c391 ]
The allocated buffers are used as a command payload, for which the block layer and/or DMA API do the proper bounce buffering if needed.
Link: https://lore.kernel.org/r/20211222090842.920724-1-hch@lst.de Reported-by: Baoquan He bhe@redhat.com Reviewed-by: Baoquan He bhe@redhat.com Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/sr.c | 2 +- drivers/scsi/sr_vendor.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 8b17b35283aa5..1203374828b97 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -851,7 +851,7 @@ static void get_capabilities(struct scsi_cd *cd)
/* allocate transfer buffer */ - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if (!buffer) { sr_printk(KERN_ERR, cd, "out of memory.\n"); return; diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c index 1f988a1b9166f..a61635326ae0a 100644 --- a/drivers/scsi/sr_vendor.c +++ b/drivers/scsi/sr_vendor.c @@ -131,7 +131,7 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength) if (cd->vendor == VENDOR_TOSHIBA) density = (blocklength > 2048) ? 0x81 : 0x83;
- buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if (!buffer) return -ENOMEM;
@@ -179,7 +179,7 @@ int sr_cd_check(struct cdrom_device_info *cdi) if (cd->cdi.mask & CDC_MULTI_SESSION) return 0;
- buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kmalloc(512, GFP_KERNEL); if (!buffer) return -ENOMEM;
From: Sreekanth Reddy sreekanth.reddy@broadcom.com
[ Upstream commit 243bcc8efdb1f44b1a1d415e6821a246714c68ce ]
Set reply queue depth of 1K for B0 and 4K for A0.
While freeing the segmented request queues use the actual queue depth that is used while creating them.
Link: https://lore.kernel.org/r/20211220141159.16117-25-sreekanth.reddy@broadcom.c... Signed-off-by: Sreekanth Reddy sreekanth.reddy@broadcom.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/scsi/mpi3mr/mpi3mr.h | 3 ++- drivers/scsi/mpi3mr/mpi3mr_fw.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 9787b53a2b598..2cc42432bd0c0 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -79,7 +79,8 @@ extern int prot_mask;
/* Operational queue management definitions */ #define MPI3MR_OP_REQ_Q_QD 512 -#define MPI3MR_OP_REP_Q_QD 4096 +#define MPI3MR_OP_REP_Q_QD 1024 +#define MPI3MR_OP_REP_Q_QD4K 4096 #define MPI3MR_OP_REQ_Q_SEG_SIZE 4096 #define MPI3MR_OP_REP_Q_SEG_SIZE 4096 #define MPI3MR_MAX_SEG_LIST_SIZE 4096 diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 4a8316c6bd41a..5af36c54cb596 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1278,7 +1278,7 @@ static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx) mrioc->op_reply_qinfo[q_idx].q_segment_list = NULL; } } else - size = mrioc->req_qinfo[q_idx].num_requests * + size = mrioc->req_qinfo[q_idx].segment_qd * mrioc->facts.op_req_sz;
for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) { @@ -1565,6 +1565,8 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx)
reply_qid = qidx + 1; op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; + if (!mrioc->pdev->revision) + op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; op_reply_q->ci = 0; op_reply_q->ephase = 1; atomic_set(&op_reply_q->pend_ios, 0);
From: Tzung-Bi Shih tzungbi@google.com
[ Upstream commit 4e28491a7a198c668437f2be8a91a76aa52f20eb ]
The of_parse_phandle() document: >>> Use of_node_put() on it when done.
The driver didn't call of_node_put(). Fixes the leak.
Signed-off-by: Tzung-Bi Shih tzungbi@google.com Link: https://lore.kernel.org/r/20211214040028.2992627-1-tzungbi@google.com Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index a606133951b70..24a5d0adec1ba 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -1172,7 +1172,11 @@ static int mt8192_mt6359_dev_probe(struct platform_device *pdev) return ret; }
- return devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(&pdev->dev, card); + + of_node_put(platform_node); + of_node_put(hdmi_codec); + return ret; }
#ifdef CONFIG_OF
From: Chunfeng Yun chunfeng.yun@mediatek.com
[ Upstream commit 6f2b033cb883f64ad084a75f13634242c7e179a6 ]
Due to some SoCs have a bit shift issue that will drop a bit for usb3 phy or pcie phy, fix it by adding software efuse reading and setting, but only support it optionally for version 2/3.
Signed-off-by: Chunfeng Yun chunfeng.yun@mediatek.com Link: https://lore.kernel.org/r/20211218082802.5256-2-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul vkoul@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/phy/mediatek/phy-mtk-tphy.c | 162 ++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+)
diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index cdcef865fe9e5..98a942c607a67 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -12,6 +12,7 @@ #include <linux/iopoll.h> #include <linux/mfd/syscon.h> #include <linux/module.h> +#include <linux/nvmem-consumer.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/phy/phy.h> @@ -41,6 +42,9 @@ #define SSUSB_SIFSLV_V2_U3PHYD 0x200 #define SSUSB_SIFSLV_V2_U3PHYA 0x400
+#define U3P_MISC_REG1 0x04 +#define MR1_EFUSE_AUTO_LOAD_DIS BIT(6) + #define U3P_USBPHYACR0 0x000 #define PA0_RG_U2PLL_FORCE_ON BIT(15) #define PA0_USB20_PLL_PREDIV GENMASK(7, 6) @@ -133,6 +137,8 @@ #define P3C_RG_SWRST_U3_PHYD_FORCE_EN BIT(24)
#define U3P_U3_PHYA_REG0 0x000 +#define P3A_RG_IEXT_INTR GENMASK(15, 10) +#define P3A_RG_IEXT_INTR_VAL(x) ((0x3f & (x)) << 10) #define P3A_RG_CLKDRV_OFF GENMASK(3, 2) #define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2)
@@ -187,6 +193,19 @@ #define P3D_RG_FWAKE_TH GENMASK(21, 16) #define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
+#define U3P_U3_PHYD_IMPCAL0 0x010 +#define P3D_RG_FORCE_TX_IMPEL BIT(31) +#define P3D_RG_TX_IMPEL GENMASK(28, 24) +#define P3D_RG_TX_IMPEL_VAL(x) ((0x1f & (x)) << 24) + +#define U3P_U3_PHYD_IMPCAL1 0x014 +#define P3D_RG_FORCE_RX_IMPEL BIT(31) +#define P3D_RG_RX_IMPEL GENMASK(28, 24) +#define P3D_RG_RX_IMPEL_VAL(x) ((0x1f & (x)) << 24) + +#define U3P_U3_PHYD_RSV 0x054 +#define P3D_RG_EFUSE_AUTO_LOAD_DIS BIT(12) + #define U3P_U3_PHYD_CDR1 0x05c #define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24) #define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24) @@ -307,6 +326,11 @@ struct mtk_phy_pdata { * 48M PLL, fix it by switching PLL to 26M from default 48M */ bool sw_pll_48m_to_26m; + /* + * Some SoCs (e.g. mt8195) drop a bit when use auto load efuse, + * support sw way, also support it for v2/v3 optionally. + */ + bool sw_efuse_supported; enum mtk_phy_version version; };
@@ -336,6 +360,10 @@ struct mtk_phy_instance { struct regmap *type_sw; u32 type_sw_reg; u32 type_sw_index; + u32 efuse_sw_en; + u32 efuse_intr; + u32 efuse_tx_imp; + u32 efuse_rx_imp; int eye_src; int eye_vrt; int eye_term; @@ -1040,6 +1068,130 @@ static int phy_type_set(struct mtk_phy_instance *instance) return 0; }
+static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instance) +{ + struct device *dev = &instance->phy->dev; + int ret = 0; + + /* tphy v1 doesn't support sw efuse, skip it */ + if (!tphy->pdata->sw_efuse_supported) { + instance->efuse_sw_en = 0; + return 0; + } + + /* software efuse is optional */ + instance->efuse_sw_en = device_property_read_bool(dev, "nvmem-cells"); + if (!instance->efuse_sw_en) + return 0; + + switch (instance->type) { + case PHY_TYPE_USB2: + ret = nvmem_cell_read_variable_le_u32(dev, "intr", &instance->efuse_intr); + if (ret) { + dev_err(dev, "fail to get u2 intr efuse, %d\n", ret); + break; + } + + /* no efuse, ignore it */ + if (!instance->efuse_intr) { + dev_warn(dev, "no u2 intr efuse, but dts enable it\n"); + instance->efuse_sw_en = 0; + break; + } + + dev_dbg(dev, "u2 efuse - intr %x\n", instance->efuse_intr); + break; + + case PHY_TYPE_USB3: + case PHY_TYPE_PCIE: + ret = nvmem_cell_read_variable_le_u32(dev, "intr", &instance->efuse_intr); + if (ret) { + dev_err(dev, "fail to get u3 intr efuse, %d\n", ret); + break; + } + + ret = nvmem_cell_read_variable_le_u32(dev, "rx_imp", &instance->efuse_rx_imp); + if (ret) { + dev_err(dev, "fail to get u3 rx_imp efuse, %d\n", ret); + break; + } + + ret = nvmem_cell_read_variable_le_u32(dev, "tx_imp", &instance->efuse_tx_imp); + if (ret) { + dev_err(dev, "fail to get u3 tx_imp efuse, %d\n", ret); + break; + } + + /* no efuse, ignore it */ + if (!instance->efuse_intr && + !instance->efuse_rx_imp && + !instance->efuse_rx_imp) { + dev_warn(dev, "no u3 intr efuse, but dts enable it\n"); + instance->efuse_sw_en = 0; + break; + } + + dev_dbg(dev, "u3 efuse - intr %x, rx_imp %x, tx_imp %x\n", + instance->efuse_intr, instance->efuse_rx_imp,instance->efuse_tx_imp); + break; + default: + dev_err(dev, "no sw efuse for type %d\n", instance->type); + ret = -EINVAL; + } + + return ret; +} + +static void phy_efuse_set(struct mtk_phy_instance *instance) +{ + struct device *dev = &instance->phy->dev; + struct u2phy_banks *u2_banks = &instance->u2_banks; + struct u3phy_banks *u3_banks = &instance->u3_banks; + u32 tmp; + + if (!instance->efuse_sw_en) + return; + + switch (instance->type) { + case PHY_TYPE_USB2: + tmp = readl(u2_banks->misc + U3P_MISC_REG1); + tmp |= MR1_EFUSE_AUTO_LOAD_DIS; + writel(tmp, u2_banks->misc + U3P_MISC_REG1); + + tmp = readl(u2_banks->com + U3P_USBPHYACR1); + tmp &= ~PA1_RG_INTR_CAL; + tmp |= PA1_RG_INTR_CAL_VAL(instance->efuse_intr); + writel(tmp, u2_banks->com + U3P_USBPHYACR1); + break; + case PHY_TYPE_USB3: + case PHY_TYPE_PCIE: + tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RSV); + tmp |= P3D_RG_EFUSE_AUTO_LOAD_DIS; + writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RSV); + + tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL0); + tmp &= ~P3D_RG_TX_IMPEL; + tmp |= P3D_RG_TX_IMPEL_VAL(instance->efuse_tx_imp); + tmp |= P3D_RG_FORCE_TX_IMPEL; + writel(tmp, u3_banks->phyd + U3P_U3_PHYD_IMPCAL0); + + tmp = readl(u3_banks->phyd + U3P_U3_PHYD_IMPCAL1); + tmp &= ~P3D_RG_RX_IMPEL; + tmp |= P3D_RG_RX_IMPEL_VAL(instance->efuse_rx_imp); + tmp |= P3D_RG_FORCE_RX_IMPEL; + writel(tmp, u3_banks->phyd + U3P_U3_PHYD_IMPCAL1); + + tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG0); + tmp &= ~P3A_RG_IEXT_INTR; + tmp |= P3A_RG_IEXT_INTR_VAL(instance->efuse_intr); + writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG0); + break; + default: + dev_warn(dev, "no sw efuse for type %d\n", instance->type); + break; + } +} + static int mtk_phy_init(struct phy *phy) { struct mtk_phy_instance *instance = phy_get_drvdata(phy); @@ -1050,6 +1202,8 @@ static int mtk_phy_init(struct phy *phy) if (ret) return ret;
+ phy_efuse_set(instance); + switch (instance->type) { case PHY_TYPE_USB2: u2_phy_instance_init(tphy, instance); @@ -1134,6 +1288,7 @@ static struct phy *mtk_phy_xlate(struct device *dev, struct mtk_phy_instance *instance = NULL; struct device_node *phy_np = args->np; int index; + int ret;
if (args->args_count != 1) { dev_err(dev, "invalid number of cells in 'phy' property\n"); @@ -1174,6 +1329,10 @@ static struct phy *mtk_phy_xlate(struct device *dev, return ERR_PTR(-EINVAL); }
+ ret = phy_efuse_get(tphy, instance); + if (ret) + return ERR_PTR(ret); + phy_parse_property(tphy, instance); phy_type_set(instance);
@@ -1196,10 +1355,12 @@ static const struct mtk_phy_pdata tphy_v1_pdata = {
static const struct mtk_phy_pdata tphy_v2_pdata = { .avoid_rx_sen_degradation = false, + .sw_efuse_supported = true, .version = MTK_PHY_V2, };
static const struct mtk_phy_pdata tphy_v3_pdata = { + .sw_efuse_supported = true, .version = MTK_PHY_V3, };
@@ -1210,6 +1371,7 @@ static const struct mtk_phy_pdata mt8173_pdata = {
static const struct mtk_phy_pdata mt8195_pdata = { .sw_pll_48m_to_26m = true, + .sw_efuse_supported = true, .version = MTK_PHY_V3, };
From: Tzung-Bi Shih tzungbi@google.com
[ Upstream commit 493433785df0075afc0c106ab65f10a605d0b35d ]
Fixes the device_node leak.
Signed-off-by: Tzung-Bi Shih tzungbi@google.com Link: https://lore.kernel.org/r/20211224064719.2031210-2-tzungbi@google.com Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/mediatek/mt8173/mt8173-max98090.c | 3 +++ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 2 ++ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 2 ++ sound/soc/mediatek/mt8173/mt8173-rt5650.c | 2 ++ 4 files changed, 9 insertions(+)
diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index fc94314bfc02f..3bdd4931316cd 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -180,6 +180,9 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + + of_node_put(codec_node); + of_node_put(platform_node); return ret; }
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 0f28dc2217c09..390da5bf727eb 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -218,6 +218,8 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + + of_node_put(platform_node); return ret; }
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 077c6ee067806..c8e4e85e10575 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -285,6 +285,8 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + + of_node_put(platform_node); return ret; }
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index c28ebf891cb05..e168d31f44459 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -323,6 +323,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", __func__, ret); + + of_node_put(platform_node); return ret; }
From: Tzung-Bi Shih tzungbi@google.com
[ Upstream commit cb006006fe6221f092fadaffd3f219288304c9ad ]
Fixes the device_node leak.
Signed-off-by: Tzung-Bi Shih tzungbi@google.com Link: https://lore.kernel.org/r/20211224064719.2031210-3-tzungbi@google.com Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c | 6 +++++- sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index a4d26a6fc8492..bda103211e0bd 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -781,7 +781,11 @@ static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev) return ret; }
- return devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(&pdev->dev, card); + + of_node_put(platform_node); + of_node_put(hdmi_codec); + return ret; }
#ifdef CONFIG_OF diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 94dcbd36c8697..c7b10c48c6c22 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -780,7 +780,12 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) __func__, ret); }
- return devm_snd_soc_register_card(&pdev->dev, card); + ret = devm_snd_soc_register_card(&pdev->dev, card); + + of_node_put(platform_node); + of_node_put(ec_codec); + of_node_put(hdmi_codec); + return ret; }
#ifdef CONFIG_OF
From: Ohad Sharabi osharabi@habana.ai
[ Upstream commit 4fac990f604e6c10538026835a8a30f3c1b6fcf5 ]
Reporting FW errors involves reading of the error registers.
In case we have a corrupted FW descriptor we cannot do that since the dynamic scratchpad is potentially corrupted as well and may cause kernel crush when attempting access to a corrupted register offset.
Signed-off-by: Ohad Sharabi osharabi@habana.ai Reviewed-by: Oded Gabbay ogabbay@kernel.org Signed-off-by: Oded Gabbay ogabbay@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/misc/habanalabs/common/firmware_if.c | 17 +++++++++++++++-- drivers/misc/habanalabs/common/habanalabs.h | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 8d2568c63f19e..a8e683964ab03 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1703,6 +1703,9 @@ static int hl_fw_dynamic_validate_descriptor(struct hl_device *hdev, return rc; }
+ /* here we can mark the descriptor as valid as the content has been validated */ + fw_loader->dynamic_loader.fw_desc_valid = true; + return 0; }
@@ -1759,7 +1762,13 @@ static int hl_fw_dynamic_read_and_validate_descriptor(struct hl_device *hdev, return rc; }
- /* extract address copy the descriptor from */ + /* + * extract address to copy the descriptor from + * in addition, as the descriptor value is going to be over-ridden by new data- we mark it + * as invalid. + * it will be marked again as valid once validated + */ + fw_loader->dynamic_loader.fw_desc_valid = false; src = hdev->pcie_bar[region->bar_id] + region->offset_in_bar + response->ram_offset; memcpy_fromio(fw_desc, src, sizeof(struct lkd_fw_comms_desc)); @@ -2239,6 +2248,9 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, dev_info(hdev->dev, "Loading firmware to device, may take some time...\n");
+ /* initialize FW descriptor as invalid */ + fw_loader->dynamic_loader.fw_desc_valid = false; + /* * In this stage, "cpu_dyn_regs" contains only LKD's hard coded values! * It will be updated from FW after hl_fw_dynamic_request_descriptor(). @@ -2325,7 +2337,8 @@ static int hl_fw_dynamic_init_cpu(struct hl_device *hdev, return 0;
protocol_err: - fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0), + if (fw_loader->dynamic_loader.fw_desc_valid) + fw_read_errors(hdev, le32_to_cpu(dyn_regs->cpu_boot_err0), le32_to_cpu(dyn_regs->cpu_boot_err1), le32_to_cpu(dyn_regs->cpu_boot_dev_sts0), le32_to_cpu(dyn_regs->cpu_boot_dev_sts1)); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index bebebcb163ee8..dfcd87b98ca08 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -992,6 +992,7 @@ struct fw_response { * @image_region: region to copy the FW image to * @fw_image_size: size of FW image to load * @wait_for_bl_timeout: timeout for waiting for boot loader to respond + * @fw_desc_valid: true if FW descriptor has been validated and hence the data can be used */ struct dynamic_fw_load_mgr { struct fw_response response; @@ -999,6 +1000,7 @@ struct dynamic_fw_load_mgr { struct pci_mem_region *image_region; size_t fw_image_size; u32 wait_for_bl_timeout; + bool fw_desc_valid; };
/**
From: Miaoqian Lin linmq006@gmail.com
[ Upstream commit 399c91c3f30531593e5ff6ca7b53f47092128669 ]
The of_device_get_match_data() function may return NULL. Add check to prevent potential null dereference.
Signed-off-by: Miaoqian Lin linmq006@gmail.com Reviewed-by: AngeloGioacchino Del Regno angelogioacchino.delregno@collabora.com Link: https://lore.kernel.org/r/20211224082103.7658-1-linmq006@gmail.com Signed-off-by: Vinod Koul vkoul@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c index 28ad9403c4414..67b005d5b9e35 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c @@ -146,6 +146,8 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) return -ENOMEM;
mipi_tx->driver_data = of_device_get_match_data(dev); + if (!mipi_tx->driver_data) + return -ENODEV;
mipi_tx->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mipi_tx->regs))
From: Conor Dooley conor.dooley@microchip.com
[ Upstream commit f10b1fc0161cd99e54c5687fcc63368aa255e05e ]
The Polarfire SoC is currently using two different compatible string prefixes. Fix this by changing "polarfire-soc-*" strings to "mpfs-*" in its system controller in order to match the compatible string used in the soc binding and device tree.
Signed-off-by: Conor Dooley conor.dooley@microchip.com Reviewed-by: Geert Uytterhoeven geert@linux-m68k.org Signed-off-by: Jassi Brar jaswinder.singh@linaro.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/mailbox/mailbox-mpfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c index 0d6e2231a2c75..4e34854d12389 100644 --- a/drivers/mailbox/mailbox-mpfs.c +++ b/drivers/mailbox/mailbox-mpfs.c @@ -232,7 +232,7 @@ static int mpfs_mbox_probe(struct platform_device *pdev) }
static const struct of_device_id mpfs_mbox_of_match[] = { - {.compatible = "microchip,polarfire-soc-mailbox", }, + {.compatible = "microchip,mpfs-mailbox", }, {}, }; MODULE_DEVICE_TABLE(of, mpfs_mbox_of_match);
From: Linus Walleij linus.walleij@linaro.org
[ Upstream commit b7f1ac9bb6413b739ea91bd61bdf23c9130a8007 ]
The board file using this driver has been deleted and the FSG3 LEDs can be modeled using a system controller and some register bit LEDs in the device tree so this driver is no longer needed.
Reported-by: Lukas Bulwahn lukas.bulwahn@gmail.com Cc: Krzysztof HaĆasa khalasa@piap.pl Cc: Rod Whitby rod@whitby.id.au Signed-off-by: Linus Walleij linus.walleij@linaro.org Signed-off-by: Pavel Machek pavel@ucw.cz Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/leds/Kconfig | 7 -- drivers/leds/Makefile | 1 - drivers/leds/leds-fsg.c | 193 ---------------------------------------- 3 files changed, 201 deletions(-) delete mode 100644 drivers/leds/leds-fsg.c
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index ed800f5da7d88..c262ee4453494 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -260,13 +260,6 @@ config LEDS_NET48XX This option enables support for the Soekris net4801 and net4826 error LED.
-config LEDS_FSG - tristate "LED Support for the Freecom FSG-3" - depends on LEDS_CLASS - depends on MACH_FSG - help - This option enables support for the LEDs on the Freecom FSG-3. - config LEDS_WRAP tristate "LED Support for the WRAP series LEDs" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index c636ec069612d..36506bddcc303 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -26,7 +26,6 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_CPCAP) += leds-cpcap.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o -obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c deleted file mode 100644 index bc6b420637d61..0000000000000 --- a/drivers/leds/leds-fsg.c +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * LED Driver for the Freecom FSG-3 - * - * Copyright (c) 2008 Rod Whitby rod@whitby.id.au - * - * Author: Rod Whitby rod@whitby.id.au - * - * Based on leds-spitz.c - * Copyright 2005-2006 Openedhand Ltd. - * Author: Richard Purdie rpurdie@openedhand.com - */ - -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/leds.h> -#include <linux/module.h> -#include <linux/io.h> -#include <mach/hardware.h> - -#define FSG_LED_WLAN_BIT 0 -#define FSG_LED_WAN_BIT 1 -#define FSG_LED_SATA_BIT 2 -#define FSG_LED_USB_BIT 4 -#define FSG_LED_RING_BIT 5 -#define FSG_LED_SYNC_BIT 7 - -static short __iomem *latch_address; -static unsigned short latch_value; - - -static void fsg_led_wlan_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) { - latch_value &= ~(1 << FSG_LED_WLAN_BIT); - *latch_address = latch_value; - } else { - latch_value |= (1 << FSG_LED_WLAN_BIT); - *latch_address = latch_value; - } -} - -static void fsg_led_wan_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) { - latch_value &= ~(1 << FSG_LED_WAN_BIT); - *latch_address = latch_value; - } else { - latch_value |= (1 << FSG_LED_WAN_BIT); - *latch_address = latch_value; - } -} - -static void fsg_led_sata_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) { - latch_value &= ~(1 << FSG_LED_SATA_BIT); - *latch_address = latch_value; - } else { - latch_value |= (1 << FSG_LED_SATA_BIT); - *latch_address = latch_value; - } -} - -static void fsg_led_usb_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) { - latch_value &= ~(1 << FSG_LED_USB_BIT); - *latch_address = latch_value; - } else { - latch_value |= (1 << FSG_LED_USB_BIT); - *latch_address = latch_value; - } -} - -static void fsg_led_sync_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) { - latch_value &= ~(1 << FSG_LED_SYNC_BIT); - *latch_address = latch_value; - } else { - latch_value |= (1 << FSG_LED_SYNC_BIT); - *latch_address = latch_value; - } -} - -static void fsg_led_ring_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - if (value) { - latch_value &= ~(1 << FSG_LED_RING_BIT); - *latch_address = latch_value; - } else { - latch_value |= (1 << FSG_LED_RING_BIT); - *latch_address = latch_value; - } -} - - -static struct led_classdev fsg_wlan_led = { - .name = "fsg:blue:wlan", - .brightness_set = fsg_led_wlan_set, - .flags = LED_CORE_SUSPENDRESUME, -}; - -static struct led_classdev fsg_wan_led = { - .name = "fsg:blue:wan", - .brightness_set = fsg_led_wan_set, - .flags = LED_CORE_SUSPENDRESUME, -}; - -static struct led_classdev fsg_sata_led = { - .name = "fsg:blue:sata", - .brightness_set = fsg_led_sata_set, - .flags = LED_CORE_SUSPENDRESUME, -}; - -static struct led_classdev fsg_usb_led = { - .name = "fsg:blue:usb", - .brightness_set = fsg_led_usb_set, - .flags = LED_CORE_SUSPENDRESUME, -}; - -static struct led_classdev fsg_sync_led = { - .name = "fsg:blue:sync", - .brightness_set = fsg_led_sync_set, - .flags = LED_CORE_SUSPENDRESUME, -}; - -static struct led_classdev fsg_ring_led = { - .name = "fsg:blue:ring", - .brightness_set = fsg_led_ring_set, - .flags = LED_CORE_SUSPENDRESUME, -}; - - -static int fsg_led_probe(struct platform_device *pdev) -{ - int ret; - - /* Map the LED chip select address space */ - latch_address = (unsigned short *) devm_ioremap(&pdev->dev, - IXP4XX_EXP_BUS_BASE(2), 512); - if (!latch_address) - return -ENOMEM; - - latch_value = 0xffff; - *latch_address = latch_value; - - ret = devm_led_classdev_register(&pdev->dev, &fsg_wlan_led); - if (ret < 0) - return ret; - - ret = devm_led_classdev_register(&pdev->dev, &fsg_wan_led); - if (ret < 0) - return ret; - - ret = devm_led_classdev_register(&pdev->dev, &fsg_sata_led); - if (ret < 0) - return ret; - - ret = devm_led_classdev_register(&pdev->dev, &fsg_usb_led); - if (ret < 0) - return ret; - - ret = devm_led_classdev_register(&pdev->dev, &fsg_sync_led); - if (ret < 0) - return ret; - - ret = devm_led_classdev_register(&pdev->dev, &fsg_ring_led); - if (ret < 0) - return ret; - - return ret; -} - -static struct platform_driver fsg_led_driver = { - .probe = fsg_led_probe, - .driver = { - .name = "fsg-led", - }, -}; - -module_platform_driver(fsg_led_driver); - -MODULE_AUTHOR("Rod Whitby rod@whitby.id.au"); -MODULE_DESCRIPTION("Freecom FSG-3 LED driver"); -MODULE_LICENSE("GPL");
linux-stable-mirror@lists.linaro.org