Commit e431e0e4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull USB/PHY fixes from Greg KH:
 "Here are a number of small USB and PHY driver fixes for 4.11-rc4.

  Nothing major here, just an bunch of small fixes, and a handfull of
  good fixes from Johan for devices with crazy descriptors. There are a
  few new device ids in here as well.

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

* tag 'usb-4.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (26 commits)
  usb: gadget: f_hid: fix: Don't access hidg->req without spinlock held
  usb: gadget: udc: remove pointer dereference after free
  usb: gadget: f_uvc: Sanity check wMaxPacketSize for SuperSpeed
  usb: gadget: f_uvc: Fix SuperSpeed companion descriptor's wBytesPerInterval
  usb: gadget: acm: fix endianness in notifications
  usb: dwc3: gadget: delay unmap of bounced requests
  USB: serial: qcserial: add Dell DW5811e
  usb: hub: Fix crash after failure to read BOS descriptor
  ACM gadget: fix endianness in notifications
  USB: usbtmc: fix probe error path
  USB: usbtmc: add missing endpoint sanity check
  USB: serial: option: add Quectel UC15, UC20, EC21, and EC25 modems
  usb: musb: fix possible spinlock deadlock
  usb: musb: dsps: fix iounmap in error and exit paths
  usb: musb: cppi41: don't check early-TX-interrupt for Isoch transfer
  usb-core: Add LINEAR_FRAME_INTR_BINTERVAL USB quirk
  uwb: i1480-dfu: fix NULL-deref at probe
  uwb: hwa-rc: fix NULL-deref at probe
  USB: wusbcore: fix NULL-deref at probe
  USB: uss720: fix NULL-deref at probe
  ...
parents 42234bf8 fd290e70
Broadcom USB3 phy binding for northstar plus SoC
The USB3 phy is internal to the SoC and is accessed using mdio interface.
Required mdio bus properties:
- reg: Should be 0x0 for SoC internal USB3 phy
- #address-cells: must be 1
- #size-cells: must be 0
Required USB3 PHY properties:
- compatible: should be "brcm,nsp-usb3-phy"
- reg: USB3 Phy address on SoC internal MDIO bus and it should be 0x10.
- usb3-ctrl-syscon: handler of syscon node defining physical address
of usb3 control register.
- #phy-cells: must be 0
Required usb3 control properties:
- compatible: should be "brcm,nsp-usb3-ctrl"
- reg: offset and length of the control registers
Example:
mdio@0 {
reg = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
usb3_phy: usb-phy@10 {
compatible = "brcm,nsp-usb3-phy";
reg = <0x10>;
usb3-ctrl-syscon = <&usb3_ctrl>;
#phy-cells = <0>;
status = "disabled";
};
};
usb3_ctrl: syscon@104408 {
compatible = "brcm,nsp-usb3-ctrl", "syscon";
reg = <0x104408 0x3fc>;
};
......@@ -449,6 +449,7 @@ config PHY_QCOM_UFS
config PHY_QCOM_USB_HS
tristate "Qualcomm USB HS PHY module"
depends on USB_ULPI_BUS
depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in
select GENERIC_PHY
help
Support for the USB high-speed ULPI compliant phy on Qualcomm
......@@ -510,12 +511,4 @@ config PHY_MESON8B_USB2
and GXBB SoCs.
If unsure, say N.
config PHY_NSP_USB3
tristate "Broadcom NorthStar plus USB3 PHY driver"
depends on OF && (ARCH_BCM_NSP || COMPILE_TEST)
select GENERIC_PHY
default ARCH_BCM_NSP
help
Enable this to support the Broadcom Northstar plus USB3 PHY.
If unsure, say N.
endmenu
......@@ -62,4 +62,3 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
obj-$(CONFIG_PHY_NSP_USB3) += phy-bcm-nsp-usb3.o
/*
* Copyright (C) 2016 Broadcom
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/mdio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#define NSP_USB3_RST_CTRL_OFFSET 0x3f8
/* mdio reg access */
#define NSP_USB3_PHY_BASE_ADDR_REG 0x1f
#define NSP_USB3_PHY_PLL30_BLOCK 0x8000
#define NSP_USB3_PLL_CONTROL 0x01
#define NSP_USB3_PLLA_CONTROL0 0x0a
#define NSP_USB3_PLLA_CONTROL1 0x0b
#define NSP_USB3_PHY_TX_PMD_BLOCK 0x8040
#define NSP_USB3_TX_PMD_CONTROL1 0x01
#define NSP_USB3_PHY_PIPE_BLOCK 0x8060
#define NSP_USB3_LFPS_CMP 0x02
#define NSP_USB3_LFPS_DEGLITCH 0x03
struct nsp_usb3_phy {
struct regmap *usb3_ctrl;
struct phy *phy;
struct mdio_device *mdiodev;
};
static int nsp_usb3_phy_init(struct phy *phy)
{
struct nsp_usb3_phy *iphy = phy_get_drvdata(phy);
struct mii_bus *bus = iphy->mdiodev->bus;
int addr = iphy->mdiodev->addr;
u32 data;
int rc;
rc = regmap_read(iphy->usb3_ctrl, 0, &data);
if (rc)
return rc;
data |= 1;
rc = regmap_write(iphy->usb3_ctrl, 0, data);
if (rc)
return rc;
rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 1);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
NSP_USB3_PHY_PLL30_BLOCK);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x1000);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL0, 0x6400);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0xc000);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0x8000);
if (rc)
return rc;
rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 0);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x9000);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
NSP_USB3_PHY_PIPE_BLOCK);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_CMP, 0xf30d);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_DEGLITCH, 0x6302);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
NSP_USB3_PHY_TX_PMD_BLOCK);
if (rc)
return rc;
rc = mdiobus_write(bus, addr, NSP_USB3_TX_PMD_CONTROL1, 0x1003);
return rc;
}
static struct phy_ops nsp_usb3_phy_ops = {
.init = nsp_usb3_phy_init,
.owner = THIS_MODULE,
};
static int nsp_usb3_phy_probe(struct mdio_device *mdiodev)
{
struct device *dev = &mdiodev->dev;
struct phy_provider *provider;
struct nsp_usb3_phy *iphy;
iphy = devm_kzalloc(dev, sizeof(*iphy), GFP_KERNEL);
if (!iphy)
return -ENOMEM;
iphy->mdiodev = mdiodev;
iphy->usb3_ctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
"usb3-ctrl-syscon");
if (IS_ERR(iphy->usb3_ctrl))
return PTR_ERR(iphy->usb3_ctrl);
iphy->phy = devm_phy_create(dev, dev->of_node, &nsp_usb3_phy_ops);
if (IS_ERR(iphy->phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(iphy->phy);
}
phy_set_drvdata(iphy->phy, iphy);
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(provider)) {
dev_err(dev, "could not register PHY provider\n");
return PTR_ERR(provider);
}
return 0;
}
static const struct of_device_id nsp_usb3_phy_of_match[] = {
{.compatible = "brcm,nsp-usb3-phy",},
{ /* sentinel */ }
};
static struct mdio_driver nsp_usb3_phy_driver = {
.mdiodrv = {
.driver = {
.name = "nsp-usb3-phy",
.of_match_table = nsp_usb3_phy_of_match,
},
},
.probe = nsp_usb3_phy_probe,
};
mdio_module_driver(nsp_usb3_phy_driver);
MODULE_DESCRIPTION("Broadcom NSP USB3 PHY driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com");
......@@ -254,8 +254,8 @@ static int exynos_pcie_phy_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
exynos_phy->blk_base = devm_ioremap_resource(dev, res);
if (IS_ERR(exynos_phy->phy_base))
return PTR_ERR(exynos_phy->phy_base);
if (IS_ERR(exynos_phy->blk_base))
return PTR_ERR(exynos_phy->blk_base);
exynos_phy->drv_data = drv_data;
......
......@@ -1381,7 +1381,7 @@ static int usbtmc_probe(struct usb_interface *intf,
dev_dbg(&intf->dev, "%s called\n", __func__);
data = kmalloc(sizeof(*data), GFP_KERNEL);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
......@@ -1444,6 +1444,13 @@ static int usbtmc_probe(struct usb_interface *intf,
break;
}
}
if (!data->bulk_out || !data->bulk_in) {
dev_err(&intf->dev, "bulk endpoints not found\n");
retcode = -ENODEV;
goto err_put;
}
/* Find int endpoint */
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
endpoint = &iface_desc->endpoint[n].desc;
......@@ -1469,8 +1476,10 @@ static int usbtmc_probe(struct usb_interface *intf,
if (data->iin_ep_present) {
/* allocate int urb */
data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!data->iin_urb)
if (!data->iin_urb) {
retcode = -ENOMEM;
goto error_register;
}
/* Protect interrupt in endpoint data until iin_urb is freed */
kref_get(&data->kref);
......@@ -1478,8 +1487,10 @@ static int usbtmc_probe(struct usb_interface *intf,
/* allocate buffer for interrupt in */
data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
GFP_KERNEL);
if (!data->iin_buffer)
if (!data->iin_buffer) {
retcode = -ENOMEM;
goto error_register;
}
/* fill interrupt urb */
usb_fill_int_urb(data->iin_urb, data->usb_dev,
......@@ -1512,6 +1523,7 @@ error_register:
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
usbtmc_free_int(data);
err_put:
kref_put(&data->kref, usbtmc_delete);
return retcode;
}
......
......@@ -280,6 +280,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
/*
* Adjust bInterval for quirked devices.
*/
/*
* This quirk fixes bIntervals reported in ms.
*/
if (to_usb_device(ddev)->quirks &
USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
n = clamp(fls(d->bInterval) + 3, i, j);
i = j = n;
}
/*
* This quirk fixes bIntervals reported in
* linear microframes.
*/
......
......@@ -4275,7 +4275,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev)
struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
if (!udev->usb2_hw_lpm_capable)
if (!udev->usb2_hw_lpm_capable || !udev->bos)
return;
if (hub)
......
......@@ -170,6 +170,14 @@ static const struct usb_device_id usb_quirk_list[] = {
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
/* Baum Vario Ultra */
{ USB_DEVICE(0x0904, 0x6101), .driver_info =
USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
{ USB_DEVICE(0x0904, 0x6102), .driver_info =
USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
{ USB_DEVICE(0x0904, 0x6103), .driver_info =
USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
/* Keytouch QWERTY Panel keyboard */
{ USB_DEVICE(0x0926, 0x3333), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
......
......@@ -171,6 +171,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status)
{
struct dwc3 *dwc = dep->dwc;
unsigned int unmap_after_complete = false;
req->started = false;
list_del(&req->list);
......@@ -180,11 +181,19 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
if (req->request.status == -EINPROGRESS)
req->request.status = status;
if (dwc->ep0_bounced && dep->number <= 1)
/*
* NOTICE we don't want to unmap before calling ->complete() if we're
* dealing with a bounced ep0 request. If we unmap it here, we would end
* up overwritting the contents of req->buf and this could confuse the
* gadget driver.
*/
if (dwc->ep0_bounced && dep->number <= 1) {
dwc->ep0_bounced = false;
usb_gadget_unmap_request_by_dev(dwc->sysdev,
&req->request, req->direction);
unmap_after_complete = true;
} else {
usb_gadget_unmap_request_by_dev(dwc->sysdev,
&req->request, req->direction);
}
trace_dwc3_gadget_giveback(req);
......@@ -192,6 +201,10 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
usb_gadget_giveback_request(&dep->endpoint, &req->request);
spin_lock(&dwc->lock);
if (unmap_after_complete)
usb_gadget_unmap_request_by_dev(dwc->sysdev,
&req->request, req->direction);
if (dep->number > 1)
pm_runtime_put(dwc->dev);
}
......
......@@ -535,13 +535,15 @@ static int acm_notify_serial_state(struct f_acm *acm)
{
struct usb_composite_dev *cdev = acm->port.func.config->cdev;
int status;
__le16 serial_state;
spin_lock(&acm->lock);
if (acm->notify_req) {
dev_dbg(&cdev->gadget->dev, "acm ttyGS%d serial state %04x\n",
acm->port_num, acm->serial_state);
serial_state = cpu_to_le16(acm->serial_state);
status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
0, &acm->serial_state, sizeof(acm->serial_state));
0, &serial_state, sizeof(acm->serial_state));
} else {
acm->pending = true;
status = 0;
......
......@@ -367,7 +367,7 @@ try_again:
count = min_t(unsigned, count, hidg->report_length);
spin_unlock_irqrestore(&hidg->write_spinlock, flags);
status = copy_from_user(hidg->req->buf, buffer, count);
status = copy_from_user(req->buf, buffer, count);
if (status != 0) {
ERROR(hidg->func.config->cdev,
......@@ -378,9 +378,9 @@ try_again:
spin_lock_irqsave(&hidg->write_spinlock, flags);
/* we our function has been disabled by host */
/* when our function has been disabled by host */
if (!hidg->req) {
free_ep_req(hidg->in_ep, hidg->req);
free_ep_req(hidg->in_ep, req);
/*
* TODO
* Should we fail with error here?
......@@ -394,7 +394,7 @@ try_again:
req->complete = f_hidg_req_complete;
req->context = hidg;
status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC);
status = usb_ep_queue(hidg->in_ep, req, GFP_ATOMIC);
if (status < 0) {
ERROR(hidg->func.config->cdev,
"usb_ep_queue error on int endpoint %zd\n", status);
......
......@@ -594,6 +594,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
/* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */
if (opts->streaming_maxburst &&
(opts->streaming_maxpacket % 1024) != 0) {
opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024);
INFO(cdev, "overriding streaming_maxpacket to %d\n",
opts->streaming_maxpacket);
}
/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
* module parameters.
*
......@@ -625,7 +633,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
uvc_ss_streaming_comp.wBytesPerInterval =
cpu_to_le16(max_packet_size * max_packet_mult *
opts->streaming_maxburst);
(opts->streaming_maxburst + 1));
/* Allocate endpoints. */
ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
......
......@@ -1523,7 +1523,6 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev,
td = phys_to_virt(addr);
addr2 = (dma_addr_t)td->next;
pci_pool_free(dev->data_requests, td, addr);
td->next = 0x00;
addr = addr2;
}
req->chain_len = 1;
......
......@@ -347,6 +347,9 @@ static int idmouse_probe(struct usb_interface *interface,
if (iface_desc->desc.bInterfaceClass != 0x0A)
return -ENODEV;
if (iface_desc->desc.bNumEndpoints < 1)
return -ENODEV;
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL)
......
......@@ -366,6 +366,10 @@ static int lvs_rh_probe(struct usb_interface *intf,
hdev = interface_to_usbdev(intf);
desc = intf->cur_altsetting;
if (desc->desc.bNumEndpoints < 1)
return -ENODEV;
endpoint = &desc->endpoint[0].desc;
/* valid only for SS root hub */
......
......@@ -709,6 +709,11 @@ static int uss720_probe(struct usb_interface *intf,
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints < 3) {
usb_put_dev(usbdev);
return -ENODEV;
}
/*
* Allocate parport interface
*/
......
......@@ -2490,8 +2490,8 @@ static int musb_remove(struct platform_device *pdev)
musb_host_cleanup(musb);
musb_gadget_cleanup(musb);
spin_lock_irqsave(&musb->lock, flags);
musb_platform_disable(musb);
spin_lock_irqsave(&musb->lock, flags);
musb_disable_interrupts(musb);
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
spin_unlock_irqrestore(&musb->lock, flags);
......
......@@ -238,8 +238,27 @@ static void cppi41_dma_callback(void *private_data,
transferred < cppi41_channel->packet_sz)
cppi41_channel->prog_len = 0;
if (cppi41_channel->is_tx)
empty = musb_is_tx_fifo_empty(hw_ep);
if (cppi41_channel->is_tx) {
u8 type;
if (is_host_active(musb))
type = hw_ep->out_qh->type;
else
type = hw_ep->ep_in.type;
if (type == USB_ENDPOINT_XFER_ISOC)
/*
* Don't use the early-TX-interrupt workaround below
* for Isoch transfter. Since Isoch are periodic
* transfer, by the time the next transfer is
* scheduled, the current one should be done already.
*
* This avoids audio playback underrun issue.
*/
empty = true;
else
empty = musb_is_tx_fifo_empty(hw_ep);
}
if (!cppi41_channel->is_tx || empty) {
cppi41_trans_done(cppi41_channel);
......
......@@ -933,7 +933,7 @@ static int dsps_probe(struct platform_device *pdev)
if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL) {
ret = dsps_setup_optional_vbus_irq(pdev, glue);
if (ret)
return ret;
goto err_iounmap;
}
platform_set_drvdata(pdev, glue);
......@@ -946,6 +946,8 @@ static int dsps_probe(struct platform_device *pdev)
err:
pm_runtime_disable(&pdev->dev);
err_iounmap:
iounmap(glue->usbss_base);
return ret;
}
......@@ -956,6 +958,7 @@ static int dsps_remove(struct platform_device *pdev)
platform_device_unregister(glue->musb);
pm_runtime_disable(&pdev->dev);
iounmap(glue->usbss_base);
return 0;
}
......
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