drm-amd-pm-correct-vega12-swctf-limit-setting.patch
drm-amd-pm-correct-vega20-swctf-limit-setting.patch
drm-amd-pm-correct-the-thermal-alert-temperature-limit-settings.patch
+usb-yurex-fix-bad-gfp-argument.patch
+usb-uas-add-quirk-for-pny-pro-elite.patch
+usb-quirks-add-no-lpm-quirk-for-another-raydium-touchscreen.patch
+usb-quirks-ignore-duplicate-endpoint-on-sound-devices-mixpre-d.patch
+usb-ignore-uas-for-jmicron-jms567-ata-atapi-bridge.patch
+usb-host-ohci-exynos-fix-error-handling-in-exynos_ohci_probe.patch
+usb-gadget-u_f-add-overflow-checks-to-vla-macros.patch
+usb-gadget-f_ncm-add-bounds-checks-to-ncm_unwrap_ntb.patch
+usb-gadget-u_f-unbreak-offset-calculation-in-vlas.patch
+usb-dwc3-gadget-don-t-setup-more-than-requested.patch
+usb-dwc3-gadget-fix-handling-zlp.patch
+usb-dwc3-gadget-handle-zlp-for-sg-requests.patch
+usb-cdc-acm-rework-notification_buffer-resizing.patch
+usb-storage-add-unusual_uas-entry-for-sony-psz-drives.patch
+usb-also-match-device-drivers-using-the-match-vfunc.patch
+usb-fix-device-driver-race.patch
+usb-typec-ucsi-fix-ab-ba-lock-inversion.patch
+usb-typec-ucsi-fix-2-unlocked-ucsi_run_command-calls.patch
+usb-typec-ucsi-rework-ppm_lock-handling.patch
+usb-typec-ucsi-hold-con-lock-for-the-entire-duration-of-ucsi_register_port.patch
+usb-typec-tcpm-fix-fix-source-hard-reset-response-for-tda-2.3.1.1-and-tda-2.3.1.2-failures.patch
--- /dev/null
+From adb6e6ac20eedcf1dce19dc75b224e63c0828ea1 Mon Sep 17 00:00:00 2001
+From: Bastien Nocera <hadess@hadess.net>
+Date: Tue, 18 Aug 2020 13:04:43 +0200
+Subject: USB: Also match device drivers using the ->match vfunc
+
+From: Bastien Nocera <hadess@hadess.net>
+
+commit adb6e6ac20eedcf1dce19dc75b224e63c0828ea1 upstream.
+
+We only ever used the ID table matching before, but we should also support
+open-coded match functions.
+
+Fixes: 88b7381a939de ("USB: Select better matching USB drivers when available")
+Signed-off-by: Bastien Nocera <hadess@hadess.net>
+Cc: stable <stable@vger.kernel.org>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/20200818110445.509668-1-hadess@hadess.net
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/generic.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/core/generic.c
++++ b/drivers/usb/core/generic.c
+@@ -207,8 +207,9 @@ static int __check_usb_generic(struct de
+ return 0;
+ if (!udrv->id_table)
+ return 0;
+-
+- return usb_device_match_id(udev, udrv->id_table) != NULL;
++ if (usb_device_match_id(udev, udrv->id_table) != NULL)
++ return 1;
++ return (udrv->match && udrv->match(udev));
+ }
+
+ static bool usb_generic_driver_match(struct usb_device *udev)
--- /dev/null
+From f4b9d8a582f738c24ebeabce5cc15f4b8159d74e Mon Sep 17 00:00:00 2001
+From: Tom Rix <trix@redhat.com>
+Date: Sat, 1 Aug 2020 08:21:54 -0700
+Subject: USB: cdc-acm: rework notification_buffer resizing
+
+From: Tom Rix <trix@redhat.com>
+
+commit f4b9d8a582f738c24ebeabce5cc15f4b8159d74e upstream.
+
+Clang static analysis reports this error
+
+cdc-acm.c:409:3: warning: Use of memory after it is freed
+ acm_process_notification(acm, (unsigned char *)dr);
+
+There are three problems, the first one is that dr is not reset
+
+The variable dr is set with
+
+if (acm->nb_index)
+ dr = (struct usb_cdc_notification *)acm->notification_buffer;
+
+But if the notification_buffer is too small it is resized with
+
+ if (acm->nb_size) {
+ kfree(acm->notification_buffer);
+ acm->nb_size = 0;
+ }
+ alloc_size = roundup_pow_of_two(expected_size);
+ /*
+ * kmalloc ensures a valid notification_buffer after a
+ * use of kfree in case the previous allocation was too
+ * small. Final freeing is done on disconnect.
+ */
+ acm->notification_buffer =
+ kmalloc(alloc_size, GFP_ATOMIC);
+
+dr should point to the new acm->notification_buffer.
+
+The second problem is any data in the notification_buffer is lost
+when the pointer is freed. In the normal case, the current data
+is accumulated in the notification_buffer here.
+
+ memcpy(&acm->notification_buffer[acm->nb_index],
+ urb->transfer_buffer, copy_size);
+
+When a resize happens, anything before
+notification_buffer[acm->nb_index] is garbage.
+
+The third problem is the acm->nb_index is not reset on a
+resizing buffer error.
+
+So switch resizing to using krealloc and reassign dr and
+reset nb_index.
+
+Fixes: ea2583529cd1 ("cdc-acm: reassemble fragmented notifications")
+Signed-off-by: Tom Rix <trix@redhat.com>
+Cc: stable <stable@vger.kernel.org>
+Acked-by: Oliver Neukum <oneukum@suse.com>
+Link: https://lore.kernel.org/r/20200801152154.20683-1-trix@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/class/cdc-acm.c | 22 ++++++++++------------
+ 1 file changed, 10 insertions(+), 12 deletions(-)
+
+--- a/drivers/usb/class/cdc-acm.c
++++ b/drivers/usb/class/cdc-acm.c
+@@ -378,21 +378,19 @@ static void acm_ctrl_irq(struct urb *urb
+ if (current_size < expected_size) {
+ /* notification is transmitted fragmented, reassemble */
+ if (acm->nb_size < expected_size) {
+- if (acm->nb_size) {
+- kfree(acm->notification_buffer);
+- acm->nb_size = 0;
+- }
++ u8 *new_buffer;
+ alloc_size = roundup_pow_of_two(expected_size);
+- /*
+- * kmalloc ensures a valid notification_buffer after a
+- * use of kfree in case the previous allocation was too
+- * small. Final freeing is done on disconnect.
+- */
+- acm->notification_buffer =
+- kmalloc(alloc_size, GFP_ATOMIC);
+- if (!acm->notification_buffer)
++ /* Final freeing is done on disconnect. */
++ new_buffer = krealloc(acm->notification_buffer,
++ alloc_size, GFP_ATOMIC);
++ if (!new_buffer) {
++ acm->nb_index = 0;
+ goto exit;
++ }
++
++ acm->notification_buffer = new_buffer;
+ acm->nb_size = alloc_size;
++ dr = (struct usb_cdc_notification *)acm->notification_buffer;
+ }
+
+ copy_size = min(current_size,
--- /dev/null
+From 5d187c0454ef4c5e046a81af36882d4d515922ec Mon Sep 17 00:00:00 2001
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Date: Thu, 6 Aug 2020 19:46:23 -0700
+Subject: usb: dwc3: gadget: Don't setup more than requested
+
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+
+commit 5d187c0454ef4c5e046a81af36882d4d515922ec upstream.
+
+The SG list may be set up with entry size more than the requested
+length. Check the usb_request->length and make sure that we don't setup
+the TRBs to send/receive more than requested. This case may occur when
+the SG entry is allocated up to a certain minimum size, but the request
+length is less than that. It can also occur when the request is reused
+for a different request length.
+
+Cc: <stable@vger.kernel.org> # v4.18+
+Fixes: a31e63b608ff ("usb: dwc3: gadget: Correct handling of scattergather lists")
+Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
+Signed-off-by: Felipe Balbi <balbi@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/dwc3/gadget.c | 51 +++++++++++++++++++++++++++++++---------------
+ 1 file changed, 35 insertions(+), 16 deletions(-)
+
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -1054,27 +1054,25 @@ static void __dwc3_prepare_one_trb(struc
+ * dwc3_prepare_one_trb - setup one TRB from one request
+ * @dep: endpoint for which this request is prepared
+ * @req: dwc3_request pointer
++ * @trb_length: buffer size of the TRB
+ * @chain: should this TRB be chained to the next?
+ * @node: only for isochronous endpoints. First TRB needs different type.
+ */
+ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+- struct dwc3_request *req, unsigned chain, unsigned node)
++ struct dwc3_request *req, unsigned int trb_length,
++ unsigned chain, unsigned node)
+ {
+ struct dwc3_trb *trb;
+- unsigned int length;
+ dma_addr_t dma;
+ unsigned stream_id = req->request.stream_id;
+ unsigned short_not_ok = req->request.short_not_ok;
+ unsigned no_interrupt = req->request.no_interrupt;
+ unsigned is_last = req->request.is_last;
+
+- if (req->request.num_sgs > 0) {
+- length = sg_dma_len(req->start_sg);
++ if (req->request.num_sgs > 0)
+ dma = sg_dma_address(req->start_sg);
+- } else {
+- length = req->request.length;
++ else
+ dma = req->request.dma;
+- }
+
+ trb = &dep->trb_pool[dep->trb_enqueue];
+
+@@ -1086,7 +1084,7 @@ static void dwc3_prepare_one_trb(struct
+
+ req->num_trbs++;
+
+- __dwc3_prepare_one_trb(dep, trb, dma, length, chain, node,
++ __dwc3_prepare_one_trb(dep, trb, dma, trb_length, chain, node,
+ stream_id, short_not_ok, no_interrupt, is_last);
+ }
+
+@@ -1096,16 +1094,27 @@ static void dwc3_prepare_one_trb_sg(stru
+ struct scatterlist *sg = req->start_sg;
+ struct scatterlist *s;
+ int i;
+-
++ unsigned int length = req->request.length;
+ unsigned int remaining = req->request.num_mapped_sgs
+ - req->num_queued_sgs;
+
++ /*
++ * If we resume preparing the request, then get the remaining length of
++ * the request and resume where we left off.
++ */
++ for_each_sg(req->request.sg, s, req->num_queued_sgs, i)
++ length -= sg_dma_len(s);
++
+ for_each_sg(sg, s, remaining, i) {
+- unsigned int length = req->request.length;
+ unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
+ unsigned int rem = length % maxp;
++ unsigned int trb_length;
+ unsigned chain = true;
+
++ trb_length = min_t(unsigned int, length, sg_dma_len(s));
++
++ length -= trb_length;
++
+ /*
+ * IOMMU driver is coalescing the list of sgs which shares a
+ * page boundary into one and giving it to USB driver. With
+@@ -1113,7 +1122,7 @@ static void dwc3_prepare_one_trb_sg(stru
+ * sgs passed. So mark the chain bit to false if it isthe last
+ * mapped sg.
+ */
+- if (i == remaining - 1)
++ if ((i == remaining - 1) || !length)
+ chain = false;
+
+ if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) {
+@@ -1123,7 +1132,7 @@ static void dwc3_prepare_one_trb_sg(stru
+ req->needs_extra_trb = true;
+
+ /* prepare normal TRB */
+- dwc3_prepare_one_trb(dep, req, true, i);
++ dwc3_prepare_one_trb(dep, req, trb_length, true, i);
+
+ /* Now prepare one extra TRB to align transfer size */
+ trb = &dep->trb_pool[dep->trb_enqueue];
+@@ -1135,7 +1144,7 @@ static void dwc3_prepare_one_trb_sg(stru
+ req->request.no_interrupt,
+ req->request.is_last);
+ } else {
+- dwc3_prepare_one_trb(dep, req, chain, i);
++ dwc3_prepare_one_trb(dep, req, trb_length, chain, i);
+ }
+
+ /*
+@@ -1150,6 +1159,16 @@ static void dwc3_prepare_one_trb_sg(stru
+
+ req->num_queued_sgs++;
+
++ /*
++ * The number of pending SG entries may not correspond to the
++ * number of mapped SG entries. If all the data are queued, then
++ * don't include unused SG entries.
++ */
++ if (length == 0) {
++ req->num_pending_sgs -= req->request.num_mapped_sgs - req->num_queued_sgs;
++ break;
++ }
++
+ if (!dwc3_calc_trbs_left(dep))
+ break;
+ }
+@@ -1169,7 +1188,7 @@ static void dwc3_prepare_one_trb_linear(
+ req->needs_extra_trb = true;
+
+ /* prepare normal TRB */
+- dwc3_prepare_one_trb(dep, req, true, 0);
++ dwc3_prepare_one_trb(dep, req, length, true, 0);
+
+ /* Now prepare one extra TRB to align transfer size */
+ trb = &dep->trb_pool[dep->trb_enqueue];
+@@ -1187,7 +1206,7 @@ static void dwc3_prepare_one_trb_linear(
+ req->needs_extra_trb = true;
+
+ /* prepare normal TRB */
+- dwc3_prepare_one_trb(dep, req, true, 0);
++ dwc3_prepare_one_trb(dep, req, length, true, 0);
+
+ /* Now prepare one extra TRB to handle ZLP */
+ trb = &dep->trb_pool[dep->trb_enqueue];
+@@ -1198,7 +1217,7 @@ static void dwc3_prepare_one_trb_linear(
+ req->request.no_interrupt,
+ req->request.is_last);
+ } else {
+- dwc3_prepare_one_trb(dep, req, false, 0);
++ dwc3_prepare_one_trb(dep, req, length, false, 0);
+ }
+ }
+
--- /dev/null
+From d2ee3ff79e6a3d4105e684021017d100524dc560 Mon Sep 17 00:00:00 2001
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Date: Thu, 6 Aug 2020 19:46:29 -0700
+Subject: usb: dwc3: gadget: Fix handling ZLP
+
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+
+commit d2ee3ff79e6a3d4105e684021017d100524dc560 upstream.
+
+The usb_request->zero doesn't apply for isoc. Also, if we prepare a
+0-length (ZLP) TRB for the OUT direction, we need to prepare an extra
+TRB to pad up to the MPS alignment. Use the same bounce buffer for the
+ZLP TRB and the extra pad TRB.
+
+Cc: <stable@vger.kernel.org> # v4.5+
+Fixes: d6e5a549cc4d ("usb: dwc3: simplify ZLP handling")
+Fixes: 04c03d10e507 ("usb: dwc3: gadget: handle request->zero")
+Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
+Signed-off-by: Felipe Balbi <balbi@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/dwc3/gadget.c | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -1199,6 +1199,7 @@ static void dwc3_prepare_one_trb_linear(
+ req->request.no_interrupt,
+ req->request.is_last);
+ } else if (req->request.zero && req->request.length &&
++ !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+ (IS_ALIGNED(req->request.length, maxp))) {
+ struct dwc3 *dwc = dep->dwc;
+ struct dwc3_trb *trb;
+@@ -1208,14 +1209,25 @@ static void dwc3_prepare_one_trb_linear(
+ /* prepare normal TRB */
+ dwc3_prepare_one_trb(dep, req, length, true, 0);
+
+- /* Now prepare one extra TRB to handle ZLP */
++ /* Prepare one extra TRB to handle ZLP */
+ trb = &dep->trb_pool[dep->trb_enqueue];
+ req->num_trbs++;
+ __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
+- false, 1, req->request.stream_id,
++ !req->direction, 1, req->request.stream_id,
+ req->request.short_not_ok,
+ req->request.no_interrupt,
+ req->request.is_last);
++
++ /* Prepare one more TRB to handle MPS alignment for OUT */
++ if (!req->direction) {
++ trb = &dep->trb_pool[dep->trb_enqueue];
++ req->num_trbs++;
++ __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp,
++ false, 1, req->request.stream_id,
++ req->request.short_not_ok,
++ req->request.no_interrupt,
++ req->request.is_last);
++ }
+ } else {
+ dwc3_prepare_one_trb(dep, req, length, false, 0);
+ }
+@@ -2668,8 +2680,17 @@ static int dwc3_gadget_ep_cleanup_comple
+ status);
+
+ if (req->needs_extra_trb) {
++ unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
++
+ ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
+ status);
++
++ /* Reclaim MPS padding TRB for ZLP */
++ if (!req->direction && req->request.zero && req->request.length &&
++ !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
++ (IS_ALIGNED(req->request.length, maxp)))
++ ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, status);
++
+ req->needs_extra_trb = false;
+ }
+
--- /dev/null
+From bc9a2e226ea95e1699f7590845554de095308b75 Mon Sep 17 00:00:00 2001
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Date: Thu, 6 Aug 2020 19:46:35 -0700
+Subject: usb: dwc3: gadget: Handle ZLP for sg requests
+
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+
+commit bc9a2e226ea95e1699f7590845554de095308b75 upstream.
+
+Currently dwc3 doesn't handle usb_request->zero for SG requests. This
+change checks and prepares extra TRBs for the ZLP for SG requests.
+
+Cc: <stable@vger.kernel.org> # v4.5+
+Fixes: 04c03d10e507 ("usb: dwc3: gadget: handle request->zero")
+Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
+Signed-off-by: Felipe Balbi <balbi@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/dwc3/gadget.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -1143,6 +1143,37 @@ static void dwc3_prepare_one_trb_sg(stru
+ req->request.short_not_ok,
+ req->request.no_interrupt,
+ req->request.is_last);
++ } else if (req->request.zero && req->request.length &&
++ !usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
++ !rem && !chain) {
++ struct dwc3 *dwc = dep->dwc;
++ struct dwc3_trb *trb;
++
++ req->needs_extra_trb = true;
++
++ /* Prepare normal TRB */
++ dwc3_prepare_one_trb(dep, req, trb_length, true, i);
++
++ /* Prepare one extra TRB to handle ZLP */
++ trb = &dep->trb_pool[dep->trb_enqueue];
++ req->num_trbs++;
++ __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
++ !req->direction, 1,
++ req->request.stream_id,
++ req->request.short_not_ok,
++ req->request.no_interrupt,
++ req->request.is_last);
++
++ /* Prepare one more TRB to handle MPS alignment */
++ if (!req->direction) {
++ trb = &dep->trb_pool[dep->trb_enqueue];
++ req->num_trbs++;
++ __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp,
++ false, 1, req->request.stream_id,
++ req->request.short_not_ok,
++ req->request.no_interrupt,
++ req->request.is_last);
++ }
+ } else {
+ dwc3_prepare_one_trb(dep, req, trb_length, chain, i);
+ }
--- /dev/null
+From d5643d2249b279077427b2c2b2ffae9b70c95b0b Mon Sep 17 00:00:00 2001
+From: Bastien Nocera <hadess@hadess.net>
+Date: Tue, 18 Aug 2020 13:04:45 +0200
+Subject: USB: Fix device driver race
+
+From: Bastien Nocera <hadess@hadess.net>
+
+commit d5643d2249b279077427b2c2b2ffae9b70c95b0b upstream.
+
+When a new device with a specialised device driver is plugged in, the
+new driver will be modprobe()'d but the driver core will attach the
+"generic" driver to the device.
+
+After that, nothing will trigger a reprobe when the modprobe()'d device
+driver has finished initialising, as the device has the "generic"
+driver attached to it.
+
+Trigger a reprobe ourselves when new specialised drivers get registered.
+
+Fixes: 88b7381a939d ("USB: Select better matching USB drivers when available")
+Signed-off-by: Bastien Nocera <hadess@hadess.net>
+Cc: stable <stable@vger.kernel.org>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+Link: https://lore.kernel.org/r/20200818110445.509668-3-hadess@hadess.net
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/driver.c | 40 ++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 38 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/core/driver.c
++++ b/drivers/usb/core/driver.c
+@@ -905,6 +905,35 @@ static int usb_uevent(struct device *dev
+ return 0;
+ }
+
++static bool is_dev_usb_generic_driver(struct device *dev)
++{
++ struct usb_device_driver *udd = dev->driver ?
++ to_usb_device_driver(dev->driver) : NULL;
++
++ return udd == &usb_generic_driver;
++}
++
++static int __usb_bus_reprobe_drivers(struct device *dev, void *data)
++{
++ struct usb_device_driver *new_udriver = data;
++ struct usb_device *udev;
++ int ret;
++
++ if (!is_dev_usb_generic_driver(dev))
++ return 0;
++
++ udev = to_usb_device(dev);
++ if (usb_device_match_id(udev, new_udriver->id_table) == NULL &&
++ (!new_udriver->match || new_udriver->match(udev) != 0))
++ return 0;
++
++ ret = device_reprobe(dev);
++ if (ret && ret != -EPROBE_DEFER)
++ dev_err(dev, "Failed to reprobe device (error %d)\n", ret);
++
++ return 0;
++}
++
+ /**
+ * usb_register_device_driver - register a USB device (not interface) driver
+ * @new_udriver: USB operations for the device driver
+@@ -934,13 +963,20 @@ int usb_register_device_driver(struct us
+
+ retval = driver_register(&new_udriver->drvwrap.driver);
+
+- if (!retval)
++ if (!retval) {
+ pr_info("%s: registered new device driver %s\n",
+ usbcore_name, new_udriver->name);
+- else
++ /*
++ * Check whether any device could be better served with
++ * this new driver
++ */
++ bus_for_each_dev(&usb_bus_type, NULL, new_udriver,
++ __usb_bus_reprobe_drivers);
++ } else {
+ printk(KERN_ERR "%s: error %d registering device "
+ " driver %s\n",
+ usbcore_name, retval, new_udriver->name);
++ }
+
+ return retval;
+ }
--- /dev/null
+From 2b74b0a04d3e9f9f08ff026e5663dce88ff94e52 Mon Sep 17 00:00:00 2001
+From: Brooke Basile <brookebasile@gmail.com>
+Date: Tue, 25 Aug 2020 09:07:27 -0400
+Subject: USB: gadget: f_ncm: add bounds checks to ncm_unwrap_ntb()
+
+From: Brooke Basile <brookebasile@gmail.com>
+
+commit 2b74b0a04d3e9f9f08ff026e5663dce88ff94e52 upstream.
+
+Some values extracted by ncm_unwrap_ntb() could possibly lead to several
+different out of bounds reads of memory. Specifically the values passed
+to netdev_alloc_skb_ip_align() need to be checked so that memory is not
+overflowed.
+
+Resolve this by applying bounds checking to a number of different
+indexes and lengths of the structure parsing logic.
+
+Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
+Signed-off-by: Brooke Basile <brookebasile@gmail.com>
+Acked-by: Felipe Balbi <balbi@kernel.org>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/gadget/function/f_ncm.c | 81 ++++++++++++++++++++++++++++++------
+ 1 file changed, 69 insertions(+), 12 deletions(-)
+
+--- a/drivers/usb/gadget/function/f_ncm.c
++++ b/drivers/usb/gadget/function/f_ncm.c
+@@ -1181,12 +1181,15 @@ static int ncm_unwrap_ntb(struct gether
+ int ndp_index;
+ unsigned dg_len, dg_len2;
+ unsigned ndp_len;
++ unsigned block_len;
+ struct sk_buff *skb2;
+ int ret = -EINVAL;
+- unsigned max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
++ unsigned ntb_max = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
++ unsigned frame_max = le16_to_cpu(ecm_desc.wMaxSegmentSize);
+ const struct ndp_parser_opts *opts = ncm->parser_opts;
+ unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
+ int dgram_counter;
++ bool ndp_after_header;
+
+ /* dwSignature */
+ if (get_unaligned_le32(tmp) != opts->nth_sign) {
+@@ -1205,25 +1208,37 @@ static int ncm_unwrap_ntb(struct gether
+ }
+ tmp++; /* skip wSequence */
+
++ block_len = get_ncm(&tmp, opts->block_length);
+ /* (d)wBlockLength */
+- if (get_ncm(&tmp, opts->block_length) > max_size) {
++ if (block_len > ntb_max) {
+ INFO(port->func.config->cdev, "OUT size exceeded\n");
+ goto err;
+ }
+
+ ndp_index = get_ncm(&tmp, opts->ndp_index);
++ ndp_after_header = false;
+
+ /* Run through all the NDP's in the NTB */
+ do {
+- /* NCM 3.2 */
+- if (((ndp_index % 4) != 0) &&
+- (ndp_index < opts->nth_size)) {
++ /*
++ * NCM 3.2
++ * dwNdpIndex
++ */
++ if (((ndp_index % 4) != 0) ||
++ (ndp_index < opts->nth_size) ||
++ (ndp_index > (block_len -
++ opts->ndp_size))) {
+ INFO(port->func.config->cdev, "Bad index: %#X\n",
+ ndp_index);
+ goto err;
+ }
++ if (ndp_index == opts->nth_size)
++ ndp_after_header = true;
+
+- /* walk through NDP */
++ /*
++ * walk through NDP
++ * dwSignature
++ */
+ tmp = (void *)(skb->data + ndp_index);
+ if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
+ INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
+@@ -1234,14 +1249,15 @@ static int ncm_unwrap_ntb(struct gether
+ ndp_len = get_unaligned_le16(tmp++);
+ /*
+ * NCM 3.3.1
++ * wLength
+ * entry is 2 items
+ * item size is 16/32 bits, opts->dgram_item_len * 2 bytes
+ * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
+ * Each entry is a dgram index and a dgram length.
+ */
+ if ((ndp_len < opts->ndp_size
+- + 2 * 2 * (opts->dgram_item_len * 2))
+- || (ndp_len % opts->ndplen_align != 0)) {
++ + 2 * 2 * (opts->dgram_item_len * 2)) ||
++ (ndp_len % opts->ndplen_align != 0)) {
+ INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
+ ndp_len);
+ goto err;
+@@ -1258,8 +1274,21 @@ static int ncm_unwrap_ntb(struct gether
+
+ do {
+ index = index2;
++ /* wDatagramIndex[0] */
++ if ((index < opts->nth_size) ||
++ (index > block_len - opts->dpe_size)) {
++ INFO(port->func.config->cdev,
++ "Bad index: %#X\n", index);
++ goto err;
++ }
++
+ dg_len = dg_len2;
+- if (dg_len < 14 + crc_len) { /* ethernet hdr + crc */
++ /*
++ * wDatagramLength[0]
++ * ethernet hdr + crc or larger than max frame size
++ */
++ if ((dg_len < 14 + crc_len) ||
++ (dg_len > frame_max)) {
+ INFO(port->func.config->cdev,
+ "Bad dgram length: %#X\n", dg_len);
+ goto err;
+@@ -1283,6 +1312,37 @@ static int ncm_unwrap_ntb(struct gether
+ index2 = get_ncm(&tmp, opts->dgram_item_len);
+ dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
+
++ if (index2 == 0 || dg_len2 == 0)
++ break;
++
++ /* wDatagramIndex[1] */
++ if (ndp_after_header) {
++ if (index2 < opts->nth_size + opts->ndp_size) {
++ INFO(port->func.config->cdev,
++ "Bad index: %#X\n", index2);
++ goto err;
++ }
++ } else {
++ if (index2 < opts->nth_size + opts->dpe_size) {
++ INFO(port->func.config->cdev,
++ "Bad index: %#X\n", index2);
++ goto err;
++ }
++ }
++ if (index2 > block_len - opts->dpe_size) {
++ INFO(port->func.config->cdev,
++ "Bad index: %#X\n", index2);
++ goto err;
++ }
++
++ /* wDatagramLength[1] */
++ if ((dg_len2 < 14 + crc_len) ||
++ (dg_len2 > frame_max)) {
++ INFO(port->func.config->cdev,
++ "Bad dgram length: %#X\n", dg_len);
++ goto err;
++ }
++
+ /*
+ * Copy the data into a new skb.
+ * This ensures the truesize is correct
+@@ -1299,9 +1359,6 @@ static int ncm_unwrap_ntb(struct gether
+ ndp_len -= 2 * (opts->dgram_item_len * 2);
+
+ dgram_counter++;
+-
+- if (index2 == 0 || dg_len2 == 0)
+- break;
+ } while (ndp_len > 2 * (opts->dgram_item_len * 2));
+ } while (ndp_index);
+
--- /dev/null
+From b1cd1b65afba95971fa457dfdb2c941c60d38c5b Mon Sep 17 00:00:00 2001
+From: Brooke Basile <brookebasile@gmail.com>
+Date: Tue, 25 Aug 2020 09:05:08 -0400
+Subject: USB: gadget: u_f: add overflow checks to VLA macros
+
+From: Brooke Basile <brookebasile@gmail.com>
+
+commit b1cd1b65afba95971fa457dfdb2c941c60d38c5b upstream.
+
+size can potentially hold an overflowed value if its assigned expression
+is left unchecked, leading to a smaller than needed allocation when
+vla_group_size() is used by callers to allocate memory.
+To fix this, add a test for saturation before declaring variables and an
+overflow check to (n) * sizeof(type).
+If the expression results in overflow, vla_group_size() will return SIZE_MAX.
+
+Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
+Suggested-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: Brooke Basile <brookebasile@gmail.com>
+Acked-by: Felipe Balbi <balbi@kernel.org>
+Cc: stable <stable@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/gadget/u_f.h | 38 +++++++++++++++++++++++++++-----------
+ 1 file changed, 27 insertions(+), 11 deletions(-)
+
+--- a/drivers/usb/gadget/u_f.h
++++ b/drivers/usb/gadget/u_f.h
+@@ -14,6 +14,7 @@
+ #define __U_F_H__
+
+ #include <linux/usb/gadget.h>
++#include <linux/overflow.h>
+
+ /* Variable Length Array Macros **********************************************/
+ #define vla_group(groupname) size_t groupname##__next = 0
+@@ -21,21 +22,36 @@
+
+ #define vla_item(groupname, type, name, n) \
+ size_t groupname##_##name##__offset = ({ \
+- size_t align_mask = __alignof__(type) - 1; \
+- size_t offset = (groupname##__next + align_mask) & ~align_mask;\
+- size_t size = (n) * sizeof(type); \
+- groupname##__next = offset + size; \
++ size_t offset = 0; \
++ if (groupname##__next != SIZE_MAX) { \
++ size_t align_mask = __alignof__(type) - 1; \
++ size_t offset = (groupname##__next + align_mask) \
++ & ~align_mask; \
++ size_t size = array_size(n, sizeof(type)); \
++ if (check_add_overflow(offset, size, \
++ &groupname##__next)) { \
++ groupname##__next = SIZE_MAX; \
++ offset = 0; \
++ } \
++ } \
+ offset; \
+ })
+
+ #define vla_item_with_sz(groupname, type, name, n) \
+- size_t groupname##_##name##__sz = (n) * sizeof(type); \
+- size_t groupname##_##name##__offset = ({ \
+- size_t align_mask = __alignof__(type) - 1; \
+- size_t offset = (groupname##__next + align_mask) & ~align_mask;\
+- size_t size = groupname##_##name##__sz; \
+- groupname##__next = offset + size; \
+- offset; \
++ size_t groupname##_##name##__sz = array_size(n, sizeof(type)); \
++ size_t groupname##_##name##__offset = ({ \
++ size_t offset = 0; \
++ if (groupname##__next != SIZE_MAX) { \
++ size_t align_mask = __alignof__(type) - 1; \
++ size_t offset = (groupname##__next + align_mask) \
++ & ~align_mask; \
++ if (check_add_overflow(offset, groupname##_##name##__sz,\
++ &groupname##__next)) { \
++ groupname##__next = SIZE_MAX; \
++ offset = 0; \
++ } \
++ } \
++ offset; \
+ })
+
+ #define vla_ptr(ptr, groupname, name) \
--- /dev/null
+From bfd08d06d978d0304eb6f7855b548aa2cd1c5486 Mon Sep 17 00:00:00 2001
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Date: Wed, 26 Aug 2020 22:21:19 +0300
+Subject: USB: gadget: u_f: Unbreak offset calculation in VLAs
+
+From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+
+commit bfd08d06d978d0304eb6f7855b548aa2cd1c5486 upstream.
+
+Inadvertently the commit b1cd1b65afba ("USB: gadget: u_f: add overflow checks
+to VLA macros") makes VLA macros to always return 0 due to different scope of
+two variables of the same name. Obviously we need to have only one.
+
+Fixes: b1cd1b65afba ("USB: gadget: u_f: add overflow checks to VLA macros")
+Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+Cc: Brooke Basile <brookebasile@gmail.com>
+Cc: stable <stable@kernel.org>
+Link: https://lore.kernel.org/r/20200826192119.56450-1-andriy.shevchenko@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/gadget/u_f.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/gadget/u_f.h
++++ b/drivers/usb/gadget/u_f.h
+@@ -25,9 +25,9 @@
+ size_t offset = 0; \
+ if (groupname##__next != SIZE_MAX) { \
+ size_t align_mask = __alignof__(type) - 1; \
+- size_t offset = (groupname##__next + align_mask) \
+- & ~align_mask; \
+ size_t size = array_size(n, sizeof(type)); \
++ offset = (groupname##__next + align_mask) & \
++ ~align_mask; \
+ if (check_add_overflow(offset, size, \
+ &groupname##__next)) { \
+ groupname##__next = SIZE_MAX; \
+@@ -43,8 +43,8 @@
+ size_t offset = 0; \
+ if (groupname##__next != SIZE_MAX) { \
+ size_t align_mask = __alignof__(type) - 1; \
+- size_t offset = (groupname##__next + align_mask) \
+- & ~align_mask; \
++ offset = (groupname##__next + align_mask) & \
++ ~align_mask; \
+ if (check_add_overflow(offset, groupname##_##name##__sz,\
+ &groupname##__next)) { \
+ groupname##__next = SIZE_MAX; \
--- /dev/null
+From 1d4169834628d18b2392a2da92b7fbf5e8e2ce89 Mon Sep 17 00:00:00 2001
+From: Tang Bin <tangbin@cmss.chinamobile.com>
+Date: Wed, 26 Aug 2020 22:49:31 +0800
+Subject: usb: host: ohci-exynos: Fix error handling in exynos_ohci_probe()
+
+From: Tang Bin <tangbin@cmss.chinamobile.com>
+
+commit 1d4169834628d18b2392a2da92b7fbf5e8e2ce89 upstream.
+
+If the function platform_get_irq() failed, the negative value
+returned will not be detected here. So fix error handling in
+exynos_ohci_probe(). And when get irq failed, the function
+platform_get_irq() logs an error message, so remove redundant
+message here.
+
+Fixes: 62194244cf87 ("USB: Add Samsung Exynos OHCI diver")
+Signed-off-by: Zhang Shengju <zhangshengju@cmss.chinamobile.com>
+Cc: stable <stable@vger.kernel.org>
+Signed-off-by: Tang Bin <tangbin@cmss.chinamobile.com>
+Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
+Link: https://lore.kernel.org/r/20200826144931.1828-1-tangbin@cmss.chinamobile.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/host/ohci-exynos.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/ohci-exynos.c
++++ b/drivers/usb/host/ohci-exynos.c
+@@ -171,9 +171,8 @@ static int exynos_ohci_probe(struct plat
+ hcd->rsrc_len = resource_size(res);
+
+ irq = platform_get_irq(pdev, 0);
+- if (!irq) {
+- dev_err(&pdev->dev, "Failed to get IRQ\n");
+- err = -ENODEV;
++ if (irq < 0) {
++ err = irq;
+ goto fail_io;
+ }
+
--- /dev/null
+From 9aa37788e7ebb3f489fb4b71ce07adadd444264a Mon Sep 17 00:00:00 2001
+From: Cyril Roelandt <tipecaml@gmail.com>
+Date: Tue, 25 Aug 2020 23:22:31 +0200
+Subject: USB: Ignore UAS for JMicron JMS567 ATA/ATAPI Bridge
+
+From: Cyril Roelandt <tipecaml@gmail.com>
+
+commit 9aa37788e7ebb3f489fb4b71ce07adadd444264a upstream.
+
+This device does not support UAS properly and a similar entry already
+exists in drivers/usb/storage/unusual_uas.h. Without this patch,
+storage_probe() defers the handling of this device to UAS, which cannot
+handle it either.
+
+Tested-by: Brice Goglin <brice.goglin@gmail.com>
+Fixes: bc3bdb12bbb3 ("usb-storage: Disable UAS on JMicron SATA enclosure")
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+CC: <stable@vger.kernel.org>
+Signed-off-by: Cyril Roelandt <tipecaml@gmail.com>
+Link: https://lore.kernel.org/r/20200825212231.46309-1-tipecaml@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/storage/unusual_devs.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -2328,7 +2328,7 @@ UNUSUAL_DEV( 0x357d, 0x7788, 0x0114, 0x
+ "JMicron",
+ "USB to ATA/ATAPI Bridge",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+- US_FL_BROKEN_FUA ),
++ US_FL_BROKEN_FUA | US_FL_IGNORE_UAS ),
+
+ /* Reported by Andrey Rahmatullin <wrar@altlinux.org> */
+ UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100,
--- /dev/null
+From 5967116e8358899ebaa22702d09b0af57fef23e1 Mon Sep 17 00:00:00 2001
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Date: Fri, 31 Jul 2020 13:16:20 +0800
+Subject: USB: quirks: Add no-lpm quirk for another Raydium touchscreen
+
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+
+commit 5967116e8358899ebaa22702d09b0af57fef23e1 upstream.
+
+There's another Raydium touchscreen needs the no-lpm quirk:
+[ 1.339149] usb 1-9: New USB device found, idVendor=2386, idProduct=350e, bcdDevice= 0.00
+[ 1.339150] usb 1-9: New USB device strings: Mfr=1, Product=2, SerialNumber=0
+[ 1.339151] usb 1-9: Product: Raydium Touch System
+[ 1.339152] usb 1-9: Manufacturer: Raydium Corporation
+...
+[ 6.450497] usb 1-9: can't set config #1, error -110
+
+BugLink: https://bugs.launchpad.net/bugs/1889446
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Cc: stable <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20200731051622.28643-1-kai.heng.feng@canonical.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/quirks.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/usb/core/quirks.c
++++ b/drivers/usb/core/quirks.c
+@@ -465,6 +465,8 @@ static const struct usb_device_id usb_qu
+
+ { USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM },
+
++ { USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
++
+ /* DJI CineSSD */
+ { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
+
--- /dev/null
+From 068834a2773b6a12805105cfadbb3d4229fc6e0a Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Wed, 26 Aug 2020 15:46:24 -0400
+Subject: USB: quirks: Ignore duplicate endpoint on Sound Devices MixPre-D
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 068834a2773b6a12805105cfadbb3d4229fc6e0a upstream.
+
+The Sound Devices MixPre-D audio card suffers from the same defect
+as the Sound Devices USBPre2: an endpoint shared between a normal
+audio interface and a vendor-specific interface, in violation of the
+USB spec. Since the USB core now treats duplicated endpoints as bugs
+and ignores them, the audio endpoint isn't available and the card
+can't be used for audio capture.
+
+Along the same lines as commit bdd1b147b802 ("USB: quirks: blacklist
+duplicate ep on Sound Devices USBPre2"), this patch adds a quirks
+entry saying to ignore ep5in for interface 1, leaving it available for
+use with standard audio interface 2.
+
+Reported-and-tested-by: Jean-Christophe Barnoud <jcbarnoud@gmail.com>
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+CC: <stable@vger.kernel.org>
+Fixes: 3e4f8e21c4f2 ("USB: core: fix check for duplicate endpoints")
+Link: https://lore.kernel.org/r/20200826194624.GA412633@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/quirks.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/usb/core/quirks.c
++++ b/drivers/usb/core/quirks.c
+@@ -370,6 +370,10 @@ static const struct usb_device_id usb_qu
+ { USB_DEVICE(0x0926, 0x0202), .driver_info =
+ USB_QUIRK_ENDPOINT_BLACKLIST },
+
++ /* Sound Devices MixPre-D */
++ { USB_DEVICE(0x0926, 0x0208), .driver_info =
++ USB_QUIRK_ENDPOINT_BLACKLIST },
++
+ /* Keytouch QWERTY Panel keyboard */
+ { USB_DEVICE(0x0926, 0x3333), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+@@ -511,6 +515,7 @@ static const struct usb_device_id usb_am
+ */
+ static const struct usb_device_id usb_endpoint_blacklist[] = {
+ { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 },
++ { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0208, 1), .driver_info = 0x85 },
+ { }
+ };
+
--- /dev/null
+From 20934c0de13b49a072fb1e0ca79fe0fe0e40eae5 Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Wed, 26 Aug 2020 10:32:29 -0400
+Subject: usb: storage: Add unusual_uas entry for Sony PSZ drives
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit 20934c0de13b49a072fb1e0ca79fe0fe0e40eae5 upstream.
+
+The PSZ-HA* family of USB disk drives from Sony can't handle the
+REPORT OPCODES command when using the UAS protocol. This patch adds
+an appropriate quirks entry.
+
+Reported-and-tested-by: Till Dörges <doerges@pre-sense.de>
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+CC: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20200826143229.GB400430@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/storage/unusual_uas.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/usb/storage/unusual_uas.h
++++ b/drivers/usb/storage/unusual_uas.h
+@@ -28,6 +28,13 @@
+ * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org>
+ */
+
++/* Reported-by: Till Dörges <doerges@pre-sense.de> */
++UNUSUAL_DEV(0x054c, 0x087d, 0x0000, 0x9999,
++ "Sony",
++ "PSZ-HA*",
++ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++ US_FL_NO_REPORT_OPCODES),
++
+ /* Reported-by: Julian Groß <julian.g@posteo.de> */
+ UNUSUAL_DEV(0x059f, 0x105f, 0x0000, 0x9999,
+ "LaCie",
--- /dev/null
+From 23e26d0577535f5ffe4ff8ed6d06e009553c0bca Mon Sep 17 00:00:00 2001
+From: Badhri Jagan Sridharan <badhri@google.com>
+Date: Mon, 17 Aug 2020 11:46:01 -0700
+Subject: usb: typec: tcpm: Fix Fix source hard reset response for TDA 2.3.1.1 and TDA 2.3.1.2 failures
+
+From: Badhri Jagan Sridharan <badhri@google.com>
+
+commit 23e26d0577535f5ffe4ff8ed6d06e009553c0bca upstream.
+
+The patch addresses the compliance test failures while running TDA
+2.3.1.1 and TDA 2.3.1.2 of the "PD Communications Engine USB PD
+Compliance MOI" test plan published in https://www.usb.org/usbc.
+For a product to be Type-C compliant, it's expected that these tests
+are run on usb.org certified Type-C compliance tester as mentioned in
+https://www.usb.org/usbc.
+
+While the purpose of TDA 2.3.1.1 and TDA 2.3.1.2 is to verify that
+the static and dynamic electrical capabilities of a Source meet the
+requirements for each PDO offered, while doing so, the tests also
+monitor that the timing of the VBUS waveform versus the messages meets
+the requirements for Hard Reset defined in PROT-PROC-HR-TSTR as
+mentioned in step 11 of TDA.2.3.1.1 and step 15 of TDA.2.3.1.2.
+
+TDB.2.2.13.1: PROT-PROC-HR-TSTR Procedure and Checks for Tester
+Originated Hard Reset
+Purpose: To perform the appropriate protocol checks relating to any
+circumstance in which the Hard Reset signal is sent by the Tester.
+
+UUT is behaving as source:
+The Tester sends a Hard Reset signal.
+1. Check VBUS stays within present valid voltage range for
+tPSHardReset min (25ms) after last bit of Hard Reset signal.
+[PROT_PROC_HR_TSTR_1]
+2. Check that VBUS starts to fall below present valid voltage range by
+tPSHardReset max (35ms). [PROT_PROC_HR_TSTR_2]
+3. Check that VBUS reaches vSafe0V within tSafe0v max (650 ms).
+[PROT_PROC_HR_TSTR_3]
+4. Check that VBUS starts rising to vSafe5V after a delay of
+tSrcRecover (0.66s - 1s) from reaching vSafe0V. [PROT_PROC_HR_TSTR_4]
+5. Check that VBUS reaches vSafe5V within tSrcTurnOn max (275ms) of
+rising above vSafe0v max (0.8V). [PROT_PROC_HR_TSTR_5] Power Delivery
+Compliance Plan 139 6. Check that Source Capabilities are finished
+sending within tFirstSourceCap max (250ms) of VBUS reaching vSafe5v
+min. [PROT_PROC_HR_TSTR_6].
+
+This is in line with 7.1.5 Response to Hard Resets of the USB Power
+Delivery Specification Revision 3.0, Version 1.2,
+"Hard Reset Signaling indicates a communication failure has occurred
+and the Source Shall stop driving VCONN, Shall remove Rp from the
+VCONN pin and Shall drive VBUS to vSafe0V as shown in Figure 7-9. The
+USB connection May reset during a Hard Reset since the VBUS voltage
+will be less than vSafe5V for an extended period of time. After
+establishing the vSafe0V voltage condition on VBUS, the Source Shall
+wait tSrcRecover before re-applying VCONN and restoring VBUS to
+vSafe5V. A Source Shall conform to the VCONN timing as specified in
+[USB Type-C 1.3]."
+
+With the above guidelines from the spec in mind, TCPM does not turn
+off VCONN while entering SRC_HARD_RESET_VBUS_OFF. The patch makes TCPM
+turn off VCONN while entering SRC_HARD_RESET_VBUS_OFF and turn it back
+on while entering SRC_HARD_RESET_VBUS_ON along with vbus instead of
+having VCONN on through hardreset.
+
+Also, the spec clearly states that "After establishing the vSafe0V
+voltage condition on VBUS", the Source Shall wait tSrcRecover before
+re-applying VCONN and restoring VBUS to vSafe5V.
+TCPM does not conform to this requirement. If the TCPC driver calls
+tcpm_vbus_change with vbus off signal, TCPM right away enters
+SRC_HARD_RESET_VBUS_ON without waiting for tSrcRecover.
+For TCPC's which are buggy/does not call tcpm_vbus_change, TCPM
+assumes that the vsafe0v is instantaneous as TCPM only waits
+tSrcRecover instead of waiting for tSafe0v + tSrcRecover.
+This patch also fixes this behavior by making sure that TCPM waits for
+tSrcRecover before transitioning into SRC_HARD_RESET_VBUS_ON when
+tcpm_vbus_change is called by TCPC.
+When TCPC does not call tcpm_vbus_change, TCPM assumes the worst case
+i.e. tSafe0v + tSrcRecover before transitioning into
+SRC_HARD_RESET_VBUS_ON.
+
+Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Cc: stable <stable@kernel.org>
+Link: https://lore.kernel.org/r/20200817184601.1899929-1-badhri@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/typec/tcpm/tcpm.c | 28 +++++++++++++++++++++++++---
+ 1 file changed, 25 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/typec/tcpm/tcpm.c
++++ b/drivers/usb/typec/tcpm/tcpm.c
+@@ -3321,13 +3321,31 @@ static void run_state_machine(struct tcp
+ tcpm_set_state(port, SNK_HARD_RESET_SINK_OFF, 0);
+ break;
+ case SRC_HARD_RESET_VBUS_OFF:
+- tcpm_set_vconn(port, true);
++ /*
++ * 7.1.5 Response to Hard Resets
++ * Hard Reset Signaling indicates a communication failure has occurred and the
++ * Source Shall stop driving VCONN, Shall remove Rp from the VCONN pin and Shall
++ * drive VBUS to vSafe0V as shown in Figure 7-9.
++ */
++ tcpm_set_vconn(port, false);
+ tcpm_set_vbus(port, false);
+ tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE,
+ tcpm_data_role_for_source(port));
+- tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
++ /*
++ * If tcpc fails to notify vbus off, TCPM will wait for PD_T_SAFE_0V +
++ * PD_T_SRC_RECOVER before turning vbus back on.
++ * From Table 7-12 Sequence Description for a Source Initiated Hard Reset:
++ * 4. Policy Engine waits tPSHardReset after sending Hard Reset Signaling and then
++ * tells the Device Policy Manager to instruct the power supply to perform a
++ * Hard Reset. The transition to vSafe0V Shall occur within tSafe0V (t2).
++ * 5. After tSrcRecover the Source applies power to VBUS in an attempt to
++ * re-establish communication with the Sink and resume USB Default Operation.
++ * The transition to vSafe5V Shall occur within tSrcTurnOn(t4).
++ */
++ tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SAFE_0V + PD_T_SRC_RECOVER);
+ break;
+ case SRC_HARD_RESET_VBUS_ON:
++ tcpm_set_vconn(port, true);
+ tcpm_set_vbus(port, true);
+ port->tcpc->set_pd_rx(port->tcpc, true);
+ tcpm_set_attached_state(port, true);
+@@ -3887,7 +3905,11 @@ static void _tcpm_pd_vbus_off(struct tcp
+ tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0);
+ break;
+ case SRC_HARD_RESET_VBUS_OFF:
+- tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, 0);
++ /*
++ * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
++ * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
++ */
++ tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
+ break;
+ case HARD_RESET_SEND:
+ break;
--- /dev/null
+From 7e90057f125c8c852940b848e06e7a72f050fc6f Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 9 Aug 2020 16:19:02 +0200
+Subject: usb: typec: ucsi: Fix 2 unlocked ucsi_run_command calls
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit 7e90057f125c8c852940b848e06e7a72f050fc6f upstream.
+
+Fix 2 unlocked ucsi_run_command calls:
+
+1. ucsi_handle_connector_change() contains one ucsi_send_command() call,
+which takes the ppm_lock for it; and one ucsi_run_command() call which
+relies on the caller have taking the ppm_lock.
+ucsi_handle_connector_change() does not take the lock, so the
+second (ucsi_run_command) calls should also be ucsi_send_command().
+
+2. ucsi_get_pdos() gets called from ucsi_handle_connector_change() which
+does not hold the ppm_lock, so it also must use ucsi_send_command().
+
+This commit also adds a WARN_ON(!mutex_is_locked(&ucsi->ppm_lock)); to
+ucsi_run_command() to avoid similar problems getting re-introduced in
+the future.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20200809141904.4317-3-hdegoede@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/typec/ucsi/ucsi.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -152,6 +152,8 @@ static int ucsi_run_command(struct ucsi
+ u8 length;
+ int ret;
+
++ WARN_ON(!mutex_is_locked(&ucsi->ppm_lock));
++
+ ret = ucsi_exec_command(ucsi, command);
+ if (ret < 0)
+ return ret;
+@@ -502,7 +504,7 @@ static void ucsi_get_pdos(struct ucsi_co
+ command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner);
+ command |= UCSI_GET_PDOS_NUM_PDOS(UCSI_MAX_PDOS - 1);
+ command |= UCSI_GET_PDOS_SRC_PDOS;
+- ret = ucsi_run_command(ucsi, command, con->src_pdos,
++ ret = ucsi_send_command(ucsi, command, con->src_pdos,
+ sizeof(con->src_pdos));
+ if (ret < 0) {
+ dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret);
+@@ -681,7 +683,7 @@ static void ucsi_handle_connector_change
+ */
+ command = UCSI_GET_CAM_SUPPORTED;
+ command |= UCSI_CONNECTOR_NUMBER(con->num);
+- ucsi_run_command(con->ucsi, command, NULL, 0);
++ ucsi_send_command(con->ucsi, command, NULL, 0);
+ }
+
+ if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE)
--- /dev/null
+From 0ff0705a2ef2929e9326c95df48bdbebb0dafaad Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 9 Aug 2020 16:19:01 +0200
+Subject: usb: typec: ucsi: Fix AB BA lock inversion
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit 0ff0705a2ef2929e9326c95df48bdbebb0dafaad upstream.
+
+Lockdep reports an AB BA lock inversion between ucsi_init() and
+ucsi_handle_connector_change():
+
+AB order:
+
+1. ucsi_init takes ucsi->ppm_lock (it runs with that locked for the
+ duration of the function)
+2. usci_init eventually end up calling ucsi_register_displayport,
+ which takes ucsi_connector->lock
+
+BA order:
+
+1. ucsi_handle_connector_change work is started, takes ucsi_connector->lock
+2. ucsi_handle_connector_change calls ucsi_send_command which takes
+ ucsi->ppm_lock
+
+The ppm_lock really only needs to be hold during 2 functions:
+ucsi_reset_ppm() and ucsi_run_command().
+
+This commit fixes the AB BA lock inversion by making ucsi_init drop the
+ucsi->ppm_lock before it starts registering ports; and replacing any
+ucsi_run_command() calls after this point with ucsi_send_command()
+(which is a wrapper around run_command taking the lock while handling
+the command).
+
+Some of the replacing of ucsi_run_command with ucsi_send_command
+in the helpers used during port registration also fixes a number of
+code paths after registration which call ucsi_run_command() without
+holding the ppm_lock:
+1. ucsi_altmode_update_active() call in ucsi/displayport.c
+2. ucsi_register_altmodes() call from ucsi_handle_connector_change()
+ (through ucsi_partner_change())
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20200809141904.4317-2-hdegoede@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/typec/ucsi/ucsi.c | 18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -205,7 +205,7 @@ void ucsi_altmode_update_active(struct u
+ int i;
+
+ command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num);
+- ret = ucsi_run_command(con->ucsi, command, &cur, sizeof(cur));
++ ret = ucsi_send_command(con->ucsi, command, &cur, sizeof(cur));
+ if (ret < 0) {
+ if (con->ucsi->version > 0x0100) {
+ dev_err(con->ucsi->dev,
+@@ -354,7 +354,7 @@ ucsi_register_altmodes_nvidia(struct ucs
+ command |= UCSI_GET_ALTMODE_RECIPIENT(recipient);
+ command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num);
+ command |= UCSI_GET_ALTMODE_OFFSET(i);
+- len = ucsi_run_command(con->ucsi, command, &alt, sizeof(alt));
++ len = ucsi_send_command(con->ucsi, command, &alt, sizeof(alt));
+ /*
+ * We are collecting all altmodes first and then registering.
+ * Some type-C device will return zero length data beyond last
+@@ -431,7 +431,7 @@ static int ucsi_register_altmodes(struct
+ command |= UCSI_GET_ALTMODE_RECIPIENT(recipient);
+ command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num);
+ command |= UCSI_GET_ALTMODE_OFFSET(i);
+- len = ucsi_run_command(con->ucsi, command, alt, sizeof(alt));
++ len = ucsi_send_command(con->ucsi, command, alt, sizeof(alt));
+ if (len <= 0)
+ return len;
+
+@@ -904,7 +904,7 @@ static int ucsi_register_port(struct ucs
+ /* Get connector capability */
+ command = UCSI_GET_CONNECTOR_CAPABILITY;
+ command |= UCSI_CONNECTOR_NUMBER(con->num);
+- ret = ucsi_run_command(ucsi, command, &con->cap, sizeof(con->cap));
++ ret = ucsi_send_command(ucsi, command, &con->cap, sizeof(con->cap));
+ if (ret < 0)
+ return ret;
+
+@@ -953,8 +953,7 @@ static int ucsi_register_port(struct ucs
+
+ /* Get the status */
+ command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
+- ret = ucsi_run_command(ucsi, command, &con->status,
+- sizeof(con->status));
++ ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status));
+ if (ret < 0) {
+ dev_err(ucsi->dev, "con%d: failed to get status\n", con->num);
+ return 0;
+@@ -1044,6 +1043,8 @@ int ucsi_init(struct ucsi *ucsi)
+ goto err_reset;
+ }
+
++ mutex_unlock(&ucsi->ppm_lock);
++
+ /* Register all connectors */
+ for (i = 0; i < ucsi->cap.num_connectors; i++) {
+ ret = ucsi_register_port(ucsi, i);
+@@ -1054,12 +1055,10 @@ int ucsi_init(struct ucsi *ucsi)
+ /* Enable all notifications */
+ ucsi->ntfy = UCSI_ENABLE_NTFY_ALL;
+ command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy;
+- ret = ucsi_run_command(ucsi, command, NULL, 0);
++ ret = ucsi_send_command(ucsi, command, NULL, 0);
+ if (ret < 0)
+ goto err_unregister;
+
+- mutex_unlock(&ucsi->ppm_lock);
+-
+ return 0;
+
+ err_unregister:
+@@ -1071,6 +1070,7 @@ err_unregister:
+ con->port = NULL;
+ }
+
++ mutex_lock(&ucsi->ppm_lock);
+ err_reset:
+ ucsi_reset_ppm(ucsi);
+ err:
--- /dev/null
+From bed97b30968ba354035a020989df0623e52b5536 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 9 Aug 2020 16:19:04 +0200
+Subject: usb: typec: ucsi: Hold con->lock for the entire duration of ucsi_register_port()
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit bed97b30968ba354035a020989df0623e52b5536 upstream.
+
+Commit 081da1325d35 ("usb: typec: ucsi: displayport: Fix a potential race
+during registration") made the ucsi code hold con->lock in
+ucsi_register_displayport(). But we really don't want any interactions
+with the connector to run before the port-registration process is fully
+complete.
+
+This commit moves the taking of con->lock from ucsi_register_displayport()
+into ucsi_register_port() to achieve this.
+
+Cc: stable@vger.kernel.org
+Fixes: 081da1325d35 ("usb: typec: ucsi: displayport: Fix a potential race during registration")
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20200809141904.4317-5-hdegoede@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/typec/ucsi/displayport.c | 9 +--------
+ drivers/usb/typec/ucsi/ucsi.c | 31 ++++++++++++++++++++++---------
+ 2 files changed, 23 insertions(+), 17 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/displayport.c
++++ b/drivers/usb/typec/ucsi/displayport.c
+@@ -288,8 +288,6 @@ struct typec_altmode *ucsi_register_disp
+ struct typec_altmode *alt;
+ struct ucsi_dp *dp;
+
+- mutex_lock(&con->lock);
+-
+ /* We can't rely on the firmware with the capabilities. */
+ desc->vdo |= DP_CAP_DP_SIGNALING | DP_CAP_RECEPTACLE;
+
+@@ -298,15 +296,12 @@ struct typec_altmode *ucsi_register_disp
+ desc->vdo |= all_assignments << 16;
+
+ alt = typec_port_register_altmode(con->port, desc);
+- if (IS_ERR(alt)) {
+- mutex_unlock(&con->lock);
++ if (IS_ERR(alt))
+ return alt;
+- }
+
+ dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
+ if (!dp) {
+ typec_unregister_altmode(alt);
+- mutex_unlock(&con->lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
+@@ -319,7 +314,5 @@ struct typec_altmode *ucsi_register_disp
+ alt->ops = &ucsi_displayport_ops;
+ typec_altmode_set_drvdata(alt, dp);
+
+- mutex_unlock(&con->lock);
+-
+ return alt;
+ }
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -898,12 +898,15 @@ static int ucsi_register_port(struct ucs
+ con->num = index + 1;
+ con->ucsi = ucsi;
+
++ /* Delay other interactions with the con until registration is complete */
++ mutex_lock(&con->lock);
++
+ /* Get connector capability */
+ command = UCSI_GET_CONNECTOR_CAPABILITY;
+ command |= UCSI_CONNECTOR_NUMBER(con->num);
+ ret = ucsi_send_command(ucsi, command, &con->cap, sizeof(con->cap));
+ if (ret < 0)
+- return ret;
++ goto out;
+
+ if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP)
+ cap->data = TYPEC_PORT_DRD;
+@@ -935,26 +938,32 @@ static int ucsi_register_port(struct ucs
+
+ ret = ucsi_register_port_psy(con);
+ if (ret)
+- return ret;
++ goto out;
+
+ /* Register the connector */
+ con->port = typec_register_port(ucsi->dev, cap);
+- if (IS_ERR(con->port))
+- return PTR_ERR(con->port);
++ if (IS_ERR(con->port)) {
++ ret = PTR_ERR(con->port);
++ goto out;
++ }
+
+ /* Alternate modes */
+ ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON);
+- if (ret)
++ if (ret) {
+ dev_err(ucsi->dev, "con%d: failed to register alt modes\n",
+ con->num);
++ goto out;
++ }
+
+ /* Get the status */
+ command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
+ ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status));
+ if (ret < 0) {
+ dev_err(ucsi->dev, "con%d: failed to get status\n", con->num);
+- return 0;
++ ret = 0;
++ goto out;
+ }
++ ret = 0; /* ucsi_send_command() returns length on success */
+
+ switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
+ case UCSI_CONSTAT_PARTNER_TYPE_UFP:
+@@ -979,17 +988,21 @@ static int ucsi_register_port(struct ucs
+
+ if (con->partner) {
+ ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP);
+- if (ret)
++ if (ret) {
+ dev_err(ucsi->dev,
+ "con%d: failed to register alternate modes\n",
+ con->num);
+- else
++ ret = 0;
++ } else {
+ ucsi_altmode_update_active(con);
++ }
+ }
+
+ trace_ucsi_register_port(con->num, &con->status);
+
+- return 0;
++out:
++ mutex_unlock(&con->lock);
++ return ret;
+ }
+
+ /**
--- /dev/null
+From 25794e3079d2a98547b6bf5764ef0240aa89b798 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 9 Aug 2020 16:19:03 +0200
+Subject: usb: typec: ucsi: Rework ppm_lock handling
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit 25794e3079d2a98547b6bf5764ef0240aa89b798 upstream.
+
+The ppm_lock really only needs to be hold during 2 functions:
+ucsi_reset_ppm() and ucsi_run_command().
+
+Push the taking of the lock down into these 2 functions, renaming
+ucsi_run_command() to ucsi_send_command() which was an existing
+wrapper already taking the lock for its callers.
+
+This simplifies things for the callers and removes the difference
+between ucsi_send_command() and ucsi_run_command() which has led
+to various locking bugs in the past.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Reviewed-by: Guenter Roeck <linux@roeck-us.net>
+Link: https://lore.kernel.org/r/20200809141904.4317-4-hdegoede@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/typec/ucsi/ucsi.c | 56 ++++++++++++++++--------------------------
+ 1 file changed, 22 insertions(+), 34 deletions(-)
+
+--- a/drivers/usb/typec/ucsi/ucsi.c
++++ b/drivers/usb/typec/ucsi/ucsi.c
+@@ -146,42 +146,33 @@ static int ucsi_exec_command(struct ucsi
+ return UCSI_CCI_LENGTH(cci);
+ }
+
+-static int ucsi_run_command(struct ucsi *ucsi, u64 command,
+- void *data, size_t size)
++int ucsi_send_command(struct ucsi *ucsi, u64 command,
++ void *data, size_t size)
+ {
+ u8 length;
+ int ret;
+
+- WARN_ON(!mutex_is_locked(&ucsi->ppm_lock));
++ mutex_lock(&ucsi->ppm_lock);
+
+ ret = ucsi_exec_command(ucsi, command);
+ if (ret < 0)
+- return ret;
++ goto out;
+
+ length = ret;
+
+ if (data) {
+ ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size);
+ if (ret)
+- return ret;
++ goto out;
+ }
+
+ ret = ucsi_acknowledge_command(ucsi);
+ if (ret)
+- return ret;
+-
+- return length;
+-}
++ goto out;
+
+-int ucsi_send_command(struct ucsi *ucsi, u64 command,
+- void *retval, size_t size)
+-{
+- int ret;
+-
+- mutex_lock(&ucsi->ppm_lock);
+- ret = ucsi_run_command(ucsi, command, retval, size);
++ ret = length;
++out:
+ mutex_unlock(&ucsi->ppm_lock);
+-
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(ucsi_send_command);
+@@ -738,20 +729,24 @@ static int ucsi_reset_ppm(struct ucsi *u
+ u32 cci;
+ int ret;
+
++ mutex_lock(&ucsi->ppm_lock);
++
+ ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command,
+ sizeof(command));
+ if (ret < 0)
+- return ret;
++ goto out;
+
+ tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
+
+ do {
+- if (time_is_before_jiffies(tmo))
+- return -ETIMEDOUT;
++ if (time_is_before_jiffies(tmo)) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
+
+ ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci));
+ if (ret)
+- return ret;
++ goto out;
+
+ /* If the PPM is still doing something else, reset it again. */
+ if (cci & ~UCSI_CCI_RESET_COMPLETE) {
+@@ -759,13 +754,15 @@ static int ucsi_reset_ppm(struct ucsi *u
+ &command,
+ sizeof(command));
+ if (ret < 0)
+- return ret;
++ goto out;
+ }
+
+ msleep(20);
+ } while (!(cci & UCSI_CCI_RESET_COMPLETE));
+
+- return 0;
++out:
++ mutex_unlock(&ucsi->ppm_lock);
++ return ret;
+ }
+
+ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
+@@ -777,9 +774,7 @@ static int ucsi_role_cmd(struct ucsi_con
+ u64 c;
+
+ /* PPM most likely stopped responding. Resetting everything. */
+- mutex_lock(&con->ucsi->ppm_lock);
+ ucsi_reset_ppm(con->ucsi);
+- mutex_unlock(&con->ucsi->ppm_lock);
+
+ c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy;
+ ucsi_send_command(con->ucsi, c, NULL, 0);
+@@ -1010,8 +1005,6 @@ int ucsi_init(struct ucsi *ucsi)
+ int ret;
+ int i;
+
+- mutex_lock(&ucsi->ppm_lock);
+-
+ /* Reset the PPM */
+ ret = ucsi_reset_ppm(ucsi);
+ if (ret) {
+@@ -1022,13 +1015,13 @@ int ucsi_init(struct ucsi *ucsi)
+ /* Enable basic notifications */
+ ucsi->ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
+ command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy;
+- ret = ucsi_run_command(ucsi, command, NULL, 0);
++ ret = ucsi_send_command(ucsi, command, NULL, 0);
+ if (ret < 0)
+ goto err_reset;
+
+ /* Get PPM capabilities */
+ command = UCSI_GET_CAPABILITY;
+- ret = ucsi_run_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap));
++ ret = ucsi_send_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap));
+ if (ret < 0)
+ goto err_reset;
+
+@@ -1045,8 +1038,6 @@ int ucsi_init(struct ucsi *ucsi)
+ goto err_reset;
+ }
+
+- mutex_unlock(&ucsi->ppm_lock);
+-
+ /* Register all connectors */
+ for (i = 0; i < ucsi->cap.num_connectors; i++) {
+ ret = ucsi_register_port(ucsi, i);
+@@ -1072,12 +1063,9 @@ err_unregister:
+ con->port = NULL;
+ }
+
+- mutex_lock(&ucsi->ppm_lock);
+ err_reset:
+ ucsi_reset_ppm(ucsi);
+ err:
+- mutex_unlock(&ucsi->ppm_lock);
+-
+ return ret;
+ }
+ EXPORT_SYMBOL_GPL(ucsi_init);
--- /dev/null
+From 9a469bc9f32dd33c7aac5744669d21a023a719cd Mon Sep 17 00:00:00 2001
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+Date: Tue, 18 Aug 2020 19:27:47 -0700
+Subject: usb: uas: Add quirk for PNY Pro Elite
+
+From: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
+
+commit 9a469bc9f32dd33c7aac5744669d21a023a719cd upstream.
+
+PNY Pro Elite USB 3.1 Gen 2 device (SSD) doesn't respond to ATA_12
+pass-through command (i.e. it just hangs). If it doesn't support this
+command, it should respond properly to the host. Let's just add a quirk
+to be able to move forward with other operations.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
+Link: https://lore.kernel.org/r/2b0585228b003eedcc82db84697b31477df152e0.1597803605.git.thinhn@synopsys.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/storage/unusual_uas.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/usb/storage/unusual_uas.h
++++ b/drivers/usb/storage/unusual_uas.h
+@@ -80,6 +80,13 @@ UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x99
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BROKEN_FUA),
+
++/* Reported-by: Thinh Nguyen <thinhn@synopsys.com> */
++UNUSUAL_DEV(0x154b, 0xf00d, 0x0000, 0x9999,
++ "PNY",
++ "Pro Elite SSD",
++ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
++ US_FL_NO_ATA_1X),
++
+ /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
+ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
+ "VIA",
--- /dev/null
+From f176ede3a3bde5b398a6777a7f9ff091baa2d3ff Mon Sep 17 00:00:00 2001
+From: Alan Stern <stern@rowland.harvard.edu>
+Date: Mon, 10 Aug 2020 14:29:54 -0400
+Subject: USB: yurex: Fix bad gfp argument
+
+From: Alan Stern <stern@rowland.harvard.edu>
+
+commit f176ede3a3bde5b398a6777a7f9ff091baa2d3ff upstream.
+
+The syzbot fuzzer identified a bug in the yurex driver: It passes
+GFP_KERNEL as a memory-allocation flag to usb_submit_urb() at a time
+when its state is TASK_INTERRUPTIBLE, not TASK_RUNNING:
+
+do not call blocking ops when !TASK_RUNNING; state=1 set at [<00000000370c7c68>] prepare_to_wait+0xb1/0x2a0 kernel/sched/wait.c:247
+WARNING: CPU: 1 PID: 340 at kernel/sched/core.c:7253 __might_sleep+0x135/0x190
+kernel/sched/core.c:7253
+Kernel panic - not syncing: panic_on_warn set ...
+CPU: 1 PID: 340 Comm: syz-executor677 Not tainted 5.8.0-syzkaller #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google
+01/01/2011
+Call Trace:
+ __dump_stack lib/dump_stack.c:77 [inline]
+ dump_stack+0xf6/0x16e lib/dump_stack.c:118
+ panic+0x2aa/0x6e1 kernel/panic.c:231
+ __warn.cold+0x20/0x50 kernel/panic.c:600
+ report_bug+0x1bd/0x210 lib/bug.c:198
+ handle_bug+0x41/0x80 arch/x86/kernel/traps.c:234
+ exc_invalid_op+0x14/0x40 arch/x86/kernel/traps.c:254
+ asm_exc_invalid_op+0x12/0x20 arch/x86/include/asm/idtentry.h:536
+RIP: 0010:__might_sleep+0x135/0x190 kernel/sched/core.c:7253
+Code: 65 48 8b 1c 25 40 ef 01 00 48 8d 7b 10 48 89 fe 48 c1 ee 03 80 3c 06 00 75
+2b 48 8b 73 10 48 c7 c7 e0 9e 06 86 e8 ed 12 f6 ff <0f> 0b e9 46 ff ff ff e8 1f
+b2 4b 00 e9 29 ff ff ff e8 15 b2 4b 00
+RSP: 0018:ffff8881cdb77a28 EFLAGS: 00010282
+RAX: 0000000000000000 RBX: ffff8881c6458000 RCX: 0000000000000000
+RDX: ffff8881c6458000 RSI: ffffffff8129ec93 RDI: ffffed1039b6ef37
+RBP: ffffffff86fdade2 R08: 0000000000000001 R09: ffff8881db32f54f
+R10: 0000000000000000 R11: 0000000030343354 R12: 00000000000001f2
+R13: 0000000000000000 R14: 0000000000000068 R15: ffffffff83c1b1aa
+ slab_pre_alloc_hook.constprop.0+0xea/0x200 mm/slab.h:498
+ slab_alloc_node mm/slub.c:2816 [inline]
+ slab_alloc mm/slub.c:2900 [inline]
+ kmem_cache_alloc_trace+0x46/0x220 mm/slub.c:2917
+ kmalloc include/linux/slab.h:554 [inline]
+ dummy_urb_enqueue+0x7a/0x880 drivers/usb/gadget/udc/dummy_hcd.c:1251
+ usb_hcd_submit_urb+0x2b2/0x22d0 drivers/usb/core/hcd.c:1547
+ usb_submit_urb+0xb4e/0x13e0 drivers/usb/core/urb.c:570
+ yurex_write+0x3ea/0x820 drivers/usb/misc/yurex.c:495
+
+This patch changes the call to use GFP_ATOMIC instead of GFP_KERNEL.
+
+Reported-and-tested-by: syzbot+c2c3302f9c601a4b1be2@syzkaller.appspotmail.com
+Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
+CC: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20200810182954.GB307778@rowland.harvard.edu
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/misc/yurex.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/misc/yurex.c
++++ b/drivers/usb/misc/yurex.c
+@@ -492,7 +492,7 @@ static ssize_t yurex_write(struct file *
+ prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE);
+ dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__,
+ dev->cntl_buffer[0]);
+- retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL);
++ retval = usb_submit_urb(dev->cntl_urb, GFP_ATOMIC);
+ if (retval >= 0)
+ timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
+ finish_wait(&dev->waitq, &wait);