USB/Thunderbolt fixes for 6.6-rc6
Here are some USB and Thunderbolt driver fixes for 6.6-rc6 to resolve a number of small reported issues. Included in here are: - thunderbolt driver fixes - xhci driver fixes - cdns3 driver fixes - musb driver fixes - a number of typec driver fixes - a few other small driver fixes All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZSwElQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylx7ACgthY1JVY+YL61s2CBKgSdVJ7eAJUAnjnFwSy4 KTcgnEAnFlm/xpfVgHwA =2xN2 -----END PGP SIGNATURE----- Merge tag 'usb-6.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB / Thunderbolt fixes from Greg KH: "Here are some USB and Thunderbolt driver fixes for 6.6-rc6 to resolve a number of small reported issues. Included in here are: - thunderbolt driver fixes - xhci driver fixes - cdns3 driver fixes - musb driver fixes - a number of typec driver fixes - a few other small driver fixes All of these have been in linux-next with no reported issues" * tag 'usb-6.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (22 commits) usb: typec: ucsi: Use GET_CAPABILITY attributes data to set power supply scope usb: typec: ucsi: Fix missing link removal usb: typec: altmodes/displayport: Signal hpd low when exiting mode xhci: Preserve RsvdP bits in ERSTBA register correctly xhci: Clear EHB bit only at end of interrupt handler xhci: track port suspend state correctly in unsuccessful resume cases usb: xhci: xhci-ring: Use sysdev for mapping bounce buffer usb: typec: ucsi: Clear EVENT_PENDING bit if ucsi_send_command fails usb: misc: onboard_hub: add support for Microchip USB2412 USB 2.0 hub usb: gadget: udc-xilinx: replace memcpy with memcpy_toio usb: cdns3: Modify the return value of cdns_set_active () to void when CONFIG_PM_SLEEP is disabled usb: dwc3: Soft reset phy on probe for host usb: hub: Guard against accesses to uninitialized BOS descriptors usb: typec: qcom: Update the logic of regulator enable and disable usb: gadget: ncm: Handle decoding of multiple NTB's in unwrap call usb: musb: Get the musb_qh poniter after musb_giveback usb: musb: Modify the "HWVers" register address usb: cdnsp: Fixes issue with dequeuing not queued requests thunderbolt: Restart XDomain discovery handshake after failure thunderbolt: Correct TMU mode initialization from hardware ...
This commit is contained in:
commit
11d3f72613
@ -41,6 +41,7 @@
|
||||
#define PHY_PORT_CS1_LINK_STATE_SHIFT 26
|
||||
|
||||
#define ICM_TIMEOUT 5000 /* ms */
|
||||
#define ICM_RETRIES 3
|
||||
#define ICM_APPROVE_TIMEOUT 10000 /* ms */
|
||||
#define ICM_MAX_LINK 4
|
||||
|
||||
@ -296,10 +297,9 @@ static bool icm_copy(struct tb_cfg_request *req, const struct ctl_pkg *pkg)
|
||||
|
||||
static int icm_request(struct tb *tb, const void *request, size_t request_size,
|
||||
void *response, size_t response_size, size_t npackets,
|
||||
unsigned int timeout_msec)
|
||||
int retries, unsigned int timeout_msec)
|
||||
{
|
||||
struct icm *icm = tb_priv(tb);
|
||||
int retries = 3;
|
||||
|
||||
do {
|
||||
struct tb_cfg_request *req;
|
||||
@ -410,7 +410,7 @@ static int icm_fr_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = icm_request(tb, &request, sizeof(request), switches,
|
||||
sizeof(*switches), npackets, ICM_TIMEOUT);
|
||||
sizeof(*switches), npackets, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
@ -463,7 +463,7 @@ icm_fr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -488,7 +488,7 @@ static int icm_fr_approve_switch(struct tb *tb, struct tb_switch *sw)
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
/* Use larger timeout as establishing tunnels can take some time */
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_APPROVE_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_APPROVE_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -515,7 +515,7 @@ static int icm_fr_add_switch_key(struct tb *tb, struct tb_switch *sw)
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -543,7 +543,7 @@ static int icm_fr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -577,7 +577,7 @@ static int icm_fr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1020,7 +1020,7 @@ icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, 20000);
|
||||
1, 10, 2000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1053,7 +1053,7 @@ static int icm_tr_approve_switch(struct tb *tb, struct tb_switch *sw)
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_APPROVE_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_APPROVE_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1081,7 +1081,7 @@ static int icm_tr_add_switch_key(struct tb *tb, struct tb_switch *sw)
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1110,7 +1110,7 @@ static int icm_tr_challenge_switch_key(struct tb *tb, struct tb_switch *sw,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1144,7 +1144,7 @@ static int icm_tr_approve_xdomain_paths(struct tb *tb, struct tb_xdomain *xd,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1170,7 +1170,7 @@ static int icm_tr_xdomain_tear_down(struct tb *tb, struct tb_xdomain *xd,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1496,7 +1496,7 @@ icm_ar_driver_ready(struct tb *tb, enum tb_security_level *security_level,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1522,7 +1522,7 @@ static int icm_ar_get_route(struct tb *tb, u8 link, u8 depth, u64 *route)
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1543,7 +1543,7 @@ static int icm_ar_get_boot_acl(struct tb *tb, uuid_t *uuids, size_t nuuids)
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1604,7 +1604,7 @@ static int icm_ar_set_boot_acl(struct tb *tb, const uuid_t *uuids,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1626,7 +1626,7 @@ icm_icl_driver_ready(struct tb *tb, enum tb_security_level *security_level,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, 20000);
|
||||
1, ICM_RETRIES, 20000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -2298,7 +2298,7 @@ static int icm_usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata,
|
||||
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
|
||||
1, ICM_TIMEOUT);
|
||||
1, ICM_RETRIES, ICM_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -2725,6 +2725,13 @@ int tb_switch_lane_bonding_enable(struct tb_switch *sw)
|
||||
!tb_port_is_width_supported(down, TB_LINK_WIDTH_DUAL))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Both lanes need to be in CL0. Here we assume lane 0 already be in
|
||||
* CL0 and check just for lane 1.
|
||||
*/
|
||||
if (tb_wait_for_port(down->dual_link_port, false) <= 0)
|
||||
return -ENOTCONN;
|
||||
|
||||
ret = tb_port_lane_bonding_enable(up);
|
||||
if (ret) {
|
||||
tb_port_warn(up, "failed to enable lane bonding\n");
|
||||
|
@ -382,7 +382,7 @@ static int tmu_mode_init(struct tb_switch *sw)
|
||||
} else if (ucap && tb_port_tmu_is_unidirectional(up)) {
|
||||
if (tmu_rates[TB_SWITCH_TMU_MODE_LOWRES] == rate)
|
||||
sw->tmu.mode = TB_SWITCH_TMU_MODE_LOWRES;
|
||||
else if (tmu_rates[TB_SWITCH_TMU_MODE_LOWRES] == rate)
|
||||
else if (tmu_rates[TB_SWITCH_TMU_MODE_HIFI_UNI] == rate)
|
||||
sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_UNI;
|
||||
} else if (rate) {
|
||||
sw->tmu.mode = TB_SWITCH_TMU_MODE_HIFI_BI;
|
||||
|
@ -703,6 +703,27 @@ out_unlock:
|
||||
mutex_unlock(&xdomain_lock);
|
||||
}
|
||||
|
||||
static void start_handshake(struct tb_xdomain *xd)
|
||||
{
|
||||
xd->state = XDOMAIN_STATE_INIT;
|
||||
queue_delayed_work(xd->tb->wq, &xd->state_work,
|
||||
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
|
||||
}
|
||||
|
||||
/* Can be called from state_work */
|
||||
static void __stop_handshake(struct tb_xdomain *xd)
|
||||
{
|
||||
cancel_delayed_work_sync(&xd->properties_changed_work);
|
||||
xd->properties_changed_retries = 0;
|
||||
xd->state_retries = 0;
|
||||
}
|
||||
|
||||
static void stop_handshake(struct tb_xdomain *xd)
|
||||
{
|
||||
cancel_delayed_work_sync(&xd->state_work);
|
||||
__stop_handshake(xd);
|
||||
}
|
||||
|
||||
static void tb_xdp_handle_request(struct work_struct *work)
|
||||
{
|
||||
struct xdomain_request_work *xw = container_of(work, typeof(*xw), work);
|
||||
@ -765,6 +786,15 @@ static void tb_xdp_handle_request(struct work_struct *work)
|
||||
case UUID_REQUEST:
|
||||
tb_dbg(tb, "%llx: received XDomain UUID request\n", route);
|
||||
ret = tb_xdp_uuid_response(ctl, route, sequence, uuid);
|
||||
/*
|
||||
* If we've stopped the discovery with an error such as
|
||||
* timing out, we will restart the handshake now that we
|
||||
* received UUID request from the remote host.
|
||||
*/
|
||||
if (!ret && xd && xd->state == XDOMAIN_STATE_ERROR) {
|
||||
dev_dbg(&xd->dev, "restarting handshake\n");
|
||||
start_handshake(xd);
|
||||
}
|
||||
break;
|
||||
|
||||
case LINK_STATE_STATUS_REQUEST:
|
||||
@ -1521,6 +1551,13 @@ static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd)
|
||||
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
|
||||
}
|
||||
|
||||
static void tb_xdomain_failed(struct tb_xdomain *xd)
|
||||
{
|
||||
xd->state = XDOMAIN_STATE_ERROR;
|
||||
queue_delayed_work(xd->tb->wq, &xd->state_work,
|
||||
msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT));
|
||||
}
|
||||
|
||||
static void tb_xdomain_state_work(struct work_struct *work)
|
||||
{
|
||||
struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work);
|
||||
@ -1547,7 +1584,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
|
||||
if (ret) {
|
||||
if (ret == -EAGAIN)
|
||||
goto retry_state;
|
||||
xd->state = XDOMAIN_STATE_ERROR;
|
||||
tb_xdomain_failed(xd);
|
||||
} else {
|
||||
tb_xdomain_queue_properties_changed(xd);
|
||||
if (xd->bonding_possible)
|
||||
@ -1612,7 +1649,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
|
||||
if (ret) {
|
||||
if (ret == -EAGAIN)
|
||||
goto retry_state;
|
||||
xd->state = XDOMAIN_STATE_ERROR;
|
||||
tb_xdomain_failed(xd);
|
||||
} else {
|
||||
xd->state = XDOMAIN_STATE_ENUMERATED;
|
||||
}
|
||||
@ -1623,6 +1660,8 @@ static void tb_xdomain_state_work(struct work_struct *work)
|
||||
break;
|
||||
|
||||
case XDOMAIN_STATE_ERROR:
|
||||
dev_dbg(&xd->dev, "discovery failed, stopping handshake\n");
|
||||
__stop_handshake(xd);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1833,21 +1872,6 @@ static void tb_xdomain_release(struct device *dev)
|
||||
kfree(xd);
|
||||
}
|
||||
|
||||
static void start_handshake(struct tb_xdomain *xd)
|
||||
{
|
||||
xd->state = XDOMAIN_STATE_INIT;
|
||||
queue_delayed_work(xd->tb->wq, &xd->state_work,
|
||||
msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT));
|
||||
}
|
||||
|
||||
static void stop_handshake(struct tb_xdomain *xd)
|
||||
{
|
||||
cancel_delayed_work_sync(&xd->properties_changed_work);
|
||||
cancel_delayed_work_sync(&xd->state_work);
|
||||
xd->properties_changed_retries = 0;
|
||||
xd->state_retries = 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tb_xdomain_suspend(struct device *dev)
|
||||
{
|
||||
stop_handshake(tb_to_xdomain(dev));
|
||||
|
@ -1125,6 +1125,9 @@ static int cdnsp_gadget_ep_dequeue(struct usb_ep *ep,
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (request->status != -EINPROGRESS)
|
||||
return 0;
|
||||
|
||||
if (!pep->endpoint.desc) {
|
||||
dev_err(pdev->dev,
|
||||
"%s: can't dequeue to disabled endpoint\n",
|
||||
|
@ -131,8 +131,7 @@ void cdns_set_active(struct cdns *cdns, u8 set_active);
|
||||
#else /* CONFIG_PM_SLEEP */
|
||||
static inline int cdns_resume(struct cdns *cdns)
|
||||
{ return 0; }
|
||||
static inline int cdns_set_active(struct cdns *cdns, u8 set_active)
|
||||
{ return 0; }
|
||||
static inline void cdns_set_active(struct cdns *cdns, u8 set_active) { }
|
||||
static inline int cdns_suspend(struct cdns *cdns)
|
||||
{ return 0; }
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
@ -151,6 +151,10 @@ int usb_device_supports_lpm(struct usb_device *udev)
|
||||
if (udev->quirks & USB_QUIRK_NO_LPM)
|
||||
return 0;
|
||||
|
||||
/* Skip if the device BOS descriptor couldn't be read */
|
||||
if (!udev->bos)
|
||||
return 0;
|
||||
|
||||
/* USB 2.1 (and greater) devices indicate LPM support through
|
||||
* their USB 2.0 Extended Capabilities BOS descriptor.
|
||||
*/
|
||||
@ -327,6 +331,10 @@ static void usb_set_lpm_parameters(struct usb_device *udev)
|
||||
if (!udev->lpm_capable || udev->speed < USB_SPEED_SUPER)
|
||||
return;
|
||||
|
||||
/* Skip if the device BOS descriptor couldn't be read */
|
||||
if (!udev->bos)
|
||||
return;
|
||||
|
||||
hub = usb_hub_to_struct_hub(udev->parent);
|
||||
/* It doesn't take time to transition the roothub into U0, since it
|
||||
* doesn't have an upstream link.
|
||||
@ -2704,13 +2712,17 @@ out_authorized:
|
||||
static enum usb_ssp_rate get_port_ssp_rate(struct usb_device *hdev,
|
||||
u32 ext_portstatus)
|
||||
{
|
||||
struct usb_ssp_cap_descriptor *ssp_cap = hdev->bos->ssp_cap;
|
||||
struct usb_ssp_cap_descriptor *ssp_cap;
|
||||
u32 attr;
|
||||
u8 speed_id;
|
||||
u8 ssac;
|
||||
u8 lanes;
|
||||
int i;
|
||||
|
||||
if (!hdev->bos)
|
||||
goto out;
|
||||
|
||||
ssp_cap = hdev->bos->ssp_cap;
|
||||
if (!ssp_cap)
|
||||
goto out;
|
||||
|
||||
@ -4215,8 +4227,15 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
enum usb3_link_state state)
|
||||
{
|
||||
int timeout;
|
||||
__u8 u1_mel = udev->bos->ss_cap->bU1devExitLat;
|
||||
__le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat;
|
||||
__u8 u1_mel;
|
||||
__le16 u2_mel;
|
||||
|
||||
/* Skip if the device BOS descriptor couldn't be read */
|
||||
if (!udev->bos)
|
||||
return;
|
||||
|
||||
u1_mel = udev->bos->ss_cap->bU1devExitLat;
|
||||
u2_mel = udev->bos->ss_cap->bU2DevExitLat;
|
||||
|
||||
/* If the device says it doesn't have *any* exit latency to come out of
|
||||
* U1 or U2, it's probably lying. Assume it doesn't implement that link
|
||||
|
@ -153,7 +153,7 @@ static inline int hub_is_superspeedplus(struct usb_device *hdev)
|
||||
{
|
||||
return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS &&
|
||||
le16_to_cpu(hdev->descriptor.bcdUSB) >= 0x0310 &&
|
||||
hdev->bos->ssp_cap);
|
||||
hdev->bos && hdev->bos->ssp_cap);
|
||||
}
|
||||
|
||||
static inline unsigned hub_power_on_good_delay(struct usb_hub *hub)
|
||||
|
@ -279,9 +279,46 @@ int dwc3_core_soft_reset(struct dwc3 *dwc)
|
||||
* XHCI driver will reset the host block. If dwc3 was configured for
|
||||
* host-only mode or current role is host, then we can return early.
|
||||
*/
|
||||
if (dwc->dr_mode == USB_DR_MODE_HOST || dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
|
||||
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the dr_mode is host and the dwc->current_dr_role is not the
|
||||
* corresponding DWC3_GCTL_PRTCAP_HOST, then the dwc3_core_init_mode
|
||||
* isn't executed yet. Ensure the phy is ready before the controller
|
||||
* updates the GCTL.PRTCAPDIR or other settings by soft-resetting
|
||||
* the phy.
|
||||
*
|
||||
* Note: GUSB3PIPECTL[n] and GUSB2PHYCFG[n] are port settings where n
|
||||
* is port index. If this is a multiport host, then we need to reset
|
||||
* all active ports.
|
||||
*/
|
||||
if (dwc->dr_mode == USB_DR_MODE_HOST) {
|
||||
u32 usb3_port;
|
||||
u32 usb2_port;
|
||||
|
||||
usb3_port = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||
usb3_port |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), usb3_port);
|
||||
|
||||
usb2_port = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
usb2_port |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), usb2_port);
|
||||
|
||||
/* Small delay for phy reset assertion */
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
usb3_port &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), usb3_port);
|
||||
|
||||
usb2_port &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), usb2_port);
|
||||
|
||||
/* Wait for clock synchronization */
|
||||
msleep(50);
|
||||
return 0;
|
||||
}
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg |= DWC3_DCTL_CSFTRST;
|
||||
reg &= ~DWC3_DCTL_RUN_STOP;
|
||||
|
@ -1156,7 +1156,8 @@ static int ncm_unwrap_ntb(struct gether *port,
|
||||
struct sk_buff_head *list)
|
||||
{
|
||||
struct f_ncm *ncm = func_to_ncm(&port->func);
|
||||
__le16 *tmp = (void *) skb->data;
|
||||
unsigned char *ntb_ptr = skb->data;
|
||||
__le16 *tmp;
|
||||
unsigned index, index2;
|
||||
int ndp_index;
|
||||
unsigned dg_len, dg_len2;
|
||||
@ -1169,6 +1170,10 @@ static int ncm_unwrap_ntb(struct gether *port,
|
||||
const struct ndp_parser_opts *opts = ncm->parser_opts;
|
||||
unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
|
||||
int dgram_counter;
|
||||
int to_process = skb->len;
|
||||
|
||||
parse_ntb:
|
||||
tmp = (__le16 *)ntb_ptr;
|
||||
|
||||
/* dwSignature */
|
||||
if (get_unaligned_le32(tmp) != opts->nth_sign) {
|
||||
@ -1215,7 +1220,7 @@ static int ncm_unwrap_ntb(struct gether *port,
|
||||
* walk through NDP
|
||||
* dwSignature
|
||||
*/
|
||||
tmp = (void *)(skb->data + ndp_index);
|
||||
tmp = (__le16 *)(ntb_ptr + ndp_index);
|
||||
if (get_unaligned_le32(tmp) != ncm->ndp_sign) {
|
||||
INFO(port->func.config->cdev, "Wrong NDP SIGN\n");
|
||||
goto err;
|
||||
@ -1272,11 +1277,11 @@ static int ncm_unwrap_ntb(struct gether *port,
|
||||
if (ncm->is_crc) {
|
||||
uint32_t crc, crc2;
|
||||
|
||||
crc = get_unaligned_le32(skb->data +
|
||||
crc = get_unaligned_le32(ntb_ptr +
|
||||
index + dg_len -
|
||||
crc_len);
|
||||
crc2 = ~crc32_le(~0,
|
||||
skb->data + index,
|
||||
ntb_ptr + index,
|
||||
dg_len - crc_len);
|
||||
if (crc != crc2) {
|
||||
INFO(port->func.config->cdev,
|
||||
@ -1303,7 +1308,7 @@ static int ncm_unwrap_ntb(struct gether *port,
|
||||
dg_len - crc_len);
|
||||
if (skb2 == NULL)
|
||||
goto err;
|
||||
skb_put_data(skb2, skb->data + index,
|
||||
skb_put_data(skb2, ntb_ptr + index,
|
||||
dg_len - crc_len);
|
||||
|
||||
skb_queue_tail(list, skb2);
|
||||
@ -1316,10 +1321,17 @@ static int ncm_unwrap_ntb(struct gether *port,
|
||||
} while (ndp_len > 2 * (opts->dgram_item_len * 2));
|
||||
} while (ndp_index);
|
||||
|
||||
dev_consume_skb_any(skb);
|
||||
|
||||
VDBG(port->func.config->cdev,
|
||||
"Parsed NTB with %d frames\n", dgram_counter);
|
||||
|
||||
to_process -= block_len;
|
||||
if (to_process != 0) {
|
||||
ntb_ptr = (unsigned char *)(ntb_ptr + block_len);
|
||||
goto parse_ntb;
|
||||
}
|
||||
|
||||
dev_consume_skb_any(skb);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
skb_queue_purge(list);
|
||||
|
@ -497,11 +497,13 @@ static int xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req,
|
||||
/* Get the Buffer address and copy the transmit data.*/
|
||||
eprambase = (u32 __force *)(udc->addr + ep->rambase);
|
||||
if (ep->is_in) {
|
||||
memcpy(eprambase, bufferptr, bytestosend);
|
||||
memcpy_toio((void __iomem *)eprambase, bufferptr,
|
||||
bytestosend);
|
||||
udc->write_fn(udc->addr, ep->offset +
|
||||
XUSB_EP_BUF0COUNT_OFFSET, bufferlen);
|
||||
} else {
|
||||
memcpy(bufferptr, eprambase, bytestosend);
|
||||
memcpy_toio((void __iomem *)bufferptr, eprambase,
|
||||
bytestosend);
|
||||
}
|
||||
/*
|
||||
* Enable the buffer for transmission.
|
||||
@ -515,11 +517,13 @@ static int xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req,
|
||||
eprambase = (u32 __force *)(udc->addr + ep->rambase +
|
||||
ep->ep_usb.maxpacket);
|
||||
if (ep->is_in) {
|
||||
memcpy(eprambase, bufferptr, bytestosend);
|
||||
memcpy_toio((void __iomem *)eprambase, bufferptr,
|
||||
bytestosend);
|
||||
udc->write_fn(udc->addr, ep->offset +
|
||||
XUSB_EP_BUF1COUNT_OFFSET, bufferlen);
|
||||
} else {
|
||||
memcpy(bufferptr, eprambase, bytestosend);
|
||||
memcpy_toio((void __iomem *)bufferptr, eprambase,
|
||||
bytestosend);
|
||||
}
|
||||
/*
|
||||
* Enable the buffer for transmission.
|
||||
@ -1021,7 +1025,7 @@ static int __xudc_ep0_queue(struct xusb_ep *ep0, struct xusb_req *req)
|
||||
udc->addr);
|
||||
length = req->usb_req.actual = min_t(u32, length,
|
||||
EP0_MAX_PACKET);
|
||||
memcpy(corebuf, req->usb_req.buf, length);
|
||||
memcpy_toio((void __iomem *)corebuf, req->usb_req.buf, length);
|
||||
udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, length);
|
||||
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1);
|
||||
} else {
|
||||
@ -1752,7 +1756,7 @@ static void xudc_handle_setup(struct xusb_udc *udc)
|
||||
|
||||
/* Load up the chapter 9 command buffer.*/
|
||||
ep0rambase = (u32 __force *) (udc->addr + XUSB_SETUP_PKT_ADDR_OFFSET);
|
||||
memcpy(&setup, ep0rambase, 8);
|
||||
memcpy_toio((void __iomem *)&setup, ep0rambase, 8);
|
||||
|
||||
udc->setup = setup;
|
||||
udc->setup.wValue = cpu_to_le16((u16 __force)setup.wValue);
|
||||
@ -1839,7 +1843,7 @@ static void xudc_ep0_out(struct xusb_udc *udc)
|
||||
(ep0->rambase << 2));
|
||||
buffer = req->usb_req.buf + req->usb_req.actual;
|
||||
req->usb_req.actual = req->usb_req.actual + bytes_to_rx;
|
||||
memcpy(buffer, ep0rambase, bytes_to_rx);
|
||||
memcpy_toio((void __iomem *)buffer, ep0rambase, bytes_to_rx);
|
||||
|
||||
if (req->usb_req.length == req->usb_req.actual) {
|
||||
/* Data transfer completed get ready for Status stage */
|
||||
@ -1915,7 +1919,7 @@ static void xudc_ep0_in(struct xusb_udc *udc)
|
||||
(ep0->rambase << 2));
|
||||
buffer = req->usb_req.buf + req->usb_req.actual;
|
||||
req->usb_req.actual = req->usb_req.actual + length;
|
||||
memcpy(ep0rambase, buffer, length);
|
||||
memcpy_toio((void __iomem *)ep0rambase, buffer, length);
|
||||
}
|
||||
udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, count);
|
||||
udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1);
|
||||
|
@ -1062,19 +1062,19 @@ static void xhci_get_usb3_port_status(struct xhci_port *port, u32 *status,
|
||||
*status |= USB_PORT_STAT_C_CONFIG_ERROR << 16;
|
||||
|
||||
/* USB3 specific wPortStatus bits */
|
||||
if (portsc & PORT_POWER) {
|
||||
if (portsc & PORT_POWER)
|
||||
*status |= USB_SS_PORT_STAT_POWER;
|
||||
/* link state handling */
|
||||
if (link_state == XDEV_U0)
|
||||
bus_state->suspended_ports &= ~(1 << portnum);
|
||||
}
|
||||
|
||||
/* remote wake resume signaling complete */
|
||||
if (bus_state->port_remote_wakeup & (1 << portnum) &&
|
||||
/* no longer suspended or resuming */
|
||||
if (link_state != XDEV_U3 &&
|
||||
link_state != XDEV_RESUME &&
|
||||
link_state != XDEV_RECOVERY) {
|
||||
bus_state->port_remote_wakeup &= ~(1 << portnum);
|
||||
usb_hcd_end_port_resume(&hcd->self, portnum);
|
||||
/* remote wake resume signaling complete */
|
||||
if (bus_state->port_remote_wakeup & (1 << portnum)) {
|
||||
bus_state->port_remote_wakeup &= ~(1 << portnum);
|
||||
usb_hcd_end_port_resume(&hcd->self, portnum);
|
||||
}
|
||||
bus_state->suspended_ports &= ~(1 << portnum);
|
||||
}
|
||||
|
||||
xhci_hub_report_usb3_link_state(xhci, status, portsc);
|
||||
@ -1131,6 +1131,7 @@ static void xhci_get_usb2_port_status(struct xhci_port *port, u32 *status,
|
||||
usb_hcd_end_port_resume(&port->rhub->hcd->self, portnum);
|
||||
}
|
||||
port->rexit_active = 0;
|
||||
bus_state->suspended_ports &= ~(1 << portnum);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2285,8 +2285,8 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
|
||||
writel(erst_size, &ir->ir_set->erst_size);
|
||||
|
||||
erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
|
||||
erst_base &= ERST_PTR_MASK;
|
||||
erst_base |= (ir->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
|
||||
erst_base &= ERST_BASE_RSVDP;
|
||||
erst_base |= ir->erst.erst_dma_addr & ~ERST_BASE_RSVDP;
|
||||
xhci_write_64(xhci, erst_base, &ir->ir_set->erst_base);
|
||||
|
||||
/* Set the event ring dequeue address of this interrupter */
|
||||
|
@ -798,7 +798,7 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
|
||||
static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci,
|
||||
struct xhci_ring *ring, struct xhci_td *td)
|
||||
{
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
struct xhci_segment *seg = td->bounce_seg;
|
||||
struct urb *urb = td->urb;
|
||||
size_t len;
|
||||
@ -2996,7 +2996,8 @@ static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
*/
|
||||
static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
|
||||
struct xhci_interrupter *ir,
|
||||
union xhci_trb *event_ring_deq)
|
||||
union xhci_trb *event_ring_deq,
|
||||
bool clear_ehb)
|
||||
{
|
||||
u64 temp_64;
|
||||
dma_addr_t deq;
|
||||
@ -3017,12 +3018,13 @@ static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
|
||||
return;
|
||||
|
||||
/* Update HC event ring dequeue pointer */
|
||||
temp_64 &= ERST_PTR_MASK;
|
||||
temp_64 &= ERST_DESI_MASK;
|
||||
temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
|
||||
}
|
||||
|
||||
/* Clear the event handler busy flag (RW1C) */
|
||||
temp_64 |= ERST_EHB;
|
||||
if (clear_ehb)
|
||||
temp_64 |= ERST_EHB;
|
||||
xhci_write_64(xhci, temp_64, &ir->ir_set->erst_dequeue);
|
||||
}
|
||||
|
||||
@ -3103,7 +3105,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
while (xhci_handle_event(xhci, ir) > 0) {
|
||||
if (event_loop++ < TRBS_PER_SEGMENT / 2)
|
||||
continue;
|
||||
xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
|
||||
xhci_update_erst_dequeue(xhci, ir, event_ring_deq, false);
|
||||
event_ring_deq = ir->event_ring->dequeue;
|
||||
|
||||
/* ring is half-full, force isoc trbs to interrupt more often */
|
||||
@ -3113,7 +3115,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
|
||||
event_loop = 0;
|
||||
}
|
||||
|
||||
xhci_update_erst_dequeue(xhci, ir, event_ring_deq);
|
||||
xhci_update_erst_dequeue(xhci, ir, event_ring_deq, true);
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
out:
|
||||
@ -3469,7 +3471,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
|
||||
static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
|
||||
u32 *trb_buff_len, struct xhci_segment *seg)
|
||||
{
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.controller;
|
||||
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
|
||||
unsigned int unalign;
|
||||
unsigned int max_pkt;
|
||||
u32 new_buff_len;
|
||||
|
@ -514,7 +514,7 @@ struct xhci_intr_reg {
|
||||
#define ERST_SIZE_MASK (0xffff << 16)
|
||||
|
||||
/* erst_base bitmasks */
|
||||
#define ERST_BASE_RSVDP (0x3f)
|
||||
#define ERST_BASE_RSVDP (GENMASK_ULL(5, 0))
|
||||
|
||||
/* erst_dequeue bitmasks */
|
||||
/* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
|
||||
|
@ -434,6 +434,7 @@ static const struct usb_device_id onboard_hub_id_table[] = {
|
||||
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */
|
||||
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 */
|
||||
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0620) }, /* Genesys Logic GL3523 USB 3.1 */
|
||||
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2412) }, /* USB2412 USB 2.0 */
|
||||
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */
|
||||
{ USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 */
|
||||
{ USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */
|
||||
|
@ -47,6 +47,7 @@ static const struct onboard_hub_pdata vialab_vl817_data = {
|
||||
};
|
||||
|
||||
static const struct of_device_id onboard_hub_match[] = {
|
||||
{ .compatible = "usb424,2412", .data = µchip_usb424_data, },
|
||||
{ .compatible = "usb424,2514", .data = µchip_usb424_data, },
|
||||
{ .compatible = "usb424,2517", .data = µchip_usb424_data, },
|
||||
{ .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
|
||||
|
@ -39,7 +39,7 @@ static const struct musb_register_map musb_regmap[] = {
|
||||
{ "IntrUsbE", MUSB_INTRUSBE, 8 },
|
||||
{ "DevCtl", MUSB_DEVCTL, 8 },
|
||||
{ "VControl", 0x68, 32 },
|
||||
{ "HWVers", 0x69, 16 },
|
||||
{ "HWVers", MUSB_HWVERS, 16 },
|
||||
{ "LinkInfo", MUSB_LINKINFO, 8 },
|
||||
{ "VPLen", MUSB_VPLEN, 8 },
|
||||
{ "HS_EOF1", MUSB_HS_EOF1, 8 },
|
||||
|
@ -321,10 +321,16 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
|
||||
musb_giveback(musb, urb, status);
|
||||
qh->is_ready = ready;
|
||||
|
||||
/*
|
||||
* musb->lock had been unlocked in musb_giveback, so qh may
|
||||
* be freed, need to get it again
|
||||
*/
|
||||
qh = musb_ep_get_qh(hw_ep, is_in);
|
||||
|
||||
/* reclaim resources (and bandwidth) ASAP; deschedule it, and
|
||||
* invalidate qh as soon as list_empty(&hep->urb_list)
|
||||
*/
|
||||
if (list_empty(&qh->hep->urb_list)) {
|
||||
if (qh && list_empty(&qh->hep->urb_list)) {
|
||||
struct list_head *head;
|
||||
struct dma_controller *dma = musb->dma_controller;
|
||||
|
||||
@ -2398,6 +2404,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||
* and its URB list has emptied, recycle this qh.
|
||||
*/
|
||||
if (ready && list_empty(&qh->hep->urb_list)) {
|
||||
musb_ep_set_qh(qh->hw_ep, is_in, NULL);
|
||||
qh->hep->hcpriv = NULL;
|
||||
list_del(&qh->ring);
|
||||
kfree(qh);
|
||||
|
@ -304,6 +304,11 @@ static int dp_altmode_vdm(struct typec_altmode *alt,
|
||||
typec_altmode_update_active(alt, false);
|
||||
dp->data.status = 0;
|
||||
dp->data.conf = 0;
|
||||
if (dp->hpd) {
|
||||
drm_connector_oob_hotplug_event(dp->connector_fwnode);
|
||||
dp->hpd = false;
|
||||
sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
|
||||
}
|
||||
break;
|
||||
case DP_CMD_STATUS_UPDATE:
|
||||
dp->data.status = *vdo;
|
||||
|
@ -381,10 +381,6 @@ static int qcom_pmic_typec_pdphy_enable(struct pmic_typec_pdphy *pmic_typec_pdph
|
||||
struct device *dev = pmic_typec_pdphy->dev;
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(pmic_typec_pdphy->vdd_pdphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* PD 2.0, DR=TYPEC_DEVICE, PR=TYPEC_SINK */
|
||||
ret = regmap_update_bits(pmic_typec_pdphy->regmap,
|
||||
pmic_typec_pdphy->base + USB_PDPHY_MSG_CONFIG_REG,
|
||||
@ -422,8 +418,6 @@ static int qcom_pmic_typec_pdphy_disable(struct pmic_typec_pdphy *pmic_typec_pdp
|
||||
ret = regmap_write(pmic_typec_pdphy->regmap,
|
||||
pmic_typec_pdphy->base + USB_PDPHY_EN_CONTROL_REG, 0);
|
||||
|
||||
regulator_disable(pmic_typec_pdphy->vdd_pdphy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -447,6 +441,10 @@ int qcom_pmic_typec_pdphy_start(struct pmic_typec_pdphy *pmic_typec_pdphy,
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(pmic_typec_pdphy->vdd_pdphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pmic_typec_pdphy->tcpm_port = tcpm_port;
|
||||
|
||||
ret = pmic_typec_pdphy_reset(pmic_typec_pdphy);
|
||||
@ -467,6 +465,8 @@ void qcom_pmic_typec_pdphy_stop(struct pmic_typec_pdphy *pmic_typec_pdphy)
|
||||
disable_irq(pmic_typec_pdphy->irq_data[i].irq);
|
||||
|
||||
qcom_pmic_typec_pdphy_reset_on(pmic_typec_pdphy);
|
||||
|
||||
regulator_disable(pmic_typec_pdphy->vdd_pdphy);
|
||||
}
|
||||
|
||||
struct pmic_typec_pdphy *qcom_pmic_typec_pdphy_alloc(struct device *dev)
|
||||
|
@ -37,6 +37,15 @@ static int ucsi_psy_get_scope(struct ucsi_connector *con,
|
||||
struct device *dev = con->ucsi->dev;
|
||||
|
||||
device_property_read_u8(dev, "scope", &scope);
|
||||
if (scope == POWER_SUPPLY_SCOPE_UNKNOWN) {
|
||||
u32 mask = UCSI_CAP_ATTR_POWER_AC_SUPPLY |
|
||||
UCSI_CAP_ATTR_BATTERY_CHARGING;
|
||||
|
||||
if (con->ucsi->cap.attributes & mask)
|
||||
scope = POWER_SUPPLY_SCOPE_SYSTEM;
|
||||
else
|
||||
scope = POWER_SUPPLY_SCOPE_DEVICE;
|
||||
}
|
||||
val->intval = scope;
|
||||
return 0;
|
||||
}
|
||||
|
@ -787,6 +787,7 @@ static void ucsi_unregister_partner(struct ucsi_connector *con)
|
||||
|
||||
typec_set_mode(con->port, TYPEC_STATE_SAFE);
|
||||
|
||||
typec_partner_set_usb_power_delivery(con->partner, NULL);
|
||||
ucsi_unregister_partner_pdos(con);
|
||||
ucsi_unregister_altmodes(con, UCSI_RECIPIENT_SOP);
|
||||
typec_unregister_partner(con->partner);
|
||||
@ -884,6 +885,7 @@ static void ucsi_handle_connector_change(struct work_struct *work)
|
||||
if (ret < 0) {
|
||||
dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n",
|
||||
__func__, ret);
|
||||
clear_bit(EVENT_PENDING, &con->ucsi->flags);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user