diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ed2d8b9a7315..5c892fa3885c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "core.h" #include "gadget.h" @@ -38,11 +39,13 @@ #include "debug.h" -#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ +#define DWC3_DEFAULT_AUTOSUSPEND_DELAY 500 /* ms */ static int count; static struct dwc3 *dwc3_instance[DWC_CTRL_COUNT]; +static void dwc3_check_params(struct dwc3 *dwc); + /** * dwc3_get_dr_mode - Validates and sets dr_mode * @dwc: pointer to our context structure @@ -114,6 +117,7 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode) dwc->current_dr_role = mode; } +EXPORT_SYMBOL(dwc3_set_prtcap); static void __dwc3_set_mode(struct work_struct *work) { @@ -230,8 +234,28 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) int retries = 1000; int ret; - usb_phy_init(dwc->usb2_phy); - usb_phy_init(dwc->usb3_phy); + ret = usb_phy_init(dwc->usb2_phy); + if (ret) { + pr_err("%s: usb_phy_init(dwc->usb2_phy) returned %d\n", + __func__, ret); + return ret; + } + + if (dwc->maximum_speed >= USB_SPEED_SUPER) { + ret = usb_phy_init(dwc->usb3_phy); + if (ret == -EBUSY) { + /* + * Setting Max speed as high when USB3 PHY initialiation + * is failing and USB superspeed can't be supported. + */ + dwc->maximum_speed = USB_SPEED_HIGH; + } else if (ret) { + pr_err("%s: usb_phy_init(dwc->usb3_phy) returned %d\n", + __func__, ret); + return ret; + } + } + ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) return ret; @@ -376,6 +400,9 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) evt = dwc->ev_buf; if (evt) dwc3_free_one_event_buffer(dwc, evt); + + /* free GSI related event buffers */ + dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_FREE, 0); } /** @@ -397,6 +424,8 @@ 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, 0); return 0; } @@ -420,6 +449,8 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc) DWC3_GEVNTSIZ_SIZE(evt->length)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); + /* setup GSI related event buffers */ + dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP, 0); return 0; } @@ -436,6 +467,9 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(0)); dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); + + /* cleanup GSI related event buffers */ + dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEANUP, 0); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) @@ -904,11 +938,24 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) * * Returns 0 on success otherwise negative errno. */ -static int dwc3_core_init(struct dwc3 *dwc) +int dwc3_core_init(struct dwc3 *dwc) { u32 reg; int ret; + if (!dwc3_core_is_valid(dwc)) { + dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); + ret = -ENODEV; + goto err0; + } + + dwc3_cache_hwparams(dwc); + ret = dwc3_get_dr_mode(dwc); + if (ret) { + ret = -EINVAL; + goto err0; + } + /* * Write Linux Version Code to our GUID register so it's easy to figure * out which kernel version a bug was found. @@ -957,7 +1004,9 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_set_incr_burst_type(dwc); usb_phy_set_suspend(dwc->usb2_phy, 0); - usb_phy_set_suspend(dwc->usb3_phy, 0); + if (dwc->maximum_speed >= USB_SPEED_SUPER) + usb_phy_set_suspend(dwc->usb3_phy, 0); + ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) goto err2; @@ -966,12 +1015,6 @@ static int dwc3_core_init(struct dwc3 *dwc) if (ret < 0) goto err3; - ret = dwc3_event_buffers_setup(dwc); - if (ret) { - dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err4; - } - /* * ENDXFER polling is available on version 3.10a and later of * the DWC_usb3 controller. It is NOT available in the @@ -1059,10 +1102,9 @@ static int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } - return 0; + dwc3_check_params(dwc); -err4: - phy_power_off(dwc->usb3_generic_phy); + return 0; err3: phy_power_off(dwc->usb2_generic_phy); @@ -1070,6 +1112,7 @@ err3: err2: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); + dwc3_free_scratch_buffers(dwc); err1: usb_phy_shutdown(dwc->usb2_phy); @@ -1083,6 +1126,7 @@ err0a: err0: return ret; } +EXPORT_SYMBOL(dwc3_core_init); static int dwc3_core_get_phy(struct dwc3 *dwc) { @@ -1151,7 +1195,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) return 0; } -static int dwc3_core_init_mode(struct dwc3 *dwc) +static int __maybe_unused dwc3_core_init_mode(struct dwc3 *dwc) { struct device *dev = dwc->dev; int ret; @@ -1204,7 +1248,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) return 0; } -static void dwc3_core_exit_mode(struct dwc3 *dwc) +static void __maybe_unused dwc3_core_exit_mode(struct dwc3 *dwc) { switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: @@ -1222,6 +1266,29 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) } } +static void (*notify_event)(struct dwc3 *, + enum dwc3_notify_event, unsigned int); +void dwc3_set_notifier(void (*notify)(struct dwc3 *, enum dwc3_notify_event, + unsigned int)) +{ + notify_event = notify; +} +EXPORT_SYMBOL(dwc3_set_notifier); + +int dwc3_notify_event(struct dwc3 *dwc, enum dwc3_notify_event event, + unsigned int value) +{ + int ret = 0; + + if (notify_event) + notify_event(dwc, event, value); + else + ret = -ENODEV; + + return ret; +} +EXPORT_SYMBOL(dwc3_notify_event); + static void dwc3_get_properties(struct dwc3 *dwc) { struct device *dev = dwc->dev; @@ -1246,6 +1313,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) hird_threshold = 12; dwc->maximum_speed = usb_get_maximum_speed(dev); + dwc->max_hw_supp_speed = dwc->maximum_speed; dwc->dr_mode = usb_get_dr_mode(dev); dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node); @@ -1322,6 +1390,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) &dwc->hsphy_interface); device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); + dwc->enable_bus_suspend = device_property_read_bool(dev, + "snps,bus-suspend-enable"); dwc->dis_metastability_quirk = device_property_read_bool(dev, "snps,dis_metastability_quirk"); @@ -1410,6 +1480,14 @@ static int dwc3_probe(struct platform_device *pdev) int ret; void __iomem *regs; + int irq; + + if (count >= DWC_CTRL_COUNT) { + dev_err(dev, "Err dwc instance %d >= %d available\n", + count, DWC_CTRL_COUNT); + ret = -EINVAL; + return ret; + } dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); if (!dwc) @@ -1421,19 +1499,34 @@ static int dwc3_probe(struct platform_device *pdev) return -ENOMEM; dwc->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } + dwc->reg_phys = res->start; dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; + irq = platform_get_irq(to_platform_device(dwc->dev), 0); + + ret = devm_request_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3", + dwc); + if (ret) { + dev_err(dwc->dev, "failed to request irq #%d --> %d\n", + irq, ret); + return -ENODEV; + } + + if (notify_event) + /* will be enabled in dwc3_msm_resume() */ + disable_irq(irq); + + dwc->irq = irq; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. @@ -1445,6 +1538,14 @@ static int dwc3_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); + dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI); + if (!dwc->dwc_wq) { + dev_err(dev, + "%s: Unable to create workqueue dwc_wq\n", __func__); + goto err0; + } + + INIT_WORK(&dwc->bh_work, dwc3_bh_work); dwc->regs = regs; dwc->regs_size = resource_size(&dwc_res); @@ -1459,7 +1560,7 @@ static int dwc3_probe(struct platform_device *pdev) ret = devm_clk_bulk_get(dev, dwc->num_clks, dwc->clks); if (ret == -EPROBE_DEFER) - return ret; + goto err0; /* * Clocks are optional, but new DT platforms should support all * clocks as required by the DT-binding. @@ -1470,61 +1571,59 @@ static int dwc3_probe(struct platform_device *pdev) ret = reset_control_deassert(dwc->reset); if (ret) - return ret; + goto err0; ret = clk_bulk_prepare_enable(dwc->num_clks, dwc->clks); if (ret) goto assert_reset; - if (!dwc3_core_is_valid(dwc)) { - dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); - ret = -ENODEV; - goto disable_clks; - } - platform_set_drvdata(pdev, dwc); - dwc3_cache_hwparams(dwc); spin_lock_init(&dwc->lock); + pm_runtime_no_callbacks(dev); pm_runtime_set_active(dev); - pm_runtime_use_autosuspend(dev); - pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); + if (dwc->enable_bus_suspend) { + pm_runtime_set_autosuspend_delay(dev, + DWC3_DEFAULT_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + } pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); - if (ret < 0) - goto err1; - pm_runtime_forbid(dev); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; - goto err2; + goto err1; } - ret = dwc3_get_dr_mode(dwc); - if (ret) - goto err3; - ret = dwc3_alloc_scratch_buffers(dwc); if (ret) - goto err3; + goto err2; - ret = dwc3_core_init(dwc); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to initialize core: %d\n", ret); - goto err4; + if (!notify_event) { + ret = dwc3_core_init(dwc); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to initialize core: %d\n", + ret); + goto err3; + } + + ret = dwc3_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + goto err3; + } + + ret = dwc3_core_init_mode(dwc); + if (ret) { + dwc3_event_buffers_cleanup(dwc); + goto err3; + } } - dwc3_check_params(dwc); - - ret = dwc3_core_init_mode(dwc); - if (ret) - goto err5; - dwc3_debugfs_init(dwc); dwc->dwc_ipc_log_ctxt = ipc_log_context_create(NUM_LOG_PAGES, @@ -1536,32 +1635,22 @@ static int dwc3_probe(struct platform_device *pdev) dwc->index = count; count++; - pm_runtime_put(dev); - + pm_runtime_allow(dev); return 0; -err5: - dwc3_event_buffers_cleanup(dwc); - dwc3_ulpi_exit(dwc); - -err4: - dwc3_free_scratch_buffers(dwc); - err3: - dwc3_free_event_buffers(dwc); - + dwc3_free_scratch_buffers(dwc); err2: - pm_runtime_allow(&pdev->dev); - + dwc3_free_event_buffers(dwc); err1: - pm_runtime_put_sync(&pdev->dev); + pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); -disable_clks: clk_bulk_disable_unprepare(dwc->num_clks, dwc->clks); assert_reset: reset_control_assert(dwc->reset); - + destroy_workqueue(dwc->dwc_wq); +err0: return ret; } @@ -1569,15 +1658,8 @@ static int dwc3_remove(struct platform_device *pdev) { struct dwc3 *dwc = platform_get_drvdata(pdev); - pm_runtime_get_sync(&pdev->dev); - dwc3_debugfs_exit(dwc); - dwc3_core_exit_mode(dwc); - dwc3_core_exit(dwc); - dwc3_ulpi_exit(dwc); - - pm_runtime_put_sync(&pdev->dev); pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1764,6 +1846,10 @@ static int dwc3_runtime_suspend(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(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, 0)) + return 0; + if (dwc3_runtime_checks(dwc)) return -EBUSY; @@ -1781,6 +1867,10 @@ static int dwc3_runtime_resume(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(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, 0)) + return 0; + device_init_wakeup(dev, false); ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); @@ -1830,6 +1920,10 @@ static int dwc3_suspend(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(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, 0)) + return 0; + ret = dwc3_suspend_common(dwc, PMSG_SUSPEND); if (ret) return ret; @@ -1844,6 +1938,10 @@ static int dwc3_resume(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(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, 0)) + return 0; + pinctrl_pm_select_default_state(dev); ret = dwc3_resume_common(dwc, PMSG_RESUME); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index ad21dd7fac1a..6e096b33b458 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -162,8 +162,20 @@ #define DWC3_OEVTEN 0xcc0C #define DWC3_OSTS 0xcc10 +/* DWC 3.1 Link Registers */ +#define DWC31_LINK_LU3LFPSRXTIM(n) (0xd010 + ((n) * 0x80)) +#define GEN2_U3_EXIT_RSP_RX_CLK(n) ((n) << 16) +#define GEN2_U3_EXIT_RSP_RX_CLK_MASK GEN2_U3_EXIT_RSP_RX_CLK(0xff) +#define GEN1_U3_EXIT_RSP_RX_CLK(n) (n) +#define GEN1_U3_EXIT_RSP_RX_CLK_MASK GEN1_U3_EXIT_RSP_RX_CLK(0xff) +#define DWC31_LINK_GDBGLTSSM 0xd050 + /* Bit fields */ +/* Global SoC Bus Configuration Register 1 */ +#define DWC3_GSBUSCFG1_PIPETRANSLIMIT_MASK (0x0f << 8) +#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n) ((n) << 8) + /* Global SoC Bus Configuration INCRx Register 0 */ #define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */ #define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */ @@ -265,6 +277,9 @@ #define DWC3_GSTS_CURMOD_DEVICE 0 #define DWC3_GSTS_CURMOD_HOST 1 +/* Global Debug LTSSM Register */ +#define DWC3_GDBGLTSSM_LINKSTATE_MASK (0xF << 22) + /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31) #define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30) @@ -294,6 +309,7 @@ #define DWC3_GUSB3PIPECTL_DISRXDETINP3 BIT(28) #define DWC3_GUSB3PIPECTL_UX_EXIT_PX BIT(27) #define DWC3_GUSB3PIPECTL_REQP1P2P3 BIT(24) +#define DWC3_GUSB3PIPECTL_DISRXDETU3 BIT(22) #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) #define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1) @@ -303,6 +319,7 @@ #define DWC3_GUSB3PIPECTL_RX_DETOPOLL BIT(8) #define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3) #define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1) +#define DWC3_GUSB3PIPECTL_DELAYP1TRANS BIT(18) /* Global TX Fifo Size Register */ #define DWC31_GTXFIFOSIZ_TXFRAMNUM BIT(15) /* DWC_usb31 only */ @@ -483,6 +500,7 @@ #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO 0x04 #define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI 0x05 +#define DWC3_DGCMD_XMIT_DEV 0x07 #define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09 #define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c @@ -683,10 +701,13 @@ struct dwc3_ep_events { * @pending_list: list of pending requests for this endpoint * @started_list: list of started requests on this endpoint * @regs: pointer to first endpoint register + * @trb_dma_pool: dma pool used to get aligned trb memory pool * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool + * @num_trbs: num of trbs in the trb dma pool * @trb_enqueue: enqueue 'pointer' into TRB array * @trb_dequeue: dequeue 'pointer' into TRB array + * @desc: usb_endpoint_descriptor pointer * @dwc: pointer to DWC controller * @saved_state: ep state saved during hibernation * @flags: endpoint flags (wedged, stalled, ...) @@ -714,8 +735,10 @@ struct dwc3_ep { void __iomem *regs; + struct dma_pool *trb_dma_pool; struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; + u32 num_trbs; struct dwc3 *dwc; u32 saved_state; @@ -751,6 +774,7 @@ struct dwc3_ep { unsigned direction:1; unsigned stream_capable:1; + unsigned gsi:1; /* For isochronous START TRANSFER workaround only */ u8 combo_num; @@ -759,6 +783,7 @@ struct dwc3_ep { struct dwc3_ep_events dbg_ep_events; struct dwc3_ep_events dbg_ep_events_diff; ktime_t dbg_ep_events_kt; + int fifo_depth; }; enum dwc3_phy { @@ -946,7 +971,7 @@ struct dwc3_scratchpad_array { __le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS]; }; -#define MAX_INTR_STATS 10 +#define MAX_INTR_STATS 10 /** * struct dwc3 - representation of our controller @@ -980,9 +1005,11 @@ struct dwc3_scratchpad_array { * @current_otg_role: current role of operation while using the OTG block * @desired_otg_role: desired role of operation while using the OTG block * @otg_restart_host: flag that OTG controller needs to restart host + * @reg_phys: physical base address of dwc3 core register address space * @nr_scratch: number of scratch buffers * @u1u2: only used on revisions <1.83a for workaround - * @maximum_speed: maximum speed requested (mainly for testing purposes) + * @maximum_speed: maximum speed to operate as requested by sw + * @max_hw_supp_speed: maximum speed supported by hw design * @revision: revision register contents * @version_type: VERSIONTYPE register contents, a sub release of a revision * @dr_mode: requested mode of operation @@ -1071,6 +1098,14 @@ struct dwc3_scratchpad_array { * 2 - No de-emphasis * 3 - Reserved * @dis_metastability_quirk: set to disable metastability quirk. + * @err_evt_seen: previous event in queue was erratic error + * @in_lpm: indicates if controller is in low power mode (no clocks) + * @irq: irq number + * @irq_cnt: total irq count + * @bh_completion_time: time taken for IRQ bottom-half completion + * @bh_handled_evt_cnt: no. of events handled per IRQ bottom-half + * @irq_dbg_index: index for capturing IRQ stats + * @vbus_draw: current to be drawn from USB * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @xhci_imod_value: imod value to use with xhci @@ -1126,6 +1161,7 @@ struct dwc3 { void __iomem *regs; size_t regs_size; + phys_addr_t reg_phys; enum usb_dr_mode dr_mode; u32 current_dr_role; @@ -1143,6 +1179,7 @@ struct dwc3 { u32 nr_scratch; u32 u1u2; u32 maximum_speed; + u32 max_hw_supp_speed; /* * All 3.1 IP version constants are greater than the 3.0 IP @@ -1265,24 +1302,42 @@ struct dwc3 { unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; + unsigned err_evt_seen:1; + unsigned enable_bus_suspend:1; + + atomic_t in_lpm; + bool b_suspend; + unsigned int vbus_draw; unsigned dis_metastability_quirk:1; u16 imod_interval; u32 xhci_imod_value; + struct workqueue_struct *dwc_wq; + struct work_struct bh_work; + + unsigned long ep_cmd_timeout_cnt; + unsigned int index; void *dwc_ipc_log_ctxt; struct dwc3_gadget_events dbg_gadget_events; /* IRQ timing statistics */ + int irq; unsigned long irq_cnt; unsigned int bh_completion_time[MAX_INTR_STATS]; unsigned int bh_handled_evt_cnt[MAX_INTR_STATS]; ktime_t irq_start_time[MAX_INTR_STATS]; + ktime_t t_pwr_evt_irq; unsigned int irq_completion_time[MAX_INTR_STATS]; unsigned int irq_event_count[MAX_INTR_STATS]; unsigned int irq_dbg_index; + + /* Indicate if the gadget was powered by the otg driver */ + unsigned int vbus_active:1; + /* Indicate if software connect was issued by the usb_gadget_driver */ + unsigned int softconnect:1; }; #define INCRX_BURST_MODE 0 @@ -1483,11 +1538,16 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param); +void dwc3_gadget_disable_irq(struct dwc3 *dwc); +int dwc3_core_init(struct dwc3 *dwc); +int dwc3_event_buffers_setup(struct dwc3 *dwc); #else static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; } static inline void dwc3_gadget_exit(struct dwc3 *dwc) { } +static inline void dwc3_gadget_restart(struct dwc3 *dwc) +{ } static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) { return 0; } static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc) @@ -1502,6 +1562,12 @@ static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { return 0; } +static inline void dwc3_gadget_disable_irq(struct dwc3 *dwc) +{ } +static int dwc3_core_init(struct dwc3 *dwc) +{ return 0; } +static int dwc3_event_buffers_setup(struct dwc3 *dwc) +{ return 0; } #endif #if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) @@ -1557,4 +1623,29 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc) { } #endif +enum dwc3_notify_event { + DWC3_CONTROLLER_ERROR_EVENT, + DWC3_CONTROLLER_RESET_EVENT, + DWC3_CONTROLLER_POST_RESET_EVENT, + DWC3_CORE_PM_SUSPEND_EVENT, + DWC3_CORE_PM_RESUME_EVENT, + DWC3_CONTROLLER_CONNDONE_EVENT, + DWC3_CONTROLLER_NOTIFY_OTG_EVENT, + DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, + DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER, + + /* USB GSI event buffer related notification */ + DWC3_GSI_EVT_BUF_ALLOC, + DWC3_GSI_EVT_BUF_SETUP, + DWC3_GSI_EVT_BUF_CLEANUP, + DWC3_GSI_EVT_BUF_CLEAR, + DWC3_GSI_EVT_BUF_FREE, + DWC3_CONTROLLER_NOTIFY_CLEAR_DB, +}; + +extern void dwc3_set_notifier(void (*notify)(struct dwc3 *dwc3, + enum dwc3_notify_event event, + unsigned int value)); +extern int dwc3_notify_event(struct dwc3 *dwc3, enum dwc3_notify_event event, + unsigned int value); #endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/drivers/usb/dwc3/debug_ipc.c b/drivers/usb/dwc3/debug_ipc.c index b6942466af0f..247d3cd4e61b 100644 --- a/drivers/usb/dwc3/debug_ipc.c +++ b/drivers/usb/dwc3/debug_ipc.c @@ -52,6 +52,7 @@ void dwc3_dbg_print(struct dwc3 *dwc, u8 ep_num, const char *name, ipc_log_string(dwc->dwc_ipc_log_ctxt, "%02X %-25.25s %4i ?\t%s", ep_num, name, status, extra); } +EXPORT_SYMBOL(dwc3_dbg_print); /** * dwc3_dbg_done: prints a DONE event diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 88cca1179633..7c419447bea3 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -331,6 +331,11 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused) unsigned long flags; u32 reg; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GSTS); current_mode = DWC3_GSTS_CURMOD(reg); @@ -394,6 +399,11 @@ static int dwc3_mode_show(struct seq_file *s, void *unused) unsigned long flags; u32 reg; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GCTL); spin_unlock_irqrestore(&dwc->lock, flags); @@ -428,6 +438,11 @@ static ssize_t dwc3_mode_write(struct file *file, u32 mode = 0; char buf[32] = {}; + if (atomic_read(&dwc->in_lpm)) { + dev_err(dwc->dev, "USB device is powered off\n"); + return count; + } + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; @@ -459,6 +474,11 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused) unsigned long flags; u32 reg; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= DWC3_DCTL_TSTCTRL_MASK; @@ -505,6 +525,11 @@ static ssize_t dwc3_testmode_write(struct file *file, u32 testmode = 0; char buf[32] = {}; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; @@ -544,6 +569,11 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) u32 reg; u8 speed; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); reg = dwc3_readl(dwc->regs, DWC3_GSTS); if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) { @@ -580,6 +610,11 @@ static ssize_t dwc3_link_state_write(struct file *file, u32 reg; u8 speed; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; @@ -640,6 +675,11 @@ static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_TXFIFO); @@ -659,6 +699,11 @@ static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXFIFO); @@ -693,6 +738,11 @@ static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXREQQ); seq_printf(s, "%u\n", val); @@ -708,6 +758,11 @@ static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ); seq_printf(s, "%u\n", val); @@ -723,6 +778,11 @@ static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ); seq_printf(s, "%u\n", val); @@ -738,6 +798,11 @@ static int dwc3_event_queue_show(struct seq_file *s, void *unused) unsigned long flags; u32 val; + if (atomic_read(&dwc->in_lpm)) { + seq_puts(s, "USB device is powered off\n"); + return 0; + } + spin_lock_irqsave(&dwc->lock, flags); val = dwc3_core_fifo_space(dep, DWC3_EVENTQ); seq_printf(s, "%u\n", val); @@ -1052,6 +1117,11 @@ static int dwc3_gadget_int_events_show(struct seq_file *s, void *unused) seq_printf(s, "%d\t", dwc->bh_completion_time[i]); seq_putc(s, '\n'); + seq_printf(s, "t_pwr evt irq : %lld\n", + ktime_to_us(dwc->t_pwr_evt_irq)); + + seq_printf(s, "ep_cmd_timeout_cnt : %lu\n", dwc->ep_cmd_timeout_cnt); + spin_unlock_irqrestore(&dwc->lock, flags); return 0; } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 2d914db9f0b0..a13cf466b9bf 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -248,6 +248,7 @@ int __dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) struct dwc3_ep *dep = to_dwc3_ep(ep); struct dwc3 *dwc = dep->dwc; + dbg_event(dep->number, "EP0STAL", value); dwc3_ep0_stall_and_restart(dwc); return 0; @@ -278,7 +279,8 @@ 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 (WARN_ON(ret < 0)) + dbg_event(dwc->eps[0]->number, "EOUTSTART", ret); } static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) @@ -691,7 +693,8 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) /* now that we have the time, issue DGCMD Set Sel */ ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_SET_PERIODIC_PAR, param); - WARN_ON(ret < 0); + if (WARN_ON(ret < 0)) + dbg_event(dep->number, "ESET_SELCMPL", ret); } static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) @@ -803,6 +806,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, dwc->ep0_next_event = DWC3_EP0_NRDY_DATA; } + dbg_setup(0x00, ctrl); if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) ret = dwc3_ep0_std_request(dwc, ctrl); else @@ -812,8 +816,16 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, dwc->delayed_status = true; out: - if (ret < 0) + /* + * Don't try to halt ep0 if ret is -ESHUTDOWN. + * ret as -ESHUTDOWN suggests that setup packet related response + * is available but queueing of ep0 is failed. Possibly ep0 is + * already disabled. + */ + if (ret < 0 && ret != -ESHUTDOWN) { + dbg_event(0x0, "ERRSTAL", ret); dwc3_ep0_stall_and_restart(dwc); + } } static void dwc3_ep0_complete_data(struct dwc3 *dwc, @@ -842,10 +854,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, status = DWC3_TRB_SIZE_TRBSTS(trb->size); if (status == DWC3_TRBSTS_SETUP_PENDING) { dwc->setup_packet_pending = true; - if (r) - dwc3_gadget_giveback(ep0, r, -ECONNRESET); - - return; + dbg_event(0x0, "SETUPPEND", status); } ur = &r->request; @@ -868,10 +877,13 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, dwc->ep0_bounced = false; } - if ((epnum & 1) && ur->actual < ur->length) + if ((epnum & 1) && ur->actual < ur->length) { + /* for some reason we did not get everything out */ + dbg_event(epnum, "INDATSTAL", 0); dwc3_ep0_stall_and_restart(dwc); - else + } else { dwc3_gadget_giveback(ep0, r, 0); + } } static void dwc3_ep0_complete_status(struct dwc3 *dwc, @@ -900,6 +912,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, if (ret < 0) { dev_err(dwc->dev, "invalid test #%d\n", dwc->test_mode_nr); + dbg_event(0x00, "INVALTEST", ret); dwc3_ep0_stall_and_restart(dwc); return; } @@ -909,6 +922,7 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, if (status == DWC3_TRBSTS_SETUP_PENDING) dwc->setup_packet_pending = true; + dbg_print(dep->number, "DONE", status, "STATUS"); dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); } @@ -1015,6 +1029,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, } WARN_ON(ret < 0); + dbg_queue(dep->number, &req->request, ret); } static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) @@ -1031,7 +1046,11 @@ 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 (WARN_ON_ONCE(ret)) + dbg_event(dep->number, "ECTRLSTATUS", ret); } static void dwc3_ep0_do_control_status(struct dwc3 *dwc, @@ -1056,7 +1075,11 @@ static 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_dbg(dwc->dev, "%s: send ep cmd ENDTRANSFER failed", + dep->name); + dbg_event(dep->number, "EENDXFER", ret); + } dep->resource_index = 0; } @@ -1087,6 +1110,7 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, dev_err(dwc->dev, "unexpected direction for Data Phase\n"); dwc3_ep0_end_control_data(dwc, dep); + dbg_event(epnum, "WRONGDR", 0); dwc3_ep0_stall_and_restart(dwc); return; } @@ -1103,7 +1127,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, if (dwc->delayed_status) { struct dwc3_ep *dep = dwc->eps[0]; - WARN_ON_ONCE(event->endpoint_number != 1); + if (event->endpoint_number != 1) + dbg_event(epnum, "EEPNUM", event->status); /* * We should handle the delay STATUS phase here if the * request for handling delay STATUS has been queued diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 53382101d5da..90477d670250 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -30,6 +30,9 @@ #define DWC3_ALIGN_FRAME(d, n) (((d)->frame_number + ((d)->interval * (n))) \ & ~((d)->interval - 1)) +static int __dwc3_gadget_start(struct dwc3 *dwc); +static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc); + /** * dwc3_gadget_set_test_mode - enables usb2 test modes * @dwc: pointer to our context structure @@ -187,9 +190,6 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, req->trb = NULL; trace_dwc3_gadget_giveback(req); - - if (dep->number > 1) - pm_runtime_put(dwc->dev); } /** @@ -270,7 +270,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, { const struct usb_endpoint_descriptor *desc = dep->endpoint.desc; struct dwc3 *dwc = dep->dwc; - u32 timeout = 1000; + u32 timeout = 3000; u32 saved_config = 0; u32 reg; @@ -379,6 +379,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, if (timeout == 0) { ret = -ETIMEDOUT; + dev_err(dwc->dev, "%s command timeout for %s\n", + dwc3_gadget_ep_cmd_string(cmd), dep->name); + dwc->ep_cmd_timeout_cnt++; cmd_status = -ETIMEDOUT; } @@ -397,6 +400,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, return ret; } +EXPORT_SYMBOL(dwc3_send_gadget_ep_cmd); static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) { @@ -421,14 +425,6 @@ static int dwc3_send_clear_stall_ep_cmd(struct dwc3_ep *dep) return dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms); } -static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, - struct dwc3_trb *trb) -{ - u32 offset = (char *) trb - (char *) dep->trb_pool; - - return dep->trb_pool_dma + offset; -} - static int dwc3_alloc_trb_pool(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; @@ -444,6 +440,7 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep) dep->name); return -ENOMEM; } + dep->num_trbs = DWC3_TRB_NUM; return 0; } @@ -452,11 +449,27 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; - dma_free_coherent(dwc->sysdev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM, - dep->trb_pool, dep->trb_pool_dma); + /* Freeing of GSI EP TRBs are handled by GSI EP ops. */ + if (dep->gsi) + return; - dep->trb_pool = NULL; - dep->trb_pool_dma = 0; + /* + * Clean up ep ring to avoid getting xferInProgress due to stale trbs + * with HWO bit set from previous composition when update transfer cmd + * is issued. + */ + if (dep->number > 1 && dep->trb_pool && dep->trb_pool_dma) { + memset(&dep->trb_pool[0], 0, + sizeof(struct dwc3_trb) * dep->num_trbs); + dbg_event(dep->number, "Clr_TRB", 0); + dev_dbg(dwc->dev, "Clr_TRB ring of %s\n", dep->name); + + dma_free_coherent(dwc->sysdev, + sizeof(struct dwc3_trb) * DWC3_TRB_NUM, + dep->trb_pool, dep->trb_pool_dma); + dep->trb_pool = NULL; + dep->trb_pool_dma = 0; + } } static int dwc3_gadget_set_xfer_resource(struct dwc3_ep *dep) @@ -618,13 +631,18 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) if (!(dep->flags & DWC3_EP_ENABLED)) { ret = dwc3_gadget_start_config(dep); - if (ret) + if (ret) { + dev_err(dwc->dev, "start_config() failed for %s\n", + dep->name); return ret; + } } ret = dwc3_gadget_set_ep_config(dep, action); - if (ret) + if (ret) { + dev_err(dwc->dev, "set_ep_config() failed for %s\n", dep->name); return ret; + } if (!(dep->flags & DWC3_EP_ENABLED)) { struct dwc3_trb *trb_st_hw; @@ -687,8 +705,6 @@ out: return 0; } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, - bool interrupt); static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; @@ -792,6 +808,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); + dbg_event(dep->number, "ENABLE", ret); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -819,6 +836,7 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep) spin_lock_irqsave(&dwc->lock, flags); ret = __dwc3_gadget_ep_disable(dep); + dbg_event(dep->number, "DISABLE", ret); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -1215,6 +1233,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; struct dwc3_request *req; + struct dwc3 *dwc = dep->dwc; int starting; int ret; u32 cmd; @@ -1228,6 +1247,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep) req = next_request(&dep->started_list); if (!req) { dep->flags |= DWC3_EP_PENDING_REQUEST; + dbg_event(dep->number, "NO REQ", 0); return 0; } @@ -1438,8 +1458,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) dep->name, &req->request)) return -EINVAL; - pm_runtime_get(dwc->dev); - req->request.actual = 0; req->request.status = -EINPROGRESS; @@ -1537,6 +1555,11 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, unsigned long flags; int ret = 0; + if (atomic_read(&dwc->in_lpm)) { + dev_err(dwc->dev, "Unable to dequeue while in LPM\n"); + return -EAGAIN; + } + trace_dwc3_ep_dequeue(req); spin_lock_irqsave(&dwc->lock, flags); @@ -1571,6 +1594,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, } out1: + dbg_event(dep->number, "DEQUEUE", 0); dwc3_gadget_giveback(dep, req, -ECONNRESET); out0: @@ -1585,13 +1609,18 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) struct dwc3 *dwc = dep->dwc; int ret; + if (!dep->endpoint.desc) { + dev_dbg(dwc->dev, "(%s)'s desc is NULL.\n", dep->name); + return -EINVAL; + } + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name); return -EINVAL; } memset(¶ms, 0x00, sizeof(params)); - + dbg_event(dep->number, "HALT", value); if (value) { struct dwc3_trb *trb; @@ -1655,6 +1684,7 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) int ret; spin_lock_irqsave(&dwc->lock, flags); + dbg_event(dep->number, "WEDGE", 0); dep->flags |= DWC3_EP_WEDGE; if (dep->number == 0 || dep->number == 1) @@ -1797,14 +1827,34 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, return 0; } +static void dwc3_stop_active_transfers(struct dwc3 *dwc) +{ + u32 epnum; + + for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { + struct dwc3_ep *dep; + + dep = dwc->eps[epnum]; + if (!dep) + continue; + + if (!(dep->flags & DWC3_EP_ENABLED)) + continue; + + if (dep->gsi && dep->direction) + dwc3_notify_event(dwc, + DWC3_CONTROLLER_NOTIFY_CLEAR_DB, 0); + + dwc3_remove_requests(dwc, dep); + } +} + static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) { u32 reg; - u32 timeout = 500; - - if (pm_runtime_suspended(dwc->dev)) - return 0; + u32 timeout = 1500; + dbg_event(0xFF, "run_stop", is_on); reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (is_on) { if (dwc->revision <= DWC3_REVISION_187A) { @@ -1814,6 +1864,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) if (dwc->revision >= DWC3_REVISION_194A) reg &= ~DWC3_DCTL_KEEP_CONNECT; + + dwc3_event_buffers_setup(dwc); + __dwc3_gadget_start(dwc); + reg |= DWC3_DCTL_RUN_STOP; if (dwc->has_hibernation) @@ -1821,6 +1875,19 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) dwc->pullups_connected = true; } else { + dwc3_gadget_disable_irq(dwc); + __dwc3_gadget_ep_disable(dwc->eps[0]); + __dwc3_gadget_ep_disable(dwc->eps[1]); + + /* + * According to dwc3 databook, it is must to remove any active + * transfers before trying to stop USB device controller. Hence + * call dwc3_stop_active_transfers() API before stopping USB + * device controller. + */ + dwc3_stop_active_transfers(dwc); + dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEAR, 0); + reg &= ~DWC3_DCTL_RUN_STOP; if (dwc->has_hibernation && !suspend) @@ -1836,9 +1903,30 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) reg &= DWC3_DSTS_DEVCTRLHLT; } while (--timeout && !(!is_on ^ !reg)); - if (!timeout) - return -ETIMEDOUT; + if (!is_on) + dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, 0); + if (!timeout) { + dev_err(dwc->dev, "failed to %s controller\n", + is_on ? "start" : "stop"); + if (is_on) + dbg_event(0xFF, "STARTTOUT", reg); + else + dbg_event(0xFF, "STOPTOUT", reg); + return -ETIMEDOUT; + } + + return 0; +} + +static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + + dwc->vbus_draw = mA; + dev_dbg(dwc->dev, "Notify controller from %s. mA = %u\n", __func__, mA); + dbg_event(0xFF, "currentDraw", mA); + dwc3_notify_event(dwc, DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT, 0); return 0; } @@ -1849,6 +1937,21 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) int ret; is_on = !!is_on; + dwc->softconnect = is_on; + + if (((dwc->dr_mode == USB_DR_MODE_OTG) && !dwc->vbus_active) + || !dwc->gadget_driver) { + /* + * Need to wait for vbus_session(on) from otg driver or to + * the udc_start. + */ + dbg_event(0xFF, "WaitPullup", 0); + return 0; + } + + pm_runtime_get_sync(dwc->dev); + dbg_event(0xFF, "Pullup gsync", + atomic_read(&dwc->dev->power.usage_count)); /* * Per databook, when we want to stop the gadget, if a control transfer @@ -1866,9 +1969,21 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) } spin_lock_irqsave(&dwc->lock, flags); + /* + * If we are here after bus suspend notify otg state machine to + * increment pm usage count of dwc to prevent pm_runtime_suspend + * during enumeration. + */ + dwc->b_suspend = false; + dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0); + ret = dwc3_gadget_run_stop(dwc, is_on, false); spin_unlock_irqrestore(&dwc->lock, flags); + pm_runtime_mark_last_busy(dwc->dev); + pm_runtime_put_autosuspend(dwc->dev); + dbg_event(0xFF, "Pullup put", + atomic_read(&dwc->dev->power.usage_count)); return ret; } @@ -1876,6 +1991,7 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc) { u32 reg; + dbg_event(0xFF, "UnmaskINT", 0); /* Enable all but Start and End of Frame IRQs */ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | DWC3_DEVTEN_EVNTOVERFLOWEN | @@ -1886,19 +2002,25 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc) DWC3_DEVTEN_USBRSTEN | DWC3_DEVTEN_DISCONNEVTEN); - if (dwc->revision < DWC3_REVISION_250A) + /* + * Enable SUSPENDEVENT(BIT:6) for version 230A and above + * else enable USB Link change event (BIT:3) for older version + */ + if (dwc->revision < DWC3_REVISION_230A) reg |= DWC3_DEVTEN_ULSTCNGEN; + else + reg |= DWC3_DEVTEN_EOPFEN; dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); } -static void dwc3_gadget_disable_irq(struct dwc3 *dwc) +void dwc3_gadget_disable_irq(struct dwc3 *dwc) { + dbg_event(0xFF, "MaskINT", 0); /* mask all interrupts */ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); } -static irqreturn_t dwc3_interrupt(int irq, void *_dwc); static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc); /** @@ -1942,12 +2064,59 @@ static void dwc3_gadget_setup_nump(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCFG, reg); } +static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active) +{ + struct dwc3 *dwc = gadget_to_dwc(_gadget); + unsigned long flags; + + if (dwc->dr_mode != USB_DR_MODE_OTG) + return -EPERM; + + is_active = !!is_active; + + dbg_event(0xFF, "VbusSess", is_active); + spin_lock_irqsave(&dwc->lock, flags); + + /* Mark that the vbus was powered */ + dwc->vbus_active = is_active; + + /* + * Check if upper level usb_gadget_driver was already registered with + * this udc controller driver (if dwc3_gadget_start was called) + */ + if (dwc->gadget_driver && dwc->softconnect) { + if (dwc->vbus_active) { + /* + * Both vbus was activated by otg and pullup was + * signaled by the gadget driver. + */ + dwc3_gadget_run_stop(dwc, 1, false); + } else { + dwc3_gadget_run_stop(dwc, 0, false); + } + } + + /* + * Clearing run/stop bit might occur before disconnect event is seen. + * Make sure to let gadget driver know in that case. + */ + if (!dwc->vbus_active) { + dev_dbg(dwc->dev, "calling disconnect from %s\n", __func__); + dwc3_gadget_disconnect_interrupt(dwc); + } + + spin_unlock_irqrestore(&dwc->lock, flags); + return 0; +} + static int __dwc3_gadget_start(struct dwc3 *dwc) { struct dwc3_ep *dep; int ret = 0; u32 reg; + dbg_event(0xFF, "__Gadgetstart", 0); + /* * Use IMOD if enabled via dwc->imod_interval. Otherwise, if * the core supports IMOD, disable it. @@ -1974,6 +2143,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); + /* + * Programs the number of outstanding pipelined transfer requests + * the AXI master pushes to the AXI slave. + */ + if (dwc->revision >= DWC3_REVISION_270A) { + reg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG1); + reg &= ~DWC3_GSBUSCFG1_PIPETRANSLIMIT_MASK; + reg |= DWC3_GSBUSCFG1_PIPETRANSLIMIT(0xe); + dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, reg); + } + dwc3_gadget_setup_nump(dwc); /* Start with SuperSpeed Default */ @@ -2015,45 +2195,37 @@ static int dwc3_gadget_start(struct usb_gadget *g, struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; int ret = 0; - int irq; - - irq = dwc->irq_gadget; - ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, - IRQF_SHARED, "dwc3", dwc->ev_buf); - if (ret) { - dev_err(dwc->dev, "failed to request irq #%d --> %d\n", - irq, ret); - goto err0; - } + dbg_event(0xFF, "Gadgetstart", 0); spin_lock_irqsave(&dwc->lock, flags); if (dwc->gadget_driver) { dev_err(dwc->dev, "%s is already bound to %s\n", dwc->gadget.name, dwc->gadget_driver->driver.name); ret = -EBUSY; - goto err1; + goto err0; } dwc->gadget_driver = driver; - if (pm_runtime_active(dwc->dev)) - __dwc3_gadget_start(dwc); - + /* + * For DRD, this might get called by gadget driver during bootup + * even though host mode might be active. Don't actually perform + * device-specific initialization until device mode is activated. + * In that case dwc3_gadget_restart() will handle it. + */ spin_unlock_irqrestore(&dwc->lock, flags); return 0; -err1: - spin_unlock_irqrestore(&dwc->lock, flags); - free_irq(irq, dwc); - err0: + spin_unlock_irqrestore(&dwc->lock, flags); return ret; } static void __dwc3_gadget_stop(struct dwc3 *dwc) { + dbg_event(0xFF, "__Gadgetstop", 0); dwc3_gadget_disable_irq(dwc); __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); @@ -2065,17 +2237,12 @@ static int dwc3_gadget_stop(struct usb_gadget *g) unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); - - if (pm_runtime_suspended(dwc->dev)) - goto out; - - __dwc3_gadget_stop(dwc); - -out: dwc->gadget_driver = NULL; spin_unlock_irqrestore(&dwc->lock, flags); - free_irq(dwc->irq_gadget, dwc->ev_buf); + dbg_event(0xFF, "fwq_started", 0); + flush_workqueue(dwc->dwc_wq); + dbg_event(0xFF, "fwq_completed", 0); return 0; } @@ -2184,6 +2351,8 @@ static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, .set_selfpowered = dwc3_gadget_set_selfpowered, + .vbus_session = dwc3_gadget_vbus_session, + .vbus_draw = dwc3_gadget_vbus_draw, .pullup = dwc3_gadget_pullup, .udc_start = dwc3_gadget_start, .udc_stop = dwc3_gadget_stop, @@ -2193,6 +2362,10 @@ static const struct usb_gadget_ops dwc3_gadget_ops = { /* -------------------------------------------------------------------------- */ +#define NUM_GSI_OUT_EPS 1 +#define NUM_GSI_IN_EPS 2 + + static int dwc3_gadget_init_control_endpoint(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; @@ -2321,15 +2494,39 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 total) { u8 epnum; + u8 out_count; + u8 in_count; + u8 idx; + struct dwc3_ep *dep; + + in_count = out_count = total / 2; + out_count += total & 1; /* in case odd, there is one more OUT */ INIT_LIST_HEAD(&dwc->gadget.ep_list); for (epnum = 0; epnum < total; epnum++) { int ret; + u8 num = epnum >> 1; ret = dwc3_gadget_init_endpoint(dwc, epnum); if (ret) return ret; + + dep = dwc->eps[epnum]; + /* Reserve EPs at the end for GSI */ + if (!dep->direction && num > + out_count - NUM_GSI_OUT_EPS - 1) { + idx = num - (out_count - NUM_GSI_OUT_EPS - 1); + snprintf(dep->name, sizeof(dep->name), "gsi-epout%d", + idx); + dep->gsi = true; + } else if (dep->direction && num > + in_count - NUM_GSI_IN_EPS - 1) { + idx = num - (in_count - NUM_GSI_IN_EPS - 1); + snprintf(dep->name, sizeof(dep->name), "gsi-epin%d", + idx); + dep->gsi = true; + } } return 0; @@ -2644,6 +2841,7 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc) { if (dwc->gadget_driver && dwc->gadget_driver->disconnect) { spin_unlock(&dwc->lock); + dbg_event(0xFF, "DISCONNECT", 0); dwc->gadget_driver->disconnect(&dwc->gadget); spin_lock(&dwc->lock); } @@ -2653,6 +2851,7 @@ static void dwc3_suspend_gadget(struct dwc3 *dwc) { if (dwc->gadget_driver && dwc->gadget_driver->suspend) { spin_unlock(&dwc->lock); + dbg_event(0xFF, "SUSPEND", 0); dwc->gadget_driver->suspend(&dwc->gadget); spin_lock(&dwc->lock); } @@ -2662,6 +2861,7 @@ static void dwc3_resume_gadget(struct dwc3 *dwc) { if (dwc->gadget_driver && dwc->gadget_driver->resume) { spin_unlock(&dwc->lock); + dbg_event(0xFF, "RESUME", 0); dwc->gadget_driver->resume(&dwc->gadget); spin_lock(&dwc->lock); } @@ -2674,13 +2874,13 @@ static void dwc3_reset_gadget(struct dwc3 *dwc) if (dwc->gadget.speed != USB_SPEED_UNKNOWN) { spin_unlock(&dwc->lock); + dbg_event(0xFF, "UDC RESET", 0); usb_gadget_udc_reset(&dwc->gadget, dwc->gadget_driver); spin_lock(&dwc->lock); } } -static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, - bool interrupt) +void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt) { struct dwc3 *dwc = dep->dwc; struct dwc3_gadget_ep_cmd_params params; @@ -2690,6 +2890,9 @@ static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) return; + dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER, + dep->number); + /* * NOTICE: We are violating what the Databook says about the * EndTransfer command. Ideally we would _always_ wait for the @@ -2730,9 +2933,12 @@ static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, WARN_ON_ONCE(ret); dep->resource_index = 0; + dbg_log_string("%s(%d): endxfer ret:%d", dep->name, dep->number, ret); + if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) udelay(100); } +EXPORT_SYMBOL(dwc3_stop_active_transfer); static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) { @@ -2752,6 +2958,7 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) dep->flags &= ~DWC3_EP_STALL; ret = dwc3_send_clear_stall_ep_cmd(dep); + dbg_event(dep->number, "ECLRSTALL", ret); WARN_ON_ONCE(ret); } } @@ -2760,6 +2967,11 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) { int reg; + dbg_event(0xFF, "DISCONNECT INT", 0); + dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__); + dwc->b_suspend = false; + dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0); + reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_INITU1ENA; dwc3_writel(dwc->regs, DWC3_DCTL, reg); @@ -2771,6 +2983,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; + dwc->link_state = DWC3_LINK_STATE_SS_DIS; usb_gadget_set_state(&dwc->gadget, USB_STATE_NOTATTACHED); dwc->connected = false; @@ -2813,6 +3026,13 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc3_gadget_disconnect_interrupt(dwc); } + dbg_event(0xFF, "BUS RESET", 0); + dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__); + dwc->b_suspend = false; + dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0); + + usb_gadget_vbus_draw(&dwc->gadget, 100); + dwc3_reset_gadget(dwc); reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -2825,6 +3045,9 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_DEVADDR_MASK); dwc3_writel(dwc->regs, DWC3_DCFG, reg); + + dwc->gadget.speed = USB_SPEED_UNKNOWN; + dwc->link_state = DWC3_LINK_STATE_U0; } static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) @@ -2834,6 +3057,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) u32 reg; u8 speed; + dbg_event(0xFF, "CONNECT DONE", 0); reg = dwc3_readl(dwc->regs, DWC3_DSTS); speed = reg & DWC3_DSTS_CONNECTSPD; dwc->speed = speed; @@ -2942,6 +3166,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) return; } + dwc3_notify_event(dwc, DWC3_CONTROLLER_CONNDONE_EVENT, 0); + /* * Configure PHY via GUSB3PIPECTLn if required. * @@ -2953,6 +3179,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) { + dbg_event(0xFF, "WAKEUP", 0); + /* * TODO take core out of low power mode when that's * implemented. @@ -3060,6 +3288,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, break; } + dev_dbg(dwc->dev, "Going from (%d)--->(%d)\n", dwc->link_state, next); dwc->link_state = next; } @@ -3068,9 +3297,31 @@ static void dwc3_gadget_suspend_interrupt(struct dwc3 *dwc, { enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; - if (dwc->link_state != next && next == DWC3_LINK_STATE_U3) + dbg_event(0xFF, "SUSPEND INT", 0); + dev_dbg(dwc->dev, "%s Entry to %d\n", __func__, next); + + if (dwc->link_state != next && next == DWC3_LINK_STATE_U3) { + /* + * When first connecting the cable, even before the initial + * DWC3_DEVICE_EVENT_RESET or DWC3_DEVICE_EVENT_CONNECT_DONE + * events, the controller sees a DWC3_DEVICE_EVENT_SUSPEND + * event. In such a case, ignore. + * Ignore suspend event until device side usb is not into + * CONFIGURED state. + */ + if (dwc->gadget.state != USB_STATE_CONFIGURED) { + dev_err(dwc->dev, "%s(): state:%d. Ignore SUSPEND.\n", + __func__, dwc->gadget.state); + return; + } + dwc3_suspend_gadget(dwc); + dev_dbg(dwc->dev, "Notify OTG from %s\n", __func__); + dwc->b_suspend = true; + dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0); + } + dwc->link_state = next; } @@ -3132,6 +3383,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, case DWC3_DEVICE_EVENT_EOPF: /* It changed to be suspend event for version 2.30a and above */ if (dwc->revision >= DWC3_REVISION_230A) { + dbg_event(0xFF, "GAD SUS", 0); dwc->dbg_gadget_events.suspend++; /* * Ignore suspend event until the gadget enters into @@ -3146,7 +3398,9 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, dwc->dbg_gadget_events.sof++; break; case DWC3_DEVICE_EVENT_ERRATIC_ERROR: + dbg_event(0xFF, "ERROR", 0); dwc->dbg_gadget_events.erratic_error++; + dwc->err_evt_seen = true; break; case DWC3_DEVICE_EVENT_CMD_CMPL: dwc->dbg_gadget_events.cmdcmplt++; @@ -3192,6 +3446,19 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) dwc3_process_event_entry(dwc, &event); + if (dwc->err_evt_seen) { + /* + * if erratic error, skip remaining events + * while controller undergoes reset + */ + evt->lpos = (evt->lpos + left) % + DWC3_EVENT_BUFFERS_SIZE; + if (dwc3_notify_event(dwc, + DWC3_CONTROLLER_ERROR_EVENT, 0)) + dwc->err_evt_seen = 0; + break; + } + /* * FIXME we wrap around correctly to the next entry as * almost all entries are 4 bytes in size. There is one @@ -3223,6 +3490,15 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) return ret; } +void dwc3_bh_work(struct work_struct *w) +{ + struct dwc3 *dwc = container_of(w, struct dwc3, bh_work); + + pm_runtime_get_sync(dwc->dev); + dwc3_thread_interrupt(dwc->irq, dwc->ev_buf); + pm_runtime_put(dwc->dev); +} + static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt) { struct dwc3_event_buffer *evt = _evt; @@ -3256,12 +3532,9 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) start_time = ktime_get(); dwc->irq_cnt++; - if (pm_runtime_suspended(dwc->dev)) { - pm_runtime_get(dwc->dev); - disable_irq_nosync(dwc->irq_gadget); - dwc->pending_events = true; + /* controller reset is still pending */ + if (dwc->err_evt_seen) return IRQ_HANDLED; - } /* * With PCIe legacy interrupt, test shows that top-half irq handler can @@ -3302,11 +3575,20 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) return IRQ_WAKE_THREAD; } -static irqreturn_t dwc3_interrupt(int irq, void *_evt) +irqreturn_t dwc3_interrupt(int irq, void *_dwc) { - struct dwc3_event_buffer *evt = _evt; + struct dwc3 *dwc = _dwc; + irqreturn_t ret = IRQ_NONE; + irqreturn_t status; - return dwc3_check_event_buf(evt); + status = dwc3_check_event_buf(dwc->ev_buf); + if (status == IRQ_WAKE_THREAD) + ret = status; + + if (ret == IRQ_WAKE_THREAD) + queue_work(dwc->dwc_wq, &dwc->bh_work); + + return IRQ_HANDLED; } static int dwc3_gadget_get_irq(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 5faf4d1249e0..7c939b2172e1 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -58,6 +58,9 @@ struct dwc3; #define to_dwc3_request(r) (container_of(r, struct dwc3_request, request)) +irqreturn_t dwc3_interrupt(int irq, void *_dwc); +void dwc3_bh_work(struct work_struct *w); + /** * next_request - gets the next request on the given list * @list: the request list to operate on @@ -111,6 +114,15 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value); int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags); int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol); +void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt); + +static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, + struct dwc3_trb *trb) +{ + u32 offset = (char *) trb - (char *) dep->trb_pool; + + return dep->trb_pool_dma + offset; +} /** * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index bae1bdccea1c..f748cd49abbf 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -134,8 +134,11 @@ err: platform_device_put(xhci); return ret; } +EXPORT_SYMBOL(dwc3_host_init); void dwc3_host_exit(struct dwc3 *dwc) { platform_device_unregister(dwc->xhci); } +EXPORT_SYMBOL(dwc3_host_exit); +