From: Greg Kroah-Hartman Date: Mon, 8 Feb 2021 10:27:01 +0000 (+0100) Subject: 5.4-stable patches X-Git-Tag: v4.4.257~33 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=06ea0672182e772115d054a211b9e9d4930efcef;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: cifs-report-error-instead-of-invalid-when-revalidating-a-dentry-fails.patch fgraph-initialize-tracing_graph_pause-at-task-creation.patch genirq-msi-activate-multi-msi-early-when-msi_flag_activate_early-is-set.patch kretprobe-avoid-re-registration-of-the-same-kretprobe-earlier.patch libnvdimm-dimm-avoid-race-between-probe-and-available_slots_show.patch mac80211-fix-station-rate-table-updates-on-assoc.patch ovl-fix-dentry-leak-in-ovl_get_redirect.patch usb-dwc2-fix-endpoint-direction-check-in-ep_from_windex.patch usb-dwc3-fix-clock-issue-during-resume-in-otg-mode.patch usb-gadget-legacy-fix-an-error-code-in-eth_bind.patch usb-host-xhci-plat-add-priv-quirk-for-skip-phy-initialization.patch usb-renesas_usbhs-clear-pipe-running-flag-in-usbhs_pkt_pop.patch usb-usblp-don-t-call-usb_set_interface-if-there-s-a-single-alt.patch usb-xhci-mtk-break-loop-when-find-the-endpoint-to-drop.patch usb-xhci-mtk-fix-unreleased-bandwidth-data.patch usb-xhci-mtk-skip-dropping-bandwidth-of-unchecked-endpoints.patch xhci-fix-bounce-buffer-usage-for-non-sg-list-case.patch --- diff --git a/queue-5.4/cifs-report-error-instead-of-invalid-when-revalidating-a-dentry-fails.patch b/queue-5.4/cifs-report-error-instead-of-invalid-when-revalidating-a-dentry-fails.patch new file mode 100644 index 00000000000..4015a11c5c6 --- /dev/null +++ b/queue-5.4/cifs-report-error-instead-of-invalid-when-revalidating-a-dentry-fails.patch @@ -0,0 +1,74 @@ +From 21b200d091826a83aafc95d847139b2b0582f6d1 Mon Sep 17 00:00:00 2001 +From: Aurelien Aptel +Date: Fri, 5 Feb 2021 15:42:48 +0100 +Subject: cifs: report error instead of invalid when revalidating a dentry fails + +From: Aurelien Aptel + +commit 21b200d091826a83aafc95d847139b2b0582f6d1 upstream. + +Assuming +- //HOST/a is mounted on /mnt +- //HOST/b is mounted on /mnt/b + +On a slow connection, running 'df' and killing it while it's +processing /mnt/b can make cifs_get_inode_info() returns -ERESTARTSYS. + +This triggers the following chain of events: +=> the dentry revalidation fail +=> dentry is put and released +=> superblock associated with the dentry is put +=> /mnt/b is unmounted + +This patch makes cifs_d_revalidate() return the error instead of 0 +(invalid) when cifs_revalidate_dentry() fails, except for ENOENT (file +deleted) and ESTALE (file recreated). + +Signed-off-by: Aurelien Aptel +Suggested-by: Shyam Prasad N +Reviewed-by: Shyam Prasad N +CC: stable@vger.kernel.org +Signed-off-by: Steve French +Signed-off-by: Greg Kroah-Hartman +--- + fs/cifs/dir.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +--- a/fs/cifs/dir.c ++++ b/fs/cifs/dir.c +@@ -738,6 +738,7 @@ static int + cifs_d_revalidate(struct dentry *direntry, unsigned int flags) + { + struct inode *inode; ++ int rc; + + if (flags & LOOKUP_RCU) + return -ECHILD; +@@ -747,8 +748,25 @@ cifs_d_revalidate(struct dentry *direntr + if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode))) + CIFS_I(inode)->time = 0; /* force reval */ + +- if (cifs_revalidate_dentry(direntry)) +- return 0; ++ rc = cifs_revalidate_dentry(direntry); ++ if (rc) { ++ cifs_dbg(FYI, "cifs_revalidate_dentry failed with rc=%d", rc); ++ switch (rc) { ++ case -ENOENT: ++ case -ESTALE: ++ /* ++ * Those errors mean the dentry is invalid ++ * (file was deleted or recreated) ++ */ ++ return 0; ++ default: ++ /* ++ * Otherwise some unexpected error happened ++ * report it as-is to VFS layer ++ */ ++ return rc; ++ } ++ } + else { + /* + * If the inode wasn't known to be a dfs entry when diff --git a/queue-5.4/fgraph-initialize-tracing_graph_pause-at-task-creation.patch b/queue-5.4/fgraph-initialize-tracing_graph_pause-at-task-creation.patch new file mode 100644 index 00000000000..ba5717aef1b --- /dev/null +++ b/queue-5.4/fgraph-initialize-tracing_graph_pause-at-task-creation.patch @@ -0,0 +1,82 @@ +From 7e0a9220467dbcfdc5bc62825724f3e52e50ab31 Mon Sep 17 00:00:00 2001 +From: "Steven Rostedt (VMware)" +Date: Fri, 29 Jan 2021 10:13:53 -0500 +Subject: fgraph: Initialize tracing_graph_pause at task creation + +From: Steven Rostedt (VMware) + +commit 7e0a9220467dbcfdc5bc62825724f3e52e50ab31 upstream. + +On some archs, the idle task can call into cpu_suspend(). The cpu_suspend() +will disable or pause function graph tracing, as there's some paths in +bringing down the CPU that can have issues with its return address being +modified. The task_struct structure has a "tracing_graph_pause" atomic +counter, that when set to something other than zero, the function graph +tracer will not modify the return address. + +The problem is that the tracing_graph_pause counter is initialized when the +function graph tracer is enabled. This can corrupt the counter for the idle +task if it is suspended in these architectures. + + CPU 1 CPU 2 + ----- ----- + do_idle() + cpu_suspend() + pause_graph_tracing() + task_struct->tracing_graph_pause++ (0 -> 1) + + start_graph_tracing() + for_each_online_cpu(cpu) { + ftrace_graph_init_idle_task(cpu) + task-struct->tracing_graph_pause = 0 (1 -> 0) + + unpause_graph_tracing() + task_struct->tracing_graph_pause-- (0 -> -1) + +The above should have gone from 1 to zero, and enabled function graph +tracing again. But instead, it is set to -1, which keeps it disabled. + +There's no reason that the field tracing_graph_pause on the task_struct can +not be initialized at boot up. + +Cc: stable@vger.kernel.org +Fixes: 380c4b1411ccd ("tracing/function-graph-tracer: append the tracing_graph_flag") +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=211339 +Reported-by: pierre.gondois@arm.com +Signed-off-by: Steven Rostedt (VMware) +Signed-off-by: Greg Kroah-Hartman +--- + init/init_task.c | 3 ++- + kernel/trace/fgraph.c | 2 -- + 2 files changed, 2 insertions(+), 3 deletions(-) + +--- a/init/init_task.c ++++ b/init/init_task.c +@@ -171,7 +171,8 @@ struct task_struct init_task + .lockdep_recursion = 0, + #endif + #ifdef CONFIG_FUNCTION_GRAPH_TRACER +- .ret_stack = NULL, ++ .ret_stack = NULL, ++ .tracing_graph_pause = ATOMIC_INIT(0), + #endif + #if defined(CONFIG_TRACING) && defined(CONFIG_PREEMPTION) + .trace_recursion = 0, +--- a/kernel/trace/fgraph.c ++++ b/kernel/trace/fgraph.c +@@ -367,7 +367,6 @@ static int alloc_retstack_tasklist(struc + } + + if (t->ret_stack == NULL) { +- atomic_set(&t->tracing_graph_pause, 0); + atomic_set(&t->trace_overrun, 0); + t->curr_ret_stack = -1; + t->curr_ret_depth = -1; +@@ -462,7 +461,6 @@ static DEFINE_PER_CPU(struct ftrace_ret_ + static void + graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack) + { +- atomic_set(&t->tracing_graph_pause, 0); + atomic_set(&t->trace_overrun, 0); + t->ftrace_timestamp = 0; + /* make curr_ret_stack visible before we add the ret_stack */ diff --git a/queue-5.4/genirq-msi-activate-multi-msi-early-when-msi_flag_activate_early-is-set.patch b/queue-5.4/genirq-msi-activate-multi-msi-early-when-msi_flag_activate_early-is-set.patch new file mode 100644 index 00000000000..453be016415 --- /dev/null +++ b/queue-5.4/genirq-msi-activate-multi-msi-early-when-msi_flag_activate_early-is-set.patch @@ -0,0 +1,123 @@ +From 4c457e8cb75eda91906a4f89fc39bde3f9a43922 Mon Sep 17 00:00:00 2001 +From: Marc Zyngier +Date: Sat, 23 Jan 2021 12:27:59 +0000 +Subject: genirq/msi: Activate Multi-MSI early when MSI_FLAG_ACTIVATE_EARLY is set + +From: Marc Zyngier + +commit 4c457e8cb75eda91906a4f89fc39bde3f9a43922 upstream. + +When MSI_FLAG_ACTIVATE_EARLY is set (which is the case for PCI), +__msi_domain_alloc_irqs() performs the activation of the interrupt (which +in the case of PCI results in the endpoint being programmed) as soon as the +interrupt is allocated. + +But it appears that this is only done for the first vector, introducing an +inconsistent behaviour for PCI Multi-MSI. + +Fix it by iterating over the number of vectors allocated to each MSI +descriptor. This is easily achieved by introducing a new +"for_each_msi_vector" iterator, together with a tiny bit of refactoring. + +Fixes: f3b0946d629c ("genirq/msi: Make sure PCI MSIs are activated early") +Reported-by: Shameer Kolothum +Signed-off-by: Marc Zyngier +Signed-off-by: Thomas Gleixner +Tested-by: Shameer Kolothum +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/20210123122759.1781359-1-maz@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/msi.h | 6 ++++++ + kernel/irq/msi.c | 44 ++++++++++++++++++++------------------------ + 2 files changed, 26 insertions(+), 24 deletions(-) + +--- a/include/linux/msi.h ++++ b/include/linux/msi.h +@@ -139,6 +139,12 @@ struct msi_desc { + list_for_each_entry((desc), dev_to_msi_list((dev)), list) + #define for_each_msi_entry_safe(desc, tmp, dev) \ + list_for_each_entry_safe((desc), (tmp), dev_to_msi_list((dev)), list) ++#define for_each_msi_vector(desc, __irq, dev) \ ++ for_each_msi_entry((desc), (dev)) \ ++ if ((desc)->irq) \ ++ for (__irq = (desc)->irq; \ ++ __irq < ((desc)->irq + (desc)->nvec_used); \ ++ __irq++) + + #ifdef CONFIG_IRQ_MSI_IOMMU + static inline const void *msi_desc_get_iommu_cookie(struct msi_desc *desc) +--- a/kernel/irq/msi.c ++++ b/kernel/irq/msi.c +@@ -437,22 +437,22 @@ int msi_domain_alloc_irqs(struct irq_dom + + can_reserve = msi_check_reservation_mode(domain, info, dev); + +- for_each_msi_entry(desc, dev) { +- virq = desc->irq; +- if (desc->nvec_used == 1) +- dev_dbg(dev, "irq %d for MSI\n", virq); +- else ++ /* ++ * This flag is set by the PCI layer as we need to activate ++ * the MSI entries before the PCI layer enables MSI in the ++ * card. Otherwise the card latches a random msi message. ++ */ ++ if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY)) ++ goto skip_activate; ++ ++ for_each_msi_vector(desc, i, dev) { ++ if (desc->irq == i) { ++ virq = desc->irq; + dev_dbg(dev, "irq [%d-%d] for MSI\n", + virq, virq + desc->nvec_used - 1); +- /* +- * This flag is set by the PCI layer as we need to activate +- * the MSI entries before the PCI layer enables MSI in the +- * card. Otherwise the card latches a random msi message. +- */ +- if (!(info->flags & MSI_FLAG_ACTIVATE_EARLY)) +- continue; ++ } + +- irq_data = irq_domain_get_irq_data(domain, desc->irq); ++ irq_data = irq_domain_get_irq_data(domain, i); + if (!can_reserve) { + irqd_clr_can_reserve(irq_data); + if (domain->flags & IRQ_DOMAIN_MSI_NOMASK_QUIRK) +@@ -463,28 +463,24 @@ int msi_domain_alloc_irqs(struct irq_dom + goto cleanup; + } + ++skip_activate: + /* + * If these interrupts use reservation mode, clear the activated bit + * so request_irq() will assign the final vector. + */ + if (can_reserve) { +- for_each_msi_entry(desc, dev) { +- irq_data = irq_domain_get_irq_data(domain, desc->irq); ++ for_each_msi_vector(desc, i, dev) { ++ irq_data = irq_domain_get_irq_data(domain, i); + irqd_clr_activated(irq_data); + } + } + return 0; + + cleanup: +- for_each_msi_entry(desc, dev) { +- struct irq_data *irqd; +- +- if (desc->irq == virq) +- break; +- +- irqd = irq_domain_get_irq_data(domain, desc->irq); +- if (irqd_is_activated(irqd)) +- irq_domain_deactivate_irq(irqd); ++ for_each_msi_vector(desc, i, dev) { ++ irq_data = irq_domain_get_irq_data(domain, i); ++ if (irqd_is_activated(irq_data)) ++ irq_domain_deactivate_irq(irq_data); + } + msi_domain_free_irqs(domain, dev); + return ret; diff --git a/queue-5.4/kretprobe-avoid-re-registration-of-the-same-kretprobe-earlier.patch b/queue-5.4/kretprobe-avoid-re-registration-of-the-same-kretprobe-earlier.patch new file mode 100644 index 00000000000..b37f07506fe --- /dev/null +++ b/queue-5.4/kretprobe-avoid-re-registration-of-the-same-kretprobe-earlier.patch @@ -0,0 +1,52 @@ +From 0188b87899ffc4a1d36a0badbe77d56c92fd91dc Mon Sep 17 00:00:00 2001 +From: Wang ShaoBo +Date: Thu, 28 Jan 2021 20:44:27 +0800 +Subject: kretprobe: Avoid re-registration of the same kretprobe earlier + +From: Wang ShaoBo + +commit 0188b87899ffc4a1d36a0badbe77d56c92fd91dc upstream. + +Our system encountered a re-init error when re-registering same kretprobe, +where the kretprobe_instance in rp->free_instances is illegally accessed +after re-init. + +Implementation to avoid re-registration has been introduced for kprobe +before, but lags for register_kretprobe(). We must check if kprobe has +been re-registered before re-initializing kretprobe, otherwise it will +destroy the data struct of kretprobe registered, which can lead to memory +leak, system crash, also some unexpected behaviors. + +We use check_kprobe_rereg() to check if kprobe has been re-registered +before running register_kretprobe()'s body, for giving a warning message +and terminate registration process. + +Link: https://lkml.kernel.org/r/20210128124427.2031088-1-bobo.shaobowang@huawei.com + +Cc: stable@vger.kernel.org +Fixes: 1f0ab40976460 ("kprobes: Prevent re-registration of the same kprobe") +[ The above commit should have been done for kretprobes too ] +Acked-by: Naveen N. Rao +Acked-by: Ananth N Mavinakayanahalli +Acked-by: Masami Hiramatsu +Signed-off-by: Wang ShaoBo +Signed-off-by: Cheng Jian +Signed-off-by: Steven Rostedt (VMware) +Signed-off-by: Greg Kroah-Hartman +--- + kernel/kprobes.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/kernel/kprobes.c ++++ b/kernel/kprobes.c +@@ -1972,6 +1972,10 @@ int register_kretprobe(struct kretprobe + if (!kprobe_on_func_entry(rp->kp.addr, rp->kp.symbol_name, rp->kp.offset)) + return -EINVAL; + ++ /* If only rp->kp.addr is specified, check reregistering kprobes */ ++ if (rp->kp.addr && check_kprobe_rereg(&rp->kp)) ++ return -EINVAL; ++ + if (kretprobe_blacklist_size) { + addr = kprobe_addr(&rp->kp); + if (IS_ERR(addr)) diff --git a/queue-5.4/libnvdimm-dimm-avoid-race-between-probe-and-available_slots_show.patch b/queue-5.4/libnvdimm-dimm-avoid-race-between-probe-and-available_slots_show.patch new file mode 100644 index 00000000000..6be11ce1515 --- /dev/null +++ b/queue-5.4/libnvdimm-dimm-avoid-race-between-probe-and-available_slots_show.patch @@ -0,0 +1,96 @@ +From 7018c897c2f243d4b5f1b94bc6b4831a7eab80fb Mon Sep 17 00:00:00 2001 +From: Dan Williams +Date: Mon, 1 Feb 2021 16:20:40 -0800 +Subject: libnvdimm/dimm: Avoid race between probe and available_slots_show() + +From: Dan Williams + +commit 7018c897c2f243d4b5f1b94bc6b4831a7eab80fb upstream. + +Richard reports that the following test: + +(while true; do + cat /sys/bus/nd/devices/nmem*/available_slots 2>&1 > /dev/null + done) & + +while true; do + for i in $(seq 0 4); do + echo nmem$i > /sys/bus/nd/drivers/nvdimm/bind + done + for i in $(seq 0 4); do + echo nmem$i > /sys/bus/nd/drivers/nvdimm/unbind + done + done + +...fails with a crash signature like: + + divide error: 0000 [#1] SMP KASAN PTI + RIP: 0010:nd_label_nfree+0x134/0x1a0 [libnvdimm] + [..] + Call Trace: + available_slots_show+0x4e/0x120 [libnvdimm] + dev_attr_show+0x42/0x80 + ? memset+0x20/0x40 + sysfs_kf_seq_show+0x218/0x410 + +The root cause is that available_slots_show() consults driver-data, but +fails to synchronize against device-unbind setting up a TOCTOU race to +access uninitialized memory. + +Validate driver-data under the device-lock. + +Fixes: 4d88a97aa9e8 ("libnvdimm, nvdimm: dimm driver and base libnvdimm device-driver infrastructure") +Cc: +Cc: Vishal Verma +Cc: Dave Jiang +Cc: Ira Weiny +Cc: Coly Li +Reported-by: Richard Palethorpe +Acked-by: Richard Palethorpe +Signed-off-by: Dan Williams +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvdimm/dimm_devs.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +--- a/drivers/nvdimm/dimm_devs.c ++++ b/drivers/nvdimm/dimm_devs.c +@@ -344,16 +344,16 @@ static ssize_t state_show(struct device + } + static DEVICE_ATTR_RO(state); + +-static ssize_t available_slots_show(struct device *dev, +- struct device_attribute *attr, char *buf) ++static ssize_t __available_slots_show(struct nvdimm_drvdata *ndd, char *buf) + { +- struct nvdimm_drvdata *ndd = dev_get_drvdata(dev); ++ struct device *dev; + ssize_t rc; + u32 nfree; + + if (!ndd) + return -ENXIO; + ++ dev = ndd->dev; + nvdimm_bus_lock(dev); + nfree = nd_label_nfree(ndd); + if (nfree - 1 > nfree) { +@@ -365,6 +365,18 @@ static ssize_t available_slots_show(stru + nvdimm_bus_unlock(dev); + return rc; + } ++ ++static ssize_t available_slots_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ ssize_t rc; ++ ++ nd_device_lock(dev); ++ rc = __available_slots_show(dev_get_drvdata(dev), buf); ++ nd_device_unlock(dev); ++ ++ return rc; ++} + static DEVICE_ATTR_RO(available_slots); + + __weak ssize_t security_show(struct device *dev, diff --git a/queue-5.4/mac80211-fix-station-rate-table-updates-on-assoc.patch b/queue-5.4/mac80211-fix-station-rate-table-updates-on-assoc.patch new file mode 100644 index 00000000000..b03d4b311e8 --- /dev/null +++ b/queue-5.4/mac80211-fix-station-rate-table-updates-on-assoc.patch @@ -0,0 +1,51 @@ +From 18fe0fae61252b5ae6e26553e2676b5fac555951 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Mon, 1 Feb 2021 09:33:24 +0100 +Subject: mac80211: fix station rate table updates on assoc + +From: Felix Fietkau + +commit 18fe0fae61252b5ae6e26553e2676b5fac555951 upstream. + +If the driver uses .sta_add, station entries are only uploaded after the sta +is in assoc state. Fix early station rate table updates by deferring them +until the sta has been uploaded. + +Cc: stable@vger.kernel.org +Signed-off-by: Felix Fietkau +Link: https://lore.kernel.org/r/20210201083324.3134-1-nbd@nbd.name +[use rcu_access_pointer() instead since we won't dereference here] +Signed-off-by: Johannes Berg +Signed-off-by: Greg Kroah-Hartman +--- + net/mac80211/driver-ops.c | 5 ++++- + net/mac80211/rate.c | 3 ++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +--- a/net/mac80211/driver-ops.c ++++ b/net/mac80211/driver-ops.c +@@ -125,8 +125,11 @@ int drv_sta_state(struct ieee80211_local + } else if (old_state == IEEE80211_STA_AUTH && + new_state == IEEE80211_STA_ASSOC) { + ret = drv_sta_add(local, sdata, &sta->sta); +- if (ret == 0) ++ if (ret == 0) { + sta->uploaded = true; ++ if (rcu_access_pointer(sta->sta.rates)) ++ drv_sta_rate_tbl_update(local, sdata, &sta->sta); ++ } + } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) { + drv_sta_remove(local, sdata, &sta->sta); +--- a/net/mac80211/rate.c ++++ b/net/mac80211/rate.c +@@ -934,7 +934,8 @@ int rate_control_set_rates(struct ieee80 + if (old) + kfree_rcu(old, rcu_head); + +- drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta); ++ if (sta->uploaded) ++ drv_sta_rate_tbl_update(hw_to_local(hw), sta->sdata, pubsta); + + ieee80211_sta_set_expected_throughput(pubsta, sta_get_expected_throughput(sta)); + diff --git a/queue-5.4/ovl-fix-dentry-leak-in-ovl_get_redirect.patch b/queue-5.4/ovl-fix-dentry-leak-in-ovl_get_redirect.patch new file mode 100644 index 00000000000..778729a81c8 --- /dev/null +++ b/queue-5.4/ovl-fix-dentry-leak-in-ovl_get_redirect.patch @@ -0,0 +1,91 @@ +From e04527fefba6e4e66492f122cf8cc6314f3cf3bf Mon Sep 17 00:00:00 2001 +From: Liangyan +Date: Tue, 22 Dec 2020 11:06:26 +0800 +Subject: ovl: fix dentry leak in ovl_get_redirect +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Liangyan + +commit e04527fefba6e4e66492f122cf8cc6314f3cf3bf upstream. + +We need to lock d_parent->d_lock before dget_dlock, or this may +have d_lockref updated parallelly like calltrace below which will +cause dentry->d_lockref leak and risk a crash. + + CPU 0 CPU 1 +ovl_set_redirect lookup_fast + ovl_get_redirect __d_lookup + dget_dlock + //no lock protection here spin_lock(&dentry->d_lock) + dentry->d_lockref.count++ dentry->d_lockref.count++ + +[   49.799059] PGD 800000061fed7067 P4D 800000061fed7067 PUD 61fec5067 PMD 0 +[   49.799689] Oops: 0002 [#1] SMP PTI +[   49.800019] CPU: 2 PID: 2332 Comm: node Not tainted 4.19.24-7.20.al7.x86_64 #1 +[   49.800678] Hardware name: Alibaba Cloud Alibaba Cloud ECS, BIOS 8a46cfe 04/01/2014 +[   49.801380] RIP: 0010:_raw_spin_lock+0xc/0x20 +[   49.803470] RSP: 0018:ffffac6fc5417e98 EFLAGS: 00010246 +[   49.803949] RAX: 0000000000000000 RBX: ffff93b8da3446c0 RCX: 0000000a00000000 +[   49.804600] RDX: 0000000000000001 RSI: 000000000000000a RDI: 0000000000000088 +[   49.805252] RBP: 0000000000000000 R08: 0000000000000000 R09: ffffffff993cf040 +[   49.805898] R10: ffff93b92292e580 R11: ffffd27f188a4b80 R12: 0000000000000000 +[   49.806548] R13: 00000000ffffff9c R14: 00000000fffffffe R15: ffff93b8da3446c0 +[   49.807200] FS:  00007ffbedffb700(0000) GS:ffff93b927880000(0000) knlGS:0000000000000000 +[   49.807935] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[   49.808461] CR2: 0000000000000088 CR3: 00000005e3f74006 CR4: 00000000003606a0 +[   49.809113] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[   49.809758] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 +[   49.810410] Call Trace: +[   49.810653]  d_delete+0x2c/0xb0 +[   49.810951]  vfs_rmdir+0xfd/0x120 +[   49.811264]  do_rmdir+0x14f/0x1a0 +[   49.811573]  do_syscall_64+0x5b/0x190 +[   49.811917]  entry_SYSCALL_64_after_hwframe+0x44/0xa9 +[   49.812385] RIP: 0033:0x7ffbf505ffd7 +[   49.814404] RSP: 002b:00007ffbedffada8 EFLAGS: 00000297 ORIG_RAX: 0000000000000054 +[   49.815098] RAX: ffffffffffffffda RBX: 00007ffbedffb640 RCX: 00007ffbf505ffd7 +[   49.815744] RDX: 0000000004449700 RSI: 0000000000000000 RDI: 0000000006c8cd50 +[   49.816394] RBP: 00007ffbedffaea0 R08: 0000000000000000 R09: 0000000000017d0b +[   49.817038] R10: 0000000000000000 R11: 0000000000000297 R12: 0000000000000012 +[   49.817687] R13: 00000000072823d8 R14: 00007ffbedffb700 R15: 00000000072823d8 +[   49.818338] Modules linked in: pvpanic cirrusfb button qemu_fw_cfg atkbd libps2 i8042 +[   49.819052] CR2: 0000000000000088 +[   49.819368] ---[ end trace 4e652b8aa299aa2d ]--- +[   49.819796] RIP: 0010:_raw_spin_lock+0xc/0x20 +[   49.821880] RSP: 0018:ffffac6fc5417e98 EFLAGS: 00010246 +[   49.822363] RAX: 0000000000000000 RBX: ffff93b8da3446c0 RCX: 0000000a00000000 +[   49.823008] RDX: 0000000000000001 RSI: 000000000000000a RDI: 0000000000000088 +[   49.823658] RBP: 0000000000000000 R08: 0000000000000000 R09: ffffffff993cf040 +[   49.825404] R10: ffff93b92292e580 R11: ffffd27f188a4b80 R12: 0000000000000000 +[   49.827147] R13: 00000000ffffff9c R14: 00000000fffffffe R15: ffff93b8da3446c0 +[   49.828890] FS:  00007ffbedffb700(0000) GS:ffff93b927880000(0000) knlGS:0000000000000000 +[   49.830725] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[   49.832359] CR2: 0000000000000088 CR3: 00000005e3f74006 CR4: 00000000003606a0 +[   49.834085] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 +[   49.835792] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 + +Cc: +Fixes: a6c606551141 ("ovl: redirect on rename-dir") +Signed-off-by: Liangyan +Reviewed-by: Joseph Qi +Suggested-by: Al Viro +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman +--- + fs/overlayfs/dir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/overlayfs/dir.c ++++ b/fs/overlayfs/dir.c +@@ -940,8 +940,8 @@ static char *ovl_get_redirect(struct den + + buflen -= thislen; + memcpy(&buf[buflen], name, thislen); +- tmp = dget_dlock(d->d_parent); + spin_unlock(&d->d_lock); ++ tmp = dget_parent(d); + + dput(d); + d = tmp; diff --git a/queue-5.4/series b/queue-5.4/series index 285dae03115..e3f30cc18d3 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -20,3 +20,20 @@ r8169-fix-wol-on-shutdown-if-config_debug_shirq-is-s.patch arm-dts-sun7i-a20-bananapro-fix-ethernet-phy-mode.patch nvmet-tcp-fix-out-of-bounds-access-when-receiving-mu.patch memblock-do-not-start-bottom-up-allocations-with-ker.patch +usb-gadget-legacy-fix-an-error-code-in-eth_bind.patch +usb-usblp-don-t-call-usb_set_interface-if-there-s-a-single-alt.patch +usb-renesas_usbhs-clear-pipe-running-flag-in-usbhs_pkt_pop.patch +usb-dwc2-fix-endpoint-direction-check-in-ep_from_windex.patch +usb-dwc3-fix-clock-issue-during-resume-in-otg-mode.patch +usb-xhci-mtk-fix-unreleased-bandwidth-data.patch +usb-xhci-mtk-skip-dropping-bandwidth-of-unchecked-endpoints.patch +usb-xhci-mtk-break-loop-when-find-the-endpoint-to-drop.patch +usb-host-xhci-plat-add-priv-quirk-for-skip-phy-initialization.patch +ovl-fix-dentry-leak-in-ovl_get_redirect.patch +mac80211-fix-station-rate-table-updates-on-assoc.patch +fgraph-initialize-tracing_graph_pause-at-task-creation.patch +kretprobe-avoid-re-registration-of-the-same-kretprobe-earlier.patch +libnvdimm-dimm-avoid-race-between-probe-and-available_slots_show.patch +genirq-msi-activate-multi-msi-early-when-msi_flag_activate_early-is-set.patch +xhci-fix-bounce-buffer-usage-for-non-sg-list-case.patch +cifs-report-error-instead-of-invalid-when-revalidating-a-dentry-fails.patch diff --git a/queue-5.4/usb-dwc2-fix-endpoint-direction-check-in-ep_from_windex.patch b/queue-5.4/usb-dwc2-fix-endpoint-direction-check-in-ep_from_windex.patch new file mode 100644 index 00000000000..e5418f49fe5 --- /dev/null +++ b/queue-5.4/usb-dwc2-fix-endpoint-direction-check-in-ep_from_windex.patch @@ -0,0 +1,74 @@ +From f670e9f9c8cac716c3506c6bac9e997b27ad441a Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Wed, 27 Jan 2021 11:39:19 +0100 +Subject: usb: dwc2: Fix endpoint direction check in ep_from_windex + +From: Heiko Stuebner + +commit f670e9f9c8cac716c3506c6bac9e997b27ad441a upstream. + +dwc2_hsotg_process_req_status uses ep_from_windex() to retrieve +the endpoint for the index provided in the wIndex request param. + +In a test-case with a rndis gadget running and sending a malformed +packet to it like: + dev.ctrl_transfer( + 0x82, # bmRequestType + 0x00, # bRequest + 0x0000, # wValue + 0x0001, # wIndex + 0x00 # wLength + ) +it is possible to cause a crash: + +[ 217.533022] dwc2 ff300000.usb: dwc2_hsotg_process_req_status: USB_REQ_GET_STATUS +[ 217.559003] Unable to handle kernel read from unreadable memory at virtual address 0000000000000088 +... +[ 218.313189] Call trace: +[ 218.330217] ep_from_windex+0x3c/0x54 +[ 218.348565] usb_gadget_giveback_request+0x10/0x20 +[ 218.368056] dwc2_hsotg_complete_request+0x144/0x184 + +This happens because ep_from_windex wants to compare the endpoint +direction even if index_to_ep() didn't return an endpoint due to +the direction not matching. + +The fix is easy insofar that the actual direction check is already +happening when calling index_to_ep() which will return NULL if there +is no endpoint for the targeted direction, so the offending check +can go away completely. + +Fixes: c6f5c050e2a7 ("usb: dwc2: gadget: add bi-directional endpoint support") +Cc: stable@vger.kernel.org +Reported-by: Gerhard Klostermeier +Signed-off-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20210127103919.58215-1-heiko@sntech.de +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc2/gadget.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +--- a/drivers/usb/dwc2/gadget.c ++++ b/drivers/usb/dwc2/gadget.c +@@ -1543,7 +1543,6 @@ static void dwc2_hsotg_complete_oursetup + static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, + u32 windex) + { +- struct dwc2_hsotg_ep *ep; + int dir = (windex & USB_DIR_IN) ? 1 : 0; + int idx = windex & 0x7F; + +@@ -1553,12 +1552,7 @@ static struct dwc2_hsotg_ep *ep_from_win + if (idx > hsotg->num_of_eps) + return NULL; + +- ep = index_to_ep(hsotg, idx, dir); +- +- if (idx && ep->dir_in != dir) +- return NULL; +- +- return ep; ++ return index_to_ep(hsotg, idx, dir); + } + + /** diff --git a/queue-5.4/usb-dwc3-fix-clock-issue-during-resume-in-otg-mode.patch b/queue-5.4/usb-dwc3-fix-clock-issue-during-resume-in-otg-mode.patch new file mode 100644 index 00000000000..977a59962f6 --- /dev/null +++ b/queue-5.4/usb-dwc3-fix-clock-issue-during-resume-in-otg-mode.patch @@ -0,0 +1,41 @@ +From 0e5a3c8284a30f4c43fd81d7285528ece74563b5 Mon Sep 17 00:00:00 2001 +From: Gary Bisson +Date: Mon, 25 Jan 2021 17:19:34 +0100 +Subject: usb: dwc3: fix clock issue during resume in OTG mode + +From: Gary Bisson + +commit 0e5a3c8284a30f4c43fd81d7285528ece74563b5 upstream. + +Commit fe8abf332b8f ("usb: dwc3: support clocks and resets for DWC3 +core") introduced clock support and a new function named +dwc3_core_init_for_resume() which enables the clock before calling +dwc3_core_init() during resume as clocks get disabled during suspend. + +Unfortunately in this commit the DWC3_GCTL_PRTCAP_OTG case was forgotten +and therefore during resume, a platform could call dwc3_core_init() +without re-enabling the clocks first, preventing to resume properly. + +So update the resume path to call dwc3_core_init_for_resume() as it +should. + +Fixes: fe8abf332b8f ("usb: dwc3: support clocks and resets for DWC3 core") +Cc: stable@vger.kernel.org +Signed-off-by: Gary Bisson +Link: https://lore.kernel.org/r/20210125161934.527820-1-gary.bisson@boundarydevices.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/dwc3/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -1718,7 +1718,7 @@ static int dwc3_resume_common(struct dwc + if (PMSG_IS_AUTO(msg)) + break; + +- ret = dwc3_core_init(dwc); ++ ret = dwc3_core_init_for_resume(dwc); + if (ret) + return ret; + diff --git a/queue-5.4/usb-gadget-legacy-fix-an-error-code-in-eth_bind.patch b/queue-5.4/usb-gadget-legacy-fix-an-error-code-in-eth_bind.patch new file mode 100644 index 00000000000..b17f71a998c --- /dev/null +++ b/queue-5.4/usb-gadget-legacy-fix-an-error-code-in-eth_bind.patch @@ -0,0 +1,35 @@ +From 3e1f4a2e1184ae6ad7f4caf682ced9554141a0f4 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Thu, 28 Jan 2021 12:33:42 +0300 +Subject: USB: gadget: legacy: fix an error code in eth_bind() + +From: Dan Carpenter + +commit 3e1f4a2e1184ae6ad7f4caf682ced9554141a0f4 upstream. + +This code should return -ENOMEM if the allocation fails but it currently +returns success. + +Fixes: 9b95236eebdb ("usb: gadget: ether: allocate and init otg descriptor by otg capabilities") +Signed-off-by: Dan Carpenter +Link: https://lore.kernel.org/r/YBKE9rqVuJEOUWpW@mwanda +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/gadget/legacy/ether.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/gadget/legacy/ether.c ++++ b/drivers/usb/gadget/legacy/ether.c +@@ -403,8 +403,10 @@ static int eth_bind(struct usb_composite + struct usb_descriptor_header *usb_desc; + + usb_desc = usb_otg_descriptor_alloc(gadget); +- if (!usb_desc) ++ if (!usb_desc) { ++ status = -ENOMEM; + goto fail1; ++ } + usb_otg_descriptor_init(gadget, usb_desc); + otg_desc[0] = usb_desc; + otg_desc[1] = NULL; diff --git a/queue-5.4/usb-host-xhci-plat-add-priv-quirk-for-skip-phy-initialization.patch b/queue-5.4/usb-host-xhci-plat-add-priv-quirk-for-skip-phy-initialization.patch new file mode 100644 index 00000000000..08ff8e6df4c --- /dev/null +++ b/queue-5.4/usb-host-xhci-plat-add-priv-quirk-for-skip-phy-initialization.patch @@ -0,0 +1,64 @@ +From f768e718911e03a4a20b65f984eaa9b09045e4cd Mon Sep 17 00:00:00 2001 +From: Peter Chen +Date: Fri, 18 Sep 2020 16:17:46 +0300 +Subject: usb: host: xhci-plat: add priv quirk for skip PHY initialization + +From: Peter Chen + +commit f768e718911e03a4a20b65f984eaa9b09045e4cd upstream. + +Some DRD controllers (eg, dwc3 & cdns3) have PHY management at +their own driver to cover both device and host mode, so add one +priv quirk for such users to skip PHY management from HCD core. + +Reviewed-by: Jun Li +Signed-off-by: Peter Chen +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20200918131752.16488-5-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-plat.c | 8 ++++++-- + drivers/usb/host/xhci.h | 1 + + 2 files changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/usb/host/xhci-plat.c ++++ b/drivers/usb/host/xhci-plat.c +@@ -163,6 +163,8 @@ static int xhci_plat_probe(struct platfo + struct usb_hcd *hcd; + int ret; + int irq; ++ struct xhci_plat_priv *priv = NULL; ++ + + if (usb_disabled()) + return -ENODEV; +@@ -257,8 +259,7 @@ static int xhci_plat_probe(struct platfo + + priv_match = of_device_get_match_data(&pdev->dev); + if (priv_match) { +- struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); +- ++ priv = hcd_to_xhci_priv(hcd); + /* Just copy data for now */ + if (priv_match) + *priv = *priv_match; +@@ -307,6 +308,9 @@ static int xhci_plat_probe(struct platfo + + hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); + xhci->shared_hcd->tpl_support = hcd->tpl_support; ++ if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)) ++ hcd->skip_phy_initialization = 1; ++ + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) + goto disable_usb_phy; +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1873,6 +1873,7 @@ struct xhci_hcd { + #define XHCI_DEFAULT_PM_RUNTIME_ALLOW BIT_ULL(33) + #define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34) + #define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35) ++#define XHCI_SKIP_PHY_INIT BIT_ULL(37) + #define XHCI_DISABLE_SPARSE BIT_ULL(38) + + unsigned int num_active_eps; diff --git a/queue-5.4/usb-renesas_usbhs-clear-pipe-running-flag-in-usbhs_pkt_pop.patch b/queue-5.4/usb-renesas_usbhs-clear-pipe-running-flag-in-usbhs_pkt_pop.patch new file mode 100644 index 00000000000..92aa805b53c --- /dev/null +++ b/queue-5.4/usb-renesas_usbhs-clear-pipe-running-flag-in-usbhs_pkt_pop.patch @@ -0,0 +1,33 @@ +From 9917f0e3cdba7b9f1a23f70e3f70b1a106be54a8 Mon Sep 17 00:00:00 2001 +From: Yoshihiro Shimoda +Date: Mon, 1 Feb 2021 21:47:20 +0900 +Subject: usb: renesas_usbhs: Clear pipe running flag in usbhs_pkt_pop() + +From: Yoshihiro Shimoda + +commit 9917f0e3cdba7b9f1a23f70e3f70b1a106be54a8 upstream. + +Should clear the pipe running flag in usbhs_pkt_pop(). Otherwise, +we cannot use this pipe after dequeue was called while the pipe was +running. + +Fixes: 8355b2b3082d ("usb: renesas_usbhs: fix the behavior of some usbhs_pkt_handle") +Reported-by: Tho Vu +Signed-off-by: Yoshihiro Shimoda +Link: https://lore.kernel.org/r/1612183640-8898-1-git-send-email-yoshihiro.shimoda.uh@renesas.com +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/renesas_usbhs/fifo.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/usb/renesas_usbhs/fifo.c ++++ b/drivers/usb/renesas_usbhs/fifo.c +@@ -126,6 +126,7 @@ struct usbhs_pkt *usbhs_pkt_pop(struct u + } + + usbhs_pipe_clear_without_sequence(pipe, 0, 0); ++ usbhs_pipe_running(pipe, 0); + + __usbhsf_pkt_del(pkt); + } diff --git a/queue-5.4/usb-usblp-don-t-call-usb_set_interface-if-there-s-a-single-alt.patch b/queue-5.4/usb-usblp-don-t-call-usb_set_interface-if-there-s-a-single-alt.patch new file mode 100644 index 00000000000..0af5510d1da --- /dev/null +++ b/queue-5.4/usb-usblp-don-t-call-usb_set_interface-if-there-s-a-single-alt.patch @@ -0,0 +1,51 @@ +From d8c6edfa3f4ee0d45d7ce5ef18d1245b78774b9d Mon Sep 17 00:00:00 2001 +From: Jeremy Figgins +Date: Sat, 23 Jan 2021 18:21:36 -0600 +Subject: USB: usblp: don't call usb_set_interface if there's a single alt + +From: Jeremy Figgins + +commit d8c6edfa3f4ee0d45d7ce5ef18d1245b78774b9d upstream. + +Some devices, such as the Winbond Electronics Corp. Virtual Com Port +(Vendor=0416, ProdId=5011), lockup when usb_set_interface() or +usb_clear_halt() are called. This device has only a single +altsetting, so it should not be necessary to call usb_set_interface(). + +Acked-by: Pete Zaitcev +Signed-off-by: Jeremy Figgins +Link: https://lore.kernel.org/r/YAy9kJhM/rG8EQXC@watson +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/class/usblp.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +--- a/drivers/usb/class/usblp.c ++++ b/drivers/usb/class/usblp.c +@@ -1329,14 +1329,17 @@ static int usblp_set_protocol(struct usb + if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) + return -EINVAL; + +- alts = usblp->protocol[protocol].alt_setting; +- if (alts < 0) +- return -EINVAL; +- r = usb_set_interface(usblp->dev, usblp->ifnum, alts); +- if (r < 0) { +- printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", +- alts, usblp->ifnum); +- return r; ++ /* Don't unnecessarily set the interface if there's a single alt. */ ++ if (usblp->intf->num_altsetting > 1) { ++ alts = usblp->protocol[protocol].alt_setting; ++ if (alts < 0) ++ return -EINVAL; ++ r = usb_set_interface(usblp->dev, usblp->ifnum, alts); ++ if (r < 0) { ++ printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", ++ alts, usblp->ifnum); ++ return r; ++ } + } + + usblp->bidir = (usblp->protocol[protocol].epread != NULL); diff --git a/queue-5.4/usb-xhci-mtk-break-loop-when-find-the-endpoint-to-drop.patch b/queue-5.4/usb-xhci-mtk-break-loop-when-find-the-endpoint-to-drop.patch new file mode 100644 index 00000000000..2c84e360497 --- /dev/null +++ b/queue-5.4/usb-xhci-mtk-break-loop-when-find-the-endpoint-to-drop.patch @@ -0,0 +1,36 @@ +From a50ea34d6dd00a12c9cd29cf7b0fa72816bffbcb Mon Sep 17 00:00:00 2001 +From: Chunfeng Yun +Date: Tue, 2 Feb 2021 16:38:24 +0800 +Subject: usb: xhci-mtk: break loop when find the endpoint to drop + +From: Chunfeng Yun + +commit a50ea34d6dd00a12c9cd29cf7b0fa72816bffbcb upstream. + +No need to check the following endpoints after finding the endpoint +wanted to drop. + +Fixes: 54f6a8af3722 ("usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints") +Cc: stable +Reported-by: Ikjoon Jang +Signed-off-by: Chunfeng Yun +Link: https://lore.kernel.org/r/1612255104-5363-1-git-send-email-chunfeng.yun@mediatek.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-mtk-sch.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/xhci-mtk-sch.c ++++ b/drivers/usb/host/xhci-mtk-sch.c +@@ -689,8 +689,10 @@ void xhci_mtk_drop_ep_quirk(struct usb_h + sch_bw = &sch_array[bw_index]; + + list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) { +- if (sch_ep->ep == ep) ++ if (sch_ep->ep == ep) { + destroy_sch_ep(udev, sch_bw, sch_ep); ++ break; ++ } + } + } + EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk); diff --git a/queue-5.4/usb-xhci-mtk-fix-unreleased-bandwidth-data.patch b/queue-5.4/usb-xhci-mtk-fix-unreleased-bandwidth-data.patch new file mode 100644 index 00000000000..a15894da5f3 --- /dev/null +++ b/queue-5.4/usb-xhci-mtk-fix-unreleased-bandwidth-data.patch @@ -0,0 +1,321 @@ +From 1d69f9d901ef14d81c3b004e3282b8cc7b456280 Mon Sep 17 00:00:00 2001 +From: Ikjoon Jang +Date: Wed, 13 Jan 2021 18:05:11 +0800 +Subject: usb: xhci-mtk: fix unreleased bandwidth data + +From: Ikjoon Jang + +commit 1d69f9d901ef14d81c3b004e3282b8cc7b456280 upstream. + +xhci-mtk needs XHCI_MTK_HOST quirk functions in add_endpoint() and +drop_endpoint() to handle its own sw bandwidth management. + +It stores bandwidth data into an internal table every time +add_endpoint() is called, and drops those in drop_endpoint(). +But when bandwidth allocation fails at one endpoint, all earlier +allocation from the same interface could still remain at the table. + +This patch moves bandwidth management codes to check_bandwidth() and +reset_bandwidth() path. To do so, this patch also adds those functions +to xhci_driver_overrides and lets mtk-xhci to release all failed +endpoints in reset_bandwidth() path. + +Fixes: 08e469de87a2 ("usb: xhci-mtk: supports bandwidth scheduling with multi-TT") +Signed-off-by: Ikjoon Jang +Link: https://lore.kernel.org/r/20210113180444.v6.1.Id0d31b5f3ddf5e734d2ab11161ac5821921b1e1e@changeid +Cc: stable +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-mtk-sch.c | 123 +++++++++++++++++++++++++++------------- + drivers/usb/host/xhci-mtk.c | 2 + drivers/usb/host/xhci-mtk.h | 13 ++++ + drivers/usb/host/xhci.c | 8 +- + drivers/usb/host/xhci.h | 4 + + 5 files changed, 111 insertions(+), 39 deletions(-) + +--- a/drivers/usb/host/xhci-mtk-sch.c ++++ b/drivers/usb/host/xhci-mtk-sch.c +@@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_s + + sch_ep->sch_tt = tt; + sch_ep->ep = ep; ++ INIT_LIST_HEAD(&sch_ep->tt_endpoint); + + return sch_ep; + } +@@ -583,6 +584,8 @@ int xhci_mtk_sch_init(struct xhci_hcd_mt + + mtk->sch_array = sch_array; + ++ INIT_LIST_HEAD(&mtk->bw_ep_list_new); ++ + return 0; + } + EXPORT_SYMBOL_GPL(xhci_mtk_sch_init); +@@ -601,19 +604,14 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd + struct xhci_ep_ctx *ep_ctx; + struct xhci_slot_ctx *slot_ctx; + struct xhci_virt_device *virt_dev; +- struct mu3h_sch_bw_info *sch_bw; + struct mu3h_sch_ep_info *sch_ep; +- struct mu3h_sch_bw_info *sch_array; + unsigned int ep_index; +- int bw_index; +- int ret = 0; + + xhci = hcd_to_xhci(hcd); + virt_dev = xhci->devs[udev->slot_id]; + ep_index = xhci_get_endpoint_index(&ep->desc); + slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); + ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); +- sch_array = mtk->sch_array; + + xhci_dbg(xhci, "%s() type:%d, speed:%d, mpkt:%d, dir:%d, ep:%p\n", + __func__, usb_endpoint_type(&ep->desc), udev->speed, +@@ -632,39 +630,34 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd + return 0; + } + +- bw_index = get_bw_index(xhci, udev, ep); +- sch_bw = &sch_array[bw_index]; +- + sch_ep = create_sch_ep(udev, ep, ep_ctx); + if (IS_ERR_OR_NULL(sch_ep)) + return -ENOMEM; + + setup_sch_info(udev, ep_ctx, sch_ep); + +- ret = check_sch_bw(udev, sch_bw, sch_ep); +- if (ret) { +- xhci_err(xhci, "Not enough bandwidth!\n"); +- if (is_fs_or_ls(udev->speed)) +- drop_tt(udev); +- +- kfree(sch_ep); +- return -ENOSPC; +- } ++ list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_list_new); + +- list_add_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk); + +- ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts) +- | EP_BCSCOUNT(sch_ep->cs_count) | EP_BBM(sch_ep->burst_mode)); +- ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset) +- | EP_BREPEAT(sch_ep->repeat)); ++static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev, ++ struct mu3h_sch_ep_info *sch_ep) ++{ ++ struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd); ++ int bw_index = get_bw_index(xhci, udev, sch_ep->ep); ++ struct mu3h_sch_bw_info *sch_bw = &mtk->sch_array[bw_index]; + +- xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n", +- sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode, +- sch_ep->offset, sch_ep->repeat); ++ update_bus_bw(sch_bw, sch_ep, 0); ++ list_del(&sch_ep->endpoint); + +- return 0; ++ if (sch_ep->sch_tt) { ++ list_del(&sch_ep->tt_endpoint); ++ drop_tt(udev); ++ } ++ kfree(sch_ep); + } +-EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk); + + void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) +@@ -675,7 +668,7 @@ void xhci_mtk_drop_ep_quirk(struct usb_h + struct xhci_virt_device *virt_dev; + struct mu3h_sch_bw_info *sch_array; + struct mu3h_sch_bw_info *sch_bw; +- struct mu3h_sch_ep_info *sch_ep; ++ struct mu3h_sch_ep_info *sch_ep, *tmp; + int bw_index; + + xhci = hcd_to_xhci(hcd); +@@ -694,17 +687,73 @@ void xhci_mtk_drop_ep_quirk(struct usb_h + bw_index = get_bw_index(xhci, udev, ep); + sch_bw = &sch_array[bw_index]; + +- list_for_each_entry(sch_ep, &sch_bw->bw_ep_list, endpoint) { ++ list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) { + if (sch_ep->ep == ep) { +- update_bus_bw(sch_bw, sch_ep, 0); +- list_del(&sch_ep->endpoint); +- if (is_fs_or_ls(udev->speed)) { +- list_del(&sch_ep->tt_endpoint); +- drop_tt(udev); +- } +- kfree(sch_ep); +- break; ++ xhci_mtk_drop_ep(mtk, udev, sch_ep); + } + } + } + EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk); ++ ++int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) ++{ ++ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); ++ struct xhci_hcd *xhci = hcd_to_xhci(hcd); ++ struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; ++ struct mu3h_sch_bw_info *sch_bw; ++ struct mu3h_sch_ep_info *sch_ep, *tmp; ++ int bw_index, ret; ++ ++ dev_dbg(&udev->dev, "%s\n", __func__); ++ ++ list_for_each_entry(sch_ep, &mtk->bw_ep_list_new, endpoint) { ++ bw_index = get_bw_index(xhci, udev, sch_ep->ep); ++ sch_bw = &mtk->sch_array[bw_index]; ++ ++ ret = check_sch_bw(udev, sch_bw, sch_ep); ++ if (ret) { ++ xhci_err(xhci, "Not enough bandwidth!\n"); ++ return -ENOSPC; ++ } ++ } ++ ++ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) { ++ struct xhci_ep_ctx *ep_ctx; ++ struct usb_host_endpoint *ep = sch_ep->ep; ++ unsigned int ep_index = xhci_get_endpoint_index(&ep->desc); ++ ++ bw_index = get_bw_index(xhci, udev, ep); ++ sch_bw = &mtk->sch_array[bw_index]; ++ ++ list_move_tail(&sch_ep->endpoint, &sch_bw->bw_ep_list); ++ ++ ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); ++ ep_ctx->reserved[0] |= cpu_to_le32(EP_BPKTS(sch_ep->pkts) ++ | EP_BCSCOUNT(sch_ep->cs_count) ++ | EP_BBM(sch_ep->burst_mode)); ++ ep_ctx->reserved[1] |= cpu_to_le32(EP_BOFFSET(sch_ep->offset) ++ | EP_BREPEAT(sch_ep->repeat)); ++ ++ xhci_dbg(xhci, " PKTS:%x, CSCOUNT:%x, BM:%x, OFFSET:%x, REPEAT:%x\n", ++ sch_ep->pkts, sch_ep->cs_count, sch_ep->burst_mode, ++ sch_ep->offset, sch_ep->repeat); ++ } ++ ++ return xhci_check_bandwidth(hcd, udev); ++} ++EXPORT_SYMBOL_GPL(xhci_mtk_check_bandwidth); ++ ++void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) ++{ ++ struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); ++ struct mu3h_sch_ep_info *sch_ep, *tmp; ++ ++ dev_dbg(&udev->dev, "%s\n", __func__); ++ ++ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) { ++ xhci_mtk_drop_ep(mtk, udev, sch_ep); ++ } ++ ++ xhci_reset_bandwidth(hcd, udev); ++} ++EXPORT_SYMBOL_GPL(xhci_mtk_reset_bandwidth); +--- a/drivers/usb/host/xhci-mtk.c ++++ b/drivers/usb/host/xhci-mtk.c +@@ -347,6 +347,8 @@ static void usb_wakeup_set(struct xhci_h + static int xhci_mtk_setup(struct usb_hcd *hcd); + static const struct xhci_driver_overrides xhci_mtk_overrides __initconst = { + .reset = xhci_mtk_setup, ++ .check_bandwidth = xhci_mtk_check_bandwidth, ++ .reset_bandwidth = xhci_mtk_reset_bandwidth, + }; + + static struct hc_driver __read_mostly xhci_mtk_hc_driver; +--- a/drivers/usb/host/xhci-mtk.h ++++ b/drivers/usb/host/xhci-mtk.h +@@ -130,6 +130,7 @@ struct mu3c_ippc_regs { + struct xhci_hcd_mtk { + struct device *dev; + struct usb_hcd *hcd; ++ struct list_head bw_ep_list_new; + struct mu3h_sch_bw_info *sch_array; + struct mu3c_ippc_regs __iomem *ippc_regs; + bool has_ippc; +@@ -166,6 +167,8 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd + struct usb_host_endpoint *ep); + void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep); ++int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); ++void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); + + #else + static inline int xhci_mtk_add_ep_quirk(struct usb_hcd *hcd, +@@ -179,6 +182,16 @@ static inline void xhci_mtk_drop_ep_quir + { + } + ++static inline int xhci_mtk_check_bandwidth(struct usb_hcd *hcd, ++ struct usb_device *udev) ++{ ++ return 0; ++} ++ ++static inline void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, ++ struct usb_device *udev) ++{ ++} + #endif + + #endif /* _XHCI_MTK_H_ */ +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -2861,7 +2861,7 @@ static void xhci_check_bw_drop_ep_stream + * else should be touching the xhci->devs[slot_id] structure, so we + * don't need to take the xhci->lock for manipulating that. + */ +-static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) ++int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) + { + int i; + int ret = 0; +@@ -2959,7 +2959,7 @@ command_cleanup: + return ret; + } + +-static void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) ++void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) + { + struct xhci_hcd *xhci; + struct xhci_virt_device *virt_dev; +@@ -5380,6 +5380,10 @@ void xhci_init_driver(struct hc_driver * + drv->reset = over->reset; + if (over->start) + drv->start = over->start; ++ if (over->check_bandwidth) ++ drv->check_bandwidth = over->check_bandwidth; ++ if (over->reset_bandwidth) ++ drv->reset_bandwidth = over->reset_bandwidth; + } + } + EXPORT_SYMBOL_GPL(xhci_init_driver); +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1911,6 +1911,8 @@ struct xhci_driver_overrides { + size_t extra_priv_size; + int (*reset)(struct usb_hcd *hcd); + int (*start)(struct usb_hcd *hcd); ++ int (*check_bandwidth)(struct usb_hcd *, struct usb_device *); ++ void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); + }; + + #define XHCI_CFC_DELAY 10 +@@ -2063,6 +2065,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, + void xhci_shutdown(struct usb_hcd *hcd); + void xhci_init_driver(struct hc_driver *drv, + const struct xhci_driver_overrides *over); ++int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); ++void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); + int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); + int xhci_ext_cap_init(struct xhci_hcd *xhci); + diff --git a/queue-5.4/usb-xhci-mtk-skip-dropping-bandwidth-of-unchecked-endpoints.patch b/queue-5.4/usb-xhci-mtk-skip-dropping-bandwidth-of-unchecked-endpoints.patch new file mode 100644 index 00000000000..01f02d226dc --- /dev/null +++ b/queue-5.4/usb-xhci-mtk-skip-dropping-bandwidth-of-unchecked-endpoints.patch @@ -0,0 +1,189 @@ +From 54f6a8af372213a254af6609758d99f7c0b6b5ad Mon Sep 17 00:00:00 2001 +From: Chunfeng Yun +Date: Mon, 1 Feb 2021 13:57:44 +0800 +Subject: usb: xhci-mtk: skip dropping bandwidth of unchecked endpoints + +From: Chunfeng Yun + +commit 54f6a8af372213a254af6609758d99f7c0b6b5ad upstream. + +For those unchecked endpoints, we don't allocate bandwidth for +them, so no need free the bandwidth, otherwise will decrease +the allocated bandwidth. +Meanwhile use xhci_dbg() instead of dev_dbg() to print logs and +rename bw_ep_list_new as bw_ep_chk_list. + +Fixes: 1d69f9d901ef ("usb: xhci-mtk: fix unreleased bandwidth data") +Cc: stable +Reviewed-and-tested-by: Ikjoon Jang +Signed-off-by: Chunfeng Yun +Link: https://lore.kernel.org/r/1612159064-28413-1-git-send-email-chunfeng.yun@mediatek.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-mtk-sch.c | 61 +++++++++++++++++++++------------------- + drivers/usb/host/xhci-mtk.h | 4 +- + 2 files changed, 36 insertions(+), 29 deletions(-) + +--- a/drivers/usb/host/xhci-mtk-sch.c ++++ b/drivers/usb/host/xhci-mtk-sch.c +@@ -200,6 +200,7 @@ static struct mu3h_sch_ep_info *create_s + + sch_ep->sch_tt = tt; + sch_ep->ep = ep; ++ INIT_LIST_HEAD(&sch_ep->endpoint); + INIT_LIST_HEAD(&sch_ep->tt_endpoint); + + return sch_ep; +@@ -374,6 +375,7 @@ static void update_bus_bw(struct mu3h_sc + sch_ep->bw_budget_table[j]; + } + } ++ sch_ep->allocated = used; + } + + static int check_sch_tt(struct usb_device *udev, +@@ -542,6 +544,22 @@ static int check_sch_bw(struct usb_devic + return 0; + } + ++static void destroy_sch_ep(struct usb_device *udev, ++ struct mu3h_sch_bw_info *sch_bw, struct mu3h_sch_ep_info *sch_ep) ++{ ++ /* only release ep bw check passed by check_sch_bw() */ ++ if (sch_ep->allocated) ++ update_bus_bw(sch_bw, sch_ep, 0); ++ ++ list_del(&sch_ep->endpoint); ++ ++ if (sch_ep->sch_tt) { ++ list_del(&sch_ep->tt_endpoint); ++ drop_tt(udev); ++ } ++ kfree(sch_ep); ++} ++ + static bool need_bw_sch(struct usb_host_endpoint *ep, + enum usb_device_speed speed, int has_tt) + { +@@ -584,7 +602,7 @@ int xhci_mtk_sch_init(struct xhci_hcd_mt + + mtk->sch_array = sch_array; + +- INIT_LIST_HEAD(&mtk->bw_ep_list_new); ++ INIT_LIST_HEAD(&mtk->bw_ep_chk_list); + + return 0; + } +@@ -636,29 +654,12 @@ int xhci_mtk_add_ep_quirk(struct usb_hcd + + setup_sch_info(udev, ep_ctx, sch_ep); + +- list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_list_new); ++ list_add_tail(&sch_ep->endpoint, &mtk->bw_ep_chk_list); + + return 0; + } + EXPORT_SYMBOL_GPL(xhci_mtk_add_ep_quirk); + +-static void xhci_mtk_drop_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev, +- struct mu3h_sch_ep_info *sch_ep) +-{ +- struct xhci_hcd *xhci = hcd_to_xhci(mtk->hcd); +- int bw_index = get_bw_index(xhci, udev, sch_ep->ep); +- struct mu3h_sch_bw_info *sch_bw = &mtk->sch_array[bw_index]; +- +- update_bus_bw(sch_bw, sch_ep, 0); +- list_del(&sch_ep->endpoint); +- +- if (sch_ep->sch_tt) { +- list_del(&sch_ep->tt_endpoint); +- drop_tt(udev); +- } +- kfree(sch_ep); +-} +- + void xhci_mtk_drop_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, + struct usb_host_endpoint *ep) + { +@@ -688,9 +689,8 @@ void xhci_mtk_drop_ep_quirk(struct usb_h + sch_bw = &sch_array[bw_index]; + + list_for_each_entry_safe(sch_ep, tmp, &sch_bw->bw_ep_list, endpoint) { +- if (sch_ep->ep == ep) { +- xhci_mtk_drop_ep(mtk, udev, sch_ep); +- } ++ if (sch_ep->ep == ep) ++ destroy_sch_ep(udev, sch_bw, sch_ep); + } + } + EXPORT_SYMBOL_GPL(xhci_mtk_drop_ep_quirk); +@@ -704,9 +704,9 @@ int xhci_mtk_check_bandwidth(struct usb_ + struct mu3h_sch_ep_info *sch_ep, *tmp; + int bw_index, ret; + +- dev_dbg(&udev->dev, "%s\n", __func__); ++ xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); + +- list_for_each_entry(sch_ep, &mtk->bw_ep_list_new, endpoint) { ++ list_for_each_entry(sch_ep, &mtk->bw_ep_chk_list, endpoint) { + bw_index = get_bw_index(xhci, udev, sch_ep->ep); + sch_bw = &mtk->sch_array[bw_index]; + +@@ -717,7 +717,7 @@ int xhci_mtk_check_bandwidth(struct usb_ + } + } + +- list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) { ++ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) { + struct xhci_ep_ctx *ep_ctx; + struct usb_host_endpoint *ep = sch_ep->ep; + unsigned int ep_index = xhci_get_endpoint_index(&ep->desc); +@@ -746,12 +746,17 @@ EXPORT_SYMBOL_GPL(xhci_mtk_check_bandwid + void xhci_mtk_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) + { + struct xhci_hcd_mtk *mtk = hcd_to_mtk(hcd); ++ struct xhci_hcd *xhci = hcd_to_xhci(hcd); ++ struct mu3h_sch_bw_info *sch_bw; + struct mu3h_sch_ep_info *sch_ep, *tmp; ++ int bw_index; + +- dev_dbg(&udev->dev, "%s\n", __func__); ++ xhci_dbg(xhci, "%s() udev %s\n", __func__, dev_name(&udev->dev)); + +- list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_list_new, endpoint) { +- xhci_mtk_drop_ep(mtk, udev, sch_ep); ++ list_for_each_entry_safe(sch_ep, tmp, &mtk->bw_ep_chk_list, endpoint) { ++ bw_index = get_bw_index(xhci, udev, sch_ep->ep); ++ sch_bw = &mtk->sch_array[bw_index]; ++ destroy_sch_ep(udev, sch_bw, sch_ep); + } + + xhci_reset_bandwidth(hcd, udev); +--- a/drivers/usb/host/xhci-mtk.h ++++ b/drivers/usb/host/xhci-mtk.h +@@ -59,6 +59,7 @@ struct mu3h_sch_bw_info { + * @ep_type: endpoint type + * @maxpkt: max packet size of endpoint + * @ep: address of usb_host_endpoint struct ++ * @allocated: the bandwidth is aready allocated from bus_bw + * @offset: which uframe of the interval that transfer should be + * scheduled first time within the interval + * @repeat: the time gap between two uframes that transfers are +@@ -86,6 +87,7 @@ struct mu3h_sch_ep_info { + u32 ep_type; + u32 maxpkt; + void *ep; ++ bool allocated; + /* + * mtk xHCI scheduling information put into reserved DWs + * in ep context +@@ -130,8 +132,8 @@ struct mu3c_ippc_regs { + struct xhci_hcd_mtk { + struct device *dev; + struct usb_hcd *hcd; +- struct list_head bw_ep_list_new; + struct mu3h_sch_bw_info *sch_array; ++ struct list_head bw_ep_chk_list; + struct mu3c_ippc_regs __iomem *ippc_regs; + bool has_ippc; + int num_u2_ports; diff --git a/queue-5.4/xhci-fix-bounce-buffer-usage-for-non-sg-list-case.patch b/queue-5.4/xhci-fix-bounce-buffer-usage-for-non-sg-list-case.patch new file mode 100644 index 00000000000..6410e1f26a2 --- /dev/null +++ b/queue-5.4/xhci-fix-bounce-buffer-usage-for-non-sg-list-case.patch @@ -0,0 +1,82 @@ +From d4a610635400ccc382792f6be69427078541c678 Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Wed, 3 Feb 2021 13:37:02 +0200 +Subject: xhci: fix bounce buffer usage for non-sg list case + +From: Mathias Nyman + +commit d4a610635400ccc382792f6be69427078541c678 upstream. + +xhci driver may in some special cases need to copy small amounts +of payload data to a bounce buffer in order to meet the boundary +and alignment restrictions set by the xHCI specification. + +In the majority of these cases the data is in a sg list, and +driver incorrectly assumed data is always in urb->sg when using +the bounce buffer. + +If data instead is contiguous, and in urb->transfer_buffer, we may still +need to bounce buffer a small part if data starts very close (less than +packet size) to a 64k boundary. + +Check if sg list is used before copying data to/from it. + +Fixes: f9c589e142d0 ("xhci: TD-fragment, align the unsplittable case with a bounce buffer") +Cc: stable@vger.kernel.org +Reported-by: Andreas Hartmann +Tested-by: Andreas Hartmann +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20210203113702.436762-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-ring.c | 31 ++++++++++++++++++++----------- + 1 file changed, 20 insertions(+), 11 deletions(-) + +--- a/drivers/usb/host/xhci-ring.c ++++ b/drivers/usb/host/xhci-ring.c +@@ -695,11 +695,16 @@ static void xhci_unmap_td_bounce_buffer( + dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len, + DMA_FROM_DEVICE); + /* for in tranfers we need to copy the data from bounce to sg */ +- len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf, +- seg->bounce_len, seg->bounce_offs); +- if (len != seg->bounce_len) +- xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n", +- len, seg->bounce_len); ++ if (urb->num_sgs) { ++ len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf, ++ seg->bounce_len, seg->bounce_offs); ++ if (len != seg->bounce_len) ++ xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n", ++ len, seg->bounce_len); ++ } else { ++ memcpy(urb->transfer_buffer + seg->bounce_offs, seg->bounce_buf, ++ seg->bounce_len); ++ } + seg->bounce_len = 0; + seg->bounce_offs = 0; + } +@@ -3263,12 +3268,16 @@ static int xhci_align_td(struct xhci_hcd + + /* create a max max_pkt sized bounce buffer pointed to by last trb */ + if (usb_urb_dir_out(urb)) { +- len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs, +- seg->bounce_buf, new_buff_len, enqd_len); +- if (len != new_buff_len) +- xhci_warn(xhci, +- "WARN Wrong bounce buffer write length: %zu != %d\n", +- len, new_buff_len); ++ if (urb->num_sgs) { ++ len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs, ++ seg->bounce_buf, new_buff_len, enqd_len); ++ if (len != new_buff_len) ++ xhci_warn(xhci, "WARN Wrong bounce buffer write length: %zu != %d\n", ++ len, new_buff_len); ++ } else { ++ memcpy(seg->bounce_buf, urb->transfer_buffer + enqd_len, new_buff_len); ++ } ++ + seg->bounce_dma = dma_map_single(dev, seg->bounce_buf, + max_pkt, DMA_TO_DEVICE); + } else {