From: Sasha Levin Date: Fri, 8 Jul 2022 20:49:51 +0000 (-0400) Subject: Fixes for 5.15 X-Git-Tag: v4.9.323~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=99dbf936bcaa6cd8e2c155140846a6be832f0b55;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.15 Signed-off-by: Sasha Levin --- diff --git a/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mag-x570s-torpedo.patch b/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mag-x570s-torpedo.patch new file mode 100644 index 00000000000..83d8eec036f --- /dev/null +++ b/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mag-x570s-torpedo.patch @@ -0,0 +1,42 @@ +From 70d147f7a2a0e7ccf2c50d96f36c4490166bd763 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Apr 2022 15:16:12 +0200 +Subject: ALSA: usb-audio: add mapping for MSI MAG X570S Torpedo MAX. + +From: Maurizio Avogadro + +[ Upstream commit 4ddef9c4d70aae0c9029bdec7c3f7f1c1c51ff8c ] + +The USB audio device 0db0:a073 based on the Realtek ALC4080 chipset +exposes all playback volume controls as "PCM". This makes +distinguishing the individual functions hard. +The mapping already adopted for device 0db0:419c based on the same +chipset fixes the issue, apply it for this device too. + +Signed-off-by: Maurizio Avogadro +Cc: +Link: https://lore.kernel.org/r/Yl1ykPaGgsFf3SnW@ryzen +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_maps.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c +index 64fdca76b40e..997425ef0a29 100644 +--- a/sound/usb/mixer_maps.c ++++ b/sound/usb/mixer_maps.c +@@ -586,6 +586,10 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { + .id = USB_ID(0x0db0, 0x419c), + .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map, + }, ++ { /* MSI MAG X570S Torpedo Max */ ++ .id = USB_ID(0x0db0, 0xa073), ++ .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map, ++ }, + { /* MSI TRX40 */ + .id = USB_ID(0x0db0, 0x543d), + .map = trx40_mobo_map, +-- +2.35.1 + diff --git a/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mpg-x570s-carbon-.patch b/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mpg-x570s-carbon-.patch new file mode 100644 index 00000000000..ea121ee6c77 --- /dev/null +++ b/queue-5.15/alsa-usb-audio-add-mapping-for-msi-mpg-x570s-carbon-.patch @@ -0,0 +1,62 @@ +From b63fa9e91ceffba521c0fee09d1d2cbd80fbffe8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 15 Jan 2022 15:02:57 +0100 +Subject: ALSA: usb-audio: add mapping for MSI MPG X570S Carbon Max Wifi. + +From: Johannes Schickel + +[ Upstream commit 5762f980ca10dcfe5eead7c40d1c34cae61f409b ] + +The USB audio device 0db0:419c based on the Realtek ALC4080 chip exposes +all playback volume controls as "PCM". This is makes distinguishing the +individual functions hard. + +The added mapping distinguishes all playback volume controls as their +respective function: + - Speaker - for back panel output + - Frontpanel Headphone - for front panel output + - IEC958 - for digital output on the back panel + +This clarifies the individual volume control functions for users. + +Signed-off-by: Johannes Schickel +Link: https://lore.kernel.org/r/20220115140257.8751-1-lordhoto@gmail.com +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/usb/mixer_maps.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c +index 6ffd23f2ee65..64fdca76b40e 100644 +--- a/sound/usb/mixer_maps.c ++++ b/sound/usb/mixer_maps.c +@@ -423,6 +423,14 @@ static const struct usbmix_name_map aorus_master_alc1220vb_map[] = { + {} + }; + ++/* MSI MPG X570S Carbon Max Wifi with ALC4080 */ ++static const struct usbmix_name_map msi_mpg_x570s_carbon_max_wifi_alc4080_map[] = { ++ { 29, "Speaker Playback" }, ++ { 30, "Front Headphone Playback" }, ++ { 32, "IEC958 Playback" }, ++ {} ++}; ++ + /* + * Control map entries + */ +@@ -574,6 +582,10 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { + .map = trx40_mobo_map, + .connector_map = trx40_mobo_connector_map, + }, ++ { /* MSI MPG X570S Carbon Max Wifi */ ++ .id = USB_ID(0x0db0, 0x419c), ++ .map = msi_mpg_x570s_carbon_max_wifi_alc4080_map, ++ }, + { /* MSI TRX40 */ + .id = USB_ID(0x0db0, 0x543d), + .map = trx40_mobo_map, +-- +2.35.1 + diff --git a/queue-5.15/asoc-rt5682-avoid-the-unexpected-irq-event-during-go.patch b/queue-5.15/asoc-rt5682-avoid-the-unexpected-irq-event-during-go.patch new file mode 100644 index 00000000000..2638f42a4c5 --- /dev/null +++ b/queue-5.15/asoc-rt5682-avoid-the-unexpected-irq-event-during-go.patch @@ -0,0 +1,66 @@ +From a1d66cbea10efc22a7dab5b80c5f03ef93b3357b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Nov 2021 17:54:49 +0800 +Subject: ASoC: rt5682: Avoid the unexpected IRQ event during going to suspend + +From: Derek Fang + +[ Upstream commit a3774a2a6544a7a4a85186e768afc07044aa507f ] + +When the system suspends, the codec driver will set SAR to +power saving mode if a headset is plugged in. +There is a chance to generate an unexpected IRQ, and leads to +issues after resuming such as noise from OMTP type headsets. + +Signed-off-by: Derek Fang +Link: https://lore.kernel.org/r/20211109095450.12950-1-derek.fang@realtek.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5682.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c +index 6ad3159eceb9..949b5638db29 100644 +--- a/sound/soc/codecs/rt5682.c ++++ b/sound/soc/codecs/rt5682.c +@@ -48,6 +48,7 @@ static const struct reg_sequence patch_list[] = { + {RT5682_SAR_IL_CMD_6, 0x0110}, + {RT5682_CHARGE_PUMP_1, 0x0210}, + {RT5682_HP_LOGIC_CTRL_2, 0x0007}, ++ {RT5682_SAR_IL_CMD_2, 0xac00}, + }; + + void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev) +@@ -2969,9 +2970,6 @@ static int rt5682_suspend(struct snd_soc_component *component) + cancel_delayed_work_sync(&rt5682->jack_detect_work); + cancel_delayed_work_sync(&rt5682->jd_check_work); + if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) { +- snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, +- RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK, +- RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG); + val = snd_soc_component_read(component, + RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK; + +@@ -2993,10 +2991,15 @@ static int rt5682_suspend(struct snd_soc_component *component) + /* enter SAR ADC power saving mode */ + snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1, + RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK | +- RT5682_SAR_BUTDET_RST_MASK | RT5682_SAR_SEL_MB1_MB2_MASK, 0); ++ RT5682_SAR_SEL_MB1_MB2_MASK, 0); ++ usleep_range(5000, 6000); ++ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, ++ RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK, ++ RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG); ++ usleep_range(10000, 12000); + snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1, +- RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_BUTDET_RST_MASK, +- RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV | RT5682_SAR_BUTDET_RST_NORMAL); ++ RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK, ++ RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV); + } + + regcache_cache_only(rt5682->regmap, true); +-- +2.35.1 + diff --git a/queue-5.15/asoc-rt5682-fix-an-incorrect-null-check-on-list-iter.patch b/queue-5.15/asoc-rt5682-fix-an-incorrect-null-check-on-list-iter.patch new file mode 100644 index 00000000000..3d5ac7fe33a --- /dev/null +++ b/queue-5.15/asoc-rt5682-fix-an-incorrect-null-check-on-list-iter.patch @@ -0,0 +1,60 @@ +From 15f05c1212d9a693668dd609552053578031b19b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 27 Mar 2022 16:10:02 +0800 +Subject: ASoC: rt5682: fix an incorrect NULL check on list iterator + +From: Xiaomeng Tong + +[ Upstream commit c8618d65007ba68d7891130642d73e89372101e8 ] + +The bug is here: + if (!dai) { + +The list iterator value 'dai' will *always* be set and non-NULL +by for_each_component_dais(), so it is incorrect to assume that +the iterator value will be NULL if the list is empty or no element +is found (In fact, it will be a bogus pointer to an invalid struct +object containing the HEAD). Otherwise it will bypass the check +'if (!dai) {' (never call dev_err() and never return -ENODEV;) +and lead to invalid memory access lately when calling +'rt5682_set_bclk1_ratio(dai, factor);'. + +To fix the bug, just return rt5682_set_bclk1_ratio(dai, factor); +when found the 'dai', otherwise dev_err() and return -ENODEV; + +Cc: stable@vger.kernel.org +Fixes: ebbfabc16d23d ("ASoC: rt5682: Add CCF usage for providing I2S clks") +Signed-off-by: Xiaomeng Tong +Link: https://lore.kernel.org/r/20220327081002.12684-1-xiam0nd.tong@gmail.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5682.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c +index 80d199843b8c..8a9e1a4fa03e 100644 +--- a/sound/soc/codecs/rt5682.c ++++ b/sound/soc/codecs/rt5682.c +@@ -2822,14 +2822,11 @@ static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate, + + for_each_component_dais(component, dai) + if (dai->id == RT5682_AIF1) +- break; +- if (!dai) { +- dev_err(rt5682->i2c_dev, "dai %d not found in component\n", +- RT5682_AIF1); +- return -ENODEV; +- } ++ return rt5682_set_bclk1_ratio(dai, factor); + +- return rt5682_set_bclk1_ratio(dai, factor); ++ dev_err(rt5682->i2c_dev, "dai %d not found in component\n", ++ RT5682_AIF1); ++ return -ENODEV; + } + + static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = { +-- +2.35.1 + diff --git a/queue-5.15/asoc-rt5682-fix-deadlock-on-resume.patch b/queue-5.15/asoc-rt5682-fix-deadlock-on-resume.patch new file mode 100644 index 00000000000..d8b24b5ec91 --- /dev/null +++ b/queue-5.15/asoc-rt5682-fix-deadlock-on-resume.patch @@ -0,0 +1,200 @@ +From 24475d1fc560af3cb3e0f6796b2933691ae2eda5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Jan 2022 12:03:25 +0200 +Subject: ASoC: rt5682: Fix deadlock on resume + +From: Peter Ujfalusi + +[ Upstream commit 4045daf0fa87846a27f56329fddad2deeb5ca354 ] + +On resume from suspend the following chain of events can happen: +A rt5682_resume() -> mod_delayed_work() for jack_detect_work +B DAPM sequence starts ( DAPM is locked now) + +A1. rt5682_jack_detect_handler() scheduled + - Takes both jdet_mutex and calibrate_mutex + - Calls in to rt5682_headset_detect() which tries to take DAPM lock, it + starts to wait for it as B path took it already. +B1. DAPM sequence reaches the "HP Amp", rt5682_hp_event() tries to take + the jdet_mutex, but it is locked in A1, so it waits. + +Deadlock. + +To solve the deadlock, drop the jdet_mutex, use the jack_detect_work to do +the jack removal handling, move the dapm lock up one level to protect the +most of the rt5682_jack_detect_handler(), but not the jack reporting as it +might trigger a DAPM sequence. +The rt5682_headset_detect() can be changed to static as well. + +Fixes: 8deb34a90f063 ("ASoC: rt5682: fix the wrong jack type detected") +Signed-off-by: Peter Ujfalusi +Link: https://lore.kernel.org/r/20220126100325.16513-1-peter.ujfalusi@linux.intel.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5682-i2c.c | 15 ++++----------- + sound/soc/codecs/rt5682.c | 24 ++++++++---------------- + sound/soc/codecs/rt5682.h | 2 -- + 3 files changed, 12 insertions(+), 29 deletions(-) + +diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c +index b17c14b8b36e..74a1fee071dd 100644 +--- a/sound/soc/codecs/rt5682-i2c.c ++++ b/sound/soc/codecs/rt5682-i2c.c +@@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work) + struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv, + jd_check_work.work); + +- if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) +- & RT5682_JDH_RS_MASK) { ++ if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK) + /* jack out */ +- rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0); +- +- snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type, +- SND_JACK_HEADSET | +- SND_JACK_BTN_0 | SND_JACK_BTN_1 | +- SND_JACK_BTN_2 | SND_JACK_BTN_3); +- } else { ++ mod_delayed_work(system_power_efficient_wq, ++ &rt5682->jack_detect_work, 0); ++ else + schedule_delayed_work(&rt5682->jd_check_work, 500); +- } + } + + static irqreturn_t rt5682_irq(int irq, void *data) +@@ -196,7 +190,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, + } + + mutex_init(&rt5682->calibrate_mutex); +- mutex_init(&rt5682->jdet_mutex); + rt5682_calibrate(rt5682); + + rt5682_apply_patch_list(rt5682, &i2c->dev); +diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c +index d470b9189768..1cd59e166cce 100644 +--- a/sound/soc/codecs/rt5682.c ++++ b/sound/soc/codecs/rt5682.c +@@ -922,15 +922,13 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component, + * + * Returns detect status. + */ +-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) ++static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) + { + struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = &component->dapm; + unsigned int val, count; + + if (jack_insert) { +- snd_soc_dapm_mutex_lock(dapm); +- + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, + RT5682_PWR_VREF2 | RT5682_PWR_MB, + RT5682_PWR_VREF2 | RT5682_PWR_MB); +@@ -981,8 +979,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) + snd_soc_component_update_bits(component, RT5682_MICBIAS_2, + RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK, + RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU); +- +- snd_soc_dapm_mutex_unlock(dapm); + } else { + rt5682_enable_push_button_irq(component, false); + snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, +@@ -1011,7 +1007,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) + dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type); + return rt5682->jack_type; + } +-EXPORT_SYMBOL_GPL(rt5682_headset_detect); + + static int rt5682_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +@@ -1094,6 +1089,7 @@ void rt5682_jack_detect_handler(struct work_struct *work) + { + struct rt5682_priv *rt5682 = + container_of(work, struct rt5682_priv, jack_detect_work.work); ++ struct snd_soc_dapm_context *dapm; + int val, btn_type; + + if (!rt5682->component || !rt5682->component->card || +@@ -1104,7 +1100,9 @@ void rt5682_jack_detect_handler(struct work_struct *work) + return; + } + +- mutex_lock(&rt5682->jdet_mutex); ++ dapm = snd_soc_component_get_dapm(rt5682->component); ++ ++ snd_soc_dapm_mutex_lock(dapm); + mutex_lock(&rt5682->calibrate_mutex); + + val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) +@@ -1164,6 +1162,9 @@ void rt5682_jack_detect_handler(struct work_struct *work) + rt5682->irq_work_delay_time = 50; + } + ++ mutex_unlock(&rt5682->calibrate_mutex); ++ snd_soc_dapm_mutex_unlock(dapm); ++ + snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | +@@ -1176,9 +1177,6 @@ void rt5682_jack_detect_handler(struct work_struct *work) + else + cancel_delayed_work_sync(&rt5682->jd_check_work); + } +- +- mutex_unlock(&rt5682->calibrate_mutex); +- mutex_unlock(&rt5682->jdet_mutex); + } + EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler); + +@@ -1528,7 +1526,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, + { + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); +- struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: +@@ -1540,17 +1537,12 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, + RT5682_DEPOP_1, 0x60, 0x60); + snd_soc_component_update_bits(component, + RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080); +- +- mutex_lock(&rt5682->jdet_mutex); +- + snd_soc_component_update_bits(component, RT5682_HP_CTRL_2, + RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN, + RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN); + usleep_range(5000, 10000); + snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1, + RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L); +- +- mutex_unlock(&rt5682->jdet_mutex); + break; + + case SND_SOC_DAPM_POST_PMD: +diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h +index f866d207d1bd..539a9fe26294 100644 +--- a/sound/soc/codecs/rt5682.h ++++ b/sound/soc/codecs/rt5682.h +@@ -1462,7 +1462,6 @@ struct rt5682_priv { + + int jack_type; + int irq_work_delay_time; +- struct mutex jdet_mutex; + }; + + extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES]; +@@ -1472,7 +1471,6 @@ int rt5682_sel_asrc_clk_src(struct snd_soc_component *component, + + void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev); + +-int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert); + void rt5682_jack_detect_handler(struct work_struct *work); + + bool rt5682_volatile_register(struct device *dev, unsigned int reg); +-- +2.35.1 + diff --git a/queue-5.15/asoc-rt5682-move-clk-related-code-to-rt5682_i2c_prob.patch b/queue-5.15/asoc-rt5682-move-clk-related-code-to-rt5682_i2c_prob.patch new file mode 100644 index 00000000000..811f5ddcc81 --- /dev/null +++ b/queue-5.15/asoc-rt5682-move-clk-related-code-to-rt5682_i2c_prob.patch @@ -0,0 +1,301 @@ +From 75edcb0cd088c3241d04806301160d9fb537c70b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Sep 2021 13:43:44 +0800 +Subject: ASoC: rt5682: move clk related code to rt5682_i2c_probe + +From: Jack Yu + +[ Upstream commit 57589f82762e40bdaa975d840fa2bc5157b5be95 ] + +The DAI clock is only used in I2S mode, to make it clear +and to fix clock resource release issue, we move CCF clock +related code to rt5682_i2c_probe to fix clock +register/unregister issue. + +Signed-off-by: Jack Yu +Link: https://lore.kernel.org/r/20210929054344.12112-1-jack.yu@realtek.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5682-i2c.c | 22 +++++++++++ + sound/soc/codecs/rt5682.c | 70 +++++++++++++---------------------- + sound/soc/codecs/rt5682.h | 3 ++ + 3 files changed, 51 insertions(+), 44 deletions(-) + +diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c +index 74a1fee071dd..3d2d7c9ce66d 100644 +--- a/sound/soc/codecs/rt5682-i2c.c ++++ b/sound/soc/codecs/rt5682-i2c.c +@@ -133,6 +133,8 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, + + i2c_set_clientdata(i2c, rt5682); + ++ rt5682->i2c_dev = &i2c->dev; ++ + rt5682->pdata = i2s_default_platform_data; + + if (pdata) +@@ -270,6 +272,26 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, + dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + } + ++#ifdef CONFIG_COMMON_CLK ++ /* Check if MCLK provided */ ++ rt5682->mclk = devm_clk_get(&i2c->dev, "mclk"); ++ if (IS_ERR(rt5682->mclk)) { ++ if (PTR_ERR(rt5682->mclk) != -ENOENT) { ++ ret = PTR_ERR(rt5682->mclk); ++ return ret; ++ } ++ rt5682->mclk = NULL; ++ } ++ ++ /* Register CCF DAI clock control */ ++ ret = rt5682_register_dai_clks(rt5682); ++ if (ret) ++ return ret; ++ ++ /* Initial setup for CCF */ ++ rt5682->lrck[RT5682_AIF1] = 48000; ++#endif ++ + return devm_snd_soc_register_component(&i2c->dev, + &rt5682_soc_component_dev, + rt5682_dai, ARRAY_SIZE(rt5682_dai)); +diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c +index 1cd59e166cce..80d199843b8c 100644 +--- a/sound/soc/codecs/rt5682.c ++++ b/sound/soc/codecs/rt5682.c +@@ -2562,7 +2562,7 @@ static int rt5682_set_bias_level(struct snd_soc_component *component, + static bool rt5682_clk_check(struct rt5682_priv *rt5682) + { + if (!rt5682->master[RT5682_AIF1]) { +- dev_dbg(rt5682->component->dev, "sysclk/dai not set correctly\n"); ++ dev_dbg(rt5682->i2c_dev, "sysclk/dai not set correctly\n"); + return false; + } + return true; +@@ -2573,13 +2573,15 @@ static int rt5682_wclk_prepare(struct clk_hw *hw) + struct rt5682_priv *rt5682 = + container_of(hw, struct rt5682_priv, + dai_clks_hw[RT5682_DAI_WCLK_IDX]); +- struct snd_soc_component *component = rt5682->component; +- struct snd_soc_dapm_context *dapm = +- snd_soc_component_get_dapm(component); ++ struct snd_soc_component *component; ++ struct snd_soc_dapm_context *dapm; + + if (!rt5682_clk_check(rt5682)) + return -EINVAL; + ++ component = rt5682->component; ++ dapm = snd_soc_component_get_dapm(component); ++ + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS"); +@@ -2609,13 +2611,15 @@ static void rt5682_wclk_unprepare(struct clk_hw *hw) + struct rt5682_priv *rt5682 = + container_of(hw, struct rt5682_priv, + dai_clks_hw[RT5682_DAI_WCLK_IDX]); +- struct snd_soc_component *component = rt5682->component; +- struct snd_soc_dapm_context *dapm = +- snd_soc_component_get_dapm(component); ++ struct snd_soc_component *component; ++ struct snd_soc_dapm_context *dapm; + + if (!rt5682_clk_check(rt5682)) + return; + ++ component = rt5682->component; ++ dapm = snd_soc_component_get_dapm(component); ++ + snd_soc_dapm_mutex_lock(dapm); + + snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS"); +@@ -2639,7 +2643,6 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw, + struct rt5682_priv *rt5682 = + container_of(hw, struct rt5682_priv, + dai_clks_hw[RT5682_DAI_WCLK_IDX]); +- struct snd_soc_component *component = rt5682->component; + const char * const clk_name = clk_hw_get_name(hw); + + if (!rt5682_clk_check(rt5682)) +@@ -2649,7 +2652,7 @@ static unsigned long rt5682_wclk_recalc_rate(struct clk_hw *hw, + */ + if (rt5682->lrck[RT5682_AIF1] != CLK_48 && + rt5682->lrck[RT5682_AIF1] != CLK_44) { +- dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n", ++ dev_warn(rt5682->i2c_dev, "%s: clk %s only support %d or %d Hz output\n", + __func__, clk_name, CLK_44, CLK_48); + return 0; + } +@@ -2663,7 +2666,6 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate, + struct rt5682_priv *rt5682 = + container_of(hw, struct rt5682_priv, + dai_clks_hw[RT5682_DAI_WCLK_IDX]); +- struct snd_soc_component *component = rt5682->component; + const char * const clk_name = clk_hw_get_name(hw); + + if (!rt5682_clk_check(rt5682)) +@@ -2673,7 +2675,7 @@ static long rt5682_wclk_round_rate(struct clk_hw *hw, unsigned long rate, + * It will force to 48kHz if not both. + */ + if (rate != CLK_48 && rate != CLK_44) { +- dev_warn(component->dev, "%s: clk %s only support %d or %d Hz output\n", ++ dev_warn(rt5682->i2c_dev, "%s: clk %s only support %d or %d Hz output\n", + __func__, clk_name, CLK_44, CLK_48); + rate = CLK_48; + } +@@ -2687,7 +2689,7 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate, + struct rt5682_priv *rt5682 = + container_of(hw, struct rt5682_priv, + dai_clks_hw[RT5682_DAI_WCLK_IDX]); +- struct snd_soc_component *component = rt5682->component; ++ struct snd_soc_component *component; + struct clk_hw *parent_hw; + const char * const clk_name = clk_hw_get_name(hw); + int pre_div; +@@ -2696,6 +2698,8 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate, + if (!rt5682_clk_check(rt5682)) + return -EINVAL; + ++ component = rt5682->component; ++ + /* + * Whether the wclk's parent clk (mclk) exists or not, please ensure + * it is fixed or set to 48MHz before setting wclk rate. It's a +@@ -2705,12 +2709,12 @@ static int rt5682_wclk_set_rate(struct clk_hw *hw, unsigned long rate, + */ + parent_hw = clk_hw_get_parent(hw); + if (!parent_hw) +- dev_warn(component->dev, ++ dev_warn(rt5682->i2c_dev, + "Parent mclk of wclk not acquired in driver. Please ensure mclk was provided as %d Hz.\n", + CLK_PLL2_FIN); + + if (parent_rate != CLK_PLL2_FIN) +- dev_warn(component->dev, "clk %s only support %d Hz input\n", ++ dev_warn(rt5682->i2c_dev, "clk %s only support %d Hz input\n", + clk_name, CLK_PLL2_FIN); + + /* +@@ -2742,10 +2746,9 @@ static unsigned long rt5682_bclk_recalc_rate(struct clk_hw *hw, + struct rt5682_priv *rt5682 = + container_of(hw, struct rt5682_priv, + dai_clks_hw[RT5682_DAI_BCLK_IDX]); +- struct snd_soc_component *component = rt5682->component; + unsigned int bclks_per_wclk; + +- bclks_per_wclk = snd_soc_component_read(component, RT5682_TDM_TCON_CTRL); ++ regmap_read(rt5682->regmap, RT5682_TDM_TCON_CTRL, &bclks_per_wclk); + + switch (bclks_per_wclk & RT5682_TDM_BCLK_MS1_MASK) { + case RT5682_TDM_BCLK_MS1_256: +@@ -2806,20 +2809,22 @@ static int rt5682_bclk_set_rate(struct clk_hw *hw, unsigned long rate, + struct rt5682_priv *rt5682 = + container_of(hw, struct rt5682_priv, + dai_clks_hw[RT5682_DAI_BCLK_IDX]); +- struct snd_soc_component *component = rt5682->component; ++ struct snd_soc_component *component; + struct snd_soc_dai *dai; + unsigned long factor; + + if (!rt5682_clk_check(rt5682)) + return -EINVAL; + ++ component = rt5682->component; ++ + factor = rt5682_bclk_get_factor(rate, parent_rate); + + for_each_component_dais(component, dai) + if (dai->id == RT5682_AIF1) + break; + if (!dai) { +- dev_err(component->dev, "dai %d not found in component\n", ++ dev_err(rt5682->i2c_dev, "dai %d not found in component\n", + RT5682_AIF1); + return -ENODEV; + } +@@ -2842,10 +2847,9 @@ static const struct clk_ops rt5682_dai_clk_ops[RT5682_DAI_NUM_CLKS] = { + }, + }; + +-static int rt5682_register_dai_clks(struct snd_soc_component *component) ++int rt5682_register_dai_clks(struct rt5682_priv *rt5682) + { +- struct device *dev = component->dev; +- struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); ++ struct device *dev = rt5682->i2c_dev; + struct rt5682_platform_data *pdata = &rt5682->pdata; + struct clk_hw *dai_clk_hw; + int i, ret; +@@ -2905,6 +2909,7 @@ static int rt5682_register_dai_clks(struct snd_soc_component *component) + + return 0; + } ++EXPORT_SYMBOL_GPL(rt5682_register_dai_clks); + #endif /* CONFIG_COMMON_CLK */ + + static int rt5682_probe(struct snd_soc_component *component) +@@ -2914,9 +2919,6 @@ static int rt5682_probe(struct snd_soc_component *component) + unsigned long time; + struct snd_soc_dapm_context *dapm = &component->dapm; + +-#ifdef CONFIG_COMMON_CLK +- int ret; +-#endif + rt5682->component = component; + + if (rt5682->is_sdw) { +@@ -2928,26 +2930,6 @@ static int rt5682_probe(struct snd_soc_component *component) + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + return -ETIMEDOUT; + } +- } else { +-#ifdef CONFIG_COMMON_CLK +- /* Check if MCLK provided */ +- rt5682->mclk = devm_clk_get(component->dev, "mclk"); +- if (IS_ERR(rt5682->mclk)) { +- if (PTR_ERR(rt5682->mclk) != -ENOENT) { +- ret = PTR_ERR(rt5682->mclk); +- return ret; +- } +- rt5682->mclk = NULL; +- } +- +- /* Register CCF DAI clock control */ +- ret = rt5682_register_dai_clks(component); +- if (ret) +- return ret; +- +- /* Initial setup for CCF */ +- rt5682->lrck[RT5682_AIF1] = CLK_48; +-#endif + } + + snd_soc_dapm_disable_pin(dapm, "MICBIAS"); +diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h +index 539a9fe26294..52ff0d9c36c5 100644 +--- a/sound/soc/codecs/rt5682.h ++++ b/sound/soc/codecs/rt5682.h +@@ -1428,6 +1428,7 @@ enum { + + struct rt5682_priv { + struct snd_soc_component *component; ++ struct device *i2c_dev; + struct rt5682_platform_data pdata; + struct regmap *regmap; + struct regmap *sdw_regmap; +@@ -1481,6 +1482,8 @@ void rt5682_calibrate(struct rt5682_priv *rt5682); + void rt5682_reset(struct rt5682_priv *rt5682); + int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev); + ++int rt5682_register_dai_clks(struct rt5682_priv *rt5682); ++ + #define RT5682_REG_NUM 318 + extern const struct reg_default rt5682_reg[RT5682_REG_NUM]; + +-- +2.35.1 + diff --git a/queue-5.15/asoc-rt5682-re-detect-the-combo-jack-after-resuming.patch b/queue-5.15/asoc-rt5682-re-detect-the-combo-jack-after-resuming.patch new file mode 100644 index 00000000000..d39885fee7e --- /dev/null +++ b/queue-5.15/asoc-rt5682-re-detect-the-combo-jack-after-resuming.patch @@ -0,0 +1,157 @@ +From 2cf86625feb194848dabe1ba576373078aaf7d17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 Nov 2021 17:54:50 +0800 +Subject: ASoC: rt5682: Re-detect the combo jack after resuming + +From: Derek Fang + +[ Upstream commit 2cd9b0ef82d936623d789bb3fbb6fcf52c500367 ] + +Sometimes, end-users change the jack type under suspending, +so it needs to re-detect the combo jack type after resuming to +avoid any unexpected behaviors. + +Signed-off-by: Derek Fang +Link: https://lore.kernel.org/r/20211109095450.12950-2-derek.fang@realtek.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/rt5682-i2c.c | 1 + + sound/soc/codecs/rt5682.c | 23 ++++++++++++++++++++--- + sound/soc/codecs/rt5682.h | 1 + + 3 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c +index b9d5d7a0975b..b17c14b8b36e 100644 +--- a/sound/soc/codecs/rt5682-i2c.c ++++ b/sound/soc/codecs/rt5682-i2c.c +@@ -196,6 +196,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, + } + + mutex_init(&rt5682->calibrate_mutex); ++ mutex_init(&rt5682->jdet_mutex); + rt5682_calibrate(rt5682); + + rt5682_apply_patch_list(rt5682, &i2c->dev); +diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c +index 949b5638db29..d470b9189768 100644 +--- a/sound/soc/codecs/rt5682.c ++++ b/sound/soc/codecs/rt5682.c +@@ -49,6 +49,7 @@ static const struct reg_sequence patch_list[] = { + {RT5682_CHARGE_PUMP_1, 0x0210}, + {RT5682_HP_LOGIC_CTRL_2, 0x0007}, + {RT5682_SAR_IL_CMD_2, 0xac00}, ++ {RT5682_CBJ_CTRL_7, 0x0104}, + }; + + void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev) +@@ -943,6 +944,10 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) + snd_soc_component_update_bits(component, + RT5682_HP_CHARGE_PUMP_1, + RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0); ++ rt5682_enable_push_button_irq(component, false); ++ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, ++ RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW); ++ usleep_range(55000, 60000); + snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, + RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH); + +@@ -1099,6 +1104,7 @@ void rt5682_jack_detect_handler(struct work_struct *work) + return; + } + ++ mutex_lock(&rt5682->jdet_mutex); + mutex_lock(&rt5682->calibrate_mutex); + + val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) +@@ -1172,6 +1178,7 @@ void rt5682_jack_detect_handler(struct work_struct *work) + } + + mutex_unlock(&rt5682->calibrate_mutex); ++ mutex_unlock(&rt5682->jdet_mutex); + } + EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler); + +@@ -1521,6 +1528,7 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, + { + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); ++ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: +@@ -1532,12 +1540,17 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, + RT5682_DEPOP_1, 0x60, 0x60); + snd_soc_component_update_bits(component, + RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080); ++ ++ mutex_lock(&rt5682->jdet_mutex); ++ + snd_soc_component_update_bits(component, RT5682_HP_CTRL_2, + RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN, + RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN); + usleep_range(5000, 10000); + snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1, + RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L); ++ ++ mutex_unlock(&rt5682->jdet_mutex); + break; + + case SND_SOC_DAPM_POST_PMD: +@@ -2969,7 +2982,7 @@ static int rt5682_suspend(struct snd_soc_component *component) + + cancel_delayed_work_sync(&rt5682->jack_detect_work); + cancel_delayed_work_sync(&rt5682->jd_check_work); +- if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) { ++ if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) { + val = snd_soc_component_read(component, + RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK; + +@@ -3000,6 +3013,8 @@ static int rt5682_suspend(struct snd_soc_component *component) + snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1, + RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK, + RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV); ++ snd_soc_component_update_bits(component, RT5682_HP_CHARGE_PUMP_1, ++ RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0); + } + + regcache_cache_only(rt5682->regmap, true); +@@ -3017,10 +3032,11 @@ static int rt5682_resume(struct snd_soc_component *component) + regcache_cache_only(rt5682->regmap, false); + regcache_sync(rt5682->regmap); + +- if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) { ++ if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) { + snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1, + RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_SEL_MB1_MB2_MASK, + RT5682_SAR_BUTDET_POW_NORM | RT5682_SAR_SEL_MB1_MB2_AUTO); ++ usleep_range(5000, 6000); + snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, + RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK, + RT5682_CTRL_MB1_FSM | RT5682_CTRL_MB2_FSM); +@@ -3028,8 +3044,9 @@ static int rt5682_resume(struct snd_soc_component *component) + RT5682_PWR_CBJ, RT5682_PWR_CBJ); + } + ++ rt5682->jack_type = 0; + mod_delayed_work(system_power_efficient_wq, +- &rt5682->jack_detect_work, msecs_to_jiffies(250)); ++ &rt5682->jack_detect_work, msecs_to_jiffies(0)); + + return 0; + } +diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h +index 8e3244a62c16..f866d207d1bd 100644 +--- a/sound/soc/codecs/rt5682.h ++++ b/sound/soc/codecs/rt5682.h +@@ -1462,6 +1462,7 @@ struct rt5682_priv { + + int jack_type; + int irq_work_delay_time; ++ struct mutex jdet_mutex; + }; + + extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES]; +-- +2.35.1 + diff --git a/queue-5.15/ath11k-add-hw_param-for-wakeup_mhi.patch b/queue-5.15/ath11k-add-hw_param-for-wakeup_mhi.patch new file mode 100644 index 00000000000..9d2700a93d0 --- /dev/null +++ b/queue-5.15/ath11k-add-hw_param-for-wakeup_mhi.patch @@ -0,0 +1,151 @@ +From e21ac40cdf6c0767cda95ef71764207abbbbadaa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 Nov 2021 09:39:41 +0200 +Subject: ath11k: add hw_param for wakeup_mhi + +From: Seevalamuthu Mariappan + +[ Upstream commit 081e2d6476e30399433b509684d5da4d1844e430 ] + +Wakeup mhi is needed before pci_read/write only for QCA6390 and WCN6855. Since +wakeup & release mhi is enabled for all hardwares, below mhi assert is seen in +QCN9074 when doing 'rmmod ath11k_pci': + + Kernel panic - not syncing: dev_wake != 0 + CPU: 2 PID: 13535 Comm: procd Not tainted 4.4.60 #1 + Hardware name: Generic DT based system + [<80316dac>] (unwind_backtrace) from [<80313700>] (show_stack+0x10/0x14) + [<80313700>] (show_stack) from [<805135dc>] (dump_stack+0x7c/0x9c) + [<805135dc>] (dump_stack) from [<8032136c>] (panic+0x84/0x1f8) + [<8032136c>] (panic) from [<80549b24>] (mhi_pm_disable_transition+0x3b8/0x5b8) + [<80549b24>] (mhi_pm_disable_transition) from [<80549ddc>] (mhi_power_down+0xb8/0x100) + [<80549ddc>] (mhi_power_down) from [<7f5242b0>] (ath11k_mhi_op_status_cb+0x284/0x3ac [ath11k_pci]) + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [E][__mhi_device_get_sync] Did not enter M0 state, cur_state:RESET pm_state:SHUTDOWN Process + [<7f5242b0>] (ath11k_mhi_op_status_cb [ath11k_pci]) from [<7f524878>] (ath11k_mhi_stop+0x10/0x20 [ath11k_pci]) + [<7f524878>] (ath11k_mhi_stop [ath11k_pci]) from [<7f525b94>] (ath11k_pci_power_down+0x54/0x90 [ath11k_pci]) + [<7f525b94>] (ath11k_pci_power_down [ath11k_pci]) from [<8056b2a8>] (pci_device_shutdown+0x30/0x44) + [<8056b2a8>] (pci_device_shutdown) from [<805cfa0c>] (device_shutdown+0x124/0x174) + [<805cfa0c>] (device_shutdown) from [<8033aaa4>] (kernel_restart+0xc/0x50) + [<8033aaa4>] (kernel_restart) from [<8033ada8>] (SyS_reboot+0x178/0x1ec) + [<8033ada8>] (SyS_reboot) from [<80301b80>] (ret_fast_syscall+0x0/0x34) + +Hence, disable wakeup/release mhi using hw_param for other hardwares. + +Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01060-QCAHKSWPL_SILICONZ-1 + +Fixes: a05bd8513335 ("ath11k: read and write registers below unwindowed address") +Signed-off-by: Seevalamuthu Mariappan +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/1636702019-26142-1-git-send-email-quic_seevalam@quicinc.com +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/ath/ath11k/core.c | 5 +++++ + drivers/net/wireless/ath/ath11k/hw.h | 1 + + drivers/net/wireless/ath/ath11k/pci.c | 12 ++++++++---- + 3 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c +index 7dcf6b13f794..48b4151e13a3 100644 +--- a/drivers/net/wireless/ath/ath11k/core.c ++++ b/drivers/net/wireless/ath/ath11k/core.c +@@ -71,6 +71,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .wakeup_mhi = false, + }, + { + .hw_rev = ATH11K_HW_IPQ6018_HW10, +@@ -112,6 +113,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .wakeup_mhi = false, + }, + { + .name = "qca6390 hw2.0", +@@ -152,6 +154,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074), + .fix_l1ss = true, ++ .wakeup_mhi = true, + }, + { + .name = "qcn9074 hw1.0", +@@ -190,6 +193,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { + .supports_suspend = false, + .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), + .fix_l1ss = true, ++ .wakeup_mhi = false, + }, + { + .name = "wcn6855 hw2.0", +@@ -230,6 +234,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { + .supports_suspend = true, + .hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855), + .fix_l1ss = false, ++ .wakeup_mhi = true, + }, + }; + +diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h +index 62f5978b3005..4fe051625edf 100644 +--- a/drivers/net/wireless/ath/ath11k/hw.h ++++ b/drivers/net/wireless/ath/ath11k/hw.h +@@ -163,6 +163,7 @@ struct ath11k_hw_params { + bool supports_suspend; + u32 hal_desc_sz; + bool fix_l1ss; ++ bool wakeup_mhi; + }; + + struct ath11k_hw_ops { +diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c +index 353a2d669fcd..7d0be9388f89 100644 +--- a/drivers/net/wireless/ath/ath11k/pci.c ++++ b/drivers/net/wireless/ath/ath11k/pci.c +@@ -182,7 +182,8 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) + /* for offset beyond BAR + 4K - 32, may + * need to wakeup MHI to access. + */ +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + +@@ -206,7 +207,8 @@ void ath11k_pci_write32(struct ath11k_base *ab, u32 offset, u32 value) + } + } + +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + } +@@ -219,7 +221,8 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) + /* for offset beyond BAR + 4K - 32, may + * need to wakeup MHI to access. + */ +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev); + +@@ -243,7 +246,8 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset) + } + } + +- if (test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && ++ if (ab->hw_params.wakeup_mhi && ++ test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) && + offset >= ACCESS_ALWAYS_OFF) + mhi_device_put(ab_pci->mhi_ctrl->mhi_dev); + +-- +2.35.1 + diff --git a/queue-5.15/batman-adv-use-netif_rx.patch b/queue-5.15/batman-adv-use-netif_rx.patch new file mode 100644 index 00000000000..3ec4fc356e1 --- /dev/null +++ b/queue-5.15/batman-adv-use-netif_rx.patch @@ -0,0 +1,46 @@ +From 97de25fc18f995bfb8d2773b427728faafa26c89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 6 Mar 2022 22:57:48 +0100 +Subject: batman-adv: Use netif_rx(). + +From: Sebastian Andrzej Siewior + +[ Upstream commit 94da81e2fc4285db373fe9a1eb012c2ee205b110 ] + +Since commit + baebdf48c3600 ("net: dev: Makes sure netif_rx() can be invoked in any context.") + +the function netif_rx() can be used in preemptible/thread context as +well as in interrupt context. + +Use netif_rx(). + +Cc: Antonio Quartulli +Cc: Marek Lindner +Cc: Simon Wunderlich +Cc: Sven Eckelmann +Cc: b.a.t.m.a.n@lists.open-mesh.org +Signed-off-by: Sebastian Andrzej Siewior +Acked-by: Sven Eckelmann +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/batman-adv/bridge_loop_avoidance.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c +index 17687848daec..11f6ef657d82 100644 +--- a/net/batman-adv/bridge_loop_avoidance.c ++++ b/net/batman-adv/bridge_loop_avoidance.c +@@ -443,7 +443,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac, + batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES, + skb->len + ETH_HLEN); + +- netif_rx_any_context(skb); ++ netif_rx(skb); + out: + batadv_hardif_put(primary_if); + } +-- +2.35.1 + diff --git a/queue-5.15/block-fix-rq-qos-breakage-from-skipping-rq_qos_done_.patch b/queue-5.15/block-fix-rq-qos-breakage-from-skipping-rq_qos_done_.patch new file mode 100644 index 00000000000..92a1e9c38fe --- /dev/null +++ b/queue-5.15/block-fix-rq-qos-breakage-from-skipping-rq_qos_done_.patch @@ -0,0 +1,181 @@ +From 1bbb367d99228ae0e7f9a6c3dab1a2718d58eab1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 13 Mar 2022 21:15:02 -1000 +Subject: block: fix rq-qos breakage from skipping rq_qos_done_bio() + +From: Tejun Heo + +[ Upstream commit aa1b46dcdc7baaf5fec0be25782ef24b26aa209e ] + +a647a524a467 ("block: don't call rq_qos_ops->done_bio if the bio isn't +tracked") made bio_endio() skip rq_qos_done_bio() if BIO_TRACKED is not set. +While this fixed a potential oops, it also broke blk-iocost by skipping the +done_bio callback for merged bios. + +Before, whether a bio goes through rq_qos_throttle() or rq_qos_merge(), +rq_qos_done_bio() would be called on the bio on completion with BIO_TRACKED +distinguishing the former from the latter. rq_qos_done_bio() is not called +for bios which wenth through rq_qos_merge(). This royally confuses +blk-iocost as the merged bios never finish and are considered perpetually +in-flight. + +One reliably reproducible failure mode is an intermediate cgroup geting +stuck active preventing its children from being activated due to the +leaf-only rule, leading to loss of control. The following is from +resctl-bench protection scenario which emulates isolating a web server like +workload from a memory bomb run on an iocost configuration which should +yield a reasonable level of protection. + + # cat /sys/block/nvme2n1/device/model + Samsung SSD 970 PRO 512GB + # cat /sys/fs/cgroup/io.cost.model + 259:0 ctrl=user model=linear rbps=834913556 rseqiops=93622 rrandiops=102913 wbps=618985353 wseqiops=72325 wrandiops=71025 + # cat /sys/fs/cgroup/io.cost.qos + 259:0 enable=1 ctrl=user rpct=95.00 rlat=18776 wpct=95.00 wlat=8897 min=60.00 max=100.00 + # resctl-bench -m 29.6G -r out.json run protection::scenario=mem-hog,loops=1 + ... + Memory Hog Summary + ================== + + IO Latency: R p50=242u:336u/2.5m p90=794u:1.4m/7.5m p99=2.7m:8.0m/62.5m max=8.0m:36.4m/350m + W p50=221u:323u/1.5m p90=709u:1.2m/5.5m p99=1.5m:2.5m/9.5m max=6.9m:35.9m/350m + + Isolation and Request Latency Impact Distributions: + + min p01 p05 p10 p25 p50 p75 p90 p95 p99 max mean stdev + isol% 15.90 15.90 15.90 40.05 57.24 59.07 60.01 74.63 74.63 90.35 90.35 58.12 15.82 + lat-imp% 0 0 0 0 0 4.55 14.68 15.54 233.5 548.1 548.1 53.88 143.6 + + Result: isol=58.12:15.82% lat_imp=53.88%:143.6 work_csv=100.0% missing=3.96% + +The isolation result of 58.12% is close to what this device would show +without any IO control. + +Fix it by introducing a new flag BIO_QOS_MERGED to mark merged bios and +calling rq_qos_done_bio() on them too. For consistency and clarity, rename +BIO_TRACKED to BIO_QOS_THROTTLED. The flag checks are moved into +rq_qos_done_bio() so that it's next to the code paths that set the flags. + +With the patch applied, the above same benchmark shows: + + # resctl-bench -m 29.6G -r out.json run protection::scenario=mem-hog,loops=1 + ... + Memory Hog Summary + ================== + + IO Latency: R p50=123u:84.4u/985u p90=322u:256u/2.5m p99=1.6m:1.4m/9.5m max=11.1m:36.0m/350m + W p50=429u:274u/995u p90=1.7m:1.3m/4.5m p99=3.4m:2.7m/11.5m max=7.9m:5.9m/26.5m + + Isolation and Request Latency Impact Distributions: + + min p01 p05 p10 p25 p50 p75 p90 p95 p99 max mean stdev + isol% 84.91 84.91 89.51 90.73 92.31 94.49 96.36 98.04 98.71 100.0 100.0 94.42 2.81 + lat-imp% 0 0 0 0 0 2.81 5.73 11.11 13.92 17.53 22.61 4.10 4.68 + + Result: isol=94.42:2.81% lat_imp=4.10%:4.68 work_csv=58.34% missing=0% + +Signed-off-by: Tejun Heo +Fixes: a647a524a467 ("block: don't call rq_qos_ops->done_bio if the bio isn't tracked") +Cc: stable@vger.kernel.org # v5.15+ +Cc: Ming Lei +Cc: Yu Kuai +Reviewed-by: Ming Lei +Link: https://lore.kernel.org/r/Yi7rdrzQEHjJLGKB@slm.duckdns.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio.c | 3 +-- + block/blk-iolatency.c | 2 +- + block/blk-rq-qos.h | 20 +++++++++++--------- + include/linux/blk_types.h | 3 ++- + 4 files changed, 15 insertions(+), 13 deletions(-) + +diff --git a/block/bio.c b/block/bio.c +index 365bb6362669..b8a8bfba714f 100644 +--- a/block/bio.c ++++ b/block/bio.c +@@ -1470,8 +1470,7 @@ void bio_endio(struct bio *bio) + if (!bio_integrity_endio(bio)) + return; + +- if (bio->bi_bdev && bio_flagged(bio, BIO_TRACKED)) +- rq_qos_done_bio(bdev_get_queue(bio->bi_bdev), bio); ++ rq_qos_done_bio(bio); + + if (bio->bi_bdev && bio_flagged(bio, BIO_TRACE_COMPLETION)) { + trace_block_bio_complete(bdev_get_queue(bio->bi_bdev), bio); +diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c +index ce3847499d85..d85f30a85ee7 100644 +--- a/block/blk-iolatency.c ++++ b/block/blk-iolatency.c +@@ -601,7 +601,7 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio) + int inflight = 0; + + blkg = bio->bi_blkg; +- if (!blkg || !bio_flagged(bio, BIO_TRACKED)) ++ if (!blkg || !bio_flagged(bio, BIO_QOS_THROTTLED)) + return; + + iolat = blkg_to_lat(bio->bi_blkg); +diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h +index 3cfbc8668cba..68267007da1c 100644 +--- a/block/blk-rq-qos.h ++++ b/block/blk-rq-qos.h +@@ -177,20 +177,20 @@ static inline void rq_qos_requeue(struct request_queue *q, struct request *rq) + __rq_qos_requeue(q->rq_qos, rq); + } + +-static inline void rq_qos_done_bio(struct request_queue *q, struct bio *bio) ++static inline void rq_qos_done_bio(struct bio *bio) + { +- if (q->rq_qos) +- __rq_qos_done_bio(q->rq_qos, bio); ++ if (bio->bi_bdev && (bio_flagged(bio, BIO_QOS_THROTTLED) || ++ bio_flagged(bio, BIO_QOS_MERGED))) { ++ struct request_queue *q = bdev_get_queue(bio->bi_bdev); ++ if (q->rq_qos) ++ __rq_qos_done_bio(q->rq_qos, bio); ++ } + } + + static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio) + { +- /* +- * BIO_TRACKED lets controllers know that a bio went through the +- * normal rq_qos path. +- */ + if (q->rq_qos) { +- bio_set_flag(bio, BIO_TRACKED); ++ bio_set_flag(bio, BIO_QOS_THROTTLED); + __rq_qos_throttle(q->rq_qos, bio); + } + } +@@ -205,8 +205,10 @@ static inline void rq_qos_track(struct request_queue *q, struct request *rq, + static inline void rq_qos_merge(struct request_queue *q, struct request *rq, + struct bio *bio) + { +- if (q->rq_qos) ++ if (q->rq_qos) { ++ bio_set_flag(bio, BIO_QOS_MERGED); + __rq_qos_merge(q->rq_qos, rq, bio); ++ } + } + + static inline void rq_qos_queue_depth_changed(struct request_queue *q) +diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h +index 17c92c0f15b2..36ce3d0fb9f3 100644 +--- a/include/linux/blk_types.h ++++ b/include/linux/blk_types.h +@@ -294,7 +294,8 @@ enum { + BIO_TRACE_COMPLETION, /* bio_endio() should trace the final completion + * of this bio. */ + BIO_CGROUP_ACCT, /* has been accounted to a cgroup */ +- BIO_TRACKED, /* set if bio goes through the rq_qos path */ ++ BIO_QOS_THROTTLED, /* bio went through rq_qos throttle path */ ++ BIO_QOS_MERGED, /* but went through rq_qos merge path */ + BIO_REMAPPED, + BIO_ZONE_WRITE_LOCKED, /* Owns a zoned device zone write lock */ + BIO_PERCPU_CACHE, /* can participate in per-cpu alloc cache */ +-- +2.35.1 + diff --git a/queue-5.15/block-only-mark-bio-as-tracked-if-it-really-is-track.patch b/queue-5.15/block-only-mark-bio-as-tracked-if-it-really-is-track.patch new file mode 100644 index 00000000000..a83a4d5f1ac --- /dev/null +++ b/queue-5.15/block-only-mark-bio-as-tracked-if-it-really-is-track.patch @@ -0,0 +1,44 @@ +From 6a52efe5286829a926e77cfcfa00024fadfe5d1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Oct 2021 20:06:18 -0600 +Subject: block: only mark bio as tracked if it really is tracked + +From: Jens Axboe + +[ Upstream commit 90b8faa0e8de1b02b619fb33f6c6e1e13e7d1d70 ] + +We set BIO_TRACKED unconditionally when rq_qos_throttle() is called, even +though we may not even have an rq_qos handler. Only mark it as TRACKED if +it really is potentially tracked. + +This saves considerable time for the case where the bio isn't tracked: + + 2.64% -1.65% [kernel.vmlinux] [k] bio_endio + +Reviewed-by: Christoph Hellwig +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/blk-rq-qos.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h +index f000f83e0621..3cfbc8668cba 100644 +--- a/block/blk-rq-qos.h ++++ b/block/blk-rq-qos.h +@@ -189,9 +189,10 @@ static inline void rq_qos_throttle(struct request_queue *q, struct bio *bio) + * BIO_TRACKED lets controllers know that a bio went through the + * normal rq_qos path. + */ +- bio_set_flag(bio, BIO_TRACKED); +- if (q->rq_qos) ++ if (q->rq_qos) { ++ bio_set_flag(bio, BIO_TRACKED); + __rq_qos_throttle(q->rq_qos, bio); ++ } + } + + static inline void rq_qos_track(struct request_queue *q, struct request *rq, +-- +2.35.1 + diff --git a/queue-5.15/block-use-bdev_get_queue-in-bio.c.patch b/queue-5.15/block-use-bdev_get_queue-in-bio.c.patch new file mode 100644 index 00000000000..8d4811cbd45 --- /dev/null +++ b/queue-5.15/block-use-bdev_get_queue-in-bio.c.patch @@ -0,0 +1,67 @@ +From 05769e3e67cc0426abc8f239b413a0bec3778364 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Oct 2021 15:03:28 +0100 +Subject: block: use bdev_get_queue() in bio.c + +From: Pavel Begunkov + +[ Upstream commit 3caee4634be68e755d2fb130962f1623661dbd5b ] + +Convert bdev->bd_disk->queue to bdev_get_queue(), it's uses a cached +queue pointer and so is faster. + +Signed-off-by: Pavel Begunkov +Link: https://lore.kernel.org/r/85c36ea784d285a5075baa10049e6b59e15fb484.1634219547.git.asml.silence@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + block/bio.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/block/bio.c b/block/bio.c +index 8381c6690dd6..365bb6362669 100644 +--- a/block/bio.c ++++ b/block/bio.c +@@ -910,7 +910,7 @@ EXPORT_SYMBOL(bio_add_pc_page); + int bio_add_zone_append_page(struct bio *bio, struct page *page, + unsigned int len, unsigned int offset) + { +- struct request_queue *q = bio->bi_bdev->bd_disk->queue; ++ struct request_queue *q = bdev_get_queue(bio->bi_bdev); + bool same_page = false; + + if (WARN_ON_ONCE(bio_op(bio) != REQ_OP_ZONE_APPEND)) +@@ -1054,7 +1054,7 @@ static int bio_iov_bvec_set(struct bio *bio, struct iov_iter *iter) + + static int bio_iov_bvec_set_append(struct bio *bio, struct iov_iter *iter) + { +- struct request_queue *q = bio->bi_bdev->bd_disk->queue; ++ struct request_queue *q = bdev_get_queue(bio->bi_bdev); + struct iov_iter i = *iter; + + iov_iter_truncate(&i, queue_max_zone_append_sectors(q) << 9); +@@ -1132,7 +1132,7 @@ static int __bio_iov_append_get_pages(struct bio *bio, struct iov_iter *iter) + { + unsigned short nr_pages = bio->bi_max_vecs - bio->bi_vcnt; + unsigned short entries_left = bio->bi_max_vecs - bio->bi_vcnt; +- struct request_queue *q = bio->bi_bdev->bd_disk->queue; ++ struct request_queue *q = bdev_get_queue(bio->bi_bdev); + unsigned int max_append_sectors = queue_max_zone_append_sectors(q); + struct bio_vec *bv = bio->bi_io_vec + bio->bi_vcnt; + struct page **pages = (struct page **)bv; +@@ -1471,10 +1471,10 @@ void bio_endio(struct bio *bio) + return; + + if (bio->bi_bdev && bio_flagged(bio, BIO_TRACKED)) +- rq_qos_done_bio(bio->bi_bdev->bd_disk->queue, bio); ++ rq_qos_done_bio(bdev_get_queue(bio->bi_bdev), bio); + + if (bio->bi_bdev && bio_flagged(bio, BIO_TRACE_COMPLETION)) { +- trace_block_bio_complete(bio->bi_bdev->bd_disk->queue, bio); ++ trace_block_bio_complete(bdev_get_queue(bio->bi_bdev), bio); + bio_clear_flag(bio, BIO_TRACE_COMPLETION); + } + +-- +2.35.1 + diff --git a/queue-5.15/bluetooth-btmtksdio-fix-use-after-free-at-btmtksdio_.patch b/queue-5.15/bluetooth-btmtksdio-fix-use-after-free-at-btmtksdio_.patch new file mode 100644 index 00000000000..f5504cd112b --- /dev/null +++ b/queue-5.15/bluetooth-btmtksdio-fix-use-after-free-at-btmtksdio_.patch @@ -0,0 +1,86 @@ +From de517be1dd5d98cecb549658b856c0d4c1f5e35b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 May 2022 06:22:15 +0800 +Subject: Bluetooth: btmtksdio: fix use-after-free at btmtksdio_recv_event + +From: Sean Wang + +[ Upstream commit 0fab6361c4ba17d1b43a991bef4238a3c1754d35 ] + +We should not access skb buffer data anymore after hci_recv_frame was +called. + +[ 39.634809] BUG: KASAN: use-after-free in btmtksdio_recv_event+0x1b0 +[ 39.634855] Read of size 1 at addr ffffff80cf28a60d by task kworker +[ 39.634962] Call trace: +[ 39.634974] dump_backtrace+0x0/0x3b8 +[ 39.634999] show_stack+0x20/0x2c +[ 39.635016] dump_stack_lvl+0x60/0x78 +[ 39.635040] print_address_description+0x70/0x2f0 +[ 39.635062] kasan_report+0x154/0x194 +[ 39.635079] __asan_report_load1_noabort+0x44/0x50 +[ 39.635099] btmtksdio_recv_event+0x1b0/0x1c4 +[ 39.635129] btmtksdio_txrx_work+0x6cc/0xac4 +[ 39.635157] process_one_work+0x560/0xc5c +[ 39.635177] worker_thread+0x7ec/0xcc0 +[ 39.635195] kthread+0x2d0/0x3d0 +[ 39.635215] ret_from_fork+0x10/0x20 +[ 39.635247] Allocated by task 0: +[ 39.635260] (stack is not available) +[ 39.635281] Freed by task 2392: +[ 39.635295] kasan_save_stack+0x38/0x68 +[ 39.635319] kasan_set_track+0x28/0x3c +[ 39.635338] kasan_set_free_info+0x28/0x4c +[ 39.635357] ____kasan_slab_free+0x104/0x150 +[ 39.635374] __kasan_slab_free+0x18/0x28 +[ 39.635391] slab_free_freelist_hook+0x114/0x248 +[ 39.635410] kfree+0xf8/0x2b4 +[ 39.635427] skb_free_head+0x58/0x98 +[ 39.635447] skb_release_data+0x2f4/0x410 +[ 39.635464] skb_release_all+0x50/0x60 +[ 39.635481] kfree_skb+0xc8/0x25c +[ 39.635498] hci_event_packet+0x894/0xca4 [bluetooth] +[ 39.635721] hci_rx_work+0x1c8/0x68c [bluetooth] +[ 39.635925] process_one_work+0x560/0xc5c +[ 39.635951] worker_thread+0x7ec/0xcc0 +[ 39.635970] kthread+0x2d0/0x3d0 +[ 39.635990] ret_from_fork+0x10/0x20 +[ 39.636021] The buggy address belongs to the object at ffffff80cf28a600 + which belongs to the cache kmalloc-512 of size 512 +[ 39.636039] The buggy address is located 13 bytes inside of + 512-byte region [ffffff80cf28a600, ffffff80cf28a800) + +Fixes: 9aebfd4a2200 ("Bluetooth: mediatek: add support for MediaTek MT7663S and MT7668S SDIO devices") +Co-developed-by: Yake Yang +Signed-off-by: Yake Yang +Signed-off-by: Sean Wang +Signed-off-by: Marcel Holtmann +Signed-off-by: Sasha Levin +--- + drivers/bluetooth/btmtksdio.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c +index ff1f5dfbb6db..d66e4df171d2 100644 +--- a/drivers/bluetooth/btmtksdio.c ++++ b/drivers/bluetooth/btmtksdio.c +@@ -331,6 +331,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb) + { + struct btmtksdio_dev *bdev = hci_get_drvdata(hdev); + struct hci_event_hdr *hdr = (void *)skb->data; ++ u8 evt = hdr->evt; + int err; + + /* Fix up the vendor event id with 0xff for vendor specific instead +@@ -355,7 +356,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb) + if (err < 0) + goto err_free_skb; + +- if (hdr->evt == HCI_EV_VENDOR) { ++ if (evt == HCI_EV_VENDOR) { + if (test_and_clear_bit(BTMTKSDIO_TX_WAIT_VND_EVT, + &bdev->tx_state)) { + /* Barrier to sync with other CPUs */ +-- +2.35.1 + diff --git a/queue-5.15/bluetooth-protect-le-accept-and-resolv-lists-with-hd.patch b/queue-5.15/bluetooth-protect-le-accept-and-resolv-lists-with-hd.patch new file mode 100644 index 00000000000..c35ba572557 --- /dev/null +++ b/queue-5.15/bluetooth-protect-le-accept-and-resolv-lists-with-hd.patch @@ -0,0 +1,96 @@ +From de9ef8d7910fd92362858caeb10aab16c2b8426a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 Apr 2022 00:31:17 +0200 +Subject: Bluetooth: protect le accept and resolv lists with hdev->lock + +From: Niels Dossche + +[ Upstream commit 5e2b6064cbc5fd582396768c5f9583f65085e368 ] + +Concurrent operations from events on le_{accept,resolv}_list are +currently unprotected by hdev->lock. +Most existing code do already protect the lists with that lock. +This can be observed in hci_debugfs and hci_sync. +Add the protection for these events too. + +Fixes: b950aa88638c ("Bluetooth: Add definitions and track LE resolve list modification") +Fixes: 0f36b589e4ee ("Bluetooth: Track LE white list modification via HCI commands") +Signed-off-by: Niels Dossche +Signed-off-by: Marcel Holtmann +Signed-off-by: Sasha Levin +--- + net/bluetooth/hci_event.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 5ac3aca6deeb..2337e9275863 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -1559,7 +1559,9 @@ static void hci_cc_le_clear_accept_list(struct hci_dev *hdev, + if (status) + return; + ++ hci_dev_lock(hdev); + hci_bdaddr_list_clear(&hdev->le_accept_list); ++ hci_dev_unlock(hdev); + } + + static void hci_cc_le_add_to_accept_list(struct hci_dev *hdev, +@@ -1577,8 +1579,10 @@ static void hci_cc_le_add_to_accept_list(struct hci_dev *hdev, + if (!sent) + return; + ++ hci_dev_lock(hdev); + hci_bdaddr_list_add(&hdev->le_accept_list, &sent->bdaddr, + sent->bdaddr_type); ++ hci_dev_unlock(hdev); + } + + static void hci_cc_le_del_from_accept_list(struct hci_dev *hdev, +@@ -1596,8 +1600,10 @@ static void hci_cc_le_del_from_accept_list(struct hci_dev *hdev, + if (!sent) + return; + ++ hci_dev_lock(hdev); + hci_bdaddr_list_del(&hdev->le_accept_list, &sent->bdaddr, + sent->bdaddr_type); ++ hci_dev_unlock(hdev); + } + + static void hci_cc_le_read_supported_states(struct hci_dev *hdev, +@@ -1661,9 +1667,11 @@ static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev, + if (!sent) + return; + ++ hci_dev_lock(hdev); + hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr, + sent->bdaddr_type, sent->peer_irk, + sent->local_irk); ++ hci_dev_unlock(hdev); + } + + static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev, +@@ -1681,8 +1689,10 @@ static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev, + if (!sent) + return; + ++ hci_dev_lock(hdev); + hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr, + sent->bdaddr_type); ++ hci_dev_unlock(hdev); + } + + static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev, +@@ -1695,7 +1705,9 @@ static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev, + if (status) + return; + ++ hci_dev_lock(hdev); + hci_bdaddr_list_clear(&hdev->le_resolv_list); ++ hci_dev_unlock(hdev); + } + + static void hci_cc_le_read_resolv_list_size(struct hci_dev *hdev, +-- +2.35.1 + diff --git a/queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch b/queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch new file mode 100644 index 00000000000..2a4899b367a --- /dev/null +++ b/queue-5.15/bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch @@ -0,0 +1,59 @@ +From 4f904a19f459c59d7ad52227a79580cd18b5552d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Dec 2021 23:10:18 +0800 +Subject: bpf, arm64: Use emit_addr_mov_i64() for BPF_PSEUDO_FUNC + +From: Hou Tao + +[ Upstream commit e4a41c2c1fa916547e63440c73a51a5eb06247af ] + +The following error is reported when running "./test_progs -t for_each" +under arm64: + + bpf_jit: multi-func JIT bug 58 != 56 + [...] + JIT doesn't support bpf-to-bpf calls + +The root cause is the size of BPF_PSEUDO_FUNC instruction increases +from 2 to 3 after the address of called bpf-function is settled and +there are two bpf-to-bpf calls in test_pkt_access. The generated +instructions are shown below: + + 0x48: 21 00 C0 D2 movz x1, #0x1, lsl #32 + 0x4c: 21 00 80 F2 movk x1, #0x1 + + 0x48: E1 3F C0 92 movn x1, #0x1ff, lsl #32 + 0x4c: 41 FE A2 F2 movk x1, #0x17f2, lsl #16 + 0x50: 81 70 9F F2 movk x1, #0xfb84 + +Fixing it by using emit_addr_mov_i64() for BPF_PSEUDO_FUNC, so +the size of jited image will not change. + +Fixes: 69c087ba6225 ("bpf: Add bpf_for_each_map_elem() helper") +Signed-off-by: Hou Tao +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/bpf/20211231151018.3781550-1-houtao1@huawei.com +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index 95439bbe5df8..4895b4d7e150 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -788,7 +788,10 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, + u64 imm64; + + imm64 = (u64)insn1.imm << 32 | (u32)imm; +- emit_a64_mov_i64(dst, imm64, ctx); ++ if (bpf_pseudo_func(insn)) ++ emit_addr_mov_i64(dst, imm64, ctx); ++ else ++ emit_a64_mov_i64(dst, imm64, ctx); + + return 1; + } +-- +2.35.1 + diff --git a/queue-5.15/btrfs-add-a-btrfs_get_dev_args_from_path-helper.patch b/queue-5.15/btrfs-add-a-btrfs_get_dev_args_from_path-helper.patch new file mode 100644 index 00000000000..70b5e29c9d0 --- /dev/null +++ b/queue-5.15/btrfs-add-a-btrfs_get_dev_args_from_path-helper.patch @@ -0,0 +1,178 @@ +From d8d0e5d7162bc4215084e81b959efdd23219396f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 Oct 2021 16:12:43 -0400 +Subject: btrfs: add a btrfs_get_dev_args_from_path helper + +From: Josef Bacik + +[ Upstream commit faa775c41d655a4786e9d53cb075a77bb5a75f66 ] + +We are going to want to populate our device lookup args outside of any +locks and then do the actual device lookup later, so add a helper to do +this work and make btrfs_find_device_by_devspec() use this helper for +now. + +Reviewed-by: Nikolay Borisov +Reviewed-by: Anand Jain +Signed-off-by: Josef Bacik +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/volumes.c | 96 ++++++++++++++++++++++++++++++---------------- + fs/btrfs/volumes.h | 4 ++ + 2 files changed, 68 insertions(+), 32 deletions(-) + +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 53417a1c5402..8d09e6d442b2 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -2361,45 +2361,81 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev) + btrfs_free_device(tgtdev); + } + +-static struct btrfs_device *btrfs_find_device_by_path( +- struct btrfs_fs_info *fs_info, const char *device_path) ++/** ++ * Populate args from device at path ++ * ++ * @fs_info: the filesystem ++ * @args: the args to populate ++ * @path: the path to the device ++ * ++ * This will read the super block of the device at @path and populate @args with ++ * the devid, fsid, and uuid. This is meant to be used for ioctls that need to ++ * lookup a device to operate on, but need to do it before we take any locks. ++ * This properly handles the special case of "missing" that a user may pass in, ++ * and does some basic sanity checks. The caller must make sure that @path is ++ * properly NUL terminated before calling in, and must call ++ * btrfs_put_dev_args_from_path() in order to free up the temporary fsid and ++ * uuid buffers. ++ * ++ * Return: 0 for success, -errno for failure ++ */ ++int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info, ++ struct btrfs_dev_lookup_args *args, ++ const char *path) + { +- BTRFS_DEV_LOOKUP_ARGS(args); +- int ret = 0; + struct btrfs_super_block *disk_super; + struct block_device *bdev; +- struct btrfs_device *device; ++ int ret; + +- ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ, +- fs_info->bdev_holder, 0, &bdev, &disk_super); +- if (ret) +- return ERR_PTR(ret); ++ if (!path || !path[0]) ++ return -EINVAL; ++ if (!strcmp(path, "missing")) { ++ args->missing = true; ++ return 0; ++ } ++ ++ args->uuid = kzalloc(BTRFS_UUID_SIZE, GFP_KERNEL); ++ args->fsid = kzalloc(BTRFS_FSID_SIZE, GFP_KERNEL); ++ if (!args->uuid || !args->fsid) { ++ btrfs_put_dev_args_from_path(args); ++ return -ENOMEM; ++ } + +- args.devid = btrfs_stack_device_id(&disk_super->dev_item); +- args.uuid = disk_super->dev_item.uuid; ++ ret = btrfs_get_bdev_and_sb(path, FMODE_READ, fs_info->bdev_holder, 0, ++ &bdev, &disk_super); ++ if (ret) ++ return ret; ++ args->devid = btrfs_stack_device_id(&disk_super->dev_item); ++ memcpy(args->uuid, disk_super->dev_item.uuid, BTRFS_UUID_SIZE); + if (btrfs_fs_incompat(fs_info, METADATA_UUID)) +- args.fsid = disk_super->metadata_uuid; ++ memcpy(args->fsid, disk_super->metadata_uuid, BTRFS_FSID_SIZE); + else +- args.fsid = disk_super->fsid; +- +- device = btrfs_find_device(fs_info->fs_devices, &args); +- ++ memcpy(args->fsid, disk_super->fsid, BTRFS_FSID_SIZE); + btrfs_release_disk_super(disk_super); +- if (!device) +- device = ERR_PTR(-ENOENT); + blkdev_put(bdev, FMODE_READ); +- return device; ++ return 0; + } + + /* +- * Lookup a device given by device id, or the path if the id is 0. ++ * Only use this jointly with btrfs_get_dev_args_from_path() because we will ++ * allocate our ->uuid and ->fsid pointers, everybody else uses local variables ++ * that don't need to be freed. + */ ++void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args) ++{ ++ kfree(args->uuid); ++ kfree(args->fsid); ++ args->uuid = NULL; ++ args->fsid = NULL; ++} ++ + struct btrfs_device *btrfs_find_device_by_devspec( + struct btrfs_fs_info *fs_info, u64 devid, + const char *device_path) + { + BTRFS_DEV_LOOKUP_ARGS(args); + struct btrfs_device *device; ++ int ret; + + if (devid) { + args.devid = devid; +@@ -2409,18 +2445,14 @@ struct btrfs_device *btrfs_find_device_by_devspec( + return device; + } + +- if (!device_path || !device_path[0]) +- return ERR_PTR(-EINVAL); +- +- if (strcmp(device_path, "missing") == 0) { +- args.missing = true; +- device = btrfs_find_device(fs_info->fs_devices, &args); +- if (!device) +- return ERR_PTR(-ENOENT); +- return device; +- } +- +- return btrfs_find_device_by_path(fs_info, device_path); ++ ret = btrfs_get_dev_args_from_path(fs_info, &args, device_path); ++ if (ret) ++ return ERR_PTR(ret); ++ device = btrfs_find_device(fs_info->fs_devices, &args); ++ btrfs_put_dev_args_from_path(&args); ++ if (!device) ++ return ERR_PTR(-ENOENT); ++ return device; + } + + /* +diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h +index f3b1380f45ad..d1df03f77e29 100644 +--- a/fs/btrfs/volumes.h ++++ b/fs/btrfs/volumes.h +@@ -487,9 +487,13 @@ void btrfs_assign_next_active_device(struct btrfs_device *device, + struct btrfs_device *btrfs_find_device_by_devspec(struct btrfs_fs_info *fs_info, + u64 devid, + const char *devpath); ++int btrfs_get_dev_args_from_path(struct btrfs_fs_info *fs_info, ++ struct btrfs_dev_lookup_args *args, ++ const char *path); + struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, + const u64 *devid, + const u8 *uuid); ++void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args); + void btrfs_free_device(struct btrfs_device *device); + int btrfs_rm_device(struct btrfs_fs_info *fs_info, + const char *device_path, u64 devid, +-- +2.35.1 + diff --git a/queue-5.15/btrfs-add-additional-parameters-to-btrfs_init_tree_r.patch b/queue-5.15/btrfs-add-additional-parameters-to-btrfs_init_tree_r.patch new file mode 100644 index 00000000000..2897a12e0fa --- /dev/null +++ b/queue-5.15/btrfs-add-additional-parameters-to-btrfs_init_tree_r.patch @@ -0,0 +1,271 @@ +From 6fc3ca40a97dc1507a2bc03abb0c8c84986793e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Oct 2021 11:21:35 +0300 +Subject: btrfs: add additional parameters to + btrfs_init_tree_ref/btrfs_init_data_ref + +From: Nikolay Borisov + +[ Upstream commit f42c5da6c12e990d8ec415199600b4d593c63bf5 ] + +In order to make 'real_root' used only in ref-verify it's required to +have the necessary context to perform the same checks that this member +is used for. So add 'mod_root' which will contain the root on behalf of +which a delayed ref was created and a 'skip_group' parameter which +will contain callsite-specific override of skip_qgroup. + +Signed-off-by: Nikolay Borisov +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/delayed-ref.h | 5 +++-- + fs/btrfs/extent-tree.c | 17 +++++++++++------ + fs/btrfs/file.c | 13 ++++++++----- + fs/btrfs/inode.c | 3 ++- + fs/btrfs/relocation.c | 21 ++++++++++++++------- + fs/btrfs/tree-log.c | 2 +- + 6 files changed, 39 insertions(+), 22 deletions(-) + +diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h +index e22fba272e4f..31266ba1d430 100644 +--- a/fs/btrfs/delayed-ref.h ++++ b/fs/btrfs/delayed-ref.h +@@ -271,7 +271,7 @@ static inline void btrfs_init_generic_ref(struct btrfs_ref *generic_ref, + } + + static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref, +- int level, u64 root) ++ int level, u64 root, u64 mod_root, bool skip_qgroup) + { + /* If @real_root not set, use @root as fallback */ + if (!generic_ref->real_root) +@@ -282,7 +282,8 @@ static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref, + } + + static inline void btrfs_init_data_ref(struct btrfs_ref *generic_ref, +- u64 ref_root, u64 ino, u64 offset) ++ u64 ref_root, u64 ino, u64 offset, u64 mod_root, ++ bool skip_qgroup) + { + /* If @real_root not set, use @root as fallback */ + if (!generic_ref->real_root) +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index 514adc83577f..e01b9344fb9c 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -2440,7 +2440,8 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans, + num_bytes, parent); + generic_ref.real_root = root->root_key.objectid; + btrfs_init_data_ref(&generic_ref, ref_root, key.objectid, +- key.offset); ++ key.offset, root->root_key.objectid, ++ for_reloc); + generic_ref.skip_qgroup = for_reloc; + if (inc) + ret = btrfs_inc_extent_ref(trans, &generic_ref); +@@ -2454,7 +2455,8 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans, + btrfs_init_generic_ref(&generic_ref, action, bytenr, + num_bytes, parent); + generic_ref.real_root = root->root_key.objectid; +- btrfs_init_tree_ref(&generic_ref, level - 1, ref_root); ++ btrfs_init_tree_ref(&generic_ref, level - 1, ref_root, ++ root->root_key.objectid, for_reloc); + generic_ref.skip_qgroup = for_reloc; + if (inc) + ret = btrfs_inc_extent_ref(trans, &generic_ref); +@@ -3289,7 +3291,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, + btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF, + buf->start, buf->len, parent); + btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf), +- root->root_key.objectid); ++ root->root_key.objectid, 0, false); + + if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { + btrfs_ref_tree_mod(fs_info, &generic_ref); +@@ -4705,7 +4707,8 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, + + btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT, + ins->objectid, ins->offset, 0); +- btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner, offset); ++ btrfs_init_data_ref(&generic_ref, root->root_key.objectid, owner, ++ offset, 0, false); + btrfs_ref_tree_mod(root->fs_info, &generic_ref); + + return btrfs_add_delayed_data_ref(trans, &generic_ref, ram_bytes); +@@ -4898,7 +4901,8 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, + btrfs_init_generic_ref(&generic_ref, BTRFS_ADD_DELAYED_EXTENT, + ins.objectid, ins.offset, parent); + generic_ref.real_root = root->root_key.objectid; +- btrfs_init_tree_ref(&generic_ref, level, root_objectid); ++ btrfs_init_tree_ref(&generic_ref, level, root_objectid, ++ root->root_key.objectid, false); + btrfs_ref_tree_mod(fs_info, &generic_ref); + ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, extent_op); + if (ret) +@@ -5315,7 +5319,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans, + + btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr, + fs_info->nodesize, parent); +- btrfs_init_tree_ref(&ref, level - 1, root->root_key.objectid); ++ btrfs_init_tree_ref(&ref, level - 1, root->root_key.objectid, ++ 0, false); + ret = btrfs_free_extent(trans, &ref); + if (ret) + goto out_unlock; +diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c +index a06c8366a8f4..1c597cd6c024 100644 +--- a/fs/btrfs/file.c ++++ b/fs/btrfs/file.c +@@ -869,7 +869,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, + btrfs_init_data_ref(&ref, + root->root_key.objectid, + new_key.objectid, +- args->start - extent_offset); ++ args->start - extent_offset, ++ 0, false); + ret = btrfs_inc_extent_ref(trans, &ref); + BUG_ON(ret); /* -ENOMEM */ + } +@@ -955,7 +956,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, + btrfs_init_data_ref(&ref, + root->root_key.objectid, + key.objectid, +- key.offset - extent_offset); ++ key.offset - extent_offset, 0, ++ false); + ret = btrfs_free_extent(trans, &ref); + BUG_ON(ret); /* -ENOMEM */ + args->bytes_found += extent_end - key.offset; +@@ -1232,7 +1234,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, + btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, bytenr, + num_bytes, 0); + btrfs_init_data_ref(&ref, root->root_key.objectid, ino, +- orig_offset); ++ orig_offset, 0, false); + ret = btrfs_inc_extent_ref(trans, &ref); + if (ret) { + btrfs_abort_transaction(trans, ret); +@@ -1257,7 +1259,8 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, + other_end = 0; + btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, bytenr, + num_bytes, 0); +- btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset); ++ btrfs_init_data_ref(&ref, root->root_key.objectid, ino, orig_offset, ++ 0, false); + if (extent_mergeable(leaf, path->slots[0] + 1, + ino, bytenr, orig_offset, + &other_start, &other_end)) { +@@ -2715,7 +2718,7 @@ static int btrfs_insert_replace_extent(struct btrfs_trans_handle *trans, + extent_info->disk_len, 0); + ref_offset = extent_info->file_offset - extent_info->data_offset; + btrfs_init_data_ref(&ref, root->root_key.objectid, +- btrfs_ino(inode), ref_offset); ++ btrfs_ino(inode), ref_offset, 0, false); + ret = btrfs_inc_extent_ref(trans, &ref); + } + +diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c +index 044d584c3467..d644dcaf3004 100644 +--- a/fs/btrfs/inode.c ++++ b/fs/btrfs/inode.c +@@ -4919,7 +4919,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, + extent_start, extent_num_bytes, 0); + ref.real_root = root->root_key.objectid; + btrfs_init_data_ref(&ref, btrfs_header_owner(leaf), +- ino, extent_offset); ++ ino, extent_offset, ++ root->root_key.objectid, false); + ret = btrfs_free_extent(trans, &ref); + if (ret) { + btrfs_abort_transaction(trans, ret); +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index a6661f2ad2c0..0300770c0a89 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -1147,7 +1147,8 @@ int replace_file_extents(struct btrfs_trans_handle *trans, + num_bytes, parent); + ref.real_root = root->root_key.objectid; + btrfs_init_data_ref(&ref, btrfs_header_owner(leaf), +- key.objectid, key.offset); ++ key.objectid, key.offset, ++ root->root_key.objectid, false); + ret = btrfs_inc_extent_ref(trans, &ref); + if (ret) { + btrfs_abort_transaction(trans, ret); +@@ -1158,7 +1159,8 @@ int replace_file_extents(struct btrfs_trans_handle *trans, + num_bytes, parent); + ref.real_root = root->root_key.objectid; + btrfs_init_data_ref(&ref, btrfs_header_owner(leaf), +- key.objectid, key.offset); ++ key.objectid, key.offset, ++ root->root_key.objectid, false); + ret = btrfs_free_extent(trans, &ref); + if (ret) { + btrfs_abort_transaction(trans, ret); +@@ -1368,7 +1370,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc, + btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, old_bytenr, + blocksize, path->nodes[level]->start); + ref.skip_qgroup = true; +- btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid); ++ btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid, ++ 0, true); + ret = btrfs_inc_extent_ref(trans, &ref); + if (ret) { + btrfs_abort_transaction(trans, ret); +@@ -1377,7 +1380,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc, + btrfs_init_generic_ref(&ref, BTRFS_ADD_DELAYED_REF, new_bytenr, + blocksize, 0); + ref.skip_qgroup = true; +- btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid); ++ btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid, 0, ++ true); + ret = btrfs_inc_extent_ref(trans, &ref); + if (ret) { + btrfs_abort_transaction(trans, ret); +@@ -1386,7 +1390,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc, + + btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, new_bytenr, + blocksize, path->nodes[level]->start); +- btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid); ++ btrfs_init_tree_ref(&ref, level - 1, src->root_key.objectid, ++ 0, true); + ref.skip_qgroup = true; + ret = btrfs_free_extent(trans, &ref); + if (ret) { +@@ -1396,7 +1401,8 @@ int replace_path(struct btrfs_trans_handle *trans, struct reloc_control *rc, + + btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, old_bytenr, + blocksize, 0); +- btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid); ++ btrfs_init_tree_ref(&ref, level - 1, dest->root_key.objectid, ++ 0, true); + ref.skip_qgroup = true; + ret = btrfs_free_extent(trans, &ref); + if (ret) { +@@ -2475,7 +2481,8 @@ static int do_relocation(struct btrfs_trans_handle *trans, + upper->eb->start); + ref.real_root = root->root_key.objectid; + btrfs_init_tree_ref(&ref, node->level, +- btrfs_header_owner(upper->eb)); ++ btrfs_header_owner(upper->eb), ++ root->root_key.objectid, false); + ret = btrfs_inc_extent_ref(trans, &ref); + if (!ret) + ret = btrfs_drop_subtree(trans, root, eb, +diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c +index 1221d8483d63..bed6811476b0 100644 +--- a/fs/btrfs/tree-log.c ++++ b/fs/btrfs/tree-log.c +@@ -761,7 +761,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans, + ins.objectid, ins.offset, 0); + btrfs_init_data_ref(&ref, + root->root_key.objectid, +- key->objectid, offset); ++ key->objectid, offset, 0, false); + ret = btrfs_inc_extent_ref(trans, &ref); + if (ret) + goto out; +-- +2.35.1 + diff --git a/queue-5.15/btrfs-don-t-access-possibly-stale-fs_info-data-in-de.patch b/queue-5.15/btrfs-don-t-access-possibly-stale-fs_info-data-in-de.patch new file mode 100644 index 00000000000..f1d87c22dd1 --- /dev/null +++ b/queue-5.15/btrfs-don-t-access-possibly-stale-fs_info-data-in-de.patch @@ -0,0 +1,83 @@ +From a6683351a79b2437780e7b15aa466a8fb7722c55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Mar 2022 22:40:27 +0800 +Subject: btrfs: don't access possibly stale fs_info data in device_list_add + +From: Dongliang Mu + +[ Upstream commit 79c9234ba596e903907de20573fd4bcc85315b06 ] + +Syzbot reported a possible use-after-free in printing information +in device_list_add. + +Very similar with the bug fixed by commit 0697d9a61099 ("btrfs: don't +access possibly stale fs_info data for printing duplicate device"), +but this time the use occurs in btrfs_info_in_rcu. + + Call Trace: + kasan_report.cold+0x83/0xdf mm/kasan/report.c:459 + btrfs_printk+0x395/0x425 fs/btrfs/super.c:244 + device_list_add.cold+0xd7/0x2ed fs/btrfs/volumes.c:957 + btrfs_scan_one_device+0x4c7/0x5c0 fs/btrfs/volumes.c:1387 + btrfs_control_ioctl+0x12a/0x2d0 fs/btrfs/super.c:2409 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:874 [inline] + __se_sys_ioctl fs/ioctl.c:860 [inline] + __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:860 + do_syscall_x64 arch/x86/entry/common.c:50 [inline] + do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 + entry_SYSCALL_64_after_hwframe+0x44/0xae + +Fix this by modifying device->fs_info to NULL too. + +Reported-and-tested-by: syzbot+82650a4e0ed38f218363@syzkaller.appspotmail.com +CC: stable@vger.kernel.org # 4.19+ +Signed-off-by: Dongliang Mu +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/volumes.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index cec54c6e1cdd..89ce0b449c22 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -955,6 +955,11 @@ static noinline struct btrfs_device *device_list_add(const char *path, + /* + * We are going to replace the device path for a given devid, + * make sure it's the same device if the device is mounted ++ * ++ * NOTE: the device->fs_info may not be reliable here so pass ++ * in a NULL to message helpers instead. This avoids a possible ++ * use-after-free when the fs_info and fs_info->sb are already ++ * torn down. + */ + if (device->bdev) { + int error; +@@ -968,12 +973,6 @@ static noinline struct btrfs_device *device_list_add(const char *path, + + if (device->bdev->bd_dev != path_dev) { + mutex_unlock(&fs_devices->device_list_mutex); +- /* +- * device->fs_info may not be reliable here, so +- * pass in a NULL instead. This avoids a +- * possible use-after-free when the fs_info and +- * fs_info->sb are already torn down. +- */ + btrfs_warn_in_rcu(NULL, + "duplicate device %s devid %llu generation %llu scanned by %s (%d)", + path, devid, found_transid, +@@ -981,7 +980,7 @@ static noinline struct btrfs_device *device_list_add(const char *path, + task_pid_nr(current)); + return ERR_PTR(-EEXIST); + } +- btrfs_info_in_rcu(device->fs_info, ++ btrfs_info_in_rcu(NULL, + "devid %llu device path %s changed to %s scanned by %s (%d)", + devid, rcu_str_deref(device->name), + path, current->comm, +-- +2.35.1 + diff --git a/queue-5.15/btrfs-fix-deadlock-between-chunk-allocation-and-chun.patch b/queue-5.15/btrfs-fix-deadlock-between-chunk-allocation-and-chun.patch new file mode 100644 index 00000000000..1cf6b42c4a6 --- /dev/null +++ b/queue-5.15/btrfs-fix-deadlock-between-chunk-allocation-and-chun.patch @@ -0,0 +1,457 @@ +From 88418df0ba0876e9bd115f9dd2ae6934d243a7a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Oct 2021 10:12:49 +0100 +Subject: btrfs: fix deadlock between chunk allocation and chunk btree + modifications + +From: Filipe Manana + +[ Upstream commit 2bb2e00ed9787e52580bb651264b8d6a2b7a9dd2 ] + +When a task is doing some modification to the chunk btree and it is not in +the context of a chunk allocation or a chunk removal, it can deadlock with +another task that is currently allocating a new data or metadata chunk. + +These contexts are the following: + +* When relocating a system chunk, when we need to COW the extent buffers + that belong to the chunk btree; + +* When adding a new device (ioctl), where we need to add a new device item + to the chunk btree; + +* When removing a device (ioctl), where we need to remove a device item + from the chunk btree; + +* When resizing a device (ioctl), where we need to update a device item in + the chunk btree and may need to relocate a system chunk that lies beyond + the new device size when shrinking a device. + +The problem happens due to a sequence of steps like the following: + +1) Task A starts a data or metadata chunk allocation and it locks the + chunk mutex; + +2) Task B is relocating a system chunk, and when it needs to COW an extent + buffer of the chunk btree, it has locked both that extent buffer as + well as its parent extent buffer; + +3) Since there is not enough available system space, either because none + of the existing system block groups have enough free space or because + the only one with enough free space is in RO mode due to the relocation, + task B triggers a new system chunk allocation. It blocks when trying to + acquire the chunk mutex, currently held by task A; + +4) Task A enters btrfs_chunk_alloc_add_chunk_item(), in order to insert + the new chunk item into the chunk btree and update the existing device + items there. But in order to do that, it has to lock the extent buffer + that task B locked at step 2, or its parent extent buffer, but task B + is waiting on the chunk mutex, which is currently locked by task A, + therefore resulting in a deadlock. + +One example report when the deadlock happens with system chunk relocation: + + INFO: task kworker/u9:5:546 blocked for more than 143 seconds. + Not tainted 5.15.0-rc3+ #1 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:kworker/u9:5 state:D stack:25936 pid: 546 ppid: 2 flags:0x00004000 + Workqueue: events_unbound btrfs_async_reclaim_metadata_space + Call Trace: + context_switch kernel/sched/core.c:4940 [inline] + __schedule+0xcd9/0x2530 kernel/sched/core.c:6287 + schedule+0xd3/0x270 kernel/sched/core.c:6366 + rwsem_down_read_slowpath+0x4ee/0x9d0 kernel/locking/rwsem.c:993 + __down_read_common kernel/locking/rwsem.c:1214 [inline] + __down_read kernel/locking/rwsem.c:1223 [inline] + down_read_nested+0xe6/0x440 kernel/locking/rwsem.c:1590 + __btrfs_tree_read_lock+0x31/0x350 fs/btrfs/locking.c:47 + btrfs_tree_read_lock fs/btrfs/locking.c:54 [inline] + btrfs_read_lock_root_node+0x8a/0x320 fs/btrfs/locking.c:191 + btrfs_search_slot_get_root fs/btrfs/ctree.c:1623 [inline] + btrfs_search_slot+0x13b4/0x2140 fs/btrfs/ctree.c:1728 + btrfs_update_device+0x11f/0x500 fs/btrfs/volumes.c:2794 + btrfs_chunk_alloc_add_chunk_item+0x34d/0xea0 fs/btrfs/volumes.c:5504 + do_chunk_alloc fs/btrfs/block-group.c:3408 [inline] + btrfs_chunk_alloc+0x84d/0xf50 fs/btrfs/block-group.c:3653 + flush_space+0x54e/0xd80 fs/btrfs/space-info.c:670 + btrfs_async_reclaim_metadata_space+0x396/0xa90 fs/btrfs/space-info.c:953 + process_one_work+0x9df/0x16d0 kernel/workqueue.c:2297 + worker_thread+0x90/0xed0 kernel/workqueue.c:2444 + kthread+0x3e5/0x4d0 kernel/kthread.c:319 + ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295 + INFO: task syz-executor:9107 blocked for more than 143 seconds. + Not tainted 5.15.0-rc3+ #1 + "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + task:syz-executor state:D stack:23200 pid: 9107 ppid: 7792 flags:0x00004004 + Call Trace: + context_switch kernel/sched/core.c:4940 [inline] + __schedule+0xcd9/0x2530 kernel/sched/core.c:6287 + schedule+0xd3/0x270 kernel/sched/core.c:6366 + schedule_preempt_disabled+0xf/0x20 kernel/sched/core.c:6425 + __mutex_lock_common kernel/locking/mutex.c:669 [inline] + __mutex_lock+0xc96/0x1680 kernel/locking/mutex.c:729 + btrfs_chunk_alloc+0x31a/0xf50 fs/btrfs/block-group.c:3631 + find_free_extent_update_loop fs/btrfs/extent-tree.c:3986 [inline] + find_free_extent+0x25cb/0x3a30 fs/btrfs/extent-tree.c:4335 + btrfs_reserve_extent+0x1f1/0x500 fs/btrfs/extent-tree.c:4415 + btrfs_alloc_tree_block+0x203/0x1120 fs/btrfs/extent-tree.c:4813 + __btrfs_cow_block+0x412/0x1620 fs/btrfs/ctree.c:415 + btrfs_cow_block+0x2f6/0x8c0 fs/btrfs/ctree.c:570 + btrfs_search_slot+0x1094/0x2140 fs/btrfs/ctree.c:1768 + relocate_tree_block fs/btrfs/relocation.c:2694 [inline] + relocate_tree_blocks+0xf73/0x1770 fs/btrfs/relocation.c:2757 + relocate_block_group+0x47e/0xc70 fs/btrfs/relocation.c:3673 + btrfs_relocate_block_group+0x48a/0xc60 fs/btrfs/relocation.c:4070 + btrfs_relocate_chunk+0x96/0x280 fs/btrfs/volumes.c:3181 + __btrfs_balance fs/btrfs/volumes.c:3911 [inline] + btrfs_balance+0x1f03/0x3cd0 fs/btrfs/volumes.c:4301 + btrfs_ioctl_balance+0x61e/0x800 fs/btrfs/ioctl.c:4137 + btrfs_ioctl+0x39ea/0x7b70 fs/btrfs/ioctl.c:4949 + vfs_ioctl fs/ioctl.c:51 [inline] + __do_sys_ioctl fs/ioctl.c:874 [inline] + __se_sys_ioctl fs/ioctl.c:860 [inline] + __x64_sys_ioctl+0x193/0x200 fs/ioctl.c:860 + do_syscall_x64 arch/x86/entry/common.c:50 [inline] + do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 + entry_SYSCALL_64_after_hwframe+0x44/0xae + +So fix this by making sure that whenever we try to modify the chunk btree +and we are neither in a chunk allocation context nor in a chunk remove +context, we reserve system space before modifying the chunk btree. + +Reported-by: Hao Sun +Link: https://lore.kernel.org/linux-btrfs/CACkBjsax51i4mu6C0C3vJqQN3NR_iVuucoeG3U1HXjrgzn5FFQ@mail.gmail.com/ +Fixes: 79bd37120b1495 ("btrfs: rework chunk allocation to avoid exhaustion of the system chunk array") +CC: stable@vger.kernel.org # 5.14+ +Reviewed-by: Josef Bacik +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 146 +++++++++++++++++++++++++---------------- + fs/btrfs/block-group.h | 2 + + fs/btrfs/relocation.c | 4 ++ + fs/btrfs/volumes.c | 15 ++++- + 4 files changed, 111 insertions(+), 56 deletions(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index aadc1203ad88..c6c5a22ff6e8 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -3406,25 +3406,6 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags) + goto out; + } + +- /* +- * If this is a system chunk allocation then stop right here and do not +- * add the chunk item to the chunk btree. This is to prevent a deadlock +- * because this system chunk allocation can be triggered while COWing +- * some extent buffer of the chunk btree and while holding a lock on a +- * parent extent buffer, in which case attempting to insert the chunk +- * item (or update the device item) would result in a deadlock on that +- * parent extent buffer. In this case defer the chunk btree updates to +- * the second phase of chunk allocation and keep our reservation until +- * the second phase completes. +- * +- * This is a rare case and can only be triggered by the very few cases +- * we have where we need to touch the chunk btree outside chunk allocation +- * and chunk removal. These cases are basically adding a device, removing +- * a device or resizing a device. +- */ +- if (flags & BTRFS_BLOCK_GROUP_SYSTEM) +- return 0; +- + ret = btrfs_chunk_alloc_add_chunk_item(trans, bg); + /* + * Normally we are not expected to fail with -ENOSPC here, since we have +@@ -3557,14 +3538,14 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags) + * This has happened before and commit eafa4fd0ad0607 ("btrfs: fix exhaustion of + * the system chunk array due to concurrent allocations") provides more details. + * +- * For allocation of system chunks, we defer the updates and insertions into the +- * chunk btree to phase 2. This is to prevent deadlocks on extent buffers because +- * if the chunk allocation is triggered while COWing an extent buffer of the +- * chunk btree, we are holding a lock on the parent of that extent buffer and +- * doing the chunk btree updates and insertions can require locking that parent. +- * This is for the very few and rare cases where we update the chunk btree that +- * are not chunk allocation or chunk removal: adding a device, removing a device +- * or resizing a device. ++ * Allocation of system chunks does not happen through this function. A task that ++ * needs to update the chunk btree (the only btree that uses system chunks), must ++ * preallocate chunk space by calling either check_system_chunk() or ++ * btrfs_reserve_chunk_metadata() - the former is used when allocating a data or ++ * metadata chunk or when removing a chunk, while the later is used before doing ++ * a modification to the chunk btree - use cases for the later are adding, ++ * removing and resizing a device as well as relocation of a system chunk. ++ * See the comment below for more details. + * + * The reservation of system space, done through check_system_chunk(), as well + * as all the updates and insertions into the chunk btree must be done while +@@ -3601,11 +3582,27 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, + if (trans->allocating_chunk) + return -ENOSPC; + /* +- * If we are removing a chunk, don't re-enter or we would deadlock. +- * System space reservation and system chunk allocation is done by the +- * chunk remove operation (btrfs_remove_chunk()). ++ * Allocation of system chunks can not happen through this path, as we ++ * could end up in a deadlock if we are allocating a data or metadata ++ * chunk and there is another task modifying the chunk btree. ++ * ++ * This is because while we are holding the chunk mutex, we will attempt ++ * to add the new chunk item to the chunk btree or update an existing ++ * device item in the chunk btree, while the other task that is modifying ++ * the chunk btree is attempting to COW an extent buffer while holding a ++ * lock on it and on its parent - if the COW operation triggers a system ++ * chunk allocation, then we can deadlock because we are holding the ++ * chunk mutex and we may need to access that extent buffer or its parent ++ * in order to add the chunk item or update a device item. ++ * ++ * Tasks that want to modify the chunk tree should reserve system space ++ * before updating the chunk btree, by calling either ++ * btrfs_reserve_chunk_metadata() or check_system_chunk(). ++ * It's possible that after a task reserves the space, it still ends up ++ * here - this happens in the cases described above at do_chunk_alloc(). ++ * The task will have to either retry or fail. + */ +- if (trans->removing_chunk) ++ if (flags & BTRFS_BLOCK_GROUP_SYSTEM) + return -ENOSPC; + + space_info = btrfs_find_space_info(fs_info, flags); +@@ -3704,17 +3701,14 @@ static u64 get_profile_num_devs(struct btrfs_fs_info *fs_info, u64 type) + return num_dev; + } + +-/* +- * Reserve space in the system space for allocating or removing a chunk +- */ +-void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) ++static void reserve_chunk_space(struct btrfs_trans_handle *trans, ++ u64 bytes, ++ u64 type) + { + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_space_info *info; + u64 left; +- u64 thresh; + int ret = 0; +- u64 num_devs; + + /* + * Needed because we can end up allocating a system chunk and for an +@@ -3727,19 +3721,13 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) + left = info->total_bytes - btrfs_space_info_used(info, true); + spin_unlock(&info->lock); + +- num_devs = get_profile_num_devs(fs_info, type); +- +- /* num_devs device items to update and 1 chunk item to add or remove */ +- thresh = btrfs_calc_metadata_size(fs_info, num_devs) + +- btrfs_calc_insert_metadata_size(fs_info, 1); +- +- if (left < thresh && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) { ++ if (left < bytes && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) { + btrfs_info(fs_info, "left=%llu, need=%llu, flags=%llu", +- left, thresh, type); ++ left, bytes, type); + btrfs_dump_space_info(fs_info, info, 0, 0); + } + +- if (left < thresh) { ++ if (left < bytes) { + u64 flags = btrfs_system_alloc_profile(fs_info); + struct btrfs_block_group *bg; + +@@ -3748,21 +3736,20 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) + * needing it, as we might not need to COW all nodes/leafs from + * the paths we visit in the chunk tree (they were already COWed + * or created in the current transaction for example). +- * +- * Also, if our caller is allocating a system chunk, do not +- * attempt to insert the chunk item in the chunk btree, as we +- * could deadlock on an extent buffer since our caller may be +- * COWing an extent buffer from the chunk btree. + */ + bg = btrfs_create_chunk(trans, flags); + if (IS_ERR(bg)) { + ret = PTR_ERR(bg); +- } else if (!(type & BTRFS_BLOCK_GROUP_SYSTEM)) { ++ } else { + /* + * If we fail to add the chunk item here, we end up + * trying again at phase 2 of chunk allocation, at + * btrfs_create_pending_block_groups(). So ignore +- * any error here. ++ * any error here. An ENOSPC here could happen, due to ++ * the cases described at do_chunk_alloc() - the system ++ * block group we just created was just turned into RO ++ * mode by a scrub for example, or a running discard ++ * temporarily removed its free space entries, etc. + */ + btrfs_chunk_alloc_add_chunk_item(trans, bg); + } +@@ -3771,12 +3758,61 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) + if (!ret) { + ret = btrfs_block_rsv_add(fs_info->chunk_root, + &fs_info->chunk_block_rsv, +- thresh, BTRFS_RESERVE_NO_FLUSH); ++ bytes, BTRFS_RESERVE_NO_FLUSH); + if (!ret) +- trans->chunk_bytes_reserved += thresh; ++ trans->chunk_bytes_reserved += bytes; + } + } + ++/* ++ * Reserve space in the system space for allocating or removing a chunk. ++ * The caller must be holding fs_info->chunk_mutex. ++ */ ++void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) ++{ ++ struct btrfs_fs_info *fs_info = trans->fs_info; ++ const u64 num_devs = get_profile_num_devs(fs_info, type); ++ u64 bytes; ++ ++ /* num_devs device items to update and 1 chunk item to add or remove. */ ++ bytes = btrfs_calc_metadata_size(fs_info, num_devs) + ++ btrfs_calc_insert_metadata_size(fs_info, 1); ++ ++ reserve_chunk_space(trans, bytes, type); ++} ++ ++/* ++ * Reserve space in the system space, if needed, for doing a modification to the ++ * chunk btree. ++ * ++ * @trans: A transaction handle. ++ * @is_item_insertion: Indicate if the modification is for inserting a new item ++ * in the chunk btree or if it's for the deletion or update ++ * of an existing item. ++ * ++ * This is used in a context where we need to update the chunk btree outside ++ * block group allocation and removal, to avoid a deadlock with a concurrent ++ * task that is allocating a metadata or data block group and therefore needs to ++ * update the chunk btree while holding the chunk mutex. After the update to the ++ * chunk btree is done, btrfs_trans_release_chunk_metadata() should be called. ++ * ++ */ ++void btrfs_reserve_chunk_metadata(struct btrfs_trans_handle *trans, ++ bool is_item_insertion) ++{ ++ struct btrfs_fs_info *fs_info = trans->fs_info; ++ u64 bytes; ++ ++ if (is_item_insertion) ++ bytes = btrfs_calc_insert_metadata_size(fs_info, 1); ++ else ++ bytes = btrfs_calc_metadata_size(fs_info, 1); ++ ++ mutex_lock(&fs_info->chunk_mutex); ++ reserve_chunk_space(trans, bytes, BTRFS_BLOCK_GROUP_SYSTEM); ++ mutex_unlock(&fs_info->chunk_mutex); ++} ++ + void btrfs_put_block_group_cache(struct btrfs_fs_info *info) + { + struct btrfs_block_group *block_group; +diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h +index c72a71efcb18..37e55ebde735 100644 +--- a/fs/btrfs/block-group.h ++++ b/fs/btrfs/block-group.h +@@ -289,6 +289,8 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags, + enum btrfs_chunk_alloc_enum force); + int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, u64 type); + void check_system_chunk(struct btrfs_trans_handle *trans, const u64 type); ++void btrfs_reserve_chunk_metadata(struct btrfs_trans_handle *trans, ++ bool is_item_insertion); + u64 btrfs_get_alloc_profile(struct btrfs_fs_info *fs_info, u64 orig_flags); + void btrfs_put_block_group_cache(struct btrfs_fs_info *info); + int btrfs_free_block_groups(struct btrfs_fs_info *info); +diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c +index 0300770c0a89..429a198f8937 100644 +--- a/fs/btrfs/relocation.c ++++ b/fs/btrfs/relocation.c +@@ -2698,8 +2698,12 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans, + list_add_tail(&node->list, &rc->backref_cache.changed); + } else { + path->lowest_level = node->level; ++ if (root == root->fs_info->chunk_root) ++ btrfs_reserve_chunk_metadata(trans, false); + ret = btrfs_search_slot(trans, root, key, path, 0, 1); + btrfs_release_path(path); ++ if (root == root->fs_info->chunk_root) ++ btrfs_trans_release_chunk_metadata(trans); + if (ret > 0) + ret = 0; + } +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index b75ce79a2540..fa68efd7e610 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -1879,8 +1879,10 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans, + key.type = BTRFS_DEV_ITEM_KEY; + key.offset = device->devid; + ++ btrfs_reserve_chunk_metadata(trans, true); + ret = btrfs_insert_empty_item(trans, trans->fs_info->chunk_root, path, + &key, sizeof(*dev_item)); ++ btrfs_trans_release_chunk_metadata(trans); + if (ret) + goto out; + +@@ -1957,7 +1959,9 @@ static int btrfs_rm_dev_item(struct btrfs_device *device) + key.type = BTRFS_DEV_ITEM_KEY; + key.offset = device->devid; + ++ btrfs_reserve_chunk_metadata(trans, false); + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); ++ btrfs_trans_release_chunk_metadata(trans); + if (ret) { + if (ret > 0) + ret = -ENOENT; +@@ -2513,7 +2517,9 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans) + key.type = BTRFS_DEV_ITEM_KEY; + + while (1) { ++ btrfs_reserve_chunk_metadata(trans, false); + ret = btrfs_search_slot(trans, root, &key, path, 0, 1); ++ btrfs_trans_release_chunk_metadata(trans); + if (ret < 0) + goto error; + +@@ -2861,6 +2867,7 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans, + struct btrfs_super_block *super_copy = fs_info->super_copy; + u64 old_total; + u64 diff; ++ int ret; + + if (!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) + return -EACCES; +@@ -2889,7 +2896,11 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans, + &trans->transaction->dev_update_list); + mutex_unlock(&fs_info->chunk_mutex); + +- return btrfs_update_device(trans, device); ++ btrfs_reserve_chunk_metadata(trans, false); ++ ret = btrfs_update_device(trans, device); ++ btrfs_trans_release_chunk_metadata(trans); ++ ++ return ret; + } + + static int btrfs_free_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset) +@@ -4926,8 +4937,10 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) + round_down(old_total - diff, fs_info->sectorsize)); + mutex_unlock(&fs_info->chunk_mutex); + ++ btrfs_reserve_chunk_metadata(trans, false); + /* Now btrfs_update_device() will change the on-disk size. */ + ret = btrfs_update_device(trans, device); ++ btrfs_trans_release_chunk_metadata(trans); + if (ret < 0) { + btrfs_abort_transaction(trans, ret); + btrfs_end_transaction(trans); +-- +2.35.1 + diff --git a/queue-5.15/btrfs-fix-invalid-delayed-ref-after-subvolume-creati.patch b/queue-5.15/btrfs-fix-invalid-delayed-ref-after-subvolume-creati.patch new file mode 100644 index 00000000000..494a0965190 --- /dev/null +++ b/queue-5.15/btrfs-fix-invalid-delayed-ref-after-subvolume-creati.patch @@ -0,0 +1,309 @@ +From 56d47ae9013f457ccbf4a4af691c9178a9822e25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Dec 2021 08:45:12 +0000 +Subject: btrfs: fix invalid delayed ref after subvolume creation failure + +From: Filipe Manana + +[ Upstream commit 7a1636089acfee7562fe79aff7d1b4c57869896d ] + +When creating a subvolume, at ioctl.c:create_subvol(), if we fail to +insert the new root's root item into the root tree, we are freeing the +metadata extent we reserved for the new root to prevent a metadata +extent leak, as we don't abort the transaction at that point (since +there is nothing at that point that is irreversible). + +However we allocated the metadata extent for the new root which we are +creating for the new subvolume, so its delayed reference refers to the +ID of this new root. But when we free the metadata extent we pass the +root of the subvolume where the new subvolume is located to +btrfs_free_tree_block() - this is incorrect because this will generate +a delayed reference that refers to the ID of the parent subvolume's root, +and not to ID of the new root. + +This results in a failure when running delayed references that leads to +a transaction abort and a trace like the following: + +[3868.738042] RIP: 0010:__btrfs_free_extent+0x709/0x950 [btrfs] +[3868.739857] Code: 68 0f 85 e6 fb ff (...) +[3868.742963] RSP: 0018:ffffb0e9045cf910 EFLAGS: 00010246 +[3868.743908] RAX: 00000000fffffffe RBX: 00000000fffffffe RCX: 0000000000000002 +[3868.745312] RDX: 00000000fffffffe RSI: 0000000000000002 RDI: ffff90b0cd793b88 +[3868.746643] RBP: 000000000e5d8000 R08: 0000000000000000 R09: ffff90b0cd793b88 +[3868.747979] R10: 0000000000000002 R11: 00014ded97944d68 R12: 0000000000000000 +[3868.749373] R13: ffff90b09afe4a28 R14: 0000000000000000 R15: ffff90b0cd793b88 +[3868.750725] FS: 00007f281c4a8b80(0000) GS:ffff90b3ada00000(0000) knlGS:0000000000000000 +[3868.752275] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[3868.753515] CR2: 00007f281c6a5000 CR3: 0000000108a42006 CR4: 0000000000370ee0 +[3868.754869] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[3868.756228] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +[3868.757803] Call Trace: +[3868.758281] +[3868.758655] ? btrfs_merge_delayed_refs+0x178/0x1c0 [btrfs] +[3868.759827] __btrfs_run_delayed_refs+0x2b1/0x1250 [btrfs] +[3868.761047] btrfs_run_delayed_refs+0x86/0x210 [btrfs] +[3868.762069] ? lock_acquired+0x19f/0x420 +[3868.762829] btrfs_commit_transaction+0x69/0xb20 [btrfs] +[3868.763860] ? _raw_spin_unlock+0x29/0x40 +[3868.764614] ? btrfs_block_rsv_release+0x1c2/0x1e0 [btrfs] +[3868.765870] create_subvol+0x1d8/0x9a0 [btrfs] +[3868.766766] btrfs_mksubvol+0x447/0x4c0 [btrfs] +[3868.767669] ? preempt_count_add+0x49/0xa0 +[3868.768444] __btrfs_ioctl_snap_create+0x123/0x190 [btrfs] +[3868.769639] ? _copy_from_user+0x66/0xa0 +[3868.770391] btrfs_ioctl_snap_create_v2+0xbb/0x140 [btrfs] +[3868.771495] btrfs_ioctl+0xd1e/0x35c0 [btrfs] +[3868.772364] ? __slab_free+0x10a/0x360 +[3868.773198] ? rcu_read_lock_sched_held+0x12/0x60 +[3868.774121] ? lock_release+0x223/0x4a0 +[3868.774863] ? lock_acquired+0x19f/0x420 +[3868.775634] ? rcu_read_lock_sched_held+0x12/0x60 +[3868.776530] ? trace_hardirqs_on+0x1b/0xe0 +[3868.777373] ? _raw_spin_unlock_irqrestore+0x3e/0x60 +[3868.778280] ? kmem_cache_free+0x321/0x3c0 +[3868.779011] ? __x64_sys_ioctl+0x83/0xb0 +[3868.779718] __x64_sys_ioctl+0x83/0xb0 +[3868.780387] do_syscall_64+0x3b/0xc0 +[3868.781059] entry_SYSCALL_64_after_hwframe+0x44/0xae +[3868.781953] RIP: 0033:0x7f281c59e957 +[3868.782585] Code: 3c 1c 48 f7 d8 4c (...) +[3868.785867] RSP: 002b:00007ffe1f83e2b8 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 +[3868.787198] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f281c59e957 +[3868.788450] RDX: 00007ffe1f83e2c0 RSI: 0000000050009418 RDI: 0000000000000003 +[3868.789748] RBP: 00007ffe1f83f300 R08: 0000000000000000 R09: 00007ffe1f83fe36 +[3868.791214] R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000003 +[3868.792468] R13: 0000000000000003 R14: 00007ffe1f83e2c0 R15: 00000000000003cc +[3868.793765] +[3868.794037] irq event stamp: 0 +[3868.794548] hardirqs last enabled at (0): [<0000000000000000>] 0x0 +[3868.795670] hardirqs last disabled at (0): [] copy_process+0x934/0x2040 +[3868.797086] softirqs last enabled at (0): [] copy_process+0x934/0x2040 +[3868.798309] softirqs last disabled at (0): [<0000000000000000>] 0x0 +[3868.799284] ---[ end trace be24c7002fe27747 ]--- +[3868.799928] BTRFS info (device dm-0): leaf 241188864 gen 1268 total ptrs 214 free space 469 owner 2 +[3868.801133] BTRFS info (device dm-0): refs 2 lock_owner 225627 current 225627 +[3868.802056] item 0 key (237436928 169 0) itemoff 16250 itemsize 33 +[3868.802863] extent refs 1 gen 1265 flags 2 +[3868.803447] ref#0: tree block backref root 1610 +(...) +[3869.064354] item 114 key (241008640 169 0) itemoff 12488 itemsize 33 +[3869.065421] extent refs 1 gen 1268 flags 2 +[3869.066115] ref#0: tree block backref root 1689 +(...) +[3869.403834] BTRFS error (device dm-0): unable to find ref byte nr 241008640 parent 0 root 1622 owner 0 offset 0 +[3869.405641] BTRFS: error (device dm-0) in __btrfs_free_extent:3076: errno=-2 No such entry +[3869.407138] BTRFS: error (device dm-0) in btrfs_run_delayed_refs:2159: errno=-2 No such entry + +Fix this by passing the new subvolume's root ID to btrfs_free_tree_block(). +This requires changing the root argument of btrfs_free_tree_block() from +struct btrfs_root * to a u64, since at this point during the subvolume +creation we have not yet created the struct btrfs_root for the new +subvolume, and btrfs_free_tree_block() only needs a root ID and nothing +else from a struct btrfs_root. + +This was triggered by test case generic/475 from fstests. + +Fixes: 67addf29004c5b ("btrfs: fix metadata extent leak after failure to create subvolume") +CC: stable@vger.kernel.org # 4.4+ +Reviewed-by: Nikolay Borisov +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/ctree.c | 17 +++++++++-------- + fs/btrfs/ctree.h | 7 ++++++- + fs/btrfs/extent-tree.c | 13 +++++++------ + fs/btrfs/free-space-tree.c | 4 ++-- + fs/btrfs/ioctl.c | 9 +++++---- + fs/btrfs/qgroup.c | 3 ++- + 6 files changed, 31 insertions(+), 22 deletions(-) + +diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c +index 899f85445925..341ce90d24b1 100644 +--- a/fs/btrfs/ctree.c ++++ b/fs/btrfs/ctree.c +@@ -462,8 +462,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, + BUG_ON(ret < 0); + rcu_assign_pointer(root->node, cow); + +- btrfs_free_tree_block(trans, root, buf, parent_start, +- last_ref); ++ btrfs_free_tree_block(trans, btrfs_root_id(root), buf, ++ parent_start, last_ref); + free_extent_buffer(buf); + add_root_to_dirty_list(root); + } else { +@@ -484,8 +484,8 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, + return ret; + } + } +- btrfs_free_tree_block(trans, root, buf, parent_start, +- last_ref); ++ btrfs_free_tree_block(trans, btrfs_root_id(root), buf, ++ parent_start, last_ref); + } + if (unlock_orig) + btrfs_tree_unlock(buf); +@@ -926,7 +926,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, + free_extent_buffer(mid); + + root_sub_used(root, mid->len); +- btrfs_free_tree_block(trans, root, mid, 0, 1); ++ btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1); + /* once for the root ptr */ + free_extent_buffer_stale(mid); + return 0; +@@ -985,7 +985,8 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, + btrfs_tree_unlock(right); + del_ptr(root, path, level + 1, pslot + 1); + root_sub_used(root, right->len); +- btrfs_free_tree_block(trans, root, right, 0, 1); ++ btrfs_free_tree_block(trans, btrfs_root_id(root), right, ++ 0, 1); + free_extent_buffer_stale(right); + right = NULL; + } else { +@@ -1030,7 +1031,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, + btrfs_tree_unlock(mid); + del_ptr(root, path, level + 1, pslot); + root_sub_used(root, mid->len); +- btrfs_free_tree_block(trans, root, mid, 0, 1); ++ btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1); + free_extent_buffer_stale(mid); + mid = NULL; + } else { +@@ -4059,7 +4060,7 @@ static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans, + root_sub_used(root, leaf->len); + + atomic_inc(&leaf->refs); +- btrfs_free_tree_block(trans, root, leaf, 0, 1); ++ btrfs_free_tree_block(trans, btrfs_root_id(root), leaf, 0, 1); + free_extent_buffer_stale(leaf); + } + /* +diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h +index 21c44846b002..cc72d8981c47 100644 +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -2256,6 +2256,11 @@ static inline bool btrfs_root_dead(const struct btrfs_root *root) + return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0; + } + ++static inline u64 btrfs_root_id(const struct btrfs_root *root) ++{ ++ return root->root_key.objectid; ++} ++ + /* struct btrfs_root_backup */ + BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, + tree_root, 64); +@@ -2718,7 +2723,7 @@ struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, + u64 empty_size, + enum btrfs_lock_nesting nest); + void btrfs_free_tree_block(struct btrfs_trans_handle *trans, +- struct btrfs_root *root, ++ u64 root_id, + struct extent_buffer *buf, + u64 parent, int last_ref); + int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, +diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c +index e01b9344fb9c..f11616f61dd6 100644 +--- a/fs/btrfs/extent-tree.c ++++ b/fs/btrfs/extent-tree.c +@@ -3280,20 +3280,20 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, + } + + void btrfs_free_tree_block(struct btrfs_trans_handle *trans, +- struct btrfs_root *root, ++ u64 root_id, + struct extent_buffer *buf, + u64 parent, int last_ref) + { +- struct btrfs_fs_info *fs_info = root->fs_info; ++ struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_ref generic_ref = { 0 }; + int ret; + + btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF, + buf->start, buf->len, parent); + btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf), +- root->root_key.objectid, 0, false); ++ root_id, 0, false); + +- if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { ++ if (root_id != BTRFS_TREE_LOG_OBJECTID) { + btrfs_ref_tree_mod(fs_info, &generic_ref); + ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, NULL); + BUG_ON(ret); /* -ENOMEM */ +@@ -3303,7 +3303,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans, + struct btrfs_block_group *cache; + bool must_pin = false; + +- if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { ++ if (root_id != BTRFS_TREE_LOG_OBJECTID) { + ret = check_ref_cleanup(trans, buf->start); + if (!ret) { + btrfs_redirty_list_add(trans->transaction, buf); +@@ -5441,7 +5441,8 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans, + goto owner_mismatch; + } + +- btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1); ++ btrfs_free_tree_block(trans, btrfs_root_id(root), eb, parent, ++ wc->refs[level] == 1); + out: + wc->refs[level] = 0; + wc->flags[level] = 0; +diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c +index a33bca94d133..3abec44c6255 100644 +--- a/fs/btrfs/free-space-tree.c ++++ b/fs/btrfs/free-space-tree.c +@@ -1256,8 +1256,8 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) + btrfs_tree_lock(free_space_root->node); + btrfs_clean_tree_block(free_space_root->node); + btrfs_tree_unlock(free_space_root->node); +- btrfs_free_tree_block(trans, free_space_root, free_space_root->node, +- 0, 1); ++ btrfs_free_tree_block(trans, btrfs_root_id(free_space_root), ++ free_space_root->node, 0, 1); + + btrfs_put_root(free_space_root); + +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index bf53af8694f8..7272d9d3fa78 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -615,11 +615,12 @@ static noinline int create_subvol(struct user_namespace *mnt_userns, + * Since we don't abort the transaction in this case, free the + * tree block so that we don't leak space and leave the + * filesystem in an inconsistent state (an extent item in the +- * extent tree without backreferences). Also no need to have +- * the tree block locked since it is not in any tree at this +- * point, so no other task can find it and use it. ++ * extent tree with a backreference for a root that does not ++ * exists). Also no need to have the tree block locked since it ++ * is not in any tree at this point, so no other task can find ++ * it and use it. + */ +- btrfs_free_tree_block(trans, root, leaf, 0, 1); ++ btrfs_free_tree_block(trans, objectid, leaf, 0, 1); + free_extent_buffer(leaf); + goto fail; + } +diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c +index 2c803108ea94..4ca809fa80ea 100644 +--- a/fs/btrfs/qgroup.c ++++ b/fs/btrfs/qgroup.c +@@ -1259,7 +1259,8 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info) + btrfs_tree_lock(quota_root->node); + btrfs_clean_tree_block(quota_root->node); + btrfs_tree_unlock(quota_root->node); +- btrfs_free_tree_block(trans, quota_root, quota_root->node, 0, 1); ++ btrfs_free_tree_block(trans, btrfs_root_id(quota_root), ++ quota_root->node, 0, 1); + + btrfs_put_root(quota_root); + +-- +2.35.1 + diff --git a/queue-5.15/btrfs-fix-warning-when-freeing-leaf-after-subvolume-.patch b/queue-5.15/btrfs-fix-warning-when-freeing-leaf-after-subvolume-.patch new file mode 100644 index 00000000000..5e32c2a4815 --- /dev/null +++ b/queue-5.15/btrfs-fix-warning-when-freeing-leaf-after-subvolume-.patch @@ -0,0 +1,93 @@ +From 84eb7d5cd410d040729f253c7db28d766ddf3fd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Dec 2021 08:45:13 +0000 +Subject: btrfs: fix warning when freeing leaf after subvolume creation failure + +From: Filipe Manana + +[ Upstream commit 212a58fda9b9077e0efc20200a4feb76afacfd95 ] + +When creating a subvolume, at ioctl.c:create_subvol(), if we fail to +insert the root item for the new subvolume into the root tree, we can +trigger the following warning: + +[78961.741046] WARNING: CPU: 0 PID: 4079814 at fs/btrfs/extent-tree.c:3357 btrfs_free_tree_block+0x2af/0x310 [btrfs] +[78961.743344] Modules linked in: +[78961.749440] dm_snapshot dm_thin_pool (...) +[78961.773648] CPU: 0 PID: 4079814 Comm: fsstress Not tainted 5.16.0-rc4-btrfs-next-108 #1 +[78961.775198] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 +[78961.777266] RIP: 0010:btrfs_free_tree_block+0x2af/0x310 [btrfs] +[78961.778398] Code: 17 00 48 85 (...) +[78961.781067] RSP: 0018:ffffaa4001657b28 EFLAGS: 00010202 +[78961.781877] RAX: 0000000000000213 RBX: ffff897f8a796910 RCX: 0000000000000000 +[78961.782780] RDX: 0000000000000000 RSI: 0000000011004000 RDI: 00000000ffffffff +[78961.783764] RBP: ffff8981f490e800 R08: 0000000000000001 R09: 0000000000000000 +[78961.784740] R10: 0000000000000000 R11: 0000000000000001 R12: ffff897fc963fcc8 +[78961.785665] R13: 0000000000000001 R14: ffff898063548000 R15: ffff898063548000 +[78961.786620] FS: 00007f31283c6b80(0000) GS:ffff8982ace00000(0000) knlGS:0000000000000000 +[78961.787717] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[78961.788598] CR2: 00007f31285c3000 CR3: 000000023fcc8003 CR4: 0000000000370ef0 +[78961.789568] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[78961.790585] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +[78961.791684] Call Trace: +[78961.792082] +[78961.792359] create_subvol+0x5d1/0x9a0 [btrfs] +[78961.793054] btrfs_mksubvol+0x447/0x4c0 [btrfs] +[78961.794009] ? preempt_count_add+0x49/0xa0 +[78961.794705] __btrfs_ioctl_snap_create+0x123/0x190 [btrfs] +[78961.795712] ? _copy_from_user+0x66/0xa0 +[78961.796382] btrfs_ioctl_snap_create_v2+0xbb/0x140 [btrfs] +[78961.797392] btrfs_ioctl+0xd1e/0x35c0 [btrfs] +[78961.798172] ? __slab_free+0x10a/0x360 +[78961.798820] ? rcu_read_lock_sched_held+0x12/0x60 +[78961.799664] ? lock_release+0x223/0x4a0 +[78961.800321] ? lock_acquired+0x19f/0x420 +[78961.800992] ? rcu_read_lock_sched_held+0x12/0x60 +[78961.801796] ? trace_hardirqs_on+0x1b/0xe0 +[78961.802495] ? _raw_spin_unlock_irqrestore+0x3e/0x60 +[78961.803358] ? kmem_cache_free+0x321/0x3c0 +[78961.804071] ? __x64_sys_ioctl+0x83/0xb0 +[78961.804711] __x64_sys_ioctl+0x83/0xb0 +[78961.805348] do_syscall_64+0x3b/0xc0 +[78961.805969] entry_SYSCALL_64_after_hwframe+0x44/0xae +[78961.806830] RIP: 0033:0x7f31284bc957 +[78961.807517] Code: 3c 1c 48 f7 d8 (...) + +This is because we are calling btrfs_free_tree_block() on an extent +buffer that is dirty. Fix that by cleaning the extent buffer, with +btrfs_clean_tree_block(), before freeing it. + +This was triggered by test case generic/475 from fstests. + +Fixes: 67addf29004c5b ("btrfs: fix metadata extent leak after failure to create subvolume") +CC: stable@vger.kernel.org # 4.4+ +Reviewed-by: Nikolay Borisov +Signed-off-by: Filipe Manana +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/ioctl.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index 7272d9d3fa78..a37ab3e89a3b 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -616,10 +616,11 @@ static noinline int create_subvol(struct user_namespace *mnt_userns, + * tree block so that we don't leak space and leave the + * filesystem in an inconsistent state (an extent item in the + * extent tree with a backreference for a root that does not +- * exists). Also no need to have the tree block locked since it +- * is not in any tree at this point, so no other task can find +- * it and use it. ++ * exists). + */ ++ btrfs_tree_lock(leaf); ++ btrfs_clean_tree_block(leaf); ++ btrfs_tree_unlock(leaf); + btrfs_free_tree_block(trans, objectid, leaf, 0, 1); + free_extent_buffer(leaf); + goto fail; +-- +2.35.1 + diff --git a/queue-5.15/btrfs-handle-device-lookup-with-btrfs_dev_lookup_arg.patch b/queue-5.15/btrfs-handle-device-lookup-with-btrfs_dev_lookup_arg.patch new file mode 100644 index 00000000000..bed127f39b8 --- /dev/null +++ b/queue-5.15/btrfs-handle-device-lookup-with-btrfs_dev_lookup_arg.patch @@ -0,0 +1,486 @@ +From 163b3fa489aa076300b8e702f4b810ef963ac947 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 Oct 2021 16:12:42 -0400 +Subject: btrfs: handle device lookup with btrfs_dev_lookup_args + +From: Josef Bacik + +[ Upstream commit 562d7b1512f7369a19bca2883e2e8672d78f0481 ] + +We have a lot of device lookup functions that all do something slightly +different. Clean this up by adding a struct to hold the different +lookup criteria, and then pass this around to btrfs_find_device() so it +can do the proper matching based on the lookup criteria. + +Reviewed-by: Anand Jain +Signed-off-by: Josef Bacik +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/dev-replace.c | 16 +++--- + fs/btrfs/ioctl.c | 13 +++-- + fs/btrfs/scrub.c | 6 +- + fs/btrfs/volumes.c | 122 +++++++++++++++++++++++++---------------- + fs/btrfs/volumes.h | 20 ++++++- + 5 files changed, 112 insertions(+), 65 deletions(-) + +diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c +index bdbc310a8f8c..781556e2a37f 100644 +--- a/fs/btrfs/dev-replace.c ++++ b/fs/btrfs/dev-replace.c +@@ -70,6 +70,7 @@ static int btrfs_dev_replace_kthread(void *data); + + int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) + { ++ struct btrfs_dev_lookup_args args = { .devid = BTRFS_DEV_REPLACE_DEVID }; + struct btrfs_key key; + struct btrfs_root *dev_root = fs_info->dev_root; + struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; +@@ -100,8 +101,7 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) + * We don't have a replace item or it's corrupted. If there is + * a replace target, fail the mount. + */ +- if (btrfs_find_device(fs_info->fs_devices, +- BTRFS_DEV_REPLACE_DEVID, NULL, NULL)) { ++ if (btrfs_find_device(fs_info->fs_devices, &args)) { + btrfs_err(fs_info, + "found replace target device without a valid replace item"); + ret = -EUCLEAN; +@@ -163,8 +163,7 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) + * We don't have an active replace item but if there is a + * replace target, fail the mount. + */ +- if (btrfs_find_device(fs_info->fs_devices, +- BTRFS_DEV_REPLACE_DEVID, NULL, NULL)) { ++ if (btrfs_find_device(fs_info->fs_devices, &args)) { + btrfs_err(fs_info, + "replace devid present without an active replace item"); + ret = -EUCLEAN; +@@ -175,11 +174,10 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) + break; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: +- dev_replace->srcdev = btrfs_find_device(fs_info->fs_devices, +- src_devid, NULL, NULL); +- dev_replace->tgtdev = btrfs_find_device(fs_info->fs_devices, +- BTRFS_DEV_REPLACE_DEVID, +- NULL, NULL); ++ dev_replace->tgtdev = btrfs_find_device(fs_info->fs_devices, &args); ++ args.devid = src_devid; ++ dev_replace->srcdev = btrfs_find_device(fs_info->fs_devices, &args); ++ + /* + * allow 'btrfs dev replace_cancel' if src/tgt device is + * missing +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index a37ab3e89a3b..4951a2ab88dd 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -1657,6 +1657,7 @@ static int exclop_start_or_cancel_reloc(struct btrfs_fs_info *fs_info, + static noinline int btrfs_ioctl_resize(struct file *file, + void __user *arg) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct inode *inode = file_inode(file); + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + u64 new_size; +@@ -1712,7 +1713,8 @@ static noinline int btrfs_ioctl_resize(struct file *file, + btrfs_info(fs_info, "resizing devid %llu", devid); + } + +- device = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL); ++ args.devid = devid; ++ device = btrfs_find_device(fs_info->fs_devices, &args); + if (!device) { + btrfs_info(fs_info, "resizer unable to find device %llu", + devid); +@@ -3375,22 +3377,21 @@ static long btrfs_ioctl_fs_info(struct btrfs_fs_info *fs_info, + static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info, + void __user *arg) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct btrfs_ioctl_dev_info_args *di_args; + struct btrfs_device *dev; + int ret = 0; +- char *s_uuid = NULL; + + di_args = memdup_user(arg, sizeof(*di_args)); + if (IS_ERR(di_args)) + return PTR_ERR(di_args); + ++ args.devid = di_args->devid; + if (!btrfs_is_empty_uuid(di_args->uuid)) +- s_uuid = di_args->uuid; ++ args.uuid = di_args->uuid; + + rcu_read_lock(); +- dev = btrfs_find_device(fs_info->fs_devices, di_args->devid, s_uuid, +- NULL); +- ++ dev = btrfs_find_device(fs_info->fs_devices, &args); + if (!dev) { + ret = -ENODEV; + goto out; +diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c +index 62f4bafbe54b..6f2787b21530 100644 +--- a/fs/btrfs/scrub.c ++++ b/fs/btrfs/scrub.c +@@ -4068,6 +4068,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, + u64 end, struct btrfs_scrub_progress *progress, + int readonly, int is_dev_replace) + { ++ struct btrfs_dev_lookup_args args = { .devid = devid }; + struct scrub_ctx *sctx; + int ret; + struct btrfs_device *dev; +@@ -4115,7 +4116,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, + goto out_free_ctx; + + mutex_lock(&fs_info->fs_devices->device_list_mutex); +- dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices, &args); + if (!dev || (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) && + !is_dev_replace)) { + mutex_unlock(&fs_info->fs_devices->device_list_mutex); +@@ -4288,11 +4289,12 @@ int btrfs_scrub_cancel_dev(struct btrfs_device *dev) + int btrfs_scrub_progress(struct btrfs_fs_info *fs_info, u64 devid, + struct btrfs_scrub_progress *progress) + { ++ struct btrfs_dev_lookup_args args = { .devid = devid }; + struct btrfs_device *dev; + struct scrub_ctx *sctx = NULL; + + mutex_lock(&fs_info->fs_devices->device_list_mutex); +- dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices, &args); + if (dev) + sctx = dev->scrub_ctx; + if (sctx) +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index fa68efd7e610..53417a1c5402 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -844,9 +844,13 @@ static noinline struct btrfs_device *device_list_add(const char *path, + + device = NULL; + } else { ++ struct btrfs_dev_lookup_args args = { ++ .devid = devid, ++ .uuid = disk_super->dev_item.uuid, ++ }; ++ + mutex_lock(&fs_devices->device_list_mutex); +- device = btrfs_find_device(fs_devices, devid, +- disk_super->dev_item.uuid, NULL); ++ device = btrfs_find_device(fs_devices, &args); + + /* + * If this disk has been pulled into an fs devices created by +@@ -2360,10 +2364,9 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_device *tgtdev) + static struct btrfs_device *btrfs_find_device_by_path( + struct btrfs_fs_info *fs_info, const char *device_path) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + int ret = 0; + struct btrfs_super_block *disk_super; +- u64 devid; +- u8 *dev_uuid; + struct block_device *bdev; + struct btrfs_device *device; + +@@ -2372,14 +2375,14 @@ static struct btrfs_device *btrfs_find_device_by_path( + if (ret) + return ERR_PTR(ret); + +- devid = btrfs_stack_device_id(&disk_super->dev_item); +- dev_uuid = disk_super->dev_item.uuid; ++ args.devid = btrfs_stack_device_id(&disk_super->dev_item); ++ args.uuid = disk_super->dev_item.uuid; + if (btrfs_fs_incompat(fs_info, METADATA_UUID)) +- device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid, +- disk_super->metadata_uuid); ++ args.fsid = disk_super->metadata_uuid; + else +- device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid, +- disk_super->fsid); ++ args.fsid = disk_super->fsid; ++ ++ device = btrfs_find_device(fs_info->fs_devices, &args); + + btrfs_release_disk_super(disk_super); + if (!device) +@@ -2395,11 +2398,12 @@ struct btrfs_device *btrfs_find_device_by_devspec( + struct btrfs_fs_info *fs_info, u64 devid, + const char *device_path) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct btrfs_device *device; + + if (devid) { +- device = btrfs_find_device(fs_info->fs_devices, devid, NULL, +- NULL); ++ args.devid = devid; ++ device = btrfs_find_device(fs_info->fs_devices, &args); + if (!device) + return ERR_PTR(-ENOENT); + return device; +@@ -2409,14 +2413,11 @@ struct btrfs_device *btrfs_find_device_by_devspec( + return ERR_PTR(-EINVAL); + + if (strcmp(device_path, "missing") == 0) { +- /* Find first missing device */ +- list_for_each_entry(device, &fs_info->fs_devices->devices, +- dev_list) { +- if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, +- &device->dev_state) && !device->bdev) +- return device; +- } +- return ERR_PTR(-ENOENT); ++ args.missing = true; ++ device = btrfs_find_device(fs_info->fs_devices, &args); ++ if (!device) ++ return ERR_PTR(-ENOENT); ++ return device; + } + + return btrfs_find_device_by_path(fs_info, device_path); +@@ -2496,6 +2497,7 @@ static int btrfs_prepare_sprout(struct btrfs_fs_info *fs_info) + */ + static int btrfs_finish_sprout(struct btrfs_trans_handle *trans) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct btrfs_fs_info *fs_info = trans->fs_info; + struct btrfs_root *root = fs_info->chunk_root; + struct btrfs_path *path; +@@ -2505,7 +2507,6 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans) + struct btrfs_key key; + u8 fs_uuid[BTRFS_FSID_SIZE]; + u8 dev_uuid[BTRFS_UUID_SIZE]; +- u64 devid; + int ret; + + path = btrfs_alloc_path(); +@@ -2544,13 +2545,14 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans) + + dev_item = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_dev_item); +- devid = btrfs_device_id(leaf, dev_item); ++ args.devid = btrfs_device_id(leaf, dev_item); + read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item), + BTRFS_UUID_SIZE); + read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item), + BTRFS_FSID_SIZE); +- device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid, +- fs_uuid); ++ args.uuid = dev_uuid; ++ args.fsid = fs_uuid; ++ device = btrfs_find_device(fs_info->fs_devices, &args); + BUG_ON(!device); /* Logic error */ + + if (device->fs_devices->seeding) { +@@ -6805,6 +6807,33 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, + return BLK_STS_OK; + } + ++static bool dev_args_match_fs_devices(const struct btrfs_dev_lookup_args *args, ++ const struct btrfs_fs_devices *fs_devices) ++{ ++ if (args->fsid == NULL) ++ return true; ++ if (memcmp(fs_devices->metadata_uuid, args->fsid, BTRFS_FSID_SIZE) == 0) ++ return true; ++ return false; ++} ++ ++static bool dev_args_match_device(const struct btrfs_dev_lookup_args *args, ++ const struct btrfs_device *device) ++{ ++ ASSERT((args->devid != (u64)-1) || args->missing); ++ ++ if ((args->devid != (u64)-1) && device->devid != args->devid) ++ return false; ++ if (args->uuid && memcmp(device->uuid, args->uuid, BTRFS_UUID_SIZE) != 0) ++ return false; ++ if (!args->missing) ++ return true; ++ if (test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state) && ++ !device->bdev) ++ return true; ++ return false; ++} ++ + /* + * Find a device specified by @devid or @uuid in the list of @fs_devices, or + * return NULL. +@@ -6812,31 +6841,25 @@ blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, + * If devid and uuid are both specified, the match must be exact, otherwise + * only devid is used. + */ +-struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices, +- u64 devid, u8 *uuid, u8 *fsid) ++struct btrfs_device *btrfs_find_device(const struct btrfs_fs_devices *fs_devices, ++ const struct btrfs_dev_lookup_args *args) + { + struct btrfs_device *device; + struct btrfs_fs_devices *seed_devs; + +- if (!fsid || !memcmp(fs_devices->metadata_uuid, fsid, BTRFS_FSID_SIZE)) { ++ if (dev_args_match_fs_devices(args, fs_devices)) { + list_for_each_entry(device, &fs_devices->devices, dev_list) { +- if (device->devid == devid && +- (!uuid || memcmp(device->uuid, uuid, +- BTRFS_UUID_SIZE) == 0)) ++ if (dev_args_match_device(args, device)) + return device; + } + } + + list_for_each_entry(seed_devs, &fs_devices->seed_list, seed_list) { +- if (!fsid || +- !memcmp(seed_devs->metadata_uuid, fsid, BTRFS_FSID_SIZE)) { +- list_for_each_entry(device, &seed_devs->devices, +- dev_list) { +- if (device->devid == devid && +- (!uuid || memcmp(device->uuid, uuid, +- BTRFS_UUID_SIZE) == 0)) +- return device; +- } ++ if (!dev_args_match_fs_devices(args, seed_devs)) ++ continue; ++ list_for_each_entry(device, &seed_devs->devices, dev_list) { ++ if (dev_args_match_device(args, device)) ++ return device; + } + } + +@@ -7002,6 +7025,7 @@ static void warn_32bit_meta_chunk(struct btrfs_fs_info *fs_info, + static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, + struct btrfs_chunk *chunk) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct btrfs_fs_info *fs_info = leaf->fs_info; + struct extent_map_tree *map_tree = &fs_info->mapping_tree; + struct map_lookup *map; +@@ -7079,11 +7103,12 @@ static int read_one_chunk(struct btrfs_key *key, struct extent_buffer *leaf, + map->stripes[i].physical = + btrfs_stripe_offset_nr(leaf, chunk, i); + devid = btrfs_stripe_devid_nr(leaf, chunk, i); ++ args.devid = devid; + read_extent_buffer(leaf, uuid, (unsigned long) + btrfs_stripe_dev_uuid_nr(chunk, i), + BTRFS_UUID_SIZE); +- map->stripes[i].dev = btrfs_find_device(fs_info->fs_devices, +- devid, uuid, NULL); ++ args.uuid = uuid; ++ map->stripes[i].dev = btrfs_find_device(fs_info->fs_devices, &args); + if (!map->stripes[i].dev && + !btrfs_test_opt(fs_info, DEGRADED)) { + free_extent_map(em); +@@ -7201,6 +7226,7 @@ static struct btrfs_fs_devices *open_seed_devices(struct btrfs_fs_info *fs_info, + static int read_one_dev(struct extent_buffer *leaf, + struct btrfs_dev_item *dev_item) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct btrfs_fs_info *fs_info = leaf->fs_info; + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + struct btrfs_device *device; +@@ -7209,11 +7235,13 @@ static int read_one_dev(struct extent_buffer *leaf, + u8 fs_uuid[BTRFS_FSID_SIZE]; + u8 dev_uuid[BTRFS_UUID_SIZE]; + +- devid = btrfs_device_id(leaf, dev_item); ++ devid = args.devid = btrfs_device_id(leaf, dev_item); + read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item), + BTRFS_UUID_SIZE); + read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item), + BTRFS_FSID_SIZE); ++ args.uuid = dev_uuid; ++ args.fsid = fs_uuid; + + if (memcmp(fs_uuid, fs_devices->metadata_uuid, BTRFS_FSID_SIZE)) { + fs_devices = open_seed_devices(fs_info, fs_uuid); +@@ -7221,8 +7249,7 @@ static int read_one_dev(struct extent_buffer *leaf, + return PTR_ERR(fs_devices); + } + +- device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid, +- fs_uuid); ++ device = btrfs_find_device(fs_info->fs_devices, &args); + if (!device) { + if (!btrfs_test_opt(fs_info, DEGRADED)) { + btrfs_report_missing_device(fs_info, devid, +@@ -7899,12 +7926,14 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev) + int btrfs_get_dev_stats(struct btrfs_fs_info *fs_info, + struct btrfs_ioctl_get_dev_stats *stats) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct btrfs_device *dev; + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; + int i; + + mutex_lock(&fs_devices->device_list_mutex); +- dev = btrfs_find_device(fs_info->fs_devices, stats->devid, NULL, NULL); ++ args.devid = stats->devid; ++ dev = btrfs_find_device(fs_info->fs_devices, &args); + mutex_unlock(&fs_devices->device_list_mutex); + + if (!dev) { +@@ -7980,6 +8009,7 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info, + u64 chunk_offset, u64 devid, + u64 physical_offset, u64 physical_len) + { ++ struct btrfs_dev_lookup_args args = { .devid = devid }; + struct extent_map_tree *em_tree = &fs_info->mapping_tree; + struct extent_map *em; + struct map_lookup *map; +@@ -8035,7 +8065,7 @@ static int verify_one_dev_extent(struct btrfs_fs_info *fs_info, + } + + /* Make sure no dev extent is beyond device boundary */ +- dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices, &args); + if (!dev) { + btrfs_err(fs_info, "failed to find devid %llu", devid); + ret = -EUCLEAN; +diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h +index d86a6f9f166c..f3b1380f45ad 100644 +--- a/fs/btrfs/volumes.h ++++ b/fs/btrfs/volumes.h +@@ -418,6 +418,22 @@ struct btrfs_balance_control { + struct btrfs_balance_progress stat; + }; + ++/* ++ * Search for a given device by the set parameters ++ */ ++struct btrfs_dev_lookup_args { ++ u64 devid; ++ u8 *uuid; ++ u8 *fsid; ++ bool missing; ++}; ++ ++/* We have to initialize to -1 because BTRFS_DEV_REPLACE_DEVID is 0 */ ++#define BTRFS_DEV_LOOKUP_ARGS_INIT { .devid = (u64)-1 } ++ ++#define BTRFS_DEV_LOOKUP_ARGS(name) \ ++ struct btrfs_dev_lookup_args name = BTRFS_DEV_LOOKUP_ARGS_INIT ++ + enum btrfs_map_op { + BTRFS_MAP_READ, + BTRFS_MAP_WRITE, +@@ -482,8 +498,8 @@ void __exit btrfs_cleanup_fs_uuids(void); + int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); + int btrfs_grow_device(struct btrfs_trans_handle *trans, + struct btrfs_device *device, u64 new_size); +-struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices, +- u64 devid, u8 *uuid, u8 *fsid); ++struct btrfs_device *btrfs_find_device(const struct btrfs_fs_devices *fs_devices, ++ const struct btrfs_dev_lookup_args *args); + int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); + int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *path); + int btrfs_balance(struct btrfs_fs_info *fs_info, +-- +2.35.1 + diff --git a/queue-5.15/btrfs-remove-device-item-and-update-super-block-in-t.patch b/queue-5.15/btrfs-remove-device-item-and-update-super-block-in-t.patch new file mode 100644 index 00000000000..da1cd0fedfd --- /dev/null +++ b/queue-5.15/btrfs-remove-device-item-and-update-super-block-in-t.patch @@ -0,0 +1,222 @@ +From f9299e270e8f21fbf7fc1ba5e0c240cebb10825c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Mar 2022 13:36:38 +0800 +Subject: btrfs: remove device item and update super block in the same + transaction +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Qu Wenruo + +[ Upstream commit bbac58698a55cc0a6f0c0d69a6dcd3f9f3134c11 ] + +[BUG] +There is a report that a btrfs has a bad super block num devices. + +This makes btrfs to reject the fs completely. + + BTRFS error (device sdd3): super_num_devices 3 mismatch with num_devices 2 found here + BTRFS error (device sdd3): failed to read chunk tree: -22 + BTRFS error (device sdd3): open_ctree failed + +[CAUSE] +During btrfs device removal, chunk tree and super block num devs are +updated in two different transactions: + + btrfs_rm_device() + |- btrfs_rm_dev_item(device) + | |- trans = btrfs_start_transaction() + | | Now we got transaction X + | | + | |- btrfs_del_item() + | | Now device item is removed from chunk tree + | | + | |- btrfs_commit_transaction() + | Transaction X got committed, super num devs untouched, + | but device item removed from chunk tree. + | (AKA, super num devs is already incorrect) + | + |- cur_devices->num_devices--; + |- cur_devices->total_devices--; + |- btrfs_set_super_num_devices() + All those operations are not in transaction X, thus it will + only be written back to disk in next transaction. + +So after the transaction X in btrfs_rm_dev_item() committed, but before +transaction X+1 (which can be minutes away), a power loss happen, then +we got the super num mismatch. + +[FIX] +Instead of starting and committing a transaction inside +btrfs_rm_dev_item(), start a transaction in side btrfs_rm_device() and +pass it to btrfs_rm_dev_item(). + +And only commit the transaction after everything is done. + +Reported-by: Luca Béla Palkovics +Link: https://lore.kernel.org/linux-btrfs/CA+8xDSpvdm_U0QLBAnrH=zqDq_cWCOH5TiV46CKmp3igr44okQ@mail.gmail.com/ +CC: stable@vger.kernel.org # 4.14+ +Reviewed-by: Anand Jain +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/volumes.c | 65 ++++++++++++++++++++-------------------------- + 1 file changed, 28 insertions(+), 37 deletions(-) + +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 3bd68f1b79e6..cec54c6e1cdd 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -1942,23 +1942,18 @@ static void update_dev_time(const char *device_path) + path_put(&path); + } + +-static int btrfs_rm_dev_item(struct btrfs_device *device) ++static int btrfs_rm_dev_item(struct btrfs_trans_handle *trans, ++ struct btrfs_device *device) + { + struct btrfs_root *root = device->fs_info->chunk_root; + int ret; + struct btrfs_path *path; + struct btrfs_key key; +- struct btrfs_trans_handle *trans; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + +- trans = btrfs_start_transaction(root, 0); +- if (IS_ERR(trans)) { +- btrfs_free_path(path); +- return PTR_ERR(trans); +- } + key.objectid = BTRFS_DEV_ITEMS_OBJECTID; + key.type = BTRFS_DEV_ITEM_KEY; + key.offset = device->devid; +@@ -1969,21 +1964,12 @@ static int btrfs_rm_dev_item(struct btrfs_device *device) + if (ret) { + if (ret > 0) + ret = -ENOENT; +- btrfs_abort_transaction(trans, ret); +- btrfs_end_transaction(trans); + goto out; + } + + ret = btrfs_del_item(trans, root, path); +- if (ret) { +- btrfs_abort_transaction(trans, ret); +- btrfs_end_transaction(trans); +- } +- + out: + btrfs_free_path(path); +- if (!ret) +- ret = btrfs_commit_transaction(trans); + return ret; + } + +@@ -2124,6 +2110,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, + struct btrfs_dev_lookup_args *args, + struct block_device **bdev, fmode_t *mode) + { ++ struct btrfs_trans_handle *trans; + struct btrfs_device *device; + struct btrfs_fs_devices *cur_devices; + struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; +@@ -2139,7 +2126,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, + + ret = btrfs_check_raid_min_devices(fs_info, num_devices - 1); + if (ret) +- goto out; ++ return ret; + + device = btrfs_find_device(fs_info->fs_devices, args); + if (!device) { +@@ -2147,27 +2134,22 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, + ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND; + else + ret = -ENOENT; +- goto out; ++ return ret; + } + + if (btrfs_pinned_by_swapfile(fs_info, device)) { + btrfs_warn_in_rcu(fs_info, + "cannot remove device %s (devid %llu) due to active swapfile", + rcu_str_deref(device->name), device->devid); +- ret = -ETXTBSY; +- goto out; ++ return -ETXTBSY; + } + +- if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) { +- ret = BTRFS_ERROR_DEV_TGT_REPLACE; +- goto out; +- } ++ if (test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) ++ return BTRFS_ERROR_DEV_TGT_REPLACE; + + if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) && +- fs_info->fs_devices->rw_devices == 1) { +- ret = BTRFS_ERROR_DEV_ONLY_WRITABLE; +- goto out; +- } ++ fs_info->fs_devices->rw_devices == 1) ++ return BTRFS_ERROR_DEV_ONLY_WRITABLE; + + if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) { + mutex_lock(&fs_info->chunk_mutex); +@@ -2182,14 +2164,22 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, + if (ret) + goto error_undo; + +- /* +- * TODO: the superblock still includes this device in its num_devices +- * counter although write_all_supers() is not locked out. This +- * could give a filesystem state which requires a degraded mount. +- */ +- ret = btrfs_rm_dev_item(device); +- if (ret) ++ trans = btrfs_start_transaction(fs_info->chunk_root, 0); ++ if (IS_ERR(trans)) { ++ ret = PTR_ERR(trans); + goto error_undo; ++ } ++ ++ ret = btrfs_rm_dev_item(trans, device); ++ if (ret) { ++ /* Any error in dev item removal is critical */ ++ btrfs_crit(fs_info, ++ "failed to remove device item for devid %llu: %d", ++ device->devid, ret); ++ btrfs_abort_transaction(trans, ret); ++ btrfs_end_transaction(trans); ++ return ret; ++ } + + clear_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); + btrfs_scrub_cancel_dev(device); +@@ -2264,7 +2254,8 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, + free_fs_devices(cur_devices); + } + +-out: ++ ret = btrfs_commit_transaction(trans); ++ + return ret; + + error_undo: +@@ -2276,7 +2267,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, + device->fs_devices->rw_devices++; + mutex_unlock(&fs_info->chunk_mutex); + } +- goto out; ++ return ret; + } + + void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_device *srcdev) +-- +2.35.1 + diff --git a/queue-5.15/btrfs-rename-btrfs_alloc_chunk-to-btrfs_create_chunk.patch b/queue-5.15/btrfs-rename-btrfs_alloc_chunk-to-btrfs_create_chunk.patch new file mode 100644 index 00000000000..0d538d4a381 --- /dev/null +++ b/queue-5.15/btrfs-rename-btrfs_alloc_chunk-to-btrfs_create_chunk.patch @@ -0,0 +1,142 @@ +From 60929c7175f80f919e5d93bcaea7a3a23650a1b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Aug 2021 13:41:19 +0300 +Subject: btrfs: rename btrfs_alloc_chunk to btrfs_create_chunk + +From: Nikolay Borisov + +[ Upstream commit f6f39f7a0add4e7fd120a709545b57586a1d0393 ] + +The user facing function used to allocate new chunks is +btrfs_chunk_alloc, unfortunately there is yet another similar sounding +function - btrfs_alloc_chunk. This creates confusion, especially since +the latter function can be considered "private" in the sense that it +implements the first stage of chunk creation and as such is called by +btrfs_chunk_alloc. + +To avoid the awkwardness that comes with having similarly named but +distinctly different in their purpose function rename btrfs_alloc_chunk +to btrfs_create_chunk, given that the main purpose of this function is +to orchestrate the whole process of allocating a chunk - reserving space +into devices, deciding on characteristics of the stripe size and +creating the in-memory structures. + +Reviewed-by: Filipe Manana +Reviewed-by: Anand Jain +Signed-off-by: Nikolay Borisov +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/block-group.c | 6 +++--- + fs/btrfs/volumes.c | 10 +++++----- + fs/btrfs/volumes.h | 2 +- + fs/btrfs/zoned.c | 2 +- + 4 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c +index 37418b183b07..aadc1203ad88 100644 +--- a/fs/btrfs/block-group.c ++++ b/fs/btrfs/block-group.c +@@ -3400,7 +3400,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags) + */ + check_system_chunk(trans, flags); + +- bg = btrfs_alloc_chunk(trans, flags); ++ bg = btrfs_create_chunk(trans, flags); + if (IS_ERR(bg)) { + ret = PTR_ERR(bg); + goto out; +@@ -3461,7 +3461,7 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, u64 flags) + const u64 sys_flags = btrfs_system_alloc_profile(trans->fs_info); + struct btrfs_block_group *sys_bg; + +- sys_bg = btrfs_alloc_chunk(trans, sys_flags); ++ sys_bg = btrfs_create_chunk(trans, sys_flags); + if (IS_ERR(sys_bg)) { + ret = PTR_ERR(sys_bg); + btrfs_abort_transaction(trans, ret); +@@ -3754,7 +3754,7 @@ void check_system_chunk(struct btrfs_trans_handle *trans, u64 type) + * could deadlock on an extent buffer since our caller may be + * COWing an extent buffer from the chunk btree. + */ +- bg = btrfs_alloc_chunk(trans, flags); ++ bg = btrfs_create_chunk(trans, flags); + if (IS_ERR(bg)) { + ret = PTR_ERR(bg); + } else if (!(type & BTRFS_BLOCK_GROUP_SYSTEM)) { +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 378e03a93e10..b75ce79a2540 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -3131,7 +3131,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset) + const u64 sys_flags = btrfs_system_alloc_profile(fs_info); + struct btrfs_block_group *sys_bg; + +- sys_bg = btrfs_alloc_chunk(trans, sys_flags); ++ sys_bg = btrfs_create_chunk(trans, sys_flags); + if (IS_ERR(sys_bg)) { + ret = PTR_ERR(sys_bg); + btrfs_abort_transaction(trans, ret); +@@ -5010,7 +5010,7 @@ static void check_raid1c34_incompat_flag(struct btrfs_fs_info *info, u64 type) + } + + /* +- * Structure used internally for __btrfs_alloc_chunk() function. ++ * Structure used internally for btrfs_create_chunk() function. + * Wraps needed parameters. + */ + struct alloc_chunk_ctl { +@@ -5414,7 +5414,7 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans, + return block_group; + } + +-struct btrfs_block_group *btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ++struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans, + u64 type) + { + struct btrfs_fs_info *info = trans->fs_info; +@@ -5615,12 +5615,12 @@ static noinline int init_first_rw_device(struct btrfs_trans_handle *trans) + */ + + alloc_profile = btrfs_metadata_alloc_profile(fs_info); +- meta_bg = btrfs_alloc_chunk(trans, alloc_profile); ++ meta_bg = btrfs_create_chunk(trans, alloc_profile); + if (IS_ERR(meta_bg)) + return PTR_ERR(meta_bg); + + alloc_profile = btrfs_system_alloc_profile(fs_info); +- sys_bg = btrfs_alloc_chunk(trans, alloc_profile); ++ sys_bg = btrfs_create_chunk(trans, alloc_profile); + if (IS_ERR(sys_bg)) + return PTR_ERR(sys_bg); + +diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h +index 4db10d071d67..d86a6f9f166c 100644 +--- a/fs/btrfs/volumes.h ++++ b/fs/btrfs/volumes.h +@@ -454,7 +454,7 @@ int btrfs_get_io_geometry(struct btrfs_fs_info *fs_info, struct extent_map *map, + struct btrfs_io_geometry *io_geom); + int btrfs_read_sys_array(struct btrfs_fs_info *fs_info); + int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info); +-struct btrfs_block_group *btrfs_alloc_chunk(struct btrfs_trans_handle *trans, ++struct btrfs_block_group *btrfs_create_chunk(struct btrfs_trans_handle *trans, + u64 type); + void btrfs_mapping_tree_free(struct extent_map_tree *tree); + blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, +diff --git a/fs/btrfs/zoned.c b/fs/btrfs/zoned.c +index 596b2148807d..3bc2f92cd197 100644 +--- a/fs/btrfs/zoned.c ++++ b/fs/btrfs/zoned.c +@@ -636,7 +636,7 @@ int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info) + + /* + * stripe_size is always aligned to BTRFS_STRIPE_LEN in +- * __btrfs_alloc_chunk(). Since we want stripe_len == zone_size, ++ * btrfs_create_chunk(). Since we want stripe_len == zone_size, + * check the alignment here. + */ + if (!IS_ALIGNED(zone_size, BTRFS_STRIPE_LEN)) { +-- +2.35.1 + diff --git a/queue-5.15/btrfs-use-btrfs_get_dev_args_from_path-in-dev-remova.patch b/queue-5.15/btrfs-use-btrfs_get_dev_args_from_path-in-dev-remova.patch new file mode 100644 index 00000000000..1b784f33d55 --- /dev/null +++ b/queue-5.15/btrfs-use-btrfs_get_dev_args_from_path-in-dev-remova.patch @@ -0,0 +1,331 @@ +From 67dd3976212537f741bf75ed1efd707ea2ec78d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 5 Oct 2021 16:12:44 -0400 +Subject: btrfs: use btrfs_get_dev_args_from_path in dev removal ioctls + +From: Josef Bacik + +[ Upstream commit 1a15eb724aaef8656f8cc01d9355797cfe7c618e ] + +For device removal and replace we call btrfs_find_device_by_devspec, +which if we give it a device path and nothing else will call +btrfs_get_dev_args_from_path, which opens the block device and reads the +super block and then looks up our device based on that. + +However at this point we're holding the sb write "lock", so reading the +block device pulls in the dependency of ->open_mutex, which produces the +following lockdep splat + +====================================================== +WARNING: possible circular locking dependency detected +5.14.0-rc2+ #405 Not tainted +------------------------------------------------------ +losetup/11576 is trying to acquire lock: +ffff9bbe8cded938 ((wq_completion)loop0){+.+.}-{0:0}, at: flush_workqueue+0x67/0x5e0 + +but task is already holding lock: +ffff9bbe88e4fc68 (&lo->lo_mutex){+.+.}-{3:3}, at: __loop_clr_fd+0x41/0x660 [loop] + +which lock already depends on the new lock. + +the existing dependency chain (in reverse order) is: + +-> #4 (&lo->lo_mutex){+.+.}-{3:3}: + __mutex_lock+0x7d/0x750 + lo_open+0x28/0x60 [loop] + blkdev_get_whole+0x25/0xf0 + blkdev_get_by_dev.part.0+0x168/0x3c0 + blkdev_open+0xd2/0xe0 + do_dentry_open+0x161/0x390 + path_openat+0x3cc/0xa20 + do_filp_open+0x96/0x120 + do_sys_openat2+0x7b/0x130 + __x64_sys_openat+0x46/0x70 + do_syscall_64+0x38/0x90 + entry_SYSCALL_64_after_hwframe+0x44/0xae + +-> #3 (&disk->open_mutex){+.+.}-{3:3}: + __mutex_lock+0x7d/0x750 + blkdev_get_by_dev.part.0+0x56/0x3c0 + blkdev_get_by_path+0x98/0xa0 + btrfs_get_bdev_and_sb+0x1b/0xb0 + btrfs_find_device_by_devspec+0x12b/0x1c0 + btrfs_rm_device+0x127/0x610 + btrfs_ioctl+0x2a31/0x2e70 + __x64_sys_ioctl+0x80/0xb0 + do_syscall_64+0x38/0x90 + entry_SYSCALL_64_after_hwframe+0x44/0xae + +-> #2 (sb_writers#12){.+.+}-{0:0}: + lo_write_bvec+0xc2/0x240 [loop] + loop_process_work+0x238/0xd00 [loop] + process_one_work+0x26b/0x560 + worker_thread+0x55/0x3c0 + kthread+0x140/0x160 + ret_from_fork+0x1f/0x30 + +-> #1 ((work_completion)(&lo->rootcg_work)){+.+.}-{0:0}: + process_one_work+0x245/0x560 + worker_thread+0x55/0x3c0 + kthread+0x140/0x160 + ret_from_fork+0x1f/0x30 + +-> #0 ((wq_completion)loop0){+.+.}-{0:0}: + __lock_acquire+0x10ea/0x1d90 + lock_acquire+0xb5/0x2b0 + flush_workqueue+0x91/0x5e0 + drain_workqueue+0xa0/0x110 + destroy_workqueue+0x36/0x250 + __loop_clr_fd+0x9a/0x660 [loop] + block_ioctl+0x3f/0x50 + __x64_sys_ioctl+0x80/0xb0 + do_syscall_64+0x38/0x90 + entry_SYSCALL_64_after_hwframe+0x44/0xae + +other info that might help us debug this: + +Chain exists of: + (wq_completion)loop0 --> &disk->open_mutex --> &lo->lo_mutex + + Possible unsafe locking scenario: + + CPU0 CPU1 + ---- ---- + lock(&lo->lo_mutex); + lock(&disk->open_mutex); + lock(&lo->lo_mutex); + lock((wq_completion)loop0); + + *** DEADLOCK *** + +1 lock held by losetup/11576: + #0: ffff9bbe88e4fc68 (&lo->lo_mutex){+.+.}-{3:3}, at: __loop_clr_fd+0x41/0x660 [loop] + +stack backtrace: +CPU: 0 PID: 11576 Comm: losetup Not tainted 5.14.0-rc2+ #405 +Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-2.fc32 04/01/2014 +Call Trace: + dump_stack_lvl+0x57/0x72 + check_noncircular+0xcf/0xf0 + ? stack_trace_save+0x3b/0x50 + __lock_acquire+0x10ea/0x1d90 + lock_acquire+0xb5/0x2b0 + ? flush_workqueue+0x67/0x5e0 + ? lockdep_init_map_type+0x47/0x220 + flush_workqueue+0x91/0x5e0 + ? flush_workqueue+0x67/0x5e0 + ? verify_cpu+0xf0/0x100 + drain_workqueue+0xa0/0x110 + destroy_workqueue+0x36/0x250 + __loop_clr_fd+0x9a/0x660 [loop] + ? blkdev_ioctl+0x8d/0x2a0 + block_ioctl+0x3f/0x50 + __x64_sys_ioctl+0x80/0xb0 + do_syscall_64+0x38/0x90 + entry_SYSCALL_64_after_hwframe+0x44/0xae +RIP: 0033:0x7f31b02404cb + +Instead what we want to do is populate our device lookup args before we +grab any locks, and then pass these args into btrfs_rm_device(). From +there we can find the device and do the appropriate removal. + +Suggested-by: Anand Jain +Reviewed-by: Anand Jain +Signed-off-by: Josef Bacik +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/ioctl.c | 67 +++++++++++++++++++++++++++------------------- + fs/btrfs/volumes.c | 15 +++++------ + fs/btrfs/volumes.h | 2 +- + 3 files changed, 48 insertions(+), 36 deletions(-) + +diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c +index 4951a2ab88dd..4317720a29e8 100644 +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -3218,6 +3218,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg) + + static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct inode *inode = file_inode(file); + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_ioctl_vol_args_v2 *vol_args; +@@ -3229,35 +3230,39 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + +- ret = mnt_want_write_file(file); +- if (ret) +- return ret; +- + vol_args = memdup_user(arg, sizeof(*vol_args)); + if (IS_ERR(vol_args)) { + ret = PTR_ERR(vol_args); +- goto err_drop; ++ goto out; + } + + if (vol_args->flags & ~BTRFS_DEVICE_REMOVE_ARGS_MASK) { + ret = -EOPNOTSUPP; + goto out; + } ++ + vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; +- if (!(vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) && +- strcmp("cancel", vol_args->name) == 0) ++ if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) { ++ args.devid = vol_args->devid; ++ } else if (!strcmp("cancel", vol_args->name)) { + cancel = true; ++ } else { ++ ret = btrfs_get_dev_args_from_path(fs_info, &args, vol_args->name); ++ if (ret) ++ goto out; ++ } ++ ++ ret = mnt_want_write_file(file); ++ if (ret) ++ goto out; + + ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE, + cancel); + if (ret) +- goto out; +- /* Exclusive operation is now claimed */ ++ goto err_drop; + +- if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) +- ret = btrfs_rm_device(fs_info, NULL, vol_args->devid, &bdev, &mode); +- else +- ret = btrfs_rm_device(fs_info, vol_args->name, 0, &bdev, &mode); ++ /* Exclusive operation is now claimed */ ++ ret = btrfs_rm_device(fs_info, &args, &bdev, &mode); + + btrfs_exclop_finish(fs_info); + +@@ -3269,17 +3274,19 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) + btrfs_info(fs_info, "device deleted: %s", + vol_args->name); + } +-out: +- kfree(vol_args); + err_drop: + mnt_drop_write_file(file); + if (bdev) + blkdev_put(bdev, mode); ++out: ++ btrfs_put_dev_args_from_path(&args); ++ kfree(vol_args); + return ret; + } + + static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) + { ++ BTRFS_DEV_LOOKUP_ARGS(args); + struct inode *inode = file_inode(file); + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_ioctl_vol_args *vol_args; +@@ -3291,32 +3298,38 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + +- ret = mnt_want_write_file(file); +- if (ret) +- return ret; +- + vol_args = memdup_user(arg, sizeof(*vol_args)); +- if (IS_ERR(vol_args)) { +- ret = PTR_ERR(vol_args); +- goto out_drop_write; +- } ++ if (IS_ERR(vol_args)) ++ return PTR_ERR(vol_args); ++ + vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; +- cancel = (strcmp("cancel", vol_args->name) == 0); ++ if (!strcmp("cancel", vol_args->name)) { ++ cancel = true; ++ } else { ++ ret = btrfs_get_dev_args_from_path(fs_info, &args, vol_args->name); ++ if (ret) ++ goto out; ++ } ++ ++ ret = mnt_want_write_file(file); ++ if (ret) ++ goto out; + + ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_DEV_REMOVE, + cancel); + if (ret == 0) { +- ret = btrfs_rm_device(fs_info, vol_args->name, 0, &bdev, &mode); ++ ret = btrfs_rm_device(fs_info, &args, &bdev, &mode); + if (!ret) + btrfs_info(fs_info, "disk deleted %s", vol_args->name); + btrfs_exclop_finish(fs_info); + } + +- kfree(vol_args); +-out_drop_write: + mnt_drop_write_file(file); + if (bdev) + blkdev_put(bdev, mode); ++out: ++ btrfs_put_dev_args_from_path(&args); ++ kfree(vol_args); + return ret; + } + +diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c +index 8d09e6d442b2..3bd68f1b79e6 100644 +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -2120,8 +2120,9 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info, + update_dev_time(device_path); + } + +-int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, +- u64 devid, struct block_device **bdev, fmode_t *mode) ++int btrfs_rm_device(struct btrfs_fs_info *fs_info, ++ struct btrfs_dev_lookup_args *args, ++ struct block_device **bdev, fmode_t *mode) + { + struct btrfs_device *device; + struct btrfs_fs_devices *cur_devices; +@@ -2140,14 +2141,12 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path, + if (ret) + goto out; + +- device = btrfs_find_device_by_devspec(fs_info, devid, device_path); +- +- if (IS_ERR(device)) { +- if (PTR_ERR(device) == -ENOENT && +- device_path && strcmp(device_path, "missing") == 0) ++ device = btrfs_find_device(fs_info->fs_devices, args); ++ if (!device) { ++ if (args->missing) + ret = BTRFS_ERROR_DEV_MISSING_NOT_FOUND; + else +- ret = PTR_ERR(device); ++ ret = -ENOENT; + goto out; + } + +diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h +index d1df03f77e29..30288b728bbb 100644 +--- a/fs/btrfs/volumes.h ++++ b/fs/btrfs/volumes.h +@@ -496,7 +496,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, + void btrfs_put_dev_args_from_path(struct btrfs_dev_lookup_args *args); + void btrfs_free_device(struct btrfs_device *device); + int btrfs_rm_device(struct btrfs_fs_info *fs_info, +- const char *device_path, u64 devid, ++ struct btrfs_dev_lookup_args *args, + struct block_device **bdev, fmode_t *mode); + void __exit btrfs_cleanup_fs_uuids(void); + int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); +-- +2.35.1 + diff --git a/queue-5.15/btrfs-zoned-encapsulate-inode-locking-for-zoned-relo.patch b/queue-5.15/btrfs-zoned-encapsulate-inode-locking-for-zoned-relo.patch new file mode 100644 index 00000000000..6aac13d311f --- /dev/null +++ b/queue-5.15/btrfs-zoned-encapsulate-inode-locking-for-zoned-relo.patch @@ -0,0 +1,88 @@ +From a32dd92cd015cd2acfe3895afc45c4ea73c72d2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 06:28:34 -0800 +Subject: btrfs: zoned: encapsulate inode locking for zoned relocation + +From: Johannes Thumshirn + +[ Upstream commit 869f4cdc73f9378986755030c684c011f0b71517 ] + +Encapsulate the inode lock needed for serializing the data relocation +writes on a zoned filesystem into a helper. + +This streamlines the code reading flow and hides special casing for +zoned filesystems. + +Reviewed-by: Josef Bacik +Signed-off-by: Johannes Thumshirn +Reviewed-by: David Sterba +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/extent_io.c | 8 ++------ + fs/btrfs/zoned.h | 17 +++++++++++++++++ + 2 files changed, 19 insertions(+), 6 deletions(-) + +diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c +index 6dd375ed6e3d..059bd0753e27 100644 +--- a/fs/btrfs/extent_io.c ++++ b/fs/btrfs/extent_io.c +@@ -5139,8 +5139,6 @@ int extent_writepages(struct address_space *mapping, + struct writeback_control *wbc) + { + struct inode *inode = mapping->host; +- const bool data_reloc = btrfs_is_data_reloc_root(BTRFS_I(inode)->root); +- const bool zoned = btrfs_is_zoned(BTRFS_I(inode)->root->fs_info); + int ret = 0; + struct extent_page_data epd = { + .bio_ctrl = { 0 }, +@@ -5152,11 +5150,9 @@ int extent_writepages(struct address_space *mapping, + * Allow only a single thread to do the reloc work in zoned mode to + * protect the write pointer updates. + */ +- if (data_reloc && zoned) +- btrfs_inode_lock(inode, 0); ++ btrfs_zoned_data_reloc_lock(BTRFS_I(inode)); + ret = extent_write_cache_pages(mapping, wbc, &epd); +- if (data_reloc && zoned) +- btrfs_inode_unlock(inode, 0); ++ btrfs_zoned_data_reloc_unlock(BTRFS_I(inode)); + ASSERT(ret <= 0); + if (ret < 0) { + end_write_bio(&epd, ret); +diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h +index 813aa3cddc11..d680c3ee918a 100644 +--- a/fs/btrfs/zoned.h ++++ b/fs/btrfs/zoned.h +@@ -8,6 +8,7 @@ + #include "volumes.h" + #include "disk-io.h" + #include "block-group.h" ++#include "btrfs_inode.h" + + /* + * Block groups with more than this value (percents) of unusable space will be +@@ -324,4 +325,20 @@ static inline void btrfs_clear_treelog_bg(struct btrfs_block_group *bg) + spin_unlock(&fs_info->treelog_bg_lock); + } + ++static inline void btrfs_zoned_data_reloc_lock(struct btrfs_inode *inode) ++{ ++ struct btrfs_root *root = inode->root; ++ ++ if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info)) ++ btrfs_inode_lock(&inode->vfs_inode, 0); ++} ++ ++static inline void btrfs_zoned_data_reloc_unlock(struct btrfs_inode *inode) ++{ ++ struct btrfs_root *root = inode->root; ++ ++ if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info)) ++ btrfs_inode_unlock(&inode->vfs_inode, 0); ++} ++ + #endif +-- +2.35.1 + diff --git a/queue-5.15/btrfs-zoned-use-dedicated-lock-for-data-relocation.patch b/queue-5.15/btrfs-zoned-use-dedicated-lock-for-data-relocation.patch new file mode 100644 index 00000000000..f2adc79bdab --- /dev/null +++ b/queue-5.15/btrfs-zoned-use-dedicated-lock-for-data-relocation.patch @@ -0,0 +1,107 @@ +From 69391698b4b697b1167e7438b0e53ed3f61f460d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 18 Apr 2022 16:15:03 +0900 +Subject: btrfs: zoned: use dedicated lock for data relocation + +From: Naohiro Aota + +[ Upstream commit 5f0addf7b89085f8e0a2593faa419d6111612b9b ] + +Currently, we use btrfs_inode_{lock,unlock}() to grant an exclusive +writeback of the relocation data inode in +btrfs_zoned_data_reloc_{lock,unlock}(). However, that can cause a deadlock +in the following path. + +Thread A takes btrfs_inode_lock() and waits for metadata reservation by +e.g, waiting for writeback: + +prealloc_file_extent_cluster() + - btrfs_inode_lock(&inode->vfs_inode, 0); + - btrfs_prealloc_file_range() + ... + - btrfs_replace_file_extents() + - btrfs_start_transaction + ... + - btrfs_reserve_metadata_bytes() + +Thread B (e.g, doing a writeback work) needs to wait for the inode lock to +continue writeback process: + +do_writepages + - btrfs_writepages + - extent_writpages + - btrfs_zoned_data_reloc_lock(BTRFS_I(inode)); + - btrfs_inode_lock() + +The deadlock is caused by relying on the vfs_inode's lock. By using it, we +introduced unnecessary exclusion of writeback and +btrfs_prealloc_file_range(). Also, the lock at this point is useless as we +don't have any dirty pages in the inode yet. + +Introduce fs_info->zoned_data_reloc_io_lock and use it for the exclusive +writeback. + +Fixes: 35156d852762 ("btrfs: zoned: only allow one process to add pages to a relocation inode") +CC: stable@vger.kernel.org # 5.16.x: 869f4cdc73f9: btrfs: zoned: encapsulate inode locking for zoned relocation +CC: stable@vger.kernel.org # 5.16.x +CC: stable@vger.kernel.org # 5.17 +Cc: Johannes Thumshirn +Reviewed-by: Johannes Thumshirn +Signed-off-by: Naohiro Aota +Signed-off-by: David Sterba +Signed-off-by: Sasha Levin +--- + fs/btrfs/ctree.h | 1 + + fs/btrfs/disk-io.c | 1 + + fs/btrfs/zoned.h | 4 ++-- + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h +index cc72d8981c47..d1838de0b39c 100644 +--- a/fs/btrfs/ctree.h ++++ b/fs/btrfs/ctree.h +@@ -1027,6 +1027,7 @@ struct btrfs_fs_info { + */ + spinlock_t relocation_bg_lock; + u64 data_reloc_bg; ++ struct mutex zoned_data_reloc_io_lock; + + #ifdef CONFIG_BTRFS_FS_REF_VERIFY + spinlock_t ref_verify_lock; +diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c +index 233d894f6feb..909d19656316 100644 +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -2914,6 +2914,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info) + mutex_init(&fs_info->reloc_mutex); + mutex_init(&fs_info->delalloc_root_mutex); + mutex_init(&fs_info->zoned_meta_io_lock); ++ mutex_init(&fs_info->zoned_data_reloc_io_lock); + seqlock_init(&fs_info->profiles_lock); + + INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); +diff --git a/fs/btrfs/zoned.h b/fs/btrfs/zoned.h +index d680c3ee918a..3a826f7c2040 100644 +--- a/fs/btrfs/zoned.h ++++ b/fs/btrfs/zoned.h +@@ -330,7 +330,7 @@ static inline void btrfs_zoned_data_reloc_lock(struct btrfs_inode *inode) + struct btrfs_root *root = inode->root; + + if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info)) +- btrfs_inode_lock(&inode->vfs_inode, 0); ++ mutex_lock(&root->fs_info->zoned_data_reloc_io_lock); + } + + static inline void btrfs_zoned_data_reloc_unlock(struct btrfs_inode *inode) +@@ -338,7 +338,7 @@ static inline void btrfs_zoned_data_reloc_unlock(struct btrfs_inode *inode) + struct btrfs_root *root = inode->root; + + if (btrfs_is_data_reloc_root(root) && btrfs_is_zoned(root->fs_info)) +- btrfs_inode_unlock(&inode->vfs_inode, 0); ++ mutex_unlock(&root->fs_info->zoned_data_reloc_io_lock); + } + + #endif +-- +2.35.1 + diff --git a/queue-5.15/bus-mhi-core-use-correctly-sized-arguments-for-bit-f.patch b/queue-5.15/bus-mhi-core-use-correctly-sized-arguments-for-bit-f.patch new file mode 100644 index 00000000000..5ba19687cb1 --- /dev/null +++ b/queue-5.15/bus-mhi-core-use-correctly-sized-arguments-for-bit-f.patch @@ -0,0 +1,67 @@ +From b919a1877dfb655cdaa1c2615ef7495b3c299833 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Dec 2021 13:42:26 +0530 +Subject: bus: mhi: core: Use correctly sized arguments for bit field + +From: Kees Cook + +[ Upstream commit 5a717e93239fc373a314e03e45c43b62ebea1b26 ] + +The find.h APIs are designed to be used only on unsigned long arguments. +This can technically result in a over-read, but it is harmless in this +case. Regardless, fix it to avoid the warning seen under -Warray-bounds, +which we'd like to enable globally: + +In file included from ./include/linux/bitmap.h:9, + from ./include/linux/cpumask.h:12, + from ./arch/x86/include/asm/cpumask.h:5, + from ./arch/x86/include/asm/msr.h:11, + from ./arch/x86/include/asm/processor.h:22, + from ./arch/x86/include/asm/cpufeature.h:5, + from ./arch/x86/include/asm/thread_info.h:53, + from ./include/linux/thread_info.h:60, + from ./arch/x86/include/asm/preempt.h:7, + from ./include/linux/preempt.h:78, + from ./include/linux/spinlock.h:55, + from ./include/linux/wait.h:9, + from ./include/linux/wait_bit.h:8, + from ./include/linux/fs.h:6, + from ./include/linux/debugfs.h:15, + from drivers/bus/mhi/core/init.c:7: +drivers/bus/mhi/core/init.c: In function 'to_mhi_pm_state_str': +./include/linux/find.h:187:37: warning: array subscript 'long unsigned int[0]' is partly outside array bounds of 'enum mhi_pm_state[1]' [-Warray-bounds] + 187 | unsigned long val = *addr & GENMASK(size - 1, 0); + | ^~~~~ +drivers/bus/mhi/core/init.c:80:51: note: while referencing 'state' + 80 | const char *to_mhi_pm_state_str(enum mhi_pm_state state) + | ~~~~~~~~~~~~~~~~~~^~~~~ + +Link: https://lore.kernel.org/r/20211215232446.2069794-1-keescook@chromium.org +[mani: changed the variable name "bits" to "pm_state"] +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Kees Cook +Signed-off-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20211216081227.237749-10-manivannan.sadhasivam@linaro.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/core/init.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c +index 4183945fc2c4..c0187367ae75 100644 +--- a/drivers/bus/mhi/core/init.c ++++ b/drivers/bus/mhi/core/init.c +@@ -79,7 +79,8 @@ static const char * const mhi_pm_state_str[] = { + + const char *to_mhi_pm_state_str(enum mhi_pm_state state) + { +- int index = find_last_bit((unsigned long *)&state, 32); ++ unsigned long pm_state = state; ++ int index = find_last_bit(&pm_state, 32); + + if (index >= ARRAY_SIZE(mhi_pm_state_str)) + return "Invalid State"; +-- +2.35.1 + diff --git a/queue-5.15/bus-mhi-fix-pm_state-conversion-to-string.patch b/queue-5.15/bus-mhi-fix-pm_state-conversion-to-string.patch new file mode 100644 index 00000000000..4ef164bd0f3 --- /dev/null +++ b/queue-5.15/bus-mhi-fix-pm_state-conversion-to-string.patch @@ -0,0 +1,75 @@ +From b459a1a4993d2711f8547107174c59a767db2fc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Mar 2022 21:33:00 +0530 +Subject: bus: mhi: Fix pm_state conversion to string + +From: Paul Davey + +[ Upstream commit 64f93a9a27c1970fa8ee5ffc5a6ae2bda477ec5b ] + +On big endian architectures the mhi debugfs files which report pm state +give "Invalid State" for all states. This is caused by using +find_last_bit which takes an unsigned long* while the state is passed in +as an enum mhi_pm_state which will be of int size. + +Fix by using __fls to pass the value of state instead of find_last_bit. + +Also the current API expects "mhi_pm_state" enumerator as the function +argument but the function only works with bitmasks. So as Alex suggested, +let's change the argument to u32 to avoid confusion. + +Fixes: a6e2e3522f29 ("bus: mhi: core: Add support for PM state transitions") +Cc: stable@vger.kernel.org +[mani: changed the function argument to u32] +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Hemant Kumar +Reviewed-by: Alex Elder +Signed-off-by: Paul Davey +Signed-off-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20220301160308.107452-3-manivannan.sadhasivam@linaro.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/core/init.c | 10 ++++++---- + drivers/bus/mhi/core/internal.h | 2 +- + 2 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c +index c0187367ae75..d8787aaa176b 100644 +--- a/drivers/bus/mhi/core/init.c ++++ b/drivers/bus/mhi/core/init.c +@@ -77,12 +77,14 @@ static const char * const mhi_pm_state_str[] = { + [MHI_PM_STATE_LD_ERR_FATAL_DETECT] = "Linkdown or Error Fatal Detect", + }; + +-const char *to_mhi_pm_state_str(enum mhi_pm_state state) ++const char *to_mhi_pm_state_str(u32 state) + { +- unsigned long pm_state = state; +- int index = find_last_bit(&pm_state, 32); ++ int index; + +- if (index >= ARRAY_SIZE(mhi_pm_state_str)) ++ if (state) ++ index = __fls(state); ++ ++ if (!state || index >= ARRAY_SIZE(mhi_pm_state_str)) + return "Invalid State"; + + return mhi_pm_state_str[index]; +diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h +index c02c4d48b744..71f181402be9 100644 +--- a/drivers/bus/mhi/core/internal.h ++++ b/drivers/bus/mhi/core/internal.h +@@ -622,7 +622,7 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl, + enum mhi_pm_state __must_check mhi_tryset_pm_state( + struct mhi_controller *mhi_cntrl, + enum mhi_pm_state state); +-const char *to_mhi_pm_state_str(enum mhi_pm_state state); ++const char *to_mhi_pm_state_str(u32 state); + int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl, + enum dev_st_transition state); + void mhi_pm_st_worker(struct work_struct *work); +-- +2.35.1 + diff --git a/queue-5.15/clk-renesas-r9a07g044-update-multiplier-and-divider-.patch b/queue-5.15/clk-renesas-r9a07g044-update-multiplier-and-divider-.patch new file mode 100644 index 00000000000..a70651808b4 --- /dev/null +++ b/queue-5.15/clk-renesas-r9a07g044-update-multiplier-and-divider-.patch @@ -0,0 +1,45 @@ +From 8923d15e9fb7c424931d2dc97a215643e86182ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Dec 2021 09:32:23 +0000 +Subject: clk: renesas: r9a07g044: Update multiplier and divider values for + PLL2/3 + +From: Lad Prabhakar + +[ Upstream commit b289cdecc7c3e25e001cde260c882e4d9a8b0772 ] + +As per the HW manual (Rev.1.00 Sep, 2021) PLL2 and PLL3 should be +1600 MHz, but with current multiplier and divider values this resulted +to 1596 MHz. + +This patch updates the multiplier and divider values for PLL2 and PLL3 +so that we get the exact (1600 MHz) values. + +Fixes: 17f0ff3d49ff1 ("clk: renesas: Add support for R9A07G044 SoC") +Suggested-by: Biju Das +Signed-off-by: Lad Prabhakar +Link: https://lore.kernel.org/r/20211223093223.4725-1-prabhakar.mahadev-lad.rj@bp.renesas.com +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sasha Levin +--- + drivers/clk/renesas/r9a07g044-cpg.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c +index 1490446985e2..61609eddf7d0 100644 +--- a/drivers/clk/renesas/r9a07g044-cpg.c ++++ b/drivers/clk/renesas/r9a07g044-cpg.c +@@ -61,8 +61,8 @@ static const struct cpg_core_clk r9a07g044_core_clks[] __initconst = { + DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1), + DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000), + DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)), +- DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 133, 2), +- DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 133, 2), ++ DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3), ++ DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3), + + DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2), + DEF_FIXED(".pll2_div16", CLK_PLL2_DIV16, CLK_PLL2, 1, 16), +-- +2.35.1 + diff --git a/queue-5.15/compiler-attributes-add-__alloc_size-for-better-boun.patch b/queue-5.15/compiler-attributes-add-__alloc_size-for-better-boun.patch new file mode 100644 index 00000000000..fb2c8bafc9c --- /dev/null +++ b/queue-5.15/compiler-attributes-add-__alloc_size-for-better-boun.patch @@ -0,0 +1,206 @@ +From 22cf5e03b57d30063ad34bb3e6acec618bd4f84f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Nov 2021 13:36:19 -0700 +Subject: Compiler Attributes: add __alloc_size() for better bounds checking + +From: Kees Cook + +[ Upstream commit 86cffecdeaa278444870c8745ab166a65865dbf0 ] + +GCC and Clang can use the "alloc_size" attribute to better inform the +results of __builtin_object_size() (for compile-time constant values). +Clang can additionally use alloc_size to inform the results of +__builtin_dynamic_object_size() (for run-time values). + +Because GCC sees the frequent use of struct_size() as an allocator size +argument, and notices it can return SIZE_MAX (the overflow indication), +it complains about these call sites overflowing (since SIZE_MAX is +greater than the default -Walloc-size-larger-than=PTRDIFF_MAX). This +isn't helpful since we already know a SIZE_MAX will be caught at +run-time (this was an intentional design). To deal with this, we must +disable this check as it is both a false positive and redundant. (Clang +does not have this warning option.) + +Unfortunately, just checking the -Wno-alloc-size-larger-than is not +sufficient to make the __alloc_size attribute behave correctly under +older GCC versions. The attribute itself must be disabled in those +situations too, as there appears to be no way to reliably silence the +SIZE_MAX constant expression cases for GCC versions less than 9.1: + + In file included from ./include/linux/resource_ext.h:11, + from ./include/linux/pci.h:40, + from drivers/net/ethernet/intel/ixgbe/ixgbe.h:9, + from drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c:4: + In function 'kmalloc_node', + inlined from 'ixgbe_alloc_q_vector' at ./include/linux/slab.h:743:9: + ./include/linux/slab.h:618:9: error: argument 1 value '18446744073709551615' exceeds maximum object size 9223372036854775807 [-Werror=alloc-size-larger-than=] + return __kmalloc_node(size, flags, node); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ./include/linux/slab.h: In function 'ixgbe_alloc_q_vector': + ./include/linux/slab.h:455:7: note: in a call to allocation function '__kmalloc_node' declared here + void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_slab_alignment __malloc; + ^~~~~~~~~~~~~~ + +Specifically: + '-Wno-alloc-size-larger-than' is not correctly handled by GCC < 9.1 + https://godbolt.org/z/hqsfG7q84 (doesn't disable) + https://godbolt.org/z/P9jdrPTYh (doesn't admit to not knowing about option) + https://godbolt.org/z/465TPMWKb (only warns when other warnings appear) + + '-Walloc-size-larger-than=18446744073709551615' is not handled by GCC < 8.2 + https://godbolt.org/z/73hh1EPxz (ignores numeric value) + +Since anything marked with __alloc_size would also qualify for marking +with __malloc, just include __malloc along with it to avoid redundant +markings. (Suggested by Linus Torvalds.) + +Finally, make sure checkpatch.pl doesn't get confused about finding the +__alloc_size attribute on functions. (Thanks to Joe Perches.) + +Link: https://lkml.kernel.org/r/20210930222704.2631604-3-keescook@chromium.org +Signed-off-by: Kees Cook +Tested-by: Randy Dunlap +Cc: Andy Whitcroft +Cc: Christoph Lameter +Cc: Daniel Micay +Cc: David Rientjes +Cc: Dennis Zhou +Cc: Dwaipayan Ray +Cc: Joe Perches +Cc: Joonsoo Kim +Cc: Lukas Bulwahn +Cc: Pekka Enberg +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Alexandre Bounine +Cc: Gustavo A. R. Silva +Cc: Ira Weiny +Cc: Jing Xiangfeng +Cc: John Hubbard +Cc: kernel test robot +Cc: Matt Porter +Cc: Miguel Ojeda +Cc: Nathan Chancellor +Cc: Nick Desaulniers +Cc: Souptick Joarder +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + Makefile | 15 +++++++++++++++ + include/linux/compiler-gcc.h | 8 ++++++++ + include/linux/compiler_attributes.h | 10 ++++++++++ + include/linux/compiler_types.h | 12 ++++++++++++ + scripts/checkpatch.pl | 3 ++- + 5 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/Makefile b/Makefile +index c7750d260a55..397fb08d17f2 100644 +--- a/Makefile ++++ b/Makefile +@@ -1011,6 +1011,21 @@ ifdef CONFIG_CC_IS_GCC + KBUILD_CFLAGS += -Wno-maybe-uninitialized + endif + ++ifdef CONFIG_CC_IS_GCC ++# The allocators already balk at large sizes, so silence the compiler ++# warnings for bounds checks involving those possible values. While ++# -Wno-alloc-size-larger-than would normally be used here, earlier versions ++# of gcc (<9.1) weirdly don't handle the option correctly when _other_ ++# warnings are produced (?!). Using -Walloc-size-larger-than=SIZE_MAX ++# doesn't work (as it is documented to), silently resolving to "0" prior to ++# version 9.1 (and producing an error more recently). Numeric values larger ++# than PTRDIFF_MAX also don't work prior to version 9.1, which are silently ++# ignored, continuing to default to PTRDIFF_MAX. So, left with no other ++# choice, we must perform a versioned check to disable this warning. ++# https://lore.kernel.org/lkml/20210824115859.187f272f@canb.auug.org.au ++KBUILD_CFLAGS += $(call cc-ifversion, -ge, 0901, -Wno-alloc-size-larger-than) ++endif ++ + # disable invalid "can't wrap" optimizations for signed / pointers + KBUILD_CFLAGS += -fno-strict-overflow + +diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h +index bd2b881c6b63..b9d5f9c373a0 100644 +--- a/include/linux/compiler-gcc.h ++++ b/include/linux/compiler-gcc.h +@@ -144,3 +144,11 @@ + #else + #define __diag_GCC_8(s) + #endif ++ ++/* ++ * Prior to 9.1, -Wno-alloc-size-larger-than (and therefore the "alloc_size" ++ * attribute) do not work, and must be disabled. ++ */ ++#if GCC_VERSION < 90100 ++#undef __alloc_size__ ++#endif +diff --git a/include/linux/compiler_attributes.h b/include/linux/compiler_attributes.h +index e6ec63403965..3de06a8fae73 100644 +--- a/include/linux/compiler_attributes.h ++++ b/include/linux/compiler_attributes.h +@@ -33,6 +33,15 @@ + #define __aligned(x) __attribute__((__aligned__(x))) + #define __aligned_largest __attribute__((__aligned__)) + ++/* ++ * Note: do not use this directly. Instead, use __alloc_size() since it is conditionally ++ * available and includes other attributes. ++ * ++ * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-alloc_005fsize-function-attribute ++ * clang: https://clang.llvm.org/docs/AttributeReference.html#alloc-size ++ */ ++#define __alloc_size__(x, ...) __attribute__((__alloc_size__(x, ## __VA_ARGS__))) ++ + /* + * Note: users of __always_inline currently do not write "inline" themselves, + * which seems to be required by gcc to apply the attribute according +@@ -153,6 +162,7 @@ + + /* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-malloc-function-attribute ++ * clang: https://clang.llvm.org/docs/AttributeReference.html#malloc + */ + #define __malloc __attribute__((__malloc__)) + +diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h +index b6ff83a714ca..4f2203c4a257 100644 +--- a/include/linux/compiler_types.h ++++ b/include/linux/compiler_types.h +@@ -250,6 +250,18 @@ struct ftrace_likely_data { + # define __cficanonical + #endif + ++/* ++ * Any place that could be marked with the "alloc_size" attribute is also ++ * a place to be marked with the "malloc" attribute. Do this as part of the ++ * __alloc_size macro to avoid redundant attributes and to avoid missing a ++ * __malloc marking. ++ */ ++#ifdef __alloc_size__ ++# define __alloc_size(x, ...) __alloc_size__(x, ## __VA_ARGS__) __malloc ++#else ++# define __alloc_size(x, ...) __malloc ++#endif ++ + #ifndef asm_volatile_goto + #define asm_volatile_goto(x...) asm goto(x) + #endif +diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl +index c27d2312cfc3..88cb294dc447 100755 +--- a/scripts/checkpatch.pl ++++ b/scripts/checkpatch.pl +@@ -489,7 +489,8 @@ our $Attribute = qr{ + ____cacheline_aligned| + ____cacheline_aligned_in_smp| + ____cacheline_internodealigned_in_smp| +- __weak ++ __weak| ++ __alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\) + }x; + our $Modifier; + our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__}; +-- +2.35.1 + diff --git a/queue-5.15/cxl-port-hold-port-reference-until-decoder-release.patch b/queue-5.15/cxl-port-hold-port-reference-until-decoder-release.patch new file mode 100644 index 00000000000..fa85f103b3c --- /dev/null +++ b/queue-5.15/cxl-port-hold-port-reference-until-decoder-release.patch @@ -0,0 +1,72 @@ +From 1ebc4a4f17a863ed464c14b72a5d167428638081 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Feb 2022 16:25:11 -0800 +Subject: cxl/port: Hold port reference until decoder release + +From: Dan Williams + +[ Upstream commit 74be98774dfbc5b8b795db726bd772e735d2edd4 ] + +KASAN + DEBUG_KOBJECT_RELEASE reports a potential use-after-free in +cxl_decoder_release() where it goes to reference its parent, a cxl_port, +to free its id back to port->decoder_ida. + + BUG: KASAN: use-after-free in to_cxl_port+0x18/0x90 [cxl_core] + Read of size 8 at addr ffff888119270908 by task kworker/35:2/379 + + CPU: 35 PID: 379 Comm: kworker/35:2 Tainted: G OE 5.17.0-rc2+ #198 + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 + Workqueue: events kobject_delayed_cleanup + Call Trace: + + dump_stack_lvl+0x59/0x73 + print_address_description.constprop.0+0x1f/0x150 + ? to_cxl_port+0x18/0x90 [cxl_core] + kasan_report.cold+0x83/0xdf + ? to_cxl_port+0x18/0x90 [cxl_core] + to_cxl_port+0x18/0x90 [cxl_core] + cxl_decoder_release+0x2a/0x60 [cxl_core] + device_release+0x5f/0x100 + kobject_cleanup+0x80/0x1c0 + +The device core only guarantees parent lifetime until all children are +unregistered. If a child needs a parent to complete its ->release() +callback that child needs to hold a reference to extend the lifetime of +the parent. + +Fixes: 40ba17afdfab ("cxl/acpi: Introduce cxl_decoder objects") +Reported-by: Ben Widawsky +Tested-by: Ben Widawsky +Reviewed-by: Ben Widawsky +Link: https://lore.kernel.org/r/164505751190.4175768.13324905271463416712.stgit@dwillia2-desk3.amr.corp.intel.com +Signed-off-by: Dan Williams +Signed-off-by: Sasha Levin +--- + drivers/cxl/core/bus.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/cxl/core/bus.c b/drivers/cxl/core/bus.c +index 267d8042bec2..0987a6423ee0 100644 +--- a/drivers/cxl/core/bus.c ++++ b/drivers/cxl/core/bus.c +@@ -182,6 +182,7 @@ static void cxl_decoder_release(struct device *dev) + + ida_free(&port->decoder_ida, cxld->id); + kfree(cxld); ++ put_device(&port->dev); + } + + static const struct device_type cxl_decoder_switch_type = { +@@ -481,6 +482,9 @@ cxl_decoder_alloc(struct cxl_port *port, int nr_targets, resource_size_t base, + if (rc < 0) + goto err; + ++ /* need parent to stick around to release the id */ ++ get_device(&port->dev); ++ + *cxld = (struct cxl_decoder) { + .id = rc, + .range = { +-- +2.35.1 + diff --git a/queue-5.15/dma-buf-poll-get-a-file-reference-for-outstanding-fe.patch b/queue-5.15/dma-buf-poll-get-a-file-reference-for-outstanding-fe.patch new file mode 100644 index 00000000000..7903856f855 --- /dev/null +++ b/queue-5.15/dma-buf-poll-get-a-file-reference-for-outstanding-fe.patch @@ -0,0 +1,93 @@ +From 095e8ce5c8f15213fdfd6c5a5b81d57c648bc7b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jul 2021 09:58:57 +0200 +Subject: dma-buf/poll: Get a file reference for outstanding fence callbacks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michel Dänzer + +[ Upstream commit ff2d23843f7fb4f13055be5a4a9a20ddd04e6e9c ] + +This makes sure we don't hit the + + BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active); + +in dma_buf_release, which could be triggered by user space closing the +dma-buf file description while there are outstanding fence callbacks +from dma_buf_poll. + +Cc: stable@vger.kernel.org +Signed-off-by: Michel Dänzer +Reviewed-by: Christian König +Link: https://patchwork.freedesktop.org/patch/msgid/20210723075857.4065-1-michel@daenzer.net +Signed-off-by: Christian König +Signed-off-by: Sasha Levin +--- + drivers/dma-buf/dma-buf.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c +index f9217e300eea..968c3df2810e 100644 +--- a/drivers/dma-buf/dma-buf.c ++++ b/drivers/dma-buf/dma-buf.c +@@ -67,12 +67,9 @@ static void dma_buf_release(struct dentry *dentry) + BUG_ON(dmabuf->vmapping_counter); + + /* +- * Any fences that a dma-buf poll can wait on should be signaled +- * before releasing dma-buf. This is the responsibility of each +- * driver that uses the reservation objects. +- * +- * If you hit this BUG() it means someone dropped their ref to the +- * dma-buf while still having pending operation to the buffer. ++ * If you hit this BUG() it could mean: ++ * * There's a file reference imbalance in dma_buf_poll / dma_buf_poll_cb or somewhere else ++ * * dmabuf->cb_in/out.active are non-0 despite no pending fence callback + */ + BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active); + +@@ -200,6 +197,7 @@ static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence) + static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb) + { + struct dma_buf_poll_cb_t *dcb = (struct dma_buf_poll_cb_t *)cb; ++ struct dma_buf *dmabuf = container_of(dcb->poll, struct dma_buf, poll); + unsigned long flags; + + spin_lock_irqsave(&dcb->poll->lock, flags); +@@ -207,6 +205,8 @@ static void dma_buf_poll_cb(struct dma_fence *fence, struct dma_fence_cb *cb) + dcb->active = 0; + spin_unlock_irqrestore(&dcb->poll->lock, flags); + dma_fence_put(fence); ++ /* Paired with get_file in dma_buf_poll */ ++ fput(dmabuf->file); + } + + static bool dma_buf_poll_shared(struct dma_resv *resv, +@@ -282,8 +282,12 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll) + spin_unlock_irq(&dmabuf->poll.lock); + + if (events & EPOLLOUT) { ++ /* Paired with fput in dma_buf_poll_cb */ ++ get_file(dmabuf->file); ++ + if (!dma_buf_poll_shared(resv, dcb) && + !dma_buf_poll_excl(resv, dcb)) ++ + /* No callback queued, wake up any other waiters */ + dma_buf_poll_cb(NULL, &dcb->cb); + else +@@ -303,6 +307,9 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll) + spin_unlock_irq(&dmabuf->poll.lock); + + if (events & EPOLLIN) { ++ /* Paired with fput in dma_buf_poll_cb */ ++ get_file(dmabuf->file); ++ + if (!dma_buf_poll_excl(resv, dcb)) + /* No callback queued, wake up any other waiters */ + dma_buf_poll_cb(NULL, &dcb->cb); +-- +2.35.1 + diff --git a/queue-5.15/drbd-add-error-handling-support-for-add_disk.patch b/queue-5.15/drbd-add-error-handling-support-for-add_disk.patch new file mode 100644 index 00000000000..b938b82fe39 --- /dev/null +++ b/queue-5.15/drbd-add-error-handling-support-for-add_disk.patch @@ -0,0 +1,47 @@ +From 24922376eeda8b7c9c54bbcdf28021e3325f33b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Sep 2021 15:00:59 -0700 +Subject: drbd: add error handling support for add_disk() + +From: Luis Chamberlain + +[ Upstream commit e92ab4eda516a5bfd96c087282ebe9521deba4f4 ] + +We never checked for errors on add_disk() as this function +returned void. Now that this is fixed, use the shiny new +error handling. + +Signed-off-by: Luis Chamberlain +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_main.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c +index 8ba2fe356f01..ae6a136d278e 100644 +--- a/drivers/block/drbd/drbd_main.c ++++ b/drivers/block/drbd/drbd_main.c +@@ -2798,7 +2798,9 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + goto out_idr_remove_vol; + } + +- add_disk(disk); ++ err = add_disk(disk); ++ if (err) ++ goto out_cleanup_disk; + + /* inherit the connection state */ + device->state.conn = first_connection(resource)->cstate; +@@ -2812,6 +2814,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + drbd_debugfs_device_add(device); + return NO_ERROR; + ++out_cleanup_disk: ++ blk_cleanup_disk(disk); + out_idr_remove_vol: + idr_remove(&connection->peer_devices, vnr); + out_idr_remove_from_resource: +-- +2.35.1 + diff --git a/queue-5.15/drbd-fix-an-invalid-memory-access-caused-by-incorrec.patch b/queue-5.15/drbd-fix-an-invalid-memory-access-caused-by-incorrec.patch new file mode 100644 index 00000000000..501999d688c --- /dev/null +++ b/queue-5.15/drbd-fix-an-invalid-memory-access-caused-by-incorrec.patch @@ -0,0 +1,69 @@ +From b95039363a3ed89cf8d474e1d691d9dbf5322b73 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Apr 2022 21:04:44 +0200 +Subject: drbd: fix an invalid memory access caused by incorrect use of list + iterator +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Xiaomeng Tong + +[ Upstream commit ae4d37b5df749926891583d42a6801b5da11e3c1 ] + +The bug is here: + idr_remove(&connection->peer_devices, vnr); + +If the previous for_each_connection() don't exit early (no goto hit +inside the loop), the iterator 'connection' after the loop will be a +bogus pointer to an invalid structure object containing the HEAD +(&resource->connections). As a result, the use of 'connection' above +will lead to a invalid memory access (including a possible invalid free +as idr_remove could call free_layer). + +The original intention should have been to remove all peer_devices, +but the following lines have already done the work. So just remove +this line and the unneeded label, to fix this bug. + +Cc: stable@vger.kernel.org +Fixes: c06ece6ba6f1b ("drbd: Turn connection->volumes into connection->peer_devices") +Signed-off-by: Xiaomeng Tong +Reviewed-by: Christoph Böhmwalder +Reviewed-by: Lars Ellenberg +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_main.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c +index b91d2a9dc238..d59af26d7703 100644 +--- a/drivers/block/drbd/drbd_main.c ++++ b/drivers/block/drbd/drbd_main.c +@@ -2795,12 +2795,12 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + + if (init_submitter(device)) { + err = ERR_NOMEM; +- goto out_idr_remove_vol; ++ goto out_idr_remove_from_resource; + } + + err = add_disk(disk); + if (err) +- goto out_idr_remove_vol; ++ goto out_idr_remove_from_resource; + + /* inherit the connection state */ + device->state.conn = first_connection(resource)->cstate; +@@ -2814,8 +2814,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + drbd_debugfs_device_add(device); + return NO_ERROR; + +-out_idr_remove_vol: +- idr_remove(&connection->peer_devices, vnr); + out_idr_remove_from_resource: + for_each_connection(connection, resource) { + peer_device = idr_remove(&connection->peer_devices, vnr); +-- +2.35.1 + diff --git a/queue-5.15/drbd-fix-double-free-problem-in-drbd_create_device.patch b/queue-5.15/drbd-fix-double-free-problem-in-drbd_create_device.patch new file mode 100644 index 00000000000..d50a6bdad0f --- /dev/null +++ b/queue-5.15/drbd-fix-double-free-problem-in-drbd_create_device.patch @@ -0,0 +1,50 @@ +From baf6c215912ca443adde48acb4bf135c9e28f41d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Nov 2021 16:07:09 +0800 +Subject: drbd: Fix double free problem in drbd_create_device + +From: Wu Bo + +[ Upstream commit 27548088ac628109f70eb0b1eb521d035844dba8 ] + +In drbd_create_device(), the 'out_no_io_page' lable has called +blk_cleanup_disk() when return failed. + +So remove the 'out_cleanup_disk' lable to avoid double free the +disk pointer. + +Fixes: e92ab4eda516 ("drbd: add error handling support for add_disk()") +Signed-off-by: Wu Bo +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/1636013229-26309-1-git-send-email-wubo40@huawei.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/block/drbd/drbd_main.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c +index ae6a136d278e..b91d2a9dc238 100644 +--- a/drivers/block/drbd/drbd_main.c ++++ b/drivers/block/drbd/drbd_main.c +@@ -2800,7 +2800,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + + err = add_disk(disk); + if (err) +- goto out_cleanup_disk; ++ goto out_idr_remove_vol; + + /* inherit the connection state */ + device->state.conn = first_connection(resource)->cstate; +@@ -2814,8 +2814,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig + drbd_debugfs_device_add(device); + return NO_ERROR; + +-out_cleanup_disk: +- blk_cleanup_disk(disk); + out_idr_remove_vol: + idr_remove(&connection->peer_devices, vnr); + out_idr_remove_from_resource: +-- +2.35.1 + diff --git a/queue-5.15/drm-amd-display-fix-by-adding-fpu-protection-for-dcn.patch b/queue-5.15/drm-amd-display-fix-by-adding-fpu-protection-for-dcn.patch new file mode 100644 index 00000000000..3dac0233541 --- /dev/null +++ b/queue-5.15/drm-amd-display-fix-by-adding-fpu-protection-for-dcn.patch @@ -0,0 +1,96 @@ +From 63f6623c541b73e989c52dd8b907d577affd482c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 29 Mar 2022 13:10:31 +0530 +Subject: drm/amd/display: Fix by adding FPU protection for + dcn30_internal_validate_bw + +From: CHANDAN VURDIGERE NATARAJ + +[ Upstream commit 50e6cb3fd2cde554db646282ea10df7236e6493c ] + +[Why] +Below general protection fault observed when WebGL Aquarium is run for +longer duration. If drm debug logs are enabled and set to 0x1f then the +issue is observed within 10 minutes of run. + +[ 100.717056] general protection fault, probably for non-canonical address 0x2d33302d32323032: 0000 [#1] PREEMPT SMP NOPTI +[ 100.727921] CPU: 3 PID: 1906 Comm: DrmThread Tainted: G W 5.15.30 #12 d726c6a2d6ebe5cf9223931cbca6892f916fe18b +[ 100.754419] RIP: 0010:CalculateSwathWidth+0x1f7/0x44f +[ 100.767109] Code: 00 00 00 f2 42 0f 11 04 f0 48 8b 85 88 00 00 00 f2 42 0f 10 04 f0 48 8b 85 98 00 00 00 f2 42 0f 11 04 f0 48 8b 45 10 0f 57 c0 42 0f 2a 04 b0 0f 57 c9 f3 43 0f 2a 0c b4 e8 8c e2 f3 ff 48 8b +[ 100.781269] RSP: 0018:ffffa9230079eeb0 EFLAGS: 00010246 +[ 100.812528] RAX: 2d33302d32323032 RBX: 0000000000000500 RCX: 0000000000000000 +[ 100.819656] RDX: 0000000000000001 RSI: ffff99deb712c49c RDI: 0000000000000000 +[ 100.826781] RBP: ffffa9230079ef50 R08: ffff99deb712460c R09: ffff99deb712462c +[ 100.833907] R10: ffff99deb7124940 R11: ffff99deb7124d70 R12: ffff99deb712ae44 +[ 100.841033] R13: 0000000000000001 R14: 0000000000000000 R15: ffffa9230079f0a0 +[ 100.848159] FS: 00007af121212640(0000) GS:ffff99deba780000(0000) knlGS:0000000000000000 +[ 100.856240] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[ 100.861980] CR2: 0000209000fe1000 CR3: 000000011b18c000 CR4: 0000000000350ee0 +[ 100.869106] Call Trace: +[ 100.871555] +[ 100.873655] ? asm_sysvec_reschedule_ipi+0x12/0x20 +[ 100.878449] CalculateSwathAndDETConfiguration+0x1a3/0x6dd +[ 100.883937] dml31_ModeSupportAndSystemConfigurationFull+0x2ce4/0x76da +[ 100.890467] ? kallsyms_lookup_buildid+0xc8/0x163 +[ 100.895173] ? kallsyms_lookup_buildid+0xc8/0x163 +[ 100.899874] ? __sprint_symbol+0x80/0x135 +[ 100.903883] ? dm_update_plane_state+0x3f9/0x4d2 +[ 100.908500] ? symbol_string+0xb7/0xde +[ 100.912250] ? number+0x145/0x29b +[ 100.915566] ? vsnprintf+0x341/0x5ff +[ 100.919141] ? desc_read_finalized_seq+0x39/0x87 +[ 100.923755] ? update_load_avg+0x1b9/0x607 +[ 100.927849] ? compute_mst_dsc_configs_for_state+0x7d/0xd5b +[ 100.933416] ? fetch_pipe_params+0xa4d/0xd0c +[ 100.937686] ? dc_fpu_end+0x3d/0xa8 +[ 100.941175] dml_get_voltage_level+0x16b/0x180 +[ 100.945619] dcn30_internal_validate_bw+0x10e/0x89b +[ 100.950495] ? dcn31_validate_bandwidth+0x68/0x1fc +[ 100.955285] ? resource_build_scaling_params+0x98b/0xb8c +[ 100.960595] ? dcn31_validate_bandwidth+0x68/0x1fc +[ 100.965384] dcn31_validate_bandwidth+0x9a/0x1fc +[ 100.970001] dc_validate_global_state+0x238/0x295 +[ 100.974703] amdgpu_dm_atomic_check+0x9c1/0xbce +[ 100.979235] ? _printk+0x59/0x73 +[ 100.982467] drm_atomic_check_only+0x403/0x78b +[ 100.986912] drm_mode_atomic_ioctl+0x49b/0x546 +[ 100.991358] ? drm_ioctl+0x1c1/0x3b3 +[ 100.994936] ? drm_atomic_set_property+0x92a/0x92a +[ 100.999725] drm_ioctl_kernel+0xdc/0x149 +[ 101.003648] drm_ioctl+0x27f/0x3b3 +[ 101.007051] ? drm_atomic_set_property+0x92a/0x92a +[ 101.011842] amdgpu_drm_ioctl+0x49/0x7d +[ 101.015679] __se_sys_ioctl+0x7c/0xb8 +[ 101.015685] do_syscall_64+0x5f/0xb8 +[ 101.015690] ? __irq_exit_rcu+0x34/0x96 + +[How] +It calles populate_dml_pipes which uses doubles to initialize. +Adding FPU protection avoids context switch and probable loss of vba context +as there is potential contention while drm debug logs are enabled. + +Signed-off-by: CHANDAN VURDIGERE NATARAJ +Reviewed-by: Rodrigo Siqueira +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +index 7aadb35a3079..e224c5213258 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +@@ -1813,7 +1813,9 @@ bool dcn31_validate_bandwidth(struct dc *dc, + + BW_VAL_TRACE_COUNT(); + ++ DC_FP_START(); + out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate); ++ DC_FP_END(); + + // Disable fast_validate to set min dcfclk in alculate_wm_and_dlg + if (pipe_cnt == 0) +-- +2.35.1 + diff --git a/queue-5.15/drm-amd-display-set-min-dcfclk-if-pipe-count-is-0.patch b/queue-5.15/drm-amd-display-set-min-dcfclk-if-pipe-count-is-0.patch new file mode 100644 index 00000000000..0dc3da0fb4e --- /dev/null +++ b/queue-5.15/drm-amd-display-set-min-dcfclk-if-pipe-count-is-0.patch @@ -0,0 +1,154 @@ +From 74991c0a3852c85aaed70719363488ad5916b3da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Aug 2021 11:38:44 -0400 +Subject: drm/amd/display: Set min dcfclk if pipe count is 0 + +From: Michael Strauss + +[ Upstream commit bc204778b4032b336cb3bde85bea852d79e7e389 ] + +[WHY] +Clocks don't get recalculated in 0 stream/0 pipe configs, +blocking S0i3 if dcfclk gets high enough + +[HOW] +Create DCN31 copy of DCN30 bandwidth validation func which +doesn't entirely skip validation in 0 pipe scenarios + +Override dcfclk to vlevel 0/min value during validation if pipe +count is 0 + +Reviewed-by: Eric Yang +Acked-by: Qingqing Zhuo +Signed-off-by: Michael Strauss +Tested-by: Daniel Wheeler +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + .../drm/amd/display/dc/dcn30/dcn30_resource.c | 2 +- + .../drm/amd/display/dc/dcn30/dcn30_resource.h | 7 +++ + .../drm/amd/display/dc/dcn31/dcn31_resource.c | 63 ++++++++++++++++++- + 3 files changed, 70 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +index 0294d0cc4759..735c92a5aa36 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +@@ -1856,7 +1856,7 @@ static struct pipe_ctx *dcn30_find_split_pipe( + return pipe; + } + +-static noinline bool dcn30_internal_validate_bw( ++noinline bool dcn30_internal_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, +diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h +index b754b89beadf..b92e4cc0232f 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h ++++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h +@@ -55,6 +55,13 @@ unsigned int dcn30_calc_max_scaled_time( + + bool dcn30_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate); ++bool dcn30_internal_validate_bw( ++ struct dc *dc, ++ struct dc_state *context, ++ display_e2e_pipe_params_st *pipes, ++ int *pipe_cnt_out, ++ int *vlevel_out, ++ bool fast_validate); + void dcn30_calculate_wm_and_dlg( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, +diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +index b60ab3cc0f11..7aadb35a3079 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +@@ -1664,6 +1664,15 @@ static void dcn31_calculate_wm_and_dlg_fp( + if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk) + dcfclk = context->bw_ctx.dml.soc.min_dcfclk; + ++ /* We don't recalculate clocks for 0 pipe configs, which can block ++ * S0i3 as high clocks will block low power states ++ * Override any clocks that can block S0i3 to min here ++ */ ++ if (pipe_cnt == 0) { ++ context->bw_ctx.bw.dcn.clk.dcfclk_khz = dcfclk; // always should be vlevel 0 ++ return; ++ } ++ + pipes[0].clks_cfg.voltage = vlevel; + pipes[0].clks_cfg.dcfclk_mhz = dcfclk; + pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz; +@@ -1789,6 +1798,58 @@ static void dcn31_calculate_wm_and_dlg( + DC_FP_END(); + } + ++bool dcn31_validate_bandwidth(struct dc *dc, ++ struct dc_state *context, ++ bool fast_validate) ++{ ++ bool out = false; ++ ++ BW_VAL_TRACE_SETUP(); ++ ++ int vlevel = 0; ++ int pipe_cnt = 0; ++ display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_KERNEL); ++ DC_LOGGER_INIT(dc->ctx->logger); ++ ++ BW_VAL_TRACE_COUNT(); ++ ++ out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate); ++ ++ // Disable fast_validate to set min dcfclk in alculate_wm_and_dlg ++ if (pipe_cnt == 0) ++ fast_validate = false; ++ ++ if (!out) ++ goto validate_fail; ++ ++ BW_VAL_TRACE_END_VOLTAGE_LEVEL(); ++ ++ if (fast_validate) { ++ BW_VAL_TRACE_SKIP(fast); ++ goto validate_out; ++ } ++ ++ dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel); ++ ++ BW_VAL_TRACE_END_WATERMARKS(); ++ ++ goto validate_out; ++ ++validate_fail: ++ DC_LOG_WARNING("Mode Validation Warning: %s failed alidation.\n", ++ dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states])); ++ ++ BW_VAL_TRACE_SKIP(fail); ++ out = false; ++ ++validate_out: ++ kfree(pipes); ++ ++ BW_VAL_TRACE_FINISH(); ++ ++ return out; ++} ++ + static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap + }; +@@ -1871,7 +1932,7 @@ static struct resource_funcs dcn31_res_pool_funcs = { + .link_encs_assign = link_enc_cfg_link_encs_assign, + .link_enc_unassign = link_enc_cfg_link_enc_unassign, + .panel_cntl_create = dcn31_panel_cntl_create, +- .validate_bandwidth = dcn30_validate_bandwidth, ++ .validate_bandwidth = dcn31_validate_bandwidth, + .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, + .populate_dml_pipes = dcn31_populate_dml_pipes_from_context, +-- +2.35.1 + diff --git a/queue-5.15/drm-amd-refactor-amdgpu_aspm-to-be-evaluated-per-dev.patch b/queue-5.15/drm-amd-refactor-amdgpu_aspm-to-be-evaluated-per-dev.patch new file mode 100644 index 00000000000..97abb5e6155 --- /dev/null +++ b/queue-5.15/drm-amd-refactor-amdgpu_aspm-to-be-evaluated-per-dev.patch @@ -0,0 +1,164 @@ +From 3865f7a47bd4d4328d9e60b58e5072710cd533ee Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Feb 2022 23:19:58 -0600 +Subject: drm/amd: Refactor `amdgpu_aspm` to be evaluated per device + +From: Mario Limonciello + +[ Upstream commit 0ab5d711ec74d9e60673900974806b7688857947 ] + +Evaluating `pcie_aspm_enabled` as part of driver probe has the implication +that if one PCIe bridge with an AMD GPU connected doesn't support ASPM +then none of them do. This is an invalid assumption as the PCIe core will +configure ASPM for individual PCIe bridges. + +Create a new helper function that can be called by individual dGPUs to +react to the `amdgpu_aspm` module parameter without having negative results +for other dGPUs on the PCIe bus. + +Suggested-by: Lijo Lazar +Reviewed-by: Lijo Lazar +Signed-off-by: Mario Limonciello +Reviewed-by: Alex Deucher +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 25 +++++++++++++++++++ + drivers/gpu/drm/amd/amdgpu/cik.c | 2 +- + drivers/gpu/drm/amd/amdgpu/nv.c | 2 +- + drivers/gpu/drm/amd/amdgpu/si.c | 2 +- + drivers/gpu/drm/amd/amdgpu/soc15.c | 2 +- + drivers/gpu/drm/amd/amdgpu/vi.c | 2 +- + .../amd/pm/swsmu/smu11/sienna_cichlid_ppt.c | 2 +- + 8 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +index 2eebefd26fa8..5f95d03fd46a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h +@@ -1285,6 +1285,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, + void amdgpu_device_pci_config_reset(struct amdgpu_device *adev); + int amdgpu_device_pci_reset(struct amdgpu_device *adev); + bool amdgpu_device_need_post(struct amdgpu_device *adev); ++bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev); + + void amdgpu_cs_report_moved_bytes(struct amdgpu_device *adev, u64 num_bytes, + u64 num_vis_bytes); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +index a926b5ebbfdf..d1af709cc7dc 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +@@ -1309,6 +1309,31 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev) + return true; + } + ++/** ++ * amdgpu_device_should_use_aspm - check if the device should program ASPM ++ * ++ * @adev: amdgpu_device pointer ++ * ++ * Confirm whether the module parameter and pcie bridge agree that ASPM should ++ * be set for this device. ++ * ++ * Returns true if it should be used or false if not. ++ */ ++bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev) ++{ ++ switch (amdgpu_aspm) { ++ case -1: ++ break; ++ case 0: ++ return false; ++ case 1: ++ return true; ++ default: ++ return false; ++ } ++ return pcie_aspm_enabled(adev->pdev); ++} ++ + /* if we get transitioned to only one device, take VGA back */ + /** + * amdgpu_device_vga_set_decode - enable/disable vga decode +diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c +index f10ce740a29c..de6d10390ab2 100644 +--- a/drivers/gpu/drm/amd/amdgpu/cik.c ++++ b/drivers/gpu/drm/amd/amdgpu/cik.c +@@ -1719,7 +1719,7 @@ static void cik_program_aspm(struct amdgpu_device *adev) + bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false; + bool disable_clkreq = false; + +- if (amdgpu_aspm == 0) ++ if (!amdgpu_device_should_use_aspm(adev)) + return; + + if (pci_is_root_bus(adev->pdev->bus)) +diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c +index 9cbed9a8f1c0..6e277236b44f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/nv.c ++++ b/drivers/gpu/drm/amd/amdgpu/nv.c +@@ -584,7 +584,7 @@ static void nv_pcie_gen3_enable(struct amdgpu_device *adev) + + static void nv_program_aspm(struct amdgpu_device *adev) + { +- if (!amdgpu_aspm) ++ if (!amdgpu_device_should_use_aspm(adev)) + return; + + if (!(adev->flags & AMD_IS_APU) && +diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c +index e6d2f74a7976..7f99e130acd0 100644 +--- a/drivers/gpu/drm/amd/amdgpu/si.c ++++ b/drivers/gpu/drm/amd/amdgpu/si.c +@@ -2453,7 +2453,7 @@ static void si_program_aspm(struct amdgpu_device *adev) + bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false; + bool disable_clkreq = false; + +- if (amdgpu_aspm == 0) ++ if (!amdgpu_device_should_use_aspm(adev)) + return; + + if (adev->flags & AMD_IS_APU) +diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c +index 6439d5c3d8d8..bdb47ae96ce6 100644 +--- a/drivers/gpu/drm/amd/amdgpu/soc15.c ++++ b/drivers/gpu/drm/amd/amdgpu/soc15.c +@@ -689,7 +689,7 @@ static void soc15_pcie_gen3_enable(struct amdgpu_device *adev) + + static void soc15_program_aspm(struct amdgpu_device *adev) + { +- if (!amdgpu_aspm) ++ if (!amdgpu_device_should_use_aspm(adev)) + return; + + if (!(adev->flags & AMD_IS_APU) && +diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c +index 6645ebbd2696..039b90cdc3bc 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vi.c ++++ b/drivers/gpu/drm/amd/amdgpu/vi.c +@@ -1140,7 +1140,7 @@ static void vi_program_aspm(struct amdgpu_device *adev) + bool bL1SS = false; + bool bClkReqSupport = true; + +- if (!amdgpu_aspm) ++ if (!amdgpu_device_should_use_aspm(adev)) + return; + + if (adev->flags & AMD_IS_APU || +diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +index 574a9d7f7a5e..918d5c7c2328 100644 +--- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c ++++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +@@ -338,7 +338,7 @@ sienna_cichlid_get_allowed_feature_mask(struct smu_context *smu, + if (smu->dc_controlled_by_gpio) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ACDC_BIT); + +- if (amdgpu_aspm) ++ if (amdgpu_device_should_use_aspm(adev)) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_LCLK_BIT); + + return 0; +-- +2.35.1 + diff --git a/queue-5.15/drm-amd-vcn-fix-an-error-msg-on-vcn-3.0.patch b/queue-5.15/drm-amd-vcn-fix-an-error-msg-on-vcn-3.0.patch new file mode 100644 index 00000000000..7687aee1bdd --- /dev/null +++ b/queue-5.15/drm-amd-vcn-fix-an-error-msg-on-vcn-3.0.patch @@ -0,0 +1,40 @@ +From bf8ea95fb64e1e9fbebf251f5d186d240de57296 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 27 Mar 2022 19:07:13 +0800 +Subject: drm/amd/vcn: fix an error msg on vcn 3.0 + +From: tiancyin + +[ Upstream commit 425d7a87e54ee358f580eaf10cf28dc95f7121c1 ] + +Some video card has more than one vcn instance, passing 0 to +vcn_v3_0_pause_dpg_mode is incorrect. + +Error msg: +Register(1) [mmUVD_POWER_STATUS] failed to reach value +0x00000001 != 0x00000002 + +Reviewed-by: James Zhu +Signed-off-by: tiancyin +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +index 6e56bef4fdf8..1310617f030f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +@@ -1511,7 +1511,7 @@ static int vcn_v3_0_stop_dpg_mode(struct amdgpu_device *adev, int inst_idx) + struct dpg_pause_state state = {.fw_based = VCN_DPG_STATE__UNPAUSE}; + uint32_t tmp; + +- vcn_v3_0_pause_dpg_mode(adev, 0, &state); ++ vcn_v3_0_pause_dpg_mode(adev, inst_idx, &state); + + /* Wait for power status to be 1 */ + SOC15_WAIT_ON_RREG(VCN, inst_idx, mmUVD_POWER_STATUS, 1, +-- +2.35.1 + diff --git a/queue-5.15/drm-amdgpu-bind-to-any-0x1002-pci-diplay-class-devic.patch b/queue-5.15/drm-amdgpu-bind-to-any-0x1002-pci-diplay-class-devic.patch new file mode 100644 index 00000000000..1d9c7639b40 --- /dev/null +++ b/queue-5.15/drm-amdgpu-bind-to-any-0x1002-pci-diplay-class-devic.patch @@ -0,0 +1,62 @@ +From c33a17fe4004dfa57beeec79734d66651652654e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Aug 2021 17:18:53 -0400 +Subject: drm/amdgpu: bind to any 0x1002 PCI diplay class device +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Alex Deucher + +[ Upstream commit eb4fd29afd4aa1c98d882800ceeee7d1f5262803 ] + +Bind to all 0x1002 GPU devices. + +For now we explicitly return -ENODEV for generic bindings. +Remove this check once IP discovery based checking is in place. + +v2: rebase (Alex) + +Reviewed-by: Christian König +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index f65b4b233ffb..c294081022bd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -1952,6 +1952,16 @@ static const struct pci_device_id pciidlist[] = { + {0x1002, 0x7424, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, + {0x1002, 0x743F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BEIGE_GOBY}, + ++ { PCI_DEVICE(0x1002, PCI_ANY_ID), ++ .class = PCI_CLASS_DISPLAY_VGA << 8, ++ .class_mask = 0xffffff, ++ .driver_data = 0 }, ++ ++ { PCI_DEVICE(0x1002, PCI_ANY_ID), ++ .class = PCI_CLASS_DISPLAY_OTHER << 8, ++ .class_mask = 0xffffff, ++ .driver_data = 0 }, ++ + {0, 0, 0} + }; + +@@ -1999,6 +2009,11 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + return -ENODEV; + } + ++ if (flags == 0) { ++ DRM_INFO("Unsupported asic. Remove me when IP discovery init is in place.\n"); ++ return -ENODEV; ++ } ++ + if (amdgpu_virtual_display || + amdgpu_device_asic_has_dc_support(flags & AMD_ASIC_MASK)) + supports_atomic = true; +-- +2.35.1 + diff --git a/queue-5.15/drm-amdgpu-drop-flags-check-for-chip_ip_discovery.patch b/queue-5.15/drm-amdgpu-drop-flags-check-for-chip_ip_discovery.patch new file mode 100644 index 00000000000..5c0bcf60d95 --- /dev/null +++ b/queue-5.15/drm-amdgpu-drop-flags-check-for-chip_ip_discovery.patch @@ -0,0 +1,38 @@ +From 33a59f2b018f781bebc5f322a3779f5581b866e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Jan 2022 09:59:29 -0500 +Subject: drm/amdgpu: drop flags check for CHIP_IP_DISCOVERY + +From: Alex Deucher + +[ Upstream commit d82ce3cd30aa28db3e94ffc36ebf0af2ff12801d ] + +Support for IP based discovery is in place now so this +check is no longer required. + +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index cb0b5972e7fd..a0dd4b41ba4a 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -2009,11 +2009,6 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + return -ENODEV; + } + +- if (flags == CHIP_IP_DISCOVERY) { +- DRM_INFO("Unsupported asic. Remove me when IP discovery init is in place.\n"); +- return -ENODEV; +- } +- + if (amdgpu_virtual_display || + amdgpu_device_asic_has_dc_support(flags & AMD_ASIC_MASK)) + supports_atomic = true; +-- +2.35.1 + diff --git a/queue-5.15/drm-amdgpu-fix-rejecting-tahiti-gpus.patch b/queue-5.15/drm-amdgpu-fix-rejecting-tahiti-gpus.patch new file mode 100644 index 00000000000..4d8b840a19e --- /dev/null +++ b/queue-5.15/drm-amdgpu-fix-rejecting-tahiti-gpus.patch @@ -0,0 +1,48 @@ +From c995df2c71b06e788627a83d76c565a56142bf76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Jan 2022 07:51:41 +0100 +Subject: drm/amdgpu: Fix rejecting Tahiti GPUs + +From: Lukas Fink + +[ Upstream commit 3993a799fc971bc9b918bd969aa55864447b5dde ] + +eb4fd29afd4a ("drm/amdgpu: bind to any 0x1002 PCI diplay class device") added +generic bindings to amdgpu so that that it binds to all display class devices +with VID 0x1002 and then rejects those in amdgpu_pci_probe. + +Unfortunately it reuses a driver_data value of 0 to detect those new bindings, +which is already used to denote CHIP_TAHITI ASICs. + +The driver_data value given to those new bindings was changed in +dd0761fd24ea1 ("drm/amdgpu: set CHIP_IP_DISCOVERY as the asic type by default") +to CHIP_IP_DISCOVERY (=36), but it seems that the check in amdgpu_pci_probe +was forgotten to be changed. Therefore, it still rejects Tahiti GPUs. + +Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1860 +Fixes: eb4fd29afd4a ("drm/amdgpu: bind to any 0x1002 PCI diplay class device") + +Cc: stable@vger.kernel.org +Signed-off-by: Lukas Fink +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +index c294081022bd..cb0b5972e7fd 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +@@ -2009,7 +2009,7 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, + return -ENODEV; + } + +- if (flags == 0) { ++ if (flags == CHIP_IP_DISCOVERY) { + DRM_INFO("Unsupported asic. Remove me when IP discovery init is in place.\n"); + return -ENODEV; + } +-- +2.35.1 + diff --git a/queue-5.15/drm-amdgpu-vi-disable-aspm-on-intel-alder-lake-based.patch b/queue-5.15/drm-amdgpu-vi-disable-aspm-on-intel-alder-lake-based.patch new file mode 100644 index 00000000000..173c8a9251b --- /dev/null +++ b/queue-5.15/drm-amdgpu-vi-disable-aspm-on-intel-alder-lake-based.patch @@ -0,0 +1,76 @@ +From 26701dacdcfb79758dd98eaad7a131d2ddffdf91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Apr 2022 12:08:38 -0500 +Subject: drm/amdgpu: vi: disable ASPM on Intel Alder Lake based systems + +From: Richard Gong + +[ Upstream commit aa482ddca85a3485be0e7b83a0789dc4d987670b ] + +Active State Power Management (ASPM) feature is enabled since kernel 5.14. +There are some AMD Volcanic Islands (VI) GFX cards, such as the WX3200 and +RX640, that do not work with ASPM-enabled Intel Alder Lake based systems. +Using these GFX cards as video/display output, Intel Alder Lake based +systems will freeze after suspend/resume. + +The issue was originally reported on one system (Dell Precision 3660 with +BIOS version 0.14.81), but was later confirmed to affect at least 4 +pre-production Alder Lake based systems. + +Add an extra check to disable ASPM on Intel Alder Lake based systems with +the problematic AMD Volcanic Islands GFX cards. + +Fixes: 0064b0ce85bb ("drm/amd/pm: enable ASPM by default") +Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1885 +Signed-off-by: Richard Gong +Signed-off-by: Alex Deucher +Cc: stable@vger.kernel.org +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/vi.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c +index 039b90cdc3bc..45f0188c4273 100644 +--- a/drivers/gpu/drm/amd/amdgpu/vi.c ++++ b/drivers/gpu/drm/amd/amdgpu/vi.c +@@ -81,6 +81,10 @@ + #include "mxgpu_vi.h" + #include "amdgpu_dm.h" + ++#if IS_ENABLED(CONFIG_X86) ++#include ++#endif ++ + #define ixPCIE_LC_L1_PM_SUBSTATE 0x100100C6 + #define PCIE_LC_L1_PM_SUBSTATE__LC_L1_SUBSTATES_OVERRIDE_EN_MASK 0x00000001L + #define PCIE_LC_L1_PM_SUBSTATE__LC_PCI_PM_L1_2_OVERRIDE_MASK 0x00000002L +@@ -1134,13 +1138,24 @@ static void vi_enable_aspm(struct amdgpu_device *adev) + WREG32_PCIE(ixPCIE_LC_CNTL, data); + } + ++static bool aspm_support_quirk_check(void) ++{ ++#if IS_ENABLED(CONFIG_X86) ++ struct cpuinfo_x86 *c = &cpu_data(0); ++ ++ return !(c->x86 == 6 && c->x86_model == INTEL_FAM6_ALDERLAKE); ++#else ++ return true; ++#endif ++} ++ + static void vi_program_aspm(struct amdgpu_device *adev) + { + u32 data, data1, orig; + bool bL1SS = false; + bool bClkReqSupport = true; + +- if (!amdgpu_device_should_use_aspm(adev)) ++ if (!amdgpu_device_should_use_aspm(adev) || !aspm_support_quirk_check()) + return; + + if (adev->flags & AMD_IS_APU || +-- +2.35.1 + diff --git a/queue-5.15/drm-i915-disable-bonding-on-gen12-platforms.patch b/queue-5.15/drm-i915-disable-bonding-on-gen12-platforms.patch new file mode 100644 index 00000000000..ad0865bf11c --- /dev/null +++ b/queue-5.15/drm-i915-disable-bonding-on-gen12-platforms.patch @@ -0,0 +1,43 @@ +From c0b09353aaff042ff9843a6d0e02945862501c45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jul 2021 12:21:00 -0700 +Subject: drm/i915: Disable bonding on gen12+ platforms + +From: Matthew Brost + +[ Upstream commit ce7e75c7ef1bf8ea3d947da8c674d2f40fd7d734 ] + +Disable bonding on gen12+ platforms aside from ones already supported by +the i915 - TGL, RKL, and ADL-S. + +Signed-off-by: Matthew Brost +Reviewed-by: John Harrison +Acked-by: Daniel Vetter +Signed-off-by: Matt Roper +Link: https://patchwork.freedesktop.org/patch/msgid/20210728192100.132425-1-matthew.brost@intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/gem/i915_gem_context.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c +index ee0c0b712522..ba2e037a82e4 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c +@@ -442,6 +442,13 @@ set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data) + u16 idx, num_bonds; + int err, n; + ++ if (GRAPHICS_VER(i915) >= 12 && !IS_TIGERLAKE(i915) && ++ !IS_ROCKETLAKE(i915) && !IS_ALDERLAKE_S(i915)) { ++ drm_dbg(&i915->drm, ++ "Bonding on gen12+ aside from TGL, RKL, and ADL_S not supported\n"); ++ return -ENODEV; ++ } ++ + if (get_user(idx, &ext->virtual_index)) + return -EFAULT; + +-- +2.35.1 + diff --git a/queue-5.15/drm-i915-fix-a-race-between-vma-object-destruction-a.patch b/queue-5.15/drm-i915-fix-a-race-between-vma-object-destruction-a.patch new file mode 100644 index 00000000000..b9e10ec1894 --- /dev/null +++ b/queue-5.15/drm-i915-fix-a-race-between-vma-object-destruction-a.patch @@ -0,0 +1,55 @@ +From 28dde823cbf891cb44f4fc3d6c8b5070226ad53c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Jan 2022 12:56:22 +0100 +Subject: drm/i915: Fix a race between vma / object destruction and unbinding +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Hellström + +[ Upstream commit bc1922e5d349db4be14c55513102c024c2ae8a50 ] + +The vma destruction code was using an unlocked advisory check for +drm_mm_node_allocated() to avoid racing with eviction code unbinding +the vma. + +This is very fragile and prohibits the dereference of non-refcounted +pointers of dying vmas after a call to __i915_vma_unbind(). It also +prohibits the dereference of vma->obj of refcounted pointers of +dying vmas after a call to __i915_vma_unbind(), since even if a +refcount is held on the vma, that won't guarantee that its backing +object doesn't get destroyed. + +So introduce an unbind under the vm mutex at object destroy time, +removing all weak references of the vma and its object from the +object vma list and from the vm bound list. + +Signed-off-by: Thomas Hellström +Reviewed-by: Maarten Lankhorst +Link: https://patchwork.freedesktop.org/patch/msgid/20220127115622.302970-1-thomas.hellstrom@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/gem/i915_gem_object.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c +index 6fb9afb65034..5f48d5ea5c15 100644 +--- a/drivers/gpu/drm/i915/gem/i915_gem_object.c ++++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c +@@ -224,6 +224,12 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj) + GEM_BUG_ON(vma->obj != obj); + spin_unlock(&obj->vma.lock); + ++ /* Verify that the vma is unbound under the vm mutex. */ ++ mutex_lock(&vma->vm->mutex); ++ atomic_and(~I915_VMA_PIN_MASK, &vma->flags); ++ __i915_vma_unbind(vma); ++ mutex_unlock(&vma->vm->mutex); ++ + __i915_vma_put(vma); + + spin_lock(&obj->vma.lock); +-- +2.35.1 + diff --git a/queue-5.15/drm-i915-gt-register-the-migrate-contexts-with-their.patch b/queue-5.15/drm-i915-gt-register-the-migrate-contexts-with-their.patch new file mode 100644 index 00000000000..fa4fbfe98ae --- /dev/null +++ b/queue-5.15/drm-i915-gt-register-the-migrate-contexts-with-their.patch @@ -0,0 +1,250 @@ +From ea74c0caed4a9be8b1480ab63c6f96e375c11ecf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Sep 2021 08:25:23 +0200 +Subject: drm/i915/gt: Register the migrate contexts with their engines +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Thomas Hellström + +[ Upstream commit 3e42cc61275f95fd7f022b6380b95428efe134d3 ] + +Pinned contexts, like the migrate contexts need reset after resume +since their context image may have been lost. Also the GuC needs to +register pinned contexts. + +Add a list to struct intel_engine_cs where we add all pinned contexts on +creation, and traverse that list at resume time to reset the pinned +contexts. + +This fixes the kms_pipe_crc_basic@suspend-read-crc-pipe-a selftest for now, +but proper LMEM backup / restore is needed for full suspend functionality. +However, note that even with full LMEM backup / restore it may be +desirable to keep the reset since backing up the migrate context images +must happen using memcpy() after the migrate context has become inactive, +and for performance- and other reasons we want to avoid memcpy() from +LMEM. + +Also traverse the list at guc_init_lrc_mapping() calling +guc_kernel_context_pin() for the pinned contexts, like is already done +for the kernel context. + +v2: +- Don't reset the contexts on each __engine_unpark() but rather at + resume time (Chris Wilson). +v3: +- Reset contexts in the engine sanitize callback. (Chris Wilson) + +Cc: Tvrtko Ursulin +Cc: Matthew Auld +Cc: Maarten Lankhorst +Cc: Brost Matthew +Cc: Chris Wilson +Signed-off-by: Thomas Hellström +Reviewed-by: Matthew Auld +Link: https://patchwork.freedesktop.org/patch/msgid/20210922062527.865433-6-thomas.hellstrom@linux.intel.com +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/gt/intel_context_types.h | 8 +++++++ + drivers/gpu/drm/i915/gt/intel_engine_cs.c | 4 ++++ + drivers/gpu/drm/i915/gt/intel_engine_pm.c | 23 +++++++++++++++++++ + drivers/gpu/drm/i915/gt/intel_engine_pm.h | 2 ++ + drivers/gpu/drm/i915/gt/intel_engine_types.h | 7 ++++++ + .../drm/i915/gt/intel_execlists_submission.c | 2 ++ + .../gpu/drm/i915/gt/intel_ring_submission.c | 3 +++ + drivers/gpu/drm/i915/gt/mock_engine.c | 2 ++ + .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 12 +++++++--- + 9 files changed, 60 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h +index e54351a170e2..a63631ea0ec4 100644 +--- a/drivers/gpu/drm/i915/gt/intel_context_types.h ++++ b/drivers/gpu/drm/i915/gt/intel_context_types.h +@@ -152,6 +152,14 @@ struct intel_context { + /** sseu: Control eu/slice partitioning */ + struct intel_sseu sseu; + ++ /** ++ * pinned_contexts_link: List link for the engine's pinned contexts. ++ * This is only used if this is a perma-pinned kernel context and ++ * the list is assumed to only be manipulated during driver load ++ * or unload time so no mutex protection currently. ++ */ ++ struct list_head pinned_contexts_link; ++ + u8 wa_bb_page; /* if set, page num reserved for context workarounds */ + + struct { +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c +index 0d9105a31d84..eb99441e0ada 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c +@@ -320,6 +320,7 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id) + + BUILD_BUG_ON(BITS_PER_TYPE(engine->mask) < I915_NUM_ENGINES); + ++ INIT_LIST_HEAD(&engine->pinned_contexts_list); + engine->id = id; + engine->legacy_idx = INVALID_ENGINE; + engine->mask = BIT(id); +@@ -875,6 +876,8 @@ intel_engine_create_pinned_context(struct intel_engine_cs *engine, + return ERR_PTR(err); + } + ++ list_add_tail(&ce->pinned_contexts_link, &engine->pinned_contexts_list); ++ + /* + * Give our perma-pinned kernel timelines a separate lockdep class, + * so that we can use them from within the normal user timelines +@@ -897,6 +900,7 @@ void intel_engine_destroy_pinned_context(struct intel_context *ce) + list_del(&ce->timeline->engine_link); + mutex_unlock(&hwsp->vm->mutex); + ++ list_del(&ce->pinned_contexts_link); + intel_context_unpin(ce); + intel_context_put(ce); + } +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c +index 1f07ac4e0672..dacd62773735 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c ++++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c +@@ -298,6 +298,29 @@ void intel_engine_init__pm(struct intel_engine_cs *engine) + intel_engine_init_heartbeat(engine); + } + ++/** ++ * intel_engine_reset_pinned_contexts - Reset the pinned contexts of ++ * an engine. ++ * @engine: The engine whose pinned contexts we want to reset. ++ * ++ * Typically the pinned context LMEM images lose or get their content ++ * corrupted on suspend. This function resets their images. ++ */ ++void intel_engine_reset_pinned_contexts(struct intel_engine_cs *engine) ++{ ++ struct intel_context *ce; ++ ++ list_for_each_entry(ce, &engine->pinned_contexts_list, ++ pinned_contexts_link) { ++ /* kernel context gets reset at __engine_unpark() */ ++ if (ce == engine->kernel_context) ++ continue; ++ ++ dbg_poison_ce(ce); ++ ce->ops->reset(ce); ++ } ++} ++ + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) + #include "selftest_engine_pm.c" + #endif +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h b/drivers/gpu/drm/i915/gt/intel_engine_pm.h +index 70ea46d6cfb0..8520c595f5e1 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h ++++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h +@@ -69,4 +69,6 @@ intel_engine_create_kernel_request(struct intel_engine_cs *engine) + + void intel_engine_init__pm(struct intel_engine_cs *engine); + ++void intel_engine_reset_pinned_contexts(struct intel_engine_cs *engine); ++ + #endif /* INTEL_ENGINE_PM_H */ +diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h +index ed91bcff20eb..adc44c9fac6d 100644 +--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h ++++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h +@@ -304,6 +304,13 @@ struct intel_engine_cs { + + struct intel_context *kernel_context; /* pinned */ + ++ /** ++ * pinned_contexts_list: List of pinned contexts. This list is only ++ * assumed to be manipulated during driver load- or unload time and ++ * does therefore not have any additional protection. ++ */ ++ struct list_head pinned_contexts_list; ++ + intel_engine_mask_t saturated; /* submitting semaphores too late? */ + + struct { +diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +index cafb0608ffb4..416f5e0657f0 100644 +--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c ++++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +@@ -2787,6 +2787,8 @@ static void execlists_sanitize(struct intel_engine_cs *engine) + + /* And scrub the dirty cachelines for the HWSP */ + clflush_cache_range(engine->status_page.addr, PAGE_SIZE); ++ ++ intel_engine_reset_pinned_contexts(engine); + } + + static void enable_error_interrupt(struct intel_engine_cs *engine) +diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c +index 2958e2fae380..6f2f6ba87397 100644 +--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c ++++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c +@@ -17,6 +17,7 @@ + #include "intel_ring.h" + #include "shmem_utils.h" + #include "intel_engine_heartbeat.h" ++#include "intel_engine_pm.h" + + /* Rough estimate of the typical request size, performing a flush, + * set-context and then emitting the batch. +@@ -292,6 +293,8 @@ static void xcs_sanitize(struct intel_engine_cs *engine) + + /* And scrub the dirty cachelines for the HWSP */ + clflush_cache_range(engine->status_page.addr, PAGE_SIZE); ++ ++ intel_engine_reset_pinned_contexts(engine); + } + + static void reset_prepare(struct intel_engine_cs *engine) +diff --git a/drivers/gpu/drm/i915/gt/mock_engine.c b/drivers/gpu/drm/i915/gt/mock_engine.c +index 2c1af030310c..8b89215afe46 100644 +--- a/drivers/gpu/drm/i915/gt/mock_engine.c ++++ b/drivers/gpu/drm/i915/gt/mock_engine.c +@@ -376,6 +376,8 @@ int mock_engine_init(struct intel_engine_cs *engine) + { + struct intel_context *ce; + ++ INIT_LIST_HEAD(&engine->pinned_contexts_list); ++ + engine->sched_engine = i915_sched_engine_create(ENGINE_MOCK); + if (!engine->sched_engine) + return -ENOMEM; +diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +index 93c9de8f43e8..6e09a1cca37b 100644 +--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c ++++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +@@ -2347,6 +2347,8 @@ static void guc_sanitize(struct intel_engine_cs *engine) + + /* And scrub the dirty cachelines for the HWSP */ + clflush_cache_range(engine->status_page.addr, PAGE_SIZE); ++ ++ intel_engine_reset_pinned_contexts(engine); + } + + static void setup_hwsp(struct intel_engine_cs *engine) +@@ -2422,9 +2424,13 @@ static inline void guc_init_lrc_mapping(struct intel_guc *guc) + * and even it did this code would be run again. + */ + +- for_each_engine(engine, gt, id) +- if (engine->kernel_context) +- guc_kernel_context_pin(guc, engine->kernel_context); ++ for_each_engine(engine, gt, id) { ++ struct intel_context *ce; ++ ++ list_for_each_entry(ce, &engine->pinned_contexts_list, ++ pinned_contexts_link) ++ guc_kernel_context_pin(guc, ce); ++ } + } + + static void guc_release(struct intel_engine_cs *engine) +-- +2.35.1 + diff --git a/queue-5.15/drm-i915-replace-the-unconditional-clflush-with-drm_.patch b/queue-5.15/drm-i915-replace-the-unconditional-clflush-with-drm_.patch new file mode 100644 index 00000000000..4f98355151b --- /dev/null +++ b/queue-5.15/drm-i915-replace-the-unconditional-clflush-with-drm_.patch @@ -0,0 +1,50 @@ +From 2ffa1c26e9b351e188d9dc2dbd2805b403ca69ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Oct 2021 12:09:38 +0300 +Subject: drm/i915: Replace the unconditional clflush with + drm_clflush_virt_range() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit ef7ec41f17cbc0861891ccc0634d06a0c8dcbf09 ] + +Not all machines have clflush, so don't go assuming they do. +Not really sure why the clflush is even here since hwsp +is supposed to get snooped I thought. + +Although in my case we're talking about a i830 machine where +render/blitter snooping is definitely busted. But it might +work for the hswp perhaps. Haven't really reverse engineered +that one fully. + +Cc: stable@vger.kernel.org +Cc: Chris Wilson +Cc: Mika Kuoppala +Fixes: b436a5f8b6c8 ("drm/i915/gt: Track all timelines created using the HWSP") +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20211014090941.12159-2-ville.syrjala@linux.intel.com +Reviewed-by: Dave Airlie +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/gt/intel_ring_submission.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/gt/intel_ring_submission.c b/drivers/gpu/drm/i915/gt/intel_ring_submission.c +index 6f2f6ba87397..02e18e70c78e 100644 +--- a/drivers/gpu/drm/i915/gt/intel_ring_submission.c ++++ b/drivers/gpu/drm/i915/gt/intel_ring_submission.c +@@ -292,7 +292,7 @@ static void xcs_sanitize(struct intel_engine_cs *engine) + sanitize_hwsp(engine); + + /* And scrub the dirty cachelines for the HWSP */ +- clflush_cache_range(engine->status_page.addr, PAGE_SIZE); ++ drm_clflush_virt_range(engine->status_page.addr, PAGE_SIZE); + + intel_engine_reset_pinned_contexts(engine); + } +-- +2.35.1 + diff --git a/queue-5.15/drm-mediatek-add-cmdq_handle-in-mtk_crtc.patch b/queue-5.15/drm-mediatek-add-cmdq_handle-in-mtk_crtc.patch new file mode 100644 index 00000000000..7f166b8423d --- /dev/null +++ b/queue-5.15/drm-mediatek-add-cmdq_handle-in-mtk_crtc.patch @@ -0,0 +1,140 @@ +From c29768e62291d544a0a5302b93ff7327f4c21fa3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Oct 2021 18:19:10 +0800 +Subject: drm/mediatek: Add cmdq_handle in mtk_crtc + +From: Chun-Kuang Hu + +[ Upstream commit 7627122fd1c06800a1fe624e9fb3c269796115e8 ] + +One mtk_crtc need just one cmdq_handle, so add one cmdq_handle +in mtk_crtc to prevent frequently allocation and free of +cmdq_handle. + +Signed-off-by: Chun-Kuang Hu +Signed-off-by: jason-jh.lin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 62 +++++++++++++++++++++++-- + 1 file changed, 57 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +index dad1f85ee315..ffa54b416ca7 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +@@ -53,6 +53,7 @@ struct mtk_drm_crtc { + + #if IS_REACHABLE(CONFIG_MTK_CMDQ) + struct cmdq_client cmdq_client; ++ struct cmdq_pkt cmdq_handle; + u32 cmdq_event; + u32 cmdq_vblank_cnt; + #endif +@@ -107,12 +108,55 @@ static void mtk_drm_finish_page_flip(struct mtk_drm_crtc *mtk_crtc) + } + } + ++#if IS_REACHABLE(CONFIG_MTK_CMDQ) ++static int mtk_drm_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, ++ size_t size) ++{ ++ struct device *dev; ++ dma_addr_t dma_addr; ++ ++ pkt->va_base = kzalloc(size, GFP_KERNEL); ++ if (!pkt->va_base) { ++ kfree(pkt); ++ return -ENOMEM; ++ } ++ pkt->buf_size = size; ++ pkt->cl = (void *)client; ++ ++ dev = client->chan->mbox->dev; ++ dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, dma_addr)) { ++ dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); ++ kfree(pkt->va_base); ++ kfree(pkt); ++ return -ENOMEM; ++ } ++ ++ pkt->pa_base = dma_addr; ++ ++ return 0; ++} ++ ++static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt) ++{ ++ struct cmdq_client *client = (struct cmdq_client *)pkt->cl; ++ ++ dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, ++ DMA_TO_DEVICE); ++ kfree(pkt->va_base); ++ kfree(pkt); ++} ++#endif ++ + static void mtk_drm_crtc_destroy(struct drm_crtc *crtc) + { + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); + + mtk_mutex_put(mtk_crtc->mutex); +- ++#if IS_REACHABLE(CONFIG_MTK_CMDQ) ++ mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle); ++#endif + drm_crtc_cleanup(crtc); + } + +@@ -227,12 +271,10 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc, + #if IS_REACHABLE(CONFIG_MTK_CMDQ) + static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) + { +- struct cmdq_cb_data *data = mssg; + struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client); + struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client); + + mtk_crtc->cmdq_vblank_cnt = 0; +- cmdq_pkt_destroy(data->pkt); + } + #endif + +@@ -438,7 +480,7 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, + bool needs_vblank) + { + #if IS_REACHABLE(CONFIG_MTK_CMDQ) +- struct cmdq_pkt *cmdq_handle; ++ struct cmdq_pkt *cmdq_handle = &mtk_crtc->cmdq_handle; + #endif + struct drm_crtc *crtc = &mtk_crtc->base; + struct mtk_drm_private *priv = crtc->dev->dev_private; +@@ -478,7 +520,7 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, + #if IS_REACHABLE(CONFIG_MTK_CMDQ) + if (mtk_crtc->cmdq_client.chan) { + mbox_flush(mtk_crtc->cmdq_client.chan, 2000); +- cmdq_handle = cmdq_pkt_create(&mtk_crtc->cmdq_client, PAGE_SIZE); ++ cmdq_handle->cmd_buf_size = 0; + cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event); + cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false); + mtk_crtc_ddp_config(crtc, cmdq_handle); +@@ -877,6 +919,16 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, + drm_crtc_index(&mtk_crtc->base)); + mbox_free_channel(mtk_crtc->cmdq_client.chan); + mtk_crtc->cmdq_client.chan = NULL; ++ } else { ++ ret = mtk_drm_cmdq_pkt_create(&mtk_crtc->cmdq_client, ++ &mtk_crtc->cmdq_handle, ++ PAGE_SIZE); ++ if (ret) { ++ dev_dbg(dev, "mtk_crtc %d failed to create cmdq packet\n", ++ drm_crtc_index(&mtk_crtc->base)); ++ mbox_free_channel(mtk_crtc->cmdq_client.chan); ++ mtk_crtc->cmdq_client.chan = NULL; ++ } + } + } + #endif +-- +2.35.1 + diff --git a/queue-5.15/drm-mediatek-add-vblank-register-unregister-callback.patch b/queue-5.15/drm-mediatek-add-vblank-register-unregister-callback.patch new file mode 100644 index 00000000000..07b4d0a0ee6 --- /dev/null +++ b/queue-5.15/drm-mediatek-add-vblank-register-unregister-callback.patch @@ -0,0 +1,275 @@ +From ccb25dd2f399e9ece9cbe5d484777ce1b585caa2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Mar 2022 15:23:20 +0800 +Subject: drm/mediatek: Add vblank register/unregister callback functions + +From: Rex-BC Chen + +[ Upstream commit b74d921b900b6ce38c6247c0a1c86be9f3746493 ] + +We encountered a kernel panic issue that callback data will be NULL when +it's using in ovl irq handler. There is a timing issue between +mtk_disp_ovl_irq_handler() and mtk_ovl_disable_vblank(). + +To resolve this issue, we use the flow to register/unregister vblank cb: +- Register callback function and callback data when crtc creates. +- Unregister callback function and callback data when crtc destroies. + +With this solution, we can assure callback data will not be NULL when +vblank is disable. + +Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20220321072320.15019-1-rex-bc.chen@mediatek.com/ +Fixes: 9b0704988b15 ("drm/mediatek: Register vblank callback function") +Signed-off-by: Rex-BC Chen +Reviewed-by: jason-jh.lin +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_disp_drv.h | 16 +++++++----- + drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 22 ++++++++++++---- + drivers/gpu/drm/mediatek/mtk_disp_rdma.c | 20 +++++++++----- + drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 14 +++++++++- + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 4 +++ + drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 29 ++++++++++++++++----- + 6 files changed, 80 insertions(+), 25 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h +index 86c3068894b1..974462831133 100644 +--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h ++++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h +@@ -76,9 +76,11 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx, + void mtk_ovl_start(struct device *dev); + void mtk_ovl_stop(struct device *dev); + unsigned int mtk_ovl_supported_rotations(struct device *dev); +-void mtk_ovl_enable_vblank(struct device *dev, +- void (*vblank_cb)(void *), +- void *vblank_cb_data); ++void mtk_ovl_register_vblank_cb(struct device *dev, ++ void (*vblank_cb)(void *), ++ void *vblank_cb_data); ++void mtk_ovl_unregister_vblank_cb(struct device *dev); ++void mtk_ovl_enable_vblank(struct device *dev); + void mtk_ovl_disable_vblank(struct device *dev); + + void mtk_rdma_bypass_shadow(struct device *dev); +@@ -93,9 +95,11 @@ void mtk_rdma_layer_config(struct device *dev, unsigned int idx, + struct cmdq_pkt *cmdq_pkt); + void mtk_rdma_start(struct device *dev); + void mtk_rdma_stop(struct device *dev); +-void mtk_rdma_enable_vblank(struct device *dev, +- void (*vblank_cb)(void *), +- void *vblank_cb_data); ++void mtk_rdma_register_vblank_cb(struct device *dev, ++ void (*vblank_cb)(void *), ++ void *vblank_cb_data); ++void mtk_rdma_unregister_vblank_cb(struct device *dev); ++void mtk_rdma_enable_vblank(struct device *dev); + void mtk_rdma_disable_vblank(struct device *dev); + + #endif +diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +index 5326989d5206..411cf0f21661 100644 +--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c ++++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +@@ -96,14 +96,28 @@ static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id) + return IRQ_HANDLED; + } + +-void mtk_ovl_enable_vblank(struct device *dev, +- void (*vblank_cb)(void *), +- void *vblank_cb_data) ++void mtk_ovl_register_vblank_cb(struct device *dev, ++ void (*vblank_cb)(void *), ++ void *vblank_cb_data) + { + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); + + ovl->vblank_cb = vblank_cb; + ovl->vblank_cb_data = vblank_cb_data; ++} ++ ++void mtk_ovl_unregister_vblank_cb(struct device *dev) ++{ ++ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); ++ ++ ovl->vblank_cb = NULL; ++ ovl->vblank_cb_data = NULL; ++} ++ ++void mtk_ovl_enable_vblank(struct device *dev) ++{ ++ struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); ++ + writel(0x0, ovl->regs + DISP_REG_OVL_INTSTA); + writel_relaxed(OVL_FME_CPL_INT, ovl->regs + DISP_REG_OVL_INTEN); + } +@@ -112,8 +126,6 @@ void mtk_ovl_disable_vblank(struct device *dev) + { + struct mtk_disp_ovl *ovl = dev_get_drvdata(dev); + +- ovl->vblank_cb = NULL; +- ovl->vblank_cb_data = NULL; + writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN); + } + +diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c +index 75d7f45579e2..a6a6cb5f75af 100644 +--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c ++++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c +@@ -94,24 +94,32 @@ static void rdma_update_bits(struct device *dev, unsigned int reg, + writel(tmp, rdma->regs + reg); + } + +-void mtk_rdma_enable_vblank(struct device *dev, +- void (*vblank_cb)(void *), +- void *vblank_cb_data) ++void mtk_rdma_register_vblank_cb(struct device *dev, ++ void (*vblank_cb)(void *), ++ void *vblank_cb_data) + { + struct mtk_disp_rdma *rdma = dev_get_drvdata(dev); + + rdma->vblank_cb = vblank_cb; + rdma->vblank_cb_data = vblank_cb_data; +- rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, +- RDMA_FRAME_END_INT); + } + +-void mtk_rdma_disable_vblank(struct device *dev) ++void mtk_rdma_unregister_vblank_cb(struct device *dev) + { + struct mtk_disp_rdma *rdma = dev_get_drvdata(dev); + + rdma->vblank_cb = NULL; + rdma->vblank_cb_data = NULL; ++} ++ ++void mtk_rdma_enable_vblank(struct device *dev) ++{ ++ rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, ++ RDMA_FRAME_END_INT); ++} ++ ++void mtk_rdma_disable_vblank(struct device *dev) ++{ + rdma_update_bits(dev, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0); + } + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +index ffa54b416ca7..34bb6c713a90 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +@@ -152,11 +152,20 @@ static void mtk_drm_cmdq_pkt_destroy(struct cmdq_pkt *pkt) + static void mtk_drm_crtc_destroy(struct drm_crtc *crtc) + { + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); ++ int i; + + mtk_mutex_put(mtk_crtc->mutex); + #if IS_REACHABLE(CONFIG_MTK_CMDQ) + mtk_drm_cmdq_pkt_destroy(&mtk_crtc->cmdq_handle); + #endif ++ ++ for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) { ++ struct mtk_ddp_comp *comp; ++ ++ comp = mtk_crtc->ddp_comp[i]; ++ mtk_ddp_comp_unregister_vblank_cb(comp); ++ } ++ + drm_crtc_cleanup(crtc); + } + +@@ -570,7 +579,7 @@ static int mtk_drm_crtc_enable_vblank(struct drm_crtc *crtc) + struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); + struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; + +- mtk_ddp_comp_enable_vblank(comp, mtk_crtc_ddp_irq, &mtk_crtc->base); ++ mtk_ddp_comp_enable_vblank(comp); + + return 0; + } +@@ -870,6 +879,9 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, + if (comp->funcs->ctm_set) + has_ctm = true; + } ++ ++ mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq, ++ &mtk_crtc->base); + } + + for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +index 99cbf44463e4..22d23668b484 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +@@ -276,6 +276,8 @@ static const struct mtk_ddp_comp_funcs ddp_ovl = { + .config = mtk_ovl_config, + .start = mtk_ovl_start, + .stop = mtk_ovl_stop, ++ .register_vblank_cb = mtk_ovl_register_vblank_cb, ++ .unregister_vblank_cb = mtk_ovl_unregister_vblank_cb, + .enable_vblank = mtk_ovl_enable_vblank, + .disable_vblank = mtk_ovl_disable_vblank, + .supported_rotations = mtk_ovl_supported_rotations, +@@ -292,6 +294,8 @@ static const struct mtk_ddp_comp_funcs ddp_rdma = { + .config = mtk_rdma_config, + .start = mtk_rdma_start, + .stop = mtk_rdma_stop, ++ .register_vblank_cb = mtk_rdma_register_vblank_cb, ++ .unregister_vblank_cb = mtk_rdma_unregister_vblank_cb, + .enable_vblank = mtk_rdma_enable_vblank, + .disable_vblank = mtk_rdma_disable_vblank, + .layer_nr = mtk_rdma_layer_nr, +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +index bb914d976cf5..25cb50f2391f 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h ++++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +@@ -47,9 +47,11 @@ struct mtk_ddp_comp_funcs { + unsigned int bpc, struct cmdq_pkt *cmdq_pkt); + void (*start)(struct device *dev); + void (*stop)(struct device *dev); +- void (*enable_vblank)(struct device *dev, +- void (*vblank_cb)(void *), +- void *vblank_cb_data); ++ void (*register_vblank_cb)(struct device *dev, ++ void (*vblank_cb)(void *), ++ void *vblank_cb_data); ++ void (*unregister_vblank_cb)(struct device *dev); ++ void (*enable_vblank)(struct device *dev); + void (*disable_vblank)(struct device *dev); + unsigned int (*supported_rotations)(struct device *dev); + unsigned int (*layer_nr)(struct device *dev); +@@ -110,12 +112,25 @@ static inline void mtk_ddp_comp_stop(struct mtk_ddp_comp *comp) + comp->funcs->stop(comp->dev); + } + +-static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp, +- void (*vblank_cb)(void *), +- void *vblank_cb_data) ++static inline void mtk_ddp_comp_register_vblank_cb(struct mtk_ddp_comp *comp, ++ void (*vblank_cb)(void *), ++ void *vblank_cb_data) ++{ ++ if (comp->funcs && comp->funcs->register_vblank_cb) ++ comp->funcs->register_vblank_cb(comp->dev, vblank_cb, ++ vblank_cb_data); ++} ++ ++static inline void mtk_ddp_comp_unregister_vblank_cb(struct mtk_ddp_comp *comp) ++{ ++ if (comp->funcs && comp->funcs->unregister_vblank_cb) ++ comp->funcs->unregister_vblank_cb(comp->dev); ++} ++ ++static inline void mtk_ddp_comp_enable_vblank(struct mtk_ddp_comp *comp) + { + if (comp->funcs && comp->funcs->enable_vblank) +- comp->funcs->enable_vblank(comp->dev, vblank_cb, vblank_cb_data); ++ comp->funcs->enable_vblank(comp->dev); + } + + static inline void mtk_ddp_comp_disable_vblank(struct mtk_ddp_comp *comp) +-- +2.35.1 + diff --git a/queue-5.15/drm-mediatek-detect-cmdq-execution-timeout.patch b/queue-5.15/drm-mediatek-detect-cmdq-execution-timeout.patch new file mode 100644 index 00000000000..d38d40883be --- /dev/null +++ b/queue-5.15/drm-mediatek-detect-cmdq-execution-timeout.patch @@ -0,0 +1,81 @@ +From e00118f8bbf5550fc398d49351084f1d9cd2726b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Oct 2021 10:18:54 +0800 +Subject: drm/mediatek: Detect CMDQ execution timeout + +From: Chun-Kuang Hu + +[ Upstream commit eaf80126aba6fd1754837eec91e4c8bbd58ae52e ] + +CMDQ is used to update display register in vblank period, so +it should be execute in next 2 vblank. One vblank interrupt +before send message (occasionally) and one vblank interrupt +after cmdq done. If it fail to execute in next 3 vblank, +tiemout happen. + +Signed-off-by: Chun-Kuang Hu +Signed-off-by: jason-jh.lin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +index e23e3224ac67..dad1f85ee315 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +@@ -54,6 +54,7 @@ struct mtk_drm_crtc { + #if IS_REACHABLE(CONFIG_MTK_CMDQ) + struct cmdq_client cmdq_client; + u32 cmdq_event; ++ u32 cmdq_vblank_cnt; + #endif + + struct device *mmsys_dev; +@@ -227,7 +228,10 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc, + static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) + { + struct cmdq_cb_data *data = mssg; ++ struct cmdq_client *cmdq_cl = container_of(cl, struct cmdq_client, client); ++ struct mtk_drm_crtc *mtk_crtc = container_of(cmdq_cl, struct mtk_drm_crtc, cmdq_client); + ++ mtk_crtc->cmdq_vblank_cnt = 0; + cmdq_pkt_destroy(data->pkt); + } + #endif +@@ -483,6 +487,15 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, + cmdq_handle->pa_base, + cmdq_handle->cmd_buf_size, + DMA_TO_DEVICE); ++ /* ++ * CMDQ command should execute in next 3 vblank. ++ * One vblank interrupt before send message (occasionally) ++ * and one vblank interrupt after cmdq done, ++ * so it's timeout after 3 vblank interrupt. ++ * If it fail to execute in next 3 vblank, timeout happen. ++ */ ++ mtk_crtc->cmdq_vblank_cnt = 3; ++ + mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle); + mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0); + } +@@ -499,11 +512,14 @@ static void mtk_crtc_ddp_irq(void *data) + + #if IS_REACHABLE(CONFIG_MTK_CMDQ) + if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan) ++ mtk_crtc_ddp_config(crtc, NULL); ++ else if (mtk_crtc->cmdq_vblank_cnt > 0 && --mtk_crtc->cmdq_vblank_cnt == 0) ++ DRM_ERROR("mtk_crtc %d CMDQ execute command timeout!\n", ++ drm_crtc_index(&mtk_crtc->base)); + #else + if (!priv->data->shadow_register) +-#endif + mtk_crtc_ddp_config(crtc, NULL); +- ++#endif + mtk_drm_finish_page_flip(mtk_crtc); + } + +-- +2.35.1 + diff --git a/queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch b/queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch new file mode 100644 index 00000000000..1ac10068000 --- /dev/null +++ b/queue-5.15/drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch @@ -0,0 +1,268 @@ +From 70db39b21100039062b6e3703491a3fb9c0bb3e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Jan 2022 09:55:20 +0100 +Subject: drm/mediatek: mtk_dsi: Avoid EPROBE_DEFER loop with external bridge +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: AngeloGioacchino Del Regno + +[ Upstream commit 647474b8d980256b26b1cd112d7333a4dbd4260a ] + +DRM bridge drivers are now attaching their DSI device at probe time, +which requires us to register our DSI host in order to let the bridge +to probe: this recently started producing an endless -EPROBE_DEFER +loop on some machines that are using external bridges, like the +parade-ps8640, found on the ACER Chromebook R13. + +Now that the DSI hosts/devices probe sequence is documented, we can +do adjustments to the mtk_dsi driver as to both fix now and make sure +to avoid this situation in the future: for this, following what is +documented in drm_bridge.c, move the mtk_dsi component_add() to the +mtk_dsi_ops.attach callback and delete it in the detach callback; +keeping in mind that we are registering a drm_bridge for our DSI, +which is only used/attached if the DSI Host is bound, it wouldn't +make sense to keep adding our bridge at probe time (as it would +be useless to have it if mtk_dsi_ops.attach() fails!), so also move +that one to the dsi host attach function (and remove it in detach). + +Cc: # 5.15.x +Signed-off-by: AngeloGioacchino Del Regno +Reviewed-by: Andrzej Hajda +Reviewed-by: Jagan Teki +Tested-by: Nícolas F. R. A. Prado +Signed-off-by: Chun-Kuang Hu +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_dsi.c | 167 +++++++++++++++-------------- + 1 file changed, 84 insertions(+), 83 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c +index 5d90d2eb0019..bced4c7d668e 100644 +--- a/drivers/gpu/drm/mediatek/mtk_dsi.c ++++ b/drivers/gpu/drm/mediatek/mtk_dsi.c +@@ -786,18 +786,101 @@ void mtk_dsi_ddp_stop(struct device *dev) + mtk_dsi_poweroff(dsi); + } + ++static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) ++{ ++ int ret; ++ ++ ret = drm_simple_encoder_init(drm, &dsi->encoder, ++ DRM_MODE_ENCODER_DSI); ++ if (ret) { ++ DRM_ERROR("Failed to encoder init to drm\n"); ++ return ret; ++ } ++ ++ dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev); ++ ++ ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, ++ DRM_BRIDGE_ATTACH_NO_CONNECTOR); ++ if (ret) ++ goto err_cleanup_encoder; ++ ++ dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder); ++ if (IS_ERR(dsi->connector)) { ++ DRM_ERROR("Unable to create bridge connector\n"); ++ ret = PTR_ERR(dsi->connector); ++ goto err_cleanup_encoder; ++ } ++ drm_connector_attach_encoder(dsi->connector, &dsi->encoder); ++ ++ return 0; ++ ++err_cleanup_encoder: ++ drm_encoder_cleanup(&dsi->encoder); ++ return ret; ++} ++ ++static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) ++{ ++ int ret; ++ struct drm_device *drm = data; ++ struct mtk_dsi *dsi = dev_get_drvdata(dev); ++ ++ ret = mtk_dsi_encoder_init(drm, dsi); ++ if (ret) ++ return ret; ++ ++ return device_reset_optional(dev); ++} ++ ++static void mtk_dsi_unbind(struct device *dev, struct device *master, ++ void *data) ++{ ++ struct mtk_dsi *dsi = dev_get_drvdata(dev); ++ ++ drm_encoder_cleanup(&dsi->encoder); ++} ++ ++static const struct component_ops mtk_dsi_component_ops = { ++ .bind = mtk_dsi_bind, ++ .unbind = mtk_dsi_unbind, ++}; ++ + static int mtk_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) + { + struct mtk_dsi *dsi = host_to_dsi(host); ++ struct device *dev = host->dev; ++ int ret; + + dsi->lanes = device->lanes; + dsi->format = device->format; + dsi->mode_flags = device->mode_flags; ++ dsi->next_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0); ++ if (IS_ERR(dsi->next_bridge)) ++ return PTR_ERR(dsi->next_bridge); ++ ++ drm_bridge_add(&dsi->bridge); ++ ++ ret = component_add(host->dev, &mtk_dsi_component_ops); ++ if (ret) { ++ DRM_ERROR("failed to add dsi_host component: %d\n", ret); ++ drm_bridge_remove(&dsi->bridge); ++ return ret; ++ } + + return 0; + } + ++static int mtk_dsi_host_detach(struct mipi_dsi_host *host, ++ struct mipi_dsi_device *device) ++{ ++ struct mtk_dsi *dsi = host_to_dsi(host); ++ ++ component_del(host->dev, &mtk_dsi_component_ops); ++ drm_bridge_remove(&dsi->bridge); ++ return 0; ++} ++ + static void mtk_dsi_wait_for_idle(struct mtk_dsi *dsi) + { + int ret; +@@ -938,73 +1021,14 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host, + + static const struct mipi_dsi_host_ops mtk_dsi_ops = { + .attach = mtk_dsi_host_attach, ++ .detach = mtk_dsi_host_detach, + .transfer = mtk_dsi_host_transfer, + }; + +-static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi) +-{ +- int ret; +- +- ret = drm_simple_encoder_init(drm, &dsi->encoder, +- DRM_MODE_ENCODER_DSI); +- if (ret) { +- DRM_ERROR("Failed to encoder init to drm\n"); +- return ret; +- } +- +- dsi->encoder.possible_crtcs = mtk_drm_find_possible_crtc_by_comp(drm, dsi->host.dev); +- +- ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, +- DRM_BRIDGE_ATTACH_NO_CONNECTOR); +- if (ret) +- goto err_cleanup_encoder; +- +- dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder); +- if (IS_ERR(dsi->connector)) { +- DRM_ERROR("Unable to create bridge connector\n"); +- ret = PTR_ERR(dsi->connector); +- goto err_cleanup_encoder; +- } +- drm_connector_attach_encoder(dsi->connector, &dsi->encoder); +- +- return 0; +- +-err_cleanup_encoder: +- drm_encoder_cleanup(&dsi->encoder); +- return ret; +-} +- +-static int mtk_dsi_bind(struct device *dev, struct device *master, void *data) +-{ +- int ret; +- struct drm_device *drm = data; +- struct mtk_dsi *dsi = dev_get_drvdata(dev); +- +- ret = mtk_dsi_encoder_init(drm, dsi); +- if (ret) +- return ret; +- +- return device_reset_optional(dev); +-} +- +-static void mtk_dsi_unbind(struct device *dev, struct device *master, +- void *data) +-{ +- struct mtk_dsi *dsi = dev_get_drvdata(dev); +- +- drm_encoder_cleanup(&dsi->encoder); +-} +- +-static const struct component_ops mtk_dsi_component_ops = { +- .bind = mtk_dsi_bind, +- .unbind = mtk_dsi_unbind, +-}; +- + static int mtk_dsi_probe(struct platform_device *pdev) + { + struct mtk_dsi *dsi; + struct device *dev = &pdev->dev; +- struct drm_panel *panel; + struct resource *regs; + int irq_num; + int ret; +@@ -1021,19 +1045,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) + return ret; + } + +- ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, +- &panel, &dsi->next_bridge); +- if (ret) +- goto err_unregister_host; +- +- if (panel) { +- dsi->next_bridge = devm_drm_panel_bridge_add(dev, panel); +- if (IS_ERR(dsi->next_bridge)) { +- ret = PTR_ERR(dsi->next_bridge); +- goto err_unregister_host; +- } +- } +- + dsi->driver_data = of_device_get_match_data(dev); + + dsi->engine_clk = devm_clk_get(dev, "engine"); +@@ -1098,14 +1109,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) + dsi->bridge.of_node = dev->of_node; + dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; + +- drm_bridge_add(&dsi->bridge); +- +- ret = component_add(&pdev->dev, &mtk_dsi_component_ops); +- if (ret) { +- dev_err(&pdev->dev, "failed to add component: %d\n", ret); +- goto err_unregister_host; +- } +- + return 0; + + err_unregister_host: +@@ -1118,8 +1121,6 @@ static int mtk_dsi_remove(struct platform_device *pdev) + struct mtk_dsi *dsi = platform_get_drvdata(pdev); + + mtk_output_dsi_disable(dsi); +- drm_bridge_remove(&dsi->bridge); +- component_del(&pdev->dev, &mtk_dsi_component_ops); + mipi_dsi_host_unregister(&dsi->host); + + return 0; +-- +2.35.1 + diff --git a/queue-5.15/drm-mediatek-remove-the-pointer-of-struct-cmdq_clien.patch b/queue-5.15/drm-mediatek-remove-the-pointer-of-struct-cmdq_clien.patch new file mode 100644 index 00000000000..8f3704dfafc --- /dev/null +++ b/queue-5.15/drm-mediatek-remove-the-pointer-of-struct-cmdq_clien.patch @@ -0,0 +1,131 @@ +From 1c9bd99353e173a96fd2eb4f3ffd9516ba08add5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Oct 2021 18:19:08 +0800 +Subject: drm/mediatek: Remove the pointer of struct cmdq_client + +From: Chun-Kuang Hu + +[ Upstream commit 563c9d4a5b117552150efbecbaf0877947e98a32 ] + +In mailbox rx_callback, it pass struct mbox_client to callback +function, but it could not map back to mtk_drm_crtc instance +because struct cmdq_client use a pointer to struct mbox_client: + +struct cmdq_client { + struct mbox_client client; + struct mbox_chan *chan; +}; + +struct mtk_drm_crtc { + /* client instance data */ + struct cmdq_client *cmdq_client; +}; + +so remove the pointer of struct cmdq_client and let mtk_drm_crtc +instance define cmdq_client as: + +struct mtk_drm_crtc { + /* client instance data */ + struct cmdq_client cmdq_client; +}; + +and in rx_callback function, use struct mbox_client to get +struct mtk_drm_crtc. + +Signed-off-by: Chun-Kuang Hu +Signed-off-by: jason-jh.lin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 37 +++++++++++++------------ + 1 file changed, 20 insertions(+), 17 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +index 369d3e68c0b6..e23e3224ac67 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +@@ -52,7 +52,7 @@ struct mtk_drm_crtc { + bool pending_async_planes; + + #if IS_REACHABLE(CONFIG_MTK_CMDQ) +- struct cmdq_client *cmdq_client; ++ struct cmdq_client cmdq_client; + u32 cmdq_event; + #endif + +@@ -472,19 +472,19 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, + mtk_mutex_release(mtk_crtc->mutex); + } + #if IS_REACHABLE(CONFIG_MTK_CMDQ) +- if (mtk_crtc->cmdq_client) { +- mbox_flush(mtk_crtc->cmdq_client->chan, 2000); +- cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE); ++ if (mtk_crtc->cmdq_client.chan) { ++ mbox_flush(mtk_crtc->cmdq_client.chan, 2000); ++ cmdq_handle = cmdq_pkt_create(&mtk_crtc->cmdq_client, PAGE_SIZE); + cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event); + cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false); + mtk_crtc_ddp_config(crtc, cmdq_handle); + cmdq_pkt_finalize(cmdq_handle); +- dma_sync_single_for_device(mtk_crtc->cmdq_client->chan->mbox->dev, ++ dma_sync_single_for_device(mtk_crtc->cmdq_client.chan->mbox->dev, + cmdq_handle->pa_base, + cmdq_handle->cmd_buf_size, + DMA_TO_DEVICE); +- mbox_send_message(mtk_crtc->cmdq_client->chan, cmdq_handle); +- mbox_client_txdone(mtk_crtc->cmdq_client->chan, 0); ++ mbox_send_message(mtk_crtc->cmdq_client.chan, cmdq_handle); ++ mbox_client_txdone(mtk_crtc->cmdq_client.chan, 0); + } + #endif + mtk_crtc->config_updating = false; +@@ -498,7 +498,7 @@ static void mtk_crtc_ddp_irq(void *data) + struct mtk_drm_private *priv = crtc->dev->dev_private; + + #if IS_REACHABLE(CONFIG_MTK_CMDQ) +- if (!priv->data->shadow_register && !mtk_crtc->cmdq_client) ++ if (!priv->data->shadow_register && !mtk_crtc->cmdq_client.chan) + #else + if (!priv->data->shadow_register) + #endif +@@ -838,17 +838,20 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, + mutex_init(&mtk_crtc->hw_lock); + + #if IS_REACHABLE(CONFIG_MTK_CMDQ) +- mtk_crtc->cmdq_client = +- cmdq_mbox_create(mtk_crtc->mmsys_dev, +- drm_crtc_index(&mtk_crtc->base)); +- if (IS_ERR(mtk_crtc->cmdq_client)) { ++ mtk_crtc->cmdq_client.client.dev = mtk_crtc->mmsys_dev; ++ mtk_crtc->cmdq_client.client.tx_block = false; ++ mtk_crtc->cmdq_client.client.knows_txdone = true; ++ mtk_crtc->cmdq_client.client.rx_callback = ddp_cmdq_cb; ++ mtk_crtc->cmdq_client.chan = ++ mbox_request_channel(&mtk_crtc->cmdq_client.client, ++ drm_crtc_index(&mtk_crtc->base)); ++ if (IS_ERR(mtk_crtc->cmdq_client.chan)) { + dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n", + drm_crtc_index(&mtk_crtc->base)); +- mtk_crtc->cmdq_client = NULL; ++ mtk_crtc->cmdq_client.chan = NULL; + } + +- if (mtk_crtc->cmdq_client) { +- mtk_crtc->cmdq_client->client.rx_callback = ddp_cmdq_cb; ++ if (mtk_crtc->cmdq_client.chan) { + ret = of_property_read_u32_index(priv->mutex_node, + "mediatek,gce-events", + drm_crtc_index(&mtk_crtc->base), +@@ -856,8 +859,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, + if (ret) { + dev_dbg(dev, "mtk_crtc %d failed to get mediatek,gce-events property\n", + drm_crtc_index(&mtk_crtc->base)); +- cmdq_mbox_destroy(mtk_crtc->cmdq_client); +- mtk_crtc->cmdq_client = NULL; ++ mbox_free_channel(mtk_crtc->cmdq_client.chan); ++ mtk_crtc->cmdq_client.chan = NULL; + } + } + #endif +-- +2.35.1 + diff --git a/queue-5.15/drm-mediatek-use-mailbox-rx_callback-instead-of-cmdq.patch b/queue-5.15/drm-mediatek-use-mailbox-rx_callback-instead-of-cmdq.patch new file mode 100644 index 00000000000..cbaaec50625 --- /dev/null +++ b/queue-5.15/drm-mediatek-use-mailbox-rx_callback-instead-of-cmdq.patch @@ -0,0 +1,72 @@ +From 84e5124774632183df77a9afcf853ce807b60f60 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Oct 2021 18:19:07 +0800 +Subject: drm/mediatek: Use mailbox rx_callback instead of cmdq_task_cb + +From: Chun-Kuang Hu + +[ Upstream commit 1ee07a683b7e4e6ad9ad4f77fce4751741bc8ceb ] + +rx_callback is a standard mailbox callback mechanism and could cover the +function of proprietary cmdq_task_cb, so use the standard one instead of +the proprietary one. + +Signed-off-by: Chun-Kuang Hu +Signed-off-by: jason-jh.lin +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +index a4e80e499674..369d3e68c0b6 100644 +--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c ++++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +@@ -4,6 +4,8 @@ + */ + + #include ++#include ++#include + #include + #include + #include +@@ -222,9 +224,11 @@ struct mtk_ddp_comp *mtk_drm_ddp_comp_for_plane(struct drm_crtc *crtc, + } + + #if IS_REACHABLE(CONFIG_MTK_CMDQ) +-static void ddp_cmdq_cb(struct cmdq_cb_data data) ++static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg) + { +- cmdq_pkt_destroy(data.data); ++ struct cmdq_cb_data *data = mssg; ++ ++ cmdq_pkt_destroy(data->pkt); + } + #endif + +@@ -475,7 +479,12 @@ static void mtk_drm_crtc_update_config(struct mtk_drm_crtc *mtk_crtc, + cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false); + mtk_crtc_ddp_config(crtc, cmdq_handle); + cmdq_pkt_finalize(cmdq_handle); +- cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle); ++ dma_sync_single_for_device(mtk_crtc->cmdq_client->chan->mbox->dev, ++ cmdq_handle->pa_base, ++ cmdq_handle->cmd_buf_size, ++ DMA_TO_DEVICE); ++ mbox_send_message(mtk_crtc->cmdq_client->chan, cmdq_handle); ++ mbox_client_txdone(mtk_crtc->cmdq_client->chan, 0); + } + #endif + mtk_crtc->config_updating = false; +@@ -839,6 +848,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, + } + + if (mtk_crtc->cmdq_client) { ++ mtk_crtc->cmdq_client->client.rx_callback = ddp_cmdq_cb; + ret = of_property_read_u32_index(priv->mutex_node, + "mediatek,gce-events", + drm_crtc_index(&mtk_crtc->base), +-- +2.35.1 + diff --git a/queue-5.15/drm-msm-dp-employ-bridge-mechanism-for-display-enabl.patch b/queue-5.15/drm-msm-dp-employ-bridge-mechanism-for-display-enabl.patch new file mode 100644 index 00000000000..fc6ba93b9bb --- /dev/null +++ b/queue-5.15/drm-msm-dp-employ-bridge-mechanism-for-display-enabl.patch @@ -0,0 +1,270 @@ +From 41d3abef580d693a38c7b7c5b130fa7412d97f86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 15:15:33 -0800 +Subject: drm/msm/dp: employ bridge mechanism for display enable and disable + +From: Kuogee Hsieh + +[ Upstream commit 8a3b4c17f863cde8e8743edd8faffe916c49b960 ] + +Currently the msm_dp_*** functions implement the same sequence which would +happen when drm_bridge is used. hence get rid of this intermediate layer +and align with the drm_bridge usage to avoid customized implementation. + +Signed-off-by: Kuogee Hsieh + +Changes in v2: +-- revise commit text +-- rename dp_bridge to msm_dp_bridge +-- delete empty functions + +Changes in v3: +-- replace kzalloc() with devm_kzalloc() +-- replace __dp_display_enable() with dp_display_enable() +-- replace __dp_display_disable() with dp_display_disable() + +Changes in v4: +-- msm_dp_bridge_init() called from msm_dp_modeset_init() same as dsi + +Changes in v5: +-- delete attach, mode_fixup and pre_enable from dp_bridge_ops + +Changes in v6: +-- rebase on msm-next-plus-fixes branch + +Signed-off-by: Kuogee Hsieh +Reviewed-by: Abhinav Kumar +Link: https://lore.kernel.org/r/1638918933-2544-1-git-send-email-quic_khsieh@quicinc.com +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 21 ------ + drivers/gpu/drm/msm/dp/dp_display.c | 16 ++++- + drivers/gpu/drm/msm/dp/dp_display.h | 1 + + drivers/gpu/drm/msm/dp/dp_drm.c | 76 +++++++++++++++++++++ + drivers/gpu/drm/msm/msm_drv.h | 12 ++-- + 5 files changed, 99 insertions(+), 27 deletions(-) + +diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +index 5f236395677e..119a1f5766fb 100644 +--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c ++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +@@ -1003,9 +1003,6 @@ static void dpu_encoder_virt_mode_set(struct drm_encoder *drm_enc, + + trace_dpu_enc_mode_set(DRMID(drm_enc)); + +- if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) +- msm_dp_display_mode_set(dpu_enc->dp, drm_enc, mode, adj_mode); +- + list_for_each_entry(conn_iter, connector_list, head) + if (conn_iter->encoder == drm_enc) + conn = conn_iter; +@@ -1185,14 +1182,6 @@ static void dpu_encoder_virt_enable(struct drm_encoder *drm_enc) + + _dpu_encoder_virt_enable_helper(drm_enc); + +- if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { +- ret = msm_dp_display_enable(dpu_enc->dp, drm_enc); +- if (ret) { +- DPU_ERROR_ENC(dpu_enc, "dp display enable failed: %d\n", +- ret); +- goto out; +- } +- } + dpu_enc->enabled = true; + + out: +@@ -1226,11 +1215,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) + /* wait for idle */ + dpu_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); + +- if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { +- if (msm_dp_display_pre_disable(dpu_enc->dp, drm_enc)) +- DPU_ERROR_ENC(dpu_enc, "dp display push idle failed\n"); +- } +- + dpu_encoder_resource_control(drm_enc, DPU_ENC_RC_EVENT_PRE_STOP); + + for (i = 0; i < dpu_enc->num_phys_encs; i++) { +@@ -1255,11 +1239,6 @@ static void dpu_encoder_virt_disable(struct drm_encoder *drm_enc) + + DPU_DEBUG_ENC(dpu_enc, "encoder disabled\n"); + +- if (drm_enc->encoder_type == DRM_MODE_ENCODER_TMDS) { +- if (msm_dp_display_disable(dpu_enc->dp, drm_enc)) +- DPU_ERROR_ENC(dpu_enc, "dp display disable failed\n"); +- } +- + mutex_unlock(&dpu_enc->enc_lock); + } + +diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c +index b141ccb527b0..a51d665ab556 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.c ++++ b/drivers/gpu/drm/msm/dp/dp_display.c +@@ -1504,6 +1504,18 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, + dp_priv->panel->connector = dp_display->connector; + + priv->connectors[priv->num_connectors++] = dp_display->connector; ++ ++ dp_display->bridge = msm_dp_bridge_init(dp_display, dev, encoder); ++ if (IS_ERR(dp_display->bridge)) { ++ ret = PTR_ERR(dp_display->bridge); ++ DRM_DEV_ERROR(dev->dev, ++ "failed to create dp bridge: %d\n", ret); ++ dp_display->bridge = NULL; ++ return ret; ++ } ++ ++ priv->bridges[priv->num_bridges++] = dp_display->bridge; ++ + return 0; + } + +@@ -1606,8 +1618,8 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder) + } + + void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, +- struct drm_display_mode *mode, +- struct drm_display_mode *adjusted_mode) ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode) + { + struct dp_display_private *dp_display; + +diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h +index 8b47cdabb67e..04f4383bd3e7 100644 +--- a/drivers/gpu/drm/msm/dp/dp_display.h ++++ b/drivers/gpu/drm/msm/dp/dp_display.h +@@ -13,6 +13,7 @@ + struct msm_dp { + struct drm_device *drm_dev; + struct device *codec_dev; ++ struct drm_bridge *bridge; + struct drm_connector *connector; + struct drm_encoder *encoder; + bool is_connected; +diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c +index 764f4b81017e..6ab19a7ea57e 100644 +--- a/drivers/gpu/drm/msm/dp/dp_drm.c ++++ b/drivers/gpu/drm/msm/dp/dp_drm.c +@@ -11,6 +11,14 @@ + #include "msm_kms.h" + #include "dp_drm.h" + ++ ++struct msm_dp_bridge { ++ struct drm_bridge bridge; ++ struct msm_dp *dp_display; ++}; ++ ++#define to_dp_display(x) container_of((x), struct msm_dp_bridge, bridge) ++ + struct dp_connector { + struct drm_connector base; + struct msm_dp *dp_display; +@@ -162,3 +170,71 @@ struct drm_connector *dp_drm_connector_init(struct msm_dp *dp_display) + + return connector; + } ++ ++static void dp_bridge_mode_set(struct drm_bridge *drm_bridge, ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode) ++{ ++ struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); ++ struct msm_dp *dp_display = dp_bridge->dp_display; ++ ++ msm_dp_display_mode_set(dp_display, drm_bridge->encoder, mode, adjusted_mode); ++} ++ ++static void dp_bridge_enable(struct drm_bridge *drm_bridge) ++{ ++ struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); ++ struct msm_dp *dp_display = dp_bridge->dp_display; ++ ++ msm_dp_display_enable(dp_display, drm_bridge->encoder); ++} ++ ++static void dp_bridge_disable(struct drm_bridge *drm_bridge) ++{ ++ struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); ++ struct msm_dp *dp_display = dp_bridge->dp_display; ++ ++ msm_dp_display_pre_disable(dp_display, drm_bridge->encoder); ++} ++ ++static void dp_bridge_post_disable(struct drm_bridge *drm_bridge) ++{ ++ struct msm_dp_bridge *dp_bridge = to_dp_display(drm_bridge); ++ struct msm_dp *dp_display = dp_bridge->dp_display; ++ ++ msm_dp_display_disable(dp_display, drm_bridge->encoder); ++} ++ ++static const struct drm_bridge_funcs dp_bridge_ops = { ++ .enable = dp_bridge_enable, ++ .disable = dp_bridge_disable, ++ .post_disable = dp_bridge_post_disable, ++ .mode_set = dp_bridge_mode_set, ++}; ++ ++struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, ++ struct drm_encoder *encoder) ++{ ++ int rc; ++ struct msm_dp_bridge *dp_bridge; ++ struct drm_bridge *bridge; ++ ++ dp_bridge = devm_kzalloc(dev->dev, sizeof(*dp_bridge), GFP_KERNEL); ++ if (!dp_bridge) ++ return ERR_PTR(-ENOMEM); ++ ++ dp_bridge->dp_display = dp_display; ++ ++ bridge = &dp_bridge->bridge; ++ bridge->funcs = &dp_bridge_ops; ++ bridge->encoder = encoder; ++ ++ rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); ++ if (rc) { ++ DRM_ERROR("failed to attach bridge, rc=%d\n", rc); ++ kfree(dp_bridge); ++ return ERR_PTR(rc); ++ } ++ ++ return bridge; ++} +diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h +index bd5132bb9bde..89b7edf755d3 100644 +--- a/drivers/gpu/drm/msm/msm_drv.h ++++ b/drivers/gpu/drm/msm/msm_drv.h +@@ -384,8 +384,12 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder); + int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder); + int msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder); + void msm_dp_display_mode_set(struct msm_dp *dp, struct drm_encoder *encoder, +- struct drm_display_mode *mode, +- struct drm_display_mode *adjusted_mode); ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode); ++ ++struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, ++ struct drm_device *dev, ++ struct drm_encoder *encoder); + void msm_dp_irq_postinstall(struct msm_dp *dp_display); + void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display); + +@@ -422,8 +426,8 @@ static inline int msm_dp_display_pre_disable(struct msm_dp *dp, + } + static inline void msm_dp_display_mode_set(struct msm_dp *dp, + struct drm_encoder *encoder, +- struct drm_display_mode *mode, +- struct drm_display_mode *adjusted_mode) ++ const struct drm_display_mode *mode, ++ const struct drm_display_mode *adjusted_mode) + { + } + +-- +2.35.1 + diff --git a/queue-5.15/drm-msm-dp-fix-double-free-on-error-in-msm_dp_bridge.patch b/queue-5.15/drm-msm-dp-fix-double-free-on-error-in-msm_dp_bridge.patch new file mode 100644 index 00000000000..13c2175d764 --- /dev/null +++ b/queue-5.15/drm-msm-dp-fix-double-free-on-error-in-msm_dp_bridge.patch @@ -0,0 +1,38 @@ +From 02b01b0eb6742bbee218228fbb73181219902938 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Dec 2021 14:49:01 +0300 +Subject: drm/msm/dp: Fix double free on error in msm_dp_bridge_init() + +From: Dan Carpenter + +[ Upstream commit 48d0cf4a7cf2d5447f997e232c6378bb02434655 ] + +The "dp_bridge" pointer is allocated with devm_kzalloc() so it will be +freed automatically. Kfreeing it here will only lead to a double free. + +Fixes: 8a3b4c17f863 ("drm/msm/dp: employ bridge mechanism for display enable and disable") +Signed-off-by: Dan Carpenter +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20211215114900.GD14552@kili +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Rob Clark +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dp/dp_drm.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c +index 6ab19a7ea57e..d0ca4d0d5689 100644 +--- a/drivers/gpu/drm/msm/dp/dp_drm.c ++++ b/drivers/gpu/drm/msm/dp/dp_drm.c +@@ -232,7 +232,6 @@ struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_devi + rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (rc) { + DRM_ERROR("failed to attach bridge, rc=%d\n", rc); +- kfree(dp_bridge); + return ERR_PTR(rc); + } + +-- +2.35.1 + diff --git a/queue-5.15/drm-msm-properly-add-and-remove-internal-bridges.patch b/queue-5.15/drm-msm-properly-add-and-remove-internal-bridges.patch new file mode 100644 index 00000000000..20ca588e3c9 --- /dev/null +++ b/queue-5.15/drm-msm-properly-add-and-remove-internal-bridges.patch @@ -0,0 +1,136 @@ +From 79c275aa4cfcd00b68b97e68774b4b731bd493e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Apr 2022 02:49:53 +0300 +Subject: drm/msm: properly add and remove internal bridges + +From: Dmitry Baryshkov + +[ Upstream commit d28ea556267c4f2ec7264ab49f1b1296834321ec ] + +Add calls to drm_bridge_add()/drm_bridge_remove() DRM bridges created by +the driver. This fixes the following warning. + +WARNING: CPU: 0 PID: 1 at kernel/locking/mutex.c:579 __mutex_lock+0x840/0x9f4 +DEBUG_LOCKS_WARN_ON(lock->magic != lock) +Modules linked in: +CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.18.0-rc1-00002-g3054695a0d27-dirty #55 +Hardware name: Generic DT based system + unwind_backtrace from show_stack+0x10/0x14 + show_stack from dump_stack_lvl+0x58/0x70 + dump_stack_lvl from __warn+0xc8/0x1e8 + __warn from warn_slowpath_fmt+0x78/0xa8 + warn_slowpath_fmt from __mutex_lock+0x840/0x9f4 + __mutex_lock from mutex_lock_nested+0x1c/0x24 + mutex_lock_nested from drm_bridge_hpd_enable+0x2c/0x84 + drm_bridge_hpd_enable from msm_hdmi_modeset_init+0xc0/0x21c + msm_hdmi_modeset_init from mdp4_kms_init+0x53c/0x90c + mdp4_kms_init from msm_drm_bind+0x514/0x698 + msm_drm_bind from try_to_bring_up_aggregate_device+0x160/0x1bc + try_to_bring_up_aggregate_device from component_master_add_with_match+0xc4/0xf8 + component_master_add_with_match from msm_pdev_probe+0x274/0x350 + msm_pdev_probe from platform_probe+0x5c/0xbc + platform_probe from really_probe.part.0+0x9c/0x290 + really_probe.part.0 from __driver_probe_device+0xa8/0x13c + __driver_probe_device from driver_probe_device+0x34/0x10c + driver_probe_device from __driver_attach+0xbc/0x178 + __driver_attach from bus_for_each_dev+0x74/0xc0 + bus_for_each_dev from bus_add_driver+0x160/0x1e4 + bus_add_driver from driver_register+0x88/0x118 + driver_register from do_one_initcall+0x6c/0x334 + do_one_initcall from kernel_init_freeable+0x1bc/0x220 + kernel_init_freeable from kernel_init+0x18/0x12c + kernel_init from ret_from_fork+0x14/0x2c + +Fixes: 3d3f8b1f8b62 ("drm/bridge: make bridge registration independent of drm flow") +Reported-by: kernel test robot +Signed-off-by: Dmitry Baryshkov +Reviewed-by: Stephen Boyd +Reviewed-by: Abhinav Kumar +Patchwork: https://patchwork.freedesktop.org/patch/481778/ +Link: https://lore.kernel.org/r/20220411234953.2425280-1-dmitry.baryshkov@linaro.org +Signed-off-by: Dmitry Baryshkov +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/msm/dp/dp_drm.c | 4 ++++ + drivers/gpu/drm/msm/dsi/dsi_manager.c | 3 +++ + drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 3 +++ + drivers/gpu/drm/msm/msm_drv.c | 3 +++ + 4 files changed, 13 insertions(+) + +diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c +index d0ca4d0d5689..52128edb8aeb 100644 +--- a/drivers/gpu/drm/msm/dp/dp_drm.c ++++ b/drivers/gpu/drm/msm/dp/dp_drm.c +@@ -229,9 +229,13 @@ struct drm_bridge *msm_dp_bridge_init(struct msm_dp *dp_display, struct drm_devi + bridge->funcs = &dp_bridge_ops; + bridge->encoder = encoder; + ++ drm_bridge_add(bridge); ++ + rc = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (rc) { + DRM_ERROR("failed to attach bridge, rc=%d\n", rc); ++ drm_bridge_remove(bridge); ++ + return ERR_PTR(rc); + } + +diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c +index 6e43672f5807..fb3375cfdc84 100644 +--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c ++++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c +@@ -670,6 +670,8 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id) + bridge = &dsi_bridge->base; + bridge->funcs = &dsi_mgr_bridge_funcs; + ++ drm_bridge_add(bridge); ++ + ret = drm_bridge_attach(encoder, bridge, NULL, 0); + if (ret) + goto fail; +@@ -718,6 +720,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id) + + void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge) + { ++ drm_bridge_remove(bridge); + } + + int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg) +diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +index efcfdd70a02e..0960c5642847 100644 +--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c ++++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +@@ -15,6 +15,7 @@ void msm_hdmi_bridge_destroy(struct drm_bridge *bridge) + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + + msm_hdmi_hpd_disable(hdmi_bridge); ++ drm_bridge_remove(bridge); + } + + static void msm_hdmi_power_on(struct drm_bridge *bridge) +@@ -354,6 +355,8 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi) + DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_EDID; + ++ drm_bridge_add(bridge); ++ + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) + goto fail; +diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c +index 916361c30d77..422507435498 100644 +--- a/drivers/gpu/drm/msm/msm_drv.c ++++ b/drivers/gpu/drm/msm/msm_drv.c +@@ -363,6 +363,9 @@ static int msm_drm_uninit(struct device *dev) + + drm_mode_config_cleanup(ddev); + ++ for (i = 0; i < priv->num_bridges; i++) ++ drm_bridge_remove(priv->bridges[i]); ++ + pm_runtime_get_sync(dev); + msm_irq_uninstall(ddev); + pm_runtime_put_sync(dev); +-- +2.35.1 + diff --git a/queue-5.15/dt-bindings-soc-qcom-smd-rpm-add-compatible-for-msm8.patch b/queue-5.15/dt-bindings-soc-qcom-smd-rpm-add-compatible-for-msm8.patch new file mode 100644 index 00000000000..4a27a8b14a2 --- /dev/null +++ b/queue-5.15/dt-bindings-soc-qcom-smd-rpm-add-compatible-for-msm8.patch @@ -0,0 +1,45 @@ +From df903584abf4c239a3e51d67cfe993bf962e6a91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Aug 2021 22:29:42 +0530 +Subject: dt-bindings: soc: qcom: smd-rpm: Add compatible for MSM8953 SoC + +From: Vladimir Lypak + +[ Upstream commit 96c42812f798c5e48d55cd6fc2101ce99af19608 ] + +Document compatible for MSM8953 SoC. + +Signed-off-by: Vladimir Lypak +Signed-off-by: Adam Skladowski +Signed-off-by: Sireesh Kodali +Acked-by: Rob Herring +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20210825165943.19415-1-sireeshkodali1@gmail.com +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +index cc3fe5ed7421..77963b86b714 100644 +--- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml ++++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +@@ -34,6 +34,7 @@ properties: + - qcom,rpm-ipq6018 + - qcom,rpm-msm8226 + - qcom,rpm-msm8916 ++ - qcom,rpm-msm8953 + - qcom,rpm-msm8974 + - qcom,rpm-msm8976 + - qcom,rpm-msm8996 +@@ -57,6 +58,7 @@ if: + - qcom,rpm-apq8084 + - qcom,rpm-msm8916 + - qcom,rpm-msm8974 ++ - qcom,rpm-msm8953 + then: + required: + - qcom,smd-channels +-- +2.35.1 + diff --git a/queue-5.15/dt-bindings-soc-qcom-smd-rpm-fix-missing-msm8936-com.patch b/queue-5.15/dt-bindings-soc-qcom-smd-rpm-fix-missing-msm8936-com.patch new file mode 100644 index 00000000000..9acb8f71475 --- /dev/null +++ b/queue-5.15/dt-bindings-soc-qcom-smd-rpm-fix-missing-msm8936-com.patch @@ -0,0 +1,38 @@ +From 32559c085c248fe65c499ac5d37128430f7fc911 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Apr 2022 00:18:57 +0100 +Subject: dt-bindings: soc: qcom: smd-rpm: Fix missing MSM8936 compatible + +From: Bryan O'Donoghue + +[ Upstream commit e930244918092d44b60a7b538cf60d737010ceef ] + +Add compatible msm8936. msm8936 covers both msm8936 and msm8939. +The relevant driver already has the compat string but, we haven't +documented it. + +Fixes: d6e52482f5ab ("drivers: soc: Add MSM8936 SMD RPM compatible") +Signed-off-by: Bryan O'Donoghue +Acked-by: Krzysztof Kozlowski +Signed-off-by: Rob Herring +Link: https://lore.kernel.org/r/20220418231857.3061053-1-bryan.odonoghue@linaro.org +Signed-off-by: Sasha Levin +--- + Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +index 77963b86b714..1b0062e3c1a4 100644 +--- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml ++++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +@@ -34,6 +34,7 @@ properties: + - qcom,rpm-ipq6018 + - qcom,rpm-msm8226 + - qcom,rpm-msm8916 ++ - qcom,rpm-msm8936 + - qcom,rpm-msm8953 + - qcom,rpm-msm8974 + - qcom,rpm-msm8976 +-- +2.35.1 + diff --git a/queue-5.15/gfs2-fix-gfs2_file_buffered_write-endless-loop-worka.patch b/queue-5.15/gfs2-fix-gfs2_file_buffered_write-endless-loop-worka.patch new file mode 100644 index 00000000000..9992289b8fa --- /dev/null +++ b/queue-5.15/gfs2-fix-gfs2_file_buffered_write-endless-loop-worka.patch @@ -0,0 +1,34 @@ +From 31d722b87ad7f966a92c11fac9f013b997031f82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Mar 2022 14:47:24 +0100 +Subject: gfs2: Fix gfs2_file_buffered_write endless loop workaround + +From: Andreas Gruenbacher + +[ Upstream commit 46f3e0421ccb5474b5c006b0089b9dfd42534bb6 ] + +Since commit 554c577cee95b, gfs2_file_buffered_write() can accidentally +return a truncated iov_iter, which might confuse callers. Fix that. + +Fixes: 554c577cee95b ("gfs2: Prevent endless loops in gfs2_file_buffered_write") +Signed-off-by: Andreas Gruenbacher +Signed-off-by: Sasha Levin +--- + fs/gfs2/file.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c +index 60390f9dc31f..e93185d804e0 100644 +--- a/fs/gfs2/file.c ++++ b/fs/gfs2/file.c +@@ -1086,6 +1086,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb, + gfs2_holder_uninit(gh); + if (statfs_gh) + kfree(statfs_gh); ++ from->count = orig_count - read; + return read ? read : ret; + } + +-- +2.35.1 + diff --git a/queue-5.15/ibmvnic-allow-queueing-resets-during-probe.patch b/queue-5.15/ibmvnic-allow-queueing-resets-during-probe.patch new file mode 100644 index 00000000000..eb1ebdfcc01 --- /dev/null +++ b/queue-5.15/ibmvnic-allow-queueing-resets-during-probe.patch @@ -0,0 +1,274 @@ +From 18c541aa17246888c009a4d26127235463eeb4e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 24 Feb 2022 22:23:58 -0800 +Subject: ibmvnic: Allow queueing resets during probe + +From: Sukadev Bhattiprolu + +[ Upstream commit fd98693cb0721317f27341951593712c580c36a1 ] + +We currently don't allow queuing resets when adapter is in VNIC_PROBING +state - instead we throw away the reset and return EBUSY. The reasoning +is probably that during ibmvnic_probe() the ibmvnic_adapter itself is +being initialized so performing a reset during this time can lead us to +accessing fields in the ibmvnic_adapter that are not fully initialized. +A review of the code shows that all the adapter state neede to process a +reset is initialized before registering the CRQ so that should no longer +be a concern. + +Further the expectation is that if we do get a reset (transport event) +during probe, the do..while() loop in ibmvnic_probe() will handle this +by reinitializing the CRQ. + +While that is true to some extent, it is possible that the reset might +occur _after_ the CRQ is registered and CRQ_INIT message was exchanged +but _before_ the adapter state is set to VNIC_PROBED. As mentioned above, +such a reset will be thrown away. While the client assumes that the +adapter is functional, the vnic server will wait for the client to reinit +the adapter. This disconnect between the two leaves the adapter down +needing manual intervention. + +Because ibmvnic_probe() has other work to do after initializing the CRQ +(such as registering the netdev at a minimum) and because the reset event +can occur at any instant after the CRQ is initialized, there will always +be a window between initializing the CRQ and considering the adapter +ready for resets (ie state == PROBED). + +So rather than discarding resets during this window, allow queueing them +- but only process them after the adapter is fully initialized. + +To do this, introduce a new completion state ->probe_done and have the +reset worker thread wait on this before processing resets. + +This change brings up two new situations in or just after ibmvnic_probe(). +First after one or more resets were queued, we encounter an error and +decide to retry the initialization. At that point the queued resets are +no longer relevant since we could be talking to a new vnic server. So we +must purge/flush the queued resets before restarting the initialization. +As a side note, since we are still in the probing stage and we have not +registered the netdev, it will not be CHANGE_PARAM reset. + +Second this change opens up a potential race between the worker thread +in __ibmvnic_reset(), the tasklet and the ibmvnic_open() due to the +following sequence of events: + + 1. Register CRQ + 2. Get transport event before CRQ_INIT completes. + 3. Tasklet schedules reset: + a) add rwi to list + b) schedule_work() to start worker thread which runs + and waits for ->probe_done. + 4. ibmvnic_probe() decides to retry, purges rwi_list + 5. Re-register crq and this time rest of probe succeeds - register + netdev and complete(->probe_done). + 6. Worker thread resumes in __ibmvnic_reset() from 3b. + 7. Worker thread sets ->resetting bit + 8. ibmvnic_open() comes in, notices ->resetting bit, sets state + to IBMVNIC_OPEN and returns early expecting worker thread to + finish the open. + 9. Worker thread finds rwi_list empty and returns without + opening the interface. + +If this happens, the ->ndo_open() call is effectively lost and the +interface remains down. To address this, ensure that ->rwi_list is +not empty before setting the ->resetting bit. See also comments in +__ibmvnic_reset(). + +Fixes: 6a2fb0e99f9c ("ibmvnic: driver initialization for kdump/kexec") +Signed-off-by: Sukadev Bhattiprolu +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ibm/ibmvnic.c | 107 ++++++++++++++++++++++++++--- + drivers/net/ethernet/ibm/ibmvnic.h | 1 + + 2 files changed, 98 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c +index 9f4f40564d74..28344c3dfea1 100644 +--- a/drivers/net/ethernet/ibm/ibmvnic.c ++++ b/drivers/net/ethernet/ibm/ibmvnic.c +@@ -2471,23 +2471,82 @@ static int do_passive_init(struct ibmvnic_adapter *adapter) + static void __ibmvnic_reset(struct work_struct *work) + { + struct ibmvnic_adapter *adapter; +- bool saved_state = false; ++ unsigned int timeout = 5000; + struct ibmvnic_rwi *tmprwi; ++ bool saved_state = false; + struct ibmvnic_rwi *rwi; + unsigned long flags; +- u32 reset_state; ++ struct device *dev; ++ bool need_reset; + int num_fails = 0; ++ u32 reset_state; + int rc = 0; + + adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset); ++ dev = &adapter->vdev->dev; + +- if (test_and_set_bit_lock(0, &adapter->resetting)) { ++ /* Wait for ibmvnic_probe() to complete. If probe is taking too long ++ * or if another reset is in progress, defer work for now. If probe ++ * eventually fails it will flush and terminate our work. ++ * ++ * Three possibilities here: ++ * 1. Adpater being removed - just return ++ * 2. Timed out on probe or another reset in progress - delay the work ++ * 3. Completed probe - perform any resets in queue ++ */ ++ if (adapter->state == VNIC_PROBING && ++ !wait_for_completion_timeout(&adapter->probe_done, timeout)) { ++ dev_err(dev, "Reset thread timed out on probe"); + queue_delayed_work(system_long_wq, + &adapter->ibmvnic_delayed_reset, + IBMVNIC_RESET_DELAY); + return; + } + ++ /* adapter is done with probe (i.e state is never VNIC_PROBING now) */ ++ if (adapter->state == VNIC_REMOVING) ++ return; ++ ++ /* ->rwi_list is stable now (no one else is removing entries) */ ++ ++ /* ibmvnic_probe() may have purged the reset queue after we were ++ * scheduled to process a reset so there maybe no resets to process. ++ * Before setting the ->resetting bit though, we have to make sure ++ * that there is infact a reset to process. Otherwise we may race ++ * with ibmvnic_open() and end up leaving the vnic down: ++ * ++ * __ibmvnic_reset() ibmvnic_open() ++ * ----------------- -------------- ++ * ++ * set ->resetting bit ++ * find ->resetting bit is set ++ * set ->state to IBMVNIC_OPEN (i.e ++ * assume reset will open device) ++ * return ++ * find reset queue empty ++ * return ++ * ++ * Neither performed vnic login/open and vnic stays down ++ * ++ * If we hold the lock and conditionally set the bit, either we ++ * or ibmvnic_open() will complete the open. ++ */ ++ need_reset = false; ++ spin_lock(&adapter->rwi_lock); ++ if (!list_empty(&adapter->rwi_list)) { ++ if (test_and_set_bit_lock(0, &adapter->resetting)) { ++ queue_delayed_work(system_long_wq, ++ &adapter->ibmvnic_delayed_reset, ++ IBMVNIC_RESET_DELAY); ++ } else { ++ need_reset = true; ++ } ++ } ++ spin_unlock(&adapter->rwi_lock); ++ ++ if (!need_reset) ++ return; ++ + rwi = get_next_rwi(adapter); + while (rwi) { + spin_lock_irqsave(&adapter->state_lock, flags); +@@ -2639,13 +2698,6 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter, + goto err; + } + +- if (adapter->state == VNIC_PROBING) { +- netdev_warn(netdev, "Adapter reset during probe\n"); +- adapter->init_done_rc = -EAGAIN; +- ret = EAGAIN; +- goto err; +- } +- + list_for_each_entry(tmp, &adapter->rwi_list, list) { + if (tmp->reset_reason == reason) { + netdev_dbg(netdev, "Skipping matching reset, reason=%s\n", +@@ -5561,6 +5613,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) + struct ibmvnic_adapter *adapter; + struct net_device *netdev; + unsigned char *mac_addr_p; ++ unsigned long flags; + bool init_success; + int rc; + +@@ -5602,6 +5655,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) + spin_lock_init(&adapter->rwi_lock); + spin_lock_init(&adapter->state_lock); + mutex_init(&adapter->fw_lock); ++ init_completion(&adapter->probe_done); + init_completion(&adapter->init_done); + init_completion(&adapter->fw_done); + init_completion(&adapter->reset_done); +@@ -5617,6 +5671,26 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) + */ + adapter->failover_pending = false; + ++ /* If we had already initialized CRQ, we may have one or ++ * more resets queued already. Discard those and release ++ * the CRQ before initializing the CRQ again. ++ */ ++ release_crq_queue(adapter); ++ ++ /* Since we are still in PROBING state, __ibmvnic_reset() ++ * will not access the ->rwi_list and since we released CRQ, ++ * we won't get _new_ transport events. But there maybe an ++ * ongoing ibmvnic_reset() call. So serialize access to ++ * rwi_list. If we win the race, ibvmnic_reset() could add ++ * a reset after we purged but thats ok - we just may end ++ * up with an extra reset (i.e similar to having two or more ++ * resets in the queue at once). ++ * CHECK. ++ */ ++ spin_lock_irqsave(&adapter->rwi_lock, flags); ++ flush_reset_queue(adapter); ++ spin_unlock_irqrestore(&adapter->rwi_lock, flags); ++ + rc = init_crq_queue(adapter); + if (rc) { + dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n", +@@ -5668,6 +5742,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) + } + dev_info(&dev->dev, "ibmvnic registered\n"); + ++ complete(&adapter->probe_done); ++ + return 0; + + ibmvnic_register_fail: +@@ -5682,6 +5758,17 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) + ibmvnic_init_fail: + release_sub_crqs(adapter, 1); + release_crq_queue(adapter); ++ ++ /* cleanup worker thread after releasing CRQ so we don't get ++ * transport events (i.e new work items for the worker thread). ++ */ ++ adapter->state = VNIC_REMOVING; ++ complete(&adapter->probe_done); ++ flush_work(&adapter->ibmvnic_reset); ++ flush_delayed_work(&adapter->ibmvnic_delayed_reset); ++ ++ flush_reset_queue(adapter); ++ + mutex_destroy(&adapter->fw_lock); + free_netdev(netdev); + +diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h +index 1a9ed9202654..b01c439965ff 100644 +--- a/drivers/net/ethernet/ibm/ibmvnic.h ++++ b/drivers/net/ethernet/ibm/ibmvnic.h +@@ -927,6 +927,7 @@ struct ibmvnic_adapter { + + struct ibmvnic_tx_pool *tx_pool; + struct ibmvnic_tx_pool *tso_pool; ++ struct completion probe_done; + struct completion init_done; + int init_done_rc; + +-- +2.35.1 + diff --git a/queue-5.15/ibmvnic-clear-fop-when-retrying-probe.patch b/queue-5.15/ibmvnic-clear-fop-when-retrying-probe.patch new file mode 100644 index 00000000000..ecbe8dc5807 --- /dev/null +++ b/queue-5.15/ibmvnic-clear-fop-when-retrying-probe.patch @@ -0,0 +1,46 @@ +From f506ab7d60835d4fb1d03a52e783b22c0304636e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 24 Feb 2022 22:23:57 -0800 +Subject: ibmvnic: clear fop when retrying probe + +From: Sukadev Bhattiprolu + +[ Upstream commit f628ad531b4f34fdba0984255b4a2850dd369513 ] + +Clear ->failover_pending flag that may have been set in the previous +pass of registering CRQ. If we don't clear, a subsequent ibmvnic_open() +call would be misled into thinking a failover is pending and assuming +that the reset worker thread would open the adapter. If this pass of +registering the CRQ succeeds (i.e there is no transport event), there +wouldn't be a reset worker thread. + +This would leave the adapter unconfigured and require manual intervention +to bring it up during boot. + +Fixes: 5a18e1e0c193 ("ibmvnic: Fix failover case for non-redundant configuration") +Signed-off-by: Sukadev Bhattiprolu +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ibm/ibmvnic.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c +index 70267bd73429..9f4f40564d74 100644 +--- a/drivers/net/ethernet/ibm/ibmvnic.c ++++ b/drivers/net/ethernet/ibm/ibmvnic.c +@@ -5612,6 +5612,11 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) + do { + reinit_init_done(adapter); + ++ /* clear any failovers we got in the previous pass ++ * since we are reinitializing the CRQ ++ */ ++ adapter->failover_pending = false; ++ + rc = init_crq_queue(adapter); + if (rc) { + dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n", +-- +2.35.1 + diff --git a/queue-5.15/ibmvnic-init-init_done_rc-earlier.patch b/queue-5.15/ibmvnic-init-init_done_rc-earlier.patch new file mode 100644 index 00000000000..90df048d82c --- /dev/null +++ b/queue-5.15/ibmvnic-init-init_done_rc-earlier.patch @@ -0,0 +1,110 @@ +From 21e26d270aa7735f423b3e35d7e4355f11ad7b47 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 24 Feb 2022 22:23:56 -0800 +Subject: ibmvnic: init init_done_rc earlier + +From: Sukadev Bhattiprolu + +[ Upstream commit ae16bf15374d8b055e040ac6f3f1147ab1c9bb7d ] + +We currently initialize the ->init_done completion/return code fields +before issuing a CRQ_INIT command. But if we get a transport event soon +after registering the CRQ the taskslet may already have recorded the +completion and error code. If we initialize here, we might overwrite/ +lose that and end up issuing the CRQ_INIT only to timeout later. + +If that timeout happens during probe, we will leave the adapter in the +DOWN state rather than retrying to register/init the CRQ. + +Initialize the completion before registering the CRQ so we don't lose +the notification. + +Fixes: 032c5e82847a ("Driver for IBM System i/p VNIC protocol") +Signed-off-by: Sukadev Bhattiprolu +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/ibm/ibmvnic.c | 26 +++++++++++++++++++++----- + 1 file changed, 21 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c +index b262aa84b6a2..70267bd73429 100644 +--- a/drivers/net/ethernet/ibm/ibmvnic.c ++++ b/drivers/net/ethernet/ibm/ibmvnic.c +@@ -2063,6 +2063,19 @@ static const char *reset_reason_to_string(enum ibmvnic_reset_reason reason) + return "UNKNOWN"; + } + ++/* ++ * Initialize the init_done completion and return code values. We ++ * can get a transport event just after registering the CRQ and the ++ * tasklet will use this to communicate the transport event. To ensure ++ * we don't miss the notification/error, initialize these _before_ ++ * regisering the CRQ. ++ */ ++static inline void reinit_init_done(struct ibmvnic_adapter *adapter) ++{ ++ reinit_completion(&adapter->init_done); ++ adapter->init_done_rc = 0; ++} ++ + /* + * do_reset returns zero if we are able to keep processing reset events, or + * non-zero if we hit a fatal error and must halt. +@@ -2169,6 +2182,8 @@ static int do_reset(struct ibmvnic_adapter *adapter, + */ + adapter->state = VNIC_PROBED; + ++ reinit_init_done(adapter); ++ + if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) { + rc = init_crq_queue(adapter); + } else if (adapter->reset_reason == VNIC_RESET_MOBILITY) { +@@ -2314,7 +2329,8 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter, + */ + adapter->state = VNIC_PROBED; + +- reinit_completion(&adapter->init_done); ++ reinit_init_done(adapter); ++ + rc = init_crq_queue(adapter); + if (rc) { + netdev_err(adapter->netdev, +@@ -5485,10 +5501,6 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset) + + adapter->from_passive_init = false; + +- if (reset) +- reinit_completion(&adapter->init_done); +- +- adapter->init_done_rc = 0; + rc = ibmvnic_send_crq_init(adapter); + if (rc) { + dev_err(dev, "Send crq init failed with error %d\n", rc); +@@ -5502,12 +5514,14 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset) + + if (adapter->init_done_rc) { + release_crq_queue(adapter); ++ dev_err(dev, "CRQ-init failed, %d\n", adapter->init_done_rc); + return adapter->init_done_rc; + } + + if (adapter->from_passive_init) { + adapter->state = VNIC_OPEN; + adapter->from_passive_init = false; ++ dev_err(dev, "CRQ-init failed, passive-init\n"); + return -1; + } + +@@ -5596,6 +5610,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) + + init_success = false; + do { ++ reinit_init_done(adapter); ++ + rc = init_crq_queue(adapter); + if (rc) { + dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n", +-- +2.35.1 + diff --git a/queue-5.15/iio-accel-mma8452-use-the-correct-logic-to-get-mma84.patch b/queue-5.15/iio-accel-mma8452-use-the-correct-logic-to-get-mma84.patch new file mode 100644 index 00000000000..41bbc428db1 --- /dev/null +++ b/queue-5.15/iio-accel-mma8452-use-the-correct-logic-to-get-mma84.patch @@ -0,0 +1,58 @@ +From 8a2644dc664f70c88f6c8bfe81136d3d180fa05e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Feb 2022 10:42:21 +0800 +Subject: iio: accel: mma8452: use the correct logic to get mma8452_data + +From: Haibo Chen + +[ Upstream commit c87b7b12f48db86ac9909894f4dc0107d7df6375 ] + +The original logic to get mma8452_data is wrong, the *dev point to +the device belong to iio_dev. we can't use this dev to find the +correct i2c_client. The original logic happen to work because it +finally use dev->driver_data to get iio_dev. Here use the API +to_i2c_client() is wrong and make reader confuse. To correct the +logic, it should be like this + + struct mma8452_data *data = iio_priv(dev_get_drvdata(dev)); + +But after commit 8b7651f25962 ("iio: iio_device_alloc(): Remove +unnecessary self drvdata"), the upper logic also can't work. +When try to show the avialable scale in userspace, will meet kernel +dump, kernel handle NULL pointer dereference. + +So use dev_to_iio_dev() to correct the logic. + +Dual fixes tags as the second reflects when the bug was exposed, whilst +the first reflects when the original bug was introduced. + +Fixes: c3cdd6e48e35 ("iio: mma8452: refactor for seperating chip specific data") +Fixes: 8b7651f25962 ("iio: iio_device_alloc(): Remove unnecessary self drvdata") +Signed-off-by: Haibo Chen +Reviewed-by: Martin Kepplinger +Cc: +Link: https://lore.kernel.org/r/1645497741-5402-1-git-send-email-haibo.chen@nxp.com +Signed-off-by: Jonathan Cameron +Signed-off-by: Sasha Levin +--- + drivers/iio/accel/mma8452.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c +index 373b59557afe..1f46a73aafea 100644 +--- a/drivers/iio/accel/mma8452.c ++++ b/drivers/iio/accel/mma8452.c +@@ -380,8 +380,8 @@ static ssize_t mma8452_show_scale_avail(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mma8452_data *data = iio_priv(i2c_get_clientdata( +- to_i2c_client(dev))); ++ struct iio_dev *indio_dev = dev_to_iio_dev(dev); ++ struct mma8452_data *data = iio_priv(indio_dev); + + return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, + ARRAY_SIZE(data->chip_info->mma_scales)); +-- +2.35.1 + diff --git a/queue-5.15/input-cpcap-pwrbutton-handle-errors-from-platform_ge.patch b/queue-5.15/input-cpcap-pwrbutton-handle-errors-from-platform_ge.patch new file mode 100644 index 00000000000..13eed01f9de --- /dev/null +++ b/queue-5.15/input-cpcap-pwrbutton-handle-errors-from-platform_ge.patch @@ -0,0 +1,43 @@ +From b27c4e31a22743c4c9c698f417a15a761c41b081 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Sep 2021 18:57:32 -0700 +Subject: Input: cpcap-pwrbutton - handle errors from platform_get_irq() + +From: Tang Bin + +[ Upstream commit 58ae4004b9c4bb040958cf73986b687a5ea4d85d ] + +The function cpcap_power_button_probe() does not perform +sufficient error checking after executing platform_get_irq(), +thus fix it. + +Signed-off-by: Tang Bin +Link: https://lore.kernel.org/r/20210802121740.8700-1-tangbin@cmss.chinamobile.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +--- + drivers/input/misc/cpcap-pwrbutton.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/input/misc/cpcap-pwrbutton.c b/drivers/input/misc/cpcap-pwrbutton.c +index 0abef63217e2..372cb44d0635 100644 +--- a/drivers/input/misc/cpcap-pwrbutton.c ++++ b/drivers/input/misc/cpcap-pwrbutton.c +@@ -54,9 +54,13 @@ static irqreturn_t powerbutton_irq(int irq, void *_button) + static int cpcap_power_button_probe(struct platform_device *pdev) + { + struct cpcap_power_button *button; +- int irq = platform_get_irq(pdev, 0); ++ int irq; + int err; + ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ + button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL); + if (!button) + return -ENOMEM; +-- +2.35.1 + diff --git a/queue-5.15/input-goodix-add-a-goodix.h-header-file.patch b/queue-5.15/input-goodix-add-a-goodix.h-header-file.patch new file mode 100644 index 00000000000..132b29cedfa --- /dev/null +++ b/queue-5.15/input-goodix-add-a-goodix.h-header-file.patch @@ -0,0 +1,282 @@ +From 53f96b12f3e006d5d0d2a9c596e59cb80f4209e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Sep 2021 21:08:18 -0700 +Subject: Input: goodix - add a goodix.h header file + +From: Hans de Goede + +[ Upstream commit a2233cb7b65a017067e2f2703375ecc930a0ab30 ] + +Add a goodix.h header file, and move the register definitions, +and struct declarations there and add prototypes for various +helper functions. + +This is a preparation patch for adding support for controllers +without flash, which need to have their firmware uploaded and +need some other special handling too. + +Since MAINTAINERS needs updating because of this change anyways, +also add myself as co-maintainer. + +Reviewed-by: Bastien Nocera +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20210920150643.155872-3-hdegoede@redhat.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +--- + MAINTAINERS | 3 +- + drivers/input/touchscreen/goodix.c | 74 +++--------------------------- + drivers/input/touchscreen/goodix.h | 73 +++++++++++++++++++++++++++++ + 3 files changed, 81 insertions(+), 69 deletions(-) + create mode 100644 drivers/input/touchscreen/goodix.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index a60d7e0466af..edc32575828b 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -7952,9 +7952,10 @@ F: drivers/media/usb/go7007/ + + GOODIX TOUCHSCREEN + M: Bastien Nocera ++M: Hans de Goede + L: linux-input@vger.kernel.org + S: Maintained +-F: drivers/input/touchscreen/goodix.c ++F: drivers/input/touchscreen/goodix* + + GOOGLE ETHERNET DRIVERS + M: Jeroen de Borst +diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c +index 1eb776abe562..5ccdd6abd868 100644 +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -14,20 +14,15 @@ + #include + #include + #include +-#include +-#include +-#include +-#include +-#include + #include + #include + #include + #include +-#include + #include + #include + #include + #include ++#include "goodix.h" + + #define GOODIX_GPIO_INT_NAME "irq" + #define GOODIX_GPIO_RST_NAME "reset" +@@ -38,22 +33,11 @@ + #define GOODIX_CONTACT_SIZE 8 + #define GOODIX_MAX_CONTACT_SIZE 9 + #define GOODIX_MAX_CONTACTS 10 +-#define GOODIX_MAX_KEYS 7 + + #define GOODIX_CONFIG_MIN_LENGTH 186 + #define GOODIX_CONFIG_911_LENGTH 186 + #define GOODIX_CONFIG_967_LENGTH 228 + #define GOODIX_CONFIG_GT9X_LENGTH 240 +-#define GOODIX_CONFIG_MAX_LENGTH 240 +- +-/* Register defines */ +-#define GOODIX_REG_COMMAND 0x8040 +-#define GOODIX_CMD_SCREEN_OFF 0x05 +- +-#define GOODIX_READ_COOR_ADDR 0x814E +-#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050 +-#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047 +-#define GOODIX_REG_ID 0x8140 + + #define GOODIX_BUFFER_STATUS_READY BIT(7) + #define GOODIX_HAVE_KEY BIT(4) +@@ -68,55 +52,11 @@ + #define ACPI_GPIO_SUPPORT + #endif + +-struct goodix_ts_data; +- +-enum goodix_irq_pin_access_method { +- IRQ_PIN_ACCESS_NONE, +- IRQ_PIN_ACCESS_GPIO, +- IRQ_PIN_ACCESS_ACPI_GPIO, +- IRQ_PIN_ACCESS_ACPI_METHOD, +-}; +- +-struct goodix_chip_data { +- u16 config_addr; +- int config_len; +- int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len); +- void (*calc_config_checksum)(struct goodix_ts_data *ts); +-}; +- + struct goodix_chip_id { + const char *id; + const struct goodix_chip_data *data; + }; + +-#define GOODIX_ID_MAX_LEN 4 +- +-struct goodix_ts_data { +- struct i2c_client *client; +- struct input_dev *input_dev; +- const struct goodix_chip_data *chip; +- struct touchscreen_properties prop; +- unsigned int max_touch_num; +- unsigned int int_trigger_type; +- struct regulator *avdd28; +- struct regulator *vddio; +- struct gpio_desc *gpiod_int; +- struct gpio_desc *gpiod_rst; +- int gpio_count; +- int gpio_int_idx; +- char id[GOODIX_ID_MAX_LEN + 1]; +- u16 version; +- const char *cfg_name; +- bool reset_controller_at_probe; +- bool load_cfg_from_disk; +- struct completion firmware_loading_complete; +- unsigned long irq_flags; +- enum goodix_irq_pin_access_method irq_pin_access_method; +- unsigned int contact_size; +- u8 config[GOODIX_CONFIG_MAX_LENGTH]; +- unsigned short keymap[GOODIX_MAX_KEYS]; +-}; +- + static int goodix_check_cfg_8(struct goodix_ts_data *ts, + const u8 *cfg, int len); + static int goodix_check_cfg_16(struct goodix_ts_data *ts, +@@ -216,8 +156,7 @@ static const struct dmi_system_id inverted_x_screen[] = { + * @buf: raw write data buffer. + * @len: length of the buffer to write + */ +-static int goodix_i2c_read(struct i2c_client *client, +- u16 reg, u8 *buf, int len) ++int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len) + { + struct i2c_msg msgs[2]; + __be16 wbuf = cpu_to_be16(reg); +@@ -245,8 +184,7 @@ static int goodix_i2c_read(struct i2c_client *client, + * @buf: raw data buffer to write. + * @len: length of the buffer to write + */ +-static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, +- int len) ++int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len) + { + u8 *addr_buf; + struct i2c_msg msg; +@@ -270,7 +208,7 @@ static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, + return ret < 0 ? ret : (ret != 1 ? -EIO : 0); + } + +-static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) ++int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value) + { + return goodix_i2c_write(client, reg, &value, sizeof(value)); + } +@@ -554,7 +492,7 @@ static int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) + * @cfg: config firmware to write to device + * @len: config data length + */ +-static int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) ++int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len) + { + int error; + +@@ -652,7 +590,7 @@ static int goodix_irq_direction_input(struct goodix_ts_data *ts) + return -EINVAL; /* Never reached */ + } + +-static int goodix_int_sync(struct goodix_ts_data *ts) ++int goodix_int_sync(struct goodix_ts_data *ts) + { + int error; + +diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h +new file mode 100644 +index 000000000000..cdaced4f2980 +--- /dev/null ++++ b/drivers/input/touchscreen/goodix.h +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++#ifndef __GOODIX_H__ ++#define __GOODIX_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Register defines */ ++#define GOODIX_REG_COMMAND 0x8040 ++#define GOODIX_CMD_SCREEN_OFF 0x05 ++ ++#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050 ++#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047 ++#define GOODIX_REG_ID 0x8140 ++#define GOODIX_READ_COOR_ADDR 0x814E ++ ++#define GOODIX_ID_MAX_LEN 4 ++#define GOODIX_CONFIG_MAX_LENGTH 240 ++#define GOODIX_MAX_KEYS 7 ++ ++enum goodix_irq_pin_access_method { ++ IRQ_PIN_ACCESS_NONE, ++ IRQ_PIN_ACCESS_GPIO, ++ IRQ_PIN_ACCESS_ACPI_GPIO, ++ IRQ_PIN_ACCESS_ACPI_METHOD, ++}; ++ ++struct goodix_ts_data; ++ ++struct goodix_chip_data { ++ u16 config_addr; ++ int config_len; ++ int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len); ++ void (*calc_config_checksum)(struct goodix_ts_data *ts); ++}; ++ ++struct goodix_ts_data { ++ struct i2c_client *client; ++ struct input_dev *input_dev; ++ const struct goodix_chip_data *chip; ++ struct touchscreen_properties prop; ++ unsigned int max_touch_num; ++ unsigned int int_trigger_type; ++ struct regulator *avdd28; ++ struct regulator *vddio; ++ struct gpio_desc *gpiod_int; ++ struct gpio_desc *gpiod_rst; ++ int gpio_count; ++ int gpio_int_idx; ++ char id[GOODIX_ID_MAX_LEN + 1]; ++ u16 version; ++ const char *cfg_name; ++ bool reset_controller_at_probe; ++ bool load_cfg_from_disk; ++ struct completion firmware_loading_complete; ++ unsigned long irq_flags; ++ enum goodix_irq_pin_access_method irq_pin_access_method; ++ unsigned int contact_size; ++ u8 config[GOODIX_CONFIG_MAX_LENGTH]; ++ unsigned short keymap[GOODIX_MAX_KEYS]; ++}; ++ ++int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len); ++int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len); ++int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value); ++int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len); ++int goodix_int_sync(struct goodix_ts_data *ts); ++ ++#endif +-- +2.35.1 + diff --git a/queue-5.15/input-goodix-change-goodix_i2c_write-len-parameter-t.patch b/queue-5.15/input-goodix-change-goodix_i2c_write-len-parameter-t.patch new file mode 100644 index 00000000000..33d75aceabf --- /dev/null +++ b/queue-5.15/input-goodix-change-goodix_i2c_write-len-parameter-t.patch @@ -0,0 +1,38 @@ +From bf8bef3bc64d3569f2a27af9ac2a8ca014370de4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Sep 2021 21:08:02 -0700 +Subject: Input: goodix - change goodix_i2c_write() len parameter type to int + +From: Hans de Goede + +[ Upstream commit 31ae0102a34ed863c7d32b10e768036324991679 ] + +Change the type of the goodix_i2c_write() len parameter to from 'unsigned' +to 'int' to avoid bare use of 'unsigned', changing it to 'int' makes +goodix_i2c_write()' prototype consistent with goodix_i2c_read(). + +Reviewed-by: Bastien Nocera +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20210920150643.155872-2-hdegoede@redhat.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +--- + drivers/input/touchscreen/goodix.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c +index 5051a1766aac..1eb776abe562 100644 +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -246,7 +246,7 @@ static int goodix_i2c_read(struct i2c_client *client, + * @len: length of the buffer to write + */ + static int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, +- unsigned len) ++ int len) + { + u8 *addr_buf; + struct i2c_msg msg; +-- +2.35.1 + diff --git a/queue-5.15/input-goodix-refactor-reset-handling.patch b/queue-5.15/input-goodix-refactor-reset-handling.patch new file mode 100644 index 00000000000..07ebe4b155e --- /dev/null +++ b/queue-5.15/input-goodix-refactor-reset-handling.patch @@ -0,0 +1,162 @@ +From 3b2404e3b669cd19116ce4a758653b0948d5502e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Sep 2021 21:08:26 -0700 +Subject: Input: goodix - refactor reset handling + +From: Hans de Goede + +[ Upstream commit 209bda4741f68f102cf2f272227bfc938e387b51 ] + +Refactor reset handling a bit, change the main reset handler +into a new goodix_reset_no_int_sync() helper and add a +goodix_reset() wrapper which calls goodix_int_sync() +separately. + +Also push the dev_err() call on reset failure into the +goodix_reset_no_int_sync() and goodix_int_sync() functions, +so that we don't need to have separate dev_err() calls in +all their callers. + +This is a preparation patch for adding support for controllers +without flash, which need to have their firmware uploaded and +need some other special handling too. + +Reviewed-by: Bastien Nocera +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20210920150643.155872-4-hdegoede@redhat.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +--- + drivers/input/touchscreen/goodix.c | 48 ++++++++++++++++++++---------- + drivers/input/touchscreen/goodix.h | 1 + + 2 files changed, 33 insertions(+), 16 deletions(-) + +diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c +index 5ccdd6abd868..2ca903a8af21 100644 +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -596,56 +596,76 @@ int goodix_int_sync(struct goodix_ts_data *ts) + + error = goodix_irq_direction_output(ts, 0); + if (error) +- return error; ++ goto error; + + msleep(50); /* T5: 50ms */ + + error = goodix_irq_direction_input(ts); + if (error) +- return error; ++ goto error; + + return 0; ++ ++error: ++ dev_err(&ts->client->dev, "Controller irq sync failed.\n"); ++ return error; + } + + /** +- * goodix_reset - Reset device during power on ++ * goodix_reset_no_int_sync - Reset device, leaving interrupt line in output mode + * + * @ts: goodix_ts_data pointer + */ +-static int goodix_reset(struct goodix_ts_data *ts) ++int goodix_reset_no_int_sync(struct goodix_ts_data *ts) + { + int error; + + /* begin select I2C slave addr */ + error = gpiod_direction_output(ts->gpiod_rst, 0); + if (error) +- return error; ++ goto error; + + msleep(20); /* T2: > 10ms */ + + /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ + error = goodix_irq_direction_output(ts, ts->client->addr == 0x14); + if (error) +- return error; ++ goto error; + + usleep_range(100, 2000); /* T3: > 100us */ + + error = gpiod_direction_output(ts->gpiod_rst, 1); + if (error) +- return error; ++ goto error; + + usleep_range(6000, 10000); /* T4: > 5ms */ + + /* end select I2C slave addr */ + error = gpiod_direction_input(ts->gpiod_rst); + if (error) +- return error; ++ goto error; + +- error = goodix_int_sync(ts); ++ return 0; ++ ++error: ++ dev_err(&ts->client->dev, "Controller reset failed.\n"); ++ return error; ++} ++ ++/** ++ * goodix_reset - Reset device during power on ++ * ++ * @ts: goodix_ts_data pointer ++ */ ++static int goodix_reset(struct goodix_ts_data *ts) ++{ ++ int error; ++ ++ error = goodix_reset_no_int_sync(ts); + if (error) + return error; + +- return 0; ++ return goodix_int_sync(ts); + } + + #ifdef ACPI_GPIO_SUPPORT +@@ -1144,10 +1164,8 @@ static int goodix_ts_probe(struct i2c_client *client, + if (ts->reset_controller_at_probe) { + /* reset the controller */ + error = goodix_reset(ts); +- if (error) { +- dev_err(&client->dev, "Controller reset failed.\n"); ++ if (error) + return error; +- } + } + + error = goodix_i2c_test(client); +@@ -1289,10 +1307,8 @@ static int __maybe_unused goodix_resume(struct device *dev) + + if (error != 0 || config_ver != ts->config[0]) { + error = goodix_reset(ts); +- if (error) { +- dev_err(dev, "Controller reset failed.\n"); ++ if (error) + return error; +- } + + error = goodix_send_cfg(ts, ts->config, ts->chip->config_len); + if (error) +diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h +index cdaced4f2980..0b88554ba2ae 100644 +--- a/drivers/input/touchscreen/goodix.h ++++ b/drivers/input/touchscreen/goodix.h +@@ -69,5 +69,6 @@ int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len) + int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value); + int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len); + int goodix_int_sync(struct goodix_ts_data *ts); ++int goodix_reset_no_int_sync(struct goodix_ts_data *ts); + + #endif +-- +2.35.1 + diff --git a/queue-5.15/input-goodix-try-not-to-touch-the-reset-pin-on-x86-a.patch b/queue-5.15/input-goodix-try-not-to-touch-the-reset-pin-on-x86-a.patch new file mode 100644 index 00000000000..4a075c1e0ee --- /dev/null +++ b/queue-5.15/input-goodix-try-not-to-touch-the-reset-pin-on-x86-a.patch @@ -0,0 +1,124 @@ +From 737dfb405e507718ae739d0bf348f289e32d77dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Dec 2021 23:15:09 -0800 +Subject: Input: goodix - try not to touch the reset-pin on x86/ACPI devices + +From: Hans de Goede + +[ Upstream commit a2fd46cd3dbb83b373ba74f4043f8dae869c65f1 ] + +Unless the controller is not responding at boot or after suspend/resume, +the driver never resets the controller on x86/ACPI platforms. The driver +still requesting the reset pin at probe() though in case it needs it. + +Until now the driver has always requested the reset pin with GPIOD_IN +as type. The idea being to put the pin in high-impedance mode to save +power until the driver actually wants to issue a reset. + +But this means that just requesting the pin can cause issues, since +requesting it in another mode then GPIOD_ASIS may cause the pinctrl +driver to touch the pin settings. We have already had issues before +due to a bug in the pinctrl-cherryview.c driver which has been fixed in +commit 921daeeca91b ("pinctrl: cherryview: Preserve +CHV_PADCTRL1_INVRXTX_TXDATA flag on GPIOs"). + +And now it turns out that requesting the reset-pin as GPIOD_IN also stops +the touchscreen from working on the GPD P2 max mini-laptop. The behavior +of putting the pin in high-impedance mode relies on there being some +external pull-up to keep it high and there seems to be no pull-up on the +GPD P2 max, causing things to break. + +This commit fixes this by requesting the reset pin as is when using +the x86/ACPI code paths to lookup the GPIOs; and by not dropping it +back into input-mode in case the driver does end up issuing a reset +for error-recovery. + +BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=209061 +Fixes: a7d4b171660c ("Input: goodix - add support for getting IRQ + reset GPIOs on Cherry Trail devices") +Cc: stable@vger.kernel.org +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20211206091116.44466-2-hdegoede@redhat.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +--- + drivers/input/touchscreen/goodix.c | 30 +++++++++++++++++++++++++----- + drivers/input/touchscreen/goodix.h | 1 + + 2 files changed, 26 insertions(+), 5 deletions(-) + +diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c +index 2ca903a8af21..3667f7e51fde 100644 +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -640,10 +640,16 @@ int goodix_reset_no_int_sync(struct goodix_ts_data *ts) + + usleep_range(6000, 10000); /* T4: > 5ms */ + +- /* end select I2C slave addr */ +- error = gpiod_direction_input(ts->gpiod_rst); +- if (error) +- goto error; ++ /* ++ * Put the reset pin back in to input / high-impedance mode to save ++ * power. Only do this in the non ACPI case since some ACPI boards ++ * don't have a pull-up, so there the reset pin must stay active-high. ++ */ ++ if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) { ++ error = gpiod_direction_input(ts->gpiod_rst); ++ if (error) ++ goto error; ++ } + + return 0; + +@@ -777,6 +783,14 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts) + return -EINVAL; + } + ++ /* ++ * Normally we put the reset pin in input / high-impedance mode to save ++ * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI ++ * case, leave the pin as is. This results in the pin not being touched ++ * at all on x86/ACPI boards, except when needed for error-recover. ++ */ ++ ts->gpiod_rst_flags = GPIOD_ASIS; ++ + return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping); + } + #else +@@ -802,6 +816,12 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts) + return -EINVAL; + dev = &ts->client->dev; + ++ /* ++ * By default we request the reset pin as input, leaving it in ++ * high-impedance when not resetting the controller to save power. ++ */ ++ ts->gpiod_rst_flags = GPIOD_IN; ++ + ts->avdd28 = devm_regulator_get(dev, "AVDD28"); + if (IS_ERR(ts->avdd28)) { + error = PTR_ERR(ts->avdd28); +@@ -839,7 +859,7 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts) + ts->gpiod_int = gpiod; + + /* Get the reset line GPIO pin number */ +- gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN); ++ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags); + if (IS_ERR(gpiod)) { + error = PTR_ERR(gpiod); + if (error != -EPROBE_DEFER) +diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h +index 0b88554ba2ae..1a1571ad2cd2 100644 +--- a/drivers/input/touchscreen/goodix.h ++++ b/drivers/input/touchscreen/goodix.h +@@ -51,6 +51,7 @@ struct goodix_ts_data { + struct gpio_desc *gpiod_rst; + int gpio_count; + int gpio_int_idx; ++ enum gpiod_flags gpiod_rst_flags; + char id[GOODIX_ID_MAX_LEN + 1]; + u16 version; + const char *cfg_name; +-- +2.35.1 + diff --git a/queue-5.15/io_uring-avoid-io-wq-eagain-looping-for-iopoll.patch b/queue-5.15/io_uring-avoid-io-wq-eagain-looping-for-iopoll.patch new file mode 100644 index 00000000000..d375efc9afd --- /dev/null +++ b/queue-5.15/io_uring-avoid-io-wq-eagain-looping-for-iopoll.patch @@ -0,0 +1,40 @@ +From 24c560ad675bfcdd4ff3c5e4948716b40e953857 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 May 2022 11:24:56 +0100 +Subject: io_uring: avoid io-wq -EAGAIN looping for !IOPOLL + +From: Pavel Begunkov + +[ Upstream commit e0deb6a025ae8c850dc8685be39fb27b06c88736 ] + +If an opcode handler semi-reliably returns -EAGAIN, io_wq_submit_work() +might continue busily hammer the same handler over and over again, which +is not ideal. The -EAGAIN handling in question was put there only for +IOPOLL, so restrict it to IOPOLL mode only where there is no other +recourse than to retry as we cannot wait. + +Fixes: def596e9557c9 ("io_uring: support for IO polling") +Signed-off-by: Pavel Begunkov +Link: https://lore.kernel.org/r/f168b4f24181942f3614dd8ff648221736f572e6.1652433740.git.asml.silence@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/io_uring.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/io_uring.c b/fs/io_uring.c +index 0c5dcda0b622..9bff14c5e2b2 100644 +--- a/fs/io_uring.c ++++ b/fs/io_uring.c +@@ -6866,7 +6866,7 @@ static void io_wq_submit_work(struct io_wq_work *work) + * forcing a sync submission from here, since we can't + * wait for request slots on the block side. + */ +- if (ret != -EAGAIN) ++ if (ret != -EAGAIN || !(req->ctx->flags & IORING_SETUP_IOPOLL)) + break; + cond_resched(); + } while (1); +-- +2.35.1 + diff --git a/queue-5.15/io_uring-ensure-that-fsnotify-is-always-called.patch b/queue-5.15/io_uring-ensure-that-fsnotify-is-always-called.patch new file mode 100644 index 00000000000..f46fbff652e --- /dev/null +++ b/queue-5.15/io_uring-ensure-that-fsnotify-is-always-called.patch @@ -0,0 +1,52 @@ +From 51188a669f04cc25caf168d4544e9107dda827c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 20 Mar 2022 13:08:38 -0600 +Subject: io_uring: ensure that fsnotify is always called + +From: Jens Axboe + +[ Upstream commit f63cf5192fe3418ad5ae1a4412eba5694b145f79 ] + +Ensure that we call fsnotify_modify() if we write a file, and that we +do fsnotify_access() if we read it. This enables anyone using inotify +on the file to get notified. + +Ditto for fallocate, ensure that fsnotify_modify() is called. + +Cc: stable@vger.kernel.org +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + fs/io_uring.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/io_uring.c b/fs/io_uring.c +index 189323740324..0c5dcda0b622 100644 +--- a/fs/io_uring.c ++++ b/fs/io_uring.c +@@ -2686,8 +2686,12 @@ static bool io_rw_should_reissue(struct io_kiocb *req) + + static bool __io_complete_rw_common(struct io_kiocb *req, long res) + { +- if (req->rw.kiocb.ki_flags & IOCB_WRITE) ++ if (req->rw.kiocb.ki_flags & IOCB_WRITE) { + kiocb_end_write(req); ++ fsnotify_modify(req->file); ++ } else { ++ fsnotify_access(req->file); ++ } + if (res != req->result) { + if ((res == -EAGAIN || res == -EOPNOTSUPP) && + io_rw_should_reissue(req)) { +@@ -4183,6 +4187,8 @@ static int io_fallocate(struct io_kiocb *req, unsigned int issue_flags) + req->sync.len); + if (ret < 0) + req_set_fail(req); ++ else ++ fsnotify_modify(req->file); + io_req_complete(req, ret); + return 0; + } +-- +2.35.1 + diff --git a/queue-5.15/irqchip-gic-v3-ensure-pseudo-nmis-have-an-isb-betwee.patch b/queue-5.15/irqchip-gic-v3-ensure-pseudo-nmis-have-an-isb-betwee.patch new file mode 100644 index 00000000000..2ab6aad5181 --- /dev/null +++ b/queue-5.15/irqchip-gic-v3-ensure-pseudo-nmis-have-an-isb-betwee.patch @@ -0,0 +1,59 @@ +From 245f33562bcf9122b04ca6dc7b81cbbda44aa525 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 May 2022 14:30:36 +0100 +Subject: irqchip/gic-v3: Ensure pseudo-NMIs have an ISB between ack and + handling + +From: Mark Rutland + +[ Upstream commit adf14453d2c037ab529040c1186ea32e277e783a ] + +There are cases where a context synchronization event is necessary +between an IRQ being raised and being handled, and there are races such +that we cannot rely upon the exception entry being subsequent to the +interrupt being raised. + +We identified and fixes this for regular IRQs in commit: + + 39a06b67c2c1256b ("irqchip/gic: Ensure we have an ISB between ack and ->handle_irq") + +Unfortunately, we forgot to do the same for psuedo-NMIs when support for +those was added in commit: + + f32c926651dcd168 ("irqchip/gic-v3: Handle pseudo-NMIs") + +Which means that when pseudo-NMIs are used for PMU support, we'll hit +the same problem. + +Apply the same fix as for regular IRQs. Note that when EOI mode 1 is in +use, the call to gic_write_eoir() will provide an ISB. + +Fixes: f32c926651dcd168 ("irqchip/gic-v3: Handle pseudo-NMIs") +Signed-off-by: Mark Rutland +Cc: Marc Zyngier +Cc: Thomas Gleixner +Cc: Will Deacon +Signed-off-by: Marc Zyngier +Link: https://lore.kernel.org/r/20220513133038.226182-2-mark.rutland@arm.com +Signed-off-by: Sasha Levin +--- + drivers/irqchip/irq-gic-v3.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c +index fd4fb1b35787..d8ea330454f4 100644 +--- a/drivers/irqchip/irq-gic-v3.c ++++ b/drivers/irqchip/irq-gic-v3.c +@@ -654,6 +654,9 @@ static inline void gic_handle_nmi(u32 irqnr, struct pt_regs *regs) + + if (static_branch_likely(&supports_deactivate_key)) + gic_write_eoir(irqnr); ++ else ++ isb() ++ + /* + * Leave the PSR.I bit set to prevent other NMIs to be + * received while handling this one. +-- +2.35.1 + diff --git a/queue-5.15/kvm-don-t-create-vm-debugfs-files-outside-of-the-vm-.patch b/queue-5.15/kvm-don-t-create-vm-debugfs-files-outside-of-the-vm-.patch new file mode 100644 index 00000000000..f81c3b6f99f --- /dev/null +++ b/queue-5.15/kvm-don-t-create-vm-debugfs-files-outside-of-the-vm-.patch @@ -0,0 +1,73 @@ +From 2985ca62cf7ef0744a894c07d95826db41667038 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Apr 2022 23:56:13 +0000 +Subject: KVM: Don't create VM debugfs files outside of the VM directory + +From: Oliver Upton + +[ Upstream commit a44a4cc1c969afec97dbb2aedaf6f38eaa6253bb ] + +Unfortunately, there is no guarantee that KVM was able to instantiate a +debugfs directory for a particular VM. To that end, KVM shouldn't even +attempt to create new debugfs files in this case. If the specified +parent dentry is NULL, debugfs_create_file() will instantiate files at +the root of debugfs. + +For arm64, it is possible to create the vgic-state file outside of a +VM directory, the file is not cleaned up when a VM is destroyed. +Nonetheless, the corresponding struct kvm is freed when the VM is +destroyed. + +Nip the problem in the bud for all possible errant debugfs file +creations by initializing kvm->debugfs_dentry to -ENOENT. In so doing, +debugfs_create_file() will fail instead of creating the file in the root +directory. + +Cc: stable@kernel.org +Fixes: 929f45e32499 ("kvm: no need to check return value of debugfs_create functions") +Signed-off-by: Oliver Upton +Signed-off-by: Marc Zyngier +Link: https://lore.kernel.org/r/20220406235615.1447180-2-oupton@google.com +Signed-off-by: Sasha Levin +--- + virt/kvm/kvm_main.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index 99c591569815..9134ae252d7c 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -911,7 +911,7 @@ static void kvm_destroy_vm_debugfs(struct kvm *kvm) + int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc + + kvm_vcpu_stats_header.num_desc; + +- if (!kvm->debugfs_dentry) ++ if (IS_ERR(kvm->debugfs_dentry)) + return; + + debugfs_remove_recursive(kvm->debugfs_dentry); +@@ -934,6 +934,12 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd) + int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc + + kvm_vcpu_stats_header.num_desc; + ++ /* ++ * Force subsequent debugfs file creations to fail if the VM directory ++ * is not created. ++ */ ++ kvm->debugfs_dentry = ERR_PTR(-ENOENT); ++ + if (!debugfs_initialized()) + return 0; + +@@ -5373,7 +5379,7 @@ static void kvm_uevent_notify_change(unsigned int type, struct kvm *kvm) + } + add_uevent_var(env, "PID=%d", kvm->userspace_pid); + +- if (kvm->debugfs_dentry) { ++ if (!IS_ERR(kvm->debugfs_dentry)) { + char *tmp, *p = kmalloc(PATH_MAX, GFP_KERNEL_ACCOUNT); + + if (p) { +-- +2.35.1 + diff --git a/queue-5.15/kvm-initialize-debugfs_dentry-when-a-vm-is-created-t.patch b/queue-5.15/kvm-initialize-debugfs_dentry-when-a-vm-is-created-t.patch new file mode 100644 index 00000000000..8dd1b00c333 --- /dev/null +++ b/queue-5.15/kvm-initialize-debugfs_dentry-when-a-vm-is-created-t.patch @@ -0,0 +1,83 @@ +From 4f13ab50660d60629e63fbb603c25f1a6c9a1427 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Apr 2022 00:46:22 +0000 +Subject: KVM: Initialize debugfs_dentry when a VM is created to avoid NULL + deref + +From: Sean Christopherson + +[ Upstream commit 5c697c367a66307a5d943c3449421aff2aa3ca4a ] + +Initialize debugfs_entry to its semi-magical -ENOENT value when the VM +is created. KVM's teardown when VM creation fails is kludgy and calls +kvm_uevent_notify_change() and kvm_destroy_vm_debugfs() even if KVM never +attempted kvm_create_vm_debugfs(). Because debugfs_entry is zero +initialized, the IS_ERR() checks pass and KVM derefs a NULL pointer. + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + #PF: supervisor read access in kernel mode + #PF: error_code(0x0000) - not-present page + PGD 1068b1067 P4D 1068b1067 PUD 1068b0067 PMD 0 + Oops: 0000 [#1] SMP + CPU: 0 PID: 871 Comm: repro Not tainted 5.18.0-rc1+ #825 + Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 + RIP: 0010:__dentry_path+0x7b/0x130 + Call Trace: + + dentry_path_raw+0x42/0x70 + kvm_uevent_notify_change.part.0+0x10c/0x200 [kvm] + kvm_put_kvm+0x63/0x2b0 [kvm] + kvm_dev_ioctl+0x43a/0x920 [kvm] + __x64_sys_ioctl+0x83/0xb0 + do_syscall_64+0x31/0x50 + entry_SYSCALL_64_after_hwframe+0x44/0xae + + Modules linked in: kvm_intel kvm irqbypass + +Fixes: a44a4cc1c969 ("KVM: Don't create VM debugfs files outside of the VM directory") +Cc: stable@vger.kernel.org +Cc: Marc Zyngier +Cc: Oliver Upton +Reported-by: syzbot+df6fbbd2ee39f21289ef@syzkaller.appspotmail.com +Signed-off-by: Sean Christopherson +Reviewed-by: Oliver Upton +Message-Id: <20220415004622.2207751-1-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + virt/kvm/kvm_main.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index 9134ae252d7c..9eac68ae291e 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -934,12 +934,6 @@ static int kvm_create_vm_debugfs(struct kvm *kvm, int fd) + int kvm_debugfs_num_entries = kvm_vm_stats_header.num_desc + + kvm_vcpu_stats_header.num_desc; + +- /* +- * Force subsequent debugfs file creations to fail if the VM directory +- * is not created. +- */ +- kvm->debugfs_dentry = ERR_PTR(-ENOENT); +- + if (!debugfs_initialized()) + return 0; + +@@ -1055,6 +1049,12 @@ static struct kvm *kvm_create_vm(unsigned long type) + + BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX); + ++ /* ++ * Force subsequent debugfs file creations to fail if the VM directory ++ * is not created (by kvm_create_vm_debugfs()). ++ */ ++ kvm->debugfs_dentry = ERR_PTR(-ENOENT); ++ + if (init_srcu_struct(&kvm->srcu)) + goto out_err_no_srcu; + if (init_srcu_struct(&kvm->irq_srcu)) +-- +2.35.1 + diff --git a/queue-5.15/kvm-s390x-fix-sck-locking.patch b/queue-5.15/kvm-s390x-fix-sck-locking.patch new file mode 100644 index 00000000000..7fd207e0d23 --- /dev/null +++ b/queue-5.15/kvm-s390x-fix-sck-locking.patch @@ -0,0 +1,135 @@ +From 61debb18b5c11bf52e37e7e2c62468b44a3cdbcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Mar 2022 15:33:40 +0100 +Subject: KVM: s390x: fix SCK locking + +From: Claudio Imbrenda + +[ Upstream commit c0573ba5c5a2244dc02060b1f374d4593c1d20b7 ] + +When handling the SCK instruction, the kvm lock is taken, even though +the vcpu lock is already being held. The normal locking order is kvm +lock first and then vcpu lock. This is can (and in some circumstances +does) lead to deadlocks. + +The function kvm_s390_set_tod_clock is called both by the SCK handler +and by some IOCTLs to set the clock. The IOCTLs will not hold the vcpu +lock, so they can safely take the kvm lock. The SCK handler holds the +vcpu lock, but will also somehow need to acquire the kvm lock without +relinquishing the vcpu lock. + +The solution is to factor out the code to set the clock, and provide +two wrappers. One is called like the original function and does the +locking, the other is called kvm_s390_try_set_tod_clock and uses +trylock to try to acquire the kvm lock. This new wrapper is then used +in the SCK handler. If locking fails, -EAGAIN is returned, which is +eventually propagated to userspace, thus also freeing the vcpu lock and +allowing for forward progress. + +This is not the most efficient or elegant way to solve this issue, but +the SCK instruction is deprecated and its performance is not critical. + +The goal of this patch is just to provide a simple but correct way to +fix the bug. + +Fixes: 6a3f95a6b04c ("KVM: s390: Intercept SCK instruction") +Signed-off-by: Claudio Imbrenda +Reviewed-by: Christian Borntraeger +Reviewed-by: Janis Schoetterl-Glausch +Link: https://lore.kernel.org/r/20220301143340.111129-1-imbrenda@linux.ibm.com +Cc: stable@vger.kernel.org +Signed-off-by: Christian Borntraeger +Signed-off-by: Sasha Levin +--- + arch/s390/kvm/kvm-s390.c | 19 ++++++++++++++++--- + arch/s390/kvm/kvm-s390.h | 4 ++-- + arch/s390/kvm/priv.c | 15 ++++++++++++++- + 3 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c +index 402597f9d050..b456aa196c04 100644 +--- a/arch/s390/kvm/kvm-s390.c ++++ b/arch/s390/kvm/kvm-s390.c +@@ -3913,14 +3913,12 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) + return 0; + } + +-void kvm_s390_set_tod_clock(struct kvm *kvm, +- const struct kvm_s390_vm_tod_clock *gtod) ++static void __kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod) + { + struct kvm_vcpu *vcpu; + union tod_clock clk; + int i; + +- mutex_lock(&kvm->lock); + preempt_disable(); + + store_tod_clock_ext(&clk); +@@ -3941,7 +3939,22 @@ void kvm_s390_set_tod_clock(struct kvm *kvm, + + kvm_s390_vcpu_unblock_all(kvm); + preempt_enable(); ++} ++ ++void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod) ++{ ++ mutex_lock(&kvm->lock); ++ __kvm_s390_set_tod_clock(kvm, gtod); ++ mutex_unlock(&kvm->lock); ++} ++ ++int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod) ++{ ++ if (!mutex_trylock(&kvm->lock)) ++ return 0; ++ __kvm_s390_set_tod_clock(kvm, gtod); + mutex_unlock(&kvm->lock); ++ return 1; + } + + /** +diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h +index 1539dd981104..f8803bf0ff17 100644 +--- a/arch/s390/kvm/kvm-s390.h ++++ b/arch/s390/kvm/kvm-s390.h +@@ -326,8 +326,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); + int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu); + + /* implemented in kvm-s390.c */ +-void kvm_s390_set_tod_clock(struct kvm *kvm, +- const struct kvm_s390_vm_tod_clock *gtod); ++void kvm_s390_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod); ++int kvm_s390_try_set_tod_clock(struct kvm *kvm, const struct kvm_s390_vm_tod_clock *gtod); + long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable); + int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr); + int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr); +diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c +index 417154b314a6..6a765fe22eaf 100644 +--- a/arch/s390/kvm/priv.c ++++ b/arch/s390/kvm/priv.c +@@ -102,7 +102,20 @@ static int handle_set_clock(struct kvm_vcpu *vcpu) + return kvm_s390_inject_prog_cond(vcpu, rc); + + VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod); +- kvm_s390_set_tod_clock(vcpu->kvm, >od); ++ /* ++ * To set the TOD clock the kvm lock must be taken, but the vcpu lock ++ * is already held in handle_set_clock. The usual lock order is the ++ * opposite. As SCK is deprecated and should not be used in several ++ * cases, for example when the multiple epoch facility or TOD clock ++ * steering facility is installed (see Principles of Operation), a ++ * slow path can be used. If the lock can not be taken via try_lock, ++ * the instruction will be retried via -EAGAIN at a later point in ++ * time. ++ */ ++ if (!kvm_s390_try_set_tod_clock(vcpu->kvm, >od)) { ++ kvm_s390_retry_instr(vcpu); ++ return -EAGAIN; ++ } + + kvm_s390_set_psw_cc(vcpu, 0); + return 0; +-- +2.35.1 + diff --git a/queue-5.15/kvm-use-__vcalloc-for-very-large-allocations.patch b/queue-5.15/kvm-use-__vcalloc-for-very-large-allocations.patch new file mode 100644 index 00000000000..b8f1cb19a82 --- /dev/null +++ b/queue-5.15/kvm-use-__vcalloc-for-very-large-allocations.patch @@ -0,0 +1,94 @@ +From 7d144e57875e6e10e3e93bf63061f0761191419d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Mar 2022 04:49:37 -0500 +Subject: KVM: use __vcalloc for very large allocations + +From: Paolo Bonzini + +[ Upstream commit 37b2a6510a48ca361ced679f92682b7b7d7d0330 ] + +Allocations whose size is related to the memslot size can be arbitrarily +large. Do not use kvzalloc/kvcalloc, as those are limited to "not crazy" +sizes that fit in 32 bits. + +Cc: stable@vger.kernel.org +Fixes: 7661809d493b ("mm: don't allow oversized kvmalloc() calls") +Reviewed-by: David Hildenbrand +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/powerpc/kvm/book3s_hv_uvmem.c | 2 +- + arch/x86/kvm/mmu/page_track.c | 4 ++-- + arch/x86/kvm/x86.c | 4 ++-- + virt/kvm/kvm_main.c | 4 ++-- + 4 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c b/arch/powerpc/kvm/book3s_hv_uvmem.c +index 3fbe710ff839..3d4ee75b0fb7 100644 +--- a/arch/powerpc/kvm/book3s_hv_uvmem.c ++++ b/arch/powerpc/kvm/book3s_hv_uvmem.c +@@ -251,7 +251,7 @@ int kvmppc_uvmem_slot_init(struct kvm *kvm, const struct kvm_memory_slot *slot) + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; +- p->pfns = vzalloc(array_size(slot->npages, sizeof(*p->pfns))); ++ p->pfns = vcalloc(slot->npages, sizeof(*p->pfns)); + if (!p->pfns) { + kfree(p); + return -ENOMEM; +diff --git a/arch/x86/kvm/mmu/page_track.c b/arch/x86/kvm/mmu/page_track.c +index 21427e84a82e..630ae70bb6bd 100644 +--- a/arch/x86/kvm/mmu/page_track.c ++++ b/arch/x86/kvm/mmu/page_track.c +@@ -36,8 +36,8 @@ int kvm_page_track_create_memslot(struct kvm_memory_slot *slot, + + for (i = 0; i < KVM_PAGE_TRACK_MAX; i++) { + slot->arch.gfn_track[i] = +- kvcalloc(npages, sizeof(*slot->arch.gfn_track[i]), +- GFP_KERNEL_ACCOUNT); ++ __vcalloc(npages, sizeof(*slot->arch.gfn_track[i]), ++ GFP_KERNEL_ACCOUNT); + if (!slot->arch.gfn_track[i]) + goto track_free; + } +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 39aaa21e28f7..8974884ef2ad 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -11552,7 +11552,7 @@ static int memslot_rmap_alloc(struct kvm_memory_slot *slot, + if (slot->arch.rmap[i]) + continue; + +- slot->arch.rmap[i] = kvcalloc(lpages, sz, GFP_KERNEL_ACCOUNT); ++ slot->arch.rmap[i] = __vcalloc(lpages, sz, GFP_KERNEL_ACCOUNT); + if (!slot->arch.rmap[i]) { + memslot_rmap_free(slot); + return -ENOMEM; +@@ -11633,7 +11633,7 @@ static int kvm_alloc_memslot_metadata(struct kvm *kvm, + + lpages = __kvm_mmu_slot_lpages(slot, npages, level); + +- linfo = kvcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT); ++ linfo = __vcalloc(lpages, sizeof(*linfo), GFP_KERNEL_ACCOUNT); + if (!linfo) + goto out_free; + +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index fefdf3a6dae3..99c591569815 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -1255,9 +1255,9 @@ static int kvm_vm_release(struct inode *inode, struct file *filp) + */ + static int kvm_alloc_dirty_bitmap(struct kvm_memory_slot *memslot) + { +- unsigned long dirty_bytes = 2 * kvm_dirty_bitmap_bytes(memslot); ++ unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(memslot); + +- memslot->dirty_bitmap = kvzalloc(dirty_bytes, GFP_KERNEL_ACCOUNT); ++ memslot->dirty_bitmap = __vcalloc(2, dirty_bytes, GFP_KERNEL_ACCOUNT); + if (!memslot->dirty_bitmap) + return -ENOMEM; + +-- +2.35.1 + diff --git a/queue-5.15/kvm-x86-mmu-use-common-tdp-mmu-zap-helper-for-mmu-no.patch b/queue-5.15/kvm-x86-mmu-use-common-tdp-mmu-zap-helper-for-mmu-no.patch new file mode 100644 index 00000000000..67bec90a41e --- /dev/null +++ b/queue-5.15/kvm-x86-mmu-use-common-tdp-mmu-zap-helper-for-mmu-no.patch @@ -0,0 +1,50 @@ +From 0a25179387b96a566e3b371ef59279f1ea916809 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Dec 2021 01:15:54 +0000 +Subject: KVM: x86/mmu: Use common TDP MMU zap helper for MMU notifier unmap + hook + +From: Sean Christopherson + +[ Upstream commit 83b83a02073ec8d18c77a9bbe0881d710f7a9d32 ] + +Use the common TDP MMU zap helper when handling an MMU notifier unmap +event, the two flows are semantically identical. Consolidate the code in +preparation for a future bug fix, as both kvm_tdp_mmu_unmap_gfn_range() +and __kvm_tdp_mmu_zap_gfn_range() are guilty of not zapping SPTEs in +invalid roots. + +No functional change intended. + +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Message-Id: <20211215011557.399940-2-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/tdp_mmu.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c +index 6195f0d219ae..6c2bb60ccd88 100644 +--- a/arch/x86/kvm/mmu/tdp_mmu.c ++++ b/arch/x86/kvm/mmu/tdp_mmu.c +@@ -1098,13 +1098,8 @@ int kvm_tdp_mmu_map(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code, + bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range, + bool flush) + { +- struct kvm_mmu_page *root; +- +- for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false) +- flush = zap_gfn_range(kvm, root, range->start, range->end, +- range->may_block, flush, false); +- +- return flush; ++ return __kvm_tdp_mmu_zap_gfn_range(kvm, range->slot->as_id, range->start, ++ range->end, range->may_block, flush); + } + + typedef bool (*tdp_handler_t)(struct kvm *kvm, struct tdp_iter *iter, +-- +2.35.1 + diff --git a/queue-5.15/kvm-x86-mmu-use-yield-safe-tdp-mmu-root-iter-in-mmu-.patch b/queue-5.15/kvm-x86-mmu-use-yield-safe-tdp-mmu-root-iter-in-mmu-.patch new file mode 100644 index 00000000000..047bf7ace23 --- /dev/null +++ b/queue-5.15/kvm-x86-mmu-use-yield-safe-tdp-mmu-root-iter-in-mmu-.patch @@ -0,0 +1,40 @@ +From b6d49e59a28b2f32843078a88e9867be0f4d4539 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Nov 2021 01:50:08 +0000 +Subject: KVM: x86/mmu: Use yield-safe TDP MMU root iter in MMU notifier + unmapping + +From: Sean Christopherson + +[ Upstream commit 7533377215b6ee432c06c5855f6be5d66e694e46 ] + +Use the yield-safe variant of the TDP MMU iterator when handling an +unmapping event from the MMU notifier, as most occurences of the event +allow yielding. + +Fixes: e1eed5847b09 ("KVM: x86/mmu: Allow yielding during MMU notifier unmap/zap, if possible") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Message-Id: <20211120015008.3780032-1-seanjc@google.com> +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + arch/x86/kvm/mmu/tdp_mmu.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c +index 853780eb033b..6195f0d219ae 100644 +--- a/arch/x86/kvm/mmu/tdp_mmu.c ++++ b/arch/x86/kvm/mmu/tdp_mmu.c +@@ -1100,7 +1100,7 @@ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range, + { + struct kvm_mmu_page *root; + +- for_each_tdp_mmu_root(kvm, root, range->slot->as_id) ++ for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false) + flush = zap_gfn_range(kvm, root, range->start, range->end, + range->may_block, flush, false); + +-- +2.35.1 + diff --git a/queue-5.15/media-davinci-vpif-fix-use-after-free-on-driver-unbi.patch b/queue-5.15/media-davinci-vpif-fix-use-after-free-on-driver-unbi.patch new file mode 100644 index 00000000000..840a5dc30ca --- /dev/null +++ b/queue-5.15/media-davinci-vpif-fix-use-after-free-on-driver-unbi.patch @@ -0,0 +1,189 @@ +From e5374a0d2e9679bb6d597bf0c47508d5b2316665 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Dec 2021 15:20:24 +0100 +Subject: media: davinci: vpif: fix use-after-free on driver unbind + +From: Johan Hovold + +[ Upstream commit 43acb728bbc40169d2e2425e84a80068270974be ] + +The driver allocates and registers two platform device structures during +probe, but the devices were never deregistered on driver unbind. + +This results in a use-after-free on driver unbind as the device +structures were allocated using devres and would be freed by driver +core when remove() returns. + +Fix this by adding the missing deregistration calls to the remove() +callback and failing probe on registration errors. + +Note that the platform device structures must be freed using a proper +release callback to avoid leaking associated resources like device +names. + +Fixes: 479f7a118105 ("[media] davinci: vpif: adaptions for DT support") +Cc: stable@vger.kernel.org # 4.12 +Cc: Kevin Hilman +Signed-off-by: Johan Hovold +Reviewed-by: Lad Prabhakar +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/davinci/vpif.c | 97 ++++++++++++++++++++------- + 1 file changed, 71 insertions(+), 26 deletions(-) + +diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c +index 5658c7f148d7..8ffc01c606d0 100644 +--- a/drivers/media/platform/davinci/vpif.c ++++ b/drivers/media/platform/davinci/vpif.c +@@ -41,6 +41,11 @@ MODULE_ALIAS("platform:" VPIF_DRIVER_NAME); + #define VPIF_CH2_MAX_MODES 15 + #define VPIF_CH3_MAX_MODES 2 + ++struct vpif_data { ++ struct platform_device *capture; ++ struct platform_device *display; ++}; ++ + DEFINE_SPINLOCK(vpif_lock); + EXPORT_SYMBOL_GPL(vpif_lock); + +@@ -423,11 +428,19 @@ int vpif_channel_getfid(u8 channel_id) + } + EXPORT_SYMBOL(vpif_channel_getfid); + ++static void vpif_pdev_release(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ ++ kfree(pdev); ++} ++ + static int vpif_probe(struct platform_device *pdev) + { + static struct resource *res, *res_irq; + struct platform_device *pdev_capture, *pdev_display; + struct device_node *endpoint = NULL; ++ struct vpif_data *data; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +@@ -435,6 +448,12 @@ static int vpif_probe(struct platform_device *pdev) + if (IS_ERR(vpif_base)) + return PTR_ERR(vpif_base); + ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, data); ++ + pm_runtime_enable(&pdev->dev); + pm_runtime_get(&pdev->dev); + +@@ -462,49 +481,75 @@ static int vpif_probe(struct platform_device *pdev) + goto err_put_rpm; + } + +- pdev_capture = devm_kzalloc(&pdev->dev, sizeof(*pdev_capture), +- GFP_KERNEL); +- if (pdev_capture) { +- pdev_capture->name = "vpif_capture"; +- pdev_capture->id = -1; +- pdev_capture->resource = res_irq; +- pdev_capture->num_resources = 1; +- pdev_capture->dev.dma_mask = pdev->dev.dma_mask; +- pdev_capture->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; +- pdev_capture->dev.parent = &pdev->dev; +- platform_device_register(pdev_capture); +- } else { +- dev_warn(&pdev->dev, "Unable to allocate memory for pdev_capture.\n"); ++ pdev_capture = kzalloc(sizeof(*pdev_capture), GFP_KERNEL); ++ if (!pdev_capture) { ++ ret = -ENOMEM; ++ goto err_put_rpm; + } + +- pdev_display = devm_kzalloc(&pdev->dev, sizeof(*pdev_display), +- GFP_KERNEL); +- if (pdev_display) { +- pdev_display->name = "vpif_display"; +- pdev_display->id = -1; +- pdev_display->resource = res_irq; +- pdev_display->num_resources = 1; +- pdev_display->dev.dma_mask = pdev->dev.dma_mask; +- pdev_display->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; +- pdev_display->dev.parent = &pdev->dev; +- platform_device_register(pdev_display); +- } else { +- dev_warn(&pdev->dev, "Unable to allocate memory for pdev_display.\n"); ++ pdev_capture->name = "vpif_capture"; ++ pdev_capture->id = -1; ++ pdev_capture->resource = res_irq; ++ pdev_capture->num_resources = 1; ++ pdev_capture->dev.dma_mask = pdev->dev.dma_mask; ++ pdev_capture->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; ++ pdev_capture->dev.parent = &pdev->dev; ++ pdev_capture->dev.release = vpif_pdev_release; ++ ++ ret = platform_device_register(pdev_capture); ++ if (ret) ++ goto err_put_pdev_capture; ++ ++ pdev_display = kzalloc(sizeof(*pdev_display), GFP_KERNEL); ++ if (!pdev_display) { ++ ret = -ENOMEM; ++ goto err_put_pdev_capture; + } + ++ pdev_display->name = "vpif_display"; ++ pdev_display->id = -1; ++ pdev_display->resource = res_irq; ++ pdev_display->num_resources = 1; ++ pdev_display->dev.dma_mask = pdev->dev.dma_mask; ++ pdev_display->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; ++ pdev_display->dev.parent = &pdev->dev; ++ pdev_display->dev.release = vpif_pdev_release; ++ ++ ret = platform_device_register(pdev_display); ++ if (ret) ++ goto err_put_pdev_display; ++ ++ data->capture = pdev_capture; ++ data->display = pdev_display; ++ + return 0; + ++err_put_pdev_display: ++ platform_device_put(pdev_display); ++err_put_pdev_capture: ++ platform_device_put(pdev_capture); + err_put_rpm: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); ++ kfree(data); + + return ret; + } + + static int vpif_remove(struct platform_device *pdev) + { ++ struct vpif_data *data = platform_get_drvdata(pdev); ++ ++ if (data->capture) ++ platform_device_unregister(data->capture); ++ if (data->display) ++ platform_device_unregister(data->display); ++ + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); ++ ++ kfree(data); ++ + return 0; + } + +-- +2.35.1 + diff --git a/queue-5.15/media-ir_toy-prevent-device-from-hanging-during-tran.patch b/queue-5.15/media-ir_toy-prevent-device-from-hanging-during-tran.patch new file mode 100644 index 00000000000..67813f33d64 --- /dev/null +++ b/queue-5.15/media-ir_toy-prevent-device-from-hanging-during-tran.patch @@ -0,0 +1,40 @@ +From 98157c283c583fd9fcb7974e6fe4167a57dc0567 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Sep 2021 16:57:46 +0200 +Subject: media: ir_toy: prevent device from hanging during transmit + +From: Sean Young + +[ Upstream commit 4114978dcd24e72415276bba60ff4ff355970bbc ] + +If the IR Toy is receiving IR while a transmit is done, it may end up +hanging. We can prevent this from happening by re-entering sample mode +just before issuing the transmit command. + +Link: https://github.com/bengtmartensson/HarcHardware/discussions/25 + +Cc: stable@vger.kernel.org +[mchehab: renamed: s/STATE_RESET/STATE_COMMAND_NO_RESP/ ] +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/rc/ir_toy.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c +index 7f394277478b..53ae19fa103a 100644 +--- a/drivers/media/rc/ir_toy.c ++++ b/drivers/media/rc/ir_toy.c +@@ -310,7 +310,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count) + buf[i] = cpu_to_be16(v); + } + +- buf[count] = cpu_to_be16(0xffff); ++ buf[count] = 0xffff; + + irtoy->tx_buf = buf; + irtoy->tx_len = size; +-- +2.35.1 + diff --git a/queue-5.15/media-omap3isp-use-struct_group-for-memcpy-region.patch b/queue-5.15/media-omap3isp-use-struct_group-for-memcpy-region.patch new file mode 100644 index 00000000000..9bcdb150415 --- /dev/null +++ b/queue-5.15/media-omap3isp-use-struct_group-for-memcpy-region.patch @@ -0,0 +1,135 @@ +From a3911f90c150b423ab9bcf36e172f507f8765853 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Jan 2022 18:29:52 +0100 +Subject: media: omap3isp: Use struct_group() for memcpy() region + +From: Kees Cook + +[ Upstream commit d4568fc8525897e683983806f813be1ae9eedaed ] + +In preparation for FORTIFY_SOURCE performing compile-time and run-time +field bounds checking for memcpy(), memmove(), and memset(), avoid +intentionally writing across neighboring fields. Wrap the target region +in struct_group(). This additionally fixes a theoretical misalignment +of the copy (since the size of "buf" changes between 64-bit and 32-bit, +but this is likely never built for 64-bit). + +FWIW, I think this code is totally broken on 64-bit (which appears to +not be a "real" build configuration): it would either always fail (with +an uninitialized data->buf_size) or would cause corruption in userspace +due to the copy_to_user() in the call path against an uninitialized +data->buf value: + +omap3isp_stat_request_statistics_time32(...) + struct omap3isp_stat_data data64; + ... + omap3isp_stat_request_statistics(stat, &data64); + +int omap3isp_stat_request_statistics(struct ispstat *stat, + struct omap3isp_stat_data *data) + ... + buf = isp_stat_buf_get(stat, data); + +static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat, + struct omap3isp_stat_data *data) +... + if (buf->buf_size > data->buf_size) { + ... + return ERR_PTR(-EINVAL); + } + ... + rval = copy_to_user(data->buf, + buf->virt_addr, + buf->buf_size); + +Regardless, additionally initialize data64 to be zero-filled to avoid +undefined behavior. + +Link: https://lore.kernel.org/lkml/20211215220505.GB21862@embeddedor + +Cc: Arnd Bergmann +Fixes: 378e3f81cb56 ("media: omap3isp: support 64-bit version of omap3isp_stat_data") +Cc: stable@vger.kernel.org +Reviewed-by: Gustavo A. R. Silva +Signed-off-by: Kees Cook +Reviewed-by: Laurent Pinchart +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Sasha Levin +--- + drivers/media/platform/omap3isp/ispstat.c | 5 +++-- + include/uapi/linux/omap3isp.h | 21 +++++++++++++-------- + 2 files changed, 16 insertions(+), 10 deletions(-) + +diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c +index 5b9b57f4d9bf..68cf68dbcace 100644 +--- a/drivers/media/platform/omap3isp/ispstat.c ++++ b/drivers/media/platform/omap3isp/ispstat.c +@@ -512,7 +512,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, + int omap3isp_stat_request_statistics_time32(struct ispstat *stat, + struct omap3isp_stat_data_time32 *data) + { +- struct omap3isp_stat_data data64; ++ struct omap3isp_stat_data data64 = { }; + int ret; + + ret = omap3isp_stat_request_statistics(stat, &data64); +@@ -521,7 +521,8 @@ int omap3isp_stat_request_statistics_time32(struct ispstat *stat, + + data->ts.tv_sec = data64.ts.tv_sec; + data->ts.tv_usec = data64.ts.tv_usec; +- memcpy(&data->buf, &data64.buf, sizeof(*data) - sizeof(data->ts)); ++ data->buf = (uintptr_t)data64.buf; ++ memcpy(&data->frame, &data64.frame, sizeof(data->frame)); + + return 0; + } +diff --git a/include/uapi/linux/omap3isp.h b/include/uapi/linux/omap3isp.h +index 87b55755f4ff..d9db7ad43890 100644 +--- a/include/uapi/linux/omap3isp.h ++++ b/include/uapi/linux/omap3isp.h +@@ -162,6 +162,7 @@ struct omap3isp_h3a_aewb_config { + * struct omap3isp_stat_data - Statistic data sent to or received from user + * @ts: Timestamp of returned framestats. + * @buf: Pointer to pass to user. ++ * @buf_size: Size of buffer. + * @frame_number: Frame number of requested stats. + * @cur_frame: Current frame number being processed. + * @config_counter: Number of the configuration associated with the data. +@@ -176,10 +177,12 @@ struct omap3isp_stat_data { + struct timeval ts; + #endif + void __user *buf; +- __u32 buf_size; +- __u16 frame_number; +- __u16 cur_frame; +- __u16 config_counter; ++ __struct_group(/* no tag */, frame, /* no attrs */, ++ __u32 buf_size; ++ __u16 frame_number; ++ __u16 cur_frame; ++ __u16 config_counter; ++ ); + }; + + #ifdef __KERNEL__ +@@ -189,10 +192,12 @@ struct omap3isp_stat_data_time32 { + __s32 tv_usec; + } ts; + __u32 buf; +- __u32 buf_size; +- __u16 frame_number; +- __u16 cur_frame; +- __u16 config_counter; ++ __struct_group(/* no tag */, frame, /* no attrs */, ++ __u32 buf_size; ++ __u16 frame_number; ++ __u16 cur_frame; ++ __u16 config_counter; ++ ); + }; + #endif + +-- +2.35.1 + diff --git a/queue-5.15/memory-renesas-rpc-if-avoid-unaligned-bus-access-for.patch b/queue-5.15/memory-renesas-rpc-if-avoid-unaligned-bus-access-for.patch new file mode 100644 index 00000000000..40009543b21 --- /dev/null +++ b/queue-5.15/memory-renesas-rpc-if-avoid-unaligned-bus-access-for.patch @@ -0,0 +1,130 @@ +From df654f0afe33c08afd50534b9891e6e08f596a0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Sep 2021 13:48:30 -0500 +Subject: memory: renesas-rpc-if: Avoid unaligned bus access for HyperFlash + +From: Andrew Gabbasov + +[ Upstream commit 1869023e24c0de73a160a424dac4621cefd628ae ] + +HyperFlash devices in Renesas SoCs use 2-bytes addressing, according +to HW manual paragraph 62.3.3 (which officially describes Serial Flash +access, but seems to be applicable to HyperFlash too). And 1-byte bus +read operations to 2-bytes unaligned addresses in external address space +read mode work incorrectly (returns the other byte from the same word). + +Function memcpy_fromio(), used by the driver to read data from the bus, +in ARM64 architecture (to which Renesas cores belong) uses 8-bytes +bus accesses for appropriate aligned addresses, and 1-bytes accesses +for other addresses. This results in incorrect data read from HyperFlash +in unaligned cases. + +This issue can be reproduced using something like the following commands +(where mtd1 is a parition on Hyperflash storage, defined properly +in a device tree): + +[Correct fragment, read from Hyperflash] + + root@rcar-gen3:~# dd if=/dev/mtd1 of=/tmp/zz bs=32 count=1 + root@rcar-gen3:~# hexdump -C /tmp/zz + 00000000 f4 03 00 aa f5 03 01 aa f6 03 02 aa f7 03 03 aa |................| + 00000010 00 00 80 d2 40 20 18 d5 00 06 81 d2 a0 18 a6 f2 |....@ ..........| + 00000020 + +[Incorrect read of the same fragment: see the difference at offsets 8-11] + + root@rcar-gen3:~# dd if=/dev/mtd1 of=/tmp/zz bs=12 count=1 + root@rcar-gen3:~# hexdump -C /tmp/zz + 00000000 f4 03 00 aa f5 03 01 aa 03 03 aa aa |............| + 0000000c + +Fix this issue by creating a local replacement of the copying function, +that performs only properly aligned bus accesses, and is used for reading +from HyperFlash. + +Fixes: ca7d8b980b67f ("memory: add Renesas RPC-IF driver") +Cc: +Signed-off-by: Andrew Gabbasov +Link: https://lore.kernel.org/r/20210922184830.29147-1-andrew_gabbasov@mentor.com +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Sasha Levin +--- + drivers/memory/renesas-rpc-if.c | 48 +++++++++++++++++++++++++++++++-- + 1 file changed, 46 insertions(+), 2 deletions(-) + +diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c +index 3a416705f61c..c77b23b68a93 100644 +--- a/drivers/memory/renesas-rpc-if.c ++++ b/drivers/memory/renesas-rpc-if.c +@@ -199,7 +199,6 @@ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val) + + *val = readl(rpc->base + reg); + return 0; +- + } + + static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val) +@@ -577,6 +576,48 @@ int rpcif_manual_xfer(struct rpcif *rpc) + } + EXPORT_SYMBOL(rpcif_manual_xfer); + ++static void memcpy_fromio_readw(void *to, ++ const void __iomem *from, ++ size_t count) ++{ ++ const int maxw = (IS_ENABLED(CONFIG_64BIT)) ? 8 : 4; ++ u8 buf[2]; ++ ++ if (count && ((unsigned long)from & 1)) { ++ *(u16 *)buf = __raw_readw((void __iomem *)((unsigned long)from & ~1)); ++ *(u8 *)to = buf[1]; ++ from++; ++ to++; ++ count--; ++ } ++ while (count >= 2 && !IS_ALIGNED((unsigned long)from, maxw)) { ++ *(u16 *)to = __raw_readw(from); ++ from += 2; ++ to += 2; ++ count -= 2; ++ } ++ while (count >= maxw) { ++#ifdef CONFIG_64BIT ++ *(u64 *)to = __raw_readq(from); ++#else ++ *(u32 *)to = __raw_readl(from); ++#endif ++ from += maxw; ++ to += maxw; ++ count -= maxw; ++ } ++ while (count >= 2) { ++ *(u16 *)to = __raw_readw(from); ++ from += 2; ++ to += 2; ++ count -= 2; ++ } ++ if (count) { ++ *(u16 *)buf = __raw_readw(from); ++ *(u8 *)to = buf[0]; ++ } ++} ++ + ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf) + { + loff_t from = offs & (RPCIF_DIRMAP_SIZE - 1); +@@ -598,7 +639,10 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf) + regmap_write(rpc->regmap, RPCIF_DRDMCR, rpc->dummy); + regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr); + +- memcpy_fromio(buf, rpc->dirmap + from, len); ++ if (rpc->bus_size == 2) ++ memcpy_fromio_readw(buf, rpc->dirmap + from, len); ++ else ++ memcpy_fromio(buf, rpc->dirmap + from, len); + + pm_runtime_put(rpc->dev); + +-- +2.35.1 + diff --git a/queue-5.15/mm-hwpoison-avoid-the-impact-of-hwpoison_filter-retu.patch b/queue-5.15/mm-hwpoison-avoid-the-impact-of-hwpoison_filter-retu.patch new file mode 100644 index 00000000000..4bd3ff6221b --- /dev/null +++ b/queue-5.15/mm-hwpoison-avoid-the-impact-of-hwpoison_filter-retu.patch @@ -0,0 +1,145 @@ +From 2dfee9660b82b297bc639c30ea574745465511cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Mar 2022 14:44:38 -0700 +Subject: mm/hwpoison: avoid the impact of hwpoison_filter() return value on + mce handler + +From: luofei + +[ Upstream commit d1fe111fb62a1cf0446a2919f5effbb33ad0702c ] + +When the hwpoison page meets the filter conditions, it should not be +regarded as successful memory_failure() processing for mce handler, but +should return a distinct value, otherwise mce handler regards the error +page has been identified and isolated, which may lead to calling +set_mce_nospec() to change page attribute, etc. + +Here memory_failure() return -EOPNOTSUPP to indicate that the error +event is filtered, mce handler should not take any action for this +situation and hwpoison injector should treat as correct. + +Link: https://lkml.kernel.org/r/20220223082135.2769649-1-luofei@unicloud.com +Signed-off-by: luofei +Acked-by: Borislav Petkov +Cc: Dave Hansen +Cc: H. Peter Anvin +Cc: Ingo Molnar +Cc: Miaohe Lin +Cc: Naoya Horiguchi +Cc: Thomas Gleixner +Cc: Tony Luck +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/cpu/mce/core.c | 8 +++++--- + drivers/base/memory.c | 2 ++ + mm/hwpoison-inject.c | 3 ++- + mm/madvise.c | 2 ++ + mm/memory-failure.c | 9 +++++++-- + 5 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c +index e23e74e2f928..848cfb013f58 100644 +--- a/arch/x86/kernel/cpu/mce/core.c ++++ b/arch/x86/kernel/cpu/mce/core.c +@@ -1297,10 +1297,12 @@ static void kill_me_maybe(struct callback_head *cb) + + /* + * -EHWPOISON from memory_failure() means that it already sent SIGBUS +- * to the current process with the proper error info, so no need to +- * send SIGBUS here again. ++ * to the current process with the proper error info, ++ * -EOPNOTSUPP means hwpoison_filter() filtered the error event, ++ * ++ * In both cases, no further processing is required. + */ +- if (ret == -EHWPOISON) ++ if (ret == -EHWPOISON || ret == -EOPNOTSUPP) + return; + + if (p->mce_vaddr != (void __user *)-1l) { +diff --git a/drivers/base/memory.c b/drivers/base/memory.c +index c0d501a3a714..c778d1df7455 100644 +--- a/drivers/base/memory.c ++++ b/drivers/base/memory.c +@@ -555,6 +555,8 @@ static ssize_t hard_offline_page_store(struct device *dev, + return -EINVAL; + pfn >>= PAGE_SHIFT; + ret = memory_failure(pfn, 0); ++ if (ret == -EOPNOTSUPP) ++ ret = 0; + return ret ? ret : count; + } + +diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c +index aff4d27ec235..a1d6fc3c78b9 100644 +--- a/mm/hwpoison-inject.c ++++ b/mm/hwpoison-inject.c +@@ -48,7 +48,8 @@ static int hwpoison_inject(void *data, u64 val) + + inject: + pr_info("Injecting memory failure at pfn %#lx\n", pfn); +- return memory_failure(pfn, 0); ++ err = memory_failure(pfn, 0); ++ return (err == -EOPNOTSUPP) ? 0 : err; + } + + static int hwpoison_unpoison(void *data, u64 val) +diff --git a/mm/madvise.c b/mm/madvise.c +index 8e5ca01a6cc0..882767d58c27 100644 +--- a/mm/madvise.c ++++ b/mm/madvise.c +@@ -968,6 +968,8 @@ static int madvise_inject_error(int behavior, + pr_info("Injecting memory failure for pfn %#lx at process virtual address %#lx\n", + pfn, start); + ret = memory_failure(pfn, MF_COUNT_INCREASED); ++ if (ret == -EOPNOTSUPP) ++ ret = 0; + } + + if (ret) +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index e6425d959fa9..5664bafd5e77 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1444,7 +1444,7 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags) + if (TestClearPageHWPoison(head)) + num_poisoned_pages_dec(); + unlock_page(head); +- return 0; ++ return -EOPNOTSUPP; + } + unlock_page(head); + res = MF_FAILED; +@@ -1525,7 +1525,7 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags, + goto out; + + if (hwpoison_filter(page)) { +- rc = 0; ++ rc = -EOPNOTSUPP; + goto unlock; + } + +@@ -1594,6 +1594,10 @@ static DEFINE_MUTEX(mf_mutex); + * + * Must run in process context (e.g. a work queue) with interrupts + * enabled and no spinlocks hold. ++ * ++ * Return: 0 for successfully handled the memory error, ++ * -EOPNOTSUPP for memory_filter() filtered the error event, ++ * < 0(except -EOPNOTSUPP) on failure. + */ + int memory_failure(unsigned long pfn, int flags) + { +@@ -1742,6 +1746,7 @@ int memory_failure(unsigned long pfn, int flags) + num_poisoned_pages_dec(); + unlock_page(p); + put_page(p); ++ res = -EOPNOTSUPP; + goto unlock_mutex; + } + +-- +2.35.1 + diff --git a/queue-5.15/mm-hwpoison-fix-race-between-hugetlb-free-demotion-a.patch b/queue-5.15/mm-hwpoison-fix-race-between-hugetlb-free-demotion-a.patch new file mode 100644 index 00000000000..ddbdcfa785e --- /dev/null +++ b/queue-5.15/mm-hwpoison-fix-race-between-hugetlb-free-demotion-a.patch @@ -0,0 +1,305 @@ +From c8a970ddb852ccec59093b75dea9358c01fe4900 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Apr 2022 16:35:33 -0700 +Subject: mm/hwpoison: fix race between hugetlb free/demotion and + memory_failure_hugetlb() + +From: Naoya Horiguchi + +[ Upstream commit 405ce051236cc65b30bbfe490b28ce60ae6aed85 ] + +There is a race condition between memory_failure_hugetlb() and hugetlb +free/demotion, which causes setting PageHWPoison flag on the wrong page. +The one simple result is that wrong processes can be killed, but another +(more serious) one is that the actual error is left unhandled, so no one +prevents later access to it, and that might lead to more serious results +like consuming corrupted data. + +Think about the below race window: + + CPU 1 CPU 2 + memory_failure_hugetlb + struct page *head = compound_head(p); + hugetlb page might be freed to + buddy, or even changed to another + compound page. + + get_hwpoison_page -- page is not what we want now... + +The current code first does prechecks roughly and then reconfirms after +taking refcount, but it's found that it makes code overly complicated, +so move the prechecks in a single hugetlb_lock range. + +A newly introduced function, try_memory_failure_hugetlb(), always takes +hugetlb_lock (even for non-hugetlb pages). That can be improved, but +memory_failure() is rare in principle, so should not be a big problem. + +Link: https://lkml.kernel.org/r/20220408135323.1559401-2-naoya.horiguchi@linux.dev +Fixes: 761ad8d7c7b5 ("mm: hwpoison: introduce memory_failure_hugetlb()") +Signed-off-by: Naoya Horiguchi +Reported-by: Mike Kravetz +Reviewed-by: Miaohe Lin +Reviewed-by: Mike Kravetz +Cc: Yang Shi +Cc: Dan Carpenter +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + include/linux/hugetlb.h | 6 ++ + include/linux/mm.h | 8 +++ + mm/hugetlb.c | 10 +++ + mm/memory-failure.c | 137 ++++++++++++++++++++++++++++++---------- + 4 files changed, 127 insertions(+), 34 deletions(-) + +diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h +index 1faebe1cd0ed..22c1d935e22d 100644 +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -167,6 +167,7 @@ long hugetlb_unreserve_pages(struct inode *inode, long start, long end, + long freed); + bool isolate_huge_page(struct page *page, struct list_head *list); + int get_hwpoison_huge_page(struct page *page, bool *hugetlb); ++int get_huge_page_for_hwpoison(unsigned long pfn, int flags); + void putback_active_hugepage(struct page *page); + void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason); + void free_huge_page(struct page *page); +@@ -362,6 +363,11 @@ static inline int get_hwpoison_huge_page(struct page *page, bool *hugetlb) + return 0; + } + ++static inline int get_huge_page_for_hwpoison(unsigned long pfn, int flags) ++{ ++ return 0; ++} ++ + static inline void putback_active_hugepage(struct page *page) + { + } +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 7a80a08eec84..c5fa46e9c0ca 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -3132,6 +3132,14 @@ extern int sysctl_memory_failure_recovery; + extern void shake_page(struct page *p); + extern atomic_long_t num_poisoned_pages __read_mostly; + extern int soft_offline_page(unsigned long pfn, int flags); ++#ifdef CONFIG_MEMORY_FAILURE ++extern int __get_huge_page_for_hwpoison(unsigned long pfn, int flags); ++#else ++static inline int __get_huge_page_for_hwpoison(unsigned long pfn, int flags) ++{ ++ return 0; ++} ++#endif + + + /* +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index e4c717b08cfe..eed96302897a 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -6290,6 +6290,16 @@ int get_hwpoison_huge_page(struct page *page, bool *hugetlb) + return ret; + } + ++int get_huge_page_for_hwpoison(unsigned long pfn, int flags) ++{ ++ int ret; ++ ++ spin_lock_irq(&hugetlb_lock); ++ ret = __get_huge_page_for_hwpoison(pfn, flags); ++ spin_unlock_irq(&hugetlb_lock); ++ return ret; ++} ++ + void putback_active_hugepage(struct page *page) + { + spin_lock_irq(&hugetlb_lock); +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index a4d70c21c146..ecd64b203272 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1419,50 +1419,113 @@ static int try_to_split_thp_page(struct page *page, const char *msg) + return 0; + } + +-static int memory_failure_hugetlb(unsigned long pfn, int flags) ++/* ++ * Called from hugetlb code with hugetlb_lock held. ++ * ++ * Return values: ++ * 0 - free hugepage ++ * 1 - in-use hugepage ++ * 2 - not a hugepage ++ * -EBUSY - the hugepage is busy (try to retry) ++ * -EHWPOISON - the hugepage is already hwpoisoned ++ */ ++int __get_huge_page_for_hwpoison(unsigned long pfn, int flags) ++{ ++ struct page *page = pfn_to_page(pfn); ++ struct page *head = compound_head(page); ++ int ret = 2; /* fallback to normal page handling */ ++ bool count_increased = false; ++ ++ if (!PageHeadHuge(head)) ++ goto out; ++ ++ if (flags & MF_COUNT_INCREASED) { ++ ret = 1; ++ count_increased = true; ++ } else if (HPageFreed(head) || HPageMigratable(head)) { ++ ret = get_page_unless_zero(head); ++ if (ret) ++ count_increased = true; ++ } else { ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ if (TestSetPageHWPoison(head)) { ++ ret = -EHWPOISON; ++ goto out; ++ } ++ ++ return ret; ++out: ++ if (count_increased) ++ put_page(head); ++ return ret; ++} ++ ++#ifdef CONFIG_HUGETLB_PAGE ++/* ++ * Taking refcount of hugetlb pages needs extra care about race conditions ++ * with basic operations like hugepage allocation/free/demotion. ++ * So some of prechecks for hwpoison (pinning, and testing/setting ++ * PageHWPoison) should be done in single hugetlb_lock range. ++ */ ++static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb) + { +- struct page *p = pfn_to_page(pfn); +- struct page *head = compound_head(p); + int res; ++ struct page *p = pfn_to_page(pfn); ++ struct page *head; + unsigned long page_flags; ++ bool retry = true; + +- if (TestSetPageHWPoison(head)) { +- pr_err("Memory failure: %#lx: already hardware poisoned\n", +- pfn); +- res = -EHWPOISON; +- if (flags & MF_ACTION_REQUIRED) ++ *hugetlb = 1; ++retry: ++ res = get_huge_page_for_hwpoison(pfn, flags); ++ if (res == 2) { /* fallback to normal page handling */ ++ *hugetlb = 0; ++ return 0; ++ } else if (res == -EHWPOISON) { ++ pr_err("Memory failure: %#lx: already hardware poisoned\n", pfn); ++ if (flags & MF_ACTION_REQUIRED) { ++ head = compound_head(p); + res = kill_accessing_process(current, page_to_pfn(head), flags); ++ } ++ return res; ++ } else if (res == -EBUSY) { ++ if (retry) { ++ retry = false; ++ goto retry; ++ } ++ action_result(pfn, MF_MSG_UNKNOWN, MF_IGNORED); + return res; + } + ++ head = compound_head(p); ++ lock_page(head); ++ ++ if (hwpoison_filter(p)) { ++ ClearPageHWPoison(head); ++ res = -EOPNOTSUPP; ++ goto out; ++ } ++ + num_poisoned_pages_inc(); + +- if (!(flags & MF_COUNT_INCREASED)) { +- res = get_hwpoison_page(p, flags); +- if (!res) { +- lock_page(head); +- if (hwpoison_filter(p)) { +- if (TestClearPageHWPoison(head)) +- num_poisoned_pages_dec(); +- unlock_page(head); +- return -EOPNOTSUPP; +- } +- unlock_page(head); +- res = MF_FAILED; +- if (__page_handle_poison(p)) { +- page_ref_inc(p); +- res = MF_RECOVERED; +- } +- action_result(pfn, MF_MSG_FREE_HUGE, res); +- return res == MF_RECOVERED ? 0 : -EBUSY; +- } else if (res < 0) { +- action_result(pfn, MF_MSG_UNKNOWN, MF_IGNORED); +- return -EBUSY; ++ /* ++ * Handling free hugepage. The possible race with hugepage allocation ++ * or demotion can be prevented by PageHWPoison flag. ++ */ ++ if (res == 0) { ++ unlock_page(head); ++ res = MF_FAILED; ++ if (__page_handle_poison(p)) { ++ page_ref_inc(p); ++ res = MF_RECOVERED; + } ++ action_result(pfn, MF_MSG_FREE_HUGE, res); ++ return res == MF_RECOVERED ? 0 : -EBUSY; + } + +- lock_page(head); +- + /* + * The page could have changed compound pages due to race window. + * If this happens just bail out. +@@ -1501,6 +1564,12 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags) + unlock_page(head); + return res; + } ++#else ++static inline int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb) ++{ ++ return 0; ++} ++#endif + + static int memory_failure_dev_pagemap(unsigned long pfn, int flags, + struct dev_pagemap *pgmap) +@@ -1620,6 +1689,7 @@ int memory_failure(unsigned long pfn, int flags) + int res = 0; + unsigned long page_flags; + bool retry = true; ++ int hugetlb = 0; + + if (!sysctl_memory_failure_recovery) + panic("Memory failure on page %lx", pfn); +@@ -1640,10 +1710,9 @@ int memory_failure(unsigned long pfn, int flags) + mutex_lock(&mf_mutex); + + try_again: +- if (PageHuge(p)) { +- res = memory_failure_hugetlb(pfn, flags); ++ res = try_memory_failure_hugetlb(pfn, flags, &hugetlb); ++ if (hugetlb) + goto unlock_mutex; +- } + + if (TestSetPageHWPoison(p)) { + pr_err("Memory failure: %#lx: already hardware poisoned\n", +-- +2.35.1 + diff --git a/queue-5.15/mm-hwpoison-mf_mutex-for-soft-offline-and-unpoison.patch b/queue-5.15/mm-hwpoison-mf_mutex-for-soft-offline-and-unpoison.patch new file mode 100644 index 00000000000..d2d29db0de5 --- /dev/null +++ b/queue-5.15/mm-hwpoison-mf_mutex-for-soft-offline-and-unpoison.patch @@ -0,0 +1,222 @@ +From 37d6e57e30a76da61bd50ea469d272175c5ea977 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Jan 2022 14:09:02 -0800 +Subject: mm/hwpoison: mf_mutex for soft offline and unpoison + +From: Naoya Horiguchi + +[ Upstream commit 91d005479e06392617bacc114509d611b705eaac ] + +Patch series "mm/hwpoison: fix unpoison_memory()", v4. + +The main purpose of this series is to sync unpoison code to recent +changes around how hwpoison code takes page refcount. Unpoison should +work or simply fail (without crash) if impossible. + +The recent works of keeping hwpoison pages in shmem pagecache introduce +a new state of hwpoisoned pages, but unpoison for such pages is not +supported yet with this series. + +It seems that soft-offline and unpoison can be used as general purpose +page offline/online mechanism (not in the context of memory error). I +think that we need some additional works to realize it because currently +soft-offline and unpoison are assumed not to happen so frequently (print +out too many messages for aggressive usecases). But anyway this could +be another interesting next topic. + +v1: https://lore.kernel.org/linux-mm/20210614021212.223326-1-nao.horiguchi@gmail.com/ +v2: https://lore.kernel.org/linux-mm/20211025230503.2650970-1-naoya.horiguchi@linux.dev/ +v3: https://lore.kernel.org/linux-mm/20211105055058.3152564-1-naoya.horiguchi@linux.dev/ + +This patch (of 3): + +Originally mf_mutex is introduced to serialize multiple MCE events, but +it is not that useful to allow unpoison to run in parallel with +memory_failure() and soft offline. So apply mf_mutex to soft offline +and unpoison. The memory failure handler and soft offline handler get +simpler with this. + +Link: https://lkml.kernel.org/r/20211115084006.3728254-1-naoya.horiguchi@linux.dev +Link: https://lkml.kernel.org/r/20211115084006.3728254-2-naoya.horiguchi@linux.dev +Signed-off-by: Naoya Horiguchi +Reviewed-by: Yang Shi +Cc: "Aneesh Kumar K.V" +Cc: David Hildenbrand +Cc: Ding Hui +Cc: Miaohe Lin +Cc: Michal Hocko +Cc: Oscar Salvador +Cc: Peter Xu +Cc: Tony Luck +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + mm/memory-failure.c | 62 +++++++++++++-------------------------------- + 1 file changed, 18 insertions(+), 44 deletions(-) + +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index c3ceb7436933..e6425d959fa9 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -1463,14 +1463,6 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags) + lock_page(head); + page_flags = head->flags; + +- if (!PageHWPoison(head)) { +- pr_err("Memory failure: %#lx: just unpoisoned\n", pfn); +- num_poisoned_pages_dec(); +- unlock_page(head); +- put_page(head); +- return 0; +- } +- + /* + * TODO: hwpoison for pud-sized hugetlb doesn't work right now, so + * simply disable it. In order to make it work properly, we need +@@ -1584,6 +1576,8 @@ static int memory_failure_dev_pagemap(unsigned long pfn, int flags, + return rc; + } + ++static DEFINE_MUTEX(mf_mutex); ++ + /** + * memory_failure - Handle memory failure of a page. + * @pfn: Page Number of the corrupted page +@@ -1610,7 +1604,6 @@ int memory_failure(unsigned long pfn, int flags) + int res = 0; + unsigned long page_flags; + bool retry = true; +- static DEFINE_MUTEX(mf_mutex); + + if (!sysctl_memory_failure_recovery) + panic("Memory failure on page %lx", pfn); +@@ -1744,16 +1737,6 @@ int memory_failure(unsigned long pfn, int flags) + */ + page_flags = p->flags; + +- /* +- * unpoison always clear PG_hwpoison inside page lock +- */ +- if (!PageHWPoison(p)) { +- pr_err("Memory failure: %#lx: just unpoisoned\n", pfn); +- num_poisoned_pages_dec(); +- unlock_page(p); +- put_page(p); +- goto unlock_mutex; +- } + if (hwpoison_filter(p)) { + if (TestClearPageHWPoison(p)) + num_poisoned_pages_dec(); +@@ -1934,6 +1917,7 @@ int unpoison_memory(unsigned long pfn) + struct page *page; + struct page *p; + int freeit = 0; ++ int ret = 0; + unsigned long flags = 0; + static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL, + DEFAULT_RATELIMIT_BURST); +@@ -1944,39 +1928,30 @@ int unpoison_memory(unsigned long pfn) + p = pfn_to_page(pfn); + page = compound_head(p); + ++ mutex_lock(&mf_mutex); ++ + if (!PageHWPoison(p)) { + unpoison_pr_info("Unpoison: Page was already unpoisoned %#lx\n", + pfn, &unpoison_rs); +- return 0; ++ goto unlock_mutex; + } + + if (page_count(page) > 1) { + unpoison_pr_info("Unpoison: Someone grabs the hwpoison page %#lx\n", + pfn, &unpoison_rs); +- return 0; ++ goto unlock_mutex; + } + + if (page_mapped(page)) { + unpoison_pr_info("Unpoison: Someone maps the hwpoison page %#lx\n", + pfn, &unpoison_rs); +- return 0; ++ goto unlock_mutex; + } + + if (page_mapping(page)) { + unpoison_pr_info("Unpoison: the hwpoison page has non-NULL mapping %#lx\n", + pfn, &unpoison_rs); +- return 0; +- } +- +- /* +- * unpoison_memory() can encounter thp only when the thp is being +- * worked by memory_failure() and the page lock is not held yet. +- * In such case, we yield to memory_failure() and make unpoison fail. +- */ +- if (!PageHuge(page) && PageTransHuge(page)) { +- unpoison_pr_info("Unpoison: Memory failure is now running on %#lx\n", +- pfn, &unpoison_rs); +- return 0; ++ goto unlock_mutex; + } + + if (!get_hwpoison_page(p, flags)) { +@@ -1984,29 +1959,23 @@ int unpoison_memory(unsigned long pfn) + num_poisoned_pages_dec(); + unpoison_pr_info("Unpoison: Software-unpoisoned free page %#lx\n", + pfn, &unpoison_rs); +- return 0; ++ goto unlock_mutex; + } + +- lock_page(page); +- /* +- * This test is racy because PG_hwpoison is set outside of page lock. +- * That's acceptable because that won't trigger kernel panic. Instead, +- * the PG_hwpoison page will be caught and isolated on the entrance to +- * the free buddy page pool. +- */ + if (TestClearPageHWPoison(page)) { + unpoison_pr_info("Unpoison: Software-unpoisoned page %#lx\n", + pfn, &unpoison_rs); + num_poisoned_pages_dec(); + freeit = 1; + } +- unlock_page(page); + + put_page(page); + if (freeit && !(pfn == my_zero_pfn(0) && page_count(p) == 1)) + put_page(page); + +- return 0; ++unlock_mutex: ++ mutex_unlock(&mf_mutex); ++ return ret; + } + EXPORT_SYMBOL(unpoison_memory); + +@@ -2187,9 +2156,12 @@ int soft_offline_page(unsigned long pfn, int flags) + return -EIO; + } + ++ mutex_lock(&mf_mutex); ++ + if (PageHWPoison(page)) { + pr_info("%s: %#lx page already poisoned\n", __func__, pfn); + put_ref_page(ref_page); ++ mutex_unlock(&mf_mutex); + return 0; + } + +@@ -2208,5 +2180,7 @@ int soft_offline_page(unsigned long pfn, int flags) + } + } + ++ mutex_unlock(&mf_mutex); ++ + return ret; + } +-- +2.35.1 + diff --git a/queue-5.15/mm-memory-failure.c-fix-race-with-changing-page-comp.patch b/queue-5.15/mm-memory-failure.c-fix-race-with-changing-page-comp.patch new file mode 100644 index 00000000000..a9656c2b09b --- /dev/null +++ b/queue-5.15/mm-memory-failure.c-fix-race-with-changing-page-comp.patch @@ -0,0 +1,107 @@ +From b4e44dfaac719d6981fdb1c6a0089279e142bc41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Mar 2022 14:44:44 -0700 +Subject: mm/memory-failure.c: fix race with changing page compound again + +From: Miaohe Lin + +[ Upstream commit 888af2701db79b9b27c7e37f9ede528a5ca53b76 ] + +Patch series "A few fixup patches for memory failure", v2. + +This series contains a few patches to fix the race with changing page +compound page, make non-LRU movable pages unhandlable and so on. More +details can be found in the respective changelogs. + +There is a race window where we got the compound_head, the hugetlb page +could be freed to buddy, or even changed to another compound page just +before we try to get hwpoison page. Think about the below race window: + + CPU 1 CPU 2 + memory_failure_hugetlb + struct page *head = compound_head(p); + hugetlb page might be freed to + buddy, or even changed to another + compound page. + + get_hwpoison_page -- page is not what we want now... + +If this race happens, just bail out. Also MF_MSG_DIFFERENT_PAGE_SIZE is +introduced to record this event. + +[akpm@linux-foundation.org: s@/**@/*@, per Naoya Horiguchi] + +Link: https://lkml.kernel.org/r/20220312074613.4798-1-linmiaohe@huawei.com +Link: https://lkml.kernel.org/r/20220312074613.4798-2-linmiaohe@huawei.com +Signed-off-by: Miaohe Lin +Acked-by: Naoya Horiguchi +Cc: Tony Luck +Cc: Borislav Petkov +Cc: Mike Kravetz +Cc: Yang Shi +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Sasha Levin +--- + include/linux/mm.h | 1 + + include/ras/ras_event.h | 1 + + mm/memory-failure.c | 12 ++++++++++++ + 3 files changed, 14 insertions(+) + +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 85205adcdd0d..7a80a08eec84 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -3167,6 +3167,7 @@ enum mf_action_page_type { + MF_MSG_BUDDY_2ND, + MF_MSG_DAX, + MF_MSG_UNSPLIT_THP, ++ MF_MSG_DIFFERENT_PAGE_SIZE, + MF_MSG_UNKNOWN, + }; + +diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h +index 0bdbc0d17d2f..cac13ff1d6eb 100644 +--- a/include/ras/ras_event.h ++++ b/include/ras/ras_event.h +@@ -376,6 +376,7 @@ TRACE_EVENT(aer_event, + EM ( MF_MSG_BUDDY_2ND, "free buddy page (2nd try)" ) \ + EM ( MF_MSG_DAX, "dax page" ) \ + EM ( MF_MSG_UNSPLIT_THP, "unsplit thp" ) \ ++ EM ( MF_MSG_DIFFERENT_PAGE_SIZE, "different page size" ) \ + EMe ( MF_MSG_UNKNOWN, "unknown page" ) + + /* +diff --git a/mm/memory-failure.c b/mm/memory-failure.c +index 5664bafd5e77..a4d70c21c146 100644 +--- a/mm/memory-failure.c ++++ b/mm/memory-failure.c +@@ -741,6 +741,7 @@ static const char * const action_page_types[] = { + [MF_MSG_BUDDY_2ND] = "free buddy page (2nd try)", + [MF_MSG_DAX] = "dax page", + [MF_MSG_UNSPLIT_THP] = "unsplit thp", ++ [MF_MSG_DIFFERENT_PAGE_SIZE] = "different page size", + [MF_MSG_UNKNOWN] = "unknown page", + }; + +@@ -1461,6 +1462,17 @@ static int memory_failure_hugetlb(unsigned long pfn, int flags) + } + + lock_page(head); ++ ++ /* ++ * The page could have changed compound pages due to race window. ++ * If this happens just bail out. ++ */ ++ if (!PageHuge(p) || compound_head(p) != head) { ++ action_result(pfn, MF_MSG_DIFFERENT_PAGE_SIZE, MF_IGNORED); ++ res = -EBUSY; ++ goto out; ++ } ++ + page_flags = head->flags; + + /* +-- +2.35.1 + diff --git a/queue-5.15/mm-vmalloc-introduce-array-allocation-functions.patch b/queue-5.15/mm-vmalloc-introduce-array-allocation-functions.patch new file mode 100644 index 00000000000..9b568400e8b --- /dev/null +++ b/queue-5.15/mm-vmalloc-introduce-array-allocation-functions.patch @@ -0,0 +1,102 @@ +From 0fe8b2ff024aec861bac0aa495b13c94e728883c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Mar 2022 04:47:22 -0500 +Subject: mm: vmalloc: introduce array allocation functions + +From: Paolo Bonzini + +[ Upstream commit a8749a35c39903120ec421ef2525acc8e0daa55c ] + +Linux has dozens of occurrences of vmalloc(array_size()) and +vzalloc(array_size()). Allow to simplify the code by providing +vmalloc_array and vcalloc, as well as the underscored variants that let +the caller specify the GFP flags. + +Acked-by: Michal Hocko +Signed-off-by: Paolo Bonzini +Signed-off-by: Sasha Levin +--- + include/linux/vmalloc.h | 5 +++++ + mm/util.c | 50 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 55 insertions(+) + +diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h +index 4fe9e885bbfa..5535be1012a2 100644 +--- a/include/linux/vmalloc.h ++++ b/include/linux/vmalloc.h +@@ -159,6 +159,11 @@ void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask, + int node, const void *caller); + void *vmalloc_no_huge(unsigned long size); + ++extern void *__vmalloc_array(size_t n, size_t size, gfp_t flags) __alloc_size(1, 2); ++extern void *vmalloc_array(size_t n, size_t size) __alloc_size(1, 2); ++extern void *__vcalloc(size_t n, size_t size, gfp_t flags) __alloc_size(1, 2); ++extern void *vcalloc(size_t n, size_t size) __alloc_size(1, 2); ++ + extern void vfree(const void *addr); + extern void vfree_atomic(const void *addr); + +diff --git a/mm/util.c b/mm/util.c +index 3073de05c2bd..ea04979f131e 100644 +--- a/mm/util.c ++++ b/mm/util.c +@@ -698,6 +698,56 @@ static inline void *__page_rmapping(struct page *page) + return (void *)mapping; + } + ++/** ++ * __vmalloc_array - allocate memory for a virtually contiguous array. ++ * @n: number of elements. ++ * @size: element size. ++ * @flags: the type of memory to allocate (see kmalloc). ++ */ ++void *__vmalloc_array(size_t n, size_t size, gfp_t flags) ++{ ++ size_t bytes; ++ ++ if (unlikely(check_mul_overflow(n, size, &bytes))) ++ return NULL; ++ return __vmalloc(bytes, flags); ++} ++EXPORT_SYMBOL(__vmalloc_array); ++ ++/** ++ * vmalloc_array - allocate memory for a virtually contiguous array. ++ * @n: number of elements. ++ * @size: element size. ++ */ ++void *vmalloc_array(size_t n, size_t size) ++{ ++ return __vmalloc_array(n, size, GFP_KERNEL); ++} ++EXPORT_SYMBOL(vmalloc_array); ++ ++/** ++ * __vcalloc - allocate and zero memory for a virtually contiguous array. ++ * @n: number of elements. ++ * @size: element size. ++ * @flags: the type of memory to allocate (see kmalloc). ++ */ ++void *__vcalloc(size_t n, size_t size, gfp_t flags) ++{ ++ return __vmalloc_array(n, size, flags | __GFP_ZERO); ++} ++EXPORT_SYMBOL(__vcalloc); ++ ++/** ++ * vcalloc - allocate and zero memory for a virtually contiguous array. ++ * @n: number of elements. ++ * @size: element size. ++ */ ++void *vcalloc(size_t n, size_t size) ++{ ++ return __vmalloc_array(n, size, GFP_KERNEL | __GFP_ZERO); ++} ++EXPORT_SYMBOL(vcalloc); ++ + /* Neutral page->mapping pointer to address_space or anon_vma or other */ + void *page_rmapping(struct page *page) + { +-- +2.35.1 + diff --git a/queue-5.15/module-change-to-print-useful-messages-from-elf_vali.patch b/queue-5.15/module-change-to-print-useful-messages-from-elf_vali.patch new file mode 100644 index 00000000000..f934638b418 --- /dev/null +++ b/queue-5.15/module-change-to-print-useful-messages-from-elf_vali.patch @@ -0,0 +1,179 @@ +From fc77dede4f15185c8c414633566597c2e5399f2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Oct 2021 14:57:40 -0600 +Subject: module: change to print useful messages from elf_validity_check() + +From: Shuah Khan + +[ Upstream commit 7fd982f394c42f25a73fe9dfbf1e6b11fa26b40a ] + +elf_validity_check() checks ELF headers for errors and ELF Spec. +compliance and if any of them fail it returns -ENOEXEC from all of +these error paths. Almost all of them don't print any messages. + +When elf_validity_check() returns an error, load_module() prints an +error message without error code. It is hard to determine why the +module ELF structure is invalid, even if load_module() prints the +error code which is -ENOEXEC in all of these cases. + +Change to print useful error messages from elf_validity_check() to +clearly say what went wrong and why the ELF validity checks failed. + +Remove the load_module() error message which is no longer needed. +This patch includes changes to fix build warns on 32-bit platforms: + +warning: format '%llu' expects argument of type 'long long unsigned int', +but argument 3 has type 'Elf32_Off' {aka 'unsigned int'} +Reported-by: kernel test robot + +Signed-off-by: Shuah Khan +Signed-off-by: Luis Chamberlain +Signed-off-by: Sasha Levin +--- + kernel/module.c | 75 +++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 54 insertions(+), 21 deletions(-) + +diff --git a/kernel/module.c b/kernel/module.c +index 83991c2d5af9..256b3c80a771 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -2967,14 +2967,29 @@ static int elf_validity_check(struct load_info *info) + Elf_Shdr *shdr, *strhdr; + int err; + +- if (info->len < sizeof(*(info->hdr))) +- return -ENOEXEC; ++ if (info->len < sizeof(*(info->hdr))) { ++ pr_err("Invalid ELF header len %lu\n", info->len); ++ goto no_exec; ++ } + +- if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0 +- || info->hdr->e_type != ET_REL +- || !elf_check_arch(info->hdr) +- || info->hdr->e_shentsize != sizeof(Elf_Shdr)) +- return -ENOEXEC; ++ if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0) { ++ pr_err("Invalid ELF header magic: != %s\n", ELFMAG); ++ goto no_exec; ++ } ++ if (info->hdr->e_type != ET_REL) { ++ pr_err("Invalid ELF header type: %u != %u\n", ++ info->hdr->e_type, ET_REL); ++ goto no_exec; ++ } ++ if (!elf_check_arch(info->hdr)) { ++ pr_err("Invalid architecture in ELF header: %u\n", ++ info->hdr->e_machine); ++ goto no_exec; ++ } ++ if (info->hdr->e_shentsize != sizeof(Elf_Shdr)) { ++ pr_err("Invalid ELF section header size\n"); ++ goto no_exec; ++ } + + /* + * e_shnum is 16 bits, and sizeof(Elf_Shdr) is +@@ -2983,8 +2998,10 @@ static int elf_validity_check(struct load_info *info) + */ + if (info->hdr->e_shoff >= info->len + || (info->hdr->e_shnum * sizeof(Elf_Shdr) > +- info->len - info->hdr->e_shoff)) +- return -ENOEXEC; ++ info->len - info->hdr->e_shoff)) { ++ pr_err("Invalid ELF section header overflow\n"); ++ goto no_exec; ++ } + + info->sechdrs = (void *)info->hdr + info->hdr->e_shoff; + +@@ -2992,13 +3009,19 @@ static int elf_validity_check(struct load_info *info) + * Verify if the section name table index is valid. + */ + if (info->hdr->e_shstrndx == SHN_UNDEF +- || info->hdr->e_shstrndx >= info->hdr->e_shnum) +- return -ENOEXEC; ++ || info->hdr->e_shstrndx >= info->hdr->e_shnum) { ++ pr_err("Invalid ELF section name index: %d || e_shstrndx (%d) >= e_shnum (%d)\n", ++ info->hdr->e_shstrndx, info->hdr->e_shstrndx, ++ info->hdr->e_shnum); ++ goto no_exec; ++ } + + strhdr = &info->sechdrs[info->hdr->e_shstrndx]; + err = validate_section_offset(info, strhdr); +- if (err < 0) ++ if (err < 0) { ++ pr_err("Invalid ELF section hdr(type %u)\n", strhdr->sh_type); + return err; ++ } + + /* + * The section name table must be NUL-terminated, as required +@@ -3006,8 +3029,10 @@ static int elf_validity_check(struct load_info *info) + * strings in the section safe. + */ + info->secstrings = (void *)info->hdr + strhdr->sh_offset; +- if (info->secstrings[strhdr->sh_size - 1] != '\0') +- return -ENOEXEC; ++ if (info->secstrings[strhdr->sh_size - 1] != '\0') { ++ pr_err("ELF Spec violation: section name table isn't null terminated\n"); ++ goto no_exec; ++ } + + /* + * The code assumes that section 0 has a length of zero and +@@ -3015,8 +3040,11 @@ static int elf_validity_check(struct load_info *info) + */ + if (info->sechdrs[0].sh_type != SHT_NULL + || info->sechdrs[0].sh_size != 0 +- || info->sechdrs[0].sh_addr != 0) +- return -ENOEXEC; ++ || info->sechdrs[0].sh_addr != 0) { ++ pr_err("ELF Spec violation: section 0 type(%d)!=SH_NULL or non-zero len or addr\n", ++ info->sechdrs[0].sh_type); ++ goto no_exec; ++ } + + for (i = 1; i < info->hdr->e_shnum; i++) { + shdr = &info->sechdrs[i]; +@@ -3026,8 +3054,12 @@ static int elf_validity_check(struct load_info *info) + continue; + case SHT_SYMTAB: + if (shdr->sh_link == SHN_UNDEF +- || shdr->sh_link >= info->hdr->e_shnum) +- return -ENOEXEC; ++ || shdr->sh_link >= info->hdr->e_shnum) { ++ pr_err("Invalid ELF sh_link!=SHN_UNDEF(%d) or (sh_link(%d) >= hdr->e_shnum(%d)\n", ++ shdr->sh_link, shdr->sh_link, ++ info->hdr->e_shnum); ++ goto no_exec; ++ } + fallthrough; + default: + err = validate_section_offset(info, shdr); +@@ -3049,6 +3081,9 @@ static int elf_validity_check(struct load_info *info) + } + + return 0; ++ ++no_exec: ++ return -ENOEXEC; + } + + #define COPY_CHUNK_SIZE (16*PAGE_SIZE) +@@ -3925,10 +3960,8 @@ static int load_module(struct load_info *info, const char __user *uargs, + * sections. + */ + err = elf_validity_check(info); +- if (err) { +- pr_err("Module has invalid ELF structures\n"); ++ if (err) + goto free_copy; +- } + + /* + * Everything checks out, so set up the section info +-- +2.35.1 + diff --git a/queue-5.15/module-fix-e_shstrndx-.sh_size-0-oob-access.patch b/queue-5.15/module-fix-e_shstrndx-.sh_size-0-oob-access.patch new file mode 100644 index 00000000000..7231209e7c5 --- /dev/null +++ b/queue-5.15/module-fix-e_shstrndx-.sh_size-0-oob-access.patch @@ -0,0 +1,47 @@ +From 1fc8cfecf39c2e0b0a67d72401f23424ee1f20ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 May 2022 12:54:20 +0300 +Subject: module: fix [e_shstrndx].sh_size=0 OOB access + +From: Alexey Dobriyan + +[ Upstream commit 391e982bfa632b8315235d8be9c0a81374c6a19c ] + +It is trivial to craft a module to trigger OOB access in this line: + + if (info->secstrings[strhdr->sh_size - 1] != '\0') { + +BUG: unable to handle page fault for address: ffffc90000aa0fff +PGD 100000067 P4D 100000067 PUD 100066067 PMD 10436f067 PTE 0 +Oops: 0000 [#1] PREEMPT SMP PTI +CPU: 7 PID: 1215 Comm: insmod Not tainted 5.18.0-rc5-00007-g9bf578647087-dirty #10 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-4.fc34 04/01/2014 +RIP: 0010:load_module+0x19b/0x2391 + +Fixes: ec2a29593c83 ("module: harden ELF info handling") +Signed-off-by: Alexey Dobriyan +[rebased patch onto modules-next] +Signed-off-by: Luis Chamberlain +Signed-off-by: Sasha Levin +--- + kernel/module.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/kernel/module.c b/kernel/module.c +index 256b3c80a771..ef79f4dbda87 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -3029,6 +3029,10 @@ static int elf_validity_check(struct load_info *info) + * strings in the section safe. + */ + info->secstrings = (void *)info->hdr + strhdr->sh_offset; ++ if (strhdr->sh_size == 0) { ++ pr_err("empty section name table\n"); ++ goto no_exec; ++ } + if (info->secstrings[strhdr->sh_size - 1] != '\0') { + pr_err("ELF Spec violation: section name table isn't null terminated\n"); + goto no_exec; +-- +2.35.1 + diff --git a/queue-5.15/mt76-mt76_connac-fix-mcu_ce_cmd_set_roc-definition-e.patch b/queue-5.15/mt76-mt76_connac-fix-mcu_ce_cmd_set_roc-definition-e.patch new file mode 100644 index 00000000000..388390ff1a1 --- /dev/null +++ b/queue-5.15/mt76-mt76_connac-fix-mcu_ce_cmd_set_roc-definition-e.patch @@ -0,0 +1,36 @@ +From 750c534564011a8c06417ea3955a3d674dd8ea7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Dec 2021 16:33:55 +0800 +Subject: mt76: mt76_connac: fix MCU_CE_CMD_SET_ROC definition error + +From: Sean Wang + +[ Upstream commit bf9727a27442a50c75b7d99a5088330c578b2a42 ] + +Fixed an MCU_CE_CMD_SET_ROC definition error that occurred from a previous +refactor work. + +Fixes: d0e274af2f2e4 ("mt76: mt76_connac: create mcu library") +Signed-off-by: Sean Wang +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +index 77d4435e4581..72a70a7046fb 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +@@ -556,7 +556,7 @@ enum { + MCU_CMD_SET_BSS_CONNECTED = MCU_CE_PREFIX | 0x16, + MCU_CMD_SET_BSS_ABORT = MCU_CE_PREFIX | 0x17, + MCU_CMD_CANCEL_HW_SCAN = MCU_CE_PREFIX | 0x1b, +- MCU_CMD_SET_ROC = MCU_CE_PREFIX | 0x1d, ++ MCU_CMD_SET_ROC = MCU_CE_PREFIX | 0x1c, + MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33, + MCU_CMD_SET_RATE_TX_POWER = MCU_CE_PREFIX | 0x5d, + MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, +-- +2.35.1 + diff --git a/queue-5.15/mt76-mt7921-do-not-always-disable-fw-runtime-pm.patch b/queue-5.15/mt76-mt7921-do-not-always-disable-fw-runtime-pm.patch new file mode 100644 index 00000000000..3a05388b1ec --- /dev/null +++ b/queue-5.15/mt76-mt7921-do-not-always-disable-fw-runtime-pm.patch @@ -0,0 +1,46 @@ +From 75e5d37892bfbf6dc35d880cf42d809dbd361a67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Dec 2021 12:36:02 +0100 +Subject: mt76: mt7921: do not always disable fw runtime-pm + +From: Lorenzo Bianconi + +[ Upstream commit b44eeb8cbdf2b88f2844f11e4f263b0abed5b5b0 ] + +After commit 'd430dffbe9dd ("mt76: mt7921: fix a possible race +enabling/disabling runtime-pm")', runtime-pm is always disabled in the +fw even if the user requests to enable it toggling debugfs node since +mt7921_pm_interface_iter routine will use pm->enable to configure the fw. +Fix the issue moving enable variable configuration before running +mt7921_pm_interface_iter routine. + +Fixes: d430dffbe9dd ("mt76: mt7921: fix a possible race enabling/disabling runtime-pm") +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +index b9f25599227d..cfcf7964c688 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +@@ -291,13 +291,12 @@ mt7921_pm_set(void *data, u64 val) + pm->enable = false; + mt76_connac_pm_wake(&dev->mphy, pm); + ++ pm->enable = val; + ieee80211_iterate_active_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_pm_interface_iter, dev); + + mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); +- +- pm->enable = val; + mt76_connac_power_save_sched(&dev->mphy, pm); + out: + mutex_unlock(&dev->mt76.mutex); +-- +2.35.1 + diff --git a/queue-5.15/mt76-mt7921-fix-a-possible-race-enabling-disabling-r.patch b/queue-5.15/mt76-mt7921-fix-a-possible-race-enabling-disabling-r.patch new file mode 100644 index 00000000000..0d634c7e360 --- /dev/null +++ b/queue-5.15/mt76-mt7921-fix-a-possible-race-enabling-disabling-r.patch @@ -0,0 +1,82 @@ +From 79d1311e3ae778795f8d8ea317d45b7f48bde8e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Dec 2021 14:57:09 +0100 +Subject: mt76: mt7921: fix a possible race enabling/disabling runtime-pm + +From: Lorenzo Bianconi + +[ Upstream commit d430dffbe9dd30759f3c64b65bf85b0245c8d8ab ] + +Fix a possible race enabling/disabling runtime-pm between +mt7921_pm_set() and mt7921_poll_rx() since mt7921_pm_wake_work() +always schedules rx-napi callback and it will trigger +mt7921_pm_power_save_work routine putting chip to in low-power state +during mt7921_pm_set processing. + +Suggested-by: Deren Wu +Tested-by: Deren Wu +Fixes: 1d8efc741df8 ("mt76: mt7921: introduce Runtime PM support") +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/0f3e075a2033dc05f09dab4059e5be8cbdccc239.1640094847.git.lorenzo@kernel.org +Signed-off-by: Sasha Levin +--- + drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c | 3 --- + drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c | 12 +++++++++--- + 2 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +index af43bcb54578..306e9eaea917 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +@@ -7,9 +7,6 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm) + { + struct mt76_dev *dev = phy->dev; + +- if (!pm->enable) +- return 0; +- + if (mt76_is_usb(dev)) + return 0; + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +index 82fb2585f413..b9f25599227d 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +@@ -276,7 +276,7 @@ mt7921_pm_set(void *data, u64 val) + struct mt7921_dev *dev = data; + struct mt76_connac_pm *pm = &dev->pm; + +- mt7921_mutex_acquire(dev); ++ mutex_lock(&dev->mt76.mutex); + + if (val == pm->enable) + goto out; +@@ -285,7 +285,11 @@ mt7921_pm_set(void *data, u64 val) + pm->stats.last_wake_event = jiffies; + pm->stats.last_doze_event = jiffies; + } +- pm->enable = val; ++ /* make sure the chip is awake here and ps_work is scheduled ++ * just at end of the this routine. ++ */ ++ pm->enable = false; ++ mt76_connac_pm_wake(&dev->mphy, pm); + + ieee80211_iterate_active_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, +@@ -293,8 +297,10 @@ mt7921_pm_set(void *data, u64 val) + + mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); + ++ pm->enable = val; ++ mt76_connac_power_save_sched(&dev->mphy, pm); + out: +- mt7921_mutex_release(dev); ++ mutex_unlock(&dev->mt76.mutex); + + return 0; + } +-- +2.35.1 + diff --git a/queue-5.15/mt76-mt7921-get-rid-of-mt7921_mac_set_beacon_filter.patch b/queue-5.15/mt76-mt7921-get-rid-of-mt7921_mac_set_beacon_filter.patch new file mode 100644 index 00000000000..5630771e1be --- /dev/null +++ b/queue-5.15/mt76-mt7921-get-rid-of-mt7921_mac_set_beacon_filter.patch @@ -0,0 +1,75 @@ +From af7a84be858c67bb5ceafccb62554e831c55e569 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Aug 2021 10:38:03 +0200 +Subject: mt76: mt7921: get rid of mt7921_mac_set_beacon_filter + +From: Lorenzo Bianconi + +[ Upstream commit b30363102a4122f6eed37927b64a2c7ac70b8859 ] + +Remove mt7921_mac_set_beacon_filter routine since it is no longer used. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../net/wireless/mediatek/mt76/mt7921/mac.c | 28 ------------------- + .../wireless/mediatek/mt76/mt7921/mt7921.h | 3 -- + 2 files changed, 31 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +index bef8d4a76ed9..426e7a32bdc8 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +@@ -1573,34 +1573,6 @@ void mt7921_pm_power_save_work(struct work_struct *work) + queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); + } + +-int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy, +- struct ieee80211_vif *vif, +- bool enable) +-{ +- struct mt7921_dev *dev = phy->dev; +- bool ext_phy = phy != &dev->phy; +- int err; +- +- if (!dev->pm.enable) +- return -EOPNOTSUPP; +- +- err = mt7921_mcu_set_bss_pm(dev, vif, enable); +- if (err) +- return err; +- +- if (enable) { +- vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; +- mt76_set(dev, MT_WF_RFCR(ext_phy), +- MT_WF_RFCR_DROP_OTHER_BEACON); +- } else { +- vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; +- mt76_clear(dev, MT_WF_RFCR(ext_phy), +- MT_WF_RFCR_DROP_OTHER_BEACON); +- } +- +- return 0; +-} +- + void mt7921_coredump_work(struct work_struct *work) + { + struct mt7921_dev *dev; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +index 2d8bd6bfc820..1aafd8723b3a 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +@@ -381,9 +381,6 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev); + void mt7921_pm_wake_work(struct work_struct *work); + void mt7921_pm_power_save_work(struct work_struct *work); + bool mt7921_wait_for_mcu_init(struct mt7921_dev *dev); +-int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy, +- struct ieee80211_vif *vif, +- bool enable); + void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); + void mt7921_coredump_work(struct work_struct *work); + int mt7921_wfsys_reset(struct mt7921_dev *dev); +-- +2.35.1 + diff --git a/queue-5.15/mt76-mt7921-introduce-mt7921_mcu_set_beacon_filter-u.patch b/queue-5.15/mt76-mt7921-introduce-mt7921_mcu_set_beacon_filter-u.patch new file mode 100644 index 00000000000..aa2dded8236 --- /dev/null +++ b/queue-5.15/mt76-mt7921-introduce-mt7921_mcu_set_beacon_filter-u.patch @@ -0,0 +1,242 @@ +From 4d6cc28ed723bdf30fc20ec81ff0a9c65910f580 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Aug 2021 12:37:22 +0200 +Subject: mt76: mt7921: introduce mt7921_mcu_set_beacon_filter utility routine + +From: Lorenzo Bianconi + +[ Upstream commit 890809ca1986e63d29dd1591090af67b655ed89c ] + +Introduce mt7921_mcu_set_beacon_filter utility routine in order to +remove duplicated code for hw beacon filtering. +Move mt7921_pm_interface_iter in debugfs since it is just used there. +Make the following routine static: +- mt7921_pm_interface_iter +- mt7921_mcu_uni_bss_bcnft +- mt7921_mcu_set_bss_pm + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +Signed-off-by: Sasha Levin +--- + .../wireless/mediatek/mt76/mt7921/debugfs.c | 20 +++++--- + .../net/wireless/mediatek/mt76/mt7921/main.c | 33 +------------ + .../net/wireless/mediatek/mt76/mt7921/mcu.c | 47 ++++++++++--------- + .../wireless/mediatek/mt76/mt7921/mt7921.h | 8 ++-- + 4 files changed, 45 insertions(+), 63 deletions(-) + +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +index 8d5e261cd10f..82fb2585f413 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +@@ -262,30 +262,38 @@ mt7921_txpwr(struct seq_file *s, void *data) + return 0; + } + ++static void ++mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) ++{ ++ struct mt7921_dev *dev = priv; ++ ++ mt7921_mcu_set_beacon_filter(dev, vif, dev->pm.enable); ++} ++ + static int + mt7921_pm_set(void *data, u64 val) + { + struct mt7921_dev *dev = data; + struct mt76_connac_pm *pm = &dev->pm; +- struct mt76_phy *mphy = dev->phy.mt76; +- +- if (val == pm->enable) +- return 0; + + mt7921_mutex_acquire(dev); + ++ if (val == pm->enable) ++ goto out; ++ + if (!pm->enable) { + pm->stats.last_wake_event = jiffies; + pm->stats.last_doze_event = jiffies; + } + pm->enable = val; + +- ieee80211_iterate_active_interfaces(mphy->hw, ++ ieee80211_iterate_active_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, +- mt7921_pm_interface_iter, mphy->priv); ++ mt7921_pm_interface_iter, dev); + + mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); + ++out: + mt7921_mutex_release(dev); + + return 0; +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +index 30252f408ddc..13a7ae3d8351 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c +@@ -528,36 +528,6 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw, + mt7921_mutex_release(dev); + } + +-static int +-mt7921_bss_bcnft_apply(struct mt7921_dev *dev, struct ieee80211_vif *vif, +- bool assoc) +-{ +- int ret; +- +- if (!dev->pm.enable) +- return 0; +- +- if (assoc) { +- ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true); +- if (ret) +- return ret; +- +- vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; +- mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); +- +- return 0; +- } +- +- ret = mt7921_mcu_set_bss_pm(dev, vif, false); +- if (ret) +- return ret; +- +- vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; +- mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); +- +- return 0; +-} +- + static void mt7921_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, +@@ -587,7 +557,8 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, + if (changed & BSS_CHANGED_ASSOC) { + mt7921_mcu_sta_update(dev, NULL, vif, true, + MT76_STA_INFO_STATE_ASSOC); +- mt7921_bss_bcnft_apply(dev, vif, info->assoc); ++ if (dev->pm.enable) ++ mt7921_mcu_set_beacon_filter(dev, vif, info->assoc); + } + + if (changed & BSS_CHANGED_ARP_FILTER) { +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +index 4119f8efd896..dabc0de2ec65 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +@@ -1205,8 +1205,9 @@ int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif) + &ps_req, sizeof(ps_req), true); + } + +-int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, +- bool enable) ++static int ++mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, ++ bool enable) + { + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct { +@@ -1240,8 +1241,9 @@ int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, + &bcnft_req, sizeof(bcnft_req), true); + } + +-int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, +- bool enable) ++static int ++mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, ++ bool enable) + { + struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv; + struct { +@@ -1390,31 +1392,34 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev) + return err; + } + +-void +-mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) ++int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, ++ struct ieee80211_vif *vif, ++ bool enable) + { +- struct mt7921_phy *phy = priv; +- struct mt7921_dev *dev = phy->dev; + struct ieee80211_hw *hw = mt76_hw(dev); +- int ret; +- +- if (dev->pm.enable) +- ret = mt7921_mcu_uni_bss_bcnft(dev, vif, true); +- else +- ret = mt7921_mcu_set_bss_pm(dev, vif, false); ++ int err; + +- if (ret) +- return; ++ if (enable) { ++ err = mt7921_mcu_uni_bss_bcnft(dev, vif, true); ++ if (err) ++ return err; + +- if (dev->pm.enable) { + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + ieee80211_hw_set(hw, CONNECTION_MONITOR); + mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); +- } else { +- vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; +- __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); +- mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); ++ ++ return 0; + } ++ ++ err = mt7921_mcu_set_bss_pm(dev, vif, false); ++ if (err) ++ return err; ++ ++ vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; ++ __clear_bit(IEEE80211_HW_CONNECTION_MONITOR, hw->flags); ++ mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON); ++ ++ return 0; + } + + int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr) +diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +index 1aafd8723b3a..32d4f2cab94e 100644 +--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h ++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +@@ -363,6 +363,9 @@ void mt7921_set_stream_he_caps(struct mt7921_phy *phy); + void mt7921_update_channel(struct mt76_phy *mphy); + int mt7921_init_debugfs(struct mt7921_dev *dev); + ++int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev, ++ struct ieee80211_vif *vif, ++ bool enable); + int mt7921_mcu_uni_tx_ba(struct mt7921_dev *dev, + struct ieee80211_ampdu_params *params, + bool enable); +@@ -371,17 +374,12 @@ int mt7921_mcu_uni_rx_ba(struct mt7921_dev *dev, + bool enable); + void mt7921_scan_work(struct work_struct *work); + int mt7921_mcu_uni_bss_ps(struct mt7921_dev *dev, struct ieee80211_vif *vif); +-int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif, +- bool enable); +-int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif, +- bool enable); + int __mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); + int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev); + int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev); + void mt7921_pm_wake_work(struct work_struct *work); + void mt7921_pm_power_save_work(struct work_struct *work); + bool mt7921_wait_for_mcu_init(struct mt7921_dev *dev); +-void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); + void mt7921_coredump_work(struct work_struct *work); + int mt7921_wfsys_reset(struct mt7921_dev *dev); + int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr); +-- +2.35.1 + diff --git a/queue-5.15/mtd-spi-nor-skip-erase-logic-when-spi_nor_no_erase-i.patch b/queue-5.15/mtd-spi-nor-skip-erase-logic-when-spi_nor_no_erase-i.patch new file mode 100644 index 00000000000..3679655bb17 --- /dev/null +++ b/queue-5.15/mtd-spi-nor-skip-erase-logic-when-spi_nor_no_erase-i.patch @@ -0,0 +1,49 @@ +From 19e11ecc859faa363850ae8ac44ffb24d0886ffe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Feb 2022 18:33:34 +0200 +Subject: mtd: spi-nor: Skip erase logic when SPI_NOR_NO_ERASE is set + +From: Tudor Ambarus + +[ Upstream commit 151c6b49d679872d6fc0b50e0ad96303091694a2 ] + +Even if SPI_NOR_NO_ERASE was set, one could still send erase opcodes +to the flash. It is not recommended to send unsupported opcodes to +flashes. Fix the logic and do not set mtd->_erase when SPI_NOR_NO_ERASE +is specified. With this users will not be able to issue erase opcodes to +flashes and instead they will recive an -ENOTSUPP error. + +Fixes: b199489d37b2 ("mtd: spi-nor: add the framework for SPI NOR") +Signed-off-by: Tudor Ambarus +Reviewed-by: Michael Walle +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/20220228163334.277730-1-tudor.ambarus@microchip.com +Signed-off-by: Sasha Levin +--- + drivers/mtd/spi-nor/core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index 90f39aabc1ff..d97cdbc2b9de 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -3148,7 +3148,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, + mtd->writesize = nor->params->writesize; + mtd->flags = MTD_CAP_NORFLASH; + mtd->size = nor->params->size; +- mtd->_erase = spi_nor_erase; + mtd->_read = spi_nor_read; + mtd->_suspend = spi_nor_suspend; + mtd->_resume = spi_nor_resume; +@@ -3178,6 +3177,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, + + if (info->flags & SPI_NOR_NO_ERASE) + mtd->flags |= MTD_NO_ERASE; ++ else ++ mtd->_erase = spi_nor_erase; + + mtd->dev.parent = dev; + nor->page_size = nor->params->page_size; +-- +2.35.1 + diff --git a/queue-5.15/net-mlx5e-check-action-fwd-drop-flag-exists-also-for.patch b/queue-5.15/net-mlx5e-check-action-fwd-drop-flag-exists-also-for.patch new file mode 100644 index 00000000000..bb73911a84c --- /dev/null +++ b/queue-5.15/net-mlx5e-check-action-fwd-drop-flag-exists-also-for.patch @@ -0,0 +1,56 @@ +From 269beb92fc9bab7c88951328ee1bc09fd9a01cea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Aug 2021 09:38:32 +0300 +Subject: net/mlx5e: Check action fwd/drop flag exists also for nic flows + +From: Roi Dayan + +[ Upstream commit 6b50cf45b6a0e99f3cab848a72ecca8da56b7460 ] + +The driver should add offloaded rules with either a fwd or drop action. +The check existed in parsing fdb flows but not when parsing nic flows. +Move the test into actions_match_supported() which is called for +checking nic flows and fdb flows. + +Signed-off-by: Roi Dayan +Reviewed-by: Maor Dickman +Signed-off-by: Saeed Mahameed +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +index 3aa8d0b83d10..fe52db591121 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +@@ -3305,6 +3305,12 @@ static bool actions_match_supported(struct mlx5e_priv *priv, + ct_flow = flow_flag_test(flow, CT) && !ct_clear; + actions = flow->attr->action; + ++ if (!(actions & ++ (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) { ++ NL_SET_ERR_MSG_MOD(extack, "Rule must have at least one forward/drop action"); ++ return false; ++ } ++ + if (mlx5e_is_eswitch_flow(flow)) { + if (flow->attr->esw_attr->split_count && ct_flow && + !MLX5_CAP_GEN(flow->attr->esw_attr->in_mdev, reg_c_preserve)) { +@@ -4207,13 +4213,6 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, + attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; + } + +- if (!(attr->action & +- (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) { +- NL_SET_ERR_MSG_MOD(extack, +- "Rule must have at least one forward/drop action"); +- return -EOPNOTSUPP; +- } +- + if (esw_attr->split_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) { + NL_SET_ERR_MSG_MOD(extack, + "current firmware doesn't support split rule for port mirroring"); +-- +2.35.1 + diff --git a/queue-5.15/net-mlx5e-split-actions_match_supported-into-a-sub-f.patch b/queue-5.15/net-mlx5e-split-actions_match_supported-into-a-sub-f.patch new file mode 100644 index 00000000000..d7a72c2cd67 --- /dev/null +++ b/queue-5.15/net-mlx5e-split-actions_match_supported-into-a-sub-f.patch @@ -0,0 +1,111 @@ +From c6628b78c8f999589ec6a630d9e6222ef2d22cad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Aug 2021 12:53:13 +0300 +Subject: net/mlx5e: Split actions_match_supported() into a sub function + +From: Roi Dayan + +[ Upstream commit 9c1d3511a2c2fd30c991a20c670991ece4ef27c1 ] + +There will probably be more checks, some for nic flows, some for fdb +flows and some are shared checks. Split it for fdb and nic to avoid +the function getting too big. + +Signed-off-by: Roi Dayan +Reviewed-by: Maor Dickman +Signed-off-by: Saeed Mahameed +Signed-off-by: Sasha Levin +--- + .../net/ethernet/mellanox/mlx5/core/en_tc.c | 65 +++++++++++-------- + 1 file changed, 39 insertions(+), 26 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +index fe52db591121..3c6c7801f131 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +@@ -3291,19 +3291,41 @@ static bool modify_header_match_supported(struct mlx5e_priv *priv, + return true; + } + +-static bool actions_match_supported(struct mlx5e_priv *priv, +- struct flow_action *flow_action, +- struct mlx5e_tc_flow_parse_attr *parse_attr, +- struct mlx5e_tc_flow *flow, +- struct netlink_ext_ack *extack) ++static bool ++actions_match_supported_fdb(struct mlx5e_priv *priv, ++ struct mlx5e_tc_flow_parse_attr *parse_attr, ++ struct mlx5e_tc_flow *flow, ++ struct netlink_ext_ack *extack) ++{ ++ bool ct_flow, ct_clear; ++ ++ ct_clear = flow->attr->ct_attr.ct_action & TCA_CT_ACT_CLEAR; ++ ct_flow = flow_flag_test(flow, CT) && !ct_clear; ++ ++ if (flow->attr->esw_attr->split_count && ct_flow && ++ !MLX5_CAP_GEN(flow->attr->esw_attr->in_mdev, reg_c_preserve)) { ++ /* All registers used by ct are cleared when using ++ * split rules. ++ */ ++ NL_SET_ERR_MSG_MOD(extack, "Can't offload mirroring with action ct"); ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool ++actions_match_supported(struct mlx5e_priv *priv, ++ struct flow_action *flow_action, ++ struct mlx5e_tc_flow_parse_attr *parse_attr, ++ struct mlx5e_tc_flow *flow, ++ struct netlink_ext_ack *extack) + { +- bool ct_flow = false, ct_clear = false; +- u32 actions; ++ u32 actions = flow->attr->action; ++ bool ct_flow, ct_clear; + +- ct_clear = flow->attr->ct_attr.ct_action & +- TCA_CT_ACT_CLEAR; ++ ct_clear = flow->attr->ct_attr.ct_action & TCA_CT_ACT_CLEAR; + ct_flow = flow_flag_test(flow, CT) && !ct_clear; +- actions = flow->attr->action; + + if (!(actions & + (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) { +@@ -3311,23 +3333,14 @@ static bool actions_match_supported(struct mlx5e_priv *priv, + return false; + } + +- if (mlx5e_is_eswitch_flow(flow)) { +- if (flow->attr->esw_attr->split_count && ct_flow && +- !MLX5_CAP_GEN(flow->attr->esw_attr->in_mdev, reg_c_preserve)) { +- /* All registers used by ct are cleared when using +- * split rules. +- */ +- NL_SET_ERR_MSG_MOD(extack, +- "Can't offload mirroring with action ct"); +- return false; +- } +- } ++ if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR && ++ !modify_header_match_supported(priv, &parse_attr->spec, flow_action, ++ actions, ct_flow, ct_clear, extack)) ++ return false; + +- if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) +- return modify_header_match_supported(priv, &parse_attr->spec, +- flow_action, actions, +- ct_flow, ct_clear, +- extack); ++ if (mlx5e_is_eswitch_flow(flow) && ++ !actions_match_supported_fdb(priv, parse_attr, flow, extack)) ++ return false; + + return true; + } +-- +2.35.1 + diff --git a/queue-5.15/net-mlx5e-tc-reject-rules-with-drop-and-modify-hdr-a.patch b/queue-5.15/net-mlx5e-tc-reject-rules-with-drop-and-modify-hdr-a.patch new file mode 100644 index 00000000000..9e92120d0b0 --- /dev/null +++ b/queue-5.15/net-mlx5e-tc-reject-rules-with-drop-and-modify-hdr-a.patch @@ -0,0 +1,44 @@ +From 08fd7c1aed95d86dba3605427ca0505d0030061d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Jan 2022 10:38:02 +0200 +Subject: net/mlx5e: TC, Reject rules with drop and modify hdr action + +From: Roi Dayan + +[ Upstream commit a2446bc77a16cefd27de712d28af2396d6287593 ] + +This kind of action is not supported by firmware and generates a +syndrome. + +kernel: mlx5_core 0000:08:00.0: mlx5_cmd_check:777:(pid 102063): SET_FLOW_TABLE_ENTRY(0x936) op_mod(0x0) failed, status bad parameter(0x3), syndrome (0x8708c3) + +Fixes: d7e75a325cb2 ("net/mlx5e: Add offloading of E-Switch TC pedit (header re-write) actions") +Signed-off-by: Roi Dayan +Reviewed-by: Oz Shlomo +Reviewed-by: Maor Dickman +Signed-off-by: Saeed Mahameed +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +index 3c6c7801f131..eb0d9082ccc5 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +@@ -3333,6 +3333,12 @@ actions_match_supported(struct mlx5e_priv *priv, + return false; + } + ++ if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR && ++ actions & MLX5_FLOW_CONTEXT_ACTION_DROP) { ++ NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported"); ++ return false; ++ } ++ + if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR && + !modify_header_match_supported(priv, &parse_attr->spec, flow_action, + actions, ct_flow, ct_clear, extack)) +-- +2.35.1 + diff --git a/queue-5.15/net-mlx5e-tc-reject-rules-with-forward-and-drop-acti.patch b/queue-5.15/net-mlx5e-tc-reject-rules-with-forward-and-drop-acti.patch new file mode 100644 index 00000000000..9c60f19d480 --- /dev/null +++ b/queue-5.15/net-mlx5e-tc-reject-rules-with-forward-and-drop-acti.patch @@ -0,0 +1,41 @@ +From 2fed603288ae5b4a36ffa1f1c31b209d5c0621ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Jan 2022 15:00:30 +0200 +Subject: net/mlx5e: TC, Reject rules with forward and drop actions + +From: Roi Dayan + +[ Upstream commit 5623ef8a118838aae65363750dfafcba734dc8cb ] + +Such rules are redundant but allowed and passed to the driver. +The driver does not support offloading such rules so return an error. + +Fixes: 03a9d11e6eeb ("net/mlx5e: Add TC drop and mirred/redirect action parsing for SRIOV offloads") +Signed-off-by: Roi Dayan +Reviewed-by: Oz Shlomo +Signed-off-by: Saeed Mahameed +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +index eb0d9082ccc5..843c8435387f 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +@@ -3333,6 +3333,12 @@ actions_match_supported(struct mlx5e_priv *priv, + return false; + } + ++ if (!(~actions & ++ (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) { ++ NL_SET_ERR_MSG_MOD(extack, "Rule cannot support forward+drop action"); ++ return false; ++ } ++ + if (actions & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR && + actions & MLX5_FLOW_CONTEXT_ACTION_DROP) { + NL_SET_ERR_MSG_MOD(extack, "Drop with modify header action is not supported"); +-- +2.35.1 + diff --git a/queue-5.15/netfilter-nf_tables-convert-pktinfo-tprot_set-to-fla.patch b/queue-5.15/netfilter-nf_tables-convert-pktinfo-tprot_set-to-fla.patch new file mode 100644 index 00000000000..54cc01bfa28 --- /dev/null +++ b/queue-5.15/netfilter-nf_tables-convert-pktinfo-tprot_set-to-fla.patch @@ -0,0 +1,191 @@ +From ca8bc50489444e634dbff70523538a7b959d2656 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Oct 2021 21:47:55 +0200 +Subject: netfilter: nf_tables: convert pktinfo->tprot_set to flags field + +From: Pablo Neira Ayuso + +[ Upstream commit b5bdc6f9c24db9a0adf8bd00c0e935b184654f00 ] + +Generalize boolean field to store more flags on the pktinfo structure. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables.h | 8 ++++++-- + include/net/netfilter/nf_tables_ipv4.h | 7 ++++--- + include/net/netfilter/nf_tables_ipv6.h | 6 +++--- + net/netfilter/nf_tables_core.c | 2 +- + net/netfilter/nf_tables_trace.c | 4 ++-- + net/netfilter/nft_meta.c | 2 +- + net/netfilter/nft_payload.c | 4 ++-- + 7 files changed, 19 insertions(+), 14 deletions(-) + +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index 2af1c2c64128..d005f87691da 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -21,10 +21,14 @@ struct module; + + #define NFT_JUMP_STACK_SIZE 16 + ++enum { ++ NFT_PKTINFO_L4PROTO = (1 << 0), ++}; ++ + struct nft_pktinfo { + struct sk_buff *skb; + const struct nf_hook_state *state; +- bool tprot_set; ++ u8 flags; + u8 tprot; + u16 fragoff; + unsigned int thoff; +@@ -75,7 +79,7 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt, + + static inline void nft_set_pktinfo_unspec(struct nft_pktinfo *pkt) + { +- pkt->tprot_set = false; ++ pkt->flags = 0; + pkt->tprot = 0; + pkt->thoff = 0; + pkt->fragoff = 0; +diff --git a/include/net/netfilter/nf_tables_ipv4.h b/include/net/netfilter/nf_tables_ipv4.h +index eb4c094cd54d..c4a6147b0ef8 100644 +--- a/include/net/netfilter/nf_tables_ipv4.h ++++ b/include/net/netfilter/nf_tables_ipv4.h +@@ -10,7 +10,7 @@ static inline void nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt) + struct iphdr *ip; + + ip = ip_hdr(pkt->skb); +- pkt->tprot_set = true; ++ pkt->flags = NFT_PKTINFO_L4PROTO; + pkt->tprot = ip->protocol; + pkt->thoff = ip_hdrlen(pkt->skb); + pkt->fragoff = ntohs(ip->frag_off) & IP_OFFSET; +@@ -36,7 +36,7 @@ static inline int __nft_set_pktinfo_ipv4_validate(struct nft_pktinfo *pkt) + else if (len < thoff) + return -1; + +- pkt->tprot_set = true; ++ pkt->flags = NFT_PKTINFO_L4PROTO; + pkt->tprot = iph->protocol; + pkt->thoff = thoff; + pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET; +@@ -71,7 +71,7 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt) + goto inhdr_error; + } + +- pkt->tprot_set = true; ++ pkt->flags = NFT_PKTINFO_L4PROTO; + pkt->tprot = iph->protocol; + pkt->thoff = thoff; + pkt->fragoff = ntohs(iph->frag_off) & IP_OFFSET; +@@ -82,4 +82,5 @@ static inline int nft_set_pktinfo_ipv4_ingress(struct nft_pktinfo *pkt) + __IP_INC_STATS(nft_net(pkt), IPSTATS_MIB_INHDRERRORS); + return -1; + } ++ + #endif +diff --git a/include/net/netfilter/nf_tables_ipv6.h b/include/net/netfilter/nf_tables_ipv6.h +index 7595e02b00ba..ec7eaeaf4f04 100644 +--- a/include/net/netfilter/nf_tables_ipv6.h ++++ b/include/net/netfilter/nf_tables_ipv6.h +@@ -18,7 +18,7 @@ static inline void nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt) + return; + } + +- pkt->tprot_set = true; ++ pkt->flags = NFT_PKTINFO_L4PROTO; + pkt->tprot = protohdr; + pkt->thoff = thoff; + pkt->fragoff = frag_off; +@@ -50,7 +50,7 @@ static inline int __nft_set_pktinfo_ipv6_validate(struct nft_pktinfo *pkt) + if (protohdr < 0) + return -1; + +- pkt->tprot_set = true; ++ pkt->flags = NFT_PKTINFO_L4PROTO; + pkt->tprot = protohdr; + pkt->thoff = thoff; + pkt->fragoff = frag_off; +@@ -96,7 +96,7 @@ static inline int nft_set_pktinfo_ipv6_ingress(struct nft_pktinfo *pkt) + if (protohdr < 0) + goto inhdr_error; + +- pkt->tprot_set = true; ++ pkt->flags = NFT_PKTINFO_L4PROTO; + pkt->tprot = protohdr; + pkt->thoff = thoff; + pkt->fragoff = frag_off; +diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c +index 907e848dbc17..d4d8f613af51 100644 +--- a/net/netfilter/nf_tables_core.c ++++ b/net/netfilter/nf_tables_core.c +@@ -79,7 +79,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr, + if (priv->base == NFT_PAYLOAD_NETWORK_HEADER) + ptr = skb_network_header(skb); + else { +- if (!pkt->tprot_set) ++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO)) + return false; + ptr = skb_network_header(skb) + nft_thoff(pkt); + } +diff --git a/net/netfilter/nf_tables_trace.c b/net/netfilter/nf_tables_trace.c +index e4fe2f0780eb..84a7dea46efa 100644 +--- a/net/netfilter/nf_tables_trace.c ++++ b/net/netfilter/nf_tables_trace.c +@@ -113,13 +113,13 @@ static int nf_trace_fill_pkt_info(struct sk_buff *nlskb, + int off = skb_network_offset(skb); + unsigned int len, nh_end; + +- nh_end = pkt->tprot_set ? nft_thoff(pkt) : skb->len; ++ nh_end = pkt->flags & NFT_PKTINFO_L4PROTO ? nft_thoff(pkt) : skb->len; + len = min_t(unsigned int, nh_end - skb_network_offset(skb), + NFT_TRACETYPE_NETWORK_HSIZE); + if (trace_fill_header(nlskb, NFTA_TRACE_NETWORK_HEADER, skb, off, len)) + return -1; + +- if (pkt->tprot_set) { ++ if (pkt->flags & NFT_PKTINFO_L4PROTO) { + len = min_t(unsigned int, skb->len - nft_thoff(pkt), + NFT_TRACETYPE_TRANSPORT_HSIZE); + if (trace_fill_header(nlskb, NFTA_TRACE_TRANSPORT_HEADER, skb, +diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c +index 44d9b38e5f90..14412f69a34e 100644 +--- a/net/netfilter/nft_meta.c ++++ b/net/netfilter/nft_meta.c +@@ -321,7 +321,7 @@ void nft_meta_get_eval(const struct nft_expr *expr, + nft_reg_store8(dest, nft_pf(pkt)); + break; + case NFT_META_L4PROTO: +- if (!pkt->tprot_set) ++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO)) + goto err; + nft_reg_store8(dest, pkt->tprot); + break; +diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c +index 132875cd7fff..c3ccfff54a35 100644 +--- a/net/netfilter/nft_payload.c ++++ b/net/netfilter/nft_payload.c +@@ -108,7 +108,7 @@ void nft_payload_eval(const struct nft_expr *expr, + offset = skb_network_offset(skb); + break; + case NFT_PAYLOAD_TRANSPORT_HEADER: +- if (!pkt->tprot_set) ++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO)) + goto err; + offset = nft_thoff(pkt); + break; +@@ -613,7 +613,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr, + offset = skb_network_offset(skb); + break; + case NFT_PAYLOAD_TRANSPORT_HEADER: +- if (!pkt->tprot_set) ++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO)) + goto err; + offset = nft_thoff(pkt); + break; +-- +2.35.1 + diff --git a/queue-5.15/netfilter-nft_payload-don-t-allow-th-access-for-frag.patch b/queue-5.15/netfilter-nft_payload-don-t-allow-th-access-for-frag.patch new file mode 100644 index 00000000000..559f1804424 --- /dev/null +++ b/queue-5.15/netfilter-nft_payload-don-t-allow-th-access-for-frag.patch @@ -0,0 +1,81 @@ +From 35ed055b5b815f497a91408e24c2b526d2cdd364 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 29 Jan 2022 17:13:23 +0100 +Subject: netfilter: nft_payload: don't allow th access for fragments + +From: Florian Westphal + +[ Upstream commit a9e8503def0fd4ed89ade1f61c315f904581d439 ] + +Loads relative to ->thoff naturally expect that this points to the +transport header, but this is only true if pkt->fragoff == 0. + +This has little effect for rulesets with connection tracking/nat because +these enable ip defra. For other rulesets this prevents false matches. + +Fixes: 96518518cc41 ("netfilter: add nftables") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nft_exthdr.c | 2 +- + net/netfilter/nft_payload.c | 9 +++++---- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c +index dbe1f2e7dd9e..9e927ab4df15 100644 +--- a/net/netfilter/nft_exthdr.c ++++ b/net/netfilter/nft_exthdr.c +@@ -167,7 +167,7 @@ nft_tcp_header_pointer(const struct nft_pktinfo *pkt, + { + struct tcphdr *tcph; + +- if (pkt->tprot != IPPROTO_TCP) ++ if (pkt->tprot != IPPROTO_TCP || pkt->fragoff) + return NULL; + + tcph = skb_header_pointer(pkt->skb, nft_thoff(pkt), sizeof(*tcph), buffer); +diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c +index ee359a4a60f5..b46e01365bd9 100644 +--- a/net/netfilter/nft_payload.c ++++ b/net/netfilter/nft_payload.c +@@ -84,7 +84,7 @@ static int __nft_payload_inner_offset(struct nft_pktinfo *pkt) + { + unsigned int thoff = nft_thoff(pkt); + +- if (!(pkt->flags & NFT_PKTINFO_L4PROTO)) ++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff) + return -1; + + switch (pkt->tprot) { +@@ -148,7 +148,7 @@ void nft_payload_eval(const struct nft_expr *expr, + offset = skb_network_offset(skb); + break; + case NFT_PAYLOAD_TRANSPORT_HEADER: +- if (!(pkt->flags & NFT_PKTINFO_L4PROTO)) ++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff) + goto err; + offset = nft_thoff(pkt); + break; +@@ -658,7 +658,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr, + offset = skb_network_offset(skb); + break; + case NFT_PAYLOAD_TRANSPORT_HEADER: +- if (!(pkt->flags & NFT_PKTINFO_L4PROTO)) ++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO) || pkt->fragoff) + goto err; + offset = nft_thoff(pkt); + break; +@@ -697,7 +697,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr, + if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP && + pkt->tprot == IPPROTO_SCTP && + skb->ip_summed != CHECKSUM_PARTIAL) { +- if (nft_payload_csum_sctp(skb, nft_thoff(pkt))) ++ if (pkt->fragoff == 0 && ++ nft_payload_csum_sctp(skb, nft_thoff(pkt))) + goto err; + } + +-- +2.35.1 + diff --git a/queue-5.15/netfilter-nft_payload-support-for-inner-header-match.patch b/queue-5.15/netfilter-nft_payload-support-for-inner-header-match.patch new file mode 100644 index 00000000000..8ebe30818fc --- /dev/null +++ b/queue-5.15/netfilter-nft_payload-support-for-inner-header-match.patch @@ -0,0 +1,172 @@ +From 78c276321cd1b4cb114ebdebe38bd97c4768824a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Oct 2021 22:15:00 +0200 +Subject: netfilter: nft_payload: support for inner header matching / mangling + +From: Pablo Neira Ayuso + +[ Upstream commit c46b38dc8743535e686b911d253a844f0bd50ead ] + +Allow to match and mangle on inner headers / payload data after the +transport header. There is a new field in the pktinfo structure that +stores the inner header offset which is calculated only when requested. +Only TCP and UDP supported at this stage. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_tables.h | 2 + + include/uapi/linux/netfilter/nf_tables.h | 2 + + net/netfilter/nft_payload.c | 56 +++++++++++++++++++++++- + 3 files changed, 58 insertions(+), 2 deletions(-) + +diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h +index d005f87691da..bcfee89012a1 100644 +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -23,6 +23,7 @@ struct module; + + enum { + NFT_PKTINFO_L4PROTO = (1 << 0), ++ NFT_PKTINFO_INNER = (1 << 1), + }; + + struct nft_pktinfo { +@@ -32,6 +33,7 @@ struct nft_pktinfo { + u8 tprot; + u16 fragoff; + unsigned int thoff; ++ unsigned int inneroff; + }; + + static inline struct sock *nft_sk(const struct nft_pktinfo *pkt) +diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h +index e94d1fa554cb..07871c8a0601 100644 +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -753,11 +753,13 @@ enum nft_dynset_attributes { + * @NFT_PAYLOAD_LL_HEADER: link layer header + * @NFT_PAYLOAD_NETWORK_HEADER: network header + * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header ++ * @NFT_PAYLOAD_INNER_HEADER: inner header / payload + */ + enum nft_payload_bases { + NFT_PAYLOAD_LL_HEADER, + NFT_PAYLOAD_NETWORK_HEADER, + NFT_PAYLOAD_TRANSPORT_HEADER, ++ NFT_PAYLOAD_INNER_HEADER, + }; + + /** +diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c +index c3ccfff54a35..ee359a4a60f5 100644 +--- a/net/netfilter/nft_payload.c ++++ b/net/netfilter/nft_payload.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + + static bool nft_payload_rebuild_vlan_hdr(const struct sk_buff *skb, int mac_off, +@@ -79,6 +80,45 @@ nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len) + return skb_copy_bits(skb, offset + mac_off, dst_u8, len) == 0; + } + ++static int __nft_payload_inner_offset(struct nft_pktinfo *pkt) ++{ ++ unsigned int thoff = nft_thoff(pkt); ++ ++ if (!(pkt->flags & NFT_PKTINFO_L4PROTO)) ++ return -1; ++ ++ switch (pkt->tprot) { ++ case IPPROTO_UDP: ++ pkt->inneroff = thoff + sizeof(struct udphdr); ++ break; ++ case IPPROTO_TCP: { ++ struct tcphdr *th, _tcph; ++ ++ th = skb_header_pointer(pkt->skb, thoff, sizeof(_tcph), &_tcph); ++ if (!th) ++ return -1; ++ ++ pkt->inneroff = thoff + __tcp_hdrlen(th); ++ } ++ break; ++ default: ++ return -1; ++ } ++ ++ pkt->flags |= NFT_PKTINFO_INNER; ++ ++ return 0; ++} ++ ++static int nft_payload_inner_offset(const struct nft_pktinfo *pkt) ++{ ++ if (!(pkt->flags & NFT_PKTINFO_INNER) && ++ __nft_payload_inner_offset((struct nft_pktinfo *)pkt) < 0) ++ return -1; ++ ++ return pkt->inneroff; ++} ++ + void nft_payload_eval(const struct nft_expr *expr, + struct nft_regs *regs, + const struct nft_pktinfo *pkt) +@@ -112,6 +152,11 @@ void nft_payload_eval(const struct nft_expr *expr, + goto err; + offset = nft_thoff(pkt); + break; ++ case NFT_PAYLOAD_INNER_HEADER: ++ offset = nft_payload_inner_offset(pkt); ++ if (offset < 0) ++ goto err; ++ break; + default: + BUG(); + } +@@ -617,6 +662,11 @@ static void nft_payload_set_eval(const struct nft_expr *expr, + goto err; + offset = nft_thoff(pkt); + break; ++ case NFT_PAYLOAD_INNER_HEADER: ++ offset = nft_payload_inner_offset(pkt); ++ if (offset < 0) ++ goto err; ++ break; + default: + BUG(); + } +@@ -625,7 +675,8 @@ static void nft_payload_set_eval(const struct nft_expr *expr, + offset += priv->offset; + + if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) && +- (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER || ++ ((priv->base != NFT_PAYLOAD_TRANSPORT_HEADER && ++ priv->base != NFT_PAYLOAD_INNER_HEADER) || + skb->ip_summed != CHECKSUM_PARTIAL)) { + fsum = skb_checksum(skb, offset, priv->len, 0); + tsum = csum_partial(src, priv->len, 0); +@@ -744,6 +795,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx, + case NFT_PAYLOAD_LL_HEADER: + case NFT_PAYLOAD_NETWORK_HEADER: + case NFT_PAYLOAD_TRANSPORT_HEADER: ++ case NFT_PAYLOAD_INNER_HEADER: + break; + default: + return ERR_PTR(-EOPNOTSUPP); +@@ -762,7 +814,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx, + len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN])); + + if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) && +- base != NFT_PAYLOAD_LL_HEADER) ++ base != NFT_PAYLOAD_LL_HEADER && base != NFT_PAYLOAD_INNER_HEADER) + return &nft_payload_fast_ops; + else + return &nft_payload_ops; +-- +2.35.1 + diff --git a/queue-5.15/nfsd-commit-operations-must-not-return-nfs-err_inval.patch b/queue-5.15/nfsd-commit-operations-must-not-return-nfs-err_inval.patch new file mode 100644 index 00000000000..5ac253a65bf --- /dev/null +++ b/queue-5.15/nfsd-commit-operations-must-not-return-nfs-err_inval.patch @@ -0,0 +1,180 @@ +From ee4b59358b00686f1bf54c9e8dc579fa7c6f8379 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Jan 2022 15:50:31 -0500 +Subject: NFSD: COMMIT operations must not return NFS?ERR_INVAL + +From: Chuck Lever + +[ Upstream commit 3f965021c8bc38965ecb1924f570c4842b33d408 ] + +Since, well, forever, the Linux NFS server's nfsd_commit() function +has returned nfserr_inval when the passed-in byte range arguments +were non-sensical. + +However, according to RFC 1813 section 3.3.21, NFSv3 COMMIT requests +are permitted to return only the following non-zero status codes: + + NFS3ERR_IO + NFS3ERR_STALE + NFS3ERR_BADHANDLE + NFS3ERR_SERVERFAULT + +NFS3ERR_INVAL is not included in that list. Likewise, NFS4ERR_INVAL +is not listed in the COMMIT row of Table 6 in RFC 8881. + +RFC 7530 does permit COMMIT to return NFS4ERR_INVAL, but does not +specify when it can or should be used. + +Instead of dropping or failing a COMMIT request in a byte range that +is not supported, turn it into a valid request by treating one or +both arguments as zero. Offset zero means start-of-file, count zero +means until-end-of-file, so we only ever extend the commit range. +NFS servers are always allowed to commit more and sooner than +requested. + +The range check is no longer bounded by NFS_OFFSET_MAX, but rather +by the value that is returned in the maxfilesize field of the NFSv3 +FSINFO procedure or the NFSv4 maxfilesize file attribute. + +Note that this change results in a new pynfs failure: + +CMT4 st_commit.testCommitOverflow : RUNNING +CMT4 st_commit.testCommitOverflow : FAILURE + COMMIT with offset + count overflow should return + NFS4ERR_INVAL, instead got NFS4_OK + +IMO the test is not correct as written: RFC 8881 does not allow the +COMMIT operation to return NFS4ERR_INVAL. + +Reported-by: Dan Aloni +Cc: stable@vger.kernel.org +Signed-off-by: Chuck Lever +Reviewed-by: Bruce Fields +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 6 ------ + fs/nfsd/vfs.c | 53 +++++++++++++++++++++++++++++++--------------- + fs/nfsd/vfs.h | 4 ++-- + 3 files changed, 38 insertions(+), 25 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index b540489ea240..936eebd4c56d 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -660,15 +660,9 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) + argp->count, + (unsigned long long) argp->offset); + +- if (argp->offset > NFS_OFFSET_MAX) { +- resp->status = nfserr_inval; +- goto out; +- } +- + fh_copy(&resp->fh, &argp->fh); + resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset, + argp->count, resp->verf); +-out: + return rpc_success; + } + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index c8e3f81d110e..abfbb6953e89 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1108,42 +1108,61 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, + } + + #ifdef CONFIG_NFSD_V3 +-/* +- * Commit all pending writes to stable storage. ++/** ++ * nfsd_commit - Commit pending writes to stable storage ++ * @rqstp: RPC request being processed ++ * @fhp: NFS filehandle ++ * @offset: raw offset from beginning of file ++ * @count: raw count of bytes to sync ++ * @verf: filled in with the server's current write verifier + * +- * Note: we only guarantee that data that lies within the range specified +- * by the 'offset' and 'count' parameters will be synced. ++ * Note: we guarantee that data that lies within the range specified ++ * by the 'offset' and 'count' parameters will be synced. The server ++ * is permitted to sync data that lies outside this range at the ++ * same time. + * + * Unfortunately we cannot lock the file to make sure we return full WCC + * data to the client, as locking happens lower down in the filesystem. ++ * ++ * Return values: ++ * An nfsstat value in network byte order. + */ + __be32 +-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, +- loff_t offset, unsigned long count, __be32 *verf) ++nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, ++ u32 count, __be32 *verf) + { ++ u64 maxbytes; ++ loff_t start, end; + struct nfsd_net *nn; + struct nfsd_file *nf; +- loff_t end = LLONG_MAX; +- __be32 err = nfserr_inval; +- +- if (offset < 0) +- goto out; +- if (count != 0) { +- end = offset + (loff_t)count - 1; +- if (end < offset) +- goto out; +- } ++ __be32 err; + + err = nfsd_file_acquire(rqstp, fhp, + NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf); + if (err) + goto out; ++ ++ /* ++ * Convert the client-provided (offset, count) range to a ++ * (start, end) range. If the client-provided range falls ++ * outside the maximum file size of the underlying FS, ++ * clamp the sync range appropriately. ++ */ ++ start = 0; ++ end = LLONG_MAX; ++ maxbytes = (u64)fhp->fh_dentry->d_sb->s_maxbytes; ++ if (offset < maxbytes) { ++ start = offset; ++ if (count && (offset + count - 1 < maxbytes)) ++ end = offset + count - 1; ++ } ++ + nn = net_generic(nf->nf_net, nfsd_net_id); + if (EX_ISSYNC(fhp->fh_export)) { + errseq_t since = READ_ONCE(nf->nf_file->f_wb_err); + int err2; + +- err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); ++ err2 = vfs_fsync_range(nf->nf_file, start, end, 0); + switch (err2) { + case 0: + nfsd_copy_boot_verifier(verf, nn); +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index b21b76e6b9a8..3cf5a8a13da5 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -73,8 +73,8 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, + struct svc_fh *res, int createmode, + u32 *verifier, bool *truncp, bool *created); +-__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, +- loff_t, unsigned long, __be32 *verf); ++__be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp, ++ u64 offset, u32 count, __be32 *verf); + #endif /* CONFIG_NFSD_V3 */ + #ifdef CONFIG_NFSD_V4 + __be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, +-- +2.35.1 + diff --git a/queue-5.15/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch b/queue-5.15/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch new file mode 100644 index 00000000000..03034beb72d --- /dev/null +++ b/queue-5.15/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch @@ -0,0 +1,66 @@ +From bf108ea172027ce18c12db5a722943ad666d2583 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Dec 2021 14:26:03 -0500 +Subject: NFSD: De-duplicate net_generic(nf->nf_net, nfsd_net_id) + +From: Chuck Lever + +[ Upstream commit 2c445a0e72cb1fbfbdb7f9473c53556ee27c1d90 ] + +Since this pointer is used repeatedly, move it to a stack variable. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 5f62fa0963ce..c8e3f81d110e 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1121,6 +1121,7 @@ __be32 + nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + loff_t offset, unsigned long count, __be32 *verf) + { ++ struct nfsd_net *nn; + struct nfsd_file *nf; + loff_t end = LLONG_MAX; + __be32 err = nfserr_inval; +@@ -1137,6 +1138,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf); + if (err) + goto out; ++ nn = net_generic(nf->nf_net, nfsd_net_id); + if (EX_ISSYNC(fhp->fh_export)) { + errseq_t since = READ_ONCE(nf->nf_file->f_wb_err); + int err2; +@@ -1144,8 +1146,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); + switch (err2) { + case 0: +- nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net, +- nfsd_net_id)); ++ nfsd_copy_boot_verifier(verf, nn); + err2 = filemap_check_wb_err(nf->nf_file->f_mapping, + since); + err = nfserrno(err2); +@@ -1154,13 +1155,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + err = nfserr_notsupp; + break; + default: +- nfsd_reset_boot_verifier(net_generic(nf->nf_net, +- nfsd_net_id)); ++ nfsd_reset_boot_verifier(nn); + err = nfserrno(err2); + } + } else +- nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net, +- nfsd_net_id)); ++ nfsd_copy_boot_verifier(verf, nn); + + nfsd_file_put(nf); + out: +-- +2.35.1 + diff --git a/queue-5.15/pci-pciehp-ignore-link-down-up-caused-by-error-induc.patch b/queue-5.15/pci-pciehp-ignore-link-down-up-caused-by-error-induc.patch new file mode 100644 index 00000000000..2bb4bc8b9e8 --- /dev/null +++ b/queue-5.15/pci-pciehp-ignore-link-down-up-caused-by-error-induc.patch @@ -0,0 +1,179 @@ +From cef53b5144e8e5932507f993c499987da65b7324 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 31 Jul 2021 14:39:01 +0200 +Subject: PCI: pciehp: Ignore Link Down/Up caused by error-induced Hot Reset + +From: Lukas Wunner + +[ Upstream commit ea401499e943c307e6d44af6c2b4e068643e7884 ] + +Stuart Hayes reports that an error handled by DPC at a Root Port results +in pciehp gratuitously bringing down a subordinate hotplug port: + + RP -- UP -- DP -- UP -- DP (hotplug) -- EP + +pciehp brings the slot down because the Link to the Endpoint goes down. +That is caused by a Hot Reset being propagated as a result of DPC. +Per PCIe Base Spec 5.0, section 6.6.1 "Conventional Reset": + + For a Switch, the following must cause a hot reset to be sent on all + Downstream Ports: [...] + + * The Data Link Layer of the Upstream Port reporting DL_Down status. + In Switches that support Link speeds greater than 5.0 GT/s, the + Upstream Port must direct the LTSSM of each Downstream Port to the + Hot Reset state, but not hold the LTSSMs in that state. This permits + each Downstream Port to begin Link training immediately after its + hot reset completes. This behavior is recommended for all Switches. + + * Receiving a hot reset on the Upstream Port. + +Once DPC recovers, pcie_do_recovery() walks down the hierarchy and +invokes pcie_portdrv_slot_reset() to restore each port's config space. +At that point, a hotplug interrupt is signaled per PCIe Base Spec r5.0, +section 6.7.3.4 "Software Notification of Hot-Plug Events": + + If the Port is enabled for edge-triggered interrupt signaling using + MSI or MSI-X, an interrupt message must be sent every time the logical + AND of the following conditions transitions from FALSE to TRUE: [...] + + * The Hot-Plug Interrupt Enable bit in the Slot Control register is + set to 1b. + + * At least one hot-plug event status bit in the Slot Status register + and its associated enable bit in the Slot Control register are both + set to 1b. + +Prevent pciehp from gratuitously bringing down the slot by clearing the +error-induced Data Link Layer State Changed event before restoring +config space. Afterwards, check whether the link has unexpectedly +failed to retrain and synthesize a DLLSC event if so. + +Allow each pcie_port_service_driver (one of them being pciehp) to define +a slot_reset callback and re-use the existing pm_iter() function to +iterate over the callbacks. + +Thereby, the Endpoint driver remains bound throughout error recovery and +may restore the device to working state. + +Surprise removal during error recovery is detected through a Presence +Detect Changed event. The hotplug port is expected to not signal that +event as a result of a Hot Reset. + +The issue isn't DPC-specific, it also occurs when an error is handled by +AER through aer_root_reset(). So while the issue was noticed only now, +it's been around since 2006 when AER support was first introduced. + +[bhelgaas: drop PCI_ERROR_RECOVERY Kconfig, split pm_iter() rename to +preparatory patch] +Link: https://lore.kernel.org/linux-pci/08c046b0-c9f2-3489-eeef-7e7aca435bb9@gmail.com/ +Fixes: 6c2b374d7485 ("PCI-Express AER implemetation: AER core and aerdriver") +Link: https://lore.kernel.org/r/251f4edcc04c14f873ff1c967bc686169cd07d2d.1627638184.git.lukas@wunner.de +Reported-by: Stuart Hayes +Tested-by: Stuart Hayes +Signed-off-by: Lukas Wunner +Signed-off-by: Bjorn Helgaas +Cc: stable@vger.kernel.org # v2.6.19+: ba952824e6c1: PCI/portdrv: Report reset for frozen channel +Cc: Keith Busch +Signed-off-by: Sasha Levin +--- + drivers/pci/hotplug/pciehp.h | 2 ++ + drivers/pci/hotplug/pciehp_core.c | 2 ++ + drivers/pci/hotplug/pciehp_hpc.c | 26 ++++++++++++++++++++++++++ + drivers/pci/pcie/portdrv.h | 2 ++ + drivers/pci/pcie/portdrv_pci.c | 3 +++ + 5 files changed, 35 insertions(+) + +diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h +index 10d7e7e1b553..e0a614acee05 100644 +--- a/drivers/pci/hotplug/pciehp.h ++++ b/drivers/pci/hotplug/pciehp.h +@@ -192,6 +192,8 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status); + int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status); + int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status); + ++int pciehp_slot_reset(struct pcie_device *dev); ++ + static inline const char *slot_name(struct controller *ctrl) + { + return hotplug_slot_name(&ctrl->hotplug_slot); +diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c +index e7fe4b42f039..4042d87d539d 100644 +--- a/drivers/pci/hotplug/pciehp_core.c ++++ b/drivers/pci/hotplug/pciehp_core.c +@@ -351,6 +351,8 @@ static struct pcie_port_service_driver hpdriver_portdrv = { + .runtime_suspend = pciehp_runtime_suspend, + .runtime_resume = pciehp_runtime_resume, + #endif /* PM */ ++ ++ .slot_reset = pciehp_slot_reset, + }; + + int __init pcie_hp_init(void) +diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c +index 8bedbc77fe95..60098a701e83 100644 +--- a/drivers/pci/hotplug/pciehp_hpc.c ++++ b/drivers/pci/hotplug/pciehp_hpc.c +@@ -865,6 +865,32 @@ void pcie_disable_interrupt(struct controller *ctrl) + pcie_write_cmd(ctrl, 0, mask); + } + ++/** ++ * pciehp_slot_reset() - ignore link event caused by error-induced hot reset ++ * @dev: PCI Express port service device ++ * ++ * Called from pcie_portdrv_slot_reset() after AER or DPC initiated a reset ++ * further up in the hierarchy to recover from an error. The reset was ++ * propagated down to this hotplug port. Ignore the resulting link flap. ++ * If the link failed to retrain successfully, synthesize the ignored event. ++ * Surprise removal during reset is detected through Presence Detect Changed. ++ */ ++int pciehp_slot_reset(struct pcie_device *dev) ++{ ++ struct controller *ctrl = get_service_data(dev); ++ ++ if (ctrl->state != ON_STATE) ++ return 0; ++ ++ pcie_capability_write_word(dev->port, PCI_EXP_SLTSTA, ++ PCI_EXP_SLTSTA_DLLSC); ++ ++ if (!pciehp_check_link_active(ctrl)) ++ pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC); ++ ++ return 0; ++} ++ + /* + * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary + * bus reset of the bridge, but at the same time we want to ensure that it is +diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h +index 6126ee4676a7..41fe1ffd5907 100644 +--- a/drivers/pci/pcie/portdrv.h ++++ b/drivers/pci/pcie/portdrv.h +@@ -85,6 +85,8 @@ struct pcie_port_service_driver { + int (*runtime_suspend)(struct pcie_device *dev); + int (*runtime_resume)(struct pcie_device *dev); + ++ int (*slot_reset)(struct pcie_device *dev); ++ + /* Device driver may resume normal operations */ + void (*error_resume)(struct pci_dev *dev); + +diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c +index c7ff1eea225a..1af74c3d9d5d 100644 +--- a/drivers/pci/pcie/portdrv_pci.c ++++ b/drivers/pci/pcie/portdrv_pci.c +@@ -160,6 +160,9 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, + + static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) + { ++ size_t off = offsetof(struct pcie_port_service_driver, slot_reset); ++ device_for_each_child(&dev->dev, &off, pcie_port_device_iter); ++ + pci_restore_state(dev); + pci_save_state(dev); + return PCI_ERS_RESULT_RECOVERED; +-- +2.35.1 + diff --git a/queue-5.15/pci-portdrv-rename-pm_iter-to-pcie_port_device_iter.patch b/queue-5.15/pci-portdrv-rename-pm_iter-to-pcie_port_device_iter.patch new file mode 100644 index 00000000000..e35680d5b01 --- /dev/null +++ b/queue-5.15/pci-portdrv-rename-pm_iter-to-pcie_port_device_iter.patch @@ -0,0 +1,116 @@ +From a9a4c4fae3732ed658c04f1d51892e4569f57dc6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Oct 2021 13:58:40 -0500 +Subject: PCI/portdrv: Rename pm_iter() to pcie_port_device_iter() + +From: Lukas Wunner + +[ Upstream commit 3134689f98f9e09004a4727370adc46e7635b4be ] + +Rename pm_iter() to pcie_port_device_iter() and make it visible outside +CONFIG_PM and portdrv_core.c so it can be used for pciehp slot reset +recovery. + +[bhelgaas: split into its own patch] +Link: https://lore.kernel.org/linux-pci/08c046b0-c9f2-3489-eeef-7e7aca435bb9@gmail.com/ +Link: https://lore.kernel.org/r/251f4edcc04c14f873ff1c967bc686169cd07d2d.1627638184.git.lukas@wunner.de +Signed-off-by: Lukas Wunner +Signed-off-by: Bjorn Helgaas +Signed-off-by: Sasha Levin +--- + drivers/pci/pcie/portdrv.h | 1 + + drivers/pci/pcie/portdrv_core.c | 20 ++++++++++---------- + 2 files changed, 11 insertions(+), 10 deletions(-) + +diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h +index 2ff5724b8f13..6126ee4676a7 100644 +--- a/drivers/pci/pcie/portdrv.h ++++ b/drivers/pci/pcie/portdrv.h +@@ -110,6 +110,7 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *new); + + extern struct bus_type pcie_port_bus_type; + int pcie_port_device_register(struct pci_dev *dev); ++int pcie_port_device_iter(struct device *dev, void *data); + #ifdef CONFIG_PM + int pcie_port_device_suspend(struct device *dev); + int pcie_port_device_resume_noirq(struct device *dev); +diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c +index 3ee63968deaa..604feeb84ee4 100644 +--- a/drivers/pci/pcie/portdrv_core.c ++++ b/drivers/pci/pcie/portdrv_core.c +@@ -367,24 +367,24 @@ int pcie_port_device_register(struct pci_dev *dev) + return status; + } + +-#ifdef CONFIG_PM +-typedef int (*pcie_pm_callback_t)(struct pcie_device *); ++typedef int (*pcie_callback_t)(struct pcie_device *); + +-static int pm_iter(struct device *dev, void *data) ++int pcie_port_device_iter(struct device *dev, void *data) + { + struct pcie_port_service_driver *service_driver; + size_t offset = *(size_t *)data; +- pcie_pm_callback_t cb; ++ pcie_callback_t cb; + + if ((dev->bus == &pcie_port_bus_type) && dev->driver) { + service_driver = to_service_driver(dev->driver); +- cb = *(pcie_pm_callback_t *)((void *)service_driver + offset); ++ cb = *(pcie_callback_t *)((void *)service_driver + offset); + if (cb) + return cb(to_pcie_device(dev)); + } + return 0; + } + ++#ifdef CONFIG_PM + /** + * pcie_port_device_suspend - suspend port services associated with a PCIe port + * @dev: PCI Express port to handle +@@ -392,13 +392,13 @@ static int pm_iter(struct device *dev, void *data) + int pcie_port_device_suspend(struct device *dev) + { + size_t off = offsetof(struct pcie_port_service_driver, suspend); +- return device_for_each_child(dev, &off, pm_iter); ++ return device_for_each_child(dev, &off, pcie_port_device_iter); + } + + int pcie_port_device_resume_noirq(struct device *dev) + { + size_t off = offsetof(struct pcie_port_service_driver, resume_noirq); +- return device_for_each_child(dev, &off, pm_iter); ++ return device_for_each_child(dev, &off, pcie_port_device_iter); + } + + /** +@@ -408,7 +408,7 @@ int pcie_port_device_resume_noirq(struct device *dev) + int pcie_port_device_resume(struct device *dev) + { + size_t off = offsetof(struct pcie_port_service_driver, resume); +- return device_for_each_child(dev, &off, pm_iter); ++ return device_for_each_child(dev, &off, pcie_port_device_iter); + } + + /** +@@ -418,7 +418,7 @@ int pcie_port_device_resume(struct device *dev) + int pcie_port_device_runtime_suspend(struct device *dev) + { + size_t off = offsetof(struct pcie_port_service_driver, runtime_suspend); +- return device_for_each_child(dev, &off, pm_iter); ++ return device_for_each_child(dev, &off, pcie_port_device_iter); + } + + /** +@@ -428,7 +428,7 @@ int pcie_port_device_runtime_suspend(struct device *dev) + int pcie_port_device_runtime_resume(struct device *dev) + { + size_t off = offsetof(struct pcie_port_service_driver, runtime_resume); +- return device_for_each_child(dev, &off, pm_iter); ++ return device_for_each_child(dev, &off, pcie_port_device_iter); + } + #endif /* PM */ + +-- +2.35.1 + diff --git a/queue-5.15/platform-x86-wmi-fix-driver-notify-vs-probe-race.patch b/queue-5.15/platform-x86-wmi-fix-driver-notify-vs-probe-race.patch new file mode 100644 index 00000000000..f8e4d7a154c --- /dev/null +++ b/queue-5.15/platform-x86-wmi-fix-driver-notify-vs-probe-race.patch @@ -0,0 +1,69 @@ +From 4fb1d32679362fbe42c6b51cc7b97aca3c883712 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Nov 2021 20:00:28 +0100 +Subject: platform/x86: wmi: Fix driver->notify() vs ->probe() race + +From: Hans de Goede + +[ Upstream commit 9918878676a5f9e99b98679f04b9e6c0f5426b0a ] + +The driver core sets struct device->driver before calling out +to the bus' probe() method, this leaves a window where an ACPI +notify may happen on the WMI object before the driver's +probe() method has completed running, causing e.g. the +driver's notify() callback to get called with drvdata +not yet being set leading to a NULL pointer deref. + +At a check for this to the WMI core, ensuring that the notify() +callback is not called before the driver is ready. + +Fixes: 1686f5444546 ("platform/x86: wmi: Incorporate acpi_install_notify_handler") +Reviewed-by: Andy Shevchenko +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20211128190031.405620-2-hdegoede@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/wmi.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c +index a00b72ace6d2..c4f917d45b51 100644 +--- a/drivers/platform/x86/wmi.c ++++ b/drivers/platform/x86/wmi.c +@@ -53,6 +53,7 @@ struct guid_block { + + enum { /* wmi_block flags */ + WMI_READ_TAKES_NO_ARGS, ++ WMI_PROBED, + }; + + struct wmi_block { +@@ -980,6 +981,7 @@ static int wmi_dev_probe(struct device *dev) + } + } + ++ set_bit(WMI_PROBED, &wblock->flags); + return 0; + + probe_misc_failure: +@@ -997,6 +999,8 @@ static void wmi_dev_remove(struct device *dev) + struct wmi_block *wblock = dev_to_wblock(dev); + struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); + ++ clear_bit(WMI_PROBED, &wblock->flags); ++ + if (wdriver->filter_callback) { + misc_deregister(&wblock->char_dev); + kfree(wblock->char_dev.name); +@@ -1299,7 +1303,7 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, + return; + + /* If a driver is bound, then notify the driver. */ +- if (wblock->dev.dev.driver) { ++ if (test_bit(WMI_PROBED, &wblock->flags) && wblock->dev.dev.driver) { + struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver); + struct acpi_object_list input; + union acpi_object params[1]; +-- +2.35.1 + diff --git a/queue-5.15/platform-x86-wmi-introduce-helper-to-convert-driver-.patch b/queue-5.15/platform-x86-wmi-introduce-helper-to-convert-driver-.patch new file mode 100644 index 00000000000..499429a4f99 --- /dev/null +++ b/queue-5.15/platform-x86-wmi-introduce-helper-to-convert-driver-.patch @@ -0,0 +1,101 @@ +From 6179f225e94fd8c93b9612d7c581e9884f24901c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 4 Sep 2021 17:56:32 +0000 +Subject: platform/x86: wmi: introduce helper to convert driver to WMI driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Barnabás Pőcze + +[ Upstream commit e7b2e33449e22fdbaa0247d96f31543affe6163d ] + +Introduce a helper function which wraps the appropriate +`container_of()` macro invocation to convert +a `struct device_driver` to `struct wmi_driver`. + +Signed-off-by: Barnabás Pőcze +Link: https://lore.kernel.org/r/20210904175450.156801-27-pobrn@protonmail.com +Reviewed-by: Hans de Goede +Signed-off-by: Hans de Goede +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/wmi.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c +index 1b65bb61ce88..9aeb1a009097 100644 +--- a/drivers/platform/x86/wmi.c ++++ b/drivers/platform/x86/wmi.c +@@ -676,6 +676,11 @@ static struct wmi_device *dev_to_wdev(struct device *dev) + return container_of(dev, struct wmi_device, dev); + } + ++static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv) ++{ ++ return container_of(drv, struct wmi_driver, driver); ++} ++ + /* + * sysfs interface + */ +@@ -794,8 +799,7 @@ static void wmi_dev_release(struct device *dev) + + static int wmi_dev_match(struct device *dev, struct device_driver *driver) + { +- struct wmi_driver *wmi_driver = +- container_of(driver, struct wmi_driver, driver); ++ struct wmi_driver *wmi_driver = drv_to_wdrv(driver); + struct wmi_block *wblock = dev_to_wblock(dev); + const struct wmi_device_id *id = wmi_driver->id_table; + +@@ -892,8 +896,7 @@ static long wmi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + } + + /* let the driver do any filtering and do the call */ +- wdriver = container_of(wblock->dev.dev.driver, +- struct wmi_driver, driver); ++ wdriver = drv_to_wdrv(wblock->dev.dev.driver); + if (!try_module_get(wdriver->driver.owner)) { + ret = -EBUSY; + goto out_ioctl; +@@ -926,8 +929,7 @@ static const struct file_operations wmi_fops = { + static int wmi_dev_probe(struct device *dev) + { + struct wmi_block *wblock = dev_to_wblock(dev); +- struct wmi_driver *wdriver = +- container_of(dev->driver, struct wmi_driver, driver); ++ struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); + int ret = 0; + char *buf; + +@@ -990,8 +992,7 @@ static int wmi_dev_probe(struct device *dev) + static void wmi_dev_remove(struct device *dev) + { + struct wmi_block *wblock = dev_to_wblock(dev); +- struct wmi_driver *wdriver = +- container_of(dev->driver, struct wmi_driver, driver); ++ struct wmi_driver *wdriver = drv_to_wdrv(dev->driver); + + if (wdriver->filter_callback) { + misc_deregister(&wblock->char_dev); +@@ -1296,15 +1297,12 @@ static void acpi_wmi_notify_handler(acpi_handle handle, u32 event, + + /* If a driver is bound, then notify the driver. */ + if (wblock->dev.dev.driver) { +- struct wmi_driver *driver; ++ struct wmi_driver *driver = drv_to_wdrv(wblock->dev.dev.driver); + struct acpi_object_list input; + union acpi_object params[1]; + struct acpi_buffer evdata = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status status; + +- driver = container_of(wblock->dev.dev.driver, +- struct wmi_driver, driver); +- + input.count = 1; + input.pointer = params; + params[0].type = ACPI_TYPE_INTEGER; +-- +2.35.1 + diff --git a/queue-5.15/platform-x86-wmi-replace-read_takes_no_args-with-a-f.patch b/queue-5.15/platform-x86-wmi-replace-read_takes_no_args-with-a-f.patch new file mode 100644 index 00000000000..82e3edb6334 --- /dev/null +++ b/queue-5.15/platform-x86-wmi-replace-read_takes_no_args-with-a-f.patch @@ -0,0 +1,70 @@ +From 607b077f27c8d64adcfc43e25610d69f25a5fd36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Nov 2021 20:00:27 +0100 +Subject: platform/x86: wmi: Replace read_takes_no_args with a flags field + +From: Hans de Goede + +[ Upstream commit a90b38c58667142ecff2521481ed44286d46b140 ] + +Replace the wmi_block.read_takes_no_args bool field with +an unsigned long flags field, used together with test_bit() +and friends. + +This is a preparation patch for fixing a driver->notify() vs ->probe() +race, which requires atomic flag handling. + +Reviewed-by: Andy Shevchenko +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20211128190031.405620-1-hdegoede@redhat.com +Signed-off-by: Sasha Levin +--- + drivers/platform/x86/wmi.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c +index 9aeb1a009097..a00b72ace6d2 100644 +--- a/drivers/platform/x86/wmi.c ++++ b/drivers/platform/x86/wmi.c +@@ -51,6 +51,10 @@ struct guid_block { + u8 flags; + }; + ++enum { /* wmi_block flags */ ++ WMI_READ_TAKES_NO_ARGS, ++}; ++ + struct wmi_block { + struct wmi_device dev; + struct list_head list; +@@ -61,8 +65,7 @@ struct wmi_block { + wmi_notify_handler handler; + void *handler_data; + u64 req_buf_size; +- +- bool read_takes_no_args; ++ unsigned long flags; + }; + + +@@ -325,7 +328,7 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance, + wq_params[0].type = ACPI_TYPE_INTEGER; + wq_params[0].integer.value = instance; + +- if (instance == 0 && wblock->read_takes_no_args) ++ if (instance == 0 && test_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags)) + input.count = 0; + + /* +@@ -1087,7 +1090,7 @@ static int wmi_create_device(struct device *wmi_bus_dev, + * laptops, WQxx may not be a method at all.) + */ + if (info->type != ACPI_TYPE_METHOD || info->param_count == 0) +- wblock->read_takes_no_args = true; ++ set_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags); + + kfree(info); + +-- +2.35.1 + diff --git a/queue-5.15/powerpc-32-don-t-use-lmw-stmw-for-saving-restoring-n.patch b/queue-5.15/powerpc-32-don-t-use-lmw-stmw-for-saving-restoring-n.patch new file mode 100644 index 00000000000..99986d75a7b --- /dev/null +++ b/queue-5.15/powerpc-32-don-t-use-lmw-stmw-for-saving-restoring-n.patch @@ -0,0 +1,49 @@ +From f1c09f0b31f846a8d0c2ae5ed11258e0a405f3de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Aug 2021 15:29:12 +0000 +Subject: powerpc/32: Don't use lmw/stmw for saving/restoring non volatile regs + +From: Christophe Leroy + +[ Upstream commit a85c728cb5e12216c19ae5878980c2cbbbf8616d ] + +Instructions lmw/stmw are interesting for functions that are rarely +used and not in the cache, because only one instruction is to be +copied into the instruction cache instead of 19. However those +instruction are less performant than 19x raw lwz/stw as they require +synchronisation plus one additional cycle. + +SAVE_NVGPRS / REST_NVGPRS are used in only a few places which are +mostly in interrupts entries/exits and in task switch so they are +likely already in the cache. + +Using standard lwz improves null_syscall selftest by: +- 10 cycles on mpc832x. +- 2 cycles on mpc8xx. + +Signed-off-by: Christophe Leroy +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/316c543b8906712c108985c8463eec09c8db577b.1629732542.git.christophe.leroy@csgroup.eu +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/ppc_asm.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h +index 1c538a9a11e0..7be24048b8d1 100644 +--- a/arch/powerpc/include/asm/ppc_asm.h ++++ b/arch/powerpc/include/asm/ppc_asm.h +@@ -28,8 +28,8 @@ + #else + #define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) + #define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) +-#define SAVE_NVGPRS(base) stmw 13, GPR0+4*13(base) +-#define REST_NVGPRS(base) lmw 13, GPR0+4*13(base) ++#define SAVE_NVGPRS(base) SAVE_GPR(13, base); SAVE_8GPRS(14, base); SAVE_10GPRS(22, base) ++#define REST_NVGPRS(base) REST_GPR(13, base); REST_8GPRS(14, base); REST_10GPRS(22, base) + #endif + + #define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +-- +2.35.1 + diff --git a/queue-5.15/powerpc-flexible-gpr-range-save-restore-macros.patch b/queue-5.15/powerpc-flexible-gpr-range-save-restore-macros.patch new file mode 100644 index 00000000000..c6c397174b2 --- /dev/null +++ b/queue-5.15/powerpc-flexible-gpr-range-save-restore-macros.patch @@ -0,0 +1,635 @@ +From c4482f2dac96098ffdf6e188e01bdb0367cf0f5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Oct 2021 16:13:22 +1000 +Subject: powerpc: flexible GPR range save/restore macros + +From: Nicholas Piggin + +[ Upstream commit aebd1fb45c622e9a2b06fb70665d084d3a8d6c78 ] + +Introduce macros that operate on a (start, end) range of GPRs, which +reduces lines of code and need to do mental arithmetic while reading the +code. + +Signed-off-by: Nicholas Piggin +Reviewed-by: Segher Boessenkool +Reviewed-by: Christophe Leroy +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/20211022061322.2671178-1-npiggin@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/boot/crt0.S | 31 +++++++------ + arch/powerpc/crypto/md5-asm.S | 10 ++--- + arch/powerpc/crypto/sha1-powerpc-asm.S | 6 +-- + arch/powerpc/include/asm/ppc_asm.h | 43 ++++++++++++------- + arch/powerpc/kernel/entry_32.S | 23 ++++------ + arch/powerpc/kernel/exceptions-64e.S | 14 ++---- + arch/powerpc/kernel/exceptions-64s.S | 6 +-- + arch/powerpc/kernel/head_32.h | 3 +- + arch/powerpc/kernel/head_booke.h | 3 +- + arch/powerpc/kernel/interrupt_64.S | 34 ++++++--------- + arch/powerpc/kernel/optprobes_head.S | 4 +- + arch/powerpc/kernel/tm.S | 15 ++----- + .../powerpc/kernel/trace/ftrace_64_mprofile.S | 15 +++---- + arch/powerpc/kvm/book3s_hv_rmhandlers.S | 5 +-- + .../lib/test_emulate_step_exec_instr.S | 8 ++-- + 15 files changed, 94 insertions(+), 126 deletions(-) + +diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S +index 1d83966f5ef6..e8f10a599659 100644 +--- a/arch/powerpc/boot/crt0.S ++++ b/arch/powerpc/boot/crt0.S +@@ -226,16 +226,19 @@ p_base: mflr r10 /* r10 now points to runtime addr of p_base */ + #ifdef __powerpc64__ + + #define PROM_FRAME_SIZE 512 +-#define SAVE_GPR(n, base) std n,8*(n)(base) +-#define REST_GPR(n, base) ld n,8*(n)(base) +-#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +-#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +-#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +-#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +-#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +-#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +-#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +-#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) ++ ++.macro OP_REGS op, width, start, end, base, offset ++ .Lreg=\start ++ .rept (\end - \start + 1) ++ \op .Lreg,\offset+\width*.Lreg(\base) ++ .Lreg=.Lreg+1 ++ .endr ++.endm ++ ++#define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, 0 ++#define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, 0 ++#define SAVE_GPR(n, base) SAVE_GPRS(n, n, base) ++#define REST_GPR(n, base) REST_GPRS(n, n, base) + + /* prom handles the jump into and return from firmware. The prom args pointer + is loaded in r3. */ +@@ -246,9 +249,7 @@ prom: + stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ + + SAVE_GPR(2, r1) +- SAVE_GPR(13, r1) +- SAVE_8GPRS(14, r1) +- SAVE_10GPRS(22, r1) ++ SAVE_GPRS(13, 31, r1) + mfcr r10 + std r10,8*32(r1) + mfmsr r10 +@@ -283,9 +284,7 @@ prom: + + /* Restore other registers */ + REST_GPR(2, r1) +- REST_GPR(13, r1) +- REST_8GPRS(14, r1) +- REST_10GPRS(22, r1) ++ REST_GPRS(13, 31, r1) + ld r10,8*32(r1) + mtcr r10 + +diff --git a/arch/powerpc/crypto/md5-asm.S b/arch/powerpc/crypto/md5-asm.S +index 948d100a2934..fa6bc440cf4a 100644 +--- a/arch/powerpc/crypto/md5-asm.S ++++ b/arch/powerpc/crypto/md5-asm.S +@@ -38,15 +38,11 @@ + + #define INITIALIZE \ + PPC_STLU r1,-INT_FRAME_SIZE(r1); \ +- SAVE_8GPRS(14, r1); /* push registers onto stack */ \ +- SAVE_4GPRS(22, r1); \ +- SAVE_GPR(26, r1) ++ SAVE_GPRS(14, 26, r1) /* push registers onto stack */ + + #define FINALIZE \ +- REST_8GPRS(14, r1); /* pop registers from stack */ \ +- REST_4GPRS(22, r1); \ +- REST_GPR(26, r1); \ +- addi r1,r1,INT_FRAME_SIZE; ++ REST_GPRS(14, 26, r1); /* pop registers from stack */ \ ++ addi r1,r1,INT_FRAME_SIZE + + #ifdef __BIG_ENDIAN__ + #define LOAD_DATA(reg, off) \ +diff --git a/arch/powerpc/crypto/sha1-powerpc-asm.S b/arch/powerpc/crypto/sha1-powerpc-asm.S +index 23e248beff71..f0d5ed557ab1 100644 +--- a/arch/powerpc/crypto/sha1-powerpc-asm.S ++++ b/arch/powerpc/crypto/sha1-powerpc-asm.S +@@ -125,8 +125,7 @@ + + _GLOBAL(powerpc_sha_transform) + PPC_STLU r1,-INT_FRAME_SIZE(r1) +- SAVE_8GPRS(14, r1) +- SAVE_10GPRS(22, r1) ++ SAVE_GPRS(14, 31, r1) + + /* Load up A - E */ + lwz RA(0),0(r3) /* A */ +@@ -184,7 +183,6 @@ _GLOBAL(powerpc_sha_transform) + stw RD(0),12(r3) + stw RE(0),16(r3) + +- REST_8GPRS(14, r1) +- REST_10GPRS(22, r1) ++ REST_GPRS(14, 31, r1) + addi r1,r1,INT_FRAME_SIZE + blr +diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h +index 7be24048b8d1..f21e6bde17a1 100644 +--- a/arch/powerpc/include/asm/ppc_asm.h ++++ b/arch/powerpc/include/asm/ppc_asm.h +@@ -16,30 +16,41 @@ + + #define SZL (BITS_PER_LONG/8) + ++/* ++ * This expands to a sequence of operations with reg incrementing from ++ * start to end inclusive, of this form: ++ * ++ * op reg, (offset + (width * reg))(base) ++ * ++ * Note that offset is not the offset of the first operation unless start ++ * is zero (or width is zero). ++ */ ++.macro OP_REGS op, width, start, end, base, offset ++ .Lreg=\start ++ .rept (\end - \start + 1) ++ \op .Lreg, \offset + \width * .Lreg(\base) ++ .Lreg=.Lreg+1 ++ .endr ++.endm ++ + /* + * Macros for storing registers into and loading registers from + * exception frames. + */ + #ifdef __powerpc64__ +-#define SAVE_GPR(n, base) std n,GPR0+8*(n)(base) +-#define REST_GPR(n, base) ld n,GPR0+8*(n)(base) +-#define SAVE_NVGPRS(base) SAVE_8GPRS(14, base); SAVE_10GPRS(22, base) +-#define REST_NVGPRS(base) REST_8GPRS(14, base); REST_10GPRS(22, base) ++#define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, GPR0 ++#define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, GPR0 ++#define SAVE_NVGPRS(base) SAVE_GPRS(14, 31, base) ++#define REST_NVGPRS(base) REST_GPRS(14, 31, base) + #else +-#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base) +-#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base) +-#define SAVE_NVGPRS(base) SAVE_GPR(13, base); SAVE_8GPRS(14, base); SAVE_10GPRS(22, base) +-#define REST_NVGPRS(base) REST_GPR(13, base); REST_8GPRS(14, base); REST_10GPRS(22, base) ++#define SAVE_GPRS(start, end, base) OP_REGS stw, 4, start, end, base, GPR0 ++#define REST_GPRS(start, end, base) OP_REGS lwz, 4, start, end, base, GPR0 ++#define SAVE_NVGPRS(base) SAVE_GPRS(13, 31, base) ++#define REST_NVGPRS(base) REST_GPRS(13, 31, base) + #endif + +-#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) +-#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) +-#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) +-#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) +-#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) +-#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) +-#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) +-#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) ++#define SAVE_GPR(n, base) SAVE_GPRS(n, n, base) ++#define REST_GPR(n, base) REST_GPRS(n, n, base) + + #define SAVE_FPR(n, base) stfd n,8*TS_FPRWIDTH*(n)(base) + #define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base) +diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S +index 61fdd53cdd9a..c62dd9815965 100644 +--- a/arch/powerpc/kernel/entry_32.S ++++ b/arch/powerpc/kernel/entry_32.S +@@ -90,8 +90,7 @@ transfer_to_syscall: + stw r12,8(r1) + stw r2,_TRAP(r1) + SAVE_GPR(0, r1) +- SAVE_4GPRS(3, r1) +- SAVE_2GPRS(7, r1) ++ SAVE_GPRS(3, 8, r1) + addi r2,r10,-THREAD + SAVE_NVGPRS(r1) + +@@ -139,7 +138,7 @@ syscall_exit_finish: + mtxer r5 + lwz r0,GPR0(r1) + lwz r3,GPR3(r1) +- REST_8GPRS(4,r1) ++ REST_GPRS(4, 11, r1) + lwz r12,GPR12(r1) + b 1b + +@@ -232,9 +231,9 @@ fast_exception_return: + beq 3f /* if not, we've got problems */ + #endif + +-2: REST_4GPRS(3, r11) ++2: REST_GPRS(3, 6, r11) + lwz r10,_CCR(r11) +- REST_2GPRS(1, r11) ++ REST_GPRS(1, 2, r11) + mtcr r10 + lwz r10,_LINK(r11) + mtlr r10 +@@ -298,16 +297,14 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) + * the reliable stack unwinder later on. Clear it. + */ + stw r0,8(r1) +- REST_4GPRS(7, r1) +- REST_2GPRS(11, r1) ++ REST_GPRS(7, 12, r1) + + mtcr r3 + mtlr r4 + mtctr r5 + mtspr SPRN_XER,r6 + +- REST_4GPRS(2, r1) +- REST_GPR(6, r1) ++ REST_GPRS(2, 6, r1) + REST_GPR(0, r1) + REST_GPR(1, r1) + rfi +@@ -341,8 +338,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) + lwz r6,_CCR(r1) + li r0,0 + +- REST_4GPRS(7, r1) +- REST_2GPRS(11, r1) ++ REST_GPRS(7, 12, r1) + + mtlr r3 + mtctr r4 +@@ -354,7 +350,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) + */ + stw r0,8(r1) + +- REST_4GPRS(2, r1) ++ REST_GPRS(2, 5, r1) + + bne- cr1,1f /* emulate stack store */ + mtcr r6 +@@ -430,8 +426,7 @@ _ASM_NOKPROBE_SYMBOL(interrupt_return) + bne interrupt_return; \ + lwz r0,GPR0(r1); \ + lwz r2,GPR2(r1); \ +- REST_4GPRS(3, r1); \ +- REST_2GPRS(7, r1); \ ++ REST_GPRS(3, 8, r1); \ + lwz r10,_XER(r1); \ + lwz r11,_CTR(r1); \ + mtspr SPRN_XER,r10; \ +diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S +index 711c66b76df1..67dc4e3179a0 100644 +--- a/arch/powerpc/kernel/exceptions-64e.S ++++ b/arch/powerpc/kernel/exceptions-64e.S +@@ -198,8 +198,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_EMB_HV) + + stdcx. r0,0,r1 /* to clear the reservation */ + +- REST_4GPRS(2, r1) +- REST_4GPRS(6, r1) ++ REST_GPRS(2, 9, r1) + + ld r10,_CTR(r1) + ld r11,_XER(r1) +@@ -375,9 +374,7 @@ ret_from_mc_except: + exc_##n##_common: \ + std r0,GPR0(r1); /* save r0 in stackframe */ \ + std r2,GPR2(r1); /* save r2 in stackframe */ \ +- SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ +- SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ +- std r9,GPR9(r1); /* save r9 in stackframe */ \ ++ SAVE_GPRS(3, 9, r1); /* save r3 - r9 in stackframe */ \ + std r10,_NIP(r1); /* save SRR0 to stackframe */ \ + std r11,_MSR(r1); /* save SRR1 to stackframe */ \ + beq 2f; /* if from kernel mode */ \ +@@ -1061,9 +1058,7 @@ bad_stack_book3e: + std r11,_ESR(r1) + std r0,GPR0(r1); /* save r0 in stackframe */ \ + std r2,GPR2(r1); /* save r2 in stackframe */ \ +- SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ +- SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \ +- std r9,GPR9(r1); /* save r9 in stackframe */ \ ++ SAVE_GPRS(3, 9, r1); /* save r3 - r9 in stackframe */ \ + ld r3,PACA_EXGEN+EX_R10(r13);/* get back r10 */ \ + ld r4,PACA_EXGEN+EX_R11(r13);/* get back r11 */ \ + mfspr r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 XXX can be wrong */ \ +@@ -1077,8 +1072,7 @@ bad_stack_book3e: + std r10,_LINK(r1) + std r11,_CTR(r1) + std r12,_XER(r1) +- SAVE_10GPRS(14,r1) +- SAVE_8GPRS(24,r1) ++ SAVE_GPRS(14, 31, r1) + lhz r12,PACA_TRAP_SAVE(r13) + std r12,_TRAP(r1) + addi r11,r1,INT_FRAME_SIZE +diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S +index eaf1f72131a1..277eccf0f086 100644 +--- a/arch/powerpc/kernel/exceptions-64s.S ++++ b/arch/powerpc/kernel/exceptions-64s.S +@@ -574,8 +574,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) + ld r10,IAREA+EX_CTR(r13) + std r10,_CTR(r1) + std r2,GPR2(r1) /* save r2 in stackframe */ +- SAVE_4GPRS(3, r1) /* save r3 - r6 in stackframe */ +- SAVE_2GPRS(7, r1) /* save r7, r8 in stackframe */ ++ SAVE_GPRS(3, 8, r1) /* save r3 - r8 in stackframe */ + mflr r9 /* Get LR, later save to stack */ + ld r2,PACATOC(r13) /* get kernel TOC into r2 */ + std r9,_LINK(r1) +@@ -693,8 +692,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR) + mtlr r9 + ld r9,_CCR(r1) + mtcr r9 +- REST_8GPRS(2, r1) +- REST_4GPRS(10, r1) ++ REST_GPRS(2, 13, r1) + REST_GPR(0, r1) + /* restore original r1. */ + ld r1,GPR1(r1) +diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h +index 349c4a820231..261c79bdbe53 100644 +--- a/arch/powerpc/kernel/head_32.h ++++ b/arch/powerpc/kernel/head_32.h +@@ -115,8 +115,7 @@ _ASM_NOKPROBE_SYMBOL(\name\()_virt) + stw r10,8(r1) + li r10, \trapno + stw r10,_TRAP(r1) +- SAVE_4GPRS(3, r1) +- SAVE_2GPRS(7, r1) ++ SAVE_GPRS(3, 8, r1) + SAVE_NVGPRS(r1) + stw r2,GPR2(r1) + stw r12,_NIP(r1) +diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h +index ef8d1b1c234e..bb6d5d0fc4ac 100644 +--- a/arch/powerpc/kernel/head_booke.h ++++ b/arch/powerpc/kernel/head_booke.h +@@ -87,8 +87,7 @@ END_BTB_FLUSH_SECTION + stw r10, 8(r1) + li r10, \trapno + stw r10,_TRAP(r1) +- SAVE_4GPRS(3, r1) +- SAVE_2GPRS(7, r1) ++ SAVE_GPRS(3, 8, r1) + SAVE_NVGPRS(r1) + stw r2,GPR2(r1) + stw r12,_NIP(r1) +diff --git a/arch/powerpc/kernel/interrupt_64.S b/arch/powerpc/kernel/interrupt_64.S +index 4c6d1a8dcefe..ff8c8c03f41a 100644 +--- a/arch/powerpc/kernel/interrupt_64.S ++++ b/arch/powerpc/kernel/interrupt_64.S +@@ -166,10 +166,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) + * The value of AMR only matters while we're in the kernel. + */ + mtcr r2 +- ld r2,GPR2(r1) +- ld r3,GPR3(r1) +- ld r13,GPR13(r1) +- ld r1,GPR1(r1) ++ REST_GPRS(2, 3, r1) ++ REST_GPR(13, r1) ++ REST_GPR(1, r1) + RFSCV_TO_USER + b . /* prevent speculative execution */ + +@@ -187,9 +186,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) + mtctr r3 + mtlr r4 + mtspr SPRN_XER,r5 +- REST_10GPRS(2, r1) +- REST_2GPRS(12, r1) +- ld r1,GPR1(r1) ++ REST_GPRS(2, 13, r1) ++ REST_GPR(1, r1) + RFI_TO_USER + .Lsyscall_vectored_\name\()_rst_end: + +@@ -378,10 +376,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) + * The value of AMR only matters while we're in the kernel. + */ + mtcr r2 +- ld r2,GPR2(r1) +- ld r3,GPR3(r1) +- ld r13,GPR13(r1) +- ld r1,GPR1(r1) ++ REST_GPRS(2, 3, r1) ++ REST_GPR(13, r1) ++ REST_GPR(1, r1) + RFI_TO_USER + b . /* prevent speculative execution */ + +@@ -392,8 +389,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) + mtctr r3 + mtspr SPRN_XER,r4 + ld r0,GPR0(r1) +- REST_8GPRS(4, r1) +- ld r12,GPR12(r1) ++ REST_GPRS(4, 12, r1) + b .Lsyscall_restore_regs_cont + .Lsyscall_rst_end: + +@@ -522,17 +518,14 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) + ld r6,_XER(r1) + li r0,0 + +- REST_4GPRS(7, r1) +- REST_2GPRS(11, r1) +- REST_GPR(13, r1) ++ REST_GPRS(7, 13, r1) + + mtcr r3 + mtlr r4 + mtctr r5 + mtspr SPRN_XER,r6 + +- REST_4GPRS(2, r1) +- REST_GPR(6, r1) ++ REST_GPRS(2, 6, r1) + REST_GPR(0, r1) + REST_GPR(1, r1) + .ifc \srr,srr +@@ -629,8 +622,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) + ld r6,_CCR(r1) + li r0,0 + +- REST_4GPRS(7, r1) +- REST_2GPRS(11, r1) ++ REST_GPRS(7, 12, r1) + + mtlr r3 + mtctr r4 +@@ -642,7 +634,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) + */ + std r0,STACK_FRAME_OVERHEAD-16(r1) + +- REST_4GPRS(2, r1) ++ REST_GPRS(2, 5, r1) + + bne- cr1,1f /* emulate stack store */ + mtcr r6 +diff --git a/arch/powerpc/kernel/optprobes_head.S b/arch/powerpc/kernel/optprobes_head.S +index 19ea3312403c..5c7f0b4b784b 100644 +--- a/arch/powerpc/kernel/optprobes_head.S ++++ b/arch/powerpc/kernel/optprobes_head.S +@@ -10,8 +10,8 @@ + #include + + #ifdef CONFIG_PPC64 +-#define SAVE_30GPRS(base) SAVE_10GPRS(2,base); SAVE_10GPRS(12,base); SAVE_10GPRS(22,base) +-#define REST_30GPRS(base) REST_10GPRS(2,base); REST_10GPRS(12,base); REST_10GPRS(22,base) ++#define SAVE_30GPRS(base) SAVE_GPRS(2, 31, base) ++#define REST_30GPRS(base) REST_GPRS(2, 31, base) + #define TEMPLATE_FOR_IMM_LOAD_INSNS nop; nop; nop; nop; nop + #else + #define SAVE_30GPRS(base) stmw r2, GPR2(base) +diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S +index 2b91f233b05d..3beecc32940b 100644 +--- a/arch/powerpc/kernel/tm.S ++++ b/arch/powerpc/kernel/tm.S +@@ -226,11 +226,8 @@ _GLOBAL(tm_reclaim) + + /* Sync the userland GPRs 2-12, 14-31 to thread->regs: */ + SAVE_GPR(0, r7) /* user r0 */ +- SAVE_GPR(2, r7) /* user r2 */ +- SAVE_4GPRS(3, r7) /* user r3-r6 */ +- SAVE_GPR(8, r7) /* user r8 */ +- SAVE_GPR(9, r7) /* user r9 */ +- SAVE_GPR(10, r7) /* user r10 */ ++ SAVE_GPRS(2, 6, r7) /* user r2-r6 */ ++ SAVE_GPRS(8, 10, r7) /* user r8-r10 */ + ld r3, GPR1(r1) /* user r1 */ + ld r4, GPR7(r1) /* user r7 */ + ld r5, GPR11(r1) /* user r11 */ +@@ -445,12 +442,8 @@ restore_gprs: + ld r6, THREAD_TM_PPR(r3) + + REST_GPR(0, r7) /* GPR0 */ +- REST_2GPRS(2, r7) /* GPR2-3 */ +- REST_GPR(4, r7) /* GPR4 */ +- REST_4GPRS(8, r7) /* GPR8-11 */ +- REST_2GPRS(12, r7) /* GPR12-13 */ +- +- REST_NVGPRS(r7) /* GPR14-31 */ ++ REST_GPRS(2, 4, r7) /* GPR2-4 */ ++ REST_GPRS(8, 31, r7) /* GPR8-31 */ + + /* Load up PPR and DSCR here so we don't run with user values for long */ + mtspr SPRN_DSCR, r5 +diff --git a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S +index f9fd5f743eba..d636fc755f60 100644 +--- a/arch/powerpc/kernel/trace/ftrace_64_mprofile.S ++++ b/arch/powerpc/kernel/trace/ftrace_64_mprofile.S +@@ -41,15 +41,14 @@ _GLOBAL(ftrace_regs_caller) + + /* Save all gprs to pt_regs */ + SAVE_GPR(0, r1) +- SAVE_10GPRS(2, r1) ++ SAVE_GPRS(2, 11, r1) + + /* Ok to continue? */ + lbz r3, PACA_FTRACE_ENABLED(r13) + cmpdi r3, 0 + beq ftrace_no_trace + +- SAVE_10GPRS(12, r1) +- SAVE_10GPRS(22, r1) ++ SAVE_GPRS(12, 31, r1) + + /* Save previous stack pointer (r1) */ + addi r8, r1, SWITCH_FRAME_SIZE +@@ -108,10 +107,8 @@ ftrace_regs_call: + #endif + + /* Restore gprs */ +- REST_GPR(0,r1) +- REST_10GPRS(2,r1) +- REST_10GPRS(12,r1) +- REST_10GPRS(22,r1) ++ REST_GPR(0, r1) ++ REST_GPRS(2, 31, r1) + + /* Restore possibly modified LR */ + ld r0, _LINK(r1) +@@ -157,7 +154,7 @@ _GLOBAL(ftrace_caller) + stdu r1, -SWITCH_FRAME_SIZE(r1) + + /* Save all gprs to pt_regs */ +- SAVE_8GPRS(3, r1) ++ SAVE_GPRS(3, 10, r1) + + lbz r3, PACA_FTRACE_ENABLED(r13) + cmpdi r3, 0 +@@ -194,7 +191,7 @@ ftrace_call: + mtctr r3 + + /* Restore gprs */ +- REST_8GPRS(3,r1) ++ REST_GPRS(3, 10, r1) + + /* Restore callee's TOC */ + ld r2, 24(r1) +diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S +index 32a4b4d412b9..81fc1e0ebe9a 100644 +--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S ++++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S +@@ -2711,8 +2711,7 @@ kvmppc_bad_host_intr: + std r0, GPR0(r1) + std r9, GPR1(r1) + std r2, GPR2(r1) +- SAVE_4GPRS(3, r1) +- SAVE_2GPRS(7, r1) ++ SAVE_GPRS(3, 8, r1) + srdi r0, r12, 32 + clrldi r12, r12, 32 + std r0, _CCR(r1) +@@ -2735,7 +2734,7 @@ kvmppc_bad_host_intr: + ld r9, HSTATE_SCRATCH2(r13) + ld r12, HSTATE_SCRATCH0(r13) + GET_SCRATCH0(r0) +- SAVE_4GPRS(9, r1) ++ SAVE_GPRS(9, 12, r1) + std r0, GPR13(r1) + SAVE_NVGPRS(r1) + ld r5, HSTATE_CFAR(r13) +diff --git a/arch/powerpc/lib/test_emulate_step_exec_instr.S b/arch/powerpc/lib/test_emulate_step_exec_instr.S +index 9ef941d958d8..5473f9d03df3 100644 +--- a/arch/powerpc/lib/test_emulate_step_exec_instr.S ++++ b/arch/powerpc/lib/test_emulate_step_exec_instr.S +@@ -37,7 +37,7 @@ _GLOBAL(exec_instr) + * The stack pointer (GPR1) and the thread pointer (GPR13) are not + * saved as these should not be modified anyway. + */ +- SAVE_2GPRS(2, r1) ++ SAVE_GPRS(2, 3, r1) + SAVE_NVGPRS(r1) + + /* +@@ -75,8 +75,7 @@ _GLOBAL(exec_instr) + + /* Load GPRs from pt_regs */ + REST_GPR(0, r31) +- REST_10GPRS(2, r31) +- REST_GPR(12, r31) ++ REST_GPRS(2, 12, r31) + REST_NVGPRS(r31) + + /* Placeholder for the test instruction */ +@@ -99,8 +98,7 @@ _GLOBAL(exec_instr) + subi r3, r3, GPR0 + SAVE_GPR(0, r3) + SAVE_GPR(2, r3) +- SAVE_8GPRS(4, r3) +- SAVE_GPR(12, r3) ++ SAVE_GPRS(4, 12, r3) + SAVE_NVGPRS(r3) + + /* Save resulting LR to pt_regs */ +-- +2.35.1 + diff --git a/queue-5.15/powerpc-tm-fix-more-userspace-r13-corruption.patch b/queue-5.15/powerpc-tm-fix-more-userspace-r13-corruption.patch new file mode 100644 index 00000000000..c9f662a5454 --- /dev/null +++ b/queue-5.15/powerpc-tm-fix-more-userspace-r13-corruption.patch @@ -0,0 +1,119 @@ +From 021729411f0b4d327fe284fcbbe0af306d60a47b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Mar 2022 12:47:33 +1000 +Subject: powerpc/tm: Fix more userspace r13 corruption + +From: Nicholas Piggin + +[ Upstream commit 9d71165d3934e607070c4e48458c0cf161b1baea ] + +Commit cf13435b730a ("powerpc/tm: Fix userspace r13 corruption") fixes a +problem in treclaim where a SLB miss can occur on the +thread_struct->ckpt_regs while SCRATCH0 is live with the saved user r13 +value, clobbering it with the kernel r13 and ultimately resulting in +kernel r13 being stored in ckpt_regs. + +There is an equivalent problem in trechkpt where the user r13 value is +loaded into r13 from chkpt_regs to be recheckpointed, but a SLB miss +could occur on ckpt_regs accesses after that, which will result in r13 +being clobbered with a kernel value and that will get recheckpointed and +then restored to user registers. + +The same memory page is accessed right before this critical window where +a SLB miss could cause corruption, so hitting the bug requires the SLB +entry be removed within a small window of instructions, which is +possible if a SLB related MCE hits there. PAPR also permits the +hypervisor to discard this SLB entry (because slb_shadow->persistent is +only set to SLB_NUM_BOLTED) although it's not known whether any +implementations would do this (KVM does not). So this is an extremely +unlikely bug, only found by inspection. + +Fix this by also storing user r13 in a temporary location on the kernel +stack and don't change the r13 register from kernel r13 until the RI=0 +critical section that does not fault. + +The SCRATCH0 change is not strictly part of the fix, it's only used in +the RI=0 section so it does not have the same problem as the previous +SCRATCH0 bug. + +Fixes: 98ae22e15b43 ("powerpc: Add helper functions for transactional memory context switching") +Cc: stable@vger.kernel.org # v3.9+ +Signed-off-by: Nicholas Piggin +Acked-by: Michael Neuling +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/20220311024733.48926-1-npiggin@gmail.com +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/tm.S | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S +index 3beecc32940b..5a0f023a26e9 100644 +--- a/arch/powerpc/kernel/tm.S ++++ b/arch/powerpc/kernel/tm.S +@@ -443,7 +443,8 @@ restore_gprs: + + REST_GPR(0, r7) /* GPR0 */ + REST_GPRS(2, 4, r7) /* GPR2-4 */ +- REST_GPRS(8, 31, r7) /* GPR8-31 */ ++ REST_GPRS(8, 12, r7) /* GPR8-12 */ ++ REST_GPRS(14, 31, r7) /* GPR14-31 */ + + /* Load up PPR and DSCR here so we don't run with user values for long */ + mtspr SPRN_DSCR, r5 +@@ -479,18 +480,24 @@ restore_gprs: + REST_GPR(6, r7) + + /* +- * Store r1 and r5 on the stack so that we can access them after we +- * clear MSR RI. ++ * Store user r1 and r5 and r13 on the stack (in the unused save ++ * areas / compiler reserved areas), so that we can access them after ++ * we clear MSR RI. + */ + + REST_GPR(5, r7) + std r5, -8(r1) +- ld r5, GPR1(r7) ++ ld r5, GPR13(r7) + std r5, -16(r1) ++ ld r5, GPR1(r7) ++ std r5, -24(r1) + + REST_GPR(7, r7) + +- /* Clear MSR RI since we are about to use SCRATCH0. EE is already off */ ++ /* Stash the stack pointer away for use after recheckpoint */ ++ std r1, PACAR1(r13) ++ ++ /* Clear MSR RI since we are about to clobber r13. EE is already off */ + li r5, 0 + mtmsrd r5, 1 + +@@ -501,9 +508,9 @@ restore_gprs: + * until we turn MSR RI back on. + */ + +- SET_SCRATCH0(r1) + ld r5, -8(r1) +- ld r1, -16(r1) ++ ld r13, -16(r1) ++ ld r1, -24(r1) + + /* Commit register state as checkpointed state: */ + TRECHKPT +@@ -519,9 +526,9 @@ restore_gprs: + */ + + GET_PACA(r13) +- GET_SCRATCH0(r1) ++ ld r1, PACAR1(r13) + +- /* R1 is restored, so we are recoverable again. EE is still off */ ++ /* R13, R1 is restored, so we are recoverable again. EE is still off */ + li r4, MSR_RI + mtmsrd r4, 1 + +-- +2.35.1 + diff --git a/queue-5.15/powerpc-vdso-fix-incorrect-cfi-in-gettimeofday.s.patch b/queue-5.15/powerpc-vdso-fix-incorrect-cfi-in-gettimeofday.s.patch new file mode 100644 index 00000000000..c6dadda0675 --- /dev/null +++ b/queue-5.15/powerpc-vdso-fix-incorrect-cfi-in-gettimeofday.s.patch @@ -0,0 +1,142 @@ +From ee2f47969656f7ab507c4c3f776f28ea6067bb58 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 May 2022 22:50:10 +1000 +Subject: powerpc/vdso: Fix incorrect CFI in gettimeofday.S + +From: Michael Ellerman + +[ Upstream commit 6d65028eb67dbb7627651adfc460d64196d38bd8 ] + +As reported by Alan, the CFI (Call Frame Information) in the VDSO time +routines is incorrect since commit ce7d8056e38b ("powerpc/vdso: Prepare +for switching VDSO to generic C implementation."). + +DWARF has a concept called the CFA (Canonical Frame Address), which on +powerpc is calculated as an offset from the stack pointer (r1). That +means when the stack pointer is changed there must be a corresponding +CFI directive to update the calculation of the CFA. + +The current code is missing those directives for the changes to r1, +which prevents gdb from being able to generate a backtrace from inside +VDSO functions, eg: + + Breakpoint 1, 0x00007ffff7f804dc in __kernel_clock_gettime () + (gdb) bt + #0 0x00007ffff7f804dc in __kernel_clock_gettime () + #1 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6 + #2 0x00007fffffffd960 in ?? () + #3 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6 + Backtrace stopped: frame did not save the PC + +Alan helpfully describes some rules for correctly maintaining the CFI information: + + 1) Every adjustment to the current frame address reg (ie. r1) must be + described, and exactly at the instruction where r1 changes. Why? + Because stack unwinding might want to access previous frames. + + 2) If a function changes LR or any non-volatile register, the save + location for those regs must be given. The CFI can be at any + instruction after the saves up to the point that the reg is + changed. + (Exception: LR save should be described before a bl. not after) + + 3) If asychronous unwind info is needed then restores of LR and + non-volatile regs must also be described. The CFI can be at any + instruction after the reg is restored up to the point where the + save location is (potentially) trashed. + +Fix the inability to backtrace by adding CFI directives describing the +changes to r1, ie. satisfying rule 1. + +Also change the information for LR to point to the copy saved on the +stack, not the value in r0 that will be overwritten by the function +call. + +Finally, add CFI directives describing the save/restore of r2. + +With the fix gdb can correctly back trace and navigate up and down the stack: + + Breakpoint 1, 0x00007ffff7f804dc in __kernel_clock_gettime () + (gdb) bt + #0 0x00007ffff7f804dc in __kernel_clock_gettime () + #1 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6 + #2 0x0000000100015b60 in gettime () + #3 0x000000010000c8bc in print_long_format () + #4 0x000000010000d180 in print_current_files () + #5 0x00000001000054ac in main () + (gdb) up + #1 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6 + (gdb) + #2 0x0000000100015b60 in gettime () + (gdb) + #3 0x000000010000c8bc in print_long_format () + (gdb) + #4 0x000000010000d180 in print_current_files () + (gdb) + #5 0x00000001000054ac in main () + (gdb) + Initial frame selected; you cannot go up. + (gdb) down + #4 0x000000010000d180 in print_current_files () + (gdb) + #3 0x000000010000c8bc in print_long_format () + (gdb) + #2 0x0000000100015b60 in gettime () + (gdb) + #1 0x00007ffff7d8872c in clock_gettime@@GLIBC_2.17 () from /lib64/libc.so.6 + (gdb) + #0 0x00007ffff7f804dc in __kernel_clock_gettime () + (gdb) + +Fixes: ce7d8056e38b ("powerpc/vdso: Prepare for switching VDSO to generic C implementation.") +Cc: stable@vger.kernel.org # v5.11+ +Reported-by: Alan Modra +Signed-off-by: Michael Ellerman +Reviewed-by: Segher Boessenkool +Link: https://lore.kernel.org/r/20220502125010.1319370-1-mpe@ellerman.id.au +Signed-off-by: Sasha Levin +--- + arch/powerpc/kernel/vdso32/gettimeofday.S | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S +index dd2099128b8f..42d40f895c1f 100644 +--- a/arch/powerpc/kernel/vdso32/gettimeofday.S ++++ b/arch/powerpc/kernel/vdso32/gettimeofday.S +@@ -22,12 +22,15 @@ + .macro cvdso_call funct call_time=0 + .cfi_startproc + PPC_STLU r1, -PPC_MIN_STKFRM(r1) ++ .cfi_adjust_cfa_offset PPC_MIN_STKFRM + mflr r0 +- .cfi_register lr, r0 + PPC_STLU r1, -PPC_MIN_STKFRM(r1) ++ .cfi_adjust_cfa_offset PPC_MIN_STKFRM + PPC_STL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) ++ .cfi_rel_offset lr, PPC_MIN_STKFRM + PPC_LR_STKOFF + #ifdef __powerpc64__ + PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) ++ .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT + #endif + get_datapage r5 + .ifeq \call_time +@@ -39,13 +42,15 @@ + PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) + #ifdef __powerpc64__ + PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1) ++ .cfi_restore r2 + #endif + .ifeq \call_time + cmpwi r3, 0 + .endif + mtlr r0 +- .cfi_restore lr + addi r1, r1, 2 * PPC_MIN_STKFRM ++ .cfi_restore lr ++ .cfi_def_cfa_offset 0 + crclr so + .ifeq \call_time + beqlr+ +-- +2.35.1 + diff --git a/queue-5.15/powerpc-vdso-move-cvdso_call-macro-into-gettimeofday.patch b/queue-5.15/powerpc-vdso-move-cvdso_call-macro-into-gettimeofday.patch new file mode 100644 index 00000000000..29e60744ad3 --- /dev/null +++ b/queue-5.15/powerpc-vdso-move-cvdso_call-macro-into-gettimeofday.patch @@ -0,0 +1,143 @@ +From 0b7cd13fa76cd848aad5f2f2298615e8b616e0ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Jan 2022 16:30:34 +0000 +Subject: powerpc/vdso: Move cvdso_call macro into gettimeofday.S + +From: Christophe Leroy + +[ Upstream commit 692b21d78046851e75dc25bba773189c670b49c2 ] + +Now that gettimeofday.S is unique, move cvdso_call macro +into that file which is the only user. + +Signed-off-by: Christophe Leroy +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/72720359d4c58e3a3b96dd74952741225faac3de.1642782130.git.christophe.leroy@csgroup.eu +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/vdso/gettimeofday.h | 52 +------------------- + arch/powerpc/kernel/vdso32/gettimeofday.S | 44 ++++++++++++++++- + 2 files changed, 45 insertions(+), 51 deletions(-) + +diff --git a/arch/powerpc/include/asm/vdso/gettimeofday.h b/arch/powerpc/include/asm/vdso/gettimeofday.h +index df00e91c9a90..f0a4cf01e85c 100644 +--- a/arch/powerpc/include/asm/vdso/gettimeofday.h ++++ b/arch/powerpc/include/asm/vdso/gettimeofday.h +@@ -2,57 +2,9 @@ + #ifndef _ASM_POWERPC_VDSO_GETTIMEOFDAY_H + #define _ASM_POWERPC_VDSO_GETTIMEOFDAY_H + +-#include +- +-#ifdef __ASSEMBLY__ +- +-#include +- +-/* +- * The macro sets two stack frames, one for the caller and one for the callee +- * because there are no requirement for the caller to set a stack frame when +- * calling VDSO so it may have omitted to set one, especially on PPC64 +- */ +- +-.macro cvdso_call funct call_time=0 +- .cfi_startproc +- PPC_STLU r1, -PPC_MIN_STKFRM(r1) +- mflr r0 +- .cfi_register lr, r0 +- PPC_STLU r1, -PPC_MIN_STKFRM(r1) +- PPC_STL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) +-#ifdef __powerpc64__ +- PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) +-#endif +- get_datapage r5 +- .ifeq \call_time +- addi r5, r5, VDSO_DATA_OFFSET +- .else +- addi r4, r5, VDSO_DATA_OFFSET +- .endif +- bl DOTSYM(\funct) +- PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) +-#ifdef __powerpc64__ +- PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1) +-#endif +- .ifeq \call_time +- cmpwi r3, 0 +- .endif +- mtlr r0 +- .cfi_restore lr +- addi r1, r1, 2 * PPC_MIN_STKFRM +- crclr so +- .ifeq \call_time +- beqlr+ +- crset so +- neg r3, r3 +- .endif +- blr +- .cfi_endproc +-.endm +- +-#else ++#ifndef __ASSEMBLY__ + ++#include + #include + #include + #include +diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S +index 9b3ac09423c8..dd2099128b8f 100644 +--- a/arch/powerpc/kernel/vdso32/gettimeofday.S ++++ b/arch/powerpc/kernel/vdso32/gettimeofday.S +@@ -12,7 +12,49 @@ + #include + #include + #include +-#include ++ ++/* ++ * The macro sets two stack frames, one for the caller and one for the callee ++ * because there are no requirement for the caller to set a stack frame when ++ * calling VDSO so it may have omitted to set one, especially on PPC64 ++ */ ++ ++.macro cvdso_call funct call_time=0 ++ .cfi_startproc ++ PPC_STLU r1, -PPC_MIN_STKFRM(r1) ++ mflr r0 ++ .cfi_register lr, r0 ++ PPC_STLU r1, -PPC_MIN_STKFRM(r1) ++ PPC_STL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) ++#ifdef __powerpc64__ ++ PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) ++#endif ++ get_datapage r5 ++ .ifeq \call_time ++ addi r5, r5, VDSO_DATA_OFFSET ++ .else ++ addi r4, r5, VDSO_DATA_OFFSET ++ .endif ++ bl DOTSYM(\funct) ++ PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) ++#ifdef __powerpc64__ ++ PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1) ++#endif ++ .ifeq \call_time ++ cmpwi r3, 0 ++ .endif ++ mtlr r0 ++ .cfi_restore lr ++ addi r1, r1, 2 * PPC_MIN_STKFRM ++ crclr so ++ .ifeq \call_time ++ beqlr+ ++ crset so ++ neg r3, r3 ++ .endif ++ blr ++ .cfi_endproc ++.endm + + .text + /* +-- +2.35.1 + diff --git a/queue-5.15/powerpc-vdso-remove-cvdso_call_time-macro.patch b/queue-5.15/powerpc-vdso-remove-cvdso_call_time-macro.patch new file mode 100644 index 00000000000..02739e19ae0 --- /dev/null +++ b/queue-5.15/powerpc-vdso-remove-cvdso_call_time-macro.patch @@ -0,0 +1,115 @@ +From cdba38a2a3d85a93e10553e853efff9cf09c10cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Jan 2022 16:30:30 +0000 +Subject: powerpc/vdso: Remove cvdso_call_time macro + +From: Christophe Leroy + +[ Upstream commit 9b97bea90072a075363a200dd7b54ad4a24e9491 ] + +cvdso_call_time macro is very similar to cvdso_call macro. + +Add a call_time argument to cvdso_call which is 0 by default +and set to 1 when using cvdso_call to call __c_kernel_time(). + +Return returned value as is with CR[SO] cleared when it is used +for time(). + +Signed-off-by: Christophe Leroy +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/837a260ad86fc1ce297a562c2117fd69be5f7b5c.1642782130.git.christophe.leroy@csgroup.eu +Signed-off-by: Sasha Levin +--- + arch/powerpc/include/asm/vdso/gettimeofday.h | 37 ++++++-------------- + arch/powerpc/kernel/vdso32/gettimeofday.S | 2 +- + 2 files changed, 11 insertions(+), 28 deletions(-) + +diff --git a/arch/powerpc/include/asm/vdso/gettimeofday.h b/arch/powerpc/include/asm/vdso/gettimeofday.h +index 1faff0be1111..df00e91c9a90 100644 +--- a/arch/powerpc/include/asm/vdso/gettimeofday.h ++++ b/arch/powerpc/include/asm/vdso/gettimeofday.h +@@ -9,12 +9,12 @@ + #include + + /* +- * The macros sets two stack frames, one for the caller and one for the callee ++ * The macro sets two stack frames, one for the caller and one for the callee + * because there are no requirement for the caller to set a stack frame when + * calling VDSO so it may have omitted to set one, especially on PPC64 + */ + +-.macro cvdso_call funct ++.macro cvdso_call funct call_time=0 + .cfi_startproc + PPC_STLU r1, -PPC_MIN_STKFRM(r1) + mflr r0 +@@ -25,45 +25,28 @@ + PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) + #endif + get_datapage r5 ++ .ifeq \call_time + addi r5, r5, VDSO_DATA_OFFSET ++ .else ++ addi r4, r5, VDSO_DATA_OFFSET ++ .endif + bl DOTSYM(\funct) + PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) + #ifdef __powerpc64__ + PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1) + #endif ++ .ifeq \call_time + cmpwi r3, 0 ++ .endif + mtlr r0 + .cfi_restore lr + addi r1, r1, 2 * PPC_MIN_STKFRM + crclr so ++ .ifeq \call_time + beqlr+ + crset so + neg r3, r3 +- blr +- .cfi_endproc +-.endm +- +-.macro cvdso_call_time funct +- .cfi_startproc +- PPC_STLU r1, -PPC_MIN_STKFRM(r1) +- mflr r0 +- .cfi_register lr, r0 +- PPC_STLU r1, -PPC_MIN_STKFRM(r1) +- PPC_STL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) +-#ifdef __powerpc64__ +- PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) +-#endif +- get_datapage r4 +- addi r4, r4, VDSO_DATA_OFFSET +- bl DOTSYM(\funct) +- PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) +-#ifdef __powerpc64__ +- PPC_LL r2, PPC_MIN_STKFRM + STK_GOT(r1) +-#endif +- crclr so +- mtlr r0 +- .cfi_restore lr +- addi r1, r1, 2 * PPC_MIN_STKFRM ++ .endif + blr + .cfi_endproc + .endm +diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S +index d21d08140a5e..9b3ac09423c8 100644 +--- a/arch/powerpc/kernel/vdso32/gettimeofday.S ++++ b/arch/powerpc/kernel/vdso32/gettimeofday.S +@@ -63,7 +63,7 @@ V_FUNCTION_END(__kernel_clock_getres) + * + */ + V_FUNCTION_BEGIN(__kernel_time) +- cvdso_call_time __c_kernel_time ++ cvdso_call __c_kernel_time call_time=1 + V_FUNCTION_END(__kernel_time) + + /* Routines for restoring integer registers, called by the compiler. */ +-- +2.35.1 + diff --git a/queue-5.15/qed-improve-the-stack-space-of-filter_config.patch b/queue-5.15/qed-improve-the-stack-space-of-filter_config.patch new file mode 100644 index 00000000000..bbeb30b5e4e --- /dev/null +++ b/queue-5.15/qed-improve-the-stack-space-of-filter_config.patch @@ -0,0 +1,216 @@ +From 6f5729b934b920230b00008013eb4101eca246a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Sep 2021 10:50:24 +0300 +Subject: qed: Improve the stack space of filter_config() + +From: Shai Malin + +[ Upstream commit f55e36d5ab76c3097ff36ecea60b91c6b0d80fc8 ] + +As it was reported and discussed in: https://lore.kernel.org/lkml/CAHk-=whF9F89vsfH8E9TGc0tZA-yhzi2Di8wOtquNB5vRkFX5w@mail.gmail.com/ +This patch improves the stack space of qede_config_rx_mode() by +splitting filter_config() to 3 functions and removing the +union qed_filter_type_params. + +Reported-by: Naresh Kamboju +Signed-off-by: Ariel Elior +Signed-off-by: Shai Malin +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/qlogic/qed/qed_l2.c | 23 ++------- + .../net/ethernet/qlogic/qede/qede_filter.c | 47 ++++++++----------- + include/linux/qed/qed_eth_if.h | 21 ++++----- + 3 files changed, 30 insertions(+), 61 deletions(-) + +diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c +index dfaf10edfabf..ba8c7a31cce1 100644 +--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c ++++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c +@@ -2763,25 +2763,6 @@ static int qed_configure_filter_mcast(struct qed_dev *cdev, + return qed_filter_mcast_cmd(cdev, &mcast, QED_SPQ_MODE_CB, NULL); + } + +-static int qed_configure_filter(struct qed_dev *cdev, +- struct qed_filter_params *params) +-{ +- enum qed_filter_rx_mode_type accept_flags; +- +- switch (params->type) { +- case QED_FILTER_TYPE_UCAST: +- return qed_configure_filter_ucast(cdev, ¶ms->filter.ucast); +- case QED_FILTER_TYPE_MCAST: +- return qed_configure_filter_mcast(cdev, ¶ms->filter.mcast); +- case QED_FILTER_TYPE_RX_MODE: +- accept_flags = params->filter.accept_flags; +- return qed_configure_filter_rx_mode(cdev, accept_flags); +- default: +- DP_NOTICE(cdev, "Unknown filter type %d\n", (int)params->type); +- return -EINVAL; +- } +-} +- + static int qed_configure_arfs_searcher(struct qed_dev *cdev, + enum qed_filter_config_mode mode) + { +@@ -2904,7 +2885,9 @@ static const struct qed_eth_ops qed_eth_ops_pass = { + .q_rx_stop = &qed_stop_rxq, + .q_tx_start = &qed_start_txq, + .q_tx_stop = &qed_stop_txq, +- .filter_config = &qed_configure_filter, ++ .filter_config_rx_mode = &qed_configure_filter_rx_mode, ++ .filter_config_ucast = &qed_configure_filter_ucast, ++ .filter_config_mcast = &qed_configure_filter_mcast, + .fastpath_stop = &qed_fastpath_stop, + .eth_cqe_completion = &qed_fp_cqe_completion, + .get_vport_stats = &qed_get_vport_stats, +diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c +index a2e4dfb5cb44..f99b085b56a5 100644 +--- a/drivers/net/ethernet/qlogic/qede/qede_filter.c ++++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c +@@ -619,30 +619,28 @@ static int qede_set_ucast_rx_mac(struct qede_dev *edev, + enum qed_filter_xcast_params_type opcode, + unsigned char mac[ETH_ALEN]) + { +- struct qed_filter_params filter_cmd; ++ struct qed_filter_ucast_params ucast; + +- memset(&filter_cmd, 0, sizeof(filter_cmd)); +- filter_cmd.type = QED_FILTER_TYPE_UCAST; +- filter_cmd.filter.ucast.type = opcode; +- filter_cmd.filter.ucast.mac_valid = 1; +- ether_addr_copy(filter_cmd.filter.ucast.mac, mac); ++ memset(&ucast, 0, sizeof(ucast)); ++ ucast.type = opcode; ++ ucast.mac_valid = 1; ++ ether_addr_copy(ucast.mac, mac); + +- return edev->ops->filter_config(edev->cdev, &filter_cmd); ++ return edev->ops->filter_config_ucast(edev->cdev, &ucast); + } + + static int qede_set_ucast_rx_vlan(struct qede_dev *edev, + enum qed_filter_xcast_params_type opcode, + u16 vid) + { +- struct qed_filter_params filter_cmd; ++ struct qed_filter_ucast_params ucast; + +- memset(&filter_cmd, 0, sizeof(filter_cmd)); +- filter_cmd.type = QED_FILTER_TYPE_UCAST; +- filter_cmd.filter.ucast.type = opcode; +- filter_cmd.filter.ucast.vlan_valid = 1; +- filter_cmd.filter.ucast.vlan = vid; ++ memset(&ucast, 0, sizeof(ucast)); ++ ucast.type = opcode; ++ ucast.vlan_valid = 1; ++ ucast.vlan = vid; + +- return edev->ops->filter_config(edev->cdev, &filter_cmd); ++ return edev->ops->filter_config_ucast(edev->cdev, &ucast); + } + + static int qede_config_accept_any_vlan(struct qede_dev *edev, bool action) +@@ -1057,18 +1055,17 @@ static int qede_set_mcast_rx_mac(struct qede_dev *edev, + enum qed_filter_xcast_params_type opcode, + unsigned char *mac, int num_macs) + { +- struct qed_filter_params filter_cmd; ++ struct qed_filter_mcast_params mcast; + int i; + +- memset(&filter_cmd, 0, sizeof(filter_cmd)); +- filter_cmd.type = QED_FILTER_TYPE_MCAST; +- filter_cmd.filter.mcast.type = opcode; +- filter_cmd.filter.mcast.num = num_macs; ++ memset(&mcast, 0, sizeof(mcast)); ++ mcast.type = opcode; ++ mcast.num = num_macs; + + for (i = 0; i < num_macs; i++, mac += ETH_ALEN) +- ether_addr_copy(filter_cmd.filter.mcast.mac[i], mac); ++ ether_addr_copy(mcast.mac[i], mac); + +- return edev->ops->filter_config(edev->cdev, &filter_cmd); ++ return edev->ops->filter_config_mcast(edev->cdev, &mcast); + } + + int qede_set_mac_addr(struct net_device *ndev, void *p) +@@ -1194,7 +1191,6 @@ void qede_config_rx_mode(struct net_device *ndev) + { + enum qed_filter_rx_mode_type accept_flags; + struct qede_dev *edev = netdev_priv(ndev); +- struct qed_filter_params rx_mode; + unsigned char *uc_macs, *temp; + struct netdev_hw_addr *ha; + int rc, uc_count; +@@ -1220,10 +1216,6 @@ void qede_config_rx_mode(struct net_device *ndev) + + netif_addr_unlock_bh(ndev); + +- /* Configure the struct for the Rx mode */ +- memset(&rx_mode, 0, sizeof(struct qed_filter_params)); +- rx_mode.type = QED_FILTER_TYPE_RX_MODE; +- + /* Remove all previous unicast secondary macs and multicast macs + * (configure / leave the primary mac) + */ +@@ -1271,8 +1263,7 @@ void qede_config_rx_mode(struct net_device *ndev) + qede_config_accept_any_vlan(edev, false); + } + +- rx_mode.filter.accept_flags = accept_flags; +- edev->ops->filter_config(edev->cdev, &rx_mode); ++ edev->ops->filter_config_rx_mode(edev->cdev, accept_flags); + out: + kfree(uc_macs); + } +diff --git a/include/linux/qed/qed_eth_if.h b/include/linux/qed/qed_eth_if.h +index 812a4d751163..4df0bf0a0864 100644 +--- a/include/linux/qed/qed_eth_if.h ++++ b/include/linux/qed/qed_eth_if.h +@@ -145,12 +145,6 @@ struct qed_filter_mcast_params { + unsigned char mac[64][ETH_ALEN]; + }; + +-union qed_filter_type_params { +- enum qed_filter_rx_mode_type accept_flags; +- struct qed_filter_ucast_params ucast; +- struct qed_filter_mcast_params mcast; +-}; +- + enum qed_filter_type { + QED_FILTER_TYPE_UCAST, + QED_FILTER_TYPE_MCAST, +@@ -158,11 +152,6 @@ enum qed_filter_type { + QED_MAX_FILTER_TYPES, + }; + +-struct qed_filter_params { +- enum qed_filter_type type; +- union qed_filter_type_params filter; +-}; +- + struct qed_tunn_params { + u16 vxlan_port; + u8 update_vxlan_port; +@@ -314,8 +303,14 @@ struct qed_eth_ops { + + int (*q_tx_stop)(struct qed_dev *cdev, u8 rss_id, void *handle); + +- int (*filter_config)(struct qed_dev *cdev, +- struct qed_filter_params *params); ++ int (*filter_config_rx_mode)(struct qed_dev *cdev, ++ enum qed_filter_rx_mode_type type); ++ ++ int (*filter_config_ucast)(struct qed_dev *cdev, ++ struct qed_filter_ucast_params *params); ++ ++ int (*filter_config_mcast)(struct qed_dev *cdev, ++ struct qed_filter_mcast_params *params); + + int (*fastpath_stop)(struct qed_dev *cdev); + +-- +2.35.1 + diff --git a/queue-5.15/risc-v-defconfigs-set-config_fb-y-for-fb-console.patch b/queue-5.15/risc-v-defconfigs-set-config_fb-y-for-fb-console.patch new file mode 100644 index 00000000000..d955657cb3b --- /dev/null +++ b/queue-5.15/risc-v-defconfigs-set-config_fb-y-for-fb-console.patch @@ -0,0 +1,50 @@ +From 60ebac0790e3cdd61d8f3195025142ab92661ec3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Nov 2021 08:44:02 -0800 +Subject: RISC-V: defconfigs: Set CONFIG_FB=y, for FB console + +From: Palmer Dabbelt + +[ Upstream commit 3d12b634fe8206ea974c6061a3f3eea529ffbc48 ] + +We have CONFIG_FRAMEBUFFER_CONSOLE=y in the defconfigs, but that depends +on CONFIG_FB so it's not actually getting set. I'm assuming most users +on real systems want a framebuffer console, so this enables CONFIG_FB to +allow that to take effect. + +Fixes: 33c57c0d3c67 ("RISC-V: Add a basic defconfig") +Reviewed-by: Anup Patel +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sasha Levin +--- + arch/riscv/configs/defconfig | 1 + + arch/riscv/configs/rv32_defconfig | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig +index c252fd5706d2..f2a2f9c9ed49 100644 +--- a/arch/riscv/configs/defconfig ++++ b/arch/riscv/configs/defconfig +@@ -76,6 +76,7 @@ CONFIG_DRM=m + CONFIG_DRM_RADEON=m + CONFIG_DRM_NOUVEAU=m + CONFIG_DRM_VIRTIO_GPU=m ++CONFIG_FB=y + CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_USB=y + CONFIG_USB_XHCI_HCD=y +diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig +index 434ef5b64599..cdd113e7a291 100644 +--- a/arch/riscv/configs/rv32_defconfig ++++ b/arch/riscv/configs/rv32_defconfig +@@ -71,6 +71,7 @@ CONFIG_POWER_RESET=y + CONFIG_DRM=y + CONFIG_DRM_RADEON=y + CONFIG_DRM_VIRTIO_GPU=y ++CONFIG_FB=y + CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_USB=y + CONFIG_USB_XHCI_HCD=y +-- +2.35.1 + diff --git a/queue-5.15/riscv-defconfig-enable-drm_nouveau.patch b/queue-5.15/riscv-defconfig-enable-drm_nouveau.patch new file mode 100644 index 00000000000..96163c9f2bd --- /dev/null +++ b/queue-5.15/riscv-defconfig-enable-drm_nouveau.patch @@ -0,0 +1,43 @@ +From df87782aac9f7b585ff033d7c42ba8be13cbd16d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Oct 2021 18:46:58 +0200 +Subject: riscv: defconfig: enable DRM_NOUVEAU + +From: Heinrich Schuchardt + +[ Upstream commit ffa7a9141bb70702744a312f904b190ca064bdd7 ] + +Both RADEON and NOUVEAU graphics cards are supported on RISC-V. Enabling +the one and not the other does not make sense. + +As typically at most one of RADEON, NOUVEAU, or VIRTIO GPU support will be +needed DRM drivers should be compiled as modules. + +Signed-off-by: Heinrich Schuchardt +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sasha Levin +--- + arch/riscv/configs/defconfig | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig +index 4ebc80315f01..c252fd5706d2 100644 +--- a/arch/riscv/configs/defconfig ++++ b/arch/riscv/configs/defconfig +@@ -72,9 +72,10 @@ CONFIG_GPIOLIB=y + CONFIG_GPIO_SIFIVE=y + # CONFIG_PTP_1588_CLOCK is not set + CONFIG_POWER_RESET=y +-CONFIG_DRM=y +-CONFIG_DRM_RADEON=y +-CONFIG_DRM_VIRTIO_GPU=y ++CONFIG_DRM=m ++CONFIG_DRM_RADEON=m ++CONFIG_DRM_NOUVEAU=m ++CONFIG_DRM_VIRTIO_GPU=m + CONFIG_FRAMEBUFFER_CONSOLE=y + CONFIG_USB=y + CONFIG_USB_XHCI_HCD=y +-- +2.35.1 + diff --git a/queue-5.15/riscv-mm-add-xip_fixup-for-riscv_pfn_base.patch b/queue-5.15/riscv-mm-add-xip_fixup-for-riscv_pfn_base.patch new file mode 100644 index 00000000000..232e5f4b30a --- /dev/null +++ b/queue-5.15/riscv-mm-add-xip_fixup-for-riscv_pfn_base.patch @@ -0,0 +1,36 @@ +From 5fcee4219b77b08e315c1c97a1e9e3937575fb32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Feb 2022 13:14:08 -0800 +Subject: riscv/mm: Add XIP_FIXUP for riscv_pfn_base + +From: Palmer Dabbelt + +[ Upstream commit ca0cb9a60f6d86d4b2139c6f393a78f39edcd7cb ] + +This manifests as a crash early in boot on VexRiscv. + +Signed-off-by: Myrtle Shah +[Palmer: split commit] +Fixes: 44c922572952 ("RISC-V: enable XIP") +Cc: stable@vger.kernel.org +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sasha Levin +--- + arch/riscv/mm/init.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c +index 7f130ac3b9f9..c58a7c77989b 100644 +--- a/arch/riscv/mm/init.c ++++ b/arch/riscv/mm/init.c +@@ -265,6 +265,7 @@ pgd_t early_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); + static pmd_t __maybe_unused early_dtb_pmd[PTRS_PER_PMD] __initdata __aligned(PAGE_SIZE); + + #ifdef CONFIG_XIP_KERNEL ++#define riscv_pfn_base (*(unsigned long *)XIP_FIXUP(&riscv_pfn_base)) + #define trampoline_pg_dir ((pgd_t *)XIP_FIXUP(trampoline_pg_dir)) + #define fixmap_pte ((pte_t *)XIP_FIXUP(fixmap_pte)) + #define early_pg_dir ((pgd_t *)XIP_FIXUP(early_pg_dir)) +-- +2.35.1 + diff --git a/queue-5.15/rxrpc-fix-locking-issue.patch b/queue-5.15/rxrpc-fix-locking-issue.patch new file mode 100644 index 00000000000..c8356513255 --- /dev/null +++ b/queue-5.15/rxrpc-fix-locking-issue.patch @@ -0,0 +1,278 @@ +From 6c69b2ec22827f6af9b763afbd7a393864949492 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 May 2022 08:45:28 +0100 +Subject: rxrpc: Fix locking issue + +From: David Howells + +[ Upstream commit ad25f5cb39872ca14bcbe00816ae65c22fe04b89 ] + +There's a locking issue with the per-netns list of calls in rxrpc. The +pieces of code that add and remove a call from the list use write_lock() +and the calls procfile uses read_lock() to access it. However, the timer +callback function may trigger a removal by trying to queue a call for +processing and finding that it's already queued - at which point it has a +spare refcount that it has to do something with. Unfortunately, if it puts +the call and this reduces the refcount to 0, the call will be removed from +the list. Unfortunately, since the _bh variants of the locking functions +aren't used, this can deadlock. + +================================ +WARNING: inconsistent lock state +5.18.0-rc3-build4+ #10 Not tainted +-------------------------------- +inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. +ksoftirqd/2/25 [HC0[0]:SC1[1]:HE1:SE0] takes: +ffff888107ac4038 (&rxnet->call_lock){+.?.}-{2:2}, at: rxrpc_put_call+0x103/0x14b +{SOFTIRQ-ON-W} state was registered at: +... + Possible unsafe locking scenario: + + CPU0 + ---- + lock(&rxnet->call_lock); + + lock(&rxnet->call_lock); + + *** DEADLOCK *** + +1 lock held by ksoftirqd/2/25: + #0: ffff8881008ffdb0 ((&call->timer)){+.-.}-{0:0}, at: call_timer_fn+0x5/0x23d + +Changes +======= +ver #2) + - Changed to using list_next_rcu() rather than rcu_dereference() directly. + +Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") +Signed-off-by: David Howells +cc: Marc Dionne +cc: linux-afs@lists.infradead.org +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + fs/seq_file.c | 32 ++++++++++++++++++++++++++++++++ + include/linux/list.h | 10 ++++++++++ + include/linux/seq_file.h | 4 ++++ + net/rxrpc/ar-internal.h | 2 +- + net/rxrpc/call_accept.c | 6 +++--- + net/rxrpc/call_object.c | 18 +++++++++--------- + net/rxrpc/net_ns.c | 2 +- + net/rxrpc/proc.c | 10 ++-------- + 8 files changed, 62 insertions(+), 22 deletions(-) + +diff --git a/fs/seq_file.c b/fs/seq_file.c +index 4a2cda04d3e2..b17ee4c4f618 100644 +--- a/fs/seq_file.c ++++ b/fs/seq_file.c +@@ -947,6 +947,38 @@ struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos) + } + EXPORT_SYMBOL(seq_list_next); + ++struct list_head *seq_list_start_rcu(struct list_head *head, loff_t pos) ++{ ++ struct list_head *lh; ++ ++ list_for_each_rcu(lh, head) ++ if (pos-- == 0) ++ return lh; ++ ++ return NULL; ++} ++EXPORT_SYMBOL(seq_list_start_rcu); ++ ++struct list_head *seq_list_start_head_rcu(struct list_head *head, loff_t pos) ++{ ++ if (!pos) ++ return head; ++ ++ return seq_list_start_rcu(head, pos - 1); ++} ++EXPORT_SYMBOL(seq_list_start_head_rcu); ++ ++struct list_head *seq_list_next_rcu(void *v, struct list_head *head, ++ loff_t *ppos) ++{ ++ struct list_head *lh; ++ ++ lh = list_next_rcu((struct list_head *)v); ++ ++*ppos; ++ return lh == head ? NULL : lh; ++} ++EXPORT_SYMBOL(seq_list_next_rcu); ++ + /** + * seq_hlist_start - start an iteration of a hlist + * @head: the head of the hlist +diff --git a/include/linux/list.h b/include/linux/list.h +index a119dd1990d4..d206ae93c06d 100644 +--- a/include/linux/list.h ++++ b/include/linux/list.h +@@ -577,6 +577,16 @@ static inline void list_splice_tail_init(struct list_head *list, + #define list_for_each(pos, head) \ + for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next) + ++/** ++ * list_for_each_rcu - Iterate over a list in an RCU-safe fashion ++ * @pos: the &struct list_head to use as a loop cursor. ++ * @head: the head for your list. ++ */ ++#define list_for_each_rcu(pos, head) \ ++ for (pos = rcu_dereference((head)->next); \ ++ !list_is_head(pos, (head)); \ ++ pos = rcu_dereference(pos->next)) ++ + /** + * list_for_each_continue - continue iteration over a list + * @pos: the &struct list_head to use as a loop cursor. +diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h +index 5733890df64f..0b429111f85e 100644 +--- a/include/linux/seq_file.h ++++ b/include/linux/seq_file.h +@@ -261,6 +261,10 @@ extern struct list_head *seq_list_start_head(struct list_head *head, + extern struct list_head *seq_list_next(void *v, struct list_head *head, + loff_t *ppos); + ++extern struct list_head *seq_list_start_rcu(struct list_head *head, loff_t pos); ++extern struct list_head *seq_list_start_head_rcu(struct list_head *head, loff_t pos); ++extern struct list_head *seq_list_next_rcu(void *v, struct list_head *head, loff_t *ppos); ++ + /* + * Helpers for iteration over hlist_head-s in seq_files + */ +diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h +index dce056adb78c..f2d593e27b64 100644 +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -68,7 +68,7 @@ struct rxrpc_net { + struct proc_dir_entry *proc_net; /* Subdir in /proc/net */ + u32 epoch; /* Local epoch for detecting local-end reset */ + struct list_head calls; /* List of calls active in this namespace */ +- rwlock_t call_lock; /* Lock for ->calls */ ++ spinlock_t call_lock; /* Lock for ->calls */ + atomic_t nr_calls; /* Count of allocated calls */ + + atomic_t nr_conns; +diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c +index 1ae90fb97936..8b24ffbc72ef 100644 +--- a/net/rxrpc/call_accept.c ++++ b/net/rxrpc/call_accept.c +@@ -140,9 +140,9 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, + write_unlock(&rx->call_lock); + + rxnet = call->rxnet; +- write_lock(&rxnet->call_lock); +- list_add_tail(&call->link, &rxnet->calls); +- write_unlock(&rxnet->call_lock); ++ spin_lock_bh(&rxnet->call_lock); ++ list_add_tail_rcu(&call->link, &rxnet->calls); ++ spin_unlock_bh(&rxnet->call_lock); + + b->call_backlog[call_head] = call; + smp_store_release(&b->call_backlog_head, (call_head + 1) & (size - 1)); +diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c +index 043508fd8d8a..25c9a2cbf048 100644 +--- a/net/rxrpc/call_object.c ++++ b/net/rxrpc/call_object.c +@@ -337,9 +337,9 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, + write_unlock(&rx->call_lock); + + rxnet = call->rxnet; +- write_lock(&rxnet->call_lock); +- list_add_tail(&call->link, &rxnet->calls); +- write_unlock(&rxnet->call_lock); ++ spin_lock_bh(&rxnet->call_lock); ++ list_add_tail_rcu(&call->link, &rxnet->calls); ++ spin_unlock_bh(&rxnet->call_lock); + + /* From this point on, the call is protected by its own lock. */ + release_sock(&rx->sk); +@@ -631,9 +631,9 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op) + ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); + + if (!list_empty(&call->link)) { +- write_lock(&rxnet->call_lock); ++ spin_lock_bh(&rxnet->call_lock); + list_del_init(&call->link); +- write_unlock(&rxnet->call_lock); ++ spin_unlock_bh(&rxnet->call_lock); + } + + rxrpc_cleanup_call(call); +@@ -705,7 +705,7 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet) + _enter(""); + + if (!list_empty(&rxnet->calls)) { +- write_lock(&rxnet->call_lock); ++ spin_lock_bh(&rxnet->call_lock); + + while (!list_empty(&rxnet->calls)) { + call = list_entry(rxnet->calls.next, +@@ -720,12 +720,12 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet) + rxrpc_call_states[call->state], + call->flags, call->events); + +- write_unlock(&rxnet->call_lock); ++ spin_unlock_bh(&rxnet->call_lock); + cond_resched(); +- write_lock(&rxnet->call_lock); ++ spin_lock_bh(&rxnet->call_lock); + } + +- write_unlock(&rxnet->call_lock); ++ spin_unlock_bh(&rxnet->call_lock); + } + + atomic_dec(&rxnet->nr_calls); +diff --git a/net/rxrpc/net_ns.c b/net/rxrpc/net_ns.c +index cc7e30733feb..e4d6d432515b 100644 +--- a/net/rxrpc/net_ns.c ++++ b/net/rxrpc/net_ns.c +@@ -50,7 +50,7 @@ static __net_init int rxrpc_init_net(struct net *net) + rxnet->epoch |= RXRPC_RANDOM_EPOCH; + + INIT_LIST_HEAD(&rxnet->calls); +- rwlock_init(&rxnet->call_lock); ++ spin_lock_init(&rxnet->call_lock); + atomic_set(&rxnet->nr_calls, 1); + + atomic_set(&rxnet->nr_conns, 1); +diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c +index e2f990754f88..5a67955cc00f 100644 +--- a/net/rxrpc/proc.c ++++ b/net/rxrpc/proc.c +@@ -26,29 +26,23 @@ static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = { + */ + static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos) + __acquires(rcu) +- __acquires(rxnet->call_lock) + { + struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); + + rcu_read_lock(); +- read_lock(&rxnet->call_lock); +- return seq_list_start_head(&rxnet->calls, *_pos); ++ return seq_list_start_head_rcu(&rxnet->calls, *_pos); + } + + static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos) + { + struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); + +- return seq_list_next(v, &rxnet->calls, pos); ++ return seq_list_next_rcu(v, &rxnet->calls, pos); + } + + static void rxrpc_call_seq_stop(struct seq_file *seq, void *v) +- __releases(rxnet->call_lock) + __releases(rcu) + { +- struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); +- +- read_unlock(&rxnet->call_lock); + rcu_read_unlock(); + } + +-- +2.35.1 + diff --git a/queue-5.15/s390-boot-allocate-amode31-section-in-decompressor.patch b/queue-5.15/s390-boot-allocate-amode31-section-in-decompressor.patch new file mode 100644 index 00000000000..54a698a198b --- /dev/null +++ b/queue-5.15/s390-boot-allocate-amode31-section-in-decompressor.patch @@ -0,0 +1,156 @@ +From 0001f7eab67a67000c3c1f01f6c059320bccef7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Sep 2021 14:18:26 +0200 +Subject: s390/boot: allocate amode31 section in decompressor + +From: Alexander Gordeev + +[ Upstream commit e3ec8e0f5711d73f7e5d5c3cffdf4fad4f1487b9 ] + +The memory for amode31 section is allocated from the decompressed +kernel. Instead, allocate that memory from the decompressor. This +is a prerequisite to allow initialization of the virtual memory +before the decompressed kernel takes over. + +Reviewed-by: Heiko Carstens +Signed-off-by: Alexander Gordeev +Signed-off-by: Vasily Gorbik +Signed-off-by: Sasha Levin +--- + arch/s390/boot/compressed/decompressor.h | 1 + + arch/s390/boot/startup.c | 8 ++++++++ + arch/s390/kernel/entry.h | 1 + + arch/s390/kernel/setup.c | 22 +++++++++------------- + arch/s390/kernel/vmlinux.lds.S | 1 + + 5 files changed, 20 insertions(+), 13 deletions(-) + +diff --git a/arch/s390/boot/compressed/decompressor.h b/arch/s390/boot/compressed/decompressor.h +index a59f75c5b049..f75cc31a77dd 100644 +--- a/arch/s390/boot/compressed/decompressor.h ++++ b/arch/s390/boot/compressed/decompressor.h +@@ -24,6 +24,7 @@ struct vmlinux_info { + unsigned long dynsym_start; + unsigned long rela_dyn_start; + unsigned long rela_dyn_end; ++ unsigned long amode31_size; + }; + + /* Symbols defined by linker scripts */ +diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c +index b13352dd1e1c..1aa11a8f57dd 100644 +--- a/arch/s390/boot/startup.c ++++ b/arch/s390/boot/startup.c +@@ -15,6 +15,7 @@ + #include "uv.h" + + unsigned long __bootdata_preserved(__kaslr_offset); ++unsigned long __bootdata(__amode31_base); + unsigned long __bootdata_preserved(VMALLOC_START); + unsigned long __bootdata_preserved(VMALLOC_END); + struct page *__bootdata_preserved(vmemmap); +@@ -233,6 +234,12 @@ static void offset_vmlinux_info(unsigned long offset) + vmlinux.dynsym_start += offset; + } + ++static unsigned long reserve_amode31(unsigned long safe_addr) ++{ ++ __amode31_base = PAGE_ALIGN(safe_addr); ++ return safe_addr + vmlinux.amode31_size; ++} ++ + void startup_kernel(void) + { + unsigned long random_lma; +@@ -247,6 +254,7 @@ void startup_kernel(void) + setup_lpp(); + store_ipl_parmblock(); + safe_addr = mem_safe_offset(); ++ safe_addr = reserve_amode31(safe_addr); + safe_addr = read_ipl_report(safe_addr); + uv_query_info(); + rescue_initrd(safe_addr); +diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h +index 7f2696e8d511..6083090be1f4 100644 +--- a/arch/s390/kernel/entry.h ++++ b/arch/s390/kernel/entry.h +@@ -70,5 +70,6 @@ extern struct exception_table_entry _stop_amode31_ex_table[]; + #define __amode31_data __section(".amode31.data") + #define __amode31_ref __section(".amode31.refs") + extern long _start_amode31_refs[], _end_amode31_refs[]; ++extern unsigned long __amode31_base; + + #endif /* _ENTRY_H */ +diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c +index 8ede12c4ba6b..e38de9e8ee13 100644 +--- a/arch/s390/kernel/setup.c ++++ b/arch/s390/kernel/setup.c +@@ -95,10 +95,10 @@ EXPORT_SYMBOL(console_irq); + * relocated above 2 GB, because it has to use 31 bit addresses. + * Such code and data is part of the .amode31 section. + */ +-unsigned long __amode31_ref __samode31 = __pa(&_samode31); +-unsigned long __amode31_ref __eamode31 = __pa(&_eamode31); +-unsigned long __amode31_ref __stext_amode31 = __pa(&_stext_amode31); +-unsigned long __amode31_ref __etext_amode31 = __pa(&_etext_amode31); ++unsigned long __amode31_ref __samode31 = (unsigned long)&_samode31; ++unsigned long __amode31_ref __eamode31 = (unsigned long)&_eamode31; ++unsigned long __amode31_ref __stext_amode31 = (unsigned long)&_stext_amode31; ++unsigned long __amode31_ref __etext_amode31 = (unsigned long)&_etext_amode31; + struct exception_table_entry __amode31_ref *__start_amode31_ex_table = _start_amode31_ex_table; + struct exception_table_entry __amode31_ref *__stop_amode31_ex_table = _stop_amode31_ex_table; + +@@ -149,6 +149,7 @@ struct mem_detect_info __bootdata(mem_detect); + struct initrd_data __bootdata(initrd_data); + + unsigned long __bootdata_preserved(__kaslr_offset); ++unsigned long __bootdata(__amode31_base); + unsigned int __bootdata_preserved(zlib_dfltcc_support); + EXPORT_SYMBOL(zlib_dfltcc_support); + u64 __bootdata_preserved(stfle_fac_list[16]); +@@ -800,6 +801,7 @@ static void __init reserve_kernel(void) + + memblock_reserve(0, STARTUP_NORMAL_OFFSET); + memblock_reserve((unsigned long)sclp_early_sccb, EXT_SCCB_READ_SCP); ++ memblock_reserve(__amode31_base, __eamode31 - __samode31); + memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn) + - (unsigned long)_stext); + } +@@ -820,20 +822,14 @@ static void __init setup_memory(void) + + static void __init relocate_amode31_section(void) + { +- unsigned long amode31_addr, amode31_size; +- long amode31_offset; ++ unsigned long amode31_size = __eamode31 - __samode31; ++ long amode31_offset = __amode31_base - __samode31; + long *ptr; + +- /* Allocate a new AMODE31 capable memory region */ +- amode31_size = __eamode31 - __samode31; + pr_info("Relocating AMODE31 section of size 0x%08lx\n", amode31_size); +- amode31_addr = (unsigned long)memblock_alloc_low(amode31_size, PAGE_SIZE); +- if (!amode31_addr) +- panic("Failed to allocate memory for AMODE31 section\n"); +- amode31_offset = amode31_addr - __samode31; + + /* Move original AMODE31 section to the new one */ +- memmove((void *)amode31_addr, (void *)__samode31, amode31_size); ++ memmove((void *)__amode31_base, (void *)__samode31, amode31_size); + /* Zero out the old AMODE31 section to catch invalid accesses within it */ + memset((void *)__samode31, 0, amode31_size); + +diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S +index 63bdb9e1bfc1..42c43521878f 100644 +--- a/arch/s390/kernel/vmlinux.lds.S ++++ b/arch/s390/kernel/vmlinux.lds.S +@@ -212,6 +212,7 @@ SECTIONS + QUAD(__dynsym_start) /* dynsym_start */ + QUAD(__rela_dyn_start) /* rela_dyn_start */ + QUAD(__rela_dyn_end) /* rela_dyn_end */ ++ QUAD(_eamode31 - _samode31) /* amode31_size */ + } :NONE + + /* Debugging sections. */ +-- +2.35.1 + diff --git a/queue-5.15/s390-setup-preserve-memory-at-oldmem_base-and-oldmem.patch b/queue-5.15/s390-setup-preserve-memory-at-oldmem_base-and-oldmem.patch new file mode 100644 index 00000000000..b20a601becb --- /dev/null +++ b/queue-5.15/s390-setup-preserve-memory-at-oldmem_base-and-oldmem.patch @@ -0,0 +1,40 @@ +From ce1ab2ca6f876edd9c3118d16224e046ceb7c313 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Feb 2022 11:25:09 +0100 +Subject: s390/setup: preserve memory at OLDMEM_BASE and OLDMEM_SIZE + +From: Alexander Egorenkov + +[ Upstream commit 6b4b54c7ca347bcb4aa7a3cc01aa16e84ac7fbe4 ] + +We need to preserve the values at OLDMEM_BASE and OLDMEM_SIZE which are +used by zgetdump in case when kdump crashes. In that case zgetdump will +attempt to read OLDMEM_BASE and OLDMEM_SIZE in order to find out where +the memory range [0 - OLDMEM_SIZE] belonging to the production kernel is. + +Fixes: f1a546947431 ("s390/setup: don't reserve memory that occupied decompressor's head") +Cc: stable@vger.kernel.org # 5.15+ +Signed-off-by: Alexander Egorenkov +Acked-by: Vasily Gorbik +Signed-off-by: Vasily Gorbik +Signed-off-by: Sasha Levin +--- + arch/s390/kernel/setup.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c +index 2ebde341d057..36c1f31dfd66 100644 +--- a/arch/s390/kernel/setup.c ++++ b/arch/s390/kernel/setup.c +@@ -798,6 +798,8 @@ static void __init check_initrd(void) + static void __init reserve_kernel(void) + { + memblock_reserve(0, STARTUP_NORMAL_OFFSET); ++ memblock_reserve(OLDMEM_BASE, sizeof(unsigned long)); ++ memblock_reserve(OLDMEM_SIZE, sizeof(unsigned long)); + memblock_reserve(__amode31_base, __eamode31 - __samode31); + memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP); + memblock_reserve(__pa(_stext), _end - _stext); +-- +2.35.1 + diff --git a/queue-5.15/s390-setup-use-physical-pointers-for-memblock_reserv.patch b/queue-5.15/s390-setup-use-physical-pointers-for-memblock_reserv.patch new file mode 100644 index 00000000000..2656b877ab9 --- /dev/null +++ b/queue-5.15/s390-setup-use-physical-pointers-for-memblock_reserv.patch @@ -0,0 +1,43 @@ +From 71a90551a633bf62bef091dd671959717a2a2932 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 13:06:02 +0100 +Subject: s390/setup: use physical pointers for memblock_reserve() + +From: Alexander Gordeev + +[ Upstream commit 04f11ed7d8e018e1f01ebda5814ddfeb3a1e6ae1 ] + +memblock_reserve() function accepts physcal address of a memory +block to be reserved, but provided with virtual memory pointers. + +Reviewed-by: Heiko Carstens +Signed-off-by: Alexander Gordeev +Signed-off-by: Vasily Gorbik +Signed-off-by: Sasha Levin +--- + arch/s390/kernel/setup.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c +index e38de9e8ee13..2ebde341d057 100644 +--- a/arch/s390/kernel/setup.c ++++ b/arch/s390/kernel/setup.c +@@ -797,13 +797,10 @@ static void __init check_initrd(void) + */ + static void __init reserve_kernel(void) + { +- unsigned long start_pfn = PFN_UP(__pa(_end)); +- + memblock_reserve(0, STARTUP_NORMAL_OFFSET); +- memblock_reserve((unsigned long)sclp_early_sccb, EXT_SCCB_READ_SCP); + memblock_reserve(__amode31_base, __eamode31 - __samode31); +- memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn) +- - (unsigned long)_stext); ++ memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP); ++ memblock_reserve(__pa(_stext), _end - _stext); + } + + static void __init setup_memory(void) +-- +2.35.1 + diff --git a/queue-5.15/scsi-qla2xxx-edif-replace-list_for_each_safe-with-li.patch b/queue-5.15/scsi-qla2xxx-edif-replace-list_for_each_safe-with-li.patch new file mode 100644 index 00000000000..d78c0507fb9 --- /dev/null +++ b/queue-5.15/scsi-qla2xxx-edif-replace-list_for_each_safe-with-li.patch @@ -0,0 +1,145 @@ +From bbde4623d891f1ffb9444969baf72dbdc6dcd606 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Oct 2021 04:54:06 -0700 +Subject: scsi: qla2xxx: edif: Replace list_for_each_safe with + list_for_each_entry_safe + +From: Quinn Tran + +[ Upstream commit 8062b742d3bd336ca10ab5a1db1629d33700f9c6 ] + +This patch is per review comment by Hannes Reinecke from previous +submission to replace list_for_each_safe with list_for_each_entry_safe. + +Link: https://lore.kernel.org/r/20211026115412.27691-8-njavali@marvell.com +Reviewed-by: Hannes Reinecke +Reviewed-by: Himanshu Madhani +Signed-off-by: Quinn Tran +Signed-off-by: Nilesh Javali +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/qla2xxx/qla_edif.c | 39 ++++++++------------------------- + drivers/scsi/qla2xxx/qla_edif.h | 1 - + drivers/scsi/qla2xxx/qla_os.c | 8 +++---- + 3 files changed, 13 insertions(+), 35 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c +index a00fe88c6021..e40b9cc38214 100644 +--- a/drivers/scsi/qla2xxx/qla_edif.c ++++ b/drivers/scsi/qla2xxx/qla_edif.c +@@ -1684,41 +1684,25 @@ static struct enode * + qla_enode_find(scsi_qla_host_t *vha, uint32_t ntype, uint32_t p1, uint32_t p2) + { + struct enode *node_rtn = NULL; +- struct enode *list_node = NULL; ++ struct enode *list_node, *q; + unsigned long flags; +- struct list_head *pos, *q; + uint32_t sid; +- uint32_t rw_flag; + struct purexevent *purex; + + /* secure the list from moving under us */ + spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags); + +- list_for_each_safe(pos, q, &vha->pur_cinfo.head) { +- list_node = list_entry(pos, struct enode, list); ++ list_for_each_entry_safe(list_node, q, &vha->pur_cinfo.head, list) { + + /* node type determines what p1 and p2 are */ + purex = &list_node->u.purexinfo; + sid = p1; +- rw_flag = p2; + + if (purex->pur_info.pur_sid.b24 == sid) { +- if (purex->pur_info.pur_pend == 1 && +- rw_flag == PUR_GET) { +- /* +- * if the receive is in progress +- * and its a read/get then can't +- * transfer yet +- */ +- ql_dbg(ql_dbg_edif, vha, 0x9106, +- "%s purex xfer in progress for sid=%x\n", +- __func__, sid); +- } else { +- /* found it and its complete */ +- node_rtn = list_node; +- list_del(pos); +- break; +- } ++ /* found it and its complete */ ++ node_rtn = list_node; ++ list_del(&list_node->list); ++ break; + } + } + +@@ -2428,7 +2412,6 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp) + + purex = &ptr->u.purexinfo; + purex->pur_info.pur_sid = a.did; +- purex->pur_info.pur_pend = 0; + purex->pur_info.pur_bytes_rcvd = totlen; + purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr); + purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle); +@@ -3180,18 +3163,14 @@ static uint16_t qla_edif_sadb_get_sa_index(fc_port_t *fcport, + /* release any sadb entries -- only done at teardown */ + void qla_edif_sadb_release(struct qla_hw_data *ha) + { +- struct list_head *pos; +- struct list_head *tmp; +- struct edif_sa_index_entry *entry; ++ struct edif_sa_index_entry *entry, *tmp; + +- list_for_each_safe(pos, tmp, &ha->sadb_rx_index_list) { +- entry = list_entry(pos, struct edif_sa_index_entry, next); ++ list_for_each_entry_safe(entry, tmp, &ha->sadb_rx_index_list, next) { + list_del(&entry->next); + kfree(entry); + } + +- list_for_each_safe(pos, tmp, &ha->sadb_tx_index_list) { +- entry = list_entry(pos, struct edif_sa_index_entry, next); ++ list_for_each_entry_safe(entry, tmp, &ha->sadb_tx_index_list, next) { + list_del(&entry->next); + kfree(entry); + } +diff --git a/drivers/scsi/qla2xxx/qla_edif.h b/drivers/scsi/qla2xxx/qla_edif.h +index 45cf87e33778..32800bfb32a3 100644 +--- a/drivers/scsi/qla2xxx/qla_edif.h ++++ b/drivers/scsi/qla2xxx/qla_edif.h +@@ -101,7 +101,6 @@ struct dinfo { + }; + + struct pur_ninfo { +- unsigned int pur_pend:1; + port_id_t pur_sid; + port_id_t pur_did; + uint8_t vp_idx; +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index 12958aea893f..c7ab8a8be24c 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -3886,13 +3886,13 @@ qla2x00_remove_one(struct pci_dev *pdev) + static inline void + qla24xx_free_purex_list(struct purex_list *list) + { +- struct list_head *item, *next; ++ struct purex_item *item, *next; + ulong flags; + + spin_lock_irqsave(&list->lock, flags); +- list_for_each_safe(item, next, &list->head) { +- list_del(item); +- kfree(list_entry(item, struct purex_item, list)); ++ list_for_each_entry_safe(item, next, &list->head, list) { ++ list_del(&item->list); ++ kfree(item); + } + spin_unlock_irqrestore(&list->lock, flags); + } +-- +2.35.1 + diff --git a/queue-5.15/scsi-qla2xxx-fix-crash-during-module-load-unload-tes.patch b/queue-5.15/scsi-qla2xxx-fix-crash-during-module-load-unload-tes.patch new file mode 100644 index 00000000000..212cb12e008 --- /dev/null +++ b/queue-5.15/scsi-qla2xxx-fix-crash-during-module-load-unload-tes.patch @@ -0,0 +1,63 @@ +From 5486a36c77b7c513bc8e7ee7f5efb2f25bbec26a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Mar 2022 01:25:56 -0800 +Subject: scsi: qla2xxx: Fix crash during module load unload test + +From: Arun Easi + +[ Upstream commit 0972252450f90db56dd5415a20e2aec21a08d036 ] + +During purex packet handling the driver was incorrectly freeing a +pre-allocated structure. Fix this by skipping that entry. + +System crashed with the following stack during a module unload test. + +Call Trace: + sbitmap_init_node+0x7f/0x1e0 + sbitmap_queue_init_node+0x24/0x150 + blk_mq_init_bitmaps+0x3d/0xa0 + blk_mq_init_tags+0x68/0x90 + blk_mq_alloc_map_and_rqs+0x44/0x120 + blk_mq_alloc_set_map_and_rqs+0x63/0x150 + blk_mq_alloc_tag_set+0x11b/0x230 + scsi_add_host_with_dma.cold+0x3f/0x245 + qla2x00_probe_one+0xd5a/0x1b80 [qla2xxx] + +Call Trace with slub_debug and debug kernel: + kasan_report_invalid_free+0x50/0x80 + __kasan_slab_free+0x137/0x150 + slab_free_freelist_hook+0xc6/0x190 + kfree+0xe8/0x2e0 + qla2x00_free_device+0x3bb/0x5d0 [qla2xxx] + qla2x00_remove_one+0x668/0xcf0 [qla2xxx] + +Link: https://lore.kernel.org/r/20220310092604.22950-6-njavali@marvell.com +Fixes: 62e9dd177732 ("scsi: qla2xxx: Change in PUREX to handle FPIN ELS requests") +Cc: stable@vger.kernel.org +Reported-by: Marco Patalano +Tested-by: Marco Patalano +Reviewed-by: Himanshu Madhani +Signed-off-by: Arun Easi +Signed-off-by: Nilesh Javali +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/qla2xxx/qla_os.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index c7ab8a8be24c..e683b1c01c9f 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -3892,6 +3892,8 @@ qla24xx_free_purex_list(struct purex_list *list) + spin_lock_irqsave(&list->lock, flags); + list_for_each_entry_safe(item, next, &list->head, list) { + list_del(&item->list); ++ if (item == &item->vha->default_item) ++ continue; + kfree(item); + } + spin_unlock_irqrestore(&list->lock, flags); +-- +2.35.1 + diff --git a/queue-5.15/scsi-qla2xxx-fix-laggy-fc-remote-port-session-recove.patch b/queue-5.15/scsi-qla2xxx-fix-laggy-fc-remote-port-session-recove.patch new file mode 100644 index 00000000000..14c8bd888e4 --- /dev/null +++ b/queue-5.15/scsi-qla2xxx-fix-laggy-fc-remote-port-session-recove.patch @@ -0,0 +1,99 @@ +From 38ec01bdbe4dc6581768c5f268071e0427f6ef3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Mar 2022 01:25:59 -0800 +Subject: scsi: qla2xxx: Fix laggy FC remote port session recovery + +From: Quinn Tran + +[ Upstream commit 713b415726f100f6644971e75ebfe1edbef1a390 ] + +For session recovery, driver relies on the dpc thread to initiate certain +operations. The dpc thread runs exclusively without the Mailbox interface +being occupied. A recent code change for heartbeat check via mailbox cmd 0 +is preventing the dpc thread from carrying out its operation. This patch +allows the higher priority error recovery to run first before running the +lower priority heartbeat check. + +Link: https://lore.kernel.org/r/20220310092604.22950-9-njavali@marvell.com +Fixes: d94d8158e184 ("scsi: qla2xxx: Add heartbeat check") +Cc: stable@vger.kernel.org +Reviewed-by: Himanshu Madhani +Signed-off-by: Quinn Tran +Signed-off-by: Nilesh Javali +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/qla2xxx/qla_def.h | 1 + + drivers/scsi/qla2xxx/qla_os.c | 20 +++++++++++++++++--- + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h +index 0589ab8e6467..303ad60d1d49 100644 +--- a/drivers/scsi/qla2xxx/qla_def.h ++++ b/drivers/scsi/qla2xxx/qla_def.h +@@ -4621,6 +4621,7 @@ struct qla_hw_data { + struct workqueue_struct *wq; + struct work_struct heartbeat_work; + struct qlfc_fw fw_buf; ++ unsigned long last_heartbeat_run_jiffies; + + /* FCP_CMND priority support */ + struct qla_fcp_prio_cfg *fcp_prio_cfg; +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index b224326bacee..12958aea893f 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -7205,7 +7205,7 @@ static bool qla_do_heartbeat(struct scsi_qla_host *vha) + return do_heartbeat; + } + +-static void qla_heart_beat(struct scsi_qla_host *vha) ++static void qla_heart_beat(struct scsi_qla_host *vha, u16 dpc_started) + { + struct qla_hw_data *ha = vha->hw; + +@@ -7215,8 +7215,19 @@ static void qla_heart_beat(struct scsi_qla_host *vha) + if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha)) + return; + +- if (qla_do_heartbeat(vha)) ++ /* ++ * dpc thread cannot run if heartbeat is running at the same time. ++ * We also do not want to starve heartbeat task. Therefore, do ++ * heartbeat task at least once every 5 seconds. ++ */ ++ if (dpc_started && ++ time_before(jiffies, ha->last_heartbeat_run_jiffies + 5 * HZ)) ++ return; ++ ++ if (qla_do_heartbeat(vha)) { ++ ha->last_heartbeat_run_jiffies = jiffies; + queue_work(ha->wq, &ha->heartbeat_work); ++ } + } + + /************************************************************************** +@@ -7407,6 +7418,8 @@ qla2x00_timer(struct timer_list *t) + start_dpc++; + } + ++ /* borrowing w to signify dpc will run */ ++ w = 0; + /* Schedule the DPC routine if needed */ + if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || + test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) || +@@ -7439,9 +7452,10 @@ qla2x00_timer(struct timer_list *t) + test_bit(RELOGIN_NEEDED, &vha->dpc_flags), + test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)); + qla2xxx_wake_dpc(vha); ++ w = 1; + } + +- qla_heart_beat(vha); ++ qla_heart_beat(vha, w); + + qla2x00_restart_timer(vha, WATCH_INTERVAL); + } +-- +2.35.1 + diff --git a/queue-5.15/scsi-qla2xxx-fix-loss-of-nvme-namespaces-after-drive.patch b/queue-5.15/scsi-qla2xxx-fix-loss-of-nvme-namespaces-after-drive.patch new file mode 100644 index 00000000000..202158cd7d3 --- /dev/null +++ b/queue-5.15/scsi-qla2xxx-fix-loss-of-nvme-namespaces-after-drive.patch @@ -0,0 +1,74 @@ +From 008496d3d83efaa493b531b6f998f9b902322282 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Mar 2022 01:25:54 -0800 +Subject: scsi: qla2xxx: Fix loss of NVMe namespaces after driver reload test + +From: Arun Easi + +[ Upstream commit db212f2eb3fb7f546366777e93c8f54614d39269 ] + +Driver registration of localport can race when it happens at the remote +port discovery time. Fix this by calling the registration under a mutex. + +Link: https://lore.kernel.org/r/20220310092604.22950-4-njavali@marvell.com +Fixes: e84067d74301 ("scsi: qla2xxx: Add FC-NVMe F/W initialization and transport registration") +Cc: stable@vger.kernel.org +Reported-by: Marco Patalano +Tested-by: Marco Patalano +Reviewed-by: Himanshu Madhani +Signed-off-by: Arun Easi +Signed-off-by: Nilesh Javali +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/qla2xxx/qla_nvme.c | 27 +++++++++++++++++++-------- + 1 file changed, 19 insertions(+), 8 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c +index 42b29f4fd937..1bf3ab10846a 100644 +--- a/drivers/scsi/qla2xxx/qla_nvme.c ++++ b/drivers/scsi/qla2xxx/qla_nvme.c +@@ -775,7 +775,6 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha) + ha = vha->hw; + tmpl = &qla_nvme_fc_transport; + +- WARN_ON(vha->nvme_local_port); + + qla_nvme_fc_transport.max_hw_queues = + min((uint8_t)(qla_nvme_fc_transport.max_hw_queues), +@@ -786,13 +785,25 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha) + pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR; + pinfo.port_id = vha->d_id.b24; + +- ql_log(ql_log_info, vha, 0xffff, +- "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n", +- pinfo.node_name, pinfo.port_name, pinfo.port_id); +- qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary; +- +- ret = nvme_fc_register_localport(&pinfo, tmpl, +- get_device(&ha->pdev->dev), &vha->nvme_local_port); ++ mutex_lock(&ha->vport_lock); ++ /* ++ * Check again for nvme_local_port to see if any other thread raced ++ * with this one and finished registration. ++ */ ++ if (!vha->nvme_local_port) { ++ ql_log(ql_log_info, vha, 0xffff, ++ "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n", ++ pinfo.node_name, pinfo.port_name, pinfo.port_id); ++ qla_nvme_fc_transport.dma_boundary = vha->host->dma_boundary; ++ ++ ret = nvme_fc_register_localport(&pinfo, tmpl, ++ get_device(&ha->pdev->dev), ++ &vha->nvme_local_port); ++ mutex_unlock(&ha->vport_lock); ++ } else { ++ mutex_unlock(&ha->vport_lock); ++ return 0; ++ } + if (ret) { + ql_log(ql_log_warn, vha, 0xffff, + "register_localport failed: ret=%x\n", ret); +-- +2.35.1 + diff --git a/queue-5.15/scsi-qla2xxx-move-heartbeat-handling-from-dpc-thread.patch b/queue-5.15/scsi-qla2xxx-move-heartbeat-handling-from-dpc-thread.patch new file mode 100644 index 00000000000..d92878241ca --- /dev/null +++ b/queue-5.15/scsi-qla2xxx-move-heartbeat-handling-from-dpc-thread.patch @@ -0,0 +1,219 @@ +From c6c065c3f8b75d197175726efac829397a77e4c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 8 Sep 2021 09:46:20 -0700 +Subject: scsi: qla2xxx: Move heartbeat handling from DPC thread to workqueue +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Manish Rangankar + +[ Upstream commit 3a4e1f3b3a3c733de3b82b9b522e54803e1165ae ] + +DPC thread gets restricted due to a no-op mailbox, which is a blocking call +and has a high execution frequency. To free up the DPC thread we move no-op +handling to the workqueue. Also, modified qla_do_heartbeat() to send no-op +MBC if we don’t have any active interrupts, but there are still I/Os +outstanding with firmware. + +Link: https://lore.kernel.org/r/20210908164622.19240-9-njavali@marvell.com +Fixes: d94d8158e184 ("scsi: qla2xxx: Add heartbeat check") +Reviewed-by: Himanshu Madhani +Signed-off-by: Manish Rangankar +Signed-off-by: Nilesh Javali +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/qla2xxx/qla_def.h | 4 +- + drivers/scsi/qla2xxx/qla_init.c | 2 + + drivers/scsi/qla2xxx/qla_os.c | 78 +++++++++++++++------------------ + 3 files changed, 40 insertions(+), 44 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h +index 2ea35e47ea44..0589ab8e6467 100644 +--- a/drivers/scsi/qla2xxx/qla_def.h ++++ b/drivers/scsi/qla2xxx/qla_def.h +@@ -3759,6 +3759,7 @@ struct qla_qpair { + struct qla_fw_resources fwres ____cacheline_aligned; + u32 cmd_cnt; + u32 cmd_completion_cnt; ++ u32 prev_completion_cnt; + }; + + /* Place holder for FW buffer parameters */ +@@ -4618,6 +4619,7 @@ struct qla_hw_data { + struct qla_chip_state_84xx *cs84xx; + struct isp_operations *isp_ops; + struct workqueue_struct *wq; ++ struct work_struct heartbeat_work; + struct qlfc_fw fw_buf; + + /* FCP_CMND priority support */ +@@ -4719,7 +4721,6 @@ struct qla_hw_data { + + struct qla_hw_data_stat stat; + pci_error_state_t pci_error_state; +- u64 prev_cmd_cnt; + struct dma_pool *purex_dma_pool; + struct btree_head32 host_map; + +@@ -4865,7 +4866,6 @@ typedef struct scsi_qla_host { + #define SET_ZIO_THRESHOLD_NEEDED 32 + #define ISP_ABORT_TO_ROM 33 + #define VPORT_DELETE 34 +-#define HEARTBEAT_CHK 38 + + #define PROCESS_PUREX_IOCB 63 + +diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c +index af8df5a800c6..c3ba2995209b 100644 +--- a/drivers/scsi/qla2xxx/qla_init.c ++++ b/drivers/scsi/qla2xxx/qla_init.c +@@ -7096,12 +7096,14 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) + ha->chip_reset++; + ha->base_qpair->chip_reset = ha->chip_reset; + ha->base_qpair->cmd_cnt = ha->base_qpair->cmd_completion_cnt = 0; ++ ha->base_qpair->prev_completion_cnt = 0; + for (i = 0; i < ha->max_qpairs; i++) { + if (ha->queue_pair_map[i]) { + ha->queue_pair_map[i]->chip_reset = + ha->base_qpair->chip_reset; + ha->queue_pair_map[i]->cmd_cnt = + ha->queue_pair_map[i]->cmd_completion_cnt = 0; ++ ha->base_qpair->prev_completion_cnt = 0; + } + } + +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index 77c0bf06f162..b224326bacee 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -2779,6 +2779,16 @@ qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time) + return atomic_read(&vha->loop_state) == LOOP_READY; + } + ++static void qla_heartbeat_work_fn(struct work_struct *work) ++{ ++ struct qla_hw_data *ha = container_of(work, ++ struct qla_hw_data, heartbeat_work); ++ struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); ++ ++ if (!ha->flags.mbox_busy && base_vha->flags.init_done) ++ qla_no_op_mb(base_vha); ++} ++ + static void qla2x00_iocb_work_fn(struct work_struct *work) + { + struct scsi_qla_host *vha = container_of(work, +@@ -3217,6 +3227,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) + host->transportt, sht->vendor_id); + + INIT_WORK(&base_vha->iocb_work, qla2x00_iocb_work_fn); ++ INIT_WORK(&ha->heartbeat_work, qla_heartbeat_work_fn); + + /* Set up the irqs */ + ret = qla2x00_request_irqs(ha, rsp); +@@ -7103,17 +7114,6 @@ qla2x00_do_dpc(void *data) + qla2x00_lip_reset(base_vha); + } + +- if (test_bit(HEARTBEAT_CHK, &base_vha->dpc_flags)) { +- /* +- * if there is a mb in progress then that's +- * enough of a check to see if fw is still ticking. +- */ +- if (!ha->flags.mbox_busy && base_vha->flags.init_done) +- qla_no_op_mb(base_vha); +- +- clear_bit(HEARTBEAT_CHK, &base_vha->dpc_flags); +- } +- + ha->dpc_active = 0; + end_loop: + set_current_state(TASK_INTERRUPTIBLE); +@@ -7172,57 +7172,51 @@ qla2x00_rst_aen(scsi_qla_host_t *vha) + + static bool qla_do_heartbeat(struct scsi_qla_host *vha) + { +- u64 cmd_cnt, prev_cmd_cnt; +- bool do_hb = false; + struct qla_hw_data *ha = vha->hw; +- int i; ++ u32 cmpl_cnt; ++ u16 i; ++ bool do_heartbeat = false; + +- /* if cmds are still pending down in fw, then do hb */ +- if (ha->base_qpair->cmd_cnt != ha->base_qpair->cmd_completion_cnt) { +- do_hb = true; ++ /* ++ * Allow do_heartbeat only if we don’t have any active interrupts, ++ * but there are still IOs outstanding with firmware. ++ */ ++ cmpl_cnt = ha->base_qpair->cmd_completion_cnt; ++ if (cmpl_cnt == ha->base_qpair->prev_completion_cnt && ++ cmpl_cnt != ha->base_qpair->cmd_cnt) { ++ do_heartbeat = true; + goto skip; + } ++ ha->base_qpair->prev_completion_cnt = cmpl_cnt; + + for (i = 0; i < ha->max_qpairs; i++) { +- if (ha->queue_pair_map[i] && +- ha->queue_pair_map[i]->cmd_cnt != +- ha->queue_pair_map[i]->cmd_completion_cnt) { +- do_hb = true; +- break; ++ if (ha->queue_pair_map[i]) { ++ cmpl_cnt = ha->queue_pair_map[i]->cmd_completion_cnt; ++ if (cmpl_cnt == ha->queue_pair_map[i]->prev_completion_cnt && ++ cmpl_cnt != ha->queue_pair_map[i]->cmd_cnt) { ++ do_heartbeat = true; ++ break; ++ } ++ ha->queue_pair_map[i]->prev_completion_cnt = cmpl_cnt; + } + } + + skip: +- prev_cmd_cnt = ha->prev_cmd_cnt; +- cmd_cnt = ha->base_qpair->cmd_cnt; +- for (i = 0; i < ha->max_qpairs; i++) { +- if (ha->queue_pair_map[i]) +- cmd_cnt += ha->queue_pair_map[i]->cmd_cnt; +- } +- ha->prev_cmd_cnt = cmd_cnt; +- +- if (!do_hb && ((cmd_cnt - prev_cmd_cnt) > 50)) +- /* +- * IOs are completing before periodic hb check. +- * IOs seems to be running, do hb for sanity check. +- */ +- do_hb = true; +- +- return do_hb; ++ return do_heartbeat; + } + + static void qla_heart_beat(struct scsi_qla_host *vha) + { ++ struct qla_hw_data *ha = vha->hw; ++ + if (vha->vp_idx) + return; + + if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha)) + return; + +- if (qla_do_heartbeat(vha)) { +- set_bit(HEARTBEAT_CHK, &vha->dpc_flags); +- qla2xxx_wake_dpc(vha); +- } ++ if (qla_do_heartbeat(vha)) ++ queue_work(ha->wq, &ha->heartbeat_work); + } + + /************************************************************************** +-- +2.35.1 + diff --git a/queue-5.15/serial-8250_mtk-make-sure-to-select-the-right-featur.patch b/queue-5.15/serial-8250_mtk-make-sure-to-select-the-right-featur.patch new file mode 100644 index 00000000000..62ec8d55742 --- /dev/null +++ b/queue-5.15/serial-8250_mtk-make-sure-to-select-the-right-featur.patch @@ -0,0 +1,50 @@ +From e542f7f58f6a46e18587ecd4bfe0488c19596b25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Apr 2022 15:23:27 +0200 +Subject: serial: 8250_mtk: Make sure to select the right FEATURE_SEL + +From: AngeloGioacchino Del Regno + +[ Upstream commit 6f81fdded0d024c7d4084d434764f30bca1cd6b1 ] + +Set the FEATURE_SEL at probe time to make sure that BIT(0) is enabled: +this guarantees that when the port is configured as AP UART, the +right register layout is interpreted by the UART IP. + +Signed-off-by: AngeloGioacchino Del Regno +Cc: stable +Link: https://lore.kernel.org/r/20220427132328.228297-3-angelogioacchino.delregno@collabora.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/8250/8250_mtk.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c +index de48a58460f4..de57f47635cd 100644 +--- a/drivers/tty/serial/8250/8250_mtk.c ++++ b/drivers/tty/serial/8250/8250_mtk.c +@@ -57,6 +57,9 @@ + #define MTK_UART_XON1 40 /* I/O: Xon character 1 */ + #define MTK_UART_XOFF1 42 /* I/O: Xoff character 1 */ + ++#define MTK_UART_FEATURE_SEL 39 /* Feature Selection register */ ++#define MTK_UART_FEAT_NEWRMAP BIT(0) /* Use new register map */ ++ + #ifdef CONFIG_SERIAL_8250_DMA + enum dma_rx_status { + DMA_RX_START = 0, +@@ -572,6 +575,10 @@ static int mtk8250_probe(struct platform_device *pdev) + uart.dma = data->dma; + #endif + ++ /* Set AP UART new register map */ ++ writel(MTK_UART_FEAT_NEWRMAP, uart.port.membase + ++ (MTK_UART_FEATURE_SEL << uart.port.regshift)); ++ + /* Disable Rate Fix function */ + writel(0x0, uart.port.membase + + (MTK_UART_RATE_FIX << uart.port.regshift)); +-- +2.35.1 + diff --git a/queue-5.15/serial-sc16is7xx-clear-rs485-bits-in-the-shutdown.patch b/queue-5.15/serial-sc16is7xx-clear-rs485-bits-in-the-shutdown.patch new file mode 100644 index 00000000000..d6dd94f3c21 --- /dev/null +++ b/queue-5.15/serial-sc16is7xx-clear-rs485-bits-in-the-shutdown.patch @@ -0,0 +1,48 @@ +From fbaa1f49ecb52375abe09e7f9259ff49d9483c40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Mar 2022 19:00:42 +0800 +Subject: serial: sc16is7xx: Clear RS485 bits in the shutdown + +From: Hui Wang + +[ Upstream commit 927728a34f11b5a27f4610bdb7068317d6fdc72a ] + +We tested RS485 function on an EVB which has SC16IS752, after +finishing the test, we started the RS232 function test, but found the +RTS is still working in the RS485 mode. + +That is because both startup and shutdown call port_update() to set +the EFCR_REG, this will not clear the RS485 bits once the bits are set +in the reconf_rs485(). To fix it, clear the RS485 bits in shutdown. + +Cc: +Signed-off-by: Hui Wang +Link: https://lore.kernel.org/r/20220308110042.108451-1-hui.wang@canonical.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/sc16is7xx.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c +index 0ab788058fa2..e98aa7b97cc5 100644 +--- a/drivers/tty/serial/sc16is7xx.c ++++ b/drivers/tty/serial/sc16is7xx.c +@@ -1055,10 +1055,12 @@ static void sc16is7xx_shutdown(struct uart_port *port) + + /* Disable all interrupts */ + sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); +- /* Disable TX/RX */ ++ /* Disable TX/RX, clear auto RS485 and RTS invert */ + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, + SC16IS7XX_EFCR_RXDISABLE_BIT | +- SC16IS7XX_EFCR_TXDISABLE_BIT, ++ SC16IS7XX_EFCR_TXDISABLE_BIT | ++ SC16IS7XX_EFCR_AUTO_RS485_BIT | ++ SC16IS7XX_EFCR_RTS_INVERT_BIT, + SC16IS7XX_EFCR_RXDISABLE_BIT | + SC16IS7XX_EFCR_TXDISABLE_BIT); + +-- +2.35.1 + diff --git a/queue-5.15/series b/queue-5.15/series index 21f74d664ca..b720e62ec0d 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -17,3 +17,145 @@ usbnet-fix-memory-leak-in-error-case.patch net-rose-fix-uaf-bug-caused-by-rose_t0timer_expiry.patch netfilter-nft_set_pipapo-release-elements-in-clone-from-abort-path.patch netfilter-nf_tables-stricter-validation-of-element-data.patch +btrfs-rename-btrfs_alloc_chunk-to-btrfs_create_chunk.patch +btrfs-add-additional-parameters-to-btrfs_init_tree_r.patch +btrfs-fix-invalid-delayed-ref-after-subvolume-creati.patch +btrfs-fix-warning-when-freeing-leaf-after-subvolume-.patch +input-cpcap-pwrbutton-handle-errors-from-platform_ge.patch +input-goodix-change-goodix_i2c_write-len-parameter-t.patch +input-goodix-add-a-goodix.h-header-file.patch +input-goodix-refactor-reset-handling.patch +input-goodix-try-not-to-touch-the-reset-pin-on-x86-a.patch +dma-buf-poll-get-a-file-reference-for-outstanding-fe.patch +btrfs-fix-deadlock-between-chunk-allocation-and-chun.patch +drm-i915-disable-bonding-on-gen12-platforms.patch +drm-i915-gt-register-the-migrate-contexts-with-their.patch +drm-i915-replace-the-unconditional-clflush-with-drm_.patch +pci-portdrv-rename-pm_iter-to-pcie_port_device_iter.patch +pci-pciehp-ignore-link-down-up-caused-by-error-induc.patch +media-ir_toy-prevent-device-from-hanging-during-tran.patch +memory-renesas-rpc-if-avoid-unaligned-bus-access-for.patch +ath11k-add-hw_param-for-wakeup_mhi.patch +qed-improve-the-stack-space-of-filter_config.patch +platform-x86-wmi-introduce-helper-to-convert-driver-.patch +platform-x86-wmi-replace-read_takes_no_args-with-a-f.patch +platform-x86-wmi-fix-driver-notify-vs-probe-race.patch +mt76-mt7921-get-rid-of-mt7921_mac_set_beacon_filter.patch +mt76-mt7921-introduce-mt7921_mcu_set_beacon_filter-u.patch +mt76-mt7921-fix-a-possible-race-enabling-disabling-r.patch +bpf-arm64-use-emit_addr_mov_i64-for-bpf_pseudo_func.patch +riscv-defconfig-enable-drm_nouveau.patch +risc-v-defconfigs-set-config_fb-y-for-fb-console.patch +net-mlx5e-check-action-fwd-drop-flag-exists-also-for.patch +net-mlx5e-split-actions_match_supported-into-a-sub-f.patch +net-mlx5e-tc-reject-rules-with-drop-and-modify-hdr-a.patch +net-mlx5e-tc-reject-rules-with-forward-and-drop-acti.patch +asoc-rt5682-avoid-the-unexpected-irq-event-during-go.patch +asoc-rt5682-re-detect-the-combo-jack-after-resuming.patch +asoc-rt5682-fix-deadlock-on-resume.patch +netfilter-nf_tables-convert-pktinfo-tprot_set-to-fla.patch +netfilter-nft_payload-support-for-inner-header-match.patch +netfilter-nft_payload-don-t-allow-th-access-for-frag.patch +drm-mediatek-mtk_dsi-avoid-eprobe_defer-loop-with-ex.patch +s390-boot-allocate-amode31-section-in-decompressor.patch +s390-setup-use-physical-pointers-for-memblock_reserv.patch +s390-setup-preserve-memory-at-oldmem_base-and-oldmem.patch +ibmvnic-init-init_done_rc-earlier.patch +ibmvnic-clear-fop-when-retrying-probe.patch +ibmvnic-allow-queueing-resets-during-probe.patch +virtio-blk-avoid-preallocating-big-sgl-for-data.patch +io_uring-ensure-that-fsnotify-is-always-called.patch +block-use-bdev_get_queue-in-bio.c.patch +block-only-mark-bio-as-tracked-if-it-really-is-track.patch +block-fix-rq-qos-breakage-from-skipping-rq_qos_done_.patch +stddef-introduce-struct_group-helper-macro.patch +media-omap3isp-use-struct_group-for-memcpy-region.patch +media-davinci-vpif-fix-use-after-free-on-driver-unbi.patch +mt76-mt76_connac-fix-mcu_ce_cmd_set_roc-definition-e.patch +mt76-mt7921-do-not-always-disable-fw-runtime-pm.patch +cxl-port-hold-port-reference-until-decoder-release.patch +clk-renesas-r9a07g044-update-multiplier-and-divider-.patch +kvm-x86-mmu-use-yield-safe-tdp-mmu-root-iter-in-mmu-.patch +kvm-x86-mmu-use-common-tdp-mmu-zap-helper-for-mmu-no.patch +scsi-qla2xxx-move-heartbeat-handling-from-dpc-thread.patch +scsi-qla2xxx-fix-laggy-fc-remote-port-session-recove.patch +scsi-qla2xxx-edif-replace-list_for_each_safe-with-li.patch +scsi-qla2xxx-fix-crash-during-module-load-unload-tes.patch +gfs2-fix-gfs2_file_buffered_write-endless-loop-worka.patch +vdpa-mlx5-avoid-processing-works-if-workqueue-was-de.patch +btrfs-handle-device-lookup-with-btrfs_dev_lookup_arg.patch +btrfs-add-a-btrfs_get_dev_args_from_path-helper.patch +btrfs-use-btrfs_get_dev_args_from_path-in-dev-remova.patch +btrfs-remove-device-item-and-update-super-block-in-t.patch +drbd-add-error-handling-support-for-add_disk.patch +drbd-fix-double-free-problem-in-drbd_create_device.patch +drbd-fix-an-invalid-memory-access-caused-by-incorrec.patch +drm-amd-display-set-min-dcfclk-if-pipe-count-is-0.patch +drm-amd-display-fix-by-adding-fpu-protection-for-dcn.patch +nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch +nfsd-commit-operations-must-not-return-nfs-err_inval.patch +riscv-mm-add-xip_fixup-for-riscv_pfn_base.patch +iio-accel-mma8452-use-the-correct-logic-to-get-mma84.patch +batman-adv-use-netif_rx.patch +mtd-spi-nor-skip-erase-logic-when-spi_nor_no_erase-i.patch +compiler-attributes-add-__alloc_size-for-better-boun.patch +mm-vmalloc-introduce-array-allocation-functions.patch +kvm-use-__vcalloc-for-very-large-allocations.patch +btrfs-don-t-access-possibly-stale-fs_info-data-in-de.patch +kvm-s390x-fix-sck-locking.patch +scsi-qla2xxx-fix-loss-of-nvme-namespaces-after-drive.patch +powerpc-32-don-t-use-lmw-stmw-for-saving-restoring-n.patch +powerpc-flexible-gpr-range-save-restore-macros.patch +powerpc-tm-fix-more-userspace-r13-corruption.patch +serial-sc16is7xx-clear-rs485-bits-in-the-shutdown.patch +bus-mhi-core-use-correctly-sized-arguments-for-bit-f.patch +bus-mhi-fix-pm_state-conversion-to-string.patch +stddef-introduce-declare_flex_array-helper.patch +uapi-linux-stddef.h-add-include-guards.patch +asoc-rt5682-move-clk-related-code-to-rt5682_i2c_prob.patch +asoc-rt5682-fix-an-incorrect-null-check-on-list-iter.patch +drm-amd-vcn-fix-an-error-msg-on-vcn-3.0.patch +kvm-don-t-create-vm-debugfs-files-outside-of-the-vm-.patch +tty-n_gsm-modify-cr-pf-bit-when-config-requester.patch +tty-n_gsm-save-dlci-address-open-status-when-config-.patch +tty-n_gsm-fix-frame-reception-handling.patch +alsa-usb-audio-add-mapping-for-msi-mpg-x570s-carbon-.patch +alsa-usb-audio-add-mapping-for-msi-mag-x570s-torpedo.patch +tty-n_gsm-fix-missing-update-of-modem-controls-after.patch +btrfs-zoned-encapsulate-inode-locking-for-zoned-relo.patch +btrfs-zoned-use-dedicated-lock-for-data-relocation.patch +kvm-initialize-debugfs_dentry-when-a-vm-is-created-t.patch +mm-hwpoison-mf_mutex-for-soft-offline-and-unpoison.patch +mm-hwpoison-avoid-the-impact-of-hwpoison_filter-retu.patch +mm-memory-failure.c-fix-race-with-changing-page-comp.patch +mm-hwpoison-fix-race-between-hugetlb-free-demotion-a.patch +tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch +tty-n_gsm-fix-sometimes-uninitialized-warning-in-gsm.patch +powerpc-vdso-remove-cvdso_call_time-macro.patch +powerpc-vdso-move-cvdso_call-macro-into-gettimeofday.patch +powerpc-vdso-fix-incorrect-cfi-in-gettimeofday.s.patch +serial-8250_mtk-make-sure-to-select-the-right-featur.patch +tty-n_gsm-fix-invalid-gsmtty_write_room-result.patch +drm-amdgpu-bind-to-any-0x1002-pci-diplay-class-devic.patch +drm-amdgpu-fix-rejecting-tahiti-gpus.patch +drm-amdgpu-drop-flags-check-for-chip_ip_discovery.patch +drm-amd-refactor-amdgpu_aspm-to-be-evaluated-per-dev.patch +drm-amdgpu-vi-disable-aspm-on-intel-alder-lake-based.patch +drm-i915-fix-a-race-between-vma-object-destruction-a.patch +drm-mediatek-use-mailbox-rx_callback-instead-of-cmdq.patch +drm-mediatek-remove-the-pointer-of-struct-cmdq_clien.patch +drm-mediatek-detect-cmdq-execution-timeout.patch +drm-mediatek-add-cmdq_handle-in-mtk_crtc.patch +drm-mediatek-add-vblank-register-unregister-callback.patch +drm-msm-dp-employ-bridge-mechanism-for-display-enabl.patch +drm-msm-dp-fix-double-free-on-error-in-msm_dp_bridge.patch +drm-msm-properly-add-and-remove-internal-bridges.patch +bluetooth-protect-le-accept-and-resolv-lists-with-hd.patch +bluetooth-btmtksdio-fix-use-after-free-at-btmtksdio_.patch +io_uring-avoid-io-wq-eagain-looping-for-iopoll.patch +irqchip-gic-v3-ensure-pseudo-nmis-have-an-isb-betwee.patch +rxrpc-fix-locking-issue.patch +dt-bindings-soc-qcom-smd-rpm-add-compatible-for-msm8.patch +dt-bindings-soc-qcom-smd-rpm-fix-missing-msm8936-com.patch +module-change-to-print-useful-messages-from-elf_vali.patch +module-fix-e_shstrndx-.sh_size-0-oob-access.patch diff --git a/queue-5.15/stddef-introduce-declare_flex_array-helper.patch b/queue-5.15/stddef-introduce-declare_flex_array-helper.patch new file mode 100644 index 00000000000..ed580918f94 --- /dev/null +++ b/queue-5.15/stddef-introduce-declare_flex_array-helper.patch @@ -0,0 +1,155 @@ +From f387f204fd79d9ddb2e48d62eb9aa8d94da222e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Aug 2021 11:21:23 -0700 +Subject: stddef: Introduce DECLARE_FLEX_ARRAY() helper + +From: Kees Cook + +[ Upstream commit 3080ea5553cc909b000d1f1d964a9041962f2c5b ] + +There are many places where kernel code wants to have several different +typed trailing flexible arrays. This would normally be done with multiple +flexible arrays in a union, but since GCC and Clang don't (on the surface) +allow this, there have been many open-coded workarounds, usually involving +neighboring 0-element arrays at the end of a structure. For example, +instead of something like this: + +struct thing { + ... + union { + struct type1 foo[]; + struct type2 bar[]; + }; +}; + +code works around the compiler with: + +struct thing { + ... + struct type1 foo[0]; + struct type2 bar[]; +}; + +Another case is when a flexible array is wanted as the single member +within a struct (which itself is usually in a union). For example, this +would be worked around as: + +union many { + ... + struct { + struct type3 baz[0]; + }; +}; + +These kinds of work-arounds cause problems with size checks against such +zero-element arrays (for example when building with -Warray-bounds and +-Wzero-length-bounds, and with the coming FORTIFY_SOURCE improvements), +so they must all be converted to "real" flexible arrays, avoiding warnings +like this: + +fs/hpfs/anode.c: In function 'hpfs_add_sector_to_btree': +fs/hpfs/anode.c:209:27: warning: array subscript 0 is outside the bounds of an interior zero-length array 'struct bplus_internal_node[0]' [-Wzero-length-bounds] + 209 | anode->btree.u.internal[0].down = cpu_to_le32(a); + | ~~~~~~~~~~~~~~~~~~~~~~~^~~ +In file included from fs/hpfs/hpfs_fn.h:26, + from fs/hpfs/anode.c:10: +fs/hpfs/hpfs.h:412:32: note: while referencing 'internal' + 412 | struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving + | ^~~~~~~~ + +drivers/net/can/usb/etas_es58x/es58x_fd.c: In function 'es58x_fd_tx_can_msg': +drivers/net/can/usb/etas_es58x/es58x_fd.c:360:35: warning: array subscript 65535 is outside the bounds of an interior zero-length array 'u8[0]' {aka 'unsigned char[]'} [-Wzero-length-bounds] + 360 | tx_can_msg = (typeof(tx_can_msg))&es58x_fd_urb_cmd->raw_msg[msg_len]; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In file included from drivers/net/can/usb/etas_es58x/es58x_core.h:22, + from drivers/net/can/usb/etas_es58x/es58x_fd.c:17: +drivers/net/can/usb/etas_es58x/es58x_fd.h:231:6: note: while referencing 'raw_msg' + 231 | u8 raw_msg[0]; + | ^~~~~~~ + +However, it _is_ entirely possible to have one or more flexible arrays +in a struct or union: it just has to be in another struct. And since it +cannot be alone in a struct, such a struct must have at least 1 other +named member -- but that member can be zero sized. Wrap all this nonsense +into the new DECLARE_FLEX_ARRAY() in support of having flexible arrays +in unions (or alone in a struct). + +As with struct_group(), since this is needed in UAPI headers as well, +implement the core there, with a non-UAPI wrapper. + +Additionally update kernel-doc to understand its existence. + +https://github.com/KSPP/linux/issues/137 + +Cc: Arnd Bergmann +Cc: "Gustavo A. R. Silva" +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + include/linux/stddef.h | 13 +++++++++++++ + include/uapi/linux/stddef.h | 16 ++++++++++++++++ + scripts/kernel-doc | 2 ++ + 3 files changed, 31 insertions(+) + +diff --git a/include/linux/stddef.h b/include/linux/stddef.h +index 938216f8ab7e..31fdbb784c24 100644 +--- a/include/linux/stddef.h ++++ b/include/linux/stddef.h +@@ -84,4 +84,17 @@ enum { + #define struct_group_tagged(TAG, NAME, MEMBERS...) \ + __struct_group(TAG, NAME, /* no attrs */, MEMBERS) + ++/** ++ * DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union ++ * ++ * @TYPE: The type of each flexible array element ++ * @NAME: The name of the flexible array member ++ * ++ * In order to have a flexible array member in a union or alone in a ++ * struct, it needs to be wrapped in an anonymous struct with at least 1 ++ * named member, but that member can be empty. ++ */ ++#define DECLARE_FLEX_ARRAY(TYPE, NAME) \ ++ __DECLARE_FLEX_ARRAY(TYPE, NAME) ++ + #endif +diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h +index 610204f7c275..3021ea25a284 100644 +--- a/include/uapi/linux/stddef.h ++++ b/include/uapi/linux/stddef.h +@@ -25,3 +25,19 @@ + struct { MEMBERS } ATTRS; \ + struct TAG { MEMBERS } ATTRS NAME; \ + } ++ ++/** ++ * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union ++ * ++ * @TYPE: The type of each flexible array element ++ * @NAME: The name of the flexible array member ++ * ++ * In order to have a flexible array member in a union or alone in a ++ * struct, it needs to be wrapped in an anonymous struct with at least 1 ++ * named member, but that member can be empty. ++ */ ++#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \ ++ struct { \ ++ struct { } __empty_ ## NAME; \ ++ TYPE NAME[]; \ ++ } +diff --git a/scripts/kernel-doc b/scripts/kernel-doc +index 38aa799a776c..5d54b57ff90c 100755 +--- a/scripts/kernel-doc ++++ b/scripts/kernel-doc +@@ -1263,6 +1263,8 @@ sub dump_struct($$) { + $members =~ s/DECLARE_KFIFO\s*\($args,\s*$args,\s*$args\)/$2 \*$1/gos; + # replace DECLARE_KFIFO_PTR + $members =~ s/DECLARE_KFIFO_PTR\s*\($args,\s*$args\)/$2 \*$1/gos; ++ # replace DECLARE_FLEX_ARRAY ++ $members =~ s/(?:__)?DECLARE_FLEX_ARRAY\s*\($args,\s*$args\)/$1 $2\[\]/gos; + my $declaration = $members; + + # Split nested struct/union elements as newer ones +-- +2.35.1 + diff --git a/queue-5.15/stddef-introduce-struct_group-helper-macro.patch b/queue-5.15/stddef-introduce-struct_group-helper-macro.patch new file mode 100644 index 00000000000..9a57509f2b3 --- /dev/null +++ b/queue-5.15/stddef-introduce-struct_group-helper-macro.patch @@ -0,0 +1,261 @@ +From 553ceca024d425f94b68e9a132423f8eb3fb7081 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 May 2021 20:01:15 -0700 +Subject: stddef: Introduce struct_group() helper macro + +From: Kees Cook + +[ Upstream commit 50d7bd38c3aafc4749e05e8d7fcb616979143602 ] + +Kernel code has a regular need to describe groups of members within a +structure usually when they need to be copied or initialized separately +from the rest of the surrounding structure. The generally accepted design +pattern in C is to use a named sub-struct: + + struct foo { + int one; + struct { + int two; + int three, four; + } thing; + int five; + }; + +This would allow for traditional references and sizing: + + memcpy(&dst.thing, &src.thing, sizeof(dst.thing)); + +However, doing this would mean that referencing struct members enclosed +by such named structs would always require including the sub-struct name +in identifiers: + + do_something(dst.thing.three); + +This has tended to be quite inflexible, especially when such groupings +need to be added to established code which causes huge naming churn. +Three workarounds exist in the kernel for this problem, and each have +other negative properties. + +To avoid the naming churn, there is a design pattern of adding macro +aliases for the named struct: + + #define f_three thing.three + +This ends up polluting the global namespace, and makes it difficult to +search for identifiers. + +Another common work-around in kernel code avoids the pollution by avoiding +the named struct entirely, instead identifying the group's boundaries using +either a pair of empty anonymous structs of a pair of zero-element arrays: + + struct foo { + int one; + struct { } start; + int two; + int three, four; + struct { } finish; + int five; + }; + + struct foo { + int one; + int start[0]; + int two; + int three, four; + int finish[0]; + int five; + }; + +This allows code to avoid needing to use a sub-struct named for member +references within the surrounding structure, but loses the benefits of +being able to actually use such a struct, making it rather fragile. Using +these requires open-coded calculation of sizes and offsets. The efforts +made to avoid common mistakes include lots of comments, or adding various +BUILD_BUG_ON()s. Such code is left with no way for the compiler to reason +about the boundaries (e.g. the "start" object looks like it's 0 bytes +in length), making bounds checking depend on open-coded calculations: + + if (length > offsetof(struct foo, finish) - + offsetof(struct foo, start)) + return -EINVAL; + memcpy(&dst.start, &src.start, offsetof(struct foo, finish) - + offsetof(struct foo, start)); + +However, the vast majority of places in the kernel that operate on +groups of members do so without any identification of the grouping, +relying either on comments or implicit knowledge of the struct contents, +which is even harder for the compiler to reason about, and results in +even more fragile manual sizing, usually depending on member locations +outside of the region (e.g. to copy "two" and "three", use the start of +"four" to find the size): + + BUILD_BUG_ON((offsetof(struct foo, four) < + offsetof(struct foo, two)) || + (offsetof(struct foo, four) < + offsetof(struct foo, three)); + if (length > offsetof(struct foo, four) - + offsetof(struct foo, two)) + return -EINVAL; + memcpy(&dst.two, &src.two, length); + +In order to have a regular programmatic way to describe a struct +region that can be used for references and sizing, can be examined for +bounds checking, avoids forcing the use of intermediate identifiers, +and avoids polluting the global namespace, introduce the struct_group() +macro. This macro wraps the member declarations to create an anonymous +union of an anonymous struct (no intermediate name) and a named struct +(for references and sizing): + + struct foo { + int one; + struct_group(thing, + int two; + int three, four; + ); + int five; + }; + + if (length > sizeof(src.thing)) + return -EINVAL; + memcpy(&dst.thing, &src.thing, length); + do_something(dst.three); + +There are some rare cases where the resulting struct_group() needs +attributes added, so struct_group_attr() is also introduced to allow +for specifying struct attributes (e.g. __align(x) or __packed). +Additionally, there are places where such declarations would like to +have the struct be tagged, so struct_group_tagged() is added. + +Given there is a need for a handful of UAPI uses too, the underlying +__struct_group() macro has been defined in UAPI so it can be used there +too. + +To avoid confusing scripts/kernel-doc, hide the macro from its struct +parsing. + +Co-developed-by: Keith Packard +Signed-off-by: Keith Packard +Acked-by: Gustavo A. R. Silva +Link: https://lore.kernel.org/lkml/20210728023217.GC35706@embeddedor +Enhanced-by: Rasmus Villemoes +Link: https://lore.kernel.org/lkml/41183a98-bdb9-4ad6-7eab-5a7292a6df84@rasmusvillemoes.dk +Enhanced-by: Dan Williams +Link: https://lore.kernel.org/lkml/1d9a2e6df2a9a35b2cdd50a9a68cac5991e7e5f0.camel@intel.com +Enhanced-by: Daniel Vetter +Link: https://lore.kernel.org/lkml/YQKa76A6XuFqgM03@phenom.ffwll.local +Acked-by: Dan Williams +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + include/linux/stddef.h | 48 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/stddef.h | 21 ++++++++++++++++ + scripts/kernel-doc | 7 ++++++ + 3 files changed, 76 insertions(+) + +diff --git a/include/linux/stddef.h b/include/linux/stddef.h +index 998a4ba28eba..938216f8ab7e 100644 +--- a/include/linux/stddef.h ++++ b/include/linux/stddef.h +@@ -36,4 +36,52 @@ enum { + #define offsetofend(TYPE, MEMBER) \ + (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER)) + ++/** ++ * struct_group() - Wrap a set of declarations in a mirrored struct ++ * ++ * @NAME: The identifier name of the mirrored sub-struct ++ * @MEMBERS: The member declarations for the mirrored structs ++ * ++ * Used to create an anonymous union of two structs with identical ++ * layout and size: one anonymous and one named. The former can be ++ * used normally without sub-struct naming, and the latter can be ++ * used to reason about the start, end, and size of the group of ++ * struct members. ++ */ ++#define struct_group(NAME, MEMBERS...) \ ++ __struct_group(/* no tag */, NAME, /* no attrs */, MEMBERS) ++ ++/** ++ * struct_group_attr() - Create a struct_group() with trailing attributes ++ * ++ * @NAME: The identifier name of the mirrored sub-struct ++ * @ATTRS: Any struct attributes to apply ++ * @MEMBERS: The member declarations for the mirrored structs ++ * ++ * Used to create an anonymous union of two structs with identical ++ * layout and size: one anonymous and one named. The former can be ++ * used normally without sub-struct naming, and the latter can be ++ * used to reason about the start, end, and size of the group of ++ * struct members. Includes structure attributes argument. ++ */ ++#define struct_group_attr(NAME, ATTRS, MEMBERS...) \ ++ __struct_group(/* no tag */, NAME, ATTRS, MEMBERS) ++ ++/** ++ * struct_group_tagged() - Create a struct_group with a reusable tag ++ * ++ * @TAG: The tag name for the named sub-struct ++ * @NAME: The identifier name of the mirrored sub-struct ++ * @MEMBERS: The member declarations for the mirrored structs ++ * ++ * Used to create an anonymous union of two structs with identical ++ * layout and size: one anonymous and one named. The former can be ++ * used normally without sub-struct naming, and the latter can be ++ * used to reason about the start, end, and size of the group of ++ * struct members. Includes struct tag argument for the named copy, ++ * so the specified layout can be reused later. ++ */ ++#define struct_group_tagged(TAG, NAME, MEMBERS...) \ ++ __struct_group(TAG, NAME, /* no attrs */, MEMBERS) ++ + #endif +diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h +index ee8220f8dcf5..610204f7c275 100644 +--- a/include/uapi/linux/stddef.h ++++ b/include/uapi/linux/stddef.h +@@ -4,3 +4,24 @@ + #ifndef __always_inline + #define __always_inline inline + #endif ++ ++/** ++ * __struct_group() - Create a mirrored named and anonyomous struct ++ * ++ * @TAG: The tag name for the named sub-struct (usually empty) ++ * @NAME: The identifier name of the mirrored sub-struct ++ * @ATTRS: Any struct attributes (usually empty) ++ * @MEMBERS: The member declarations for the mirrored structs ++ * ++ * Used to create an anonymous union of two structs with identical layout ++ * and size: one anonymous and one named. The former's members can be used ++ * normally without sub-struct naming, and the latter can be used to ++ * reason about the start, end, and size of the group of struct members. ++ * The named struct can also be explicitly tagged for layer reuse, as well ++ * as both having struct attributes appended. ++ */ ++#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \ ++ union { \ ++ struct { MEMBERS } ATTRS; \ ++ struct TAG { MEMBERS } ATTRS NAME; \ ++ } +diff --git a/scripts/kernel-doc b/scripts/kernel-doc +index cfcb60737957..38aa799a776c 100755 +--- a/scripts/kernel-doc ++++ b/scripts/kernel-doc +@@ -1245,6 +1245,13 @@ sub dump_struct($$) { + $members =~ s/\s*CRYPTO_MINALIGN_ATTR/ /gos; + $members =~ s/\s*____cacheline_aligned_in_smp/ /gos; + $members =~ s/\s*____cacheline_aligned/ /gos; ++ # unwrap struct_group(): ++ # - first eat non-declaration parameters and rewrite for final match ++ # - then remove macro, outer parens, and trailing semicolon ++ $members =~ s/\bstruct_group\s*\(([^,]*,)/STRUCT_GROUP(/gos; ++ $members =~ s/\bstruct_group_(attr|tagged)\s*\(([^,]*,){2}/STRUCT_GROUP(/gos; ++ $members =~ s/\b__struct_group\s*\(([^,]*,){3}/STRUCT_GROUP(/gos; ++ $members =~ s/\bSTRUCT_GROUP(\(((?:(?>[^)(]+)|(?1))*)\))[^;]*;/$2/gos; + + my $args = qr{([^,)]+)}; + # replace DECLARE_BITMAP +-- +2.35.1 + diff --git a/queue-5.15/tty-n_gsm-fix-frame-reception-handling.patch b/queue-5.15/tty-n_gsm-fix-frame-reception-handling.patch new file mode 100644 index 00000000000..2e39cd1f299 --- /dev/null +++ b/queue-5.15/tty-n_gsm-fix-frame-reception-handling.patch @@ -0,0 +1,123 @@ +From 7409b51bf34ae44c47a07b1531c801b5ba167121 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 14 Apr 2022 02:42:11 -0700 +Subject: tty: n_gsm: fix frame reception handling + +From: Daniel Starke + +[ Upstream commit 7a0e4b1733b635026a87c023f6d703faf0095e39 ] + +The frame checksum (FCS) is currently handled in gsm_queue() after +reception of a frame. However, this breaks layering. A workaround with +'received_fcs' was implemented so far. +Furthermore, frames are handled as such even if no end flag was received. +Move FCS calculation from gsm_queue() to gsm0_receive() and gsm1_receive(). +Also delay gsm_queue() call there until a full frame was received to fix +both points. + +Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Starke +Link: https://lore.kernel.org/r/20220414094225.4527-6-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/n_gsm.c | 53 +++++++++++++++++++++++++-------------------- + 1 file changed, 30 insertions(+), 23 deletions(-) + +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index 3038e5631be5..d3d5308daf35 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -221,7 +221,6 @@ struct gsm_mux { + int encoding; + u8 control; + u8 fcs; +- u8 received_fcs; + u8 *txframe; /* TX framing buffer */ + + /* Method for the receiver side */ +@@ -1799,18 +1798,7 @@ static void gsm_queue(struct gsm_mux *gsm) + u8 cr; + int address; + int i, j, k, address_tmp; +- /* We have to sneak a look at the packet body to do the FCS. +- A somewhat layering violation in the spec */ + +- if ((gsm->control & ~PF) == UI) +- gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len); +- if (gsm->encoding == 0) { +- /* WARNING: gsm->received_fcs is used for +- gsm->encoding = 0 only. +- In this case it contain the last piece of data +- required to generate final CRC */ +- gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); +- } + if (gsm->fcs != GOOD_FCS) { + gsm->bad_fcs++; + if (debug & 4) +@@ -1997,19 +1985,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) + break; + case GSM_DATA: /* Data */ + gsm->buf[gsm->count++] = c; +- if (gsm->count == gsm->len) ++ if (gsm->count == gsm->len) { ++ /* Calculate final FCS for UI frames over all data */ ++ if ((gsm->control & ~PF) != UIH) { ++ gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, ++ gsm->count); ++ } + gsm->state = GSM_FCS; ++ } + break; + case GSM_FCS: /* FCS follows the packet */ +- gsm->received_fcs = c; +- gsm_queue(gsm); ++ gsm->fcs = gsm_fcs_add(gsm->fcs, c); + gsm->state = GSM_SSOF; + break; + case GSM_SSOF: +- if (c == GSM0_SOF) { +- gsm->state = GSM_SEARCH; +- break; +- } ++ gsm->state = GSM_SEARCH; ++ if (c == GSM0_SOF) ++ gsm_queue(gsm); ++ else ++ gsm->bad_size++; + break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, gsm->state); +@@ -2038,11 +2032,24 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) + return; + } + if (c == GSM1_SOF) { +- /* EOF is only valid in frame if we have got to the data state +- and received at least one byte (the FCS) */ +- if (gsm->state == GSM_DATA && gsm->count) { +- /* Extract the FCS */ ++ /* EOF is only valid in frame if we have got to the data state */ ++ if (gsm->state == GSM_DATA) { ++ if (gsm->count < 1) { ++ /* Missing FSC */ ++ gsm->malformed++; ++ gsm->state = GSM_START; ++ return; ++ } ++ /* Remove the FCS from data */ + gsm->count--; ++ if ((gsm->control & ~PF) != UIH) { ++ /* Calculate final FCS for UI frames over all ++ * data but FCS ++ */ ++ gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, ++ gsm->count); ++ } ++ /* Add the FCS itself to test against GOOD_FCS */ + gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]); + gsm->len = gsm->count; + gsm_queue(gsm); +-- +2.35.1 + diff --git a/queue-5.15/tty-n_gsm-fix-invalid-gsmtty_write_room-result.patch b/queue-5.15/tty-n_gsm-fix-invalid-gsmtty_write_room-result.patch new file mode 100644 index 00000000000..5d58fd642bd --- /dev/null +++ b/queue-5.15/tty-n_gsm-fix-invalid-gsmtty_write_room-result.patch @@ -0,0 +1,70 @@ +From ac5b2e58dfe6e9c75456f9f1d3671c55137d4162 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 May 2022 10:17:33 +0200 +Subject: tty: n_gsm: fix invalid gsmtty_write_room() result + +From: Daniel Starke + +[ Upstream commit 9361ebfbb79fd1bc8594a487c01ad52cdaa391ea ] + +gsmtty_write() does not prevent the user to use the full fifo size of 4096 +bytes as allocated in gsm_dlci_alloc(). However, gsmtty_write_room() tries +to limit the return value by 'TX_SIZE' and returns a negative value if the +fifo has more than 'TX_SIZE' bytes stored. This is obviously wrong as +'TX_SIZE' is defined as 512. +Define 'TX_SIZE' to the fifo size and use it accordingly for allocation to +keep the current behavior. Return the correct remaining size of the fifo in +gsmtty_write_room() via kfifo_avail(). + +Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Starke +Link: https://lore.kernel.org/r/20220504081733.3494-3-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/n_gsm.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index fd4a86111a6e..4a430f6ca170 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -137,6 +137,7 @@ struct gsm_dlci { + int retries; + /* Uplink tty if active */ + struct tty_port port; /* The tty bound to this DLCI if there is one */ ++#define TX_SIZE 4096 /* Must be power of 2. */ + struct kfifo fifo; /* Queue fifo for the DLCI */ + int adaption; /* Adaption layer in use */ + int prev_adaption; +@@ -1758,7 +1759,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) + return NULL; + spin_lock_init(&dlci->lock); + mutex_init(&dlci->mutex); +- if (kfifo_alloc(&dlci->fifo, 4096, GFP_KERNEL) < 0) { ++ if (kfifo_alloc(&dlci->fifo, TX_SIZE, GFP_KERNEL) < 0) { + kfree(dlci); + return NULL; + } +@@ -3035,8 +3036,6 @@ static struct tty_ldisc_ops tty_ldisc_packet = { + * Virtual tty side + */ + +-#define TX_SIZE 512 +- + /** + * gsm_modem_upd_via_data - send modem bits via convergence layer + * @dlci: channel +@@ -3274,7 +3273,7 @@ static unsigned int gsmtty_write_room(struct tty_struct *tty) + struct gsm_dlci *dlci = tty->driver_data; + if (dlci->state == DLCI_CLOSED) + return 0; +- return TX_SIZE - kfifo_len(&dlci->fifo); ++ return kfifo_avail(&dlci->fifo); + } + + static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty) +-- +2.35.1 + diff --git a/queue-5.15/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch b/queue-5.15/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch new file mode 100644 index 00000000000..ab89390f795 --- /dev/null +++ b/queue-5.15/tty-n_gsm-fix-invalid-use-of-msc-in-advanced-option.patch @@ -0,0 +1,244 @@ +From 95fe37f5383e99f2e764fa8b3fae1a9a59714626 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 00:10:24 -0700 +Subject: tty: n_gsm: fix invalid use of MSC in advanced option + +From: Daniel Starke + +[ Upstream commit c19ffe00fed6bb423d81406d2a7e5793074c7d83 ] + +n_gsm is based on the 3GPP 07.010 and its newer version is the 3GPP 27.010. +See https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1516 +The changes from 07.010 to 27.010 are non-functional. Therefore, I refer to +the newer 27.010 here. Chapter 5.4.6.3.7 states that the Modem Status +Command (MSC) shall only be used if the basic option was chosen. +The current implementation uses MSC frames even if advanced option was +chosen to inform the peer about modem line state updates. A standard +conform peer may choose to discard these frames in advanced option mode. +Furthermore, gsmtty_modem_update() is not part of the 'tty_operations' +functions despite its name. +Rename gsmtty_modem_update() to gsm_modem_update() to clarify this. Split +its function into gsm_modem_upd_via_data() and gsm_modem_upd_via_msc() +depending on the encoding and adaption. Introduce gsm_dlci_modem_output() +as adaption of gsm_dlci_data_output() to encode and queue empty frames in +advanced option mode. Use it in gsm_modem_upd_via_data(). +gsm_modem_upd_via_msc() is based on the initial gsmtty_modem_update() +function which used only MSC frames to update modem states. + +Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Starke +Link: https://lore.kernel.org/r/20220422071025.5490-2-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/n_gsm.c | 125 +++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 117 insertions(+), 8 deletions(-) + +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index c52d5e0d5c6f..c8ca00fad8e4 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -371,7 +371,7 @@ static const u8 gsm_fcs8[256] = { + #define GOOD_FCS 0xCF + + static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len); +-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk); ++static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk); + + /** + * gsm_fcs_add - update FCS +@@ -928,6 +928,63 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, + return size; + } + ++/** ++ * gsm_dlci_modem_output - try and push modem status out of a DLCI ++ * @gsm: mux ++ * @dlci: the DLCI to pull modem status from ++ * @brk: break signal ++ * ++ * Push an empty frame in to the transmit queue to update the modem status ++ * bits and to transmit an optional break. ++ * ++ * Caller must hold the tx_lock of the mux. ++ */ ++ ++static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci, ++ u8 brk) ++{ ++ u8 *dp = NULL; ++ struct gsm_msg *msg; ++ int size; ++ ++ /* for modem bits without break data */ ++ if (dlci->adaption == 1) { ++ size = 0; ++ } else if (dlci->adaption == 2) { ++ size = 1; ++ if (brk > 0) ++ size++; ++ } else { ++ pr_err("%s: unsupported adaption %d\n", __func__, ++ dlci->adaption); ++ } ++ ++ msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); ++ if (!msg) { ++ pr_err("%s: gsm_data_alloc error", __func__); ++ return -ENOMEM; ++ } ++ dp = msg->data; ++ switch (dlci->adaption) { ++ case 1: /* Unstructured */ ++ break; ++ case 2: /* Unstructured with modem bits. */ ++ if (brk == 0) { ++ *dp++ = (gsm_encode_modem(dlci) << 1) | EA; ++ } else { ++ *dp++ = gsm_encode_modem(dlci) << 1; ++ *dp++ = (brk << 4) | 2 | EA; /* Length, Break, EA */ ++ } ++ break; ++ default: ++ /* Handled above */ ++ break; ++ } ++ ++ __gsm_data_queue(dlci, msg); ++ return size; ++} ++ + /** + * gsm_dlci_data_sweep - look for data to send + * @gsm: the GSM mux +@@ -1492,7 +1549,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) + pr_debug("DLCI %d goes open.\n", dlci->addr); + /* Send current modem state */ + if (dlci->addr) +- gsmtty_modem_update(dlci, 0); ++ gsm_modem_update(dlci, 0); + wake_up(&dlci->gsm->event); + } + +@@ -2977,12 +3034,43 @@ static struct tty_ldisc_ops tty_ldisc_packet = { + + #define TX_SIZE 512 + +-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) ++/** ++ * gsm_modem_upd_via_data - send modem bits via convergence layer ++ * @dlci: channel ++ * @brk: break signal ++ * ++ * Send an empty frame to signal mobile state changes and to transmit the ++ * break signal for adaption 2. ++ */ ++ ++static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk) ++{ ++ struct gsm_mux *gsm = dlci->gsm; ++ unsigned long flags; ++ ++ if (dlci->state != DLCI_OPEN || dlci->adaption != 2) ++ return; ++ ++ spin_lock_irqsave(&gsm->tx_lock, flags); ++ gsm_dlci_modem_output(gsm, dlci, brk); ++ spin_unlock_irqrestore(&gsm->tx_lock, flags); ++} ++ ++/** ++ * gsm_modem_upd_via_msc - send modem bits via control frame ++ * @dlci: channel ++ * @brk: break signal ++ */ ++ ++static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk) + { + u8 modembits[3]; + struct gsm_control *ctrl; + int len = 2; + ++ if (dlci->gsm->encoding != 0) ++ return 0; ++ + modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */ + if (!brk) { + modembits[1] = (gsm_encode_modem(dlci) << 1) | EA; +@@ -2997,6 +3085,27 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) + return gsm_control_wait(dlci->gsm, ctrl); + } + ++/** ++ * gsm_modem_update - send modem status line state ++ * @dlci: channel ++ * @brk: break signal ++ */ ++ ++static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk) ++{ ++ if (dlci->adaption == 2) { ++ /* Send convergence layer type 2 empty data frame. */ ++ gsm_modem_upd_via_data(dlci, brk); ++ return 0; ++ } else if (dlci->gsm->encoding == 0) { ++ /* Send as MSC control message. */ ++ return gsm_modem_upd_via_msc(dlci, brk); ++ } ++ ++ /* Modem status lines are not supported. */ ++ return -EPROTONOSUPPORT; ++} ++ + static int gsm_carrier_raised(struct tty_port *port) + { + struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port); +@@ -3029,7 +3138,7 @@ static void gsm_dtr_rts(struct tty_port *port, int onoff) + modem_tx &= ~(TIOCM_DTR | TIOCM_RTS); + if (modem_tx != dlci->modem_tx) { + dlci->modem_tx = modem_tx; +- gsmtty_modem_update(dlci, 0); ++ gsm_modem_update(dlci, 0); + } + } + +@@ -3218,7 +3327,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty, + + if (modem_tx != dlci->modem_tx) { + dlci->modem_tx = modem_tx; +- return gsmtty_modem_update(dlci, 0); ++ return gsm_modem_update(dlci, 0); + } + return 0; + } +@@ -3279,7 +3388,7 @@ static void gsmtty_throttle(struct tty_struct *tty) + dlci->modem_tx &= ~TIOCM_RTS; + dlci->throttled = true; + /* Send an MSC with RTS cleared */ +- gsmtty_modem_update(dlci, 0); ++ gsm_modem_update(dlci, 0); + } + + static void gsmtty_unthrottle(struct tty_struct *tty) +@@ -3291,7 +3400,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty) + dlci->modem_tx |= TIOCM_RTS; + dlci->throttled = false; + /* Send an MSC with RTS set */ +- gsmtty_modem_update(dlci, 0); ++ gsm_modem_update(dlci, 0); + } + + static int gsmtty_break_ctl(struct tty_struct *tty, int state) +@@ -3309,7 +3418,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) + if (encode > 0x0F) + encode = 0x0F; /* Best effort */ + } +- return gsmtty_modem_update(dlci, encode); ++ return gsm_modem_update(dlci, encode); + } + + static void gsmtty_cleanup(struct tty_struct *tty) +-- +2.35.1 + diff --git a/queue-5.15/tty-n_gsm-fix-missing-update-of-modem-controls-after.patch b/queue-5.15/tty-n_gsm-fix-missing-update-of-modem-controls-after.patch new file mode 100644 index 00000000000..ee7b7e32ad4 --- /dev/null +++ b/queue-5.15/tty-n_gsm-fix-missing-update-of-modem-controls-after.patch @@ -0,0 +1,48 @@ +From 89a62581ea1dbac20493de0e2927609322683feb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 Apr 2022 03:13:44 -0700 +Subject: tty: n_gsm: fix missing update of modem controls after DLCI open + +From: Daniel Starke + +[ Upstream commit 48473802506d2d6151f59e0e764932b33b53cb3b ] + +Currently the peer is not informed about the initial state of the modem +control lines after a new DLCI has been opened. +Fix this by sending the initial modem control line states after DLCI open. + +Fixes: e1eaea46bb40 ("tty: n_gsm line discipline") +Cc: stable@vger.kernel.org +Signed-off-by: Daniel Starke +Link: https://lore.kernel.org/r/20220420101346.3315-1-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/n_gsm.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index d3d5308daf35..c52d5e0d5c6f 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -371,6 +371,7 @@ static const u8 gsm_fcs8[256] = { + #define GOOD_FCS 0xCF + + static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len); ++static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk); + + /** + * gsm_fcs_add - update FCS +@@ -1489,6 +1490,9 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) + dlci->state = DLCI_OPEN; + if (debug & 8) + pr_debug("DLCI %d goes open.\n", dlci->addr); ++ /* Send current modem state */ ++ if (dlci->addr) ++ gsmtty_modem_update(dlci, 0); + wake_up(&dlci->gsm->event); + } + +-- +2.35.1 + diff --git a/queue-5.15/tty-n_gsm-fix-sometimes-uninitialized-warning-in-gsm.patch b/queue-5.15/tty-n_gsm-fix-sometimes-uninitialized-warning-in-gsm.patch new file mode 100644 index 00000000000..b34fb67b752 --- /dev/null +++ b/queue-5.15/tty-n_gsm-fix-sometimes-uninitialized-warning-in-gsm.patch @@ -0,0 +1,62 @@ +From e85282d8f21109436a793e2b711aba30b2fabd1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Apr 2022 03:47:26 -0700 +Subject: tty: n_gsm: fix sometimes uninitialized warning in + gsm_dlci_modem_output() + +From: Daniel Starke + +[ Upstream commit 19317433057dc1f2ca9a975e4e6b547282c2a5ef ] + +'size' may be used uninitialized in gsm_dlci_modem_output() if called with +an adaption that is neither 1 nor 2. The function is currently only called +by gsm_modem_upd_via_data() and only for adaption 2. +Properly handle every invalid case by returning -EINVAL to silence the +compiler warning and avoid future regressions. + +Fixes: c19ffe00fed6 ("tty: n_gsm: fix invalid use of MSC in advanced option") +Cc: stable@vger.kernel.org +Reported-by: kernel test robot +Signed-off-by: Daniel Starke +Link: https://lore.kernel.org/r/20220425104726.7986-1-daniel.starke@siemens.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/n_gsm.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index c8ca00fad8e4..fd4a86111a6e 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -945,18 +945,21 @@ static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci, + { + u8 *dp = NULL; + struct gsm_msg *msg; +- int size; ++ int size = 0; + + /* for modem bits without break data */ +- if (dlci->adaption == 1) { +- size = 0; +- } else if (dlci->adaption == 2) { +- size = 1; ++ switch (dlci->adaption) { ++ case 1: /* Unstructured */ ++ break; ++ case 2: /* Unstructured with modem bits. */ ++ size++; + if (brk > 0) + size++; +- } else { ++ break; ++ default: + pr_err("%s: unsupported adaption %d\n", __func__, + dlci->adaption); ++ return -EINVAL; + } + + msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); +-- +2.35.1 + diff --git a/queue-5.15/tty-n_gsm-modify-cr-pf-bit-when-config-requester.patch b/queue-5.15/tty-n_gsm-modify-cr-pf-bit-when-config-requester.patch new file mode 100644 index 00000000000..4b5db5e27b2 --- /dev/null +++ b/queue-5.15/tty-n_gsm-modify-cr-pf-bit-when-config-requester.patch @@ -0,0 +1,83 @@ +From 2b325213c8a48eab25b91459eabb9e4ad3339b65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Aug 2021 20:17:47 +0800 +Subject: tty: n_gsm: Modify CR,PF bit when config requester + +From: Zhenguo Zhao + +[ Upstream commit cc0f42122a7e7a5ede9c5f2a41199128b8449eda ] + +When n_gsm config "initiator=0",as requester,gsmld receives dlci SABM/DISC +control command frame,but send UA frame is error. + +Example: +Gsmld receive dlc0 SABM frame "f9 03 3f 01 1c f9",now it sends UA +frame "f9 01 63 01 a3 f9",CR and PF bit are 0,but it should be set +1 from requster to initiator. + +Kernel test log as follows: + +Before modify + +[ 271.732031] c1 gsmld_receive: 00000000: f9 03 3f 01 1c f9 +[ 271.741719] c1 <-- 0) C: SABM(P) +[ 271.749483] c1 gsmld_output: 00000000: f9 01 63 01 a3 f9 +[ 271.758337] c1 --> 0) R: UA(F) + +After modify + +[ 261.233188] c0 gsmld_receive: 00000000: f9 03 3f 01 1c f9 +[ 261.242767] c0 <-- 0) C: SABM(P) +[ 261.250497] c0 gsmld_output: 00000000: f9 03 73 01 d7 f9 +[ 261.259759] c0 --> 0) C: UA(P) + +Signed-off-by: Zhenguo Zhao +Link: https://lore.kernel.org/r/1629461872-26965-3-git-send-email-zhenguo6858@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/n_gsm.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index 6734ef22c304..91ce8e6e889a 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -625,7 +625,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) + + static inline void gsm_response(struct gsm_mux *gsm, int addr, int control) + { +- gsm_send(gsm, addr, 0, control); ++ gsm_send(gsm, addr, 1, control); + } + + /** +@@ -1818,9 +1818,9 @@ static void gsm_queue(struct gsm_mux *gsm) + if (dlci == NULL) + return; + if (dlci->dead) +- gsm_response(gsm, address, DM); ++ gsm_response(gsm, address, DM|PF); + else { +- gsm_response(gsm, address, UA); ++ gsm_response(gsm, address, UA|PF); + gsm_dlci_open(dlci); + } + break; +@@ -1828,11 +1828,11 @@ static void gsm_queue(struct gsm_mux *gsm) + if (cr == 0) + goto invalid; + if (dlci == NULL || dlci->state == DLCI_CLOSED) { +- gsm_response(gsm, address, DM); ++ gsm_response(gsm, address, DM|PF); + return; + } + /* Real close complete */ +- gsm_response(gsm, address, UA); ++ gsm_response(gsm, address, UA|PF); + gsm_dlci_close(dlci); + break; + case UA|PF: +-- +2.35.1 + diff --git a/queue-5.15/tty-n_gsm-save-dlci-address-open-status-when-config-.patch b/queue-5.15/tty-n_gsm-save-dlci-address-open-status-when-config-.patch new file mode 100644 index 00000000000..afc84f9f996 --- /dev/null +++ b/queue-5.15/tty-n_gsm-save-dlci-address-open-status-when-config-.patch @@ -0,0 +1,134 @@ +From 6bbfd936ed4e7116ec27460069c010d11314a45e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Aug 2021 20:17:52 +0800 +Subject: tty: n_gsm: Save dlci address open status when config requester + +From: Zhenguo Zhao + +[ Upstream commit 0b91b5332368f2fb0c3e5cfebc6aff9e167acd8b ] + +When n_gsm config "initiator=0",as requester ,receive SABM frame,n_gsm +register gsmtty dev,and save dlci open address status,if receive DLC0 +DISC or CLD frame,it can unregister the gsmtty dev by saving dlci address. + +Signed-off-by: Zhenguo Zhao +Link: https://lore.kernel.org/r/1629461872-26965-8-git-send-email-zhenguo6858@gmail.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/n_gsm.c | 57 +++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 53 insertions(+), 4 deletions(-) + +diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c +index 91ce8e6e889a..3038e5631be5 100644 +--- a/drivers/tty/n_gsm.c ++++ b/drivers/tty/n_gsm.c +@@ -274,6 +274,10 @@ static DEFINE_SPINLOCK(gsm_mux_lock); + + static struct tty_driver *gsm_tty_driver; + ++/* Save dlci open address */ ++static int addr_open[256] = { 0 }; ++/* Save dlci open count */ ++static int addr_cnt; + /* + * This section of the driver logic implements the GSM encodings + * both the basic and the 'advanced'. Reliable transport is not +@@ -1191,6 +1195,7 @@ static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen) + } + + static void gsm_dlci_begin_close(struct gsm_dlci *dlci); ++static void gsm_dlci_close(struct gsm_dlci *dlci); + + /** + * gsm_control_message - DLCI 0 control processing +@@ -1209,15 +1214,28 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, + { + u8 buf[1]; + unsigned long flags; ++ struct gsm_dlci *dlci; ++ int i; ++ int address; + + switch (command) { + case CMD_CLD: { +- struct gsm_dlci *dlci = gsm->dlci[0]; ++ if (addr_cnt > 0) { ++ for (i = 0; i < addr_cnt; i++) { ++ address = addr_open[i]; ++ dlci = gsm->dlci[address]; ++ gsm_dlci_close(dlci); ++ addr_open[i] = 0; ++ } ++ } + /* Modem wishes to close down */ ++ dlci = gsm->dlci[0]; + if (dlci) { + dlci->dead = true; + gsm->dead = true; +- gsm_dlci_begin_close(dlci); ++ gsm_dlci_close(dlci); ++ addr_cnt = 0; ++ gsm_response(gsm, 0, UA|PF); + } + } + break; +@@ -1780,6 +1798,7 @@ static void gsm_queue(struct gsm_mux *gsm) + struct gsm_dlci *dlci; + u8 cr; + int address; ++ int i, j, k, address_tmp; + /* We have to sneak a look at the packet body to do the FCS. + A somewhat layering violation in the spec */ + +@@ -1822,6 +1841,11 @@ static void gsm_queue(struct gsm_mux *gsm) + else { + gsm_response(gsm, address, UA|PF); + gsm_dlci_open(dlci); ++ /* Save dlci open address */ ++ if (address) { ++ addr_open[addr_cnt] = address; ++ addr_cnt++; ++ } + } + break; + case DISC|PF: +@@ -1832,8 +1856,33 @@ static void gsm_queue(struct gsm_mux *gsm) + return; + } + /* Real close complete */ +- gsm_response(gsm, address, UA|PF); +- gsm_dlci_close(dlci); ++ if (!address) { ++ if (addr_cnt > 0) { ++ for (i = 0; i < addr_cnt; i++) { ++ address = addr_open[i]; ++ dlci = gsm->dlci[address]; ++ gsm_dlci_close(dlci); ++ addr_open[i] = 0; ++ } ++ } ++ dlci = gsm->dlci[0]; ++ gsm_dlci_close(dlci); ++ addr_cnt = 0; ++ gsm_response(gsm, 0, UA|PF); ++ } else { ++ gsm_response(gsm, address, UA|PF); ++ gsm_dlci_close(dlci); ++ /* clear dlci address */ ++ for (j = 0; j < addr_cnt; j++) { ++ address_tmp = addr_open[j]; ++ if (address_tmp == address) { ++ for (k = j; k < addr_cnt; k++) ++ addr_open[k] = addr_open[k+1]; ++ addr_cnt--; ++ break; ++ } ++ } ++ } + break; + case UA|PF: + if (cr == 0 || dlci == NULL) +-- +2.35.1 + diff --git a/queue-5.15/uapi-linux-stddef.h-add-include-guards.patch b/queue-5.15/uapi-linux-stddef.h-add-include-guards.patch new file mode 100644 index 00000000000..d9b3b21c51c --- /dev/null +++ b/queue-5.15/uapi-linux-stddef.h-add-include-guards.patch @@ -0,0 +1,43 @@ +From 096444144cb973be2d86643d7b738f2c0b7aeb90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 29 Mar 2022 10:12:52 -0700 +Subject: uapi/linux/stddef.h: Add include guards + +From: Tadeusz Struk + +[ Upstream commit 55037ed7bdc62151a726f5685f88afa6a82959b1 ] + +Add include guard wrapper define to uapi/linux/stddef.h to prevent macro +redefinition errors when stddef.h is included more than once. This was not +needed before since the only contents already used a redefinition test. + +Signed-off-by: Tadeusz Struk +Link: https://lore.kernel.org/r/20220329171252.57279-1-tadeusz.struk@linaro.org +Fixes: 50d7bd38c3aa ("stddef: Introduce struct_group() helper macro") +Cc: stable@vger.kernel.org +Signed-off-by: Kees Cook +Signed-off-by: Sasha Levin +--- + include/uapi/linux/stddef.h | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/include/uapi/linux/stddef.h b/include/uapi/linux/stddef.h +index 3021ea25a284..7837ba4fe728 100644 +--- a/include/uapi/linux/stddef.h ++++ b/include/uapi/linux/stddef.h +@@ -1,4 +1,7 @@ + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#ifndef _UAPI_LINUX_STDDEF_H ++#define _UAPI_LINUX_STDDEF_H ++ + #include + + #ifndef __always_inline +@@ -41,3 +44,4 @@ + struct { } __empty_ ## NAME; \ + TYPE NAME[]; \ + } ++#endif +-- +2.35.1 + diff --git a/queue-5.15/vdpa-mlx5-avoid-processing-works-if-workqueue-was-de.patch b/queue-5.15/vdpa-mlx5-avoid-processing-works-if-workqueue-was-de.patch new file mode 100644 index 00000000000..c5d2d2b0c52 --- /dev/null +++ b/queue-5.15/vdpa-mlx5-avoid-processing-works-if-workqueue-was-de.patch @@ -0,0 +1,57 @@ +From c264e9eda48ab0a18955994020bd9cd69abbb51e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Mar 2022 16:13:03 +0200 +Subject: vdpa/mlx5: Avoid processing works if workqueue was destroyed + +From: Eli Cohen + +[ Upstream commit ad6dc1daaf29f97f23cc810d60ee01c0e83f4c6b ] + +If mlx5_vdpa gets unloaded while a VM is running, the workqueue will be +destroyed. However, vhost might still have reference to the kick +function and might attempt to push new works. This could lead to null +pointer dereference. + +To fix this, set mvdev->wq to NULL just before destroying and verify +that the workqueue is not NULL in mlx5_vdpa_kick_vq before attempting to +push a new work. + +Fixes: 5262912ef3cf ("vdpa/mlx5: Add support for control VQ and MAC setting") +Signed-off-by: Eli Cohen +Link: https://lore.kernel.org/r/20220321141303.9586-1-elic@nvidia.com +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + drivers/vdpa/mlx5/net/mlx5_vnet.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c +index 174895372e7f..467a349dc26c 100644 +--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c ++++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c +@@ -1641,7 +1641,7 @@ static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx) + return; + + if (unlikely(is_ctrl_vq_idx(mvdev, idx))) { +- if (!mvdev->cvq.ready) ++ if (!mvdev->wq || !mvdev->cvq.ready) + return; + + queue_work(mvdev->wq, &ndev->cvq_ent.work); +@@ -2626,9 +2626,12 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device * + struct mlx5_vdpa_mgmtdev *mgtdev = container_of(v_mdev, struct mlx5_vdpa_mgmtdev, mgtdev); + struct mlx5_vdpa_dev *mvdev = to_mvdev(dev); + struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); ++ struct workqueue_struct *wq; + + mlx5_notifier_unregister(mvdev->mdev, &ndev->nb); +- destroy_workqueue(mvdev->wq); ++ wq = mvdev->wq; ++ mvdev->wq = NULL; ++ destroy_workqueue(wq); + _vdpa_unregister_device(dev); + mgtdev->ndev = NULL; + } +-- +2.35.1 + diff --git a/queue-5.15/virtio-blk-avoid-preallocating-big-sgl-for-data.patch b/queue-5.15/virtio-blk-avoid-preallocating-big-sgl-for-data.patch new file mode 100644 index 00000000000..6b7cbd7d0b5 --- /dev/null +++ b/queue-5.15/virtio-blk-avoid-preallocating-big-sgl-for-data.patch @@ -0,0 +1,298 @@ +From 15b1f99e4888efe37e66effb6352c03081ff3d36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Sep 2021 16:14:34 +0300 +Subject: virtio-blk: avoid preallocating big SGL for data + +From: Max Gurtovoy + +[ Upstream commit 02746e26c39ee473b975e0f68d1295abc92672ed ] + +No need to pre-allocate a big buffer for the IO SGL anymore. If a device +has lots of deep queues, preallocation for the sg list can consume +substantial amounts of memory. For HW virtio-blk device, nr_hw_queues +can be 64 or 128 and each queue's depth might be 128. This means the +resulting preallocation for the data SGLs is big. + +Switch to runtime allocation for SGL for lists longer than 2 entries. +This is the approach used by NVMe drivers so it should be reasonable for +virtio block as well. Runtime SGL allocation has always been the case +for the legacy I/O path so this is nothing new. + +The preallocated small SGL depends on SG_CHAIN so if the ARCH doesn't +support SG_CHAIN, use only runtime allocation for the SGL. + +Re-organize the setup of the IO request to fit the new sg chain +mechanism. + +No performance degradation was seen (fio libaio engine with 16 jobs and +128 iodepth): + +IO size IOPs Rand Read (before/after) IOPs Rand Write (before/after) +-------- --------------------------------- ---------------------------------- +512B 318K/316K 329K/325K + +4KB 323K/321K 353K/349K + +16KB 199K/208K 250K/275K + +128KB 36K/36.1K 39.2K/41.7K + +Signed-off-by: Max Gurtovoy +Reviewed-by: Israel Rukshin +Link: https://lore.kernel.org/r/20210901131434.31158-1-mgurtovoy@nvidia.com +Reviewed-by: Feng Li +Reviewed-by: Stefan Hajnoczi +Tested-by: Stefan Hajnoczi +Reviewed-by: Christoph Hellwig +Signed-off-by: Arnd Bergmann # kconfig fixups +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Sasha Levin +--- + drivers/block/Kconfig | 1 + + drivers/block/virtio_blk.c | 156 ++++++++++++++++++++++++------------- + 2 files changed, 101 insertions(+), 56 deletions(-) + +diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig +index f93cb989241c..28ed157b1203 100644 +--- a/drivers/block/Kconfig ++++ b/drivers/block/Kconfig +@@ -410,6 +410,7 @@ config XEN_BLKDEV_BACKEND + config VIRTIO_BLK + tristate "Virtio block driver" + depends on VIRTIO ++ select SG_POOL + help + This is the virtual block driver for virtio. It can be used with + QEMU based VMMs (like KVM or Xen). Say Y or M. +diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c +index c05138a28475..ccc5770d7654 100644 +--- a/drivers/block/virtio_blk.c ++++ b/drivers/block/virtio_blk.c +@@ -24,6 +24,12 @@ + /* The maximum number of sg elements that fit into a virtqueue */ + #define VIRTIO_BLK_MAX_SG_ELEMS 32768 + ++#ifdef CONFIG_ARCH_NO_SG_CHAIN ++#define VIRTIO_BLK_INLINE_SG_CNT 0 ++#else ++#define VIRTIO_BLK_INLINE_SG_CNT 2 ++#endif ++ + static int major; + static DEFINE_IDA(vd_index_ida); + +@@ -77,6 +83,7 @@ struct virtio_blk { + struct virtblk_req { + struct virtio_blk_outhdr out_hdr; + u8 status; ++ struct sg_table sg_table; + struct scatterlist sg[]; + }; + +@@ -162,12 +169,92 @@ static int virtblk_setup_discard_write_zeroes(struct request *req, bool unmap) + return 0; + } + +-static inline void virtblk_request_done(struct request *req) ++static void virtblk_unmap_data(struct request *req, struct virtblk_req *vbr) + { +- struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); ++ if (blk_rq_nr_phys_segments(req)) ++ sg_free_table_chained(&vbr->sg_table, ++ VIRTIO_BLK_INLINE_SG_CNT); ++} ++ ++static int virtblk_map_data(struct blk_mq_hw_ctx *hctx, struct request *req, ++ struct virtblk_req *vbr) ++{ ++ int err; ++ ++ if (!blk_rq_nr_phys_segments(req)) ++ return 0; ++ ++ vbr->sg_table.sgl = vbr->sg; ++ err = sg_alloc_table_chained(&vbr->sg_table, ++ blk_rq_nr_phys_segments(req), ++ vbr->sg_table.sgl, ++ VIRTIO_BLK_INLINE_SG_CNT); ++ if (unlikely(err)) ++ return -ENOMEM; + ++ return blk_rq_map_sg(hctx->queue, req, vbr->sg_table.sgl); ++} ++ ++static void virtblk_cleanup_cmd(struct request *req) ++{ + if (req->rq_flags & RQF_SPECIAL_PAYLOAD) + kfree(bvec_virt(&req->special_vec)); ++} ++ ++static int virtblk_setup_cmd(struct virtio_device *vdev, struct request *req, ++ struct virtblk_req *vbr) ++{ ++ bool unmap = false; ++ u32 type; ++ ++ vbr->out_hdr.sector = 0; ++ ++ switch (req_op(req)) { ++ case REQ_OP_READ: ++ type = VIRTIO_BLK_T_IN; ++ vbr->out_hdr.sector = cpu_to_virtio64(vdev, ++ blk_rq_pos(req)); ++ break; ++ case REQ_OP_WRITE: ++ type = VIRTIO_BLK_T_OUT; ++ vbr->out_hdr.sector = cpu_to_virtio64(vdev, ++ blk_rq_pos(req)); ++ break; ++ case REQ_OP_FLUSH: ++ type = VIRTIO_BLK_T_FLUSH; ++ break; ++ case REQ_OP_DISCARD: ++ type = VIRTIO_BLK_T_DISCARD; ++ break; ++ case REQ_OP_WRITE_ZEROES: ++ type = VIRTIO_BLK_T_WRITE_ZEROES; ++ unmap = !(req->cmd_flags & REQ_NOUNMAP); ++ break; ++ case REQ_OP_DRV_IN: ++ type = VIRTIO_BLK_T_GET_ID; ++ break; ++ default: ++ WARN_ON_ONCE(1); ++ return BLK_STS_IOERR; ++ } ++ ++ vbr->out_hdr.type = cpu_to_virtio32(vdev, type); ++ vbr->out_hdr.ioprio = cpu_to_virtio32(vdev, req_get_ioprio(req)); ++ ++ if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) { ++ if (virtblk_setup_discard_write_zeroes(req, unmap)) ++ return BLK_STS_RESOURCE; ++ } ++ ++ return 0; ++} ++ ++static inline void virtblk_request_done(struct request *req) ++{ ++ struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); ++ ++ virtblk_unmap_data(req, vbr); ++ virtblk_cleanup_cmd(req); + blk_mq_end_request(req, virtblk_result(vbr)); + } + +@@ -225,57 +312,23 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, + int qid = hctx->queue_num; + int err; + bool notify = false; +- bool unmap = false; +- u32 type; + + BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); + +- switch (req_op(req)) { +- case REQ_OP_READ: +- case REQ_OP_WRITE: +- type = 0; +- break; +- case REQ_OP_FLUSH: +- type = VIRTIO_BLK_T_FLUSH; +- break; +- case REQ_OP_DISCARD: +- type = VIRTIO_BLK_T_DISCARD; +- break; +- case REQ_OP_WRITE_ZEROES: +- type = VIRTIO_BLK_T_WRITE_ZEROES; +- unmap = !(req->cmd_flags & REQ_NOUNMAP); +- break; +- case REQ_OP_DRV_IN: +- type = VIRTIO_BLK_T_GET_ID; +- break; +- default: +- WARN_ON_ONCE(1); +- return BLK_STS_IOERR; +- } +- +- vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type); +- vbr->out_hdr.sector = type ? +- 0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req)); +- vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req)); ++ err = virtblk_setup_cmd(vblk->vdev, req, vbr); ++ if (unlikely(err)) ++ return err; + + blk_mq_start_request(req); + +- if (type == VIRTIO_BLK_T_DISCARD || type == VIRTIO_BLK_T_WRITE_ZEROES) { +- err = virtblk_setup_discard_write_zeroes(req, unmap); +- if (err) +- return BLK_STS_RESOURCE; +- } +- +- num = blk_rq_map_sg(hctx->queue, req, vbr->sg); +- if (num) { +- if (rq_data_dir(req) == WRITE) +- vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT); +- else +- vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN); ++ num = virtblk_map_data(hctx, req, vbr); ++ if (unlikely(num < 0)) { ++ virtblk_cleanup_cmd(req); ++ return BLK_STS_RESOURCE; + } + + spin_lock_irqsave(&vblk->vqs[qid].lock, flags); +- err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); ++ err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg_table.sgl, num); + if (err) { + virtqueue_kick(vblk->vqs[qid].vq); + /* Don't stop the queue if -ENOMEM: we may have failed to +@@ -284,6 +337,8 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx, + if (err == -ENOSPC) + blk_mq_stop_hw_queue(hctx); + spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); ++ virtblk_unmap_data(req, vbr); ++ virtblk_cleanup_cmd(req); + switch (err) { + case -ENOSPC: + return BLK_STS_DEV_RESOURCE; +@@ -660,16 +715,6 @@ static const struct attribute_group *virtblk_attr_groups[] = { + NULL, + }; + +-static int virtblk_init_request(struct blk_mq_tag_set *set, struct request *rq, +- unsigned int hctx_idx, unsigned int numa_node) +-{ +- struct virtio_blk *vblk = set->driver_data; +- struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq); +- +- sg_init_table(vbr->sg, vblk->sg_elems); +- return 0; +-} +- + static int virtblk_map_queues(struct blk_mq_tag_set *set) + { + struct virtio_blk *vblk = set->driver_data; +@@ -682,7 +727,6 @@ static const struct blk_mq_ops virtio_mq_ops = { + .queue_rq = virtio_queue_rq, + .commit_rqs = virtio_commit_rqs, + .complete = virtblk_request_done, +- .init_request = virtblk_init_request, + .map_queues = virtblk_map_queues, + }; + +@@ -762,7 +806,7 @@ static int virtblk_probe(struct virtio_device *vdev) + vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + vblk->tag_set.cmd_size = + sizeof(struct virtblk_req) + +- sizeof(struct scatterlist) * sg_elems; ++ sizeof(struct scatterlist) * VIRTIO_BLK_INLINE_SG_CNT; + vblk->tag_set.driver_data = vblk; + vblk->tag_set.nr_hw_queues = vblk->num_vqs; + +-- +2.35.1 +