Loading drivers/usb/dwc3/core.c +14 −13 Original line number Diff line number Diff line Loading @@ -342,7 +342,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) dwc3_free_one_event_buffer(dwc, evt); /* free GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE); dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE, 0); } /** Loading @@ -365,7 +365,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) dwc->ev_buf = evt; /* alloc GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC); dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC, 0); return 0; } Loading @@ -390,7 +390,7 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); /* setup GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP); dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP, 0); return 0; } Loading @@ -409,7 +409,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); /* cleanup GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP); dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP, 0); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) Loading Loading @@ -879,7 +879,7 @@ int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL3, reg); } dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT); dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT, 0); /* * Workaround for STAR 9001198391 which affects dwc3 core Loading Loading @@ -1014,19 +1014,20 @@ static void __maybe_unused dwc3_core_exit_mode(struct dwc3 *dwc) } } static void (*notify_event)(struct dwc3 *, unsigned int); void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int)) static void (*notify_event)(struct dwc3 *, unsigned int, unsigned int); void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int, unsigned int)) { notify_event = notify; } EXPORT_SYMBOL(dwc3_set_notifier); int dwc3_notify_event(struct dwc3 *dwc, unsigned int event) int dwc3_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value) { int ret = 0; if (notify_event) notify_event(dwc, event); notify_event(dwc, event, value); else ret = -ENODEV; Loading Loading @@ -1440,7 +1441,7 @@ static int dwc3_runtime_suspend(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT, 0)) return 0; if (dwc3_runtime_checks(dwc)) Loading @@ -1461,7 +1462,7 @@ static int dwc3_runtime_resume(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) return 0; device_init_wakeup(dev, false); Loading Loading @@ -1517,7 +1518,7 @@ static int dwc3_suspend(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT, 0)) return 0; ret = dwc3_suspend_common(dwc); Loading @@ -1535,7 +1536,7 @@ static int dwc3_resume(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) return 0; pinctrl_pm_select_default_state(dev); Loading drivers/usb/dwc3/core.h +18 −15 Original line number Diff line number Diff line Loading @@ -843,12 +843,13 @@ struct dwc3_scratchpad_array { #define DWC3_CONTROLLER_NOTIFY_OTG_EVENT 6 #define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT 7 #define DWC3_CONTROLLER_RESTART_USB_SESSION 8 #define DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER 9 /* USB GSI event buffer related notification */ #define DWC3_GSI_EVT_BUF_ALLOC 9 #define DWC3_GSI_EVT_BUF_SETUP 10 #define DWC3_GSI_EVT_BUF_CLEANUP 11 #define DWC3_GSI_EVT_BUF_FREE 12 #define DWC3_GSI_EVT_BUF_ALLOC 10 #define DWC3_GSI_EVT_BUF_SETUP 11 #define DWC3_GSI_EVT_BUF_CLEANUP 12 #define DWC3_GSI_EVT_BUF_FREE 13 #define MAX_INTR_STATS 10 Loading Loading @@ -1457,7 +1458,9 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) #endif extern void dwc3_set_notifier( void (*notify)(struct dwc3 *dwc3, unsigned int event)); extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event); void (*notify)(struct dwc3 *dwc3, unsigned int event, unsigned int value)); extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event, unsigned int value); void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend); #endif /* __DRIVERS_USB_DWC3_CORE_H */ drivers/usb/dwc3/dbm.c +40 −20 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ enum dbm_reg { DBM_HW_TRB2_EP, DBM_HW_TRB3_EP, DBM_PIPE_CFG, DBM_DISABLE_UPDXFER, DBM_SOFT_RESET, DBM_GEN_CFG, DBM_GEVNTADR_LSB, Loading Loading @@ -101,6 +102,7 @@ static const struct dbm_reg_data dbm_1_5_regtable[] = { [DBM_HW_TRB2_EP] = { 0x0240, 0x4 }, [DBM_HW_TRB3_EP] = { 0x0250, 0x4 }, [DBM_PIPE_CFG] = { 0x0274, 0x0 }, [DBM_DISABLE_UPDXFER] = { 0x0298, 0x0 }, [DBM_SOFT_RESET] = { 0x020C, 0x0 }, [DBM_GEN_CFG] = { 0x0210, 0x0 }, [DBM_GEVNTADR_LSB] = { 0x0260, 0x0 }, Loading Loading @@ -188,7 +190,7 @@ static int find_matching_dbm_ep(struct dbm *dbm, u8 usb_ep) if (dbm->ep_num_mapping[i] == usb_ep) return i; pr_err("%s: No DBM EP matches USB EP %d", __func__, usb_ep); pr_debug("%s: No DBM EP matches USB EP %d", __func__, usb_ep); return -ENODEV; /* Not found */ } Loading Loading @@ -287,6 +289,7 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer, { int dbm_ep; u32 ep_cfg; u32 data; if (!dbm) { pr_err("%s: dbm pointer is NULL!\n", __func__); Loading @@ -308,9 +311,6 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer, return -ENODEV; } /* First, reset the dbm endpoint */ ep_soft_reset(dbm, dbm_ep, 0); /* Set ioc bit for dbm_ep if needed */ msm_dbm_write_reg_field(dbm, DBM_DBG_CNFG, DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0); Loading @@ -333,6 +333,10 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer, msm_dbm_write_ep_reg_field(dbm, DBM_EP_CFG, dbm_ep, DBM_EN_EP, 1); data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER); data &= ~(0x1 << dbm_ep); msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data); return dbm_ep; } Loading Loading @@ -377,7 +381,7 @@ int dbm_ep_unconfig(struct dbm *dbm, u8 usb_ep) dbm_ep = find_matching_dbm_ep(dbm, usb_ep); if (dbm_ep < 0) { pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep); pr_debug("usb ep index %d has no corespondng dbm ep\n", usb_ep); return -ENODEV; } Loading @@ -387,23 +391,10 @@ int dbm_ep_unconfig(struct dbm *dbm, u8 usb_ep) data &= (~0x1); msm_dbm_write_ep_reg(dbm, DBM_EP_CFG, dbm_ep, data); /* Reset the dbm endpoint */ ep_soft_reset(dbm, dbm_ep, true); /* * The necessary delay between asserting and deasserting the dbm ep * reset is based on the number of active endpoints. If there is more * than one endpoint, a 1 msec delay is required. Otherwise, a shorter * delay will suffice. * * As this function can be called in atomic context, sleeping variants * for delay are not possible - albeit a 1ms delay. * ep_soft_reset is not required during disconnect as pipe reset on * next connect will take care of the same. */ if (dbm_get_num_of_eps_configured(dbm) > 1) udelay(1000); else udelay(10); ep_soft_reset(dbm, dbm_ep, false); return 0; } Loading Loading @@ -445,6 +436,35 @@ int dbm_event_buffer_config(struct dbm *dbm, u32 addr_lo, u32 addr_hi, int size) return 0; } /** * Disable update xfer before queueing stop xfer command to USB3 core. * * @usb_ep - USB physical EP number. * */ int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep) { u32 data; int dbm_ep; if (!dbm) { pr_err("%s: dbm pointer is NULL!\n", __func__); return -EPERM; } dbm_ep = find_matching_dbm_ep(dbm, usb_ep); if (dbm_ep < 0) { pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep); return -ENODEV; } data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER); data |= (0x1 << dbm_ep); msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data); return 0; } int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr, u32 size, u8 dst_pipe_idx) Loading drivers/usb/dwc3/dbm.h +1 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ int dbm_event_buffer_config(struct dbm *dbm, u32 addr_lo, u32 addr_hi, int size); int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr, u32 size, u8 dst_pipe_idx); int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep); void dbm_set_speed(struct dbm *dbm, bool speed); void dbm_enable(struct dbm *dbm); int dbm_ep_soft_reset(struct dbm *dbm, u8 usb_ep, bool enter_reset); Loading drivers/usb/dwc3/dwc3-msm.c +140 −73 Original line number Diff line number Diff line Loading @@ -286,7 +286,8 @@ struct dwc3_msm { static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc); static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA); static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event); static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value); static int dwc3_restart_usb_host_mode(struct notifier_block *nb, unsigned long event, void *ptr); Loading Loading @@ -442,6 +443,16 @@ static inline bool dwc3_msm_is_superspeed(struct dwc3_msm *mdwc) return dwc3_msm_is_dev_superspeed(mdwc); } static int dwc3_msm_dbm_disable_updxfer(struct dwc3 *dwc, u8 usb_ep) { struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); dev_dbg(mdwc->dev, "%s\n", __func__); dwc3_dbm_disable_update_xfer(mdwc->dbm, usb_ep); return 0; } #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) /** * Configure the DBM with the BAM's data fifo. Loading Loading @@ -697,59 +708,89 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep, struct dwc3_msm_req_complete *req_complete; unsigned long flags; int ret = 0, size; u8 bam_pipe; bool producer; bool disable_wb; bool internal_mem; bool ioc; bool superspeed; /* * We must obtain the lock of the dwc3 core driver, * including disabling interrupts, so we will be sure * that we are the only ones that configure the HW device * core and ensure that we queuing the request will finish * as soon as possible so we will release back the lock. */ spin_lock_irqsave(&dwc->lock, flags); if (!dep->endpoint.desc) { dev_err(mdwc->dev, "%s: trying to queue request %pK to disabled ep %s\n", __func__, request, ep->name); spin_unlock_irqrestore(&dwc->lock, flags); return -EPERM; } if (!mdwc->original_ep_ops[dep->number]) { dev_err(mdwc->dev, "ep [%s,%d] was unconfigured as msm endpoint\n", ep->name, dep->number); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } if (!request) { dev_err(mdwc->dev, "%s: request is NULL\n", __func__); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } if (!(request->udc_priv & MSM_SPS_MODE)) { /* Not SPS mode, call original queue */ dev_vdbg(mdwc->dev, "%s: not sps mode, use regular queue\n", dev_err(mdwc->dev, "%s: sps mode is not set\n", __func__); return (mdwc->original_ep_ops[dep->number])->queue(ep, request, gfp_flags); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } /* HW restriction regarding TRB size (8KB) */ if (req->request.length < 0x2000) { dev_err(mdwc->dev, "%s: Min TRB size is 8KB\n", __func__); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } if (dep->number == 0 || dep->number == 1) { dev_err(mdwc->dev, "%s: trying to queue dbm request %pK to ep %s\n", __func__, request, ep->name); spin_unlock_irqrestore(&dwc->lock, flags); return -EPERM; } if (dep->trb_dequeue != dep->trb_enqueue || !list_empty(&dep->pending_list) || !list_empty(&dep->started_list)) { dev_err(mdwc->dev, "%s: trying to queue dbm request %pK tp ep %s\n", __func__, request, ep->name); spin_unlock_irqrestore(&dwc->lock, flags); return -EPERM; } dep->trb_dequeue = 0; dep->trb_enqueue = 0; /* * Override req->complete function, but before doing that, * store it's original pointer in the req_complete_list. */ req_complete = kzalloc(sizeof(*req_complete), gfp_flags); if (!req_complete) if (!req_complete) { dev_err(mdwc->dev, "%s: not enough memory\n", __func__); spin_unlock_irqrestore(&dwc->lock, flags); return -ENOMEM; } req_complete->req = request; req_complete->orig_complete = request->complete; list_add_tail(&req_complete->list_item, &mdwc->req_complete_list); request->complete = dwc3_msm_req_complete_func; /* * Configure the DBM endpoint */ bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK; producer = ((request->udc_priv & MSM_PRODUCER) ? true : false); disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false); internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false); ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false); ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer, disable_wb, internal_mem, ioc); if (ret < 0) { dev_err(mdwc->dev, "error %d after calling dbm_ep_config\n", ret); return ret; } dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n", __func__, request, ep->name, request->length); size = dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0)); Loading @@ -758,44 +799,6 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep, dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)), DWC3_GEVNTSIZ_SIZE(size)); /* * We must obtain the lock of the dwc3 core driver, * including disabling interrupts, so we will be sure * that we are the only ones that configure the HW device * core and ensure that we queuing the request will finish * as soon as possible so we will release back the lock. */ spin_lock_irqsave(&dwc->lock, flags); if (!dep->endpoint.desc) { dev_err(mdwc->dev, "%s: trying to queue request %p to disabled ep %s\n", __func__, request, ep->name); ret = -EPERM; goto err; } if (dep->number == 0 || dep->number == 1) { dev_err(mdwc->dev, "%s: trying to queue dbm request %p to control ep %s\n", __func__, request, ep->name); ret = -EPERM; goto err; } if (dep->trb_dequeue != dep->trb_enqueue || !list_empty(&dep->pending_list) || !list_empty(&dep->started_list)) { dev_err(mdwc->dev, "%s: trying to queue dbm request %p tp ep %s\n", __func__, request, ep->name); ret = -EPERM; goto err; } else { dep->trb_dequeue = 0; dep->trb_enqueue = 0; } ret = __dwc3_msm_ep_queue(dep, req); if (ret < 0) { dev_err(mdwc->dev, Loading Loading @@ -1471,37 +1474,68 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, * * @return int - 0 on success, negetive on error. */ int msm_ep_config(struct usb_ep *ep) int msm_ep_config(struct usb_ep *ep, struct usb_request *request) { struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); struct usb_ep_ops *new_ep_ops; int ret = 0; u8 bam_pipe; bool producer; bool disable_wb; bool internal_mem; bool ioc; unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); /* Save original ep ops for future restore*/ if (mdwc->original_ep_ops[dep->number]) { dev_err(mdwc->dev, "ep [%s,%d] already configured as msm endpoint\n", ep->name, dep->number); spin_unlock_irqrestore(&dwc->lock, flags); return -EPERM; } mdwc->original_ep_ops[dep->number] = ep->ops; /* Set new usb ops as we like */ new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_ATOMIC); if (!new_ep_ops) if (!new_ep_ops) { spin_unlock_irqrestore(&dwc->lock, flags); return -ENOMEM; } (*new_ep_ops) = (*ep->ops); new_ep_ops->queue = dwc3_msm_ep_queue; new_ep_ops->gsi_ep_op = dwc3_msm_gsi_ep_op; ep->ops = new_ep_ops; if (!mdwc->dbm || !request || (dep->endpoint.ep_type == EP_TYPE_GSI)) { spin_unlock_irqrestore(&dwc->lock, flags); return 0; } /* * Do HERE more usb endpoint configurations * which are specific to MSM. * Configure the DBM endpoint if required. */ bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK; producer = ((request->udc_priv & MSM_PRODUCER) ? true : false); disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false); internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false); ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false); ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer, disable_wb, internal_mem, ioc); if (ret < 0) { dev_err(mdwc->dev, "error %d after calling dbm_ep_config\n", ret); spin_unlock_irqrestore(&dwc->lock, flags); return ret; } spin_unlock_irqrestore(&dwc->lock, flags); return 0; } Loading @@ -1522,12 +1556,15 @@ int msm_ep_unconfig(struct usb_ep *ep) struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); struct usb_ep_ops *old_ep_ops; unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); /* Restore original ep ops */ if (!mdwc->original_ep_ops[dep->number]) { dev_err(mdwc->dev, "ep [%s,%d] was not configured as msm endpoint\n", ep->name, dep->number); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } old_ep_ops = (struct usb_ep_ops *)ep->ops; Loading @@ -1539,6 +1576,32 @@ int msm_ep_unconfig(struct usb_ep *ep) * Do HERE more usb endpoint un-configurations * which are specific to MSM. */ if (!mdwc->dbm || (dep->endpoint.ep_type == EP_TYPE_GSI)) { spin_unlock_irqrestore(&dwc->lock, flags); return 0; } if (dep->trb_dequeue == dep->trb_enqueue && list_empty(&dep->pending_list) && list_empty(&dep->started_list)) { dev_dbg(mdwc->dev, "%s: request is not queued, disable DBM ep for ep %s\n", __func__, ep->name); /* Unconfigure dbm ep */ dbm_ep_unconfig(mdwc->dbm, dep->number); /* * If this is the last endpoint we unconfigured, than reset also * the event buffers; unless unconfiguring the ep due to lpm, * in which case the event buffer only gets reset during the * block reset. */ if (dbm_get_num_of_eps_configured(mdwc->dbm) == 0 && !dbm_reset_ep_after_lpm(mdwc->dbm)) dbm_event_buffer_config(mdwc->dbm, 0, 0, 0); } spin_unlock_irqrestore(&dwc->lock, flags); return 0; } Loading Loading @@ -1722,7 +1785,8 @@ static void dwc3_msm_vbus_draw_work(struct work_struct *w) dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw); } static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event) static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value) { struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); struct dwc3_event_buffer *evt; Loading Loading @@ -1908,6 +1972,9 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event) evt->buf, evt->dma); } break; case DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER: dwc3_msm_dbm_disable_updxfer(dwc, value); break; default: dev_dbg(mdwc->dev, "unknown dwc3 event\n"); break; Loading Loading
drivers/usb/dwc3/core.c +14 −13 Original line number Diff line number Diff line Loading @@ -342,7 +342,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) dwc3_free_one_event_buffer(dwc, evt); /* free GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE); dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE, 0); } /** Loading @@ -365,7 +365,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) dwc->ev_buf = evt; /* alloc GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC); dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_ALLOC, 0); return 0; } Loading @@ -390,7 +390,7 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); /* setup GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP); dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP, 0); return 0; } Loading @@ -409,7 +409,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); /* cleanup GSI related event buffers */ dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP); dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP, 0); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) Loading Loading @@ -879,7 +879,7 @@ int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL3, reg); } dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT); dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT, 0); /* * Workaround for STAR 9001198391 which affects dwc3 core Loading Loading @@ -1014,19 +1014,20 @@ static void __maybe_unused dwc3_core_exit_mode(struct dwc3 *dwc) } } static void (*notify_event)(struct dwc3 *, unsigned int); void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int)) static void (*notify_event)(struct dwc3 *, unsigned int, unsigned int); void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int, unsigned int)) { notify_event = notify; } EXPORT_SYMBOL(dwc3_set_notifier); int dwc3_notify_event(struct dwc3 *dwc, unsigned int event) int dwc3_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value) { int ret = 0; if (notify_event) notify_event(dwc, event); notify_event(dwc, event, value); else ret = -ENODEV; Loading Loading @@ -1440,7 +1441,7 @@ static int dwc3_runtime_suspend(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT, 0)) return 0; if (dwc3_runtime_checks(dwc)) Loading @@ -1461,7 +1462,7 @@ static int dwc3_runtime_resume(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) return 0; device_init_wakeup(dev, false); Loading Loading @@ -1517,7 +1518,7 @@ static int dwc3_suspend(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_SUSPEND_EVENT, 0)) return 0; ret = dwc3_suspend_common(dwc); Loading @@ -1535,7 +1536,7 @@ static int dwc3_resume(struct device *dev) int ret; /* Check if platform glue driver handling PM, if not then handle here */ if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT)) if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT, 0)) return 0; pinctrl_pm_select_default_state(dev); Loading
drivers/usb/dwc3/core.h +18 −15 Original line number Diff line number Diff line Loading @@ -843,12 +843,13 @@ struct dwc3_scratchpad_array { #define DWC3_CONTROLLER_NOTIFY_OTG_EVENT 6 #define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT 7 #define DWC3_CONTROLLER_RESTART_USB_SESSION 8 #define DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER 9 /* USB GSI event buffer related notification */ #define DWC3_GSI_EVT_BUF_ALLOC 9 #define DWC3_GSI_EVT_BUF_SETUP 10 #define DWC3_GSI_EVT_BUF_CLEANUP 11 #define DWC3_GSI_EVT_BUF_FREE 12 #define DWC3_GSI_EVT_BUF_ALLOC 10 #define DWC3_GSI_EVT_BUF_SETUP 11 #define DWC3_GSI_EVT_BUF_CLEANUP 12 #define DWC3_GSI_EVT_BUF_FREE 13 #define MAX_INTR_STATS 10 Loading Loading @@ -1457,7 +1458,9 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) #endif extern void dwc3_set_notifier( void (*notify)(struct dwc3 *dwc3, unsigned int event)); extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event); void (*notify)(struct dwc3 *dwc3, unsigned int event, unsigned int value)); extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event, unsigned int value); void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend); #endif /* __DRIVERS_USB_DWC3_CORE_H */
drivers/usb/dwc3/dbm.c +40 −20 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ enum dbm_reg { DBM_HW_TRB2_EP, DBM_HW_TRB3_EP, DBM_PIPE_CFG, DBM_DISABLE_UPDXFER, DBM_SOFT_RESET, DBM_GEN_CFG, DBM_GEVNTADR_LSB, Loading Loading @@ -101,6 +102,7 @@ static const struct dbm_reg_data dbm_1_5_regtable[] = { [DBM_HW_TRB2_EP] = { 0x0240, 0x4 }, [DBM_HW_TRB3_EP] = { 0x0250, 0x4 }, [DBM_PIPE_CFG] = { 0x0274, 0x0 }, [DBM_DISABLE_UPDXFER] = { 0x0298, 0x0 }, [DBM_SOFT_RESET] = { 0x020C, 0x0 }, [DBM_GEN_CFG] = { 0x0210, 0x0 }, [DBM_GEVNTADR_LSB] = { 0x0260, 0x0 }, Loading Loading @@ -188,7 +190,7 @@ static int find_matching_dbm_ep(struct dbm *dbm, u8 usb_ep) if (dbm->ep_num_mapping[i] == usb_ep) return i; pr_err("%s: No DBM EP matches USB EP %d", __func__, usb_ep); pr_debug("%s: No DBM EP matches USB EP %d", __func__, usb_ep); return -ENODEV; /* Not found */ } Loading Loading @@ -287,6 +289,7 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer, { int dbm_ep; u32 ep_cfg; u32 data; if (!dbm) { pr_err("%s: dbm pointer is NULL!\n", __func__); Loading @@ -308,9 +311,6 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer, return -ENODEV; } /* First, reset the dbm endpoint */ ep_soft_reset(dbm, dbm_ep, 0); /* Set ioc bit for dbm_ep if needed */ msm_dbm_write_reg_field(dbm, DBM_DBG_CNFG, DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0); Loading @@ -333,6 +333,10 @@ int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe, bool producer, msm_dbm_write_ep_reg_field(dbm, DBM_EP_CFG, dbm_ep, DBM_EN_EP, 1); data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER); data &= ~(0x1 << dbm_ep); msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data); return dbm_ep; } Loading Loading @@ -377,7 +381,7 @@ int dbm_ep_unconfig(struct dbm *dbm, u8 usb_ep) dbm_ep = find_matching_dbm_ep(dbm, usb_ep); if (dbm_ep < 0) { pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep); pr_debug("usb ep index %d has no corespondng dbm ep\n", usb_ep); return -ENODEV; } Loading @@ -387,23 +391,10 @@ int dbm_ep_unconfig(struct dbm *dbm, u8 usb_ep) data &= (~0x1); msm_dbm_write_ep_reg(dbm, DBM_EP_CFG, dbm_ep, data); /* Reset the dbm endpoint */ ep_soft_reset(dbm, dbm_ep, true); /* * The necessary delay between asserting and deasserting the dbm ep * reset is based on the number of active endpoints. If there is more * than one endpoint, a 1 msec delay is required. Otherwise, a shorter * delay will suffice. * * As this function can be called in atomic context, sleeping variants * for delay are not possible - albeit a 1ms delay. * ep_soft_reset is not required during disconnect as pipe reset on * next connect will take care of the same. */ if (dbm_get_num_of_eps_configured(dbm) > 1) udelay(1000); else udelay(10); ep_soft_reset(dbm, dbm_ep, false); return 0; } Loading Loading @@ -445,6 +436,35 @@ int dbm_event_buffer_config(struct dbm *dbm, u32 addr_lo, u32 addr_hi, int size) return 0; } /** * Disable update xfer before queueing stop xfer command to USB3 core. * * @usb_ep - USB physical EP number. * */ int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep) { u32 data; int dbm_ep; if (!dbm) { pr_err("%s: dbm pointer is NULL!\n", __func__); return -EPERM; } dbm_ep = find_matching_dbm_ep(dbm, usb_ep); if (dbm_ep < 0) { pr_err("usb ep index %d has no corresponding dbm ep\n", usb_ep); return -ENODEV; } data = msm_dbm_read_reg(dbm, DBM_DISABLE_UPDXFER); data |= (0x1 << dbm_ep); msm_dbm_write_reg(dbm, DBM_DISABLE_UPDXFER, data); return 0; } int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr, u32 size, u8 dst_pipe_idx) Loading
drivers/usb/dwc3/dbm.h +1 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,7 @@ int dbm_event_buffer_config(struct dbm *dbm, u32 addr_lo, u32 addr_hi, int size); int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr, u32 size, u8 dst_pipe_idx); int dwc3_dbm_disable_update_xfer(struct dbm *dbm, u8 usb_ep); void dbm_set_speed(struct dbm *dbm, bool speed); void dbm_enable(struct dbm *dbm); int dbm_ep_soft_reset(struct dbm *dbm, u8 usb_ep, bool enter_reset); Loading
drivers/usb/dwc3/dwc3-msm.c +140 −73 Original line number Diff line number Diff line Loading @@ -286,7 +286,8 @@ struct dwc3_msm { static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc); static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA); static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event); static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value); static int dwc3_restart_usb_host_mode(struct notifier_block *nb, unsigned long event, void *ptr); Loading Loading @@ -442,6 +443,16 @@ static inline bool dwc3_msm_is_superspeed(struct dwc3_msm *mdwc) return dwc3_msm_is_dev_superspeed(mdwc); } static int dwc3_msm_dbm_disable_updxfer(struct dwc3 *dwc, u8 usb_ep) { struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); dev_dbg(mdwc->dev, "%s\n", __func__); dwc3_dbm_disable_update_xfer(mdwc->dbm, usb_ep); return 0; } #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) /** * Configure the DBM with the BAM's data fifo. Loading Loading @@ -697,59 +708,89 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep, struct dwc3_msm_req_complete *req_complete; unsigned long flags; int ret = 0, size; u8 bam_pipe; bool producer; bool disable_wb; bool internal_mem; bool ioc; bool superspeed; /* * We must obtain the lock of the dwc3 core driver, * including disabling interrupts, so we will be sure * that we are the only ones that configure the HW device * core and ensure that we queuing the request will finish * as soon as possible so we will release back the lock. */ spin_lock_irqsave(&dwc->lock, flags); if (!dep->endpoint.desc) { dev_err(mdwc->dev, "%s: trying to queue request %pK to disabled ep %s\n", __func__, request, ep->name); spin_unlock_irqrestore(&dwc->lock, flags); return -EPERM; } if (!mdwc->original_ep_ops[dep->number]) { dev_err(mdwc->dev, "ep [%s,%d] was unconfigured as msm endpoint\n", ep->name, dep->number); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } if (!request) { dev_err(mdwc->dev, "%s: request is NULL\n", __func__); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } if (!(request->udc_priv & MSM_SPS_MODE)) { /* Not SPS mode, call original queue */ dev_vdbg(mdwc->dev, "%s: not sps mode, use regular queue\n", dev_err(mdwc->dev, "%s: sps mode is not set\n", __func__); return (mdwc->original_ep_ops[dep->number])->queue(ep, request, gfp_flags); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } /* HW restriction regarding TRB size (8KB) */ if (req->request.length < 0x2000) { dev_err(mdwc->dev, "%s: Min TRB size is 8KB\n", __func__); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } if (dep->number == 0 || dep->number == 1) { dev_err(mdwc->dev, "%s: trying to queue dbm request %pK to ep %s\n", __func__, request, ep->name); spin_unlock_irqrestore(&dwc->lock, flags); return -EPERM; } if (dep->trb_dequeue != dep->trb_enqueue || !list_empty(&dep->pending_list) || !list_empty(&dep->started_list)) { dev_err(mdwc->dev, "%s: trying to queue dbm request %pK tp ep %s\n", __func__, request, ep->name); spin_unlock_irqrestore(&dwc->lock, flags); return -EPERM; } dep->trb_dequeue = 0; dep->trb_enqueue = 0; /* * Override req->complete function, but before doing that, * store it's original pointer in the req_complete_list. */ req_complete = kzalloc(sizeof(*req_complete), gfp_flags); if (!req_complete) if (!req_complete) { dev_err(mdwc->dev, "%s: not enough memory\n", __func__); spin_unlock_irqrestore(&dwc->lock, flags); return -ENOMEM; } req_complete->req = request; req_complete->orig_complete = request->complete; list_add_tail(&req_complete->list_item, &mdwc->req_complete_list); request->complete = dwc3_msm_req_complete_func; /* * Configure the DBM endpoint */ bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK; producer = ((request->udc_priv & MSM_PRODUCER) ? true : false); disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false); internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false); ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false); ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer, disable_wb, internal_mem, ioc); if (ret < 0) { dev_err(mdwc->dev, "error %d after calling dbm_ep_config\n", ret); return ret; } dev_vdbg(dwc->dev, "%s: queing request %p to ep %s length %d\n", __func__, request, ep->name, request->length); size = dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0)); Loading @@ -758,44 +799,6 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep, dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)), DWC3_GEVNTSIZ_SIZE(size)); /* * We must obtain the lock of the dwc3 core driver, * including disabling interrupts, so we will be sure * that we are the only ones that configure the HW device * core and ensure that we queuing the request will finish * as soon as possible so we will release back the lock. */ spin_lock_irqsave(&dwc->lock, flags); if (!dep->endpoint.desc) { dev_err(mdwc->dev, "%s: trying to queue request %p to disabled ep %s\n", __func__, request, ep->name); ret = -EPERM; goto err; } if (dep->number == 0 || dep->number == 1) { dev_err(mdwc->dev, "%s: trying to queue dbm request %p to control ep %s\n", __func__, request, ep->name); ret = -EPERM; goto err; } if (dep->trb_dequeue != dep->trb_enqueue || !list_empty(&dep->pending_list) || !list_empty(&dep->started_list)) { dev_err(mdwc->dev, "%s: trying to queue dbm request %p tp ep %s\n", __func__, request, ep->name); ret = -EPERM; goto err; } else { dep->trb_dequeue = 0; dep->trb_enqueue = 0; } ret = __dwc3_msm_ep_queue(dep, req); if (ret < 0) { dev_err(mdwc->dev, Loading Loading @@ -1471,37 +1474,68 @@ static int dwc3_msm_gsi_ep_op(struct usb_ep *ep, * * @return int - 0 on success, negetive on error. */ int msm_ep_config(struct usb_ep *ep) int msm_ep_config(struct usb_ep *ep, struct usb_request *request) { struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); struct usb_ep_ops *new_ep_ops; int ret = 0; u8 bam_pipe; bool producer; bool disable_wb; bool internal_mem; bool ioc; unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); /* Save original ep ops for future restore*/ if (mdwc->original_ep_ops[dep->number]) { dev_err(mdwc->dev, "ep [%s,%d] already configured as msm endpoint\n", ep->name, dep->number); spin_unlock_irqrestore(&dwc->lock, flags); return -EPERM; } mdwc->original_ep_ops[dep->number] = ep->ops; /* Set new usb ops as we like */ new_ep_ops = kzalloc(sizeof(struct usb_ep_ops), GFP_ATOMIC); if (!new_ep_ops) if (!new_ep_ops) { spin_unlock_irqrestore(&dwc->lock, flags); return -ENOMEM; } (*new_ep_ops) = (*ep->ops); new_ep_ops->queue = dwc3_msm_ep_queue; new_ep_ops->gsi_ep_op = dwc3_msm_gsi_ep_op; ep->ops = new_ep_ops; if (!mdwc->dbm || !request || (dep->endpoint.ep_type == EP_TYPE_GSI)) { spin_unlock_irqrestore(&dwc->lock, flags); return 0; } /* * Do HERE more usb endpoint configurations * which are specific to MSM. * Configure the DBM endpoint if required. */ bam_pipe = request->udc_priv & MSM_PIPE_ID_MASK; producer = ((request->udc_priv & MSM_PRODUCER) ? true : false); disable_wb = ((request->udc_priv & MSM_DISABLE_WB) ? true : false); internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false); ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false); ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer, disable_wb, internal_mem, ioc); if (ret < 0) { dev_err(mdwc->dev, "error %d after calling dbm_ep_config\n", ret); spin_unlock_irqrestore(&dwc->lock, flags); return ret; } spin_unlock_irqrestore(&dwc->lock, flags); return 0; } Loading @@ -1522,12 +1556,15 @@ int msm_ep_unconfig(struct usb_ep *ep) struct dwc3 *dwc = dep->dwc; struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); struct usb_ep_ops *old_ep_ops; unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); /* Restore original ep ops */ if (!mdwc->original_ep_ops[dep->number]) { dev_err(mdwc->dev, "ep [%s,%d] was not configured as msm endpoint\n", ep->name, dep->number); spin_unlock_irqrestore(&dwc->lock, flags); return -EINVAL; } old_ep_ops = (struct usb_ep_ops *)ep->ops; Loading @@ -1539,6 +1576,32 @@ int msm_ep_unconfig(struct usb_ep *ep) * Do HERE more usb endpoint un-configurations * which are specific to MSM. */ if (!mdwc->dbm || (dep->endpoint.ep_type == EP_TYPE_GSI)) { spin_unlock_irqrestore(&dwc->lock, flags); return 0; } if (dep->trb_dequeue == dep->trb_enqueue && list_empty(&dep->pending_list) && list_empty(&dep->started_list)) { dev_dbg(mdwc->dev, "%s: request is not queued, disable DBM ep for ep %s\n", __func__, ep->name); /* Unconfigure dbm ep */ dbm_ep_unconfig(mdwc->dbm, dep->number); /* * If this is the last endpoint we unconfigured, than reset also * the event buffers; unless unconfiguring the ep due to lpm, * in which case the event buffer only gets reset during the * block reset. */ if (dbm_get_num_of_eps_configured(mdwc->dbm) == 0 && !dbm_reset_ep_after_lpm(mdwc->dbm)) dbm_event_buffer_config(mdwc->dbm, 0, 0, 0); } spin_unlock_irqrestore(&dwc->lock, flags); return 0; } Loading Loading @@ -1722,7 +1785,8 @@ static void dwc3_msm_vbus_draw_work(struct work_struct *w) dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw); } static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event) static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value) { struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent); struct dwc3_event_buffer *evt; Loading Loading @@ -1908,6 +1972,9 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event) evt->buf, evt->dma); } break; case DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER: dwc3_msm_dbm_disable_updxfer(dwc, value); break; default: dev_dbg(mdwc->dev, "unknown dwc3 event\n"); break; Loading