Commit 469a2f50 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull USB / Thunderbolt driver fixes from Greg KH:
 "Here are some small USB and Thunderbolt driver fixes for reported
  problems. Included in here are:

   - thunderbolt driver memory leak fix

   - thunderbolt display flicker fix

   - usb dwc3 driver fix

   - usb gadget uvc disconnect crash fix

   - usb typec Kconfig build dependency fix

   - usb typec small fixes

   - usb-con-gpio bugfix

   - usb-storage old driver bugfix

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

* tag 'usb-6.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  thunderbolt: Fix memory leak in tb_handle_dp_bandwidth_request()
  usb: dwc3: Properly handle processing of pending events
  usb-storage: alauda: Fix uninit-value in alauda_check_media()
  usb: common: usb-conn-gpio: Prevent bailing out if initial role is none
  USB: Gadget: core: Help prevent panic during UVC unconfigure
  usb: typec: mux: intel: Add dependency on USB_COMMON
  usb: typec: nb7vpq904m: Add an error handling path in nb7vpq904m_probe()
  usb: typec: altmodes/displayport: Signal hpd when configuring pin assignment
  usb: typec: tcpm: Fix response to vsafe0V event
  thunderbolt: Fix Thunderbolt 3 display flickering issue on 2nd hot plug onwards
parents 43972cf2 f48585c4
......@@ -1964,6 +1964,8 @@ static void tb_handle_dp_bandwidth_request(struct work_struct *work)
pm_runtime_mark_last_busy(&tb->dev);
pm_runtime_put_autosuspend(&tb->dev);
kfree(ev);
}
static void tb_queue_dp_bandwidth_request(struct tb *tb, u64 route, u8 port)
......
......@@ -579,7 +579,9 @@ int tb_switch_tmu_disable(struct tb_switch *sw)
* uni-directional mode and we don't want to change it's TMU
* mode.
*/
tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_OFF]);
ret = tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_OFF]);
if (ret)
return ret;
tb_port_tmu_time_sync_disable(up);
ret = tb_port_tmu_time_sync_disable(down);
......
......@@ -42,6 +42,7 @@ struct usb_conn_info {
struct power_supply_desc desc;
struct power_supply *charger;
bool initial_detection;
};
/*
......@@ -86,11 +87,13 @@ static void usb_conn_detect_cable(struct work_struct *work)
dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n",
usb_role_string(info->last_role), usb_role_string(role), id, vbus);
if (info->last_role == role) {
if (!info->initial_detection && info->last_role == role) {
dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role));
return;
}
info->initial_detection = false;
if (info->last_role == USB_ROLE_HOST && info->vbus)
regulator_disable(info->vbus);
......@@ -258,6 +261,7 @@ static int usb_conn_probe(struct platform_device *pdev)
device_set_wakeup_capable(&pdev->dev, true);
/* Perform initial detection */
info->initial_detection = true;
usb_conn_queue_dwork(info, 0);
return 0;
......
......@@ -4455,9 +4455,14 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
u32 count;
if (pm_runtime_suspended(dwc->dev)) {
dwc->pending_events = true;
/*
* Trigger runtime resume. The get() function will be balanced
* after processing the pending events in dwc3_process_pending
* events().
*/
pm_runtime_get(dwc->dev);
disable_irq_nosync(dwc->irq_gadget);
dwc->pending_events = true;
return IRQ_HANDLED;
}
......@@ -4718,6 +4723,8 @@ void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
{
if (dwc->pending_events) {
dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf);
dwc3_thread_interrupt(dwc->irq_gadget, dwc->ev_buf);
pm_runtime_put(dwc->dev);
dwc->pending_events = false;
enable_irq(dwc->irq_gadget);
}
......
......@@ -822,6 +822,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
* usb_gadget_activate() is called. For example, user mode components may
* need to be activated before the system can talk to hosts.
*
* This routine may sleep; it must not be called in interrupt context
* (such as from within a gadget driver's disconnect() callback).
*
* Returns zero on success, else negative errno.
*/
int usb_gadget_deactivate(struct usb_gadget *gadget)
......@@ -860,6 +863,8 @@ EXPORT_SYMBOL_GPL(usb_gadget_deactivate);
* This routine activates gadget which was previously deactivated with
* usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed.
*
* This routine may sleep; it must not be called in interrupt context.
*
* Returns zero on success, else negative errno.
*/
int usb_gadget_activate(struct usb_gadget *gadget)
......@@ -1638,7 +1643,11 @@ static void gadget_unbind_driver(struct device *dev)
usb_gadget_disable_async_callbacks(udc);
if (gadget->irq)
synchronize_irq(gadget->irq);
mutex_unlock(&udc->connect_lock);
udc->driver->unbind(gadget);
mutex_lock(&udc->connect_lock);
usb_gadget_udc_stop_locked(udc);
mutex_unlock(&udc->connect_lock);
......
......@@ -318,7 +318,8 @@ static int alauda_get_media_status(struct us_data *us, unsigned char *data)
rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
command, 0xc0, 0, 1, data, 2);
usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]);
if (rc == USB_STOR_XFER_GOOD)
usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]);
return rc;
}
......@@ -454,9 +455,14 @@ static int alauda_init_media(struct us_data *us)
static int alauda_check_media(struct us_data *us)
{
struct alauda_info *info = (struct alauda_info *) us->extra;
unsigned char status[2];
unsigned char *status = us->iobuf;
int rc;
alauda_get_media_status(us, status);
rc = alauda_get_media_status(us, status);
if (rc != USB_STOR_XFER_GOOD) {
status[0] = 0xF0; /* Pretend there's no media */
status[1] = 0;
}
/* Check for no media or door open */
if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10)
......
......@@ -60,6 +60,7 @@ struct dp_altmode {
enum dp_state state;
bool hpd;
bool pending_hpd;
struct mutex lock; /* device lock */
struct work_struct work;
......@@ -144,8 +145,13 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
dp->state = DP_STATE_EXIT;
} else if (!(con & DP_CONF_CURRENTLY(dp->data.conf))) {
ret = dp_altmode_configure(dp, con);
if (!ret)
if (!ret) {
dp->state = DP_STATE_CONFIGURE;
if (dp->hpd != hpd) {
dp->hpd = hpd;
dp->pending_hpd = true;
}
}
} else {
if (dp->hpd != hpd) {
drm_connector_oob_hotplug_event(dp->connector_fwnode);
......@@ -161,6 +167,16 @@ static int dp_altmode_configured(struct dp_altmode *dp)
{
sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment");
/*
* If the DFP_D/UFP_D sends a change in HPD when first notifying the
* DisplayPort driver that it is connected, then we wait until
* configuration is complete to signal HPD.
*/
if (dp->pending_hpd) {
drm_connector_oob_hotplug_event(dp->connector_fwnode);
sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
dp->pending_hpd = false;
}
return dp_altmode_notify(dp);
}
......
......@@ -29,6 +29,7 @@ config TYPEC_MUX_INTEL_PMC
tristate "Intel PMC mux control"
depends on ACPI
depends on INTEL_SCU_IPC
select USB_COMMON
select USB_ROLE_SWITCH
help
Driver for USB muxes controlled by Intel PMC FW. Intel PMC FW can
......
......@@ -463,16 +463,18 @@ static int nb7vpq904m_probe(struct i2c_client *client)
ret = nb7vpq904m_register_bridge(nb7);
if (ret)
return ret;
goto err_disable_gpio;
sw_desc.drvdata = nb7;
sw_desc.fwnode = dev->fwnode;
sw_desc.set = nb7vpq904m_sw_set;
nb7->sw = typec_switch_register(dev, &sw_desc);
if (IS_ERR(nb7->sw))
return dev_err_probe(dev, PTR_ERR(nb7->sw),
"Error registering typec switch\n");
if (IS_ERR(nb7->sw)) {
ret = dev_err_probe(dev, PTR_ERR(nb7->sw),
"Error registering typec switch\n");
goto err_disable_gpio;
}
retimer_desc.drvdata = nb7;
retimer_desc.fwnode = dev->fwnode;
......@@ -480,12 +482,21 @@ static int nb7vpq904m_probe(struct i2c_client *client)
nb7->retimer = typec_retimer_register(dev, &retimer_desc);
if (IS_ERR(nb7->retimer)) {
typec_switch_unregister(nb7->sw);
return dev_err_probe(dev, PTR_ERR(nb7->retimer),
"Error registering typec retimer\n");
ret = dev_err_probe(dev, PTR_ERR(nb7->retimer),
"Error registering typec retimer\n");
goto err_switch_unregister;
}
return 0;
err_switch_unregister:
typec_switch_unregister(nb7->sw);
err_disable_gpio:
gpiod_set_value(nb7->enable_gpio, 0);
regulator_disable(nb7->vcc_supply);
return ret;
}
static void nb7vpq904m_remove(struct i2c_client *client)
......
......@@ -5349,6 +5349,10 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
/* Do nothing, vbus drop expected */
break;
case SNK_HARD_RESET_WAIT_VBUS:
/* Do nothing, its OK to receive vbus off events */
break;
default:
if (port->pwr_role == TYPEC_SINK && port->attached)
tcpm_set_state(port, SNK_UNATTACHED, tcpm_wait_for_discharge(port));
......@@ -5395,6 +5399,9 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
case SNK_DEBOUNCED:
/*Do nothing, still waiting for VSAFE5V for connect */
break;
case SNK_HARD_RESET_WAIT_VBUS:
/* Do nothing, its OK to receive vbus off events */
break;
default:
if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled)
tcpm_set_state(port, SNK_UNATTACHED, 0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment