mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-04-13 09:59:31 +00:00
USB fixes for 6.14-rc6
Here are some small USB driver fixes for some reported issues for 6.14-rc6. These contain: - typec driver fixes - dwc3 driver fixes - xhci driver fixes - renesas controller fixes - gadget driver fixes - a new USB quirk added All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZ83RpQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ykjuwCgtiIGxLWcgV/ZjynWswrovKFX3akAnAh6kW1G +E7ta+MbasbGhI/Kp5pD =iCYy -----END PGP SIGNATURE----- Merge tag 'usb-6.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are some small USB driver fixes for some reported issues. These contain: - typec driver fixes - dwc3 driver fixes - xhci driver fixes - renesas controller fixes - gadget driver fixes - a new USB quirk added All of these have been in linux-next with no reported issues" * tag 'usb-6.14-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: usb: typec: ucsi: Fix NULL pointer access usb: quirks: Add DELAY_INIT and NO_LPM for Prolific Mass Storage Card Reader usb: xhci: Fix host controllers "dying" after suspend and resume usb: dwc3: Set SUSPENDENABLE soon after phy init usb: hub: lack of clearing xHC resources usb: renesas_usbhs: Flush the notify_hotplug_work usb: renesas_usbhs: Use devm_usb_get_phy() usb: renesas_usbhs: Call clk_put() usb: dwc3: gadget: Prevent irq storm when TH re-executes usb: gadget: Check bmAttributes only if configuration is valid xhci: Restrict USB4 tunnel detection for USB3 devices to Intel hosts usb: xhci: Enable the TRB overfetch quirk on VIA VL805 usb: gadget: Fix setting self-powered state on suspend usb: typec: ucsi: increase timeout for PPM reset operations acpi: typec: ucsi: Introduce a ->poll_cci method usb: typec: tcpci_rt1711h: Unmask alert interrupts to fix functionality usb: gadget: Set self-powered based on MaxPower and bmAttributes usb: gadget: u_ether: Set is_suspend flag if remote wakeup fails usb: atm: cxacru: fix a flaw in existing endpoint checks
This commit is contained in:
commit
0dc1f314f8
24 changed files with 189 additions and 83 deletions
|
@ -1131,7 +1131,10 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
|
|||
struct cxacru_data *instance;
|
||||
struct usb_device *usb_dev = interface_to_usbdev(intf);
|
||||
struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD];
|
||||
struct usb_endpoint_descriptor *in, *out;
|
||||
static const u8 ep_addrs[] = {
|
||||
CXACRU_EP_CMD + USB_DIR_IN,
|
||||
CXACRU_EP_CMD + USB_DIR_OUT,
|
||||
0};
|
||||
int ret;
|
||||
|
||||
/* instance init */
|
||||
|
@ -1179,13 +1182,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
|
|||
}
|
||||
|
||||
if (usb_endpoint_xfer_int(&cmd_ep->desc))
|
||||
ret = usb_find_common_endpoints(intf->cur_altsetting,
|
||||
NULL, NULL, &in, &out);
|
||||
ret = usb_check_int_endpoints(intf, ep_addrs);
|
||||
else
|
||||
ret = usb_find_common_endpoints(intf->cur_altsetting,
|
||||
&in, &out, NULL, NULL);
|
||||
ret = usb_check_bulk_endpoints(intf, ep_addrs);
|
||||
|
||||
if (ret) {
|
||||
if (!ret) {
|
||||
usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n");
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
|
|
|
@ -6065,6 +6065,36 @@ void usb_hub_cleanup(void)
|
|||
usb_deregister(&hub_driver);
|
||||
} /* usb_hub_cleanup() */
|
||||
|
||||
/**
|
||||
* hub_hc_release_resources - clear resources used by host controller
|
||||
* @udev: pointer to device being released
|
||||
*
|
||||
* Context: task context, might sleep
|
||||
*
|
||||
* Function releases the host controller resources in correct order before
|
||||
* making any operation on resuming usb device. The host controller resources
|
||||
* allocated for devices in tree should be released starting from the last
|
||||
* usb device in tree toward the root hub. This function is used only during
|
||||
* resuming device when usb device require reinitialization – that is, when
|
||||
* flag udev->reset_resume is set.
|
||||
*
|
||||
* This call is synchronous, and may not be used in an interrupt context.
|
||||
*/
|
||||
static void hub_hc_release_resources(struct usb_device *udev)
|
||||
{
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(udev);
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
int i;
|
||||
|
||||
/* Release up resources for all children before this device */
|
||||
for (i = 0; i < udev->maxchild; i++)
|
||||
if (hub->ports[i]->child)
|
||||
hub_hc_release_resources(hub->ports[i]->child);
|
||||
|
||||
if (hcd->driver->reset_device)
|
||||
hcd->driver->reset_device(hcd, udev);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_reset_and_verify_device - perform a USB port reset to reinitialize a device
|
||||
* @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
|
||||
|
@ -6129,6 +6159,9 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
|||
bos = udev->bos;
|
||||
udev->bos = NULL;
|
||||
|
||||
if (udev->reset_resume)
|
||||
hub_hc_release_resources(udev);
|
||||
|
||||
mutex_lock(hcd->address0_mutex);
|
||||
|
||||
for (i = 0; i < PORT_INIT_TRIES; ++i) {
|
||||
|
|
|
@ -341,6 +341,10 @@ static const struct usb_device_id usb_quirk_list[] = {
|
|||
{ USB_DEVICE(0x0638, 0x0a13), .driver_info =
|
||||
USB_QUIRK_STRING_FETCH_255 },
|
||||
|
||||
/* Prolific Single-LUN Mass Storage Card Reader */
|
||||
{ USB_DEVICE(0x067b, 0x2731), .driver_info = USB_QUIRK_DELAY_INIT |
|
||||
USB_QUIRK_NO_LPM },
|
||||
|
||||
/* Saitek Cyborg Gold Joystick */
|
||||
{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
|
||||
USB_QUIRK_CONFIG_INTF_STRINGS },
|
||||
|
|
|
@ -131,11 +131,24 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
|
||||
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
|
||||
{
|
||||
unsigned int hw_mode;
|
||||
u32 reg;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||
|
||||
/*
|
||||
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE and
|
||||
* GUSB2PHYCFG.SUSPHY should be cleared during mode switching,
|
||||
* and they can be set after core initialization.
|
||||
*/
|
||||
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
|
||||
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !ignore_susphy) {
|
||||
if (DWC3_GCTL_PRTCAP(reg) != mode)
|
||||
dwc3_enable_susphy(dwc, false);
|
||||
}
|
||||
|
||||
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
|
||||
reg |= DWC3_GCTL_PRTCAPDIR(mode);
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
|
@ -216,7 +229,7 @@ static void __dwc3_set_mode(struct work_struct *work)
|
|||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
dwc3_set_prtcap(dwc, desired_dr_role);
|
||||
dwc3_set_prtcap(dwc, desired_dr_role, false);
|
||||
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
|
@ -658,16 +671,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
|
|||
*/
|
||||
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
|
||||
|
||||
/*
|
||||
* Above DWC_usb3.0 1.94a, it is recommended to set
|
||||
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
|
||||
* So default value will be '0' when the core is reset. Application
|
||||
* needs to set it to '1' after the core initialization is completed.
|
||||
*
|
||||
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
|
||||
* cleared after power-on reset, and it can be set after core
|
||||
* initialization.
|
||||
*/
|
||||
/* Ensure the GUSB3PIPECTL.SUSPENDENABLE is cleared prior to phy init. */
|
||||
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
|
||||
|
||||
if (dwc->u2ss_inp3_quirk)
|
||||
|
@ -747,15 +751,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
|
|||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Above DWC_usb3.0 1.94a, it is recommended to set
|
||||
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
|
||||
* So default value will be '0' when the core is reset. Application
|
||||
* needs to set it to '1' after the core initialization is completed.
|
||||
*
|
||||
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
|
||||
* after power-on reset, and it can be set after core initialization.
|
||||
*/
|
||||
/* Ensure the GUSB2PHYCFG.SUSPHY is cleared prior to phy init. */
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
||||
if (dwc->dis_enblslpm_quirk)
|
||||
|
@ -830,6 +826,25 @@ static int dwc3_phy_init(struct dwc3 *dwc)
|
|||
goto err_exit_usb3_phy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Above DWC_usb3.0 1.94a, it is recommended to set
|
||||
* DWC3_GUSB3PIPECTL_SUSPHY and DWC3_GUSB2PHYCFG_SUSPHY to '0' during
|
||||
* coreConsultant configuration. So default value will be '0' when the
|
||||
* core is reset. Application needs to set it to '1' after the core
|
||||
* initialization is completed.
|
||||
*
|
||||
* Certain phy requires to be in P0 power state during initialization.
|
||||
* Make sure GUSB3PIPECTL.SUSPENDENABLE and GUSB2PHYCFG.SUSPHY are clear
|
||||
* prior to phy init to maintain in the P0 state.
|
||||
*
|
||||
* After phy initialization, some phy operations can only be executed
|
||||
* while in lower P states. Ensure GUSB3PIPECTL.SUSPENDENABLE and
|
||||
* GUSB2PHYCFG.SUSPHY are set soon after initialization to avoid
|
||||
* blocking phy ops.
|
||||
*/
|
||||
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
|
||||
dwc3_enable_susphy(dwc, true);
|
||||
|
||||
return 0;
|
||||
|
||||
err_exit_usb3_phy:
|
||||
|
@ -1588,7 +1603,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||
|
||||
switch (dwc->dr_mode) {
|
||||
case USB_DR_MODE_PERIPHERAL:
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, false);
|
||||
|
||||
if (dwc->usb2_phy)
|
||||
otg_set_vbus(dwc->usb2_phy->otg, false);
|
||||
|
@ -1600,7 +1615,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||
return dev_err_probe(dev, ret, "failed to initialize gadget\n");
|
||||
break;
|
||||
case USB_DR_MODE_HOST:
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, false);
|
||||
|
||||
if (dwc->usb2_phy)
|
||||
otg_set_vbus(dwc->usb2_phy->otg, true);
|
||||
|
@ -1645,7 +1660,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
|
|||
}
|
||||
|
||||
/* de-assert DRVVBUS for HOST and OTG mode */
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
|
||||
}
|
||||
|
||||
static void dwc3_get_software_properties(struct dwc3 *dwc)
|
||||
|
@ -1835,8 +1850,6 @@ static void dwc3_get_properties(struct dwc3 *dwc)
|
|||
dwc->tx_thr_num_pkt_prd = tx_thr_num_pkt_prd;
|
||||
dwc->tx_max_burst_prd = tx_max_burst_prd;
|
||||
|
||||
dwc->imod_interval = 0;
|
||||
|
||||
dwc->tx_fifo_resize_max_num = tx_fifo_resize_max_num;
|
||||
}
|
||||
|
||||
|
@ -1854,21 +1867,19 @@ static void dwc3_check_params(struct dwc3 *dwc)
|
|||
unsigned int hwparam_gen =
|
||||
DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3);
|
||||
|
||||
/* Check for proper value of imod_interval */
|
||||
if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
|
||||
dev_warn(dwc->dev, "Interrupt moderation not supported\n");
|
||||
dwc->imod_interval = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable IMOD for all supporting controllers.
|
||||
*
|
||||
* Particularly, DWC_usb3 v3.00a must enable this feature for
|
||||
* the following reason:
|
||||
*
|
||||
* Workaround for STAR 9000961433 which affects only version
|
||||
* 3.00a of the DWC_usb3 core. This prevents the controller
|
||||
* interrupt from being masked while handling events. IMOD
|
||||
* allows us to work around this issue. Enable it for the
|
||||
* affected version.
|
||||
*/
|
||||
if (!dwc->imod_interval &&
|
||||
DWC3_VER_IS(DWC3, 300A))
|
||||
if (dwc3_has_imod((dwc)))
|
||||
dwc->imod_interval = 1;
|
||||
|
||||
/* Check the maximum_speed parameter */
|
||||
|
@ -2457,7 +2468,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
|
||||
dwc3_gadget_resume(dwc);
|
||||
break;
|
||||
case DWC3_GCTL_PRTCAP_HOST:
|
||||
|
@ -2465,7 +2476,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
ret = dwc3_core_init_for_resume(dwc);
|
||||
if (ret)
|
||||
return ret;
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, true);
|
||||
break;
|
||||
}
|
||||
/* Restore GUSB2PHYCFG bits that were modified in suspend */
|
||||
|
@ -2494,7 +2505,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
dwc3_set_prtcap(dwc, dwc->current_dr_role);
|
||||
dwc3_set_prtcap(dwc, dwc->current_dr_role, true);
|
||||
|
||||
dwc3_otg_init(dwc);
|
||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
|
||||
|
|
|
@ -1558,7 +1558,7 @@ struct dwc3_gadget_ep_cmd_params {
|
|||
#define DWC3_HAS_OTG BIT(3)
|
||||
|
||||
/* prototypes */
|
||||
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
|
||||
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy);
|
||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
|
||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ void dwc3_otg_init(struct dwc3 *dwc)
|
|||
* block "Initialize GCTL for OTG operation".
|
||||
*/
|
||||
/* GCTL.PrtCapDir=2'b11 */
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
|
||||
/* GUSB2PHYCFG0.SusPHY=0 */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
|
@ -556,7 +556,7 @@ int dwc3_drd_init(struct dwc3 *dwc)
|
|||
|
||||
dwc3_drd_update(dwc);
|
||||
} else {
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
|
||||
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
|
||||
|
||||
/* use OTG block to get ID event */
|
||||
irq = dwc3_otg_get_irq(dwc);
|
||||
|
|
|
@ -4501,14 +4501,18 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
|
|||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
|
||||
DWC3_GEVNTSIZ_SIZE(evt->length));
|
||||
|
||||
evt->flags &= ~DWC3_EVENT_PENDING;
|
||||
/*
|
||||
* Add an explicit write memory barrier to make sure that the update of
|
||||
* clearing DWC3_EVENT_PENDING is observed in dwc3_check_event_buf()
|
||||
*/
|
||||
wmb();
|
||||
|
||||
if (dwc->imod_interval) {
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
|
||||
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
|
||||
}
|
||||
|
||||
/* Keep the clearing of DWC3_EVENT_PENDING at the end */
|
||||
evt->flags &= ~DWC3_EVENT_PENDING;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1050,10 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev,
|
|||
else
|
||||
usb_gadget_set_remote_wakeup(gadget, 0);
|
||||
done:
|
||||
if (power <= USB_SELF_POWER_VBUS_MAX_DRAW)
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
else
|
||||
if (power > USB_SELF_POWER_VBUS_MAX_DRAW ||
|
||||
(c && !(c->bmAttributes & USB_CONFIG_ATT_SELFPOWER)))
|
||||
usb_gadget_clear_selfpowered(gadget);
|
||||
else
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
|
||||
usb_gadget_vbus_draw(gadget, power);
|
||||
if (result >= 0 && cdev->delayed_status)
|
||||
|
@ -2615,7 +2616,10 @@ void composite_suspend(struct usb_gadget *gadget)
|
|||
|
||||
cdev->suspended = 1;
|
||||
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
if (cdev->config &&
|
||||
cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER)
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
|
||||
usb_gadget_vbus_draw(gadget, 2);
|
||||
}
|
||||
|
||||
|
@ -2649,8 +2653,11 @@ void composite_resume(struct usb_gadget *gadget)
|
|||
else
|
||||
maxpower = min(maxpower, 900U);
|
||||
|
||||
if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW)
|
||||
if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW ||
|
||||
!(cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER))
|
||||
usb_gadget_clear_selfpowered(gadget);
|
||||
else
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
|
||||
usb_gadget_vbus_draw(gadget, maxpower);
|
||||
} else {
|
||||
|
|
|
@ -1052,8 +1052,8 @@ void gether_suspend(struct gether *link)
|
|||
* There is a transfer in progress. So we trigger a remote
|
||||
* wakeup to inform the host.
|
||||
*/
|
||||
ether_wakeup_host(dev->port_usb);
|
||||
return;
|
||||
if (!ether_wakeup_host(dev->port_usb))
|
||||
return;
|
||||
}
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
link->is_suspend = true;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "xhci.h"
|
||||
#include "xhci-trace.h"
|
||||
|
@ -770,9 +771,16 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
|
|||
enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
|
||||
struct xhci_port *port)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
void __iomem *base;
|
||||
u32 offset;
|
||||
|
||||
/* Don't try and probe this capability for non-Intel hosts */
|
||||
hcd = xhci_to_hcd(xhci);
|
||||
if (!dev_is_pci(hcd->self.controller) ||
|
||||
to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
|
||||
return USB_LINK_UNKNOWN;
|
||||
|
||||
base = &xhci->cap_regs->hc_capbase;
|
||||
offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
|
||||
|
||||
|
|
|
@ -2437,7 +2437,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
* and our use of dma addresses in the trb_address_map radix tree needs
|
||||
* TRB_SEGMENT_SIZE alignment, so we pick the greater alignment need.
|
||||
*/
|
||||
if (xhci->quirks & XHCI_ZHAOXIN_TRB_FETCH)
|
||||
if (xhci->quirks & XHCI_TRB_OVERFETCH)
|
||||
/* Buggy HC prefetches beyond segment bounds - allocate dummy space at the end */
|
||||
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
|
||||
TRB_SEGMENT_SIZE * 2, TRB_SEGMENT_SIZE * 2, xhci->page_size * 2);
|
||||
else
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
#define PCI_DEVICE_ID_ETRON_EJ168 0x7023
|
||||
#define PCI_DEVICE_ID_ETRON_EJ188 0x7052
|
||||
|
||||
#define PCI_DEVICE_ID_VIA_VL805 0x3483
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
|
||||
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1
|
||||
|
@ -418,8 +420,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
|||
pdev->device == 0x3432)
|
||||
xhci->quirks |= XHCI_BROKEN_STREAMS;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483)
|
||||
if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) {
|
||||
xhci->quirks |= XHCI_LPM_SUPPORT;
|
||||
xhci->quirks |= XHCI_TRB_OVERFETCH;
|
||||
}
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
|
||||
pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI) {
|
||||
|
@ -467,11 +471,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
|
|||
|
||||
if (pdev->device == 0x9202) {
|
||||
xhci->quirks |= XHCI_RESET_ON_RESUME;
|
||||
xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
|
||||
xhci->quirks |= XHCI_TRB_OVERFETCH;
|
||||
}
|
||||
|
||||
if (pdev->device == 0x9203)
|
||||
xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
|
||||
xhci->quirks |= XHCI_TRB_OVERFETCH;
|
||||
}
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_CDNS &&
|
||||
|
|
|
@ -780,8 +780,12 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
|
|||
struct xhci_segment *seg;
|
||||
|
||||
ring = xhci->cmd_ring;
|
||||
xhci_for_each_ring_seg(ring->first_seg, seg)
|
||||
xhci_for_each_ring_seg(ring->first_seg, seg) {
|
||||
/* erase all TRBs before the link */
|
||||
memset(seg->trbs, 0, sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1));
|
||||
/* clear link cycle bit */
|
||||
seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= cpu_to_le32(~TRB_CYCLE);
|
||||
}
|
||||
|
||||
xhci_initialize_ring_info(ring);
|
||||
/*
|
||||
|
|
|
@ -1632,7 +1632,7 @@ struct xhci_hcd {
|
|||
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42)
|
||||
#define XHCI_SUSPEND_RESUME_CLKS BIT_ULL(43)
|
||||
#define XHCI_RESET_TO_DEFAULT BIT_ULL(44)
|
||||
#define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45)
|
||||
#define XHCI_TRB_OVERFETCH BIT_ULL(45)
|
||||
#define XHCI_ZHAOXIN_HOST BIT_ULL(46)
|
||||
#define XHCI_WRITE_64_HI_LO BIT_ULL(47)
|
||||
#define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
|
||||
|
|
|
@ -312,8 +312,10 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv)
|
|||
priv->clks[1] = of_clk_get(dev_of_node(dev), 1);
|
||||
if (PTR_ERR(priv->clks[1]) == -ENOENT)
|
||||
priv->clks[1] = NULL;
|
||||
else if (IS_ERR(priv->clks[1]))
|
||||
else if (IS_ERR(priv->clks[1])) {
|
||||
clk_put(priv->clks[0]);
|
||||
return PTR_ERR(priv->clks[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -779,6 +781,8 @@ static void usbhs_remove(struct platform_device *pdev)
|
|||
|
||||
dev_dbg(&pdev->dev, "usb remove\n");
|
||||
|
||||
flush_delayed_work(&priv->notify_hotplug_work);
|
||||
|
||||
/* power off */
|
||||
if (!usbhs_get_dparam(priv, runtime_pwctrl))
|
||||
usbhsc_power_ctrl(priv, 0);
|
||||
|
|
|
@ -1094,7 +1094,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
|
|||
goto usbhs_mod_gadget_probe_err_gpriv;
|
||||
}
|
||||
|
||||
gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);
|
||||
gpriv->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_UNDEFINED);
|
||||
dev_info(dev, "%stransceiver found\n",
|
||||
!IS_ERR(gpriv->transceiver) ? "" : "no ");
|
||||
|
||||
|
|
|
@ -334,6 +334,11 @@ static int rt1711h_probe(struct i2c_client *client)
|
|||
{
|
||||
int ret;
|
||||
struct rt1711h_chip *chip;
|
||||
const u16 alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED |
|
||||
TCPC_ALERT_TX_FAILED | TCPC_ALERT_RX_HARD_RST |
|
||||
TCPC_ALERT_RX_STATUS | TCPC_ALERT_POWER_STATUS |
|
||||
TCPC_ALERT_CC_STATUS | TCPC_ALERT_RX_BUF_OVF |
|
||||
TCPC_ALERT_FAULT;
|
||||
|
||||
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
|
@ -382,6 +387,12 @@ static int rt1711h_probe(struct i2c_client *client)
|
|||
dev_name(chip->dev), chip);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable alert interrupts */
|
||||
ret = rt1711h_write16(chip, TCPC_ALERT_MASK, alert_mask);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
enable_irq_wake(client->irq);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
* difficult to estimate the time it takes for the system to process the command
|
||||
* before it is actually passed to the PPM.
|
||||
*/
|
||||
#define UCSI_TIMEOUT_MS 5000
|
||||
#define UCSI_TIMEOUT_MS 10000
|
||||
|
||||
/*
|
||||
* UCSI_SWAP_TIMEOUT_MS - Timeout for role swap requests
|
||||
|
@ -1346,7 +1346,7 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
|
|||
|
||||
mutex_lock(&ucsi->ppm_lock);
|
||||
|
||||
ret = ucsi->ops->read_cci(ucsi, &cci);
|
||||
ret = ucsi->ops->poll_cci(ucsi, &cci);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -1364,7 +1364,7 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
|
|||
|
||||
tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
|
||||
do {
|
||||
ret = ucsi->ops->read_cci(ucsi, &cci);
|
||||
ret = ucsi->ops->poll_cci(ucsi, &cci);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (cci & UCSI_CCI_COMMAND_COMPLETE)
|
||||
|
@ -1393,7 +1393,7 @@ static int ucsi_reset_ppm(struct ucsi *ucsi)
|
|||
/* Give the PPM time to process a reset before reading CCI */
|
||||
msleep(20);
|
||||
|
||||
ret = ucsi->ops->read_cci(ucsi, &cci);
|
||||
ret = ucsi->ops->poll_cci(ucsi, &cci);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@ -1825,11 +1825,11 @@ static int ucsi_init(struct ucsi *ucsi)
|
|||
|
||||
err_unregister:
|
||||
for (con = connector; con->port; con++) {
|
||||
if (con->wq)
|
||||
destroy_workqueue(con->wq);
|
||||
ucsi_unregister_partner(con);
|
||||
ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON);
|
||||
ucsi_unregister_port_psy(con);
|
||||
if (con->wq)
|
||||
destroy_workqueue(con->wq);
|
||||
|
||||
usb_power_delivery_unregister_capabilities(con->port_sink_caps);
|
||||
con->port_sink_caps = NULL;
|
||||
|
@ -1929,8 +1929,8 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops)
|
|||
struct ucsi *ucsi;
|
||||
|
||||
if (!ops ||
|
||||
!ops->read_version || !ops->read_cci || !ops->read_message_in ||
|
||||
!ops->sync_control || !ops->async_control)
|
||||
!ops->read_version || !ops->read_cci || !ops->poll_cci ||
|
||||
!ops->read_message_in || !ops->sync_control || !ops->async_control)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL);
|
||||
|
@ -2013,10 +2013,6 @@ void ucsi_unregister(struct ucsi *ucsi)
|
|||
|
||||
for (i = 0; i < ucsi->cap.num_connectors; i++) {
|
||||
cancel_work_sync(&ucsi->connector[i].work);
|
||||
ucsi_unregister_partner(&ucsi->connector[i]);
|
||||
ucsi_unregister_altmodes(&ucsi->connector[i],
|
||||
UCSI_RECIPIENT_CON);
|
||||
ucsi_unregister_port_psy(&ucsi->connector[i]);
|
||||
|
||||
if (ucsi->connector[i].wq) {
|
||||
struct ucsi_work *uwork;
|
||||
|
@ -2032,6 +2028,11 @@ void ucsi_unregister(struct ucsi *ucsi)
|
|||
destroy_workqueue(ucsi->connector[i].wq);
|
||||
}
|
||||
|
||||
ucsi_unregister_partner(&ucsi->connector[i]);
|
||||
ucsi_unregister_altmodes(&ucsi->connector[i],
|
||||
UCSI_RECIPIENT_CON);
|
||||
ucsi_unregister_port_psy(&ucsi->connector[i]);
|
||||
|
||||
usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_sink_caps);
|
||||
ucsi->connector[i].port_sink_caps = NULL;
|
||||
usb_power_delivery_unregister_capabilities(ucsi->connector[i].port_source_caps);
|
||||
|
|
|
@ -62,6 +62,7 @@ struct dentry;
|
|||
* struct ucsi_operations - UCSI I/O operations
|
||||
* @read_version: Read implemented UCSI version
|
||||
* @read_cci: Read CCI register
|
||||
* @poll_cci: Read CCI register while polling with notifications disabled
|
||||
* @read_message_in: Read message data from UCSI
|
||||
* @sync_control: Blocking control operation
|
||||
* @async_control: Non-blocking control operation
|
||||
|
@ -76,6 +77,7 @@ struct dentry;
|
|||
struct ucsi_operations {
|
||||
int (*read_version)(struct ucsi *ucsi, u16 *version);
|
||||
int (*read_cci)(struct ucsi *ucsi, u32 *cci);
|
||||
int (*poll_cci)(struct ucsi *ucsi, u32 *cci);
|
||||
int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len);
|
||||
int (*sync_control)(struct ucsi *ucsi, u64 command);
|
||||
int (*async_control)(struct ucsi *ucsi, u64 command);
|
||||
|
|
|
@ -59,19 +59,24 @@ static int ucsi_acpi_read_version(struct ucsi *ucsi, u16 *version)
|
|||
static int ucsi_acpi_read_cci(struct ucsi *ucsi, u32 *cci)
|
||||
{
|
||||
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||
int ret;
|
||||
|
||||
if (UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) {
|
||||
ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(cci, ua->base + UCSI_CCI, sizeof(*cci));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ucsi_acpi_poll_cci(struct ucsi *ucsi, u32 *cci)
|
||||
{
|
||||
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||
int ret;
|
||||
|
||||
ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ucsi_acpi_read_cci(ucsi, cci);
|
||||
}
|
||||
|
||||
static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_len)
|
||||
{
|
||||
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||
|
@ -94,6 +99,7 @@ static int ucsi_acpi_async_control(struct ucsi *ucsi, u64 command)
|
|||
static const struct ucsi_operations ucsi_acpi_ops = {
|
||||
.read_version = ucsi_acpi_read_version,
|
||||
.read_cci = ucsi_acpi_read_cci,
|
||||
.poll_cci = ucsi_acpi_poll_cci,
|
||||
.read_message_in = ucsi_acpi_read_message_in,
|
||||
.sync_control = ucsi_sync_control_common,
|
||||
.async_control = ucsi_acpi_async_control
|
||||
|
@ -142,6 +148,7 @@ static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command)
|
|||
static const struct ucsi_operations ucsi_gram_ops = {
|
||||
.read_version = ucsi_acpi_read_version,
|
||||
.read_cci = ucsi_acpi_read_cci,
|
||||
.poll_cci = ucsi_acpi_poll_cci,
|
||||
.read_message_in = ucsi_gram_read_message_in,
|
||||
.sync_control = ucsi_gram_sync_control,
|
||||
.async_control = ucsi_acpi_async_control
|
||||
|
|
|
@ -664,6 +664,7 @@ err_put:
|
|||
static const struct ucsi_operations ucsi_ccg_ops = {
|
||||
.read_version = ucsi_ccg_read_version,
|
||||
.read_cci = ucsi_ccg_read_cci,
|
||||
.poll_cci = ucsi_ccg_read_cci,
|
||||
.read_message_in = ucsi_ccg_read_message_in,
|
||||
.sync_control = ucsi_ccg_sync_control,
|
||||
.async_control = ucsi_ccg_async_control,
|
||||
|
|
|
@ -206,6 +206,7 @@ static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con)
|
|||
static const struct ucsi_operations pmic_glink_ucsi_ops = {
|
||||
.read_version = pmic_glink_ucsi_read_version,
|
||||
.read_cci = pmic_glink_ucsi_read_cci,
|
||||
.poll_cci = pmic_glink_ucsi_read_cci,
|
||||
.read_message_in = pmic_glink_ucsi_read_message_in,
|
||||
.sync_control = ucsi_sync_control_common,
|
||||
.async_control = pmic_glink_ucsi_async_control,
|
||||
|
|
|
@ -424,6 +424,7 @@ static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data)
|
|||
static const struct ucsi_operations ucsi_stm32g0_ops = {
|
||||
.read_version = ucsi_stm32g0_read_version,
|
||||
.read_cci = ucsi_stm32g0_read_cci,
|
||||
.poll_cci = ucsi_stm32g0_read_cci,
|
||||
.read_message_in = ucsi_stm32g0_read_message_in,
|
||||
.sync_control = ucsi_sync_control_common,
|
||||
.async_control = ucsi_stm32g0_async_control,
|
||||
|
|
|
@ -74,6 +74,7 @@ static int yoga_c630_ucsi_async_control(struct ucsi *ucsi, u64 command)
|
|||
static const struct ucsi_operations yoga_c630_ucsi_ops = {
|
||||
.read_version = yoga_c630_ucsi_read_version,
|
||||
.read_cci = yoga_c630_ucsi_read_cci,
|
||||
.poll_cci = yoga_c630_ucsi_read_cci,
|
||||
.read_message_in = yoga_c630_ucsi_read_message_in,
|
||||
.sync_control = ucsi_sync_control_common,
|
||||
.async_control = yoga_c630_ucsi_async_control,
|
||||
|
|
Loading…
Add table
Reference in a new issue