mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-24 09:13:20 -05:00
USB fixes for 4.16-rc6
Here are a small clump of USB fixes for 4.16-rc6. Nothing major, just a number of fixes in lots of different drivers, as well as a PHY driver fix that snuck into this tree. Full details are in the shortlog. All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWqkFYA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynWYQCfRxixarpDUKd0rxqdSp/v1UFxP4AAoNFIpNrl CpSr9aiz/V/4eLk1z7Iu =j+5S -----END PGP SIGNATURE----- Merge tag 'usb-4.16-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a small clump of USB fixes for 4.16-rc6. Nothing major, just a number of fixes in lots of different drivers, as well as a PHY driver fix that snuck into this tree. Full details are in the shortlog. All of these have been in linux-next with no reported issues" * tag 'usb-4.16-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (22 commits) usb: musb: Fix external abort in musb_remove on omap2430 phy: qcom-ufs: add MODULE_LICENSE tag usb: typec: tcpm: fusb302: Do not log an error on -EPROBE_DEFER USB: OHCI: Fix NULL dereference in HCDs using HCD_LOCAL_MEM usbip: vudc: fix null pointer dereference on udc->lock xhci: Fix front USB ports on ASUS PRIME B350M-A usb: host: xhci-plat: revert "usb: host: xhci-plat: enable clk in resume timing" usb: usbmon: Read text within supplied buffer size usb: host: xhci-rcar: add support for r8a77965 USB: storage: Add JMicron bridge 152d:2567 to unusual_devs.h usb: xhci: dbc: Fix lockdep warning xhci: fix endpoint context tracer output Revert "typec: tcpm: Only request matching pdos" usb: musb: call pm_runtime_{get,put}_sync before reading vbus registers usb: quirks: add control message delay for 1b1c:1b20 uas: fix comparison for error code usb: gadget: udc: renesas_usb3: add binging for r8a77965 usb: renesas_usbhs: add binding for r8a77965 usb: dwc2: fix STM32F7 USB OTG HS compatible dt-bindings: usb: fix the STM32F7 DWC2 OTG HS core binding ...
This commit is contained in:
commit
3032f8c504
26 changed files with 217 additions and 224 deletions
|
@ -19,7 +19,7 @@ Required properties:
|
||||||
configured in FS mode;
|
configured in FS mode;
|
||||||
- "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs
|
- "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs
|
||||||
configured in HS mode;
|
configured in HS mode;
|
||||||
- "st,stm32f7xx-hsotg": The DWC2 USB HS controller instance in STM32F7xx SoCs
|
- "st,stm32f7-hsotg": The DWC2 USB HS controller instance in STM32F7 SoCs
|
||||||
configured in HS mode;
|
configured in HS mode;
|
||||||
- reg : Should contain 1 register range (address and length)
|
- reg : Should contain 1 register range (address and length)
|
||||||
- interrupts : Should contain 1 interrupt
|
- interrupts : Should contain 1 interrupt
|
||||||
|
|
|
@ -4,6 +4,7 @@ Required properties:
|
||||||
- compatible: Must contain one of the following:
|
- compatible: Must contain one of the following:
|
||||||
- "renesas,r8a7795-usb3-peri"
|
- "renesas,r8a7795-usb3-peri"
|
||||||
- "renesas,r8a7796-usb3-peri"
|
- "renesas,r8a7796-usb3-peri"
|
||||||
|
- "renesas,r8a77965-usb3-peri"
|
||||||
- "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible
|
- "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible
|
||||||
device
|
device
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ Required properties:
|
||||||
- "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
|
- "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
|
||||||
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
|
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
|
||||||
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
|
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
|
||||||
|
- "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device
|
||||||
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
|
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
|
||||||
- "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
|
- "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
|
||||||
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
|
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
|
||||||
|
|
|
@ -13,6 +13,7 @@ Required properties:
|
||||||
- "renesas,xhci-r8a7793" for r8a7793 SoC
|
- "renesas,xhci-r8a7793" for r8a7793 SoC
|
||||||
- "renesas,xhci-r8a7795" for r8a7795 SoC
|
- "renesas,xhci-r8a7795" for r8a7795 SoC
|
||||||
- "renesas,xhci-r8a7796" for r8a7796 SoC
|
- "renesas,xhci-r8a7796" for r8a7796 SoC
|
||||||
|
- "renesas,xhci-r8a77965" for r8a77965 SoC
|
||||||
- "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible
|
- "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible
|
||||||
device
|
device
|
||||||
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
|
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
|
||||||
|
|
|
@ -675,3 +675,8 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);
|
EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Yaniv Gardi <ygardi@codeaurora.org>");
|
||||||
|
MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
|
||||||
|
MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
|
@ -151,6 +151,10 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
|
||||||
|
|
||||||
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
|
ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
|
||||||
|
|
||||||
|
/* Linger a bit, prior to the next control message. */
|
||||||
|
if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
|
||||||
|
msleep(200);
|
||||||
|
|
||||||
kfree(dr);
|
kfree(dr);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -230,7 +230,8 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||||
{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },
|
{ USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||||
|
|
||||||
/* Corsair Strafe RGB */
|
/* Corsair Strafe RGB */
|
||||||
{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT },
|
{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT |
|
||||||
|
USB_QUIRK_DELAY_CTRL_MSG },
|
||||||
|
|
||||||
/* Corsair K70 LUX */
|
/* Corsair K70 LUX */
|
||||||
{ USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
|
{ USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||||
|
|
|
@ -137,7 +137,7 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
|
||||||
p->activate_stm_fs_transceiver = true;
|
p->activate_stm_fs_transceiver = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc2_set_stm32f7xx_hsotg_params(struct dwc2_hsotg *hsotg)
|
static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
struct dwc2_core_params *p = &hsotg->params;
|
struct dwc2_core_params *p = &hsotg->params;
|
||||||
|
|
||||||
|
@ -164,8 +164,8 @@ const struct of_device_id dwc2_of_match_table[] = {
|
||||||
{ .compatible = "st,stm32f4x9-fsotg",
|
{ .compatible = "st,stm32f4x9-fsotg",
|
||||||
.data = dwc2_set_stm32f4x9_fsotg_params },
|
.data = dwc2_set_stm32f4x9_fsotg_params },
|
||||||
{ .compatible = "st,stm32f4x9-hsotg" },
|
{ .compatible = "st,stm32f4x9-hsotg" },
|
||||||
{ .compatible = "st,stm32f7xx-hsotg",
|
{ .compatible = "st,stm32f7-hsotg",
|
||||||
.data = dwc2_set_stm32f7xx_hsotg_params },
|
.data = dwc2_set_stm32f7_hsotg_params },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
||||||
|
|
|
@ -175,7 +175,7 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||||||
dwc->desired_dr_role = mode;
|
dwc->desired_dr_role = mode;
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
queue_work(system_power_efficient_wq, &dwc->drd_work);
|
queue_work(system_freezable_wq, &dwc->drd_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
|
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
|
||||||
|
|
|
@ -1538,7 +1538,6 @@ ffs_fs_kill_sb(struct super_block *sb)
|
||||||
if (sb->s_fs_info) {
|
if (sb->s_fs_info) {
|
||||||
ffs_release_dev(sb->s_fs_info);
|
ffs_release_dev(sb->s_fs_info);
|
||||||
ffs_data_closed(sb->s_fs_info);
|
ffs_data_closed(sb->s_fs_info);
|
||||||
ffs_data_put(sb->s_fs_info);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -447,7 +447,8 @@ static int ohci_init (struct ohci_hcd *ohci)
|
||||||
struct usb_hcd *hcd = ohci_to_hcd(ohci);
|
struct usb_hcd *hcd = ohci_to_hcd(ohci);
|
||||||
|
|
||||||
/* Accept arbitrarily long scatter-gather lists */
|
/* Accept arbitrarily long scatter-gather lists */
|
||||||
hcd->self.sg_tablesize = ~0;
|
if (!(hcd->driver->flags & HCD_LOCAL_MEM))
|
||||||
|
hcd->self.sg_tablesize = ~0;
|
||||||
|
|
||||||
if (distrust_firmware)
|
if (distrust_firmware)
|
||||||
ohci->flags |= OHCI_QUIRK_HUB_POWER;
|
ohci->flags |= OHCI_QUIRK_HUB_POWER;
|
||||||
|
|
|
@ -328,13 +328,14 @@ dbc_ep_do_queue(struct dbc_ep *dep, struct dbc_request *req)
|
||||||
int dbc_ep_queue(struct dbc_ep *dep, struct dbc_request *req,
|
int dbc_ep_queue(struct dbc_ep *dep, struct dbc_request *req,
|
||||||
gfp_t gfp_flags)
|
gfp_t gfp_flags)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct xhci_dbc *dbc = dep->dbc;
|
struct xhci_dbc *dbc = dep->dbc;
|
||||||
int ret = -ESHUTDOWN;
|
int ret = -ESHUTDOWN;
|
||||||
|
|
||||||
spin_lock(&dbc->lock);
|
spin_lock_irqsave(&dbc->lock, flags);
|
||||||
if (dbc->state == DS_CONFIGURED)
|
if (dbc->state == DS_CONFIGURED)
|
||||||
ret = dbc_ep_do_queue(dep, req);
|
ret = dbc_ep_do_queue(dep, req);
|
||||||
spin_unlock(&dbc->lock);
|
spin_unlock_irqrestore(&dbc->lock, flags);
|
||||||
|
|
||||||
mod_delayed_work(system_wq, &dbc->event_work, 0);
|
mod_delayed_work(system_wq, &dbc->event_work, 0);
|
||||||
|
|
||||||
|
@ -521,15 +522,16 @@ static void xhci_do_dbc_stop(struct xhci_hcd *xhci)
|
||||||
static int xhci_dbc_start(struct xhci_hcd *xhci)
|
static int xhci_dbc_start(struct xhci_hcd *xhci)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned long flags;
|
||||||
struct xhci_dbc *dbc = xhci->dbc;
|
struct xhci_dbc *dbc = xhci->dbc;
|
||||||
|
|
||||||
WARN_ON(!dbc);
|
WARN_ON(!dbc);
|
||||||
|
|
||||||
pm_runtime_get_sync(xhci_to_hcd(xhci)->self.controller);
|
pm_runtime_get_sync(xhci_to_hcd(xhci)->self.controller);
|
||||||
|
|
||||||
spin_lock(&dbc->lock);
|
spin_lock_irqsave(&dbc->lock, flags);
|
||||||
ret = xhci_do_dbc_start(xhci);
|
ret = xhci_do_dbc_start(xhci);
|
||||||
spin_unlock(&dbc->lock);
|
spin_unlock_irqrestore(&dbc->lock, flags);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pm_runtime_put(xhci_to_hcd(xhci)->self.controller);
|
pm_runtime_put(xhci_to_hcd(xhci)->self.controller);
|
||||||
|
@ -541,6 +543,7 @@ static int xhci_dbc_start(struct xhci_hcd *xhci)
|
||||||
|
|
||||||
static void xhci_dbc_stop(struct xhci_hcd *xhci)
|
static void xhci_dbc_stop(struct xhci_hcd *xhci)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct xhci_dbc *dbc = xhci->dbc;
|
struct xhci_dbc *dbc = xhci->dbc;
|
||||||
struct dbc_port *port = &dbc->port;
|
struct dbc_port *port = &dbc->port;
|
||||||
|
|
||||||
|
@ -551,9 +554,9 @@ static void xhci_dbc_stop(struct xhci_hcd *xhci)
|
||||||
if (port->registered)
|
if (port->registered)
|
||||||
xhci_dbc_tty_unregister_device(xhci);
|
xhci_dbc_tty_unregister_device(xhci);
|
||||||
|
|
||||||
spin_lock(&dbc->lock);
|
spin_lock_irqsave(&dbc->lock, flags);
|
||||||
xhci_do_dbc_stop(xhci);
|
xhci_do_dbc_stop(xhci);
|
||||||
spin_unlock(&dbc->lock);
|
spin_unlock_irqrestore(&dbc->lock, flags);
|
||||||
|
|
||||||
pm_runtime_put_sync(xhci_to_hcd(xhci)->self.controller);
|
pm_runtime_put_sync(xhci_to_hcd(xhci)->self.controller);
|
||||||
}
|
}
|
||||||
|
@ -779,14 +782,15 @@ static void xhci_dbc_handle_events(struct work_struct *work)
|
||||||
int ret;
|
int ret;
|
||||||
enum evtreturn evtr;
|
enum evtreturn evtr;
|
||||||
struct xhci_dbc *dbc;
|
struct xhci_dbc *dbc;
|
||||||
|
unsigned long flags;
|
||||||
struct xhci_hcd *xhci;
|
struct xhci_hcd *xhci;
|
||||||
|
|
||||||
dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work);
|
dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work);
|
||||||
xhci = dbc->xhci;
|
xhci = dbc->xhci;
|
||||||
|
|
||||||
spin_lock(&dbc->lock);
|
spin_lock_irqsave(&dbc->lock, flags);
|
||||||
evtr = xhci_dbc_do_handle_events(dbc);
|
evtr = xhci_dbc_do_handle_events(dbc);
|
||||||
spin_unlock(&dbc->lock);
|
spin_unlock_irqrestore(&dbc->lock, flags);
|
||||||
|
|
||||||
switch (evtr) {
|
switch (evtr) {
|
||||||
case EVT_GSER:
|
case EVT_GSER:
|
||||||
|
|
|
@ -92,21 +92,23 @@ static void dbc_start_rx(struct dbc_port *port)
|
||||||
static void
|
static void
|
||||||
dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req)
|
dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct xhci_dbc *dbc = xhci->dbc;
|
struct xhci_dbc *dbc = xhci->dbc;
|
||||||
struct dbc_port *port = &dbc->port;
|
struct dbc_port *port = &dbc->port;
|
||||||
|
|
||||||
spin_lock(&port->port_lock);
|
spin_lock_irqsave(&port->port_lock, flags);
|
||||||
list_add_tail(&req->list_pool, &port->read_queue);
|
list_add_tail(&req->list_pool, &port->read_queue);
|
||||||
tasklet_schedule(&port->push);
|
tasklet_schedule(&port->push);
|
||||||
spin_unlock(&port->port_lock);
|
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
|
static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct xhci_dbc *dbc = xhci->dbc;
|
struct xhci_dbc *dbc = xhci->dbc;
|
||||||
struct dbc_port *port = &dbc->port;
|
struct dbc_port *port = &dbc->port;
|
||||||
|
|
||||||
spin_lock(&port->port_lock);
|
spin_lock_irqsave(&port->port_lock, flags);
|
||||||
list_add(&req->list_pool, &port->write_pool);
|
list_add(&req->list_pool, &port->write_pool);
|
||||||
switch (req->status) {
|
switch (req->status) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -119,7 +121,7 @@ static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
|
||||||
req->status);
|
req->status);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
spin_unlock(&port->port_lock);
|
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xhci_dbc_free_req(struct dbc_ep *dep, struct dbc_request *req)
|
static void xhci_dbc_free_req(struct dbc_ep *dep, struct dbc_request *req)
|
||||||
|
@ -327,12 +329,13 @@ static void dbc_rx_push(unsigned long _port)
|
||||||
{
|
{
|
||||||
struct dbc_request *req;
|
struct dbc_request *req;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
|
unsigned long flags;
|
||||||
bool do_push = false;
|
bool do_push = false;
|
||||||
bool disconnect = false;
|
bool disconnect = false;
|
||||||
struct dbc_port *port = (void *)_port;
|
struct dbc_port *port = (void *)_port;
|
||||||
struct list_head *queue = &port->read_queue;
|
struct list_head *queue = &port->read_queue;
|
||||||
|
|
||||||
spin_lock_irq(&port->port_lock);
|
spin_lock_irqsave(&port->port_lock, flags);
|
||||||
tty = port->port.tty;
|
tty = port->port.tty;
|
||||||
while (!list_empty(queue)) {
|
while (!list_empty(queue)) {
|
||||||
req = list_first_entry(queue, struct dbc_request, list_pool);
|
req = list_first_entry(queue, struct dbc_request, list_pool);
|
||||||
|
@ -392,16 +395,17 @@ static void dbc_rx_push(unsigned long _port)
|
||||||
if (!disconnect)
|
if (!disconnect)
|
||||||
dbc_start_rx(port);
|
dbc_start_rx(port);
|
||||||
|
|
||||||
spin_unlock_irq(&port->port_lock);
|
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
|
static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct dbc_port *port = container_of(_port, struct dbc_port, port);
|
struct dbc_port *port = container_of(_port, struct dbc_port, port);
|
||||||
|
|
||||||
spin_lock_irq(&port->port_lock);
|
spin_lock_irqsave(&port->port_lock, flags);
|
||||||
dbc_start_rx(port);
|
dbc_start_rx(port);
|
||||||
spin_unlock_irq(&port->port_lock);
|
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
|
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
|
||||||
xhci->quirks |= XHCI_AMD_PLL_FIX;
|
xhci->quirks |= XHCI_AMD_PLL_FIX;
|
||||||
|
|
||||||
|
if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43bb)
|
||||||
|
xhci->quirks |= XHCI_SUSPEND_DELAY;
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_AMD)
|
if (pdev->vendor == PCI_VENDOR_ID_AMD)
|
||||||
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
|
||||||
|
|
||||||
|
|
|
@ -360,7 +360,6 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xhci_suspend() needs `do_wakeup` to know whether host is allowed
|
* xhci_suspend() needs `do_wakeup` to know whether host is allowed
|
||||||
|
@ -370,12 +369,7 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
|
||||||
* reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
|
* reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
|
||||||
* also applies to runtime suspend.
|
* also applies to runtime suspend.
|
||||||
*/
|
*/
|
||||||
ret = xhci_suspend(xhci, device_may_wakeup(dev));
|
return xhci_suspend(xhci, device_may_wakeup(dev));
|
||||||
|
|
||||||
if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk))
|
|
||||||
clk_disable_unprepare(xhci->clk);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused xhci_plat_resume(struct device *dev)
|
static int __maybe_unused xhci_plat_resume(struct device *dev)
|
||||||
|
@ -384,9 +378,6 @@ static int __maybe_unused xhci_plat_resume(struct device *dev)
|
||||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk))
|
|
||||||
clk_prepare_enable(xhci->clk);
|
|
||||||
|
|
||||||
ret = xhci_priv_resume_quirk(hcd);
|
ret = xhci_priv_resume_quirk(hcd);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -83,6 +83,10 @@ static const struct soc_device_attribute rcar_quirks_match[] = {
|
||||||
.soc_id = "r8a7796",
|
.soc_id = "r8a7796",
|
||||||
.data = (void *)RCAR_XHCI_FIRMWARE_V3,
|
.data = (void *)RCAR_XHCI_FIRMWARE_V3,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.soc_id = "r8a77965",
|
||||||
|
.data = (void *)RCAR_XHCI_FIRMWARE_V3,
|
||||||
|
},
|
||||||
{ /* sentinel */ },
|
{ /* sentinel */ },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -877,6 +877,9 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
|
||||||
clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
|
clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
|
||||||
del_timer_sync(&xhci->shared_hcd->rh_timer);
|
del_timer_sync(&xhci->shared_hcd->rh_timer);
|
||||||
|
|
||||||
|
if (xhci->quirks & XHCI_SUSPEND_DELAY)
|
||||||
|
usleep_range(1000, 1500);
|
||||||
|
|
||||||
spin_lock_irq(&xhci->lock);
|
spin_lock_irq(&xhci->lock);
|
||||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
|
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
|
||||||
|
|
|
@ -718,11 +718,12 @@ struct xhci_ep_ctx {
|
||||||
/* bits 10:14 are Max Primary Streams */
|
/* bits 10:14 are Max Primary Streams */
|
||||||
/* bit 15 is Linear Stream Array */
|
/* bit 15 is Linear Stream Array */
|
||||||
/* Interval - period between requests to an endpoint - 125u increments. */
|
/* Interval - period between requests to an endpoint - 125u increments. */
|
||||||
#define EP_INTERVAL(p) (((p) & 0xff) << 16)
|
#define EP_INTERVAL(p) (((p) & 0xff) << 16)
|
||||||
#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
|
#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
|
||||||
#define CTX_TO_EP_INTERVAL(p) (((p) >> 16) & 0xff)
|
#define CTX_TO_EP_INTERVAL(p) (((p) >> 16) & 0xff)
|
||||||
#define EP_MAXPSTREAMS_MASK (0x1f << 10)
|
#define EP_MAXPSTREAMS_MASK (0x1f << 10)
|
||||||
#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK)
|
#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK)
|
||||||
|
#define CTX_TO_EP_MAXPSTREAMS(p) (((p) & EP_MAXPSTREAMS_MASK) >> 10)
|
||||||
/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
|
/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
|
||||||
#define EP_HAS_LSA (1 << 15)
|
#define EP_HAS_LSA (1 << 15)
|
||||||
/* hosts with LEC=1 use bits 31:24 as ESIT high bits. */
|
/* hosts with LEC=1 use bits 31:24 as ESIT high bits. */
|
||||||
|
@ -1825,6 +1826,7 @@ struct xhci_hcd {
|
||||||
#define XHCI_U2_DISABLE_WAKE (1 << 27)
|
#define XHCI_U2_DISABLE_WAKE (1 << 27)
|
||||||
#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
|
#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
|
||||||
#define XHCI_HW_LPM_DISABLE (1 << 29)
|
#define XHCI_HW_LPM_DISABLE (1 << 29)
|
||||||
|
#define XHCI_SUSPEND_DELAY (1 << 30)
|
||||||
|
|
||||||
unsigned int num_active_eps;
|
unsigned int num_active_eps;
|
||||||
unsigned int limit_active_eps;
|
unsigned int limit_active_eps;
|
||||||
|
@ -2549,21 +2551,22 @@ static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq,
|
||||||
u8 burst;
|
u8 burst;
|
||||||
u8 cerr;
|
u8 cerr;
|
||||||
u8 mult;
|
u8 mult;
|
||||||
u8 lsa;
|
|
||||||
u8 hid;
|
bool lsa;
|
||||||
|
bool hid;
|
||||||
|
|
||||||
esit = CTX_TO_MAX_ESIT_PAYLOAD_HI(info) << 16 |
|
esit = CTX_TO_MAX_ESIT_PAYLOAD_HI(info) << 16 |
|
||||||
CTX_TO_MAX_ESIT_PAYLOAD(tx_info);
|
CTX_TO_MAX_ESIT_PAYLOAD(tx_info);
|
||||||
|
|
||||||
ep_state = info & EP_STATE_MASK;
|
ep_state = info & EP_STATE_MASK;
|
||||||
max_pstr = info & EP_MAXPSTREAMS_MASK;
|
max_pstr = CTX_TO_EP_MAXPSTREAMS(info);
|
||||||
interval = CTX_TO_EP_INTERVAL(info);
|
interval = CTX_TO_EP_INTERVAL(info);
|
||||||
mult = CTX_TO_EP_MULT(info) + 1;
|
mult = CTX_TO_EP_MULT(info) + 1;
|
||||||
lsa = info & EP_HAS_LSA;
|
lsa = !!(info & EP_HAS_LSA);
|
||||||
|
|
||||||
cerr = (info2 & (3 << 1)) >> 1;
|
cerr = (info2 & (3 << 1)) >> 1;
|
||||||
ep_type = CTX_TO_EP_TYPE(info2);
|
ep_type = CTX_TO_EP_TYPE(info2);
|
||||||
hid = info2 & (1 << 7);
|
hid = !!(info2 & (1 << 7));
|
||||||
burst = CTX_TO_MAX_BURST(info2);
|
burst = CTX_TO_MAX_BURST(info2);
|
||||||
maxp = MAX_PACKET_DECODED(info2);
|
maxp = MAX_PACKET_DECODED(info2);
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,8 @@ struct mon_reader_text {
|
||||||
|
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
int printf_size;
|
int printf_size;
|
||||||
|
size_t printf_offset;
|
||||||
|
size_t printf_togo;
|
||||||
char *printf_buf;
|
char *printf_buf;
|
||||||
struct mutex printf_lock;
|
struct mutex printf_lock;
|
||||||
|
|
||||||
|
@ -376,75 +378,103 @@ err_alloc:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp,
|
||||||
* For simplicity, we read one record in one system call and throw out
|
char __user * const buf, const size_t nbytes)
|
||||||
* what does not fit. This means that the following does not work:
|
|
||||||
* dd if=/dbg/usbmon/0t bs=10
|
|
||||||
* Also, we do not allow seeks and do not bother advancing the offset.
|
|
||||||
*/
|
|
||||||
static ssize_t mon_text_read_t(struct file *file, char __user *buf,
|
|
||||||
size_t nbytes, loff_t *ppos)
|
|
||||||
{
|
{
|
||||||
struct mon_reader_text *rp = file->private_data;
|
const size_t togo = min(nbytes, rp->printf_togo);
|
||||||
struct mon_event_text *ep;
|
|
||||||
struct mon_text_ptr ptr;
|
|
||||||
|
|
||||||
ep = mon_text_read_wait(rp, file);
|
if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo))
|
||||||
if (IS_ERR(ep))
|
return -EFAULT;
|
||||||
return PTR_ERR(ep);
|
rp->printf_togo -= togo;
|
||||||
mutex_lock(&rp->printf_lock);
|
rp->printf_offset += togo;
|
||||||
ptr.cnt = 0;
|
return togo;
|
||||||
ptr.pbuf = rp->printf_buf;
|
|
||||||
ptr.limit = rp->printf_size;
|
|
||||||
|
|
||||||
mon_text_read_head_t(rp, &ptr, ep);
|
|
||||||
mon_text_read_statset(rp, &ptr, ep);
|
|
||||||
ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
|
|
||||||
" %d", ep->length);
|
|
||||||
mon_text_read_data(rp, &ptr, ep);
|
|
||||||
|
|
||||||
if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
|
|
||||||
ptr.cnt = -EFAULT;
|
|
||||||
mutex_unlock(&rp->printf_lock);
|
|
||||||
kmem_cache_free(rp->e_slab, ep);
|
|
||||||
return ptr.cnt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mon_text_read_u(struct file *file, char __user *buf,
|
/* ppos is not advanced since the llseek operation is not permitted. */
|
||||||
size_t nbytes, loff_t *ppos)
|
static ssize_t mon_text_read_t(struct file *file, char __user *buf,
|
||||||
|
size_t nbytes, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct mon_reader_text *rp = file->private_data;
|
struct mon_reader_text *rp = file->private_data;
|
||||||
struct mon_event_text *ep;
|
struct mon_event_text *ep;
|
||||||
struct mon_text_ptr ptr;
|
struct mon_text_ptr ptr;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
ep = mon_text_read_wait(rp, file);
|
|
||||||
if (IS_ERR(ep))
|
|
||||||
return PTR_ERR(ep);
|
|
||||||
mutex_lock(&rp->printf_lock);
|
mutex_lock(&rp->printf_lock);
|
||||||
ptr.cnt = 0;
|
|
||||||
ptr.pbuf = rp->printf_buf;
|
|
||||||
ptr.limit = rp->printf_size;
|
|
||||||
|
|
||||||
mon_text_read_head_u(rp, &ptr, ep);
|
if (rp->printf_togo == 0) {
|
||||||
if (ep->type == 'E') {
|
|
||||||
mon_text_read_statset(rp, &ptr, ep);
|
ep = mon_text_read_wait(rp, file);
|
||||||
} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
|
if (IS_ERR(ep)) {
|
||||||
mon_text_read_isostat(rp, &ptr, ep);
|
mutex_unlock(&rp->printf_lock);
|
||||||
mon_text_read_isodesc(rp, &ptr, ep);
|
return PTR_ERR(ep);
|
||||||
} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
|
}
|
||||||
mon_text_read_intstat(rp, &ptr, ep);
|
ptr.cnt = 0;
|
||||||
} else {
|
ptr.pbuf = rp->printf_buf;
|
||||||
|
ptr.limit = rp->printf_size;
|
||||||
|
|
||||||
|
mon_text_read_head_t(rp, &ptr, ep);
|
||||||
mon_text_read_statset(rp, &ptr, ep);
|
mon_text_read_statset(rp, &ptr, ep);
|
||||||
|
ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
|
||||||
|
" %d", ep->length);
|
||||||
|
mon_text_read_data(rp, &ptr, ep);
|
||||||
|
|
||||||
|
rp->printf_togo = ptr.cnt;
|
||||||
|
rp->printf_offset = 0;
|
||||||
|
|
||||||
|
kmem_cache_free(rp->e_slab, ep);
|
||||||
}
|
}
|
||||||
ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
|
|
||||||
" %d", ep->length);
|
|
||||||
mon_text_read_data(rp, &ptr, ep);
|
|
||||||
|
|
||||||
if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
|
ret = mon_text_copy_to_user(rp, buf, nbytes);
|
||||||
ptr.cnt = -EFAULT;
|
|
||||||
mutex_unlock(&rp->printf_lock);
|
mutex_unlock(&rp->printf_lock);
|
||||||
kmem_cache_free(rp->e_slab, ep);
|
return ret;
|
||||||
return ptr.cnt;
|
}
|
||||||
|
|
||||||
|
/* ppos is not advanced since the llseek operation is not permitted. */
|
||||||
|
static ssize_t mon_text_read_u(struct file *file, char __user *buf,
|
||||||
|
size_t nbytes, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct mon_reader_text *rp = file->private_data;
|
||||||
|
struct mon_event_text *ep;
|
||||||
|
struct mon_text_ptr ptr;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
mutex_lock(&rp->printf_lock);
|
||||||
|
|
||||||
|
if (rp->printf_togo == 0) {
|
||||||
|
|
||||||
|
ep = mon_text_read_wait(rp, file);
|
||||||
|
if (IS_ERR(ep)) {
|
||||||
|
mutex_unlock(&rp->printf_lock);
|
||||||
|
return PTR_ERR(ep);
|
||||||
|
}
|
||||||
|
ptr.cnt = 0;
|
||||||
|
ptr.pbuf = rp->printf_buf;
|
||||||
|
ptr.limit = rp->printf_size;
|
||||||
|
|
||||||
|
mon_text_read_head_u(rp, &ptr, ep);
|
||||||
|
if (ep->type == 'E') {
|
||||||
|
mon_text_read_statset(rp, &ptr, ep);
|
||||||
|
} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
|
||||||
|
mon_text_read_isostat(rp, &ptr, ep);
|
||||||
|
mon_text_read_isodesc(rp, &ptr, ep);
|
||||||
|
} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
|
||||||
|
mon_text_read_intstat(rp, &ptr, ep);
|
||||||
|
} else {
|
||||||
|
mon_text_read_statset(rp, &ptr, ep);
|
||||||
|
}
|
||||||
|
ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
|
||||||
|
" %d", ep->length);
|
||||||
|
mon_text_read_data(rp, &ptr, ep);
|
||||||
|
|
||||||
|
rp->printf_togo = ptr.cnt;
|
||||||
|
rp->printf_offset = 0;
|
||||||
|
|
||||||
|
kmem_cache_free(rp->e_slab, ep);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mon_text_copy_to_user(rp, buf, nbytes);
|
||||||
|
mutex_unlock(&rp->printf_lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
|
static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
|
||||||
|
|
|
@ -1756,6 +1756,7 @@ vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
int vbus;
|
int vbus;
|
||||||
u8 devctl;
|
u8 devctl;
|
||||||
|
|
||||||
|
pm_runtime_get_sync(dev);
|
||||||
spin_lock_irqsave(&musb->lock, flags);
|
spin_lock_irqsave(&musb->lock, flags);
|
||||||
val = musb->a_wait_bcon;
|
val = musb->a_wait_bcon;
|
||||||
vbus = musb_platform_get_vbus_status(musb);
|
vbus = musb_platform_get_vbus_status(musb);
|
||||||
|
@ -1769,6 +1770,7 @@ vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
vbus = 0;
|
vbus = 0;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&musb->lock, flags);
|
spin_unlock_irqrestore(&musb->lock, flags);
|
||||||
|
pm_runtime_put_sync(dev);
|
||||||
|
|
||||||
return sprintf(buf, "Vbus %s, timeout %lu msec\n",
|
return sprintf(buf, "Vbus %s, timeout %lu msec\n",
|
||||||
vbus ? "on" : "off", val);
|
vbus ? "on" : "off", val);
|
||||||
|
@ -2471,11 +2473,11 @@ static int musb_remove(struct platform_device *pdev)
|
||||||
musb_disable_interrupts(musb);
|
musb_disable_interrupts(musb);
|
||||||
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
||||||
spin_unlock_irqrestore(&musb->lock, flags);
|
spin_unlock_irqrestore(&musb->lock, flags);
|
||||||
|
musb_platform_exit(musb);
|
||||||
|
|
||||||
pm_runtime_dont_use_autosuspend(musb->controller);
|
pm_runtime_dont_use_autosuspend(musb->controller);
|
||||||
pm_runtime_put_sync(musb->controller);
|
pm_runtime_put_sync(musb->controller);
|
||||||
pm_runtime_disable(musb->controller);
|
pm_runtime_disable(musb->controller);
|
||||||
musb_platform_exit(musb);
|
|
||||||
musb_phy_callback = NULL;
|
musb_phy_callback = NULL;
|
||||||
if (musb->dma_controller)
|
if (musb->dma_controller)
|
||||||
musb_dma_controller_destroy(musb->dma_controller);
|
musb_dma_controller_destroy(musb->dma_controller);
|
||||||
|
|
|
@ -1076,7 +1076,7 @@ static int uas_post_reset(struct usb_interface *intf)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = uas_configure_endpoints(devinfo);
|
err = uas_configure_endpoints(devinfo);
|
||||||
if (err && err != ENODEV)
|
if (err && err != -ENODEV)
|
||||||
shost_printk(KERN_ERR, shost,
|
shost_printk(KERN_ERR, shost,
|
||||||
"%s: alloc streams error %d after reset",
|
"%s: alloc streams error %d after reset",
|
||||||
__func__, err);
|
__func__, err);
|
||||||
|
|
|
@ -2118,6 +2118,13 @@ UNUSUAL_DEV( 0x152d, 0x2566, 0x0114, 0x0114,
|
||||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||||
US_FL_BROKEN_FUA ),
|
US_FL_BROKEN_FUA ),
|
||||||
|
|
||||||
|
/* Reported by Teijo Kinnunen <teijo.kinnunen@code-q.fi> */
|
||||||
|
UNUSUAL_DEV( 0x152d, 0x2567, 0x0117, 0x0117,
|
||||||
|
"JMicron",
|
||||||
|
"USB to ATA/ATAPI Bridge",
|
||||||
|
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||||
|
US_FL_BROKEN_FUA ),
|
||||||
|
|
||||||
/* Reported-by George Cherian <george.cherian@cavium.com> */
|
/* Reported-by George Cherian <george.cherian@cavium.com> */
|
||||||
UNUSUAL_DEV(0x152d, 0x9561, 0x0000, 0x9999,
|
UNUSUAL_DEV(0x152d, 0x9561, 0x0000, 0x9999,
|
||||||
"JMicron",
|
"JMicron",
|
||||||
|
|
|
@ -1857,7 +1857,8 @@ static int fusb302_probe(struct i2c_client *client,
|
||||||
chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev);
|
chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev);
|
||||||
if (IS_ERR(chip->tcpm_port)) {
|
if (IS_ERR(chip->tcpm_port)) {
|
||||||
ret = PTR_ERR(chip->tcpm_port);
|
ret = PTR_ERR(chip->tcpm_port);
|
||||||
dev_err(dev, "cannot register tcpm port, ret=%d", ret);
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(dev, "cannot register tcpm port, ret=%d", ret);
|
||||||
goto destroy_workqueue;
|
goto destroy_workqueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,9 +252,6 @@ struct tcpm_port {
|
||||||
unsigned int nr_src_pdo;
|
unsigned int nr_src_pdo;
|
||||||
u32 snk_pdo[PDO_MAX_OBJECTS];
|
u32 snk_pdo[PDO_MAX_OBJECTS];
|
||||||
unsigned int nr_snk_pdo;
|
unsigned int nr_snk_pdo;
|
||||||
unsigned int nr_fixed; /* number of fixed sink PDOs */
|
|
||||||
unsigned int nr_var; /* number of variable sink PDOs */
|
|
||||||
unsigned int nr_batt; /* number of battery sink PDOs */
|
|
||||||
u32 snk_vdo[VDO_MAX_OBJECTS];
|
u32 snk_vdo[VDO_MAX_OBJECTS];
|
||||||
unsigned int nr_snk_vdo;
|
unsigned int nr_snk_vdo;
|
||||||
|
|
||||||
|
@ -1770,90 +1767,39 @@ static int tcpm_pd_check_request(struct tcpm_port *port)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define min_power(x, y) min(pdo_max_power(x), pdo_max_power(y))
|
static int tcpm_pd_select_pdo(struct tcpm_port *port)
|
||||||
#define min_current(x, y) min(pdo_max_current(x), pdo_max_current(y))
|
|
||||||
|
|
||||||
static int tcpm_pd_select_pdo(struct tcpm_port *port, int *sink_pdo,
|
|
||||||
int *src_pdo)
|
|
||||||
{
|
{
|
||||||
unsigned int i, j, max_mw = 0, max_mv = 0, mw = 0, mv = 0, ma = 0;
|
unsigned int i, max_mw = 0, max_mv = 0;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Select the source PDO providing the most power which has a
|
* Select the source PDO providing the most power while staying within
|
||||||
* matchig sink cap.
|
* the board's voltage limits. Prefer PDO providing exp
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < port->nr_source_caps; i++) {
|
for (i = 0; i < port->nr_source_caps; i++) {
|
||||||
u32 pdo = port->source_caps[i];
|
u32 pdo = port->source_caps[i];
|
||||||
enum pd_pdo_type type = pdo_type(pdo);
|
enum pd_pdo_type type = pdo_type(pdo);
|
||||||
|
unsigned int mv, ma, mw;
|
||||||
|
|
||||||
if (type == PDO_TYPE_FIXED) {
|
if (type == PDO_TYPE_FIXED)
|
||||||
for (j = 0; j < port->nr_fixed; j++) {
|
mv = pdo_fixed_voltage(pdo);
|
||||||
if (pdo_fixed_voltage(pdo) ==
|
else
|
||||||
pdo_fixed_voltage(port->snk_pdo[j])) {
|
mv = pdo_min_voltage(pdo);
|
||||||
ma = min_current(pdo, port->snk_pdo[j]);
|
|
||||||
mv = pdo_fixed_voltage(pdo);
|
if (type == PDO_TYPE_BATT) {
|
||||||
mw = ma * mv / 1000;
|
mw = pdo_max_power(pdo);
|
||||||
if (mw > max_mw ||
|
} else {
|
||||||
(mw == max_mw && mv > max_mv)) {
|
ma = min(pdo_max_current(pdo),
|
||||||
ret = 0;
|
port->max_snk_ma);
|
||||||
*src_pdo = i;
|
mw = ma * mv / 1000;
|
||||||
*sink_pdo = j;
|
}
|
||||||
max_mw = mw;
|
|
||||||
max_mv = mv;
|
/* Perfer higher voltages if available */
|
||||||
}
|
if ((mw > max_mw || (mw == max_mw && mv > max_mv)) &&
|
||||||
/* There could only be one fixed pdo
|
mv <= port->max_snk_mv) {
|
||||||
* at a specific voltage level.
|
ret = i;
|
||||||
* So breaking here.
|
max_mw = mw;
|
||||||
*/
|
max_mv = mv;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (type == PDO_TYPE_BATT) {
|
|
||||||
for (j = port->nr_fixed;
|
|
||||||
j < port->nr_fixed +
|
|
||||||
port->nr_batt;
|
|
||||||
j++) {
|
|
||||||
if (pdo_min_voltage(pdo) >=
|
|
||||||
pdo_min_voltage(port->snk_pdo[j]) &&
|
|
||||||
pdo_max_voltage(pdo) <=
|
|
||||||
pdo_max_voltage(port->snk_pdo[j])) {
|
|
||||||
mw = min_power(pdo, port->snk_pdo[j]);
|
|
||||||
mv = pdo_min_voltage(pdo);
|
|
||||||
if (mw > max_mw ||
|
|
||||||
(mw == max_mw && mv > max_mv)) {
|
|
||||||
ret = 0;
|
|
||||||
*src_pdo = i;
|
|
||||||
*sink_pdo = j;
|
|
||||||
max_mw = mw;
|
|
||||||
max_mv = mv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (type == PDO_TYPE_VAR) {
|
|
||||||
for (j = port->nr_fixed +
|
|
||||||
port->nr_batt;
|
|
||||||
j < port->nr_fixed +
|
|
||||||
port->nr_batt +
|
|
||||||
port->nr_var;
|
|
||||||
j++) {
|
|
||||||
if (pdo_min_voltage(pdo) >=
|
|
||||||
pdo_min_voltage(port->snk_pdo[j]) &&
|
|
||||||
pdo_max_voltage(pdo) <=
|
|
||||||
pdo_max_voltage(port->snk_pdo[j])) {
|
|
||||||
ma = min_current(pdo, port->snk_pdo[j]);
|
|
||||||
mv = pdo_min_voltage(pdo);
|
|
||||||
mw = ma * mv / 1000;
|
|
||||||
if (mw > max_mw ||
|
|
||||||
(mw == max_mw && mv > max_mv)) {
|
|
||||||
ret = 0;
|
|
||||||
*src_pdo = i;
|
|
||||||
*sink_pdo = j;
|
|
||||||
max_mw = mw;
|
|
||||||
max_mv = mv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1865,14 +1811,13 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo)
|
||||||
unsigned int mv, ma, mw, flags;
|
unsigned int mv, ma, mw, flags;
|
||||||
unsigned int max_ma, max_mw;
|
unsigned int max_ma, max_mw;
|
||||||
enum pd_pdo_type type;
|
enum pd_pdo_type type;
|
||||||
int src_pdo_index, snk_pdo_index;
|
int index;
|
||||||
u32 pdo, matching_snk_pdo;
|
u32 pdo;
|
||||||
|
|
||||||
if (tcpm_pd_select_pdo(port, &snk_pdo_index, &src_pdo_index) < 0)
|
index = tcpm_pd_select_pdo(port);
|
||||||
|
if (index < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
pdo = port->source_caps[index];
|
||||||
pdo = port->source_caps[src_pdo_index];
|
|
||||||
matching_snk_pdo = port->snk_pdo[snk_pdo_index];
|
|
||||||
type = pdo_type(pdo);
|
type = pdo_type(pdo);
|
||||||
|
|
||||||
if (type == PDO_TYPE_FIXED)
|
if (type == PDO_TYPE_FIXED)
|
||||||
|
@ -1880,28 +1825,26 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo)
|
||||||
else
|
else
|
||||||
mv = pdo_min_voltage(pdo);
|
mv = pdo_min_voltage(pdo);
|
||||||
|
|
||||||
/* Select maximum available current within the sink pdo's limit */
|
/* Select maximum available current within the board's power limit */
|
||||||
if (type == PDO_TYPE_BATT) {
|
if (type == PDO_TYPE_BATT) {
|
||||||
mw = min_power(pdo, matching_snk_pdo);
|
mw = pdo_max_power(pdo);
|
||||||
ma = 1000 * mw / mv;
|
ma = 1000 * min(mw, port->max_snk_mw) / mv;
|
||||||
} else {
|
} else {
|
||||||
ma = min_current(pdo, matching_snk_pdo);
|
ma = min(pdo_max_current(pdo),
|
||||||
mw = ma * mv / 1000;
|
1000 * port->max_snk_mw / mv);
|
||||||
}
|
}
|
||||||
|
ma = min(ma, port->max_snk_ma);
|
||||||
|
|
||||||
flags = RDO_USB_COMM | RDO_NO_SUSPEND;
|
flags = RDO_USB_COMM | RDO_NO_SUSPEND;
|
||||||
|
|
||||||
/* Set mismatch bit if offered power is less than operating power */
|
/* Set mismatch bit if offered power is less than operating power */
|
||||||
|
mw = ma * mv / 1000;
|
||||||
max_ma = ma;
|
max_ma = ma;
|
||||||
max_mw = mw;
|
max_mw = mw;
|
||||||
if (mw < port->operating_snk_mw) {
|
if (mw < port->operating_snk_mw) {
|
||||||
flags |= RDO_CAP_MISMATCH;
|
flags |= RDO_CAP_MISMATCH;
|
||||||
if (type == PDO_TYPE_BATT &&
|
max_mw = port->operating_snk_mw;
|
||||||
(pdo_max_power(matching_snk_pdo) > pdo_max_power(pdo)))
|
max_ma = max_mw * 1000 / mv;
|
||||||
max_mw = pdo_max_power(matching_snk_pdo);
|
|
||||||
else if (pdo_max_current(matching_snk_pdo) >
|
|
||||||
pdo_max_current(pdo))
|
|
||||||
max_ma = pdo_max_current(matching_snk_pdo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpm_log(port, "cc=%d cc1=%d cc2=%d vbus=%d vconn=%s polarity=%d",
|
tcpm_log(port, "cc=%d cc1=%d cc2=%d vbus=%d vconn=%s polarity=%d",
|
||||||
|
@ -1910,16 +1853,16 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo)
|
||||||
port->polarity);
|
port->polarity);
|
||||||
|
|
||||||
if (type == PDO_TYPE_BATT) {
|
if (type == PDO_TYPE_BATT) {
|
||||||
*rdo = RDO_BATT(src_pdo_index + 1, mw, max_mw, flags);
|
*rdo = RDO_BATT(index + 1, mw, max_mw, flags);
|
||||||
|
|
||||||
tcpm_log(port, "Requesting PDO %d: %u mV, %u mW%s",
|
tcpm_log(port, "Requesting PDO %d: %u mV, %u mW%s",
|
||||||
src_pdo_index, mv, mw,
|
index, mv, mw,
|
||||||
flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
|
flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
|
||||||
} else {
|
} else {
|
||||||
*rdo = RDO_FIXED(src_pdo_index + 1, ma, max_ma, flags);
|
*rdo = RDO_FIXED(index + 1, ma, max_ma, flags);
|
||||||
|
|
||||||
tcpm_log(port, "Requesting PDO %d: %u mV, %u mA%s",
|
tcpm_log(port, "Requesting PDO %d: %u mV, %u mA%s",
|
||||||
src_pdo_index, mv, ma,
|
index, mv, ma,
|
||||||
flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
|
flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3650,19 +3593,6 @@ int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities);
|
EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities);
|
||||||
|
|
||||||
static int nr_type_pdos(const u32 *pdo, unsigned int nr_pdo,
|
|
||||||
enum pd_pdo_type type)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < nr_pdo; i++) {
|
|
||||||
if (pdo_type(pdo[i]) == type)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
|
struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
|
||||||
{
|
{
|
||||||
struct tcpm_port *port;
|
struct tcpm_port *port;
|
||||||
|
@ -3708,15 +3638,6 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
|
||||||
tcpc->config->nr_src_pdo);
|
tcpc->config->nr_src_pdo);
|
||||||
port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo,
|
port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo,
|
||||||
tcpc->config->nr_snk_pdo);
|
tcpc->config->nr_snk_pdo);
|
||||||
port->nr_fixed = nr_type_pdos(port->snk_pdo,
|
|
||||||
port->nr_snk_pdo,
|
|
||||||
PDO_TYPE_FIXED);
|
|
||||||
port->nr_var = nr_type_pdos(port->snk_pdo,
|
|
||||||
port->nr_snk_pdo,
|
|
||||||
PDO_TYPE_VAR);
|
|
||||||
port->nr_batt = nr_type_pdos(port->snk_pdo,
|
|
||||||
port->nr_snk_pdo,
|
|
||||||
PDO_TYPE_BATT);
|
|
||||||
port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcpc->config->snk_vdo,
|
port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcpc->config->snk_vdo,
|
||||||
tcpc->config->nr_snk_vdo);
|
tcpc->config->nr_snk_vdo);
|
||||||
|
|
||||||
|
|
|
@ -105,10 +105,14 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!udc) {
|
||||||
|
dev_err(dev, "no device");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
spin_lock_irqsave(&udc->lock, flags);
|
spin_lock_irqsave(&udc->lock, flags);
|
||||||
/* Don't export what we don't have */
|
/* Don't export what we don't have */
|
||||||
if (!udc || !udc->driver || !udc->pullup) {
|
if (!udc->driver || !udc->pullup) {
|
||||||
dev_err(dev, "no device or gadget not bound");
|
dev_err(dev, "gadget not bound");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,4 +63,7 @@
|
||||||
*/
|
*/
|
||||||
#define USB_QUIRK_DISCONNECT_SUSPEND BIT(12)
|
#define USB_QUIRK_DISCONNECT_SUSPEND BIT(12)
|
||||||
|
|
||||||
|
/* Device needs a pause after every control message. */
|
||||||
|
#define USB_QUIRK_DELAY_CTRL_MSG BIT(13)
|
||||||
|
|
||||||
#endif /* __LINUX_USB_QUIRKS_H */
|
#endif /* __LINUX_USB_QUIRKS_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue