mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-04 20:19:47 +08:00
USB fixes for 6.17-rc3
Here are some small USB driver fixes for 6.17-rc3 to resolve a bunch of reported issues. Included in here are: - typec driver fixes - dwc3 new device id - dwc3 driver fixes - new usb-storage driver quirks - xhci driver fixes - other tiny USB driver fixes to resolve bugs All of these have been in linux-next this week with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCaKnTpQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yk+7gCfV8UA7wAViZTaXWmqsa3GzeuSMKIAoKdcM0+j hV48oay+3njPXzlsTp0d =lRRr -----END PGP SIGNATURE----- Merge tag 'usb-6.17-rc3' 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 6.17-rc3 to resolve a bunch of reported issues. Included in here are: - typec driver fixes - dwc3 new device id - dwc3 driver fixes - new usb-storage driver quirks - xhci driver fixes - other tiny USB driver fixes to resolve bugs All of these have been in linux-next this week with no reported issues" * tag 'usb-6.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: usb: xhci: fix host not responding after suspend and resume usb: xhci: Fix slot_id resource race conflict usb: typec: fusb302: Revert incorrect threaded irq fix USB: core: Update kerneldoc for usb_hcd_giveback_urb() usb: typec: maxim_contaminant: re-enable cc toggle if cc is open and port is clean usb: typec: maxim_contaminant: disable low power mode when reading comparator values usb: dwc3: Remove WARN_ON for device endpoint command timeouts USB: storage: Ignore driver CD mode for Realtek multi-mode Wi-Fi dongles usb: storage: realtek_cr: Use correct byte order for bcs->Residue usb: chipidea: imx: improve usbmisc_imx7d_pullup() kcov, usb: Don't disable interrupts in kcov_remote_start_usb_softirq() usb: dwc3: pci: add support for the Intel Wildcat Lake usb: dwc3: Ignore late xferNotReady event to prevent halt timeout USB: storage: Add unusual-devs entry for Novatek NTK96550-based camera usb: core: hcd: fix accessing unmapped memory in SINGLE_STEP_SET_FEATURE test usb: renesas-xhci: Fix External ROM access timeouts usb: gadget: tegra-xudc: fix PM use count underflow usb: quirks: Add DELAY_INIT quick for another SanDisk 3.2Gen1 Flash Drive
This commit is contained in:
commit
8004d08330
@ -338,7 +338,8 @@ static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)
|
||||
schedule_work(&ci->usb_phy->chg_work);
|
||||
break;
|
||||
case CI_HDRC_CONTROLLER_PULLUP_EVENT:
|
||||
if (ci->role == CI_ROLE_GADGET)
|
||||
if (ci->role == CI_ROLE_GADGET &&
|
||||
ci->gadget.speed == USB_SPEED_HIGH)
|
||||
imx_usbmisc_pullup(data->usbmisc_data,
|
||||
ci->gadget.connected);
|
||||
break;
|
||||
|
@ -1068,15 +1068,24 @@ static void usbmisc_imx7d_pullup(struct imx_usbmisc_data *data, bool on)
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
if (on)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
val = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
if (!on) {
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE(1);
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN;
|
||||
} else {
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN;
|
||||
}
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE(1);
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN;
|
||||
writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
|
||||
/* Last for at least 1 micro-frame to let host see disconnect signal */
|
||||
usleep_range(125, 150);
|
||||
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_MASK;
|
||||
val |= MX7D_USBNC_USB_CTRL2_OPMODE(0);
|
||||
val &= ~MX7D_USBNC_USB_CTRL2_OPMODE_OVERRIDE_EN;
|
||||
writel(val, usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
}
|
||||
|
@ -1636,7 +1636,6 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
|
||||
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
|
||||
struct usb_anchor *anchor = urb->anchor;
|
||||
int status = urb->unlinked;
|
||||
unsigned long flags;
|
||||
|
||||
urb->hcpriv = NULL;
|
||||
if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
|
||||
@ -1654,14 +1653,13 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
|
||||
/* pass ownership to the completion handler */
|
||||
urb->status = status;
|
||||
/*
|
||||
* Only collect coverage in the softirq context and disable interrupts
|
||||
* to avoid scenarios with nested remote coverage collection sections
|
||||
* that KCOV does not support.
|
||||
* See the comment next to kcov_remote_start_usb_softirq() for details.
|
||||
* This function can be called in task context inside another remote
|
||||
* coverage collection section, but kcov doesn't support that kind of
|
||||
* recursion yet. Only collect coverage in softirq context for now.
|
||||
*/
|
||||
flags = kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum);
|
||||
kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum);
|
||||
urb->complete(urb);
|
||||
kcov_remote_stop_softirq(flags);
|
||||
kcov_remote_stop_softirq();
|
||||
|
||||
usb_anchor_resume_wakeups(anchor);
|
||||
atomic_dec(&urb->use_count);
|
||||
@ -1719,10 +1717,10 @@ static void usb_giveback_urb_bh(struct work_struct *work)
|
||||
* @urb: urb being returned to the USB device driver.
|
||||
* @status: completion status code for the URB.
|
||||
*
|
||||
* Context: atomic. The completion callback is invoked in caller's context.
|
||||
* For HCDs with HCD_BH flag set, the completion callback is invoked in BH
|
||||
* context (except for URBs submitted to the root hub which always complete in
|
||||
* caller's context).
|
||||
* Context: atomic. The completion callback is invoked either in a work queue
|
||||
* (BH) context or in the caller's context, depending on whether the HCD_BH
|
||||
* flag is set in the @hcd structure, except that URBs submitted to the
|
||||
* root hub always complete in BH context.
|
||||
*
|
||||
* This hands the URB from HCD to its USB device driver, using its
|
||||
* completion function. The HCD has freed all per-urb resources
|
||||
@ -2166,7 +2164,7 @@ static struct urb *request_single_step_set_feature_urb(
|
||||
urb->complete = usb_ehset_completion;
|
||||
urb->status = -EINPROGRESS;
|
||||
urb->actual_length = 0;
|
||||
urb->transfer_flags = URB_DIR_IN;
|
||||
urb->transfer_flags = URB_DIR_IN | URB_NO_TRANSFER_DMA_MAP;
|
||||
usb_get_urb(urb);
|
||||
atomic_inc(&urb->use_count);
|
||||
atomic_inc(&urb->dev->urbnum);
|
||||
@ -2230,9 +2228,15 @@ int ehset_single_step_set_feature(struct usb_hcd *hcd, int port)
|
||||
|
||||
/* Complete remaining DATA and STATUS stages using the same URB */
|
||||
urb->status = -EINPROGRESS;
|
||||
urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
|
||||
usb_get_urb(urb);
|
||||
atomic_inc(&urb->use_count);
|
||||
atomic_inc(&urb->dev->urbnum);
|
||||
if (map_urb_for_dma(hcd, urb, GFP_KERNEL)) {
|
||||
usb_put_urb(urb);
|
||||
goto out1;
|
||||
}
|
||||
|
||||
retval = hcd->driver->submit_single_step_set_feature(hcd, urb, 0);
|
||||
if (!retval && !wait_for_completion_timeout(&done,
|
||||
msecs_to_jiffies(2000))) {
|
||||
|
@ -371,6 +371,7 @@ static const struct usb_device_id usb_quirk_list[] = {
|
||||
{ USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM },
|
||||
|
||||
/* SanDisk Corp. SanDisk 3.2Gen1 */
|
||||
{ USB_DEVICE(0x0781, 0x5596), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
{ USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT },
|
||||
|
||||
/* SanDisk Extreme 55AE */
|
||||
|
@ -41,6 +41,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee
|
||||
#define PCI_DEVICE_ID_INTEL_TGPH 0x43ee
|
||||
#define PCI_DEVICE_ID_INTEL_JSP 0x4dee
|
||||
#define PCI_DEVICE_ID_INTEL_WCL 0x4d7e
|
||||
#define PCI_DEVICE_ID_INTEL_ADL 0x460e
|
||||
#define PCI_DEVICE_ID_INTEL_ADL_PCH 0x51ee
|
||||
#define PCI_DEVICE_ID_INTEL_ADLN 0x465e
|
||||
@ -431,6 +432,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, TGPLP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TGPH, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, JSP, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, WCL, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL_PCH, &dwc3_pci_intel_swnode) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADLN, &dwc3_pci_intel_swnode) },
|
||||
|
@ -288,7 +288,9 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
|
||||
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 8,
|
||||
DWC3_TRBCTL_CONTROL_SETUP, false);
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
WARN_ON(ret < 0);
|
||||
if (ret < 0)
|
||||
dev_err(dwc->dev, "ep0 out start transfer failed: %d\n", ret);
|
||||
|
||||
for (i = 2; i < DWC3_ENDPOINTS_NUM; i++) {
|
||||
struct dwc3_ep *dwc3_ep;
|
||||
|
||||
@ -1061,7 +1063,9 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
ret = dwc3_ep0_start_trans(dep);
|
||||
}
|
||||
|
||||
WARN_ON(ret < 0);
|
||||
if (ret < 0)
|
||||
dev_err(dwc->dev,
|
||||
"ep0 data phase start transfer failed: %d\n", ret);
|
||||
}
|
||||
|
||||
static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
||||
@ -1078,7 +1082,12 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
||||
|
||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
WARN_ON(dwc3_ep0_start_control_status(dep));
|
||||
int ret;
|
||||
|
||||
ret = dwc3_ep0_start_control_status(dep);
|
||||
if (ret)
|
||||
dev_err(dwc->dev,
|
||||
"ep0 status phase start transfer failed: %d\n", ret);
|
||||
}
|
||||
|
||||
static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
|
||||
@ -1121,7 +1130,10 @@ void dwc3_ep0_end_control_data(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms);
|
||||
WARN_ON_ONCE(ret);
|
||||
if (ret)
|
||||
dev_err_ratelimited(dwc->dev,
|
||||
"ep0 data phase end transfer failed: %d\n", ret);
|
||||
|
||||
dep->resource_index = 0;
|
||||
}
|
||||
|
||||
|
@ -1772,7 +1772,11 @@ static int __dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool int
|
||||
dep->flags |= DWC3_EP_DELAY_STOP;
|
||||
return 0;
|
||||
}
|
||||
WARN_ON_ONCE(ret);
|
||||
|
||||
if (ret)
|
||||
dev_err_ratelimited(dep->dwc->dev,
|
||||
"end transfer failed: %d\n", ret);
|
||||
|
||||
dep->resource_index = 0;
|
||||
|
||||
if (!interrupt)
|
||||
@ -3777,6 +3781,15 @@ static void dwc3_gadget_endpoint_transfer_complete(struct dwc3_ep *dep,
|
||||
static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
|
||||
const struct dwc3_event_depevt *event)
|
||||
{
|
||||
/*
|
||||
* During a device-initiated disconnect, a late xferNotReady event can
|
||||
* be generated after the End Transfer command resets the event filter,
|
||||
* but before the controller is halted. Ignore it to prevent a new
|
||||
* transfer from starting.
|
||||
*/
|
||||
if (!dep->dwc->connected)
|
||||
return;
|
||||
|
||||
dwc3_gadget_endpoint_frame_from_event(dep, event);
|
||||
|
||||
/*
|
||||
@ -4039,7 +4052,9 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
||||
dep->flags &= ~DWC3_EP_STALL;
|
||||
|
||||
ret = dwc3_send_clear_stall_ep_cmd(dep);
|
||||
WARN_ON_ONCE(ret);
|
||||
if (ret)
|
||||
dev_err_ratelimited(dwc->dev,
|
||||
"failed to clear STALL on %s\n", dep->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,6 +502,7 @@ struct tegra_xudc {
|
||||
struct clk_bulk_data *clks;
|
||||
|
||||
bool device_mode;
|
||||
bool current_device_mode;
|
||||
struct work_struct usb_role_sw_work;
|
||||
|
||||
struct phy **usb3_phy;
|
||||
@ -715,6 +716,8 @@ static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc)
|
||||
|
||||
phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG,
|
||||
USB_ROLE_DEVICE);
|
||||
|
||||
xudc->current_device_mode = true;
|
||||
}
|
||||
|
||||
static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
|
||||
@ -725,6 +728,8 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
|
||||
|
||||
dev_dbg(xudc->dev, "device mode off\n");
|
||||
|
||||
xudc->current_device_mode = false;
|
||||
|
||||
connected = !!(xudc_readl(xudc, PORTSC) & PORTSC_CCS);
|
||||
|
||||
reinit_completion(&xudc->disconnect_complete);
|
||||
@ -4044,10 +4049,10 @@ static int __maybe_unused tegra_xudc_resume(struct device *dev)
|
||||
|
||||
spin_lock_irqsave(&xudc->lock, flags);
|
||||
xudc->suspended = false;
|
||||
if (xudc->device_mode != xudc->current_device_mode)
|
||||
schedule_work(&xudc->usb_role_sw_work);
|
||||
spin_unlock_irqrestore(&xudc->lock, flags);
|
||||
|
||||
schedule_work(&xudc->usb_role_sw_work);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
return 0;
|
||||
|
@ -704,8 +704,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci,
|
||||
if (!xhci->devs[i])
|
||||
continue;
|
||||
|
||||
retval = xhci_disable_slot(xhci, i);
|
||||
xhci_free_virt_device(xhci, i);
|
||||
retval = xhci_disable_and_free_slot(xhci, i);
|
||||
if (retval)
|
||||
xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n",
|
||||
i, retval);
|
||||
|
@ -865,21 +865,20 @@ free_tts:
|
||||
* will be manipulated by the configure endpoint, allocate device, or update
|
||||
* hub functions while this function is removing the TT entries from the list.
|
||||
*/
|
||||
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
|
||||
void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev,
|
||||
int slot_id)
|
||||
{
|
||||
struct xhci_virt_device *dev;
|
||||
int i;
|
||||
int old_active_eps = 0;
|
||||
|
||||
/* Slot ID 0 is reserved */
|
||||
if (slot_id == 0 || !xhci->devs[slot_id])
|
||||
if (slot_id == 0 || !dev)
|
||||
return;
|
||||
|
||||
dev = xhci->devs[slot_id];
|
||||
|
||||
xhci->dcbaa->dev_context_ptrs[slot_id] = 0;
|
||||
if (!dev)
|
||||
return;
|
||||
/* If device ctx array still points to _this_ device, clear it */
|
||||
if (dev->out_ctx &&
|
||||
xhci->dcbaa->dev_context_ptrs[slot_id] == cpu_to_le64(dev->out_ctx->dma))
|
||||
xhci->dcbaa->dev_context_ptrs[slot_id] = 0;
|
||||
|
||||
trace_xhci_free_virt_device(dev);
|
||||
|
||||
@ -920,8 +919,9 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
|
||||
dev->udev->slot_id = 0;
|
||||
if (dev->rhub_port && dev->rhub_port->slot_id == slot_id)
|
||||
dev->rhub_port->slot_id = 0;
|
||||
kfree(xhci->devs[slot_id]);
|
||||
xhci->devs[slot_id] = NULL;
|
||||
if (xhci->devs[slot_id] == dev)
|
||||
xhci->devs[slot_id] = NULL;
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -962,7 +962,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i
|
||||
out:
|
||||
/* we are now at a leaf device */
|
||||
xhci_debugfs_remove_slot(xhci, slot_id);
|
||||
xhci_free_virt_device(xhci, slot_id);
|
||||
xhci_free_virt_device(xhci, vdev, slot_id);
|
||||
}
|
||||
|
||||
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
|
||||
|
@ -47,8 +47,9 @@
|
||||
#define RENESAS_ROM_ERASE_MAGIC 0x5A65726F
|
||||
#define RENESAS_ROM_WRITE_MAGIC 0x53524F4D
|
||||
|
||||
#define RENESAS_RETRY 10000
|
||||
#define RENESAS_DELAY 10
|
||||
#define RENESAS_RETRY 50000 /* 50000 * RENESAS_DELAY ~= 500ms */
|
||||
#define RENESAS_CHIP_ERASE_RETRY 500000 /* 500000 * RENESAS_DELAY ~= 5s */
|
||||
#define RENESAS_DELAY 10
|
||||
|
||||
#define RENESAS_FW_NAME "renesas_usb_fw.mem"
|
||||
|
||||
@ -407,7 +408,7 @@ static void renesas_rom_erase(struct pci_dev *pdev)
|
||||
/* sleep a bit while ROM is erased */
|
||||
msleep(20);
|
||||
|
||||
for (i = 0; i < RENESAS_RETRY; i++) {
|
||||
for (i = 0; i < RENESAS_CHIP_ERASE_RETRY; i++) {
|
||||
retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS,
|
||||
&status);
|
||||
status &= RENESAS_ROM_STATUS_ERASE;
|
||||
|
@ -1592,7 +1592,8 @@ static void xhci_handle_cmd_enable_slot(int slot_id, struct xhci_command *comman
|
||||
command->slot_id = 0;
|
||||
}
|
||||
|
||||
static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)
|
||||
static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id,
|
||||
u32 cmd_comp_code)
|
||||
{
|
||||
struct xhci_virt_device *virt_dev;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
@ -1607,6 +1608,10 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)
|
||||
if (xhci->quirks & XHCI_EP_LIMIT_QUIRK)
|
||||
/* Delete default control endpoint resources */
|
||||
xhci_free_device_endpoint_resources(xhci, virt_dev, true);
|
||||
if (cmd_comp_code == COMP_SUCCESS) {
|
||||
xhci->dcbaa->dev_context_ptrs[slot_id] = 0;
|
||||
xhci->devs[slot_id] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id)
|
||||
@ -1856,7 +1861,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
||||
xhci_handle_cmd_enable_slot(slot_id, cmd, cmd_comp_code);
|
||||
break;
|
||||
case TRB_DISABLE_SLOT:
|
||||
xhci_handle_cmd_disable_slot(xhci, slot_id);
|
||||
xhci_handle_cmd_disable_slot(xhci, slot_id, cmd_comp_code);
|
||||
break;
|
||||
case TRB_CONFIG_EP:
|
||||
if (!cmd->completion)
|
||||
|
@ -309,6 +309,7 @@ int xhci_enable_interrupter(struct xhci_interrupter *ir)
|
||||
return -EINVAL;
|
||||
|
||||
iman = readl(&ir->ir_set->iman);
|
||||
iman &= ~IMAN_IP;
|
||||
iman |= IMAN_IE;
|
||||
writel(iman, &ir->ir_set->iman);
|
||||
|
||||
@ -325,6 +326,7 @@ int xhci_disable_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
|
||||
return -EINVAL;
|
||||
|
||||
iman = readl(&ir->ir_set->iman);
|
||||
iman &= ~IMAN_IP;
|
||||
iman &= ~IMAN_IE;
|
||||
writel(iman, &ir->ir_set->iman);
|
||||
|
||||
@ -3932,8 +3934,7 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
|
||||
* Obtaining a new device slot to inform the xHCI host that
|
||||
* the USB device has been reset.
|
||||
*/
|
||||
ret = xhci_disable_slot(xhci, udev->slot_id);
|
||||
xhci_free_virt_device(xhci, udev->slot_id);
|
||||
ret = xhci_disable_and_free_slot(xhci, udev->slot_id);
|
||||
if (!ret) {
|
||||
ret = xhci_alloc_dev(hcd, udev);
|
||||
if (ret == 1)
|
||||
@ -4090,7 +4091,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
xhci_disable_slot(xhci, udev->slot_id);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
xhci_free_virt_device(xhci, udev->slot_id);
|
||||
xhci_free_virt_device(xhci, virt_dev, udev->slot_id);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
||||
}
|
||||
@ -4139,6 +4140,16 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id)
|
||||
{
|
||||
struct xhci_virt_device *vdev = xhci->devs[slot_id];
|
||||
int ret;
|
||||
|
||||
ret = xhci_disable_slot(xhci, slot_id);
|
||||
xhci_free_virt_device(xhci, vdev, slot_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if we have enough host controller resources for the default control
|
||||
* endpoint.
|
||||
@ -4245,8 +4256,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
return 1;
|
||||
|
||||
disable_slot:
|
||||
xhci_disable_slot(xhci, udev->slot_id);
|
||||
xhci_free_virt_device(xhci, udev->slot_id);
|
||||
xhci_disable_and_free_slot(xhci, udev->slot_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4382,8 +4392,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
dev_warn(&udev->dev, "Device not responding to setup %s.\n", act);
|
||||
|
||||
mutex_unlock(&xhci->mutex);
|
||||
ret = xhci_disable_slot(xhci, udev->slot_id);
|
||||
xhci_free_virt_device(xhci, udev->slot_id);
|
||||
ret = xhci_disable_and_free_slot(xhci, udev->slot_id);
|
||||
if (!ret) {
|
||||
if (xhci_alloc_dev(hcd, udev) == 1)
|
||||
xhci_setup_addressable_virt_dev(xhci, udev);
|
||||
|
@ -1791,7 +1791,7 @@ void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *),
|
||||
/* xHCI memory management */
|
||||
void xhci_mem_cleanup(struct xhci_hcd *xhci);
|
||||
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags);
|
||||
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id);
|
||||
void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev, int slot_id);
|
||||
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags);
|
||||
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev);
|
||||
void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
|
||||
@ -1888,6 +1888,7 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
|
||||
struct usb_tt *tt, gfp_t mem_flags);
|
||||
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id);
|
||||
int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id);
|
||||
int xhci_ext_cap_init(struct xhci_hcd *xhci);
|
||||
|
||||
int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup);
|
||||
|
@ -252,7 +252,7 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun,
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
}
|
||||
|
||||
residue = bcs->Residue;
|
||||
residue = le32_to_cpu(bcs->Residue);
|
||||
if (bcs->Tag != us->tag)
|
||||
return USB_STOR_TRANSPORT_ERROR;
|
||||
|
||||
|
@ -934,6 +934,13 @@ UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451,
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_SANE_SENSE ),
|
||||
|
||||
/* Added by Maël GUERIN <mael.guerin@murena.io> */
|
||||
UNUSUAL_DEV( 0x0603, 0x8611, 0x0000, 0xffff,
|
||||
"Novatek",
|
||||
"NTK96550-based camera",
|
||||
USB_SC_SCSI, USB_PR_BULK, NULL,
|
||||
US_FL_BULK_IGNORE_TAG ),
|
||||
|
||||
/*
|
||||
* Reported by Hanno Boeck <hanno@gmx.de>
|
||||
* Taken from the Lycoris Kernel
|
||||
@ -1494,6 +1501,28 @@ UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999,
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_NO_WP_DETECT ),
|
||||
|
||||
/*
|
||||
* Reported by Zenm Chen <zenmchen@gmail.com>
|
||||
* Ignore driver CD mode, otherwise usb_modeswitch may fail to switch
|
||||
* the device into Wi-Fi mode.
|
||||
*/
|
||||
UNUSUAL_DEV( 0x0bda, 0x1a2b, 0x0000, 0xffff,
|
||||
"Realtek",
|
||||
"DISK",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_DEVICE ),
|
||||
|
||||
/*
|
||||
* Reported by Zenm Chen <zenmchen@gmail.com>
|
||||
* Ignore driver CD mode, otherwise usb_modeswitch may fail to switch
|
||||
* the device into Wi-Fi mode.
|
||||
*/
|
||||
UNUSUAL_DEV( 0x0bda, 0xa192, 0x0000, 0xffff,
|
||||
"Realtek",
|
||||
"DISK",
|
||||
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_DEVICE ),
|
||||
|
||||
UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999,
|
||||
"Maxtor",
|
||||
"USB to SATA",
|
||||
|
@ -1485,6 +1485,9 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id)
|
||||
struct fusb302_chip *chip = dev_id;
|
||||
unsigned long flags;
|
||||
|
||||
/* Disable our level triggered IRQ until our irq_work has cleared it */
|
||||
disable_irq_nosync(chip->gpio_int_n_irq);
|
||||
|
||||
spin_lock_irqsave(&chip->irq_lock, flags);
|
||||
if (chip->irq_suspended)
|
||||
chip->irq_while_suspended = true;
|
||||
@ -1627,6 +1630,7 @@ static void fusb302_irq_work(struct work_struct *work)
|
||||
}
|
||||
done:
|
||||
mutex_unlock(&chip->lock);
|
||||
enable_irq(chip->gpio_int_n_irq);
|
||||
}
|
||||
|
||||
static int init_gpio(struct fusb302_chip *chip)
|
||||
@ -1751,10 +1755,9 @@ static int fusb302_probe(struct i2c_client *client)
|
||||
goto destroy_workqueue;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, chip->gpio_int_n_irq,
|
||||
NULL, fusb302_irq_intn,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
|
||||
"fsc_interrupt_int_n", chip);
|
||||
ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
|
||||
"fsc_interrupt_int_n", chip);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret);
|
||||
goto tcpm_unregister_port;
|
||||
@ -1779,6 +1782,7 @@ static void fusb302_remove(struct i2c_client *client)
|
||||
struct fusb302_chip *chip = i2c_get_clientdata(client);
|
||||
|
||||
disable_irq_wake(chip->gpio_int_n_irq);
|
||||
free_irq(chip->gpio_int_n_irq, chip);
|
||||
cancel_work_sync(&chip->irq_work);
|
||||
cancel_delayed_work_sync(&chip->bc_lvl_handler);
|
||||
tcpm_unregister_port(chip->tcpm_port);
|
||||
|
@ -188,6 +188,11 @@ static int max_contaminant_read_comparators(struct max_tcpci_chip *chip, u8 *ven
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Disable low power mode */
|
||||
ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL,
|
||||
FIELD_PREP(CCLPMODESEL,
|
||||
LOW_POWER_MODE_DISABLE));
|
||||
|
||||
/* Sleep to allow comparators settle */
|
||||
usleep_range(5000, 6000);
|
||||
ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL, TCPC_TCPC_CTRL_ORIENTATION, PLUG_ORNT_CC1);
|
||||
@ -324,6 +329,39 @@ static int max_contaminant_enable_dry_detection(struct max_tcpci_chip *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max_contaminant_enable_toggling(struct max_tcpci_chip *chip)
|
||||
{
|
||||
struct regmap *regmap = chip->data.regmap;
|
||||
int ret;
|
||||
|
||||
/* Disable dry detection if enabled. */
|
||||
ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL2, CCLPMODESEL,
|
||||
FIELD_PREP(CCLPMODESEL,
|
||||
LOW_POWER_MODE_DISABLE));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(regmap, TCPC_VENDOR_CC_CTRL1, CCCONNDRY, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = max_tcpci_write8(chip, TCPC_ROLE_CTRL, TCPC_ROLE_CTRL_DRP |
|
||||
FIELD_PREP(TCPC_ROLE_CTRL_CC1,
|
||||
TCPC_ROLE_CTRL_CC_RD) |
|
||||
FIELD_PREP(TCPC_ROLE_CTRL_CC2,
|
||||
TCPC_ROLE_CTRL_CC_RD));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(regmap, TCPC_TCPC_CTRL,
|
||||
TCPC_TCPC_CTRL_EN_LK4CONN_ALRT,
|
||||
TCPC_TCPC_CTRL_EN_LK4CONN_ALRT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return max_tcpci_write8(chip, TCPC_COMMAND, TCPC_CMD_LOOK4CONNECTION);
|
||||
}
|
||||
|
||||
bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect_while_debounce,
|
||||
bool *cc_handled)
|
||||
{
|
||||
@ -340,6 +378,12 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
||||
if (cc_status & TCPC_CC_STATUS_TOGGLING) {
|
||||
if (chip->contaminant_state == DETECTED)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chip->contaminant_state == NOT_DETECTED || chip->contaminant_state == SINK) {
|
||||
if (!disconnect_while_debounce)
|
||||
msleep(100);
|
||||
@ -372,6 +416,12 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect
|
||||
max_contaminant_enable_dry_detection(chip);
|
||||
return true;
|
||||
}
|
||||
|
||||
ret = max_contaminant_enable_toggling(chip);
|
||||
if (ret)
|
||||
dev_err(chip->dev,
|
||||
"Failed to enable toggling, ret=%d",
|
||||
ret);
|
||||
}
|
||||
} else if (chip->contaminant_state == DETECTED) {
|
||||
if (!(cc_status & TCPC_CC_STATUS_TOGGLING)) {
|
||||
@ -379,6 +429,14 @@ bool max_contaminant_is_contaminant(struct max_tcpci_chip *chip, bool disconnect
|
||||
if (chip->contaminant_state == DETECTED) {
|
||||
max_contaminant_enable_dry_detection(chip);
|
||||
return true;
|
||||
} else {
|
||||
ret = max_contaminant_enable_toggling(chip);
|
||||
if (ret) {
|
||||
dev_err(chip->dev,
|
||||
"Failed to enable toggling, ret=%d",
|
||||
ret);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define CCOVPDIS BIT(6)
|
||||
#define SBURPCTRL BIT(5)
|
||||
#define CCLPMODESEL GENMASK(4, 3)
|
||||
#define LOW_POWER_MODE_DISABLE 0
|
||||
#define ULTRA_LOW_POWER_MODE 1
|
||||
#define CCRPCTRL GENMASK(2, 0)
|
||||
#define UA_1_SRC 1
|
||||
|
@ -57,47 +57,21 @@ static inline void kcov_remote_start_usb(u64 id)
|
||||
|
||||
/*
|
||||
* The softirq flavor of kcov_remote_*() functions is introduced as a temporary
|
||||
* workaround for KCOV's lack of nested remote coverage sections support.
|
||||
*
|
||||
* Adding support is tracked in https://bugzilla.kernel.org/show_bug.cgi?id=210337.
|
||||
*
|
||||
* kcov_remote_start_usb_softirq():
|
||||
*
|
||||
* 1. Only collects coverage when called in the softirq context. This allows
|
||||
* avoiding nested remote coverage collection sections in the task context.
|
||||
* For example, USB/IP calls usb_hcd_giveback_urb() in the task context
|
||||
* within an existing remote coverage collection section. Thus, KCOV should
|
||||
* not attempt to start collecting coverage within the coverage collection
|
||||
* section in __usb_hcd_giveback_urb() in this case.
|
||||
*
|
||||
* 2. Disables interrupts for the duration of the coverage collection section.
|
||||
* This allows avoiding nested remote coverage collection sections in the
|
||||
* softirq context (a softirq might occur during the execution of a work in
|
||||
* the BH workqueue, which runs with in_serving_softirq() > 0).
|
||||
* For example, usb_giveback_urb_bh() runs in the BH workqueue with
|
||||
* interrupts enabled, so __usb_hcd_giveback_urb() might be interrupted in
|
||||
* the middle of its remote coverage collection section, and the interrupt
|
||||
* handler might invoke __usb_hcd_giveback_urb() again.
|
||||
* work around for kcov's lack of nested remote coverage sections support in
|
||||
* task context. Adding support for nested sections is tracked in:
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=210337
|
||||
*/
|
||||
|
||||
static inline unsigned long kcov_remote_start_usb_softirq(u64 id)
|
||||
static inline void kcov_remote_start_usb_softirq(u64 id)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (in_serving_softirq()) {
|
||||
local_irq_save(flags);
|
||||
if (in_serving_softirq() && !in_hardirq())
|
||||
kcov_remote_start_usb(id);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void kcov_remote_stop_softirq(unsigned long flags)
|
||||
static inline void kcov_remote_stop_softirq(void)
|
||||
{
|
||||
if (in_serving_softirq()) {
|
||||
if (in_serving_softirq() && !in_hardirq())
|
||||
kcov_remote_stop();
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
@ -131,11 +105,8 @@ static inline u64 kcov_common_handle(void)
|
||||
}
|
||||
static inline void kcov_remote_start_common(u64 id) {}
|
||||
static inline void kcov_remote_start_usb(u64 id) {}
|
||||
static inline unsigned long kcov_remote_start_usb_softirq(u64 id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void kcov_remote_stop_softirq(unsigned long flags) {}
|
||||
static inline void kcov_remote_start_usb_softirq(u64 id) {}
|
||||
static inline void kcov_remote_stop_softirq(void) {}
|
||||
|
||||
#endif /* CONFIG_KCOV */
|
||||
#endif /* _LINUX_KCOV_H */
|
||||
|
Loading…
Reference in New Issue
Block a user