Commit 6f0306d1 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-5.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Let's try this again...  Here are some USB fixes for 5.9-rc3.

  This differs from the previous pull request for this release in that
  the usb gadget patch now does not break some systems, and actually
  does what it was intended to do. Many thanks to Marek Szyprowski for
  quickly noticing and testing the patch from Andy Shevchenko to resolve
  this issue.

  Additionally, some more new USB quirks have been added to get some new
  devices to work properly based on user reports.

  Other than that, the patches are all here, and they contain:

   - usb gadget driver fixes

   - xhci driver fixes

   - typec fixes

   - new quirks and ids

   - fixes for USB patches that went into 5.9-rc1.

  All of these have been tested in linux-next with no reported issues"

* tag 'usb-5.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (33 commits)
  usb: storage: Add unusual_uas entry for Sony PSZ drives
  USB: Ignore UAS for JMicron JMS567 ATA/ATAPI Bridge
  usb: host: ohci-exynos: Fix error handling in exynos_ohci_probe()
  USB: gadget: u_f: Unbreak offset calculation in VLAs
  USB: quirks: Ignore duplicate endpoint on Sound Devices MixPre-D
  usb: typec: tcpm: Fix Fix source hard reset response for TDA 2.3.1.1 and TDA 2.3.1.2 failures
  USB: PHY: JZ4770: Fix static checker warning.
  USB: gadget: f_ncm: add bounds checks to ncm_unwrap_ntb()
  USB: gadget: u_f: add overflow checks to VLA macros
  xhci: Always restore EP_SOFT_CLEAR_TOGGLE even if ep reset failed
  xhci: Do warm-reset when both CAS and XDEV_RESUME are set
  usb: host: xhci: fix ep context print mismatch in debugfs
  usb: uas: Add quirk for PNY Pro Elite
  tools: usb: move to tools buildsystem
  USB: Fix device driver race
  USB: Also match device drivers using the ->match vfunc
  usb: host: xhci-tegra: fix tegra_xusb_get_phy()
  usb: host: xhci-tegra: otg usb2/usb3 port init
  usb: hcd: Fix use after free in usb_hcd_pci_remove()
  usb: typec: ucsi: Hold con->lock for the entire duration of ucsi_register_port()
  ...
parents 42df60fc 20934c0d
...@@ -378,21 +378,19 @@ static void acm_ctrl_irq(struct urb *urb) ...@@ -378,21 +378,19 @@ static void acm_ctrl_irq(struct urb *urb)
if (current_size < expected_size) { if (current_size < expected_size) {
/* notification is transmitted fragmented, reassemble */ /* notification is transmitted fragmented, reassemble */
if (acm->nb_size < expected_size) { if (acm->nb_size < expected_size) {
if (acm->nb_size) { u8 *new_buffer;
kfree(acm->notification_buffer);
acm->nb_size = 0;
}
alloc_size = roundup_pow_of_two(expected_size); alloc_size = roundup_pow_of_two(expected_size);
/* /* Final freeing is done on disconnect. */
* kmalloc ensures a valid notification_buffer after a new_buffer = krealloc(acm->notification_buffer,
* use of kfree in case the previous allocation was too alloc_size, GFP_ATOMIC);
* small. Final freeing is done on disconnect. if (!new_buffer) {
*/ acm->nb_index = 0;
acm->notification_buffer =
kmalloc(alloc_size, GFP_ATOMIC);
if (!acm->notification_buffer)
goto exit; goto exit;
}
acm->notification_buffer = new_buffer;
acm->nb_size = alloc_size; acm->nb_size = alloc_size;
dr = (struct usb_cdc_notification *)acm->notification_buffer;
} }
copy_size = min(current_size, copy_size = min(current_size,
......
...@@ -905,6 +905,35 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) ...@@ -905,6 +905,35 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0; 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 * usb_register_device_driver - register a USB device (not interface) driver
* @new_udriver: USB operations for the device driver * @new_udriver: USB operations for the device driver
...@@ -934,13 +963,20 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver, ...@@ -934,13 +963,20 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,
retval = driver_register(&new_udriver->drvwrap.driver); retval = driver_register(&new_udriver->drvwrap.driver);
if (!retval) if (!retval) {
pr_info("%s: registered new device driver %s\n", pr_info("%s: registered new device driver %s\n",
usbcore_name, new_udriver->name); 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 " printk(KERN_ERR "%s: error %d registering device "
" driver %s\n", " driver %s\n",
usbcore_name, retval, new_udriver->name); usbcore_name, retval, new_udriver->name);
}
return retval; return retval;
} }
......
...@@ -205,8 +205,9 @@ static int __check_usb_generic(struct device_driver *drv, void *data) ...@@ -205,8 +205,9 @@ static int __check_usb_generic(struct device_driver *drv, void *data)
udrv = to_usb_device_driver(drv); udrv = to_usb_device_driver(drv);
if (udrv == &usb_generic_driver) if (udrv == &usb_generic_driver)
return 0; return 0;
if (usb_device_match_id(udev, udrv->id_table) != NULL)
return 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) static bool usb_generic_driver_match(struct usb_device *udev)
......
...@@ -315,11 +315,14 @@ EXPORT_SYMBOL_GPL(usb_hcd_pci_probe); ...@@ -315,11 +315,14 @@ EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
void usb_hcd_pci_remove(struct pci_dev *dev) void usb_hcd_pci_remove(struct pci_dev *dev)
{ {
struct usb_hcd *hcd; struct usb_hcd *hcd;
int hcd_driver_flags;
hcd = pci_get_drvdata(dev); hcd = pci_get_drvdata(dev);
if (!hcd) if (!hcd)
return; return;
hcd_driver_flags = hcd->driver->flags;
if (pci_dev_run_wake(dev)) if (pci_dev_run_wake(dev))
pm_runtime_get_noresume(&dev->dev); pm_runtime_get_noresume(&dev->dev);
...@@ -347,7 +350,7 @@ void usb_hcd_pci_remove(struct pci_dev *dev) ...@@ -347,7 +350,7 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
up_read(&companions_rwsem); up_read(&companions_rwsem);
} }
usb_put_hcd(hcd); usb_put_hcd(hcd);
if ((hcd->driver->flags & HCD_MASK) < HCD_USB3) if ((hcd_driver_flags & HCD_MASK) < HCD_USB3)
pci_free_irq_vectors(dev); pci_free_irq_vectors(dev);
pci_disable_device(dev); pci_disable_device(dev);
} }
......
...@@ -370,6 +370,10 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -370,6 +370,10 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0926, 0x0202), .driver_info = { USB_DEVICE(0x0926, 0x0202), .driver_info =
USB_QUIRK_ENDPOINT_IGNORE }, USB_QUIRK_ENDPOINT_IGNORE },
/* Sound Devices MixPre-D */
{ USB_DEVICE(0x0926, 0x0208), .driver_info =
USB_QUIRK_ENDPOINT_IGNORE },
/* Keytouch QWERTY Panel keyboard */ /* Keytouch QWERTY Panel keyboard */
{ USB_DEVICE(0x0926, 0x3333), .driver_info = { USB_DEVICE(0x0926, 0x3333), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS }, USB_QUIRK_CONFIG_INTF_STRINGS },
...@@ -465,6 +469,8 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -465,6 +469,8 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM }, { USB_DEVICE(0x2386, 0x3119), .driver_info = USB_QUIRK_NO_LPM },
{ USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
/* DJI CineSSD */ /* DJI CineSSD */
{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
...@@ -509,6 +515,7 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = { ...@@ -509,6 +515,7 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = {
*/ */
static const struct usb_device_id usb_endpoint_ignore[] = { static const struct usb_device_id usb_endpoint_ignore[] = {
{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 }, { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 },
{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0208, 1), .driver_info = 0x85 },
{ } { }
}; };
......
...@@ -1054,27 +1054,25 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, ...@@ -1054,27 +1054,25 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
* dwc3_prepare_one_trb - setup one TRB from one request * dwc3_prepare_one_trb - setup one TRB from one request
* @dep: endpoint for which this request is prepared * @dep: endpoint for which this request is prepared
* @req: dwc3_request pointer * @req: dwc3_request pointer
* @trb_length: buffer size of the TRB
* @chain: should this TRB be chained to the next? * @chain: should this TRB be chained to the next?
* @node: only for isochronous endpoints. First TRB needs different type. * @node: only for isochronous endpoints. First TRB needs different type.
*/ */
static void dwc3_prepare_one_trb(struct dwc3_ep *dep, 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; struct dwc3_trb *trb;
unsigned int length;
dma_addr_t dma; dma_addr_t dma;
unsigned stream_id = req->request.stream_id; unsigned stream_id = req->request.stream_id;
unsigned short_not_ok = req->request.short_not_ok; unsigned short_not_ok = req->request.short_not_ok;
unsigned no_interrupt = req->request.no_interrupt; unsigned no_interrupt = req->request.no_interrupt;
unsigned is_last = req->request.is_last; unsigned is_last = req->request.is_last;
if (req->request.num_sgs > 0) { if (req->request.num_sgs > 0)
length = sg_dma_len(req->start_sg);
dma = sg_dma_address(req->start_sg); dma = sg_dma_address(req->start_sg);
} else { else
length = req->request.length;
dma = req->request.dma; dma = req->request.dma;
}
trb = &dep->trb_pool[dep->trb_enqueue]; trb = &dep->trb_pool[dep->trb_enqueue];
...@@ -1086,7 +1084,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, ...@@ -1086,7 +1084,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
req->num_trbs++; 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); stream_id, short_not_ok, no_interrupt, is_last);
} }
...@@ -1096,16 +1094,27 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, ...@@ -1096,16 +1094,27 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
struct scatterlist *sg = req->start_sg; struct scatterlist *sg = req->start_sg;
struct scatterlist *s; struct scatterlist *s;
int i; int i;
unsigned int length = req->request.length;
unsigned int remaining = req->request.num_mapped_sgs unsigned int remaining = req->request.num_mapped_sgs
- req->num_queued_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) { for_each_sg(sg, s, remaining, i) {
unsigned int length = req->request.length;
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
unsigned int rem = length % maxp; unsigned int rem = length % maxp;
unsigned int trb_length;
unsigned chain = true; 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 * IOMMU driver is coalescing the list of sgs which shares a
* page boundary into one and giving it to USB driver. With * page boundary into one and giving it to USB driver. With
...@@ -1113,7 +1122,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, ...@@ -1113,7 +1122,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
* sgs passed. So mark the chain bit to false if it isthe last * sgs passed. So mark the chain bit to false if it isthe last
* mapped sg. * mapped sg.
*/ */
if (i == remaining - 1) if ((i == remaining - 1) || !length)
chain = false; chain = false;
if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) { if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) {
...@@ -1123,7 +1132,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, ...@@ -1123,7 +1132,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
req->needs_extra_trb = true; req->needs_extra_trb = true;
/* prepare normal TRB */ /* 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 */ /* Now prepare one extra TRB to align transfer size */
trb = &dep->trb_pool[dep->trb_enqueue]; trb = &dep->trb_pool[dep->trb_enqueue];
...@@ -1134,8 +1143,39 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, ...@@ -1134,8 +1143,39 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
req->request.short_not_ok, req->request.short_not_ok,
req->request.no_interrupt, req->request.no_interrupt,
req->request.is_last); 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 { } else {
dwc3_prepare_one_trb(dep, req, chain, i); dwc3_prepare_one_trb(dep, req, trb_length, chain, i);
} }
/* /*
...@@ -1150,6 +1190,16 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, ...@@ -1150,6 +1190,16 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
req->num_queued_sgs++; 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)) if (!dwc3_calc_trbs_left(dep))
break; break;
} }
...@@ -1169,7 +1219,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, ...@@ -1169,7 +1219,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
req->needs_extra_trb = true; req->needs_extra_trb = true;
/* prepare normal TRB */ /* 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 */ /* Now prepare one extra TRB to align transfer size */
trb = &dep->trb_pool[dep->trb_enqueue]; trb = &dep->trb_pool[dep->trb_enqueue];
...@@ -1180,6 +1230,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, ...@@ -1180,6 +1230,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
req->request.no_interrupt, req->request.no_interrupt,
req->request.is_last); req->request.is_last);
} else if (req->request.zero && req->request.length && } else if (req->request.zero && req->request.length &&
!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
(IS_ALIGNED(req->request.length, maxp))) { (IS_ALIGNED(req->request.length, maxp))) {
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb; struct dwc3_trb *trb;
...@@ -1187,18 +1238,29 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, ...@@ -1187,18 +1238,29 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
req->needs_extra_trb = true; req->needs_extra_trb = true;
/* prepare normal TRB */ /* 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 */ /* Prepare one extra TRB to handle ZLP */
trb = &dep->trb_pool[dep->trb_enqueue]; trb = &dep->trb_pool[dep->trb_enqueue];
req->num_trbs++; req->num_trbs++;
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0, __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.short_not_ok,
req->request.no_interrupt, req->request.no_interrupt,
req->request.is_last); 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 { } else {
dwc3_prepare_one_trb(dep, req, false, 0); dwc3_prepare_one_trb(dep, req, length, false, 0);
} }
} }
...@@ -2671,8 +2733,17 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, ...@@ -2671,8 +2733,17 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
status); status);
if (req->needs_extra_trb) { if (req->needs_extra_trb) {
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event, ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
status); 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; req->needs_extra_trb = false;
} }
......
...@@ -1181,12 +1181,15 @@ static int ncm_unwrap_ntb(struct gether *port, ...@@ -1181,12 +1181,15 @@ static int ncm_unwrap_ntb(struct gether *port,
int ndp_index; int ndp_index;
unsigned dg_len, dg_len2; unsigned dg_len, dg_len2;
unsigned ndp_len; unsigned ndp_len;
unsigned block_len;
struct sk_buff *skb2; struct sk_buff *skb2;
int ret = -EINVAL; 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; const struct ndp_parser_opts *opts = ncm->parser_opts;
unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
int dgram_counter; int dgram_counter;
bool ndp_after_header;
/* dwSignature */ /* dwSignature */
if (get_unaligned_le32(tmp) != opts->nth_sign) { if (get_unaligned_le32(tmp) != opts->nth_sign) {
...@@ -1205,25 +1208,37 @@ static int ncm_unwrap_ntb(struct gether *port, ...@@ -1205,25 +1208,37 @@ static int ncm_unwrap_ntb(struct gether *port,
} }
tmp++; /* skip wSequence */ tmp++; /* skip wSequence */
block_len = get_ncm(&tmp, opts->block_length);
/* (d)wBlockLength */ /* (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"); INFO(port->func.config->cdev, "OUT size exceeded\n");
goto err; goto err;
} }
ndp_index = get_ncm(&tmp, opts->ndp_index); ndp_index = get_ncm(&tmp, opts->ndp_index);
ndp_after_header = false;
/* Run through all the NDP's in the NTB */ /* Run through all the NDP's in the NTB */
do { do {
/* NCM 3.2 */ /*
if (((ndp_index % 4) != 0) && * NCM 3.2
(ndp_index < opts->nth_size)) { * 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", INFO(port->func.config->cdev, "Bad index: %#X\n",
ndp_index); ndp_index);
goto err; 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); tmp = (void *)(skb->data + ndp_index);
if (get_unaligned_le32(tmp) != ncm->ndp_sign) { if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
INFO(port->func.config->cdev, "Wrong NDP SIGN\n"); INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
...@@ -1234,14 +1249,15 @@ static int ncm_unwrap_ntb(struct gether *port, ...@@ -1234,14 +1249,15 @@ static int ncm_unwrap_ntb(struct gether *port,
ndp_len = get_unaligned_le16(tmp++); ndp_len = get_unaligned_le16(tmp++);
/* /*
* NCM 3.3.1 * NCM 3.3.1
* wLength
* entry is 2 items * entry is 2 items
* item size is 16/32 bits, opts->dgram_item_len * 2 bytes * item size is 16/32 bits, opts->dgram_item_len * 2 bytes
* minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry
* Each entry is a dgram index and a dgram length. * Each entry is a dgram index and a dgram length.
*/ */
if ((ndp_len < opts->ndp_size if ((ndp_len < opts->ndp_size
+ 2 * 2 * (opts->dgram_item_len * 2)) + 2 * 2 * (opts->dgram_item_len * 2)) ||
|| (ndp_len % opts->ndplen_align != 0)) { (ndp_len % opts->ndplen_align != 0)) {
INFO(port->func.config->cdev, "Bad NDP length: %#X\n", INFO(port->func.config->cdev, "Bad NDP length: %#X\n",
ndp_len); ndp_len);
goto err; goto err;
...@@ -1258,8 +1274,21 @@ static int ncm_unwrap_ntb(struct gether *port, ...@@ -1258,8 +1274,21 @@ static int ncm_unwrap_ntb(struct gether *port,
do { do {
index = index2; 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; 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, INFO(port->func.config->cdev,
"Bad dgram length: %#X\n", dg_len); "Bad dgram length: %#X\n", dg_len);
goto err; goto err;
...@@ -1283,6 +1312,37 @@ static int ncm_unwrap_ntb(struct gether *port, ...@@ -1283,6 +1312,37 @@ static int ncm_unwrap_ntb(struct gether *port,
index2 = get_ncm(&tmp, opts->dgram_item_len); index2 = get_ncm(&tmp, opts->dgram_item_len);
dg_len2 = 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. * Copy the data into a new skb.
* This ensures the truesize is correct * This ensures the truesize is correct
...@@ -1299,9 +1359,6 @@ static int ncm_unwrap_ntb(struct gether *port, ...@@ -1299,9 +1359,6 @@ static int ncm_unwrap_ntb(struct gether *port,
ndp_len -= 2 * (opts->dgram_item_len * 2); ndp_len -= 2 * (opts->dgram_item_len * 2);
dgram_counter++; dgram_counter++;
if (index2 == 0 || dg_len2 == 0)
break;
} while (ndp_len > 2 * (opts->dgram_item_len * 2)); } while (ndp_len > 2 * (opts->dgram_item_len * 2));
} while (ndp_index); } while (ndp_index);
......
...@@ -753,12 +753,13 @@ static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream) ...@@ -753,12 +753,13 @@ static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
goto err_sts; goto err_sts;
return 0; return 0;
err_sts: err_sts:
usb_ep_free_request(fu->ep_status, stream->req_status);
stream->req_status = NULL;
err_out:
usb_ep_free_request(fu->ep_out, stream->req_out); usb_ep_free_request(fu->ep_out, stream->req_out);
stream->req_out = NULL; stream->req_out = NULL;
err_out:
usb_ep_free_request(fu->ep_in, stream->req_in);
stream->req_in = NULL;
out: out:
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define __U_F_H__ #define __U_F_H__
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/overflow.h>
/* Variable Length Array Macros **********************************************/ /* Variable Length Array Macros **********************************************/
#define vla_group(groupname) size_t groupname##__next = 0 #define vla_group(groupname) size_t groupname##__next = 0
...@@ -21,21 +22,36 @@ ...@@ -21,21 +22,36 @@
#define vla_item(groupname, type, name, n) \ #define vla_item(groupname, type, name, n) \
size_t groupname##_##name##__offset = ({ \ size_t groupname##_##name##__offset = ({ \
size_t align_mask = __alignof__(type) - 1; \ size_t offset = 0; \
size_t offset = (groupname##__next + align_mask) & ~align_mask;\ if (groupname##__next != SIZE_MAX) { \
size_t size = (n) * sizeof(type); \ size_t align_mask = __alignof__(type) - 1; \
groupname##__next = offset + size; \ 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; \
offset = 0; \
} \
} \
offset; \ offset; \
}) })
#define vla_item_with_sz(groupname, type, name, n) \ #define vla_item_with_sz(groupname, type, name, n) \
size_t groupname##_##name##__sz = (n) * sizeof(type); \ size_t groupname##_##name##__sz = array_size(n, sizeof(type)); \
size_t groupname##_##name##__offset = ({ \ size_t groupname##_##name##__offset = ({ \
size_t align_mask = __alignof__(type) - 1; \ size_t offset = 0; \
size_t offset = (groupname##__next + align_mask) & ~align_mask;\ if (groupname##__next != SIZE_MAX) { \
size_t size = groupname##_##name##__sz; \ size_t align_mask = __alignof__(type) - 1; \
groupname##__next = offset + size; \ offset = (groupname##__next + align_mask) & \
offset; \ ~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) \ #define vla_ptr(ptr, groupname, name) \
......
...@@ -171,9 +171,8 @@ static int exynos_ohci_probe(struct platform_device *pdev) ...@@ -171,9 +171,8 @@ static int exynos_ohci_probe(struct platform_device *pdev)
hcd->rsrc_len = resource_size(res); hcd->rsrc_len = resource_size(res);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (!irq) { if (irq < 0) {
dev_err(&pdev->dev, "Failed to get IRQ\n"); err = irq;
err = -ENODEV;
goto fail_io; goto fail_io;
} }
......
...@@ -274,7 +274,7 @@ static int xhci_slot_context_show(struct seq_file *s, void *unused) ...@@ -274,7 +274,7 @@ static int xhci_slot_context_show(struct seq_file *s, void *unused)
static int xhci_endpoint_context_show(struct seq_file *s, void *unused) static int xhci_endpoint_context_show(struct seq_file *s, void *unused)
{ {
int dci; int ep_index;
dma_addr_t dma; dma_addr_t dma;
struct xhci_hcd *xhci; struct xhci_hcd *xhci;
struct xhci_ep_ctx *ep_ctx; struct xhci_ep_ctx *ep_ctx;
...@@ -283,9 +283,9 @@ static int xhci_endpoint_context_show(struct seq_file *s, void *unused) ...@@ -283,9 +283,9 @@ static int xhci_endpoint_context_show(struct seq_file *s, void *unused)
xhci = hcd_to_xhci(bus_to_hcd(dev->udev->bus)); xhci = hcd_to_xhci(bus_to_hcd(dev->udev->bus));
for (dci = 1; dci < 32; dci++) { for (ep_index = 0; ep_index < 31; ep_index++) {
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, dci); ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
dma = dev->out_ctx->dma + dci * CTX_SIZE(xhci->hcc_params); dma = dev->out_ctx->dma + (ep_index + 1) * CTX_SIZE(xhci->hcc_params);
seq_printf(s, "%pad: %s\n", &dma, seq_printf(s, "%pad: %s\n", &dma,
xhci_decode_ep_context(le32_to_cpu(ep_ctx->ep_info), xhci_decode_ep_context(le32_to_cpu(ep_ctx->ep_info),
le32_to_cpu(ep_ctx->ep_info2), le32_to_cpu(ep_ctx->ep_info2),
......
...@@ -740,15 +740,6 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci, ...@@ -740,15 +740,6 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
{ {
u32 pls = status_reg & PORT_PLS_MASK; u32 pls = status_reg & PORT_PLS_MASK;
/* resume state is a xHCI internal state.
* Do not report it to usb core, instead, pretend to be U3,
* thus usb core knows it's not ready for transfer
*/
if (pls == XDEV_RESUME) {
*status |= USB_SS_PORT_LS_U3;
return;
}
/* When the CAS bit is set then warm reset /* When the CAS bit is set then warm reset
* should be performed on port * should be performed on port
*/ */
...@@ -770,6 +761,16 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci, ...@@ -770,6 +761,16 @@ static void xhci_hub_report_usb3_link_state(struct xhci_hcd *xhci,
*/ */
pls |= USB_PORT_STAT_CONNECTION; pls |= USB_PORT_STAT_CONNECTION;
} else { } else {
/*
* Resume state is an xHCI internal state. Do not report it to
* usb core, instead, pretend to be U3, thus usb core knows
* it's not ready for transfer.
*/
if (pls == XDEV_RESUME) {
*status |= USB_SS_PORT_LS_U3;
return;
}
/* /*
* If CAS bit isn't set but the Port is already at * If CAS bit isn't set but the Port is already at
* Compliance Mode, fake a connection so the USB core * Compliance Mode, fake a connection so the USB core
......
...@@ -50,20 +50,6 @@ ...@@ -50,20 +50,6 @@
#define RENESAS_RETRY 10000 #define RENESAS_RETRY 10000
#define RENESAS_DELAY 10 #define RENESAS_DELAY 10
#define ROM_VALID_01 0x2013
#define ROM_VALID_02 0x2026
static int renesas_verify_fw_version(struct pci_dev *pdev, u32 version)
{
switch (version) {
case ROM_VALID_01:
case ROM_VALID_02:
return 0;
}
dev_err(&pdev->dev, "FW has invalid version :%d\n", version);
return -EINVAL;
}
static int renesas_fw_download_image(struct pci_dev *dev, static int renesas_fw_download_image(struct pci_dev *dev,
const u32 *fw, size_t step, bool rom) const u32 *fw, size_t step, bool rom)
{ {
...@@ -202,10 +188,7 @@ static int renesas_check_rom_state(struct pci_dev *pdev) ...@@ -202,10 +188,7 @@ static int renesas_check_rom_state(struct pci_dev *pdev)
version &= RENESAS_FW_VERSION_FIELD; version &= RENESAS_FW_VERSION_FIELD;
version = version >> RENESAS_FW_VERSION_OFFSET; version = version >> RENESAS_FW_VERSION_OFFSET;
dev_dbg(&pdev->dev, "Found ROM version: %x\n", version);
err = renesas_verify_fw_version(pdev, version);
if (err)
return err;
/* /*
* Test if ROM is present and loaded, if so we can skip everything * Test if ROM is present and loaded, if so we can skip everything
......
...@@ -1136,7 +1136,7 @@ static struct phy *tegra_xusb_get_phy(struct tegra_xusb *tegra, char *name, ...@@ -1136,7 +1136,7 @@ static struct phy *tegra_xusb_get_phy(struct tegra_xusb *tegra, char *name,
unsigned int i, phy_count = 0; unsigned int i, phy_count = 0;
for (i = 0; i < tegra->soc->num_types; i++) { for (i = 0; i < tegra->soc->num_types; i++) {
if (!strncmp(tegra->soc->phy_types[i].name, "usb2", if (!strncmp(tegra->soc->phy_types[i].name, name,
strlen(name))) strlen(name)))
return tegra->phys[phy_count+port]; return tegra->phys[phy_count+port];
...@@ -1258,6 +1258,8 @@ static int tegra_xusb_init_usb_phy(struct tegra_xusb *tegra) ...@@ -1258,6 +1258,8 @@ static int tegra_xusb_init_usb_phy(struct tegra_xusb *tegra)
INIT_WORK(&tegra->id_work, tegra_xhci_id_work); INIT_WORK(&tegra->id_work, tegra_xhci_id_work);
tegra->id_nb.notifier_call = tegra_xhci_id_notify; tegra->id_nb.notifier_call = tegra_xhci_id_notify;
tegra->otg_usb2_port = -EINVAL;
tegra->otg_usb3_port = -EINVAL;
for (i = 0; i < tegra->num_usb_phys; i++) { for (i = 0; i < tegra->num_usb_phys; i++) {
struct phy *phy = tegra_xusb_get_phy(tegra, "usb2", i); struct phy *phy = tegra_xusb_get_phy(tegra, "usb2", i);
......
...@@ -3236,10 +3236,11 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, ...@@ -3236,10 +3236,11 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
wait_for_completion(cfg_cmd->completion); wait_for_completion(cfg_cmd->completion);
ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE;
xhci_free_command(xhci, cfg_cmd); xhci_free_command(xhci, cfg_cmd);
cleanup: cleanup:
xhci_free_command(xhci, stop_cmd); xhci_free_command(xhci, stop_cmd);
if (ep->ep_state & EP_SOFT_CLEAR_TOGGLE)
ep->ep_state &= ~EP_SOFT_CLEAR_TOGGLE;
} }
static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
......
...@@ -426,7 +426,7 @@ static int lvs_rh_probe(struct usb_interface *intf, ...@@ -426,7 +426,7 @@ static int lvs_rh_probe(struct usb_interface *intf,
USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT); USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT);
if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) { if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) {
dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret); dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret);
return ret; return ret < 0 ? ret : -EINVAL;
} }
/* submit urb to poll interrupt endpoint */ /* submit urb to poll interrupt endpoint */
......
...@@ -492,7 +492,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, ...@@ -492,7 +492,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE);
dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__, dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__,
dev->cntl_buffer[0]); 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) if (retval >= 0)
timeout = schedule_timeout(YUREX_WRITE_TIMEOUT); timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
finish_wait(&dev->waitq, &wait); finish_wait(&dev->waitq, &wait);
......
...@@ -176,6 +176,7 @@ static int ingenic_usb_phy_init(struct usb_phy *phy) ...@@ -176,6 +176,7 @@ static int ingenic_usb_phy_init(struct usb_phy *phy)
/* Wait for PHY to reset */ /* Wait for PHY to reset */
usleep_range(30, 300); usleep_range(30, 300);
reg = readl(priv->base + REG_USBPCR_OFFSET);
writel(reg & ~USBPCR_POR, priv->base + REG_USBPCR_OFFSET); writel(reg & ~USBPCR_POR, priv->base + REG_USBPCR_OFFSET);
usleep_range(300, 1000); usleep_range(300, 1000);
......
...@@ -2328,7 +2328,7 @@ UNUSUAL_DEV( 0x357d, 0x7788, 0x0114, 0x0114, ...@@ -2328,7 +2328,7 @@ UNUSUAL_DEV( 0x357d, 0x7788, 0x0114, 0x0114,
"JMicron", "JMicron",
"USB to ATA/ATAPI Bridge", "USB to ATA/ATAPI Bridge",
USB_SC_DEVICE, USB_PR_DEVICE, NULL, 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> */ /* Reported by Andrey Rahmatullin <wrar@altlinux.org> */
UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100, UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100,
......
...@@ -28,6 +28,13 @@ ...@@ -28,6 +28,13 @@
* and don't forget to CC: the USB development list <linux-usb@vger.kernel.org> * 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> */ /* Reported-by: Julian Groß <julian.g@posteo.de> */
UNUSUAL_DEV(0x059f, 0x105f, 0x0000, 0x9999, UNUSUAL_DEV(0x059f, 0x105f, 0x0000, 0x9999,
"LaCie", "LaCie",
...@@ -80,6 +87,13 @@ UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999, ...@@ -80,6 +87,13 @@ UNUSUAL_DEV(0x152d, 0x0578, 0x0000, 0x9999,
USB_SC_DEVICE, USB_PR_DEVICE, NULL, USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_BROKEN_FUA), 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> */ /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999, UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
"VIA", "VIA",
......
...@@ -3372,13 +3372,31 @@ static void run_state_machine(struct tcpm_port *port) ...@@ -3372,13 +3372,31 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_state(port, SNK_HARD_RESET_SINK_OFF, 0); tcpm_set_state(port, SNK_HARD_RESET_SINK_OFF, 0);
break; break;
case SRC_HARD_RESET_VBUS_OFF: 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_vbus(port, false);
tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE, tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE,
tcpm_data_role_for_source(port)); 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; break;
case SRC_HARD_RESET_VBUS_ON: case SRC_HARD_RESET_VBUS_ON:
tcpm_set_vconn(port, true);
tcpm_set_vbus(port, true); tcpm_set_vbus(port, true);
port->tcpc->set_pd_rx(port->tcpc, true); port->tcpc->set_pd_rx(port->tcpc, true);
tcpm_set_attached_state(port, true); tcpm_set_attached_state(port, true);
...@@ -3944,7 +3962,11 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port) ...@@ -3944,7 +3962,11 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0); tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0);
break; break;
case SRC_HARD_RESET_VBUS_OFF: 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; break;
case HARD_RESET_SEND: case HARD_RESET_SEND:
break; break;
......
...@@ -288,8 +288,6 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con, ...@@ -288,8 +288,6 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
struct typec_altmode *alt; struct typec_altmode *alt;
struct ucsi_dp *dp; struct ucsi_dp *dp;
mutex_lock(&con->lock);
/* We can't rely on the firmware with the capabilities. */ /* We can't rely on the firmware with the capabilities. */
desc->vdo |= DP_CAP_DP_SIGNALING | DP_CAP_RECEPTACLE; desc->vdo |= DP_CAP_DP_SIGNALING | DP_CAP_RECEPTACLE;
...@@ -298,15 +296,12 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con, ...@@ -298,15 +296,12 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
desc->vdo |= all_assignments << 16; desc->vdo |= all_assignments << 16;
alt = typec_port_register_altmode(con->port, desc); alt = typec_port_register_altmode(con->port, desc);
if (IS_ERR(alt)) { if (IS_ERR(alt))
mutex_unlock(&con->lock);
return alt; return alt;
}
dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
if (!dp) { if (!dp) {
typec_unregister_altmode(alt); typec_unregister_altmode(alt);
mutex_unlock(&con->lock);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
...@@ -319,7 +314,5 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con, ...@@ -319,7 +314,5 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
alt->ops = &ucsi_displayport_ops; alt->ops = &ucsi_displayport_ops;
typec_altmode_set_drvdata(alt, dp); typec_altmode_set_drvdata(alt, dp);
mutex_unlock(&con->lock);
return alt; return alt;
} }
...@@ -146,40 +146,33 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) ...@@ -146,40 +146,33 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd)
return UCSI_CCI_LENGTH(cci); return UCSI_CCI_LENGTH(cci);
} }
static int ucsi_run_command(struct ucsi *ucsi, u64 command, int ucsi_send_command(struct ucsi *ucsi, u64 command,
void *data, size_t size) void *data, size_t size)
{ {
u8 length; u8 length;
int ret; int ret;
mutex_lock(&ucsi->ppm_lock);
ret = ucsi_exec_command(ucsi, command); ret = ucsi_exec_command(ucsi, command);
if (ret < 0) if (ret < 0)
return ret; goto out;
length = ret; length = ret;
if (data) { if (data) {
ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size); ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size);
if (ret) if (ret)
return ret; goto out;
} }
ret = ucsi_acknowledge_command(ucsi); ret = ucsi_acknowledge_command(ucsi);
if (ret) if (ret)
return ret; goto out;
return length;
}
int ucsi_send_command(struct ucsi *ucsi, u64 command,
void *retval, size_t size)
{
int ret;
mutex_lock(&ucsi->ppm_lock); ret = length;
ret = ucsi_run_command(ucsi, command, retval, size); out:
mutex_unlock(&ucsi->ppm_lock); mutex_unlock(&ucsi->ppm_lock);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(ucsi_send_command); EXPORT_SYMBOL_GPL(ucsi_send_command);
...@@ -205,7 +198,7 @@ void ucsi_altmode_update_active(struct ucsi_connector *con) ...@@ -205,7 +198,7 @@ void ucsi_altmode_update_active(struct ucsi_connector *con)
int i; int i;
command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num); 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 (ret < 0) {
if (con->ucsi->version > 0x0100) { if (con->ucsi->version > 0x0100) {
dev_err(con->ucsi->dev, dev_err(con->ucsi->dev,
...@@ -354,7 +347,7 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient) ...@@ -354,7 +347,7 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient)
command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); command |= UCSI_GET_ALTMODE_RECIPIENT(recipient);
command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num);
command |= UCSI_GET_ALTMODE_OFFSET(i); 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. * We are collecting all altmodes first and then registering.
* Some type-C device will return zero length data beyond last * Some type-C device will return zero length data beyond last
...@@ -431,7 +424,7 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient) ...@@ -431,7 +424,7 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient)
command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); command |= UCSI_GET_ALTMODE_RECIPIENT(recipient);
command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num);
command |= UCSI_GET_ALTMODE_OFFSET(i); 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) if (len <= 0)
return len; return len;
...@@ -502,7 +495,7 @@ static void ucsi_get_pdos(struct ucsi_connector *con, int is_partner) ...@@ -502,7 +495,7 @@ static void ucsi_get_pdos(struct ucsi_connector *con, int is_partner)
command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner); command |= UCSI_GET_PDOS_PARTNER_PDO(is_partner);
command |= UCSI_GET_PDOS_NUM_PDOS(UCSI_MAX_PDOS - 1); command |= UCSI_GET_PDOS_NUM_PDOS(UCSI_MAX_PDOS - 1);
command |= UCSI_GET_PDOS_SRC_PDOS; 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)); sizeof(con->src_pdos));
if (ret < 0) { if (ret < 0) {
dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret); dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret);
...@@ -681,7 +674,7 @@ static void ucsi_handle_connector_change(struct work_struct *work) ...@@ -681,7 +674,7 @@ static void ucsi_handle_connector_change(struct work_struct *work)
*/ */
command = UCSI_GET_CAM_SUPPORTED; command = UCSI_GET_CAM_SUPPORTED;
command |= UCSI_CONNECTOR_NUMBER(con->num); 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) if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE)
...@@ -736,20 +729,24 @@ static int ucsi_reset_ppm(struct ucsi *ucsi) ...@@ -736,20 +729,24 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
u32 cci; u32 cci;
int ret; int ret;
mutex_lock(&ucsi->ppm_lock);
ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command, ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command,
sizeof(command)); sizeof(command));
if (ret < 0) if (ret < 0)
return ret; goto out;
tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS); tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
do { do {
if (time_is_before_jiffies(tmo)) if (time_is_before_jiffies(tmo)) {
return -ETIMEDOUT; ret = -ETIMEDOUT;
goto out;
}
ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci));
if (ret) if (ret)
return ret; goto out;
/* If the PPM is still doing something else, reset it again. */ /* If the PPM is still doing something else, reset it again. */
if (cci & ~UCSI_CCI_RESET_COMPLETE) { if (cci & ~UCSI_CCI_RESET_COMPLETE) {
...@@ -757,13 +754,15 @@ static int ucsi_reset_ppm(struct ucsi *ucsi) ...@@ -757,13 +754,15 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
&command, &command,
sizeof(command)); sizeof(command));
if (ret < 0) if (ret < 0)
return ret; goto out;
} }
msleep(20); msleep(20);
} while (!(cci & UCSI_CCI_RESET_COMPLETE)); } 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) static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
...@@ -775,9 +774,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command) ...@@ -775,9 +774,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command)
u64 c; u64 c;
/* PPM most likely stopped responding. Resetting everything. */ /* PPM most likely stopped responding. Resetting everything. */
mutex_lock(&con->ucsi->ppm_lock);
ucsi_reset_ppm(con->ucsi); ucsi_reset_ppm(con->ucsi);
mutex_unlock(&con->ucsi->ppm_lock);
c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy; c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy;
ucsi_send_command(con->ucsi, c, NULL, 0); ucsi_send_command(con->ucsi, c, NULL, 0);
...@@ -901,12 +898,15 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ...@@ -901,12 +898,15 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
con->num = index + 1; con->num = index + 1;
con->ucsi = ucsi; con->ucsi = ucsi;
/* Delay other interactions with the con until registration is complete */
mutex_lock(&con->lock);
/* Get connector capability */ /* Get connector capability */
command = UCSI_GET_CONNECTOR_CAPABILITY; command = UCSI_GET_CONNECTOR_CAPABILITY;
command |= UCSI_CONNECTOR_NUMBER(con->num); 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) if (ret < 0)
return ret; goto out;
if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP) if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DRP)
cap->data = TYPEC_PORT_DRD; cap->data = TYPEC_PORT_DRD;
...@@ -938,27 +938,32 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ...@@ -938,27 +938,32 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
ret = ucsi_register_port_psy(con); ret = ucsi_register_port_psy(con);
if (ret) if (ret)
return ret; goto out;
/* Register the connector */ /* Register the connector */
con->port = typec_register_port(ucsi->dev, cap); con->port = typec_register_port(ucsi->dev, cap);
if (IS_ERR(con->port)) if (IS_ERR(con->port)) {
return PTR_ERR(con->port); ret = PTR_ERR(con->port);
goto out;
}
/* Alternate modes */ /* Alternate modes */
ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON); ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON);
if (ret) if (ret) {
dev_err(ucsi->dev, "con%d: failed to register alt modes\n", dev_err(ucsi->dev, "con%d: failed to register alt modes\n",
con->num); con->num);
goto out;
}
/* Get the status */ /* Get the status */
command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num);
ret = ucsi_run_command(ucsi, command, &con->status, ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status));
sizeof(con->status));
if (ret < 0) { if (ret < 0) {
dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); 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)) { switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) {
case UCSI_CONSTAT_PARTNER_TYPE_UFP: case UCSI_CONSTAT_PARTNER_TYPE_UFP:
...@@ -983,17 +988,21 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ...@@ -983,17 +988,21 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
if (con->partner) { if (con->partner) {
ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP);
if (ret) if (ret) {
dev_err(ucsi->dev, dev_err(ucsi->dev,
"con%d: failed to register alternate modes\n", "con%d: failed to register alternate modes\n",
con->num); con->num);
else ret = 0;
} else {
ucsi_altmode_update_active(con); ucsi_altmode_update_active(con);
}
} }
trace_ucsi_register_port(con->num, &con->status); trace_ucsi_register_port(con->num, &con->status);
return 0; out:
mutex_unlock(&con->lock);
return ret;
} }
/** /**
...@@ -1009,8 +1018,6 @@ static int ucsi_init(struct ucsi *ucsi) ...@@ -1009,8 +1018,6 @@ static int ucsi_init(struct ucsi *ucsi)
int ret; int ret;
int i; int i;
mutex_lock(&ucsi->ppm_lock);
/* Reset the PPM */ /* Reset the PPM */
ret = ucsi_reset_ppm(ucsi); ret = ucsi_reset_ppm(ucsi);
if (ret) { if (ret) {
...@@ -1021,13 +1028,13 @@ static int ucsi_init(struct ucsi *ucsi) ...@@ -1021,13 +1028,13 @@ static int ucsi_init(struct ucsi *ucsi)
/* Enable basic notifications */ /* Enable basic notifications */
ucsi->ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR; ucsi->ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR;
command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy; 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) if (ret < 0)
goto err_reset; goto err_reset;
/* Get PPM capabilities */ /* Get PPM capabilities */
command = UCSI_GET_CAPABILITY; 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) if (ret < 0)
goto err_reset; goto err_reset;
...@@ -1054,12 +1061,10 @@ static int ucsi_init(struct ucsi *ucsi) ...@@ -1054,12 +1061,10 @@ static int ucsi_init(struct ucsi *ucsi)
/* Enable all notifications */ /* Enable all notifications */
ucsi->ntfy = UCSI_ENABLE_NTFY_ALL; ucsi->ntfy = UCSI_ENABLE_NTFY_ALL;
command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy; 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) if (ret < 0)
goto err_unregister; goto err_unregister;
mutex_unlock(&ucsi->ppm_lock);
return 0; return 0;
err_unregister: err_unregister:
...@@ -1074,8 +1079,6 @@ static int ucsi_init(struct ucsi *ucsi) ...@@ -1074,8 +1079,6 @@ static int ucsi_init(struct ucsi *ucsi)
err_reset: err_reset:
ucsi_reset_ppm(ucsi); ucsi_reset_ppm(ucsi);
err: err:
mutex_unlock(&ucsi->ppm_lock);
return ret; return ret;
} }
......
...@@ -461,6 +461,11 @@ static void stub_disconnect(struct usb_device *udev) ...@@ -461,6 +461,11 @@ static void stub_disconnect(struct usb_device *udev)
return; return;
} }
static bool usbip_match(struct usb_device *udev)
{
return true;
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* These functions need usb_port_suspend and usb_port_resume, /* These functions need usb_port_suspend and usb_port_resume,
...@@ -486,6 +491,7 @@ struct usb_device_driver stub_driver = { ...@@ -486,6 +491,7 @@ struct usb_device_driver stub_driver = {
.name = "usbip-host", .name = "usbip-host",
.probe = stub_probe, .probe = stub_probe,
.disconnect = stub_disconnect, .disconnect = stub_disconnect,
.match = usbip_match,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = stub_suspend, .suspend = stub_suspend,
.resume = stub_resume, .resume = stub_resume,
......
testusb-y += testusb.o
ffs-test-y += ffs-test.o
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Makefile for USB tools # Makefile for USB tools
include ../scripts/Makefile.include
PTHREAD_LIBS = -lpthread bindir ?= /usr/bin
WARNINGS = -Wall -Wextra
CFLAGS = $(WARNINGS) -g -I../include
LDFLAGS = $(PTHREAD_LIBS)
all: testusb ffs-test ifeq ($(srctree),)
%: %.c srctree := $(patsubst %/,%,$(dir $(CURDIR)))
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) srctree := $(patsubst %/,%,$(dir $(srctree)))
endif
# Do not use make's built-in rules
# (this improves performance and avoids hard-to-debug behaviour);
MAKEFLAGS += -r
override CFLAGS += -O2 -Wall -Wextra -g -D_GNU_SOURCE -I$(OUTPUT)include -I$(srctree)/tools/include
override LDFLAGS += -lpthread
ALL_TARGETS := testusb ffs-test
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
all: $(ALL_PROGRAMS)
export srctree OUTPUT CC LD CFLAGS
include $(srctree)/tools/build/Makefile.include
TESTUSB_IN := $(OUTPUT)testusb-in.o
$(TESTUSB_IN): FORCE
$(Q)$(MAKE) $(build)=testusb
$(OUTPUT)testusb: $(TESTUSB_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
FFS_TEST_IN := $(OUTPUT)ffs-test-in.o
$(FFS_TEST_IN): FORCE
$(Q)$(MAKE) $(build)=ffs-test
$(OUTPUT)ffs-test: $(FFS_TEST_IN)
$(QUIET_LINK)$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
clean: clean:
$(RM) testusb ffs-test rm -f $(ALL_PROGRAMS)
find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete -o -name '\.*.o.cmd' -delete
install: $(ALL_PROGRAMS)
install -d -m 755 $(DESTDIR)$(bindir); \
for program in $(ALL_PROGRAMS); do \
install $$program $(DESTDIR)$(bindir); \
done
FORCE:
.PHONY: all install clean FORCE prepare
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment