Skip to content

Commit

Permalink
Merge tag 'usb-5.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…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()
  ...
  • Loading branch information
torvalds committed Aug 30, 2020
2 parents 42df60f + 20934c0 commit 6f0306d
Show file tree
Hide file tree
Showing 26 changed files with 423 additions and 169 deletions.
22 changes: 10 additions & 12 deletions drivers/usb/class/cdc-acm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
40 changes: 38 additions & 2 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,35 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
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
Expand Down Expand Up @@ -934,13 +963,20 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,

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;
}
Expand Down
5 changes: 3 additions & 2 deletions drivers/usb/core/generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,9 @@ static int __check_usb_generic(struct device_driver *drv, void *data)
udrv = to_usb_device_driver(drv);
if (udrv == &usb_generic_driver)
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)
Expand Down
5 changes: 4 additions & 1 deletion drivers/usb/core/hcd-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,11 +315,14 @@ EXPORT_SYMBOL_GPL(usb_hcd_pci_probe);
void usb_hcd_pci_remove(struct pci_dev *dev)
{
struct usb_hcd *hcd;
int hcd_driver_flags;

hcd = pci_get_drvdata(dev);
if (!hcd)
return;

hcd_driver_flags = hcd->driver->flags;

if (pci_dev_run_wake(dev))
pm_runtime_get_noresume(&dev->dev);

Expand Down Expand Up @@ -347,7 +350,7 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
up_read(&companions_rwsem);
}
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_disable_device(dev);
}
Expand Down
7 changes: 7 additions & 0 deletions drivers/usb/core/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0926, 0x0202), .driver_info =
USB_QUIRK_ENDPOINT_IGNORE },

/* Sound Devices MixPre-D */
{ USB_DEVICE(0x0926, 0x0208), .driver_info =
USB_QUIRK_ENDPOINT_IGNORE },

/* Keytouch QWERTY Panel keyboard */
{ USB_DEVICE(0x0926, 0x3333), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
Expand Down Expand Up @@ -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, 0x350e), .driver_info = USB_QUIRK_NO_LPM },

/* DJI CineSSD */
{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },

Expand Down Expand Up @@ -509,6 +515,7 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = {
*/
static const struct usb_device_id usb_endpoint_ignore[] = {
{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 },
{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0208, 1), .driver_info = 0x85 },
{ }
};

Expand Down
107 changes: 89 additions & 18 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* @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];

Expand All @@ -1086,7 +1084,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,

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);
}

Expand All @@ -1096,24 +1094,35 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
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
* this the number of sgs mapped is not equal to the number of
* 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) {
Expand All @@ -1123,7 +1132,7 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
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];
Expand All @@ -1134,8 +1143,39 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
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, chain, i);
dwc3_prepare_one_trb(dep, req, trb_length, chain, i);
}

/*
Expand All @@ -1150,6 +1190,16 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,

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;
}
Expand All @@ -1169,7 +1219,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
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];
Expand All @@ -1180,25 +1230,37 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
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;

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 */
/* 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, false, 0);
dwc3_prepare_one_trb(dep, req, length, false, 0);
}
}

Expand Down Expand Up @@ -2671,8 +2733,17 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
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;
}

Expand Down
Loading

0 comments on commit 6f0306d

Please sign in to comment.