From: Sasha Levin Date: Sat, 14 Jan 2023 14:23:25 +0000 (-0500) Subject: Fixes for 5.10 X-Git-Tag: v4.14.303~63^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ddf53721d5172e298b7f6c695871944358403764;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.10 Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/bus-mhi-host-fix-race-between-channel-preparation-an.patch b/queue-5.10/bus-mhi-host-fix-race-between-channel-preparation-an.patch new file mode 100644 index 00000000000..ef168a491fb --- /dev/null +++ b/queue-5.10/bus-mhi-host-fix-race-between-channel-preparation-an.patch @@ -0,0 +1,46 @@ +From 566de723a12a67f70e5c839e9fa9cd401ab3be9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 16 Oct 2022 11:05:32 +0800 +Subject: bus: mhi: host: Fix race between channel preparation and M0 event + +From: Qiang Yu + +[ Upstream commit 869a99907faea6d1835b0bd0d0422ae3519c6ea9 ] + +There is a race condition where mhi_prepare_channel() updates the +read and write pointers as the base address and in parallel, if +an M0 transition occurs, the tasklet goes ahead and rings +doorbells for all channels with a delta in TRE rings assuming +they are already enabled. This causes a null pointer access. Fix +it by adding a channel enabled check before ringing channel +doorbells. + +Cc: stable@vger.kernel.org # 5.19 +Fixes: a6e2e3522f29 "bus: mhi: core: Add support for PM state transitions" +Signed-off-by: Qiang Yu +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1665889532-13634-1-git-send-email-quic_qianyu@quicinc.com +[mani: CCed stable list] +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Sasha Levin +--- + drivers/bus/mhi/core/pm.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c +index 044dcdd723a7..7d69b740b9f9 100644 +--- a/drivers/bus/mhi/core/pm.c ++++ b/drivers/bus/mhi/core/pm.c +@@ -298,7 +298,8 @@ int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl) + read_lock_irq(&mhi_chan->lock); + + /* Only ring DB if ring is not empty */ +- if (tre_ring->base && tre_ring->wp != tre_ring->rp) ++ if (tre_ring->base && tre_ring->wp != tre_ring->rp && ++ mhi_chan->ch_state == MHI_CH_STATE_ENABLED) + mhi_ring_chan_db(mhi_cntrl, mhi_chan); + read_unlock_irq(&mhi_chan->lock); + } +-- +2.35.1 + diff --git a/queue-5.10/clk-imx-imx8mp-add-shared-clk-gate-for-usb-suspend-c.patch b/queue-5.10/clk-imx-imx8mp-add-shared-clk-gate-for-usb-suspend-c.patch new file mode 100644 index 00000000000..952931c33c7 --- /dev/null +++ b/queue-5.10/clk-imx-imx8mp-add-shared-clk-gate-for-usb-suspend-c.patch @@ -0,0 +1,57 @@ +From d595e40aee8722550fb056a9e739a722734f5e46 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Sep 2022 22:54:22 +0800 +Subject: clk: imx: imx8mp: add shared clk gate for usb suspend clk + +From: Li Jun + +[ Upstream commit ed1f4ccfe947a3e1018a3bd7325134574c7ff9b3 ] + +32K usb suspend clock gate is shared with usb_root_clk, this +shared clock gate was initially defined only for usb suspend +clock, usb suspend clk is kept on while system is active or +system sleep with usb wakeup enabled, so usb root clock is +fine with this situation; with the commit cf7f3f4fa9e5 +("clk: imx8mp: fix usb_root_clk parent"), this clock gate is +changed to be for usb root clock, but usb root clock will +be off while usb is suspended, so usb suspend clock will be +gated too, this cause some usb functionalities will not work, +so define this clock to be a shared clock gate to conform with +the real HW status. + +Fixes: 9c140d9926761 ("clk: imx: Add support for i.MX8MP clock driver") +Cc: stable@vger.kernel.org # v5.19+ +Tested-by: Alexander Stein +Signed-off-by: Li Jun +Signed-off-by: Abel Vesa +Link: https://lore.kernel.org/r/1664549663-20364-2-git-send-email-jun.li@nxp.com +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c +index 187044b98bde..72592e35836b 100644 +--- a/drivers/clk/imx/clk-imx8mp.c ++++ b/drivers/clk/imx/clk-imx8mp.c +@@ -17,6 +17,7 @@ + + static u32 share_count_nand; + static u32 share_count_media; ++static u32 share_count_usb; + + static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", }; + static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +@@ -706,7 +707,8 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) + hws[IMX8MP_CLK_UART2_ROOT] = imx_clk_hw_gate4("uart2_root_clk", "uart2", ccm_base + 0x44a0, 0); + hws[IMX8MP_CLK_UART3_ROOT] = imx_clk_hw_gate4("uart3_root_clk", "uart3", ccm_base + 0x44b0, 0); + hws[IMX8MP_CLK_UART4_ROOT] = imx_clk_hw_gate4("uart4_root_clk", "uart4", ccm_base + 0x44c0, 0); +- hws[IMX8MP_CLK_USB_ROOT] = imx_clk_hw_gate4("usb_root_clk", "hsio_axi", ccm_base + 0x44d0, 0); ++ hws[IMX8MP_CLK_USB_ROOT] = imx_clk_hw_gate2_shared2("usb_root_clk", "hsio_axi", ccm_base + 0x44d0, 0, &share_count_usb); ++ hws[IMX8MP_CLK_USB_SUSP] = imx_clk_hw_gate2_shared2("usb_suspend_clk", "osc_32k", ccm_base + 0x44d0, 0, &share_count_usb); + hws[IMX8MP_CLK_USB_PHY_ROOT] = imx_clk_hw_gate4("usb_phy_root_clk", "usb_phy_ref", ccm_base + 0x44f0, 0); + hws[IMX8MP_CLK_USDHC1_ROOT] = imx_clk_hw_gate4("usdhc1_root_clk", "usdhc1", ccm_base + 0x4510, 0); + hws[IMX8MP_CLK_USDHC2_ROOT] = imx_clk_hw_gate4("usdhc2_root_clk", "usdhc2", ccm_base + 0x4520, 0); +-- +2.35.1 + diff --git a/queue-5.10/clk-imx8mp-add-clkout1-2-support.patch b/queue-5.10/clk-imx8mp-add-clkout1-2-support.patch new file mode 100644 index 00000000000..fb1afa9f9f0 --- /dev/null +++ b/queue-5.10/clk-imx8mp-add-clkout1-2-support.patch @@ -0,0 +1,80 @@ +From af13d19faf568dbf1ea31e5249ba88485d3e714e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Apr 2022 18:21:31 +0200 +Subject: clk: imx8mp: add clkout1/2 support + +From: Lucas Stach + +[ Upstream commit 43896f56b59eeaf08687fa976257ae7083d01b41 ] + +clkout1 and clkout2 allow to supply clocks from the SoC to the board, +which is used by some board designs to provide reference clocks. + +Signed-off-by: Lucas Stach +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20220427162131.3127303-1-l.stach@pengutronix.de +Signed-off-by: Abel Vesa +Stable-dep-of: 5c1f7f109094 ("dt-bindings: clocks: imx8mp: Add ID for usb suspend clock") +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mp.c | 14 ++++++++++++++ + include/dt-bindings/clock/imx8mp-clock.h | 9 +++++++-- + 2 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c +index 2af39c8240fa..187044b98bde 100644 +--- a/drivers/clk/imx/clk-imx8mp.c ++++ b/drivers/clk/imx/clk-imx8mp.c +@@ -411,6 +411,11 @@ static const char * const imx8mp_sai7_sels[] = {"osc_24m", "audio_pll1_out", "au + + static const char * const imx8mp_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; + ++static const char * const imx8mp_clkout_sels[] = {"audio_pll1_out", "audio_pll2_out", "video_pll1_out", ++ "dummy", "dummy", "gpu_pll_out", "vpu_pll_out", ++ "arm_pll_out", "sys_pll1", "sys_pll2", "sys_pll3", ++ "dummy", "dummy", "osc_24m", "dummy", "osc_32k"}; ++ + static struct clk_hw **hws; + static struct clk_hw_onecell_data *clk_hw_data; + +@@ -532,6 +537,15 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) + hws[IMX8MP_SYS_PLL2_500M] = imx_clk_hw_fixed_factor("sys_pll2_500m", "sys_pll2_500m_cg", 1, 2); + hws[IMX8MP_SYS_PLL2_1000M] = imx_clk_hw_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1); + ++ hws[IMX8MP_CLK_CLKOUT1_SEL] = imx_clk_hw_mux2("clkout1_sel", anatop_base + 0x128, 4, 4, ++ imx8mp_clkout_sels, ARRAY_SIZE(imx8mp_clkout_sels)); ++ hws[IMX8MP_CLK_CLKOUT1_DIV] = imx_clk_hw_divider("clkout1_div", "clkout1_sel", anatop_base + 0x128, 0, 4); ++ hws[IMX8MP_CLK_CLKOUT1] = imx_clk_hw_gate("clkout1", "clkout1_div", anatop_base + 0x128, 8); ++ hws[IMX8MP_CLK_CLKOUT2_SEL] = imx_clk_hw_mux2("clkout2_sel", anatop_base + 0x128, 20, 4, ++ imx8mp_clkout_sels, ARRAY_SIZE(imx8mp_clkout_sels)); ++ hws[IMX8MP_CLK_CLKOUT2_DIV] = imx_clk_hw_divider("clkout2_div", "clkout2_sel", anatop_base + 0x128, 16, 4); ++ hws[IMX8MP_CLK_CLKOUT2] = imx_clk_hw_gate("clkout2", "clkout2_div", anatop_base + 0x128, 24); ++ + hws[IMX8MP_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mp_a53_sels, ccm_base + 0x8000); + hws[IMX8MP_CLK_A53_SRC] = hws[IMX8MP_CLK_A53_DIV]; + hws[IMX8MP_CLK_A53_CG] = hws[IMX8MP_CLK_A53_DIV]; +diff --git a/include/dt-bindings/clock/imx8mp-clock.h b/include/dt-bindings/clock/imx8mp-clock.h +index 4a621fddfcd3..0ba16b76eb2f 100644 +--- a/include/dt-bindings/clock/imx8mp-clock.h ++++ b/include/dt-bindings/clock/imx8mp-clock.h +@@ -321,10 +321,15 @@ + #define IMX8MP_CLK_AUDIO_AXI 310 + #define IMX8MP_CLK_HSIO_AXI 311 + #define IMX8MP_CLK_MEDIA_ISP 312 +- + #define IMX8MP_CLK_MEDIA_DISP2_PIX 313 ++#define IMX8MP_CLK_CLKOUT1_SEL 314 ++#define IMX8MP_CLK_CLKOUT1_DIV 315 ++#define IMX8MP_CLK_CLKOUT1 316 ++#define IMX8MP_CLK_CLKOUT2_SEL 317 ++#define IMX8MP_CLK_CLKOUT2_DIV 318 ++#define IMX8MP_CLK_CLKOUT2 319 + +-#define IMX8MP_CLK_END 314 ++#define IMX8MP_CLK_END 320 + + #define IMX8MP_CLK_AUDIOMIX_SAI1_IPG 0 + #define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1 1 +-- +2.35.1 + diff --git a/queue-5.10/clk-imx8mp-add-disp2-pixel-clock.patch b/queue-5.10/clk-imx8mp-add-disp2-pixel-clock.patch new file mode 100644 index 00000000000..67fbf381021 --- /dev/null +++ b/queue-5.10/clk-imx8mp-add-disp2-pixel-clock.patch @@ -0,0 +1,77 @@ +From a0341e40173d7f5316f2fed0e32de671d17a6103 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 13 Mar 2022 13:39:49 +0100 +Subject: clk: imx8mp: Add DISP2 pixel clock + +From: Marek Vasut + +[ Upstream commit 39772efd98adecbd5b8c6096d465d2fcbafbde6a ] + +Add pixel clock for second LCDIFv3 interface. Both LCDIFv3 interfaces use +the same set of parent clock, so deduplicate imx8mp_media_disp1_pix_sels +into common imx8mp_media_disp_pix_sels and use it for both. + +Signed-off-by: Marek Vasut +Cc: Abel Vesa +Cc: Fabio Estevam +Cc: NXP Linux Team +Cc: Peng Fan +Cc: Shawn Guo +Reviewed-by: Abel Vesa +Link: https://lore.kernel.org/r/20220313123949.207284-1-marex@denx.de +Signed-off-by: Abel Vesa +Stable-dep-of: 5c1f7f109094 ("dt-bindings: clocks: imx8mp: Add ID for usb suspend clock") +Signed-off-by: Sasha Levin +--- + drivers/clk/imx/clk-imx8mp.c | 5 +++-- + include/dt-bindings/clock/imx8mp-clock.h | 4 +++- + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c +index 36e8d619e334..2af39c8240fa 100644 +--- a/drivers/clk/imx/clk-imx8mp.c ++++ b/drivers/clk/imx/clk-imx8mp.c +@@ -362,7 +362,7 @@ static const char * const imx8mp_media_mipi_phy1_ref_sels[] = {"osc_24m", "sys_p + "clk_ext2", "audio_pll2_out", + "video_pll1_out", }; + +-static const char * const imx8mp_media_disp1_pix_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out", ++static const char * const imx8mp_media_disp_pix_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out", + "audio_pll1_out", "sys_pll1_800m", + "sys_pll2_1000m", "sys_pll3_out", "clk_ext4", }; + +@@ -566,6 +566,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) + hws[IMX8MP_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb_root", imx8mp_ahb_sels, ccm_base + 0x9000); + hws[IMX8MP_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mp_audio_ahb_sels, ccm_base + 0x9100); + hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200); ++ hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300); + + hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1); + hws[IMX8MP_CLK_IPG_AUDIO_ROOT] = imx_clk_hw_divider2("ipg_audio_root", "audio_ahb", ccm_base + 0x9180, 0, 1); +@@ -630,7 +631,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) + hws[IMX8MP_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mp_usdhc3_sels, ccm_base + 0xbc80); + hws[IMX8MP_CLK_MEDIA_CAM1_PIX] = imx8m_clk_hw_composite("media_cam1_pix", imx8mp_media_cam1_pix_sels, ccm_base + 0xbd00); + hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF] = imx8m_clk_hw_composite("media_mipi_phy1_ref", imx8mp_media_mipi_phy1_ref_sels, ccm_base + 0xbd80); +- hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite("media_disp1_pix", imx8mp_media_disp1_pix_sels, ccm_base + 0xbe00); ++ hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite("media_disp1_pix", imx8mp_media_disp_pix_sels, ccm_base + 0xbe00); + hws[IMX8MP_CLK_MEDIA_CAM2_PIX] = imx8m_clk_hw_composite("media_cam2_pix", imx8mp_media_cam2_pix_sels, ccm_base + 0xbe80); + hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00); + hws[IMX8MP_CLK_MEMREPAIR] = imx8m_clk_hw_composite_critical("mem_repair", imx8mp_memrepair_sels, ccm_base + 0xbf80); +diff --git a/include/dt-bindings/clock/imx8mp-clock.h b/include/dt-bindings/clock/imx8mp-clock.h +index e8d68fbb6e3f..4a621fddfcd3 100644 +--- a/include/dt-bindings/clock/imx8mp-clock.h ++++ b/include/dt-bindings/clock/imx8mp-clock.h +@@ -322,7 +322,9 @@ + #define IMX8MP_CLK_HSIO_AXI 311 + #define IMX8MP_CLK_MEDIA_ISP 312 + +-#define IMX8MP_CLK_END 313 ++#define IMX8MP_CLK_MEDIA_DISP2_PIX 313 ++ ++#define IMX8MP_CLK_END 314 + + #define IMX8MP_CLK_AUDIOMIX_SAI1_IPG 0 + #define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1 1 +-- +2.35.1 + diff --git a/queue-5.10/dt-bindings-clocks-imx8mp-add-id-for-usb-suspend-clo.patch b/queue-5.10/dt-bindings-clocks-imx8mp-add-id-for-usb-suspend-clo.patch new file mode 100644 index 00000000000..e4b8103b206 --- /dev/null +++ b/queue-5.10/dt-bindings-clocks-imx8mp-add-id-for-usb-suspend-clo.patch @@ -0,0 +1,41 @@ +From 11dd67b938adc87c404f897682fc7315643e00aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Sep 2022 22:54:21 +0800 +Subject: dt-bindings: clocks: imx8mp: Add ID for usb suspend clock + +From: Li Jun + +[ Upstream commit 5c1f7f1090947d494c30042123e0ec846f696336 ] + +usb suspend clock has a gate shared with usb_root_clk. + +Fixes: 9c140d9926761 ("clk: imx: Add support for i.MX8MP clock driver") +Cc: stable@vger.kernel.org # v5.19+ +Acked-by: Krzysztof Kozlowski +Tested-by: Alexander Stein +Signed-off-by: Li Jun +Signed-off-by: Abel Vesa +Link: https://lore.kernel.org/r/1664549663-20364-1-git-send-email-jun.li@nxp.com +Signed-off-by: Sasha Levin +--- + include/dt-bindings/clock/imx8mp-clock.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/dt-bindings/clock/imx8mp-clock.h b/include/dt-bindings/clock/imx8mp-clock.h +index 0ba16b76eb2f..d7e513243dd2 100644 +--- a/include/dt-bindings/clock/imx8mp-clock.h ++++ b/include/dt-bindings/clock/imx8mp-clock.h +@@ -328,8 +328,9 @@ + #define IMX8MP_CLK_CLKOUT2_SEL 317 + #define IMX8MP_CLK_CLKOUT2_DIV 318 + #define IMX8MP_CLK_CLKOUT2 319 ++#define IMX8MP_CLK_USB_SUSP 320 + +-#define IMX8MP_CLK_END 320 ++#define IMX8MP_CLK_END 321 + + #define IMX8MP_CLK_AUDIOMIX_SAI1_IPG 0 + #define IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1 1 +-- +2.35.1 + diff --git a/queue-5.10/ext4-fix-uninititialized-value-in-ext4_evict_inode.patch b/queue-5.10/ext4-fix-uninititialized-value-in-ext4_evict_inode.patch new file mode 100644 index 00000000000..c1d18950308 --- /dev/null +++ b/queue-5.10/ext4-fix-uninititialized-value-in-ext4_evict_inode.patch @@ -0,0 +1,97 @@ +From ecb19c78b1c8920fe5ee45c5a9356706da1593c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 15:36:03 +0800 +Subject: ext4: fix uninititialized value in 'ext4_evict_inode' + +From: Ye Bin + +[ Upstream commit 7ea71af94eaaaf6d9aed24bc94a05b977a741cb9 ] + +Syzbot found the following issue: +===================================================== +BUG: KMSAN: uninit-value in ext4_evict_inode+0xdd/0x26b0 fs/ext4/inode.c:180 + ext4_evict_inode+0xdd/0x26b0 fs/ext4/inode.c:180 + evict+0x365/0x9a0 fs/inode.c:664 + iput_final fs/inode.c:1747 [inline] + iput+0x985/0xdd0 fs/inode.c:1773 + __ext4_new_inode+0xe54/0x7ec0 fs/ext4/ialloc.c:1361 + ext4_mknod+0x376/0x840 fs/ext4/namei.c:2844 + vfs_mknod+0x79d/0x830 fs/namei.c:3914 + do_mknodat+0x47d/0xaa0 + __do_sys_mknodat fs/namei.c:3992 [inline] + __se_sys_mknodat fs/namei.c:3989 [inline] + __ia32_sys_mknodat+0xeb/0x150 fs/namei.c:3989 + do_syscall_32_irqs_on arch/x86/entry/common.c:112 [inline] + __do_fast_syscall_32+0xa2/0x100 arch/x86/entry/common.c:178 + do_fast_syscall_32+0x33/0x70 arch/x86/entry/common.c:203 + do_SYSENTER_32+0x1b/0x20 arch/x86/entry/common.c:246 + entry_SYSENTER_compat_after_hwframe+0x70/0x82 + +Uninit was created at: + __alloc_pages+0x9f1/0xe80 mm/page_alloc.c:5578 + alloc_pages+0xaae/0xd80 mm/mempolicy.c:2285 + alloc_slab_page mm/slub.c:1794 [inline] + allocate_slab+0x1b5/0x1010 mm/slub.c:1939 + new_slab mm/slub.c:1992 [inline] + ___slab_alloc+0x10c3/0x2d60 mm/slub.c:3180 + __slab_alloc mm/slub.c:3279 [inline] + slab_alloc_node mm/slub.c:3364 [inline] + slab_alloc mm/slub.c:3406 [inline] + __kmem_cache_alloc_lru mm/slub.c:3413 [inline] + kmem_cache_alloc_lru+0x6f3/0xb30 mm/slub.c:3429 + alloc_inode_sb include/linux/fs.h:3117 [inline] + ext4_alloc_inode+0x5f/0x860 fs/ext4/super.c:1321 + alloc_inode+0x83/0x440 fs/inode.c:259 + new_inode_pseudo fs/inode.c:1018 [inline] + new_inode+0x3b/0x430 fs/inode.c:1046 + __ext4_new_inode+0x2a7/0x7ec0 fs/ext4/ialloc.c:959 + ext4_mkdir+0x4d5/0x1560 fs/ext4/namei.c:2992 + vfs_mkdir+0x62a/0x870 fs/namei.c:4035 + do_mkdirat+0x466/0x7b0 fs/namei.c:4060 + __do_sys_mkdirat fs/namei.c:4075 [inline] + __se_sys_mkdirat fs/namei.c:4073 [inline] + __ia32_sys_mkdirat+0xc4/0x120 fs/namei.c:4073 + do_syscall_32_irqs_on arch/x86/entry/common.c:112 [inline] + __do_fast_syscall_32+0xa2/0x100 arch/x86/entry/common.c:178 + do_fast_syscall_32+0x33/0x70 arch/x86/entry/common.c:203 + do_SYSENTER_32+0x1b/0x20 arch/x86/entry/common.c:246 + entry_SYSENTER_compat_after_hwframe+0x70/0x82 + +CPU: 1 PID: 4625 Comm: syz-executor.2 Not tainted 6.1.0-rc4-syzkaller-62821-gcb231e2f67ec #0 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022 +===================================================== + +Now, 'ext4_alloc_inode()' didn't init 'ei->i_flags'. If new inode failed +before set 'ei->i_flags' in '__ext4_new_inode()', then do 'iput()'. As after +6bc0d63dad7f commit will access 'ei->i_flags' in 'ext4_evict_inode()' which +will lead to access uninit-value. +To solve above issue just init 'ei->i_flags' in 'ext4_alloc_inode()'. + +Reported-by: syzbot+57b25da729eb0b88177d@syzkaller.appspotmail.com +Signed-off-by: Ye Bin +Fixes: 6bc0d63dad7f ("ext4: remove EA inode entry from mbcache on inode eviction") +Reviewed-by: Jan Kara +Reviewed-by: Eric Biggers +Link: https://lore.kernel.org/r/20221117073603.2598882-1-yebin@huaweicloud.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Sasha Levin +--- + fs/ext4/super.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 935589579b8f..e940fb07ef2e 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -1279,6 +1279,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) + return NULL; + + inode_set_iversion(&ei->vfs_inode, 1); ++ ei->i_flags = 0; + spin_lock_init(&ei->i_raw_lock); + INIT_LIST_HEAD(&ei->i_prealloc_list); + atomic_set(&ei->i_prealloc_active, 0); +-- +2.35.1 + diff --git a/queue-5.10/iommu-amd-add-pci-segment-support-for-ivrs_-ioapic-h.patch b/queue-5.10/iommu-amd-add-pci-segment-support-for-ivrs_-ioapic-h.patch new file mode 100644 index 00000000000..61158eaf9d6 --- /dev/null +++ b/queue-5.10/iommu-amd-add-pci-segment-support-for-ivrs_-ioapic-h.patch @@ -0,0 +1,193 @@ +From fb7e49a1636534a029b41bafda6f748a53b9d4a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Jul 2022 17:08:22 +0530 +Subject: iommu/amd: Add PCI segment support for ivrs_[ioapic/hpet/acpihid] + commands + +From: Suravee Suthikulpanit + +[ Upstream commit bbe3a106580c21bc883fb0c9fa3da01534392fe8 ] + +By default, PCI segment is zero and can be omitted. To support system +with non-zero PCI segment ID, modify the parsing functions to allow +PCI segment ID. + +Co-developed-by: Vasant Hegde +Signed-off-by: Vasant Hegde +Signed-off-by: Suravee Suthikulpanit +Link: https://lore.kernel.org/r/20220706113825.25582-33-vasant.hegde@amd.com +Signed-off-by: Joerg Roedel +Stable-dep-of: 1198d2316dc4 ("iommu/amd: Fix ill-formed ivrs_ioapic, ivrs_hpet and ivrs_acpihid options") +Signed-off-by: Sasha Levin +--- + .../admin-guide/kernel-parameters.txt | 34 ++++++++++---- + drivers/iommu/amd/init.c | 44 ++++++++++++------- + 2 files changed, 52 insertions(+), 26 deletions(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index f577c29f2093..ce93bb358bc1 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -2103,23 +2103,39 @@ + + ivrs_ioapic [HW,X86-64] + Provide an override to the IOAPIC-ID<->DEVICE-ID +- mapping provided in the IVRS ACPI table. For +- example, to map IOAPIC-ID decimal 10 to +- PCI device 00:14.0 write the parameter as: ++ mapping provided in the IVRS ACPI table. ++ By default, PCI segment is 0, and can be omitted. ++ For example: ++ * To map IOAPIC-ID decimal 10 to PCI device 00:14.0 ++ write the parameter as: + ivrs_ioapic[10]=00:14.0 ++ * To map IOAPIC-ID decimal 10 to PCI segment 0x1 and ++ PCI device 00:14.0 write the parameter as: ++ ivrs_ioapic[10]=0001:00:14.0 + + ivrs_hpet [HW,X86-64] + Provide an override to the HPET-ID<->DEVICE-ID +- mapping provided in the IVRS ACPI table. For +- example, to map HPET-ID decimal 0 to +- PCI device 00:14.0 write the parameter as: ++ mapping provided in the IVRS ACPI table. ++ By default, PCI segment is 0, and can be omitted. ++ For example: ++ * To map HPET-ID decimal 0 to PCI device 00:14.0 ++ write the parameter as: + ivrs_hpet[0]=00:14.0 ++ * To map HPET-ID decimal 10 to PCI segment 0x1 and ++ PCI device 00:14.0 write the parameter as: ++ ivrs_ioapic[10]=0001:00:14.0 + + ivrs_acpihid [HW,X86-64] + Provide an override to the ACPI-HID:UID<->DEVICE-ID +- mapping provided in the IVRS ACPI table. For +- example, to map UART-HID:UID AMD0020:0 to +- PCI device 00:14.5 write the parameter as: ++ mapping provided in the IVRS ACPI table. ++ ++ For example, to map UART-HID:UID AMD0020:0 to ++ PCI segment 0x1 and PCI device ID 00:14.5, ++ write the parameter as: ++ ivrs_acpihid[0001:00:14.5]=AMD0020:0 ++ ++ By default, PCI segment is 0, and can be omitted. ++ For example, PCI device 00:14.5 write the parameter as: + ivrs_acpihid[00:14.5]=AMD0020:0 + + js= [HW,JOY] Analog joystick +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index 310ab24d003a..85370f305aa8 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -85,6 +85,10 @@ + #define ACPI_DEVFLAG_ATSDIS 0x10000000 + + #define LOOP_TIMEOUT 2000000 ++ ++#define IVRS_GET_SBDF_ID(seg, bus, dev, fd) (((seg & 0xffff) << 16) | ((bus & 0xff) << 8) \ ++ | ((dev & 0x1f) << 3) | (fn & 0x7)) ++ + /* + * ACPI table definitions + * +@@ -3046,15 +3050,17 @@ static int __init parse_amd_iommu_options(char *str) + + static int __init parse_ivrs_ioapic(char *str) + { +- unsigned int bus, dev, fn; ++ u32 seg = 0, bus, dev, fn; + int ret, id, i; +- u16 devid; ++ u32 devid; + + ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn); +- + if (ret != 4) { +- pr_err("Invalid command line: ivrs_ioapic%s\n", str); +- return 1; ++ ret = sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn); ++ if (ret != 5) { ++ pr_err("Invalid command line: ivrs_ioapic%s\n", str); ++ return 1; ++ } + } + + if (early_ioapic_map_size == EARLY_MAP_SIZE) { +@@ -3063,7 +3069,7 @@ static int __init parse_ivrs_ioapic(char *str) + return 1; + } + +- devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7); ++ devid = IVRS_GET_SBDF_ID(seg, bus, dev, fn); + + cmdline_maps = true; + i = early_ioapic_map_size++; +@@ -3076,15 +3082,17 @@ static int __init parse_ivrs_ioapic(char *str) + + static int __init parse_ivrs_hpet(char *str) + { +- unsigned int bus, dev, fn; ++ u32 seg = 0, bus, dev, fn; + int ret, id, i; +- u16 devid; ++ u32 devid; + + ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn); +- + if (ret != 4) { +- pr_err("Invalid command line: ivrs_hpet%s\n", str); +- return 1; ++ ret = sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn); ++ if (ret != 5) { ++ pr_err("Invalid command line: ivrs_hpet%s\n", str); ++ return 1; ++ } + } + + if (early_hpet_map_size == EARLY_MAP_SIZE) { +@@ -3093,7 +3101,7 @@ static int __init parse_ivrs_hpet(char *str) + return 1; + } + +- devid = ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7); ++ devid = IVRS_GET_SBDF_ID(seg, bus, dev, fn); + + cmdline_maps = true; + i = early_hpet_map_size++; +@@ -3106,15 +3114,18 @@ static int __init parse_ivrs_hpet(char *str) + + static int __init parse_ivrs_acpihid(char *str) + { +- u32 bus, dev, fn; ++ u32 seg = 0, bus, dev, fn; + char *hid, *uid, *p; + char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0}; + int ret, i; + + ret = sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid); + if (ret != 4) { +- pr_err("Invalid command line: ivrs_acpihid(%s)\n", str); +- return 1; ++ ret = sscanf(str, "[%x:%x:%x.%x]=%s", &seg, &bus, &dev, &fn, acpiid); ++ if (ret != 5) { ++ pr_err("Invalid command line: ivrs_acpihid(%s)\n", str); ++ return 1; ++ } + } + + p = acpiid; +@@ -3136,8 +3147,7 @@ static int __init parse_ivrs_acpihid(char *str) + i = early_acpihid_map_size++; + memcpy(early_acpihid_map[i].hid, hid, strlen(hid)); + memcpy(early_acpihid_map[i].uid, uid, strlen(uid)); +- early_acpihid_map[i].devid = +- ((bus & 0xff) << 8) | ((dev & 0x1f) << 3) | (fn & 0x7); ++ early_acpihid_map[i].devid = IVRS_GET_SBDF_ID(seg, bus, dev, fn); + early_acpihid_map[i].cmd_line = true; + + return 1; +-- +2.35.1 + diff --git a/queue-5.10/iommu-amd-fix-ill-formed-ivrs_ioapic-ivrs_hpet-and-i.patch b/queue-5.10/iommu-amd-fix-ill-formed-ivrs_ioapic-ivrs_hpet-and-i.patch new file mode 100644 index 00000000000..270e9bb44b0 --- /dev/null +++ b/queue-5.10/iommu-amd-fix-ill-formed-ivrs_ioapic-ivrs_hpet-and-i.patch @@ -0,0 +1,216 @@ +From dde85fa0d916e51ca426ff180c52014de65de714 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Sep 2022 10:56:38 -0500 +Subject: iommu/amd: Fix ill-formed ivrs_ioapic, ivrs_hpet and ivrs_acpihid + options + +From: Kim Phillips + +[ Upstream commit 1198d2316dc4265a97d0e8445a22c7a6d17580a4 ] + +Currently, these options cause the following libkmod error: + +libkmod: ERROR ../libkmod/libkmod-config.c:489 kcmdline_parse_result: \ + Ignoring bad option on kernel command line while parsing module \ + name: 'ivrs_xxxx[XX:XX' + +Fix by introducing a new parameter format for these options and +throw a warning for the deprecated format. + +Users are still allowed to omit the PCI Segment if zero. + +Adding a Link: to the reason why we're modding the syntax parsing +in the driver and not in libkmod. + +Fixes: ca3bf5d47cec ("iommu/amd: Introduces ivrs_acpihid kernel parameter") +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/linux-modules/20200310082308.14318-2-lucas.demarchi@intel.com/ +Reported-by: Kim Phillips +Co-developed-by: Suravee Suthikulpanit +Signed-off-by: Suravee Suthikulpanit +Signed-off-by: Kim Phillips +Link: https://lore.kernel.org/r/20220919155638.391481-2-kim.phillips@amd.com +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + .../admin-guide/kernel-parameters.txt | 27 +++++-- + drivers/iommu/amd/init.c | 79 +++++++++++++------ + 2 files changed, 76 insertions(+), 30 deletions(-) + +diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt +index ce93bb358bc1..eb437d659f2c 100644 +--- a/Documentation/admin-guide/kernel-parameters.txt ++++ b/Documentation/admin-guide/kernel-parameters.txt +@@ -2105,7 +2105,13 @@ + Provide an override to the IOAPIC-ID<->DEVICE-ID + mapping provided in the IVRS ACPI table. + By default, PCI segment is 0, and can be omitted. +- For example: ++ ++ For example, to map IOAPIC-ID decimal 10 to ++ PCI segment 0x1 and PCI device 00:14.0, ++ write the parameter as: ++ ivrs_ioapic=10@0001:00:14.0 ++ ++ Deprecated formats: + * To map IOAPIC-ID decimal 10 to PCI device 00:14.0 + write the parameter as: + ivrs_ioapic[10]=00:14.0 +@@ -2117,7 +2123,13 @@ + Provide an override to the HPET-ID<->DEVICE-ID + mapping provided in the IVRS ACPI table. + By default, PCI segment is 0, and can be omitted. +- For example: ++ ++ For example, to map HPET-ID decimal 10 to ++ PCI segment 0x1 and PCI device 00:14.0, ++ write the parameter as: ++ ivrs_hpet=10@0001:00:14.0 ++ ++ Deprecated formats: + * To map HPET-ID decimal 0 to PCI device 00:14.0 + write the parameter as: + ivrs_hpet[0]=00:14.0 +@@ -2128,15 +2140,20 @@ + ivrs_acpihid [HW,X86-64] + Provide an override to the ACPI-HID:UID<->DEVICE-ID + mapping provided in the IVRS ACPI table. ++ By default, PCI segment is 0, and can be omitted. + + For example, to map UART-HID:UID AMD0020:0 to + PCI segment 0x1 and PCI device ID 00:14.5, + write the parameter as: +- ivrs_acpihid[0001:00:14.5]=AMD0020:0 ++ ivrs_acpihid=AMD0020:0@0001:00:14.5 + +- By default, PCI segment is 0, and can be omitted. +- For example, PCI device 00:14.5 write the parameter as: ++ Deprecated formats: ++ * To map UART-HID:UID AMD0020:0 to PCI segment is 0, ++ PCI device ID 00:14.5, write the parameter as: + ivrs_acpihid[00:14.5]=AMD0020:0 ++ * To map UART-HID:UID AMD0020:0 to PCI segment 0x1 and ++ PCI device ID 00:14.5, write the parameter as: ++ ivrs_acpihid[0001:00:14.5]=AMD0020:0 + + js= [HW,JOY] Analog joystick + See Documentation/input/joydev/joystick.rst. +diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c +index 85370f305aa8..ce822347f747 100644 +--- a/drivers/iommu/amd/init.c ++++ b/drivers/iommu/amd/init.c +@@ -3051,18 +3051,24 @@ static int __init parse_amd_iommu_options(char *str) + static int __init parse_ivrs_ioapic(char *str) + { + u32 seg = 0, bus, dev, fn; +- int ret, id, i; ++ int id, i; + u32 devid; + +- ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn); +- if (ret != 4) { +- ret = sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn); +- if (ret != 5) { +- pr_err("Invalid command line: ivrs_ioapic%s\n", str); +- return 1; +- } ++ if (sscanf(str, "=%d@%x:%x.%x", &id, &bus, &dev, &fn) == 4 || ++ sscanf(str, "=%d@%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5) ++ goto found; ++ ++ if (sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn) == 4 || ++ sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5) { ++ pr_warn("ivrs_ioapic%s option format deprecated; use ivrs_ioapic=%d@%04x:%02x:%02x.%d instead\n", ++ str, id, seg, bus, dev, fn); ++ goto found; + } + ++ pr_err("Invalid command line: ivrs_ioapic%s\n", str); ++ return 1; ++ ++found: + if (early_ioapic_map_size == EARLY_MAP_SIZE) { + pr_err("Early IOAPIC map overflow - ignoring ivrs_ioapic%s\n", + str); +@@ -3083,18 +3089,24 @@ static int __init parse_ivrs_ioapic(char *str) + static int __init parse_ivrs_hpet(char *str) + { + u32 seg = 0, bus, dev, fn; +- int ret, id, i; ++ int id, i; + u32 devid; + +- ret = sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn); +- if (ret != 4) { +- ret = sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn); +- if (ret != 5) { +- pr_err("Invalid command line: ivrs_hpet%s\n", str); +- return 1; +- } ++ if (sscanf(str, "=%d@%x:%x.%x", &id, &bus, &dev, &fn) == 4 || ++ sscanf(str, "=%d@%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5) ++ goto found; ++ ++ if (sscanf(str, "[%d]=%x:%x.%x", &id, &bus, &dev, &fn) == 4 || ++ sscanf(str, "[%d]=%x:%x:%x.%x", &id, &seg, &bus, &dev, &fn) == 5) { ++ pr_warn("ivrs_hpet%s option format deprecated; use ivrs_hpet=%d@%04x:%02x:%02x.%d instead\n", ++ str, id, seg, bus, dev, fn); ++ goto found; + } + ++ pr_err("Invalid command line: ivrs_hpet%s\n", str); ++ return 1; ++ ++found: + if (early_hpet_map_size == EARLY_MAP_SIZE) { + pr_err("Early HPET map overflow - ignoring ivrs_hpet%s\n", + str); +@@ -3115,19 +3127,36 @@ static int __init parse_ivrs_hpet(char *str) + static int __init parse_ivrs_acpihid(char *str) + { + u32 seg = 0, bus, dev, fn; +- char *hid, *uid, *p; ++ char *hid, *uid, *p, *addr; + char acpiid[ACPIHID_UID_LEN + ACPIHID_HID_LEN] = {0}; +- int ret, i; +- +- ret = sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid); +- if (ret != 4) { +- ret = sscanf(str, "[%x:%x:%x.%x]=%s", &seg, &bus, &dev, &fn, acpiid); +- if (ret != 5) { +- pr_err("Invalid command line: ivrs_acpihid(%s)\n", str); +- return 1; ++ int i; ++ ++ addr = strchr(str, '@'); ++ if (!addr) { ++ if (sscanf(str, "[%x:%x.%x]=%s", &bus, &dev, &fn, acpiid) == 4 || ++ sscanf(str, "[%x:%x:%x.%x]=%s", &seg, &bus, &dev, &fn, acpiid) == 5) { ++ pr_warn("ivrs_acpihid%s option format deprecated; use ivrs_acpihid=%s@%04x:%02x:%02x.%d instead\n", ++ str, acpiid, seg, bus, dev, fn); ++ goto found; + } ++ goto not_found; + } + ++ /* We have the '@', make it the terminator to get just the acpiid */ ++ *addr++ = 0; ++ ++ if (sscanf(str, "=%s", acpiid) != 1) ++ goto not_found; ++ ++ if (sscanf(addr, "%x:%x.%x", &bus, &dev, &fn) == 3 || ++ sscanf(addr, "%x:%x:%x.%x", &seg, &bus, &dev, &fn) == 4) ++ goto found; ++ ++not_found: ++ pr_err("Invalid command line: ivrs_acpihid%s\n", str); ++ return 1; ++ ++found: + p = acpiid; + hid = strsep(&p, ":"); + uid = p; +-- +2.35.1 + diff --git a/queue-5.10/series b/queue-5.10/series index 5efc9eb0253..e52fe34b950 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -8,3 +8,20 @@ s390-kexec-fix-ipl-report-address-for-kdump.patch asoc-qcom-lpass-cpu-fix-fallback-sd-line-index-handling.patch s390-cpum_sf-add-read_once-semantics-to-compare-and-swap-loops.patch s390-percpu-add-read_once-to-arch_this_cpu_to_op_simple.patch +bus-mhi-host-fix-race-between-channel-preparation-an.patch +iommu-amd-add-pci-segment-support-for-ivrs_-ioapic-h.patch +iommu-amd-fix-ill-formed-ivrs_ioapic-ivrs_hpet-and-i.patch +clk-imx8mp-add-disp2-pixel-clock.patch +clk-imx8mp-add-clkout1-2-support.patch +dt-bindings-clocks-imx8mp-add-id-for-usb-suspend-clo.patch +clk-imx-imx8mp-add-shared-clk-gate-for-usb-suspend-c.patch +xhci-avoid-parsing-transfer-events-several-times.patch +xhci-get-isochronous-ring-directly-from-endpoint-str.patch +xhci-adjust-parameters-passed-to-cleanup_halted_endp.patch +xhci-add-xhci_reset_halted_ep-helper-function.patch +xhci-move-xhci_td_cleanup-so-it-can-be-called-by-mor.patch +xhci-store-td-status-in-the-td-struct-instead-of-pas.patch +xhci-move-and-rename-xhci_cleanup_halted_endpoint.patch +xhci-prevent-infinite-loop-in-transaction-errors-rec.patch +usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch +ext4-fix-uninititialized-value-in-ext4_evict_inode.patch diff --git a/queue-5.10/usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch b/queue-5.10/usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch new file mode 100644 index 00000000000..5346b0217f5 --- /dev/null +++ b/queue-5.10/usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch @@ -0,0 +1,49 @@ +From eb5ff2547a8a34bc6c0b102f14b5cee50c045f2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Dec 2022 21:15:26 +0100 +Subject: usb: ulpi: defer ulpi_register on ulpi_read_id timeout + +From: Ferry Toth + +[ Upstream commit 8a7b31d545d3a15f0e6f5984ae16f0ca4fd76aac ] + +Since commit 0f0101719138 ("usb: dwc3: Don't switch OTG -> peripheral +if extcon is present") Dual Role support on Intel Merrifield platform +broke due to rearranging the call to dwc3_get_extcon(). + +It appears to be caused by ulpi_read_id() on the first test write failing +with -ETIMEDOUT. Currently ulpi_read_id() expects to discover the phy via +DT when the test write fails and returns 0 in that case, even if DT does not +provide the phy. As a result usb probe completes without phy. + +Make ulpi_read_id() return -ETIMEDOUT to its user if the first test write +fails. The user should then handle it appropriately. A follow up patch +will make dwc3_core_init() set -EPROBE_DEFER in this case and bail out. + +Fixes: ef6a7bcfb01c ("usb: ulpi: Support device discovery via DT") +Cc: stable@vger.kernel.org +Acked-by: Heikki Krogerus +Signed-off-by: Ferry Toth +Link: https://lore.kernel.org/r/20221205201527.13525-2-ftoth@exalondelft.nl +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/common/ulpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c +index 3c705f1bead8..1f077f2ea40f 100644 +--- a/drivers/usb/common/ulpi.c ++++ b/drivers/usb/common/ulpi.c +@@ -208,7 +208,7 @@ static int ulpi_read_id(struct ulpi *ulpi) + /* Test the interface */ + ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa); + if (ret < 0) +- goto err; ++ return ret; + + ret = ulpi_read(ulpi, ULPI_SCRATCH); + if (ret < 0) +-- +2.35.1 + diff --git a/queue-5.10/xhci-add-xhci_reset_halted_ep-helper-function.patch b/queue-5.10/xhci-add-xhci_reset_halted_ep-helper-function.patch new file mode 100644 index 00000000000..d1d41a95bb7 --- /dev/null +++ b/queue-5.10/xhci-add-xhci_reset_halted_ep-helper-function.patch @@ -0,0 +1,89 @@ +From c1b7975d93e4ff03e72349b2dc9e48ee49cc193c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 15:00:32 +0200 +Subject: xhci: Add xhci_reset_halted_ep() helper function + +From: Mathias Nyman + +[ Upstream commit d8ac95001bea683d2088acb3e61613a27b8d2d5f ] + +Create a separate helper function to issue reset endpont commands +to clear halted endpoints. + +This is useful for cases where a halted endpoint is discovered while +completing another command, and the endpoint halt needs to be cleared +with a endpoint reset first. + +No functional changes + +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20210129130044.206855-16-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a1575120972e ("xhci: Prevent infinite loop in transaction errors recovery for streams") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-ring.c | 31 +++++++++++++++++++++++++------ + 1 file changed, 25 insertions(+), 6 deletions(-) + +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index a0d210d3a3c6..b4a510450ac2 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -773,6 +773,26 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, + seg->bounce_offs = 0; + } + ++static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id, ++ unsigned int ep_index, enum xhci_ep_reset_type reset_type) ++{ ++ struct xhci_command *command; ++ int ret = 0; ++ ++ command = xhci_alloc_command(xhci, false, GFP_ATOMIC); ++ if (!command) { ++ ret = -ENOMEM; ++ goto done; ++ } ++ ++ ret = xhci_queue_reset_ep(xhci, command, slot_id, ep_index, reset_type); ++done: ++ if (ret) ++ xhci_err(xhci, "ERROR queuing reset endpoint for slot %d ep_index %d, %d\n", ++ slot_id, ep_index, ret); ++ return ret; ++} ++ + /* + * When we get a command completion for a Stop Endpoint Command, we need to + * unlink any cancelled TDs from the ring. There are two ways to do that: +@@ -1929,8 +1949,9 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, + struct xhci_td *td, + enum xhci_ep_reset_type reset_type) + { +- struct xhci_command *command; + unsigned int slot_id = ep->vdev->slot_id; ++ int err; ++ + /* + * Avoid resetting endpoint if link is inactive. Can cause host hang. + * Device will be reset soon to recover the link so don't do anything +@@ -1938,13 +1959,11 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, + if (ep->vdev->flags & VDEV_PORT_ERROR) + return; + +- command = xhci_alloc_command(xhci, false, GFP_ATOMIC); +- if (!command) +- return; +- + ep->ep_state |= EP_HALTED; + +- xhci_queue_reset_ep(xhci, command, slot_id, ep->ep_index, reset_type); ++ err = xhci_reset_halted_ep(xhci, slot_id, ep->ep_index, reset_type); ++ if (err) ++ return; + + if (reset_type == EP_HARD_RESET) { + ep->ep_state |= EP_HARD_CLEAR_TOGGLE; +-- +2.35.1 + diff --git a/queue-5.10/xhci-adjust-parameters-passed-to-cleanup_halted_endp.patch b/queue-5.10/xhci-adjust-parameters-passed-to-cleanup_halted_endp.patch new file mode 100644 index 00000000000..c0fba29e279 --- /dev/null +++ b/queue-5.10/xhci-adjust-parameters-passed-to-cleanup_halted_endp.patch @@ -0,0 +1,170 @@ +From a143c99e8669f32c1df73b63de268b2352a990a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 15:00:20 +0200 +Subject: xhci: adjust parameters passed to cleanup_halted_endpoint() + +From: Mathias Nyman + +[ Upstream commit d70f4231b81eeb6dd78bd913ff42729b524eec51 ] + +Instead of passing slot id and endpoint index to +cleanup_halted_endpoint() pass the endpoint structure pointer +as it's already known. + +Avoids again digging out the endpoint structure based on +slot id and endpoint index, and passing them along the +call chain for this purpose only. + +Add slot_id to the virt_dev structure so that it +can easily be found from a virt_dev, or its child, the +virt_ep endpoint structure. + +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20210129130044.206855-4-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a1575120972e ("xhci: Prevent infinite loop in transaction errors recovery for streams") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-mem.c | 2 ++ + drivers/usb/host/xhci-ring.c | 35 ++++++++++++++--------------------- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 17 insertions(+), 21 deletions(-) + +diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c +index 002e4948993d..a8a9addb4d25 100644 +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -1003,6 +1003,8 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, + if (!dev) + return 0; + ++ dev->slot_id = slot_id; ++ + /* Allocate the (output) device context that will be used in the HC. */ + dev->out_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags); + if (!dev->out_ctx) +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 6d34c56376e5..a0d210d3a3c6 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1925,13 +1925,12 @@ static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td, + } + + static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, +- unsigned int slot_id, unsigned int ep_index, +- unsigned int stream_id, struct xhci_td *td, +- enum xhci_ep_reset_type reset_type) ++ struct xhci_virt_ep *ep, unsigned int stream_id, ++ struct xhci_td *td, ++ enum xhci_ep_reset_type reset_type) + { +- struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; + struct xhci_command *command; +- ++ unsigned int slot_id = ep->vdev->slot_id; + /* + * Avoid resetting endpoint if link is inactive. Can cause host hang. + * Device will be reset soon to recover the link so don't do anything +@@ -1945,11 +1944,11 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, + + ep->ep_state |= EP_HALTED; + +- xhci_queue_reset_ep(xhci, command, slot_id, ep_index, reset_type); ++ xhci_queue_reset_ep(xhci, command, slot_id, ep->ep_index, reset_type); + + if (reset_type == EP_HARD_RESET) { + ep->ep_state |= EP_HARD_CLEAR_TOGGLE; +- xhci_cleanup_stalled_ring(xhci, slot_id, ep_index, stream_id, ++ xhci_cleanup_stalled_ring(xhci, slot_id, ep->ep_index, stream_id, + td); + } + xhci_ring_cmd_db(xhci); +@@ -2047,10 +2046,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, + { + struct xhci_ep_ctx *ep_ctx; + struct xhci_ring *ep_ring; +- unsigned int slot_id; + u32 trb_comp_code; + +- slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); + ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); + ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); + trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); +@@ -2079,8 +2076,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, + */ + if ((ep->ep_index != 0) || (trb_comp_code != COMP_STALL_ERROR)) + xhci_clear_hub_tt_buffer(xhci, td, ep); +- xhci_cleanup_halted_endpoint(xhci, slot_id, ep->ep_index, +- ep_ring->stream_id, td, EP_HARD_RESET); ++ xhci_cleanup_halted_endpoint(xhci, ep, ep_ring->stream_id, td, ++ EP_HARD_RESET); + } else { + /* Update ring dequeue pointer */ + while (ep_ring->dequeue != td->last_trb) +@@ -2323,9 +2320,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_ring *ep_ring; + u32 trb_comp_code; + u32 remaining, requested, ep_trb_len; +- unsigned int slot_id; + +- slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); + slot_ctx = xhci_get_slot_ctx(xhci, ep->vdev->out_ctx); + ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); + trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); +@@ -2365,8 +2360,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + le32_to_cpu(slot_ctx->tt_info) & TT_SLOT) + break; + *status = 0; +- xhci_cleanup_halted_endpoint(xhci, slot_id, ep->ep_index, +- ep_ring->stream_id, td, EP_SOFT_RESET); ++ xhci_cleanup_halted_endpoint(xhci, ep, ep_ring->stream_id, td, ++ EP_SOFT_RESET); + return 0; + default: + /* do nothing */ +@@ -2441,8 +2436,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, + case COMP_USB_TRANSACTION_ERROR: + case COMP_INVALID_STREAM_TYPE_ERROR: + case COMP_INVALID_STREAM_ID_ERROR: +- xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, 0, +- NULL, EP_SOFT_RESET); ++ xhci_cleanup_halted_endpoint(xhci, ep, 0, NULL, ++ EP_SOFT_RESET); + goto cleanup; + case COMP_RING_UNDERRUN: + case COMP_RING_OVERRUN: +@@ -2625,8 +2620,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, + if (trb_comp_code == COMP_STALL_ERROR || + xhci_requires_manual_halt_cleanup(xhci, ep_ctx, + trb_comp_code)) { +- xhci_cleanup_halted_endpoint(xhci, slot_id, +- ep_index, ++ xhci_cleanup_halted_endpoint(xhci, ep, + ep_ring->stream_id, + NULL, + EP_HARD_RESET); +@@ -2720,8 +2714,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, + if (trb_comp_code == COMP_STALL_ERROR || + xhci_requires_manual_halt_cleanup(xhci, ep_ctx, + trb_comp_code)) +- xhci_cleanup_halted_endpoint(xhci, slot_id, +- ep_index, ++ xhci_cleanup_halted_endpoint(xhci, ep, + ep_ring->stream_id, + td, EP_HARD_RESET); + goto cleanup; +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 5fbd159f6fa5..9cbf106fb3ee 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1004,6 +1004,7 @@ struct xhci_interval_bw_table { + #define EP_CTX_PER_DEV 31 + + struct xhci_virt_device { ++ int slot_id; + struct usb_device *udev; + /* + * Commands to the hardware are passed an "input context" that +-- +2.35.1 + diff --git a/queue-5.10/xhci-avoid-parsing-transfer-events-several-times.patch b/queue-5.10/xhci-avoid-parsing-transfer-events-several-times.patch new file mode 100644 index 00000000000..7f063b49be6 --- /dev/null +++ b/queue-5.10/xhci-avoid-parsing-transfer-events-several-times.patch @@ -0,0 +1,157 @@ +From 0760d5b03f7260b1e3a366c86de1ff5777b6737c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 15:00:18 +0200 +Subject: xhci: Avoid parsing transfer events several times + +From: Mathias Nyman + +[ Upstream commit ab58f3bb6aaaf98ba81d5c627ac25c08ff4ed4f1 ] + +When handling transfer events the event is passed along the handling +callpath and parsed again in several occasions. + +The event contains slot_id and endpoint index, from which the driver +endpoint structure can be found. There wasn't however a way to get the +endpoint index or parent usb device from this endpoint structure. + +A lot of extra event parsing, and thus some DMA doublefetch cases, +and excess variables and code can be avoided by adding endpoint index +and parent usb virt device pointer to the endpoint structure. + +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20210129130044.206855-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a1575120972e ("xhci: Prevent infinite loop in transaction errors recovery for streams") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-mem.c | 2 ++ + drivers/usb/host/xhci-ring.c | 28 ++++++++-------------------- + drivers/usb/host/xhci.h | 2 ++ + 3 files changed, 12 insertions(+), 20 deletions(-) + +diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c +index d1a42300ae58..002e4948993d 100644 +--- a/drivers/usb/host/xhci-mem.c ++++ b/drivers/usb/host/xhci-mem.c +@@ -1021,6 +1021,8 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, + + /* Initialize the cancellation list and watchdog timers for each ep */ + for (i = 0; i < 31; i++) { ++ dev->eps[i].ep_index = i; ++ dev->eps[i].vdev = dev; + xhci_init_endpoint_timer(xhci, &dev->eps[i]); + INIT_LIST_HEAD(&dev->eps[i].cancelled_td_list); + INIT_LIST_HEAD(&dev->eps[i].bw_endpoint_list); +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index fa3a7ac15f82..5cee7150376d 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -1936,7 +1936,7 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, + * Avoid resetting endpoint if link is inactive. Can cause host hang. + * Device will be reset soon to recover the link so don't do anything + */ +- if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) ++ if (ep->vdev->flags & VDEV_PORT_ERROR) + return; + + command = xhci_alloc_command(xhci, false, GFP_ATOMIC); +@@ -2045,18 +2045,14 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_transfer_event *event, + struct xhci_virt_ep *ep, int *status) + { +- struct xhci_virt_device *xdev; + struct xhci_ep_ctx *ep_ctx; + struct xhci_ring *ep_ring; + unsigned int slot_id; + u32 trb_comp_code; +- int ep_index; + + slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); +- xdev = xhci->devs[slot_id]; +- ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; + ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); +- ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); ++ ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); + trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); + + if (trb_comp_code == COMP_STOPPED_LENGTH_INVALID || +@@ -2081,9 +2077,9 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, + * stall later. Hub TT buffer should only be cleared for FS/LS + * devices behind HS hubs for functional stalls. + */ +- if ((ep_index != 0) || (trb_comp_code != COMP_STALL_ERROR)) ++ if ((ep->ep_index != 0) || (trb_comp_code != COMP_STALL_ERROR)) + xhci_clear_hub_tt_buffer(xhci, td, ep); +- xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, ++ xhci_cleanup_halted_endpoint(xhci, slot_id, ep->ep_index, + ep_ring->stream_id, td, EP_HARD_RESET); + } else { + /* Update ring dequeue pointer */ +@@ -2117,19 +2113,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + union xhci_trb *ep_trb, struct xhci_transfer_event *event, + struct xhci_virt_ep *ep, int *status) + { +- struct xhci_virt_device *xdev; +- unsigned int slot_id; +- int ep_index; + struct xhci_ep_ctx *ep_ctx; + u32 trb_comp_code; + u32 remaining, requested; + u32 trb_type; + + trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(ep_trb->generic.field[3])); +- slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); +- xdev = xhci->devs[slot_id]; +- ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; +- ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); ++ ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); + trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); + requested = td->urb->transfer_buffer_length; + remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); +@@ -2177,7 +2167,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + ep_ctx, trb_comp_code)) + break; + xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n", +- trb_comp_code, ep_index); ++ trb_comp_code, ep->ep_index); + fallthrough; + case COMP_STALL_ERROR: + /* Did we transfer part of the data (middle) phase? */ +@@ -2339,11 +2329,9 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + u32 trb_comp_code; + u32 remaining, requested, ep_trb_len; + unsigned int slot_id; +- int ep_index; + + slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); +- slot_ctx = xhci_get_slot_ctx(xhci, xhci->devs[slot_id]->out_ctx); +- ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; ++ slot_ctx = xhci_get_slot_ctx(xhci, ep->vdev->out_ctx); + ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); + trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); + remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); +@@ -2382,7 +2370,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + le32_to_cpu(slot_ctx->tt_info) & TT_SLOT) + break; + *status = 0; +- xhci_cleanup_halted_endpoint(xhci, slot_id, ep_index, ++ xhci_cleanup_halted_endpoint(xhci, slot_id, ep->ep_index, + ep_ring->stream_id, td, EP_SOFT_RESET); + return 0; + default: +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 059050f13522..5fbd159f6fa5 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -924,6 +924,8 @@ struct xhci_bw_info { + #define SS_BW_RESERVED 10 + + struct xhci_virt_ep { ++ struct xhci_virt_device *vdev; /* parent */ ++ unsigned int ep_index; + struct xhci_ring *ring; + /* Related to endpoints that are configured to use stream IDs only */ + struct xhci_stream_info *stream_info; +-- +2.35.1 + diff --git a/queue-5.10/xhci-get-isochronous-ring-directly-from-endpoint-str.patch b/queue-5.10/xhci-get-isochronous-ring-directly-from-endpoint-str.patch new file mode 100644 index 00000000000..28d374b921f --- /dev/null +++ b/queue-5.10/xhci-get-isochronous-ring-directly-from-endpoint-str.patch @@ -0,0 +1,97 @@ +From f423df4930ccfab33cd187579a063bdd9dbe1483 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 15:00:19 +0200 +Subject: xhci: get isochronous ring directly from endpoint structure + +From: Mathias Nyman + +[ Upstream commit d4dff8043ea5b93a30cb9b19d4407bd506a6877a ] + +isochronous endpoints do not support streams, meaning that +there is only one ring per endpoint. + +Avoid double-fetching the transfer event DMA to get the +ring. Also makes passing the event to skip_isoc_td() uncecessary. + +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20210129130044.206855-3-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a1575120972e ("xhci: Prevent infinite loop in transaction errors recovery for streams") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-ring.c | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 5cee7150376d..6d34c56376e5 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -2209,7 +2209,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + union xhci_trb *ep_trb, struct xhci_transfer_event *event, + struct xhci_virt_ep *ep, int *status) + { +- struct xhci_ring *ep_ring; + struct urb_priv *urb_priv; + int idx; + struct usb_iso_packet_descriptor *frame; +@@ -2218,7 +2217,6 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + u32 remaining, requested, ep_trb_len; + int short_framestatus; + +- ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); + trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); + urb_priv = td->urb->hcpriv; + idx = urb_priv->num_tds_done; +@@ -2279,7 +2277,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + } + + if (sum_trbs_for_length) +- frame->actual_length = sum_trb_lengths(xhci, ep_ring, ep_trb) + ++ frame->actual_length = sum_trb_lengths(xhci, ep->ring, ep_trb) + + ep_trb_len - remaining; + else + frame->actual_length = requested; +@@ -2290,15 +2288,12 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + } + + static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, +- struct xhci_transfer_event *event, + struct xhci_virt_ep *ep, int *status) + { +- struct xhci_ring *ep_ring; + struct urb_priv *urb_priv; + struct usb_iso_packet_descriptor *frame; + int idx; + +- ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); + urb_priv = td->urb->hcpriv; + idx = urb_priv->num_tds_done; + frame = &td->urb->iso_frame_desc[idx]; +@@ -2310,11 +2305,11 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + frame->actual_length = 0; + + /* Update ring dequeue pointer */ +- while (ep_ring->dequeue != td->last_trb) +- inc_deq(xhci, ep_ring); +- inc_deq(xhci, ep_ring); ++ while (ep->ring->dequeue != td->last_trb) ++ inc_deq(xhci, ep->ring); ++ inc_deq(xhci, ep->ring); + +- return xhci_td_cleanup(xhci, td, ep_ring, status); ++ return xhci_td_cleanup(xhci, td, ep->ring, status); + } + + /* +@@ -2693,7 +2688,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, + return -ESHUTDOWN; + } + +- skip_isoc_td(xhci, td, event, ep, &status); ++ skip_isoc_td(xhci, td, ep, &status); + goto cleanup; + } + if (trb_comp_code == COMP_SHORT_PACKET) +-- +2.35.1 + diff --git a/queue-5.10/xhci-move-and-rename-xhci_cleanup_halted_endpoint.patch b/queue-5.10/xhci-move-and-rename-xhci_cleanup_halted_endpoint.patch new file mode 100644 index 00000000000..f3f7287a6ed --- /dev/null +++ b/queue-5.10/xhci-move-and-rename-xhci_cleanup_halted_endpoint.patch @@ -0,0 +1,168 @@ +From 7cf62e065d3bdb30b0b9d6113df9cadf2c2dce33 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 15:00:37 +0200 +Subject: xhci: move and rename xhci_cleanup_halted_endpoint() + +From: Mathias Nyman + +[ Upstream commit 7c6c334e6fc8cd99e780fd74cd29687886a81862 ] + +Halted endpoints can be discoverd both when handling transfer events and +command completion events. Move code that handles halted endpoints before +both of those event handlers. + +Rename the function to xhci_handle_halted_ep() to better describe +what it does. Try to reserve "cleanup" word in function names for last +stage cleanup activities. + +No functional changes + +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20210129130044.206855-21-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a1575120972e ("xhci: Prevent infinite loop in transaction errors recovery for streams") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-ring.c | 84 ++++++++++++++++++------------------ + 1 file changed, 43 insertions(+), 41 deletions(-) + +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index 2bd407ff9f0b..edb712081815 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -839,6 +839,35 @@ static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id, + return ret; + } + ++static void xhci_handle_halted_endpoint(struct xhci_hcd *xhci, ++ struct xhci_virt_ep *ep, unsigned int stream_id, ++ struct xhci_td *td, ++ enum xhci_ep_reset_type reset_type) ++{ ++ unsigned int slot_id = ep->vdev->slot_id; ++ int err; ++ ++ /* ++ * Avoid resetting endpoint if link is inactive. Can cause host hang. ++ * Device will be reset soon to recover the link so don't do anything ++ */ ++ if (ep->vdev->flags & VDEV_PORT_ERROR) ++ return; ++ ++ ep->ep_state |= EP_HALTED; ++ ++ err = xhci_reset_halted_ep(xhci, slot_id, ep->ep_index, reset_type); ++ if (err) ++ return; ++ ++ if (reset_type == EP_HARD_RESET) { ++ ep->ep_state |= EP_HARD_CLEAR_TOGGLE; ++ xhci_cleanup_stalled_ring(xhci, slot_id, ep->ep_index, stream_id, ++ td); ++ } ++ xhci_ring_cmd_db(xhci); ++} ++ + /* + * When we get a command completion for a Stop Endpoint Command, we need to + * unlink any cancelled TDs from the ring. There are two ways to do that: +@@ -1990,35 +2019,6 @@ static void xhci_clear_hub_tt_buffer(struct xhci_hcd *xhci, struct xhci_td *td, + } + } + +-static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, +- struct xhci_virt_ep *ep, unsigned int stream_id, +- struct xhci_td *td, +- enum xhci_ep_reset_type reset_type) +-{ +- unsigned int slot_id = ep->vdev->slot_id; +- int err; +- +- /* +- * Avoid resetting endpoint if link is inactive. Can cause host hang. +- * Device will be reset soon to recover the link so don't do anything +- */ +- if (ep->vdev->flags & VDEV_PORT_ERROR) +- return; +- +- ep->ep_state |= EP_HALTED; +- +- err = xhci_reset_halted_ep(xhci, slot_id, ep->ep_index, reset_type); +- if (err) +- return; +- +- if (reset_type == EP_HARD_RESET) { +- ep->ep_state |= EP_HARD_CLEAR_TOGGLE; +- xhci_cleanup_stalled_ring(xhci, slot_id, ep->ep_index, stream_id, +- td); +- } +- xhci_ring_cmd_db(xhci); +-} +- + /* Check if an error has halted the endpoint ring. The class driver will + * cleanup the halt for a non-default control endpoint if we indicate a stall. + * However, a babble and other errors also halt the endpoint ring, and the class +@@ -2094,7 +2094,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, + */ + if ((ep->ep_index != 0) || (trb_comp_code != COMP_STALL_ERROR)) + xhci_clear_hub_tt_buffer(xhci, td, ep); +- xhci_cleanup_halted_endpoint(xhci, ep, ep_ring->stream_id, td, ++ ++ xhci_handle_halted_endpoint(xhci, ep, ep_ring->stream_id, td, + EP_HARD_RESET); + } else { + /* Update ring dequeue pointer */ +@@ -2379,8 +2380,9 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + break; + + td->status = 0; +- xhci_cleanup_halted_endpoint(xhci, ep, ep_ring->stream_id, td, +- EP_SOFT_RESET); ++ ++ xhci_handle_halted_endpoint(xhci, ep, ep_ring->stream_id, td, ++ EP_SOFT_RESET); + return 0; + default: + /* do nothing */ +@@ -2455,8 +2457,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, + case COMP_USB_TRANSACTION_ERROR: + case COMP_INVALID_STREAM_TYPE_ERROR: + case COMP_INVALID_STREAM_ID_ERROR: +- xhci_cleanup_halted_endpoint(xhci, ep, 0, NULL, +- EP_SOFT_RESET); ++ xhci_handle_halted_endpoint(xhci, ep, 0, NULL, ++ EP_SOFT_RESET); + goto cleanup; + case COMP_RING_UNDERRUN: + case COMP_RING_OVERRUN: +@@ -2639,10 +2641,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, + if (trb_comp_code == COMP_STALL_ERROR || + xhci_requires_manual_halt_cleanup(xhci, ep_ctx, + trb_comp_code)) { +- xhci_cleanup_halted_endpoint(xhci, ep, +- ep_ring->stream_id, +- NULL, +- EP_HARD_RESET); ++ xhci_handle_halted_endpoint(xhci, ep, ++ ep_ring->stream_id, ++ NULL, ++ EP_HARD_RESET); + } + goto cleanup; + } +@@ -2734,9 +2736,9 @@ static int handle_tx_event(struct xhci_hcd *xhci, + if (trb_comp_code == COMP_STALL_ERROR || + xhci_requires_manual_halt_cleanup(xhci, ep_ctx, + trb_comp_code)) +- xhci_cleanup_halted_endpoint(xhci, ep, +- ep_ring->stream_id, +- td, EP_HARD_RESET); ++ xhci_handle_halted_endpoint(xhci, ep, ++ ep_ring->stream_id, ++ td, EP_HARD_RESET); + goto cleanup; + } + +-- +2.35.1 + diff --git a/queue-5.10/xhci-move-xhci_td_cleanup-so-it-can-be-called-by-mor.patch b/queue-5.10/xhci-move-xhci_td_cleanup-so-it-can-be-called-by-mor.patch new file mode 100644 index 00000000000..2764d919021 --- /dev/null +++ b/queue-5.10/xhci-move-xhci_td_cleanup-so-it-can-be-called-by-mor.patch @@ -0,0 +1,133 @@ +From 2253542509fb011f596123fde46eace4cdfd8f76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 15:00:33 +0200 +Subject: xhci: move xhci_td_cleanup so it can be called by more functions + +From: Mathias Nyman + +[ Upstream commit 69eaf9e79fa7c7ff4b1eb626493ce5a81e467520 ] + +No funtional changes + +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20210129130044.206855-17-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a1575120972e ("xhci: Prevent infinite loop in transaction errors recovery for streams") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-ring.c | 92 ++++++++++++++++++------------------ + 1 file changed, 46 insertions(+), 46 deletions(-) + +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index b4a510450ac2..d523cbe7fcf1 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -773,6 +773,52 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, + seg->bounce_offs = 0; + } + ++static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, ++ struct xhci_ring *ep_ring, int *status) ++{ ++ struct urb *urb = NULL; ++ ++ /* Clean up the endpoint's TD list */ ++ urb = td->urb; ++ ++ /* if a bounce buffer was used to align this td then unmap it */ ++ xhci_unmap_td_bounce_buffer(xhci, ep_ring, td); ++ ++ /* Do one last check of the actual transfer length. ++ * If the host controller said we transferred more data than the buffer ++ * length, urb->actual_length will be a very big number (since it's ++ * unsigned). Play it safe and say we didn't transfer anything. ++ */ ++ if (urb->actual_length > urb->transfer_buffer_length) { ++ xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n", ++ urb->transfer_buffer_length, urb->actual_length); ++ urb->actual_length = 0; ++ *status = 0; ++ } ++ list_del_init(&td->td_list); ++ /* Was this TD slated to be cancelled but completed anyway? */ ++ if (!list_empty(&td->cancelled_td_list)) ++ list_del_init(&td->cancelled_td_list); ++ ++ inc_td_cnt(urb); ++ /* Giveback the urb when all the tds are completed */ ++ if (last_td_in_urb(td)) { ++ if ((urb->actual_length != urb->transfer_buffer_length && ++ (urb->transfer_flags & URB_SHORT_NOT_OK)) || ++ (*status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) ++ xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n", ++ urb, urb->actual_length, ++ urb->transfer_buffer_length, *status); ++ ++ /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */ ++ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ++ *status = 0; ++ xhci_giveback_urb_in_irq(xhci, td, *status); ++ } ++ ++ return 0; ++} ++ + static int xhci_reset_halted_ep(struct xhci_hcd *xhci, unsigned int slot_id, + unsigned int ep_index, enum xhci_ep_reset_type reset_type) + { +@@ -2013,52 +2059,6 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code) + return 0; + } + +-static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, +- struct xhci_ring *ep_ring, int *status) +-{ +- struct urb *urb = NULL; +- +- /* Clean up the endpoint's TD list */ +- urb = td->urb; +- +- /* if a bounce buffer was used to align this td then unmap it */ +- xhci_unmap_td_bounce_buffer(xhci, ep_ring, td); +- +- /* Do one last check of the actual transfer length. +- * If the host controller said we transferred more data than the buffer +- * length, urb->actual_length will be a very big number (since it's +- * unsigned). Play it safe and say we didn't transfer anything. +- */ +- if (urb->actual_length > urb->transfer_buffer_length) { +- xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n", +- urb->transfer_buffer_length, urb->actual_length); +- urb->actual_length = 0; +- *status = 0; +- } +- list_del_init(&td->td_list); +- /* Was this TD slated to be cancelled but completed anyway? */ +- if (!list_empty(&td->cancelled_td_list)) +- list_del_init(&td->cancelled_td_list); +- +- inc_td_cnt(urb); +- /* Giveback the urb when all the tds are completed */ +- if (last_td_in_urb(td)) { +- if ((urb->actual_length != urb->transfer_buffer_length && +- (urb->transfer_flags & URB_SHORT_NOT_OK)) || +- (*status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) +- xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n", +- urb, urb->actual_length, +- urb->transfer_buffer_length, *status); +- +- /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */ +- if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) +- *status = 0; +- xhci_giveback_urb_in_irq(xhci, td, *status); +- } +- +- return 0; +-} +- + static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_transfer_event *event, + struct xhci_virt_ep *ep, int *status) +-- +2.35.1 + diff --git a/queue-5.10/xhci-prevent-infinite-loop-in-transaction-errors-rec.patch b/queue-5.10/xhci-prevent-infinite-loop-in-transaction-errors-rec.patch new file mode 100644 index 00000000000..eb9ed58f854 --- /dev/null +++ b/queue-5.10/xhci-prevent-infinite-loop-in-transaction-errors-rec.patch @@ -0,0 +1,92 @@ +From ba0afe491497a64b38775963da0ab38854645c0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Nov 2022 11:19:43 +0200 +Subject: xhci: Prevent infinite loop in transaction errors recovery for + streams + +From: Mathias Nyman + +[ Upstream commit a1575120972ecd7baa6af6a69e4e7ea9213bde7c ] + +Make sure to also limit the amount of soft reset retries for transaction +errors on streams in cases where the transaction error event doesn't point +to any specific TRB. + +In these cases we don't know the TRB or stream ring, but we do know which +endpoint had the error. + +To keep error counting simple and functional, move the current err_count +from ring structure to endpoint structure. + +Cc: stable@vger.kernel.org +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20221130091944.2171610-6-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-ring.c | 14 ++++++++++---- + drivers/usb/host/xhci.h | 2 +- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index edb712081815..ead42fc3e16d 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -2349,7 +2349,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + + switch (trb_comp_code) { + case COMP_SUCCESS: +- ep_ring->err_count = 0; ++ ep->err_count = 0; + /* handle success with untransferred data as short packet */ + if (ep_trb != td->last_trb || remaining) { + xhci_warn(xhci, "WARN Successful completion on short TX\n"); +@@ -2375,7 +2375,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + break; + case COMP_USB_TRANSACTION_ERROR: + if (xhci->quirks & XHCI_NO_SOFT_RETRY || +- (ep_ring->err_count++ > MAX_SOFT_RETRY) || ++ (ep->err_count++ > MAX_SOFT_RETRY) || + le32_to_cpu(slot_ctx->tt_info) & TT_SLOT) + break; + +@@ -2457,8 +2457,14 @@ static int handle_tx_event(struct xhci_hcd *xhci, + case COMP_USB_TRANSACTION_ERROR: + case COMP_INVALID_STREAM_TYPE_ERROR: + case COMP_INVALID_STREAM_ID_ERROR: +- xhci_handle_halted_endpoint(xhci, ep, 0, NULL, +- EP_SOFT_RESET); ++ xhci_dbg(xhci, "Stream transaction error ep %u no id\n", ++ ep_index); ++ if (ep->err_count++ > MAX_SOFT_RETRY) ++ xhci_handle_halted_endpoint(xhci, ep, 0, NULL, ++ EP_HARD_RESET); ++ else ++ xhci_handle_halted_endpoint(xhci, ep, 0, NULL, ++ EP_SOFT_RESET); + goto cleanup; + case COMP_RING_UNDERRUN: + case COMP_RING_OVERRUN: +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index af3759928a95..ac09b171b783 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -933,6 +933,7 @@ struct xhci_virt_ep { + * have to restore the device state to the previous state + */ + struct xhci_ring *new_ring; ++ unsigned int err_count; + unsigned int ep_state; + #define SET_DEQ_PENDING (1 << 0) + #define EP_HALTED (1 << 1) /* For stall handling */ +@@ -1616,7 +1617,6 @@ struct xhci_ring { + * if we own the TRB (if we are the consumer). See section 4.9.1. + */ + u32 cycle_state; +- unsigned int err_count; + unsigned int stream_id; + unsigned int num_segs; + unsigned int num_trbs_free; +-- +2.35.1 + diff --git a/queue-5.10/xhci-store-td-status-in-the-td-struct-instead-of-pas.patch b/queue-5.10/xhci-store-td-status-in-the-td-struct-instead-of-pas.patch new file mode 100644 index 00000000000..1487043fe72 --- /dev/null +++ b/queue-5.10/xhci-store-td-status-in-the-td-struct-instead-of-pas.patch @@ -0,0 +1,237 @@ +From 277f9eaf444bd3bf8606c49f1bad39c45898d561 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 15:00:35 +0200 +Subject: xhci: store TD status in the td struct instead of passing it along + +From: Mathias Nyman + +[ Upstream commit a6ccd1fd4bd4fca37eaa3d76bef940d6332919bc ] + +In cases where the TD can't be given back in current handler we want +to be able to store it until its time to return the TD. + +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20210129130044.206855-19-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a1575120972e ("xhci: Prevent infinite loop in transaction errors recovery for streams") +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-ring.c | 56 +++++++++++++++++++----------------- + drivers/usb/host/xhci.h | 1 + + 2 files changed, 30 insertions(+), 27 deletions(-) + +diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c +index d523cbe7fcf1..2bd407ff9f0b 100644 +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -774,7 +774,7 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, + } + + static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, +- struct xhci_ring *ep_ring, int *status) ++ struct xhci_ring *ep_ring, int status) + { + struct urb *urb = NULL; + +@@ -793,7 +793,7 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, + xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n", + urb->transfer_buffer_length, urb->actual_length); + urb->actual_length = 0; +- *status = 0; ++ status = 0; + } + list_del_init(&td->td_list); + /* Was this TD slated to be cancelled but completed anyway? */ +@@ -805,15 +805,15 @@ static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, + if (last_td_in_urb(td)) { + if ((urb->actual_length != urb->transfer_buffer_length && + (urb->transfer_flags & URB_SHORT_NOT_OK)) || +- (*status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) ++ (status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) + xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n", + urb, urb->actual_length, +- urb->transfer_buffer_length, *status); ++ urb->transfer_buffer_length, status); + + /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) +- *status = 0; +- xhci_giveback_urb_in_irq(xhci, td, *status); ++ status = 0; ++ xhci_giveback_urb_in_irq(xhci, td, status); + } + + return 0; +@@ -2060,8 +2060,7 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code) + } + + static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, +- struct xhci_transfer_event *event, +- struct xhci_virt_ep *ep, int *status) ++ struct xhci_transfer_event *event, struct xhci_virt_ep *ep) + { + struct xhci_ep_ctx *ep_ctx; + struct xhci_ring *ep_ring; +@@ -2104,7 +2103,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, + inc_deq(xhci, ep_ring); + } + +- return xhci_td_cleanup(xhci, td, ep_ring, status); ++ return xhci_td_cleanup(xhci, td, ep_ring, td->status); + } + + /* sum trb lengths from ring dequeue up to stop_trb, _excluding_ stop_trb */ +@@ -2127,7 +2126,7 @@ static int sum_trb_lengths(struct xhci_hcd *xhci, struct xhci_ring *ring, + */ + static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + union xhci_trb *ep_trb, struct xhci_transfer_event *event, +- struct xhci_virt_ep *ep, int *status) ++ struct xhci_virt_ep *ep) + { + struct xhci_ep_ctx *ep_ctx; + u32 trb_comp_code; +@@ -2145,13 +2144,13 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + if (trb_type != TRB_STATUS) { + xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n", + (trb_type == TRB_DATA) ? "data" : "setup"); +- *status = -ESHUTDOWN; ++ td->status = -ESHUTDOWN; + break; + } +- *status = 0; ++ td->status = 0; + break; + case COMP_SHORT_PACKET: +- *status = 0; ++ td->status = 0; + break; + case COMP_STOPPED_SHORT_PACKET: + if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) +@@ -2215,7 +2214,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + td->urb->actual_length = requested; + + finish_td: +- return finish_td(xhci, td, event, ep, status); ++ return finish_td(xhci, td, event, ep); + } + + /* +@@ -2223,7 +2222,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, + */ + static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + union xhci_trb *ep_trb, struct xhci_transfer_event *event, +- struct xhci_virt_ep *ep, int *status) ++ struct xhci_virt_ep *ep) + { + struct urb_priv *urb_priv; + int idx; +@@ -2300,11 +2299,11 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + + td->urb->actual_length += frame->actual_length; + +- return finish_td(xhci, td, event, ep, status); ++ return finish_td(xhci, td, event, ep); + } + + static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, +- struct xhci_virt_ep *ep, int *status) ++ struct xhci_virt_ep *ep, int status) + { + struct urb_priv *urb_priv; + struct usb_iso_packet_descriptor *frame; +@@ -2333,7 +2332,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + */ + static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + union xhci_trb *ep_trb, struct xhci_transfer_event *event, +- struct xhci_virt_ep *ep, int *status) ++ struct xhci_virt_ep *ep) + { + struct xhci_slot_ctx *slot_ctx; + struct xhci_ring *ep_ring; +@@ -2357,13 +2356,13 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + td->urb->ep->desc.bEndpointAddress, + requested, remaining); + } +- *status = 0; ++ td->status = 0; + break; + case COMP_SHORT_PACKET: + xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n", + td->urb->ep->desc.bEndpointAddress, + requested, remaining); +- *status = 0; ++ td->status = 0; + break; + case COMP_STOPPED_SHORT_PACKET: + td->urb->actual_length = remaining; +@@ -2378,7 +2377,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + (ep_ring->err_count++ > MAX_SOFT_RETRY) || + le32_to_cpu(slot_ctx->tt_info) & TT_SLOT) + break; +- *status = 0; ++ ++ td->status = 0; + xhci_cleanup_halted_endpoint(xhci, ep, ep_ring->stream_id, td, + EP_SOFT_RESET); + return 0; +@@ -2399,7 +2399,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, + remaining); + td->urb->actual_length = 0; + } +- return finish_td(xhci, td, event, ep, status); ++ return finish_td(xhci, td, event, ep); + } + + /* +@@ -2701,7 +2701,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, + return -ESHUTDOWN; + } + +- skip_isoc_td(xhci, td, ep, &status); ++ skip_isoc_td(xhci, td, ep, status); + goto cleanup; + } + if (trb_comp_code == COMP_SHORT_PACKET) +@@ -2729,6 +2729,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, + * endpoint. Otherwise, the endpoint remains stalled + * indefinitely. + */ ++ + if (trb_is_noop(ep_trb)) { + if (trb_comp_code == COMP_STALL_ERROR || + xhci_requires_manual_halt_cleanup(xhci, ep_ctx, +@@ -2739,14 +2740,15 @@ static int handle_tx_event(struct xhci_hcd *xhci, + goto cleanup; + } + ++ td->status = status; ++ + /* update the urb's actual_length and give back to the core */ + if (usb_endpoint_xfer_control(&td->urb->ep->desc)) +- process_ctrl_td(xhci, td, ep_trb, event, ep, &status); ++ process_ctrl_td(xhci, td, ep_trb, event, ep); + else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc)) +- process_isoc_td(xhci, td, ep_trb, event, ep, &status); ++ process_isoc_td(xhci, td, ep_trb, event, ep); + else +- process_bulk_intr_td(xhci, td, ep_trb, event, ep, +- &status); ++ process_bulk_intr_td(xhci, td, ep_trb, event, ep); + cleanup: + handling_skipped_tds = ep->skip && + trb_comp_code != COMP_MISSED_SERVICE_ERROR && +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 9cbf106fb3ee..af3759928a95 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1544,6 +1544,7 @@ struct xhci_segment { + struct xhci_td { + struct list_head td_list; + struct list_head cancelled_td_list; ++ int status; + struct urb *urb; + struct xhci_segment *start_seg; + union xhci_trb *first_trb; +-- +2.35.1 +