mirror of
https://github.com/torvalds/linux.git
synced 2024-11-12 15:11:50 +00:00
usb: changes for v4.7 merge window
Here's the big USB Gadget pull request. This time not as large as usual with only 57 non-merge commits. The most important part here is, again, all the work on dwc3. This time around we're treating all endpoints (except for control endpoint) exactly the same. They all have the same amount of TRBs on the ring, they all treat the ring as an actual ring with a link TRB pointing to the head, etc. We're also helping the host side burst (on SuperSpeed GEN1 or GEN2 at least) for as long as possible until the endpoint returns NRDY. Other than this big TRB ring rework on dwc3, we also have a dwc3-omap DMA initialization fix, some extra debugfs files to aid in some odd debug sessions and a complete removal of our FIFO resizing logic. We have a new quirk for some dwc3 P3 quirk in some implementations. The rest is basically non-critical fixes and the usual cleanups. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXIek2AAoJEIaOsuA1yqRE2+cP/iZzzRshn6atj4b0BaRzyk6k acK6YNs8pBgJMt9FaVWhDOlCfa/8hg5W+6Z5Ovpx4WPyJdZbYkoxJ0ZJGKYjYZ/y U8hUxpTJ2s2wZKXRKchzT90hQvNlHdg3u2okP2GK0Oa17/idcQf2w1+0Cscm/dqN Ur5HgukLe31/MrcPr49OuLkahSPfHUQlOn8i4AZyBTh9L8ouzKDCvzUt2ABoCRLE wPcMegJhks7FQ5fksXtLsfqhqAoHpYHlsZQcH35iV8wPdtSueAtZ8tS6t445XbX9 vEsFq1ovpBMYfl/dwV6RBZiQTjZiGWaIdjOZMUcpbD03yXE2IC6l+mtE/wuhlnHu J0Rr4YmfS4g++J1+380NQGoreOBZ2u7pujQ4TAy399zsLD8LR3zOQK5IErILSfpO m6p3ElkGuAyHJKmo4CysSspXnnNGBp/fuTkYdPM9IJRJCe0YwnF/zsQd0OrNZ/Pm 39f6woE2aBQaEzdn+3Nya9B2IWYi6SIheQXPg0HETX/hujZHJv1x758VO6+c7aeq nlhRlxSe8u8DKryBG43+F+myHaIz1p0Y2O3MzIlvRv0yw87QevJ4pAWptdMITaMh YpgSjDPw5y2z91AhK/Fv+AXswKaoWBc6EEzBirW6hQWllSp+7qWloA6vYXkdHDr7 QajUBeXzNgXF8JfIos5H =7szP -----END PGP SIGNATURE----- Merge tag 'usb-for-v4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next Felipe writes: usb: changes for v4.7 merge window Here's the big USB Gadget pull request. This time not as large as usual with only 57 non-merge commits. The most important part here is, again, all the work on dwc3. This time around we're treating all endpoints (except for control endpoint) exactly the same. They all have the same amount of TRBs on the ring, they all treat the ring as an actual ring with a link TRB pointing to the head, etc. We're also helping the host side burst (on SuperSpeed GEN1 or GEN2 at least) for as long as possible until the endpoint returns NRDY. Other than this big TRB ring rework on dwc3, we also have a dwc3-omap DMA initialization fix, some extra debugfs files to aid in some odd debug sessions and a complete removal of our FIFO resizing logic. We have a new quirk for some dwc3 P3 quirk in some implementations. The rest is basically non-critical fixes and the usual cleanups.
This commit is contained in:
commit
ce15bda101
@ -14,7 +14,6 @@ Optional properties:
|
||||
the second element is expected to be a handle to the USB3/SS PHY
|
||||
- phys: from the *Generic PHY* bindings
|
||||
- phy-names: from the *Generic PHY* bindings
|
||||
- tx-fifo-resize: determines if the FIFO *has* to be reallocated.
|
||||
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
|
||||
- snps,disable_scramble_quirk: true when SW should disable data scrambling.
|
||||
Only really useful for FPGA builds.
|
||||
@ -38,6 +37,8 @@ Optional properties:
|
||||
- snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
|
||||
- snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG,
|
||||
disabling the suspend signal to the PHY.
|
||||
- snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
|
||||
in PHY P3 power state.
|
||||
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
|
||||
utmi_l1_suspend_n, false when asserts utmi_sleep_n
|
||||
- snps,hird-threshold: HIRD threshold
|
||||
@ -47,6 +48,8 @@ Optional properties:
|
||||
register for post-silicon frame length adjustment when the
|
||||
fladj_30mhz_sdbnd signal is invalid or incorrect.
|
||||
|
||||
- <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated.
|
||||
|
||||
This is usually a subnode to DWC3 glue to which it is connected.
|
||||
|
||||
dwc3@4a030000 {
|
||||
@ -54,5 +57,4 @@ dwc3@4a030000 {
|
||||
reg = <0x4a030000 0xcfff>;
|
||||
interrupts = <0 92 4>
|
||||
usb-phy = <&usb2_phy>, <&usb3,phy>;
|
||||
tx-fifo-resize;
|
||||
};
|
||||
|
@ -59,7 +59,6 @@ Example device nodes:
|
||||
interrupts = <0 205 0x4>;
|
||||
phys = <&hs_phy>, <&ss_phy>;
|
||||
phy-names = "usb2-phy", "usb3-phy";
|
||||
tx-fifo-resize;
|
||||
dr_mode = "host";
|
||||
};
|
||||
};
|
||||
|
@ -250,7 +250,8 @@ config PHY_SUN9I_USB
|
||||
tristate "Allwinner sun9i SoC USB PHY driver"
|
||||
depends on ARCH_SUNXI && HAS_IOMEM && OF
|
||||
depends on RESET_CONTROLLER
|
||||
depends on USB_COMMON
|
||||
depends on USB_SUPPORT
|
||||
select USB_COMMON
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the transceiver that is part of Allwinner
|
||||
|
@ -31,8 +31,6 @@ if USB_SUPPORT
|
||||
|
||||
config USB_COMMON
|
||||
tristate
|
||||
default y
|
||||
depends on USB || USB_GADGET
|
||||
|
||||
config USB_ARCH_HAS_HCD
|
||||
def_bool y
|
||||
@ -41,6 +39,7 @@ config USB_ARCH_HAS_HCD
|
||||
config USB
|
||||
tristate "Support for Host-side USB"
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
select USB_COMMON
|
||||
select NLS # for UTF-8 strings
|
||||
---help---
|
||||
Universal Serial Bus (USB) is a specification for a serial bus
|
||||
|
@ -2425,6 +2425,9 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
|
||||
u32 gintsts;
|
||||
u32 gintmsk;
|
||||
|
||||
if (!dwc2_is_device_mode(hsotg))
|
||||
return IRQ_NONE;
|
||||
|
||||
spin_lock(&hsotg->lock);
|
||||
irq_retry:
|
||||
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
|
||||
@ -2631,7 +2634,10 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
|
||||
desc->wMaxPacketSize, desc->bInterval);
|
||||
|
||||
/* not to be called for EP0 */
|
||||
WARN_ON(index == 0);
|
||||
if (index == 0) {
|
||||
dev_err(hsotg->dev, "%s: called for EP 0\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
|
||||
if (dir_in != hs_ep->dir_in) {
|
||||
|
@ -4703,6 +4703,7 @@ fail2:
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
urb->hcpriv = NULL;
|
||||
kfree(qtd);
|
||||
qtd = NULL;
|
||||
fail1:
|
||||
if (qh_allocated) {
|
||||
struct dwc2_qtd *qtd2, *qtd2_tmp;
|
||||
|
@ -552,6 +552,7 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
|
||||
{
|
||||
list_del(&qtd->qtd_list_entry);
|
||||
kfree(qtd);
|
||||
qtd = NULL;
|
||||
}
|
||||
|
||||
/* Descriptor DMA support functions */
|
||||
|
@ -1709,7 +1709,8 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
||||
|
||||
dwc2_deschedule_periodic(hsotg, qh);
|
||||
hsotg->periodic_qh_count--;
|
||||
if (!hsotg->periodic_qh_count) {
|
||||
if (!hsotg->periodic_qh_count &&
|
||||
hsotg->core_params->dma_desc_enable <= 0) {
|
||||
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
|
||||
intr_mask &= ~GINTSTS_SOF;
|
||||
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
|
||||
|
@ -562,7 +562,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
||||
|
||||
retval = dwc2_get_dr_mode(hsotg);
|
||||
if (retval)
|
||||
return retval;
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Reset before dwc2_get_hwparams() then it could get power-on real
|
||||
|
@ -60,6 +60,20 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||
}
|
||||
|
||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
u32 reg;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
|
||||
DWC3_GDBGFIFOSPACE_NUM(dep->number) |
|
||||
DWC3_GDBGFIFOSPACE_TYPE(type));
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
|
||||
|
||||
return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_core_soft_reset - Issues core soft reset and PHY reset
|
||||
* @dwc: pointer to our context structure
|
||||
@ -203,13 +217,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
|
||||
static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dwc->num_event_buffers; i++) {
|
||||
evt = dwc->ev_buffs[i];
|
||||
if (evt)
|
||||
dwc3_free_one_event_buffer(dwc, evt);
|
||||
}
|
||||
evt = dwc->ev_buf;
|
||||
if (evt)
|
||||
dwc3_free_one_event_buffer(dwc, evt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,27 +233,14 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
|
||||
*/
|
||||
static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
||||
{
|
||||
int num;
|
||||
int i;
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
|
||||
dwc->num_event_buffers = num;
|
||||
|
||||
dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num,
|
||||
GFP_KERNEL);
|
||||
if (!dwc->ev_buffs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct dwc3_event_buffer *evt;
|
||||
|
||||
evt = dwc3_alloc_one_event_buffer(dwc, length);
|
||||
if (IS_ERR(evt)) {
|
||||
dev_err(dwc->dev, "can't allocate event buffer\n");
|
||||
return PTR_ERR(evt);
|
||||
}
|
||||
dwc->ev_buffs[i] = evt;
|
||||
evt = dwc3_alloc_one_event_buffer(dwc, length);
|
||||
if (IS_ERR(evt)) {
|
||||
dev_err(dwc->dev, "can't allocate event buffer\n");
|
||||
return PTR_ERR(evt);
|
||||
}
|
||||
dwc->ev_buf = evt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -256,25 +254,22 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
|
||||
static int dwc3_event_buffers_setup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < dwc->num_event_buffers; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
dwc3_trace(trace_dwc3_core,
|
||||
"Event buf %p dma %08llx length %d\n",
|
||||
evt->buf, (unsigned long long) evt->dma,
|
||||
evt->length);
|
||||
evt = dwc->ev_buf;
|
||||
dwc3_trace(trace_dwc3_core,
|
||||
"Event buf %p dma %08llx length %d\n",
|
||||
evt->buf, (unsigned long long) evt->dma,
|
||||
evt->length);
|
||||
|
||||
evt->lpos = 0;
|
||||
evt->lpos = 0;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
|
||||
lower_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
|
||||
upper_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
|
||||
DWC3_GEVNTSIZ_SIZE(evt->length));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
|
||||
lower_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
|
||||
upper_32_bits(evt->dma));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
|
||||
DWC3_GEVNTSIZ_SIZE(evt->length));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -282,19 +277,16 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc)
|
||||
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < dwc->num_event_buffers; n++) {
|
||||
evt = dwc->ev_buffs[n];
|
||||
evt = dwc->ev_buf;
|
||||
|
||||
evt->lpos = 0;
|
||||
evt->lpos = 0;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK
|
||||
| DWC3_GEVNTSIZ_SIZE(0));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
|
||||
| DWC3_GEVNTSIZ_SIZE(0));
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0);
|
||||
}
|
||||
|
||||
static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc)
|
||||
@ -434,6 +426,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
if (dwc->u2ss_inp3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
|
||||
|
||||
if (dwc->dis_rxdet_inp3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3;
|
||||
|
||||
if (dwc->req_p1p2p3_quirk)
|
||||
reg |= DWC3_GUSB3PIPECTL_REQP1P2P3;
|
||||
|
||||
@ -882,9 +877,6 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
dwc->usb3_lpm_capable = device_property_read_bool(dev,
|
||||
"snps,usb3_lpm_capable");
|
||||
|
||||
dwc->needs_fifo_resize = device_property_read_bool(dev,
|
||||
"tx-fifo-resize");
|
||||
|
||||
dwc->disable_scramble_quirk = device_property_read_bool(dev,
|
||||
"snps,disable_scramble_quirk");
|
||||
dwc->u2exit_lfps_quirk = device_property_read_bool(dev,
|
||||
@ -907,6 +899,8 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
"snps,dis_u2_susphy_quirk");
|
||||
dwc->dis_enblslpm_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_enblslpm_quirk");
|
||||
dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
|
||||
"snps,dis_rxdet_inp3_quirk");
|
||||
|
||||
dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
|
||||
"snps,tx_de_emphasis_quirk");
|
||||
@ -926,7 +920,6 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
if (pdata->hird_threshold)
|
||||
hird_threshold = pdata->hird_threshold;
|
||||
|
||||
dwc->needs_fifo_resize = pdata->tx_fifo_resize;
|
||||
dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
|
||||
dwc->dr_mode = pdata->dr_mode;
|
||||
|
||||
@ -941,6 +934,7 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk;
|
||||
dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
|
||||
dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
|
||||
dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
|
||||
|
||||
dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
|
||||
if (pdata->tx_de_emphasis)
|
||||
@ -1050,19 +1044,11 @@ static int dwc3_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err5;
|
||||
|
||||
ret = dwc3_debugfs_init(dwc);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize debugfs\n");
|
||||
goto err6;
|
||||
}
|
||||
|
||||
dwc3_debugfs_init(dwc);
|
||||
pm_runtime_allow(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err6:
|
||||
dwc3_core_exit_mode(dwc);
|
||||
|
||||
err5:
|
||||
dwc3_event_buffers_cleanup(dwc);
|
||||
|
||||
|
@ -152,6 +152,24 @@
|
||||
|
||||
/* Bit fields */
|
||||
|
||||
/* Global Debug Queue/FIFO Space Available Register */
|
||||
#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f)
|
||||
#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
|
||||
#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
|
||||
|
||||
#define DWC3_TXFIFOQ 1
|
||||
#define DWC3_RXFIFOQ 3
|
||||
#define DWC3_TXREQQ 5
|
||||
#define DWC3_RXREQQ 7
|
||||
#define DWC3_RXINFOQ 9
|
||||
#define DWC3_DESCFETCHQ 13
|
||||
#define DWC3_EVENTQ 15
|
||||
|
||||
/* Global RX Threshold Configuration Register */
|
||||
#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
|
||||
#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
|
||||
#define DWC3_GRXTHRCFG_PKTCNTSEL (1 << 29)
|
||||
|
||||
/* Global Configuration Register */
|
||||
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
|
||||
#define DWC3_GCTL_U2RSTECN (1 << 16)
|
||||
@ -193,6 +211,7 @@
|
||||
/* Global USB3 PIPE Control Register */
|
||||
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
|
||||
#define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29)
|
||||
#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28)
|
||||
#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24)
|
||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
|
||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
|
||||
@ -257,6 +276,9 @@
|
||||
#define DWC3_DCFG_LOWSPEED (2 << 0)
|
||||
#define DWC3_DCFG_FULLSPEED1 (3 << 0)
|
||||
|
||||
#define DWC3_DCFG_NUMP_SHIFT 17
|
||||
#define DWC3_DCFG_NUMP(n) (((n) & 0x1f) >> DWC3_DCFG_NUMP_SHIFT)
|
||||
#define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT)
|
||||
#define DWC3_DCFG_LPM_CAP (1 << 22)
|
||||
|
||||
/* Device Control Register */
|
||||
@ -438,18 +460,17 @@ struct dwc3_event_buffer {
|
||||
#define DWC3_EP_DIRECTION_TX true
|
||||
#define DWC3_EP_DIRECTION_RX false
|
||||
|
||||
#define DWC3_TRB_NUM 32
|
||||
#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1)
|
||||
#define DWC3_TRB_NUM 256
|
||||
|
||||
/**
|
||||
* struct dwc3_ep - device side endpoint representation
|
||||
* @endpoint: usb endpoint
|
||||
* @request_list: list of requests for this endpoint
|
||||
* @req_queued: list of requests on this ep which have TRBs setup
|
||||
* @pending_list: list of pending requests for this endpoint
|
||||
* @started_list: list of started requests on this endpoint
|
||||
* @trb_pool: array of transaction buffers
|
||||
* @trb_pool_dma: dma address of @trb_pool
|
||||
* @free_slot: next slot which is going to be used
|
||||
* @busy_slot: first slot which is owned by HW
|
||||
* @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
|
||||
@ -464,13 +485,11 @@ struct dwc3_event_buffer {
|
||||
*/
|
||||
struct dwc3_ep {
|
||||
struct usb_ep endpoint;
|
||||
struct list_head request_list;
|
||||
struct list_head req_queued;
|
||||
struct list_head pending_list;
|
||||
struct list_head started_list;
|
||||
|
||||
struct dwc3_trb *trb_pool;
|
||||
dma_addr_t trb_pool_dma;
|
||||
u32 free_slot;
|
||||
u32 busy_slot;
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc;
|
||||
struct dwc3 *dwc;
|
||||
|
||||
@ -486,6 +505,18 @@ struct dwc3_ep {
|
||||
/* This last one is specific to EP0 */
|
||||
#define DWC3_EP0_DIR_IN (1 << 31)
|
||||
|
||||
/*
|
||||
* IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
|
||||
* use a u8 type here. If anybody decides to increase number of TRBs to
|
||||
* anything larger than 256 - I can't see why people would want to do
|
||||
* this though - then this type needs to be changed.
|
||||
*
|
||||
* By using u8 types we ensure that our % operator when incrementing
|
||||
* enqueue and dequeue get optimized away by the compiler.
|
||||
*/
|
||||
u8 trb_enqueue;
|
||||
u8 trb_dequeue;
|
||||
|
||||
u8 number;
|
||||
u8 type;
|
||||
u8 resource_index;
|
||||
@ -557,6 +588,7 @@ enum dwc3_link_state {
|
||||
#define DWC3_TRB_CTRL_IOC (1 << 11)
|
||||
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
|
||||
|
||||
#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4))
|
||||
#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1)
|
||||
#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2)
|
||||
#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3)
|
||||
@ -623,19 +655,32 @@ struct dwc3_hwparams {
|
||||
/* HWPARAMS7 */
|
||||
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
|
||||
|
||||
/**
|
||||
* struct dwc3_request - representation of a transfer request
|
||||
* @request: struct usb_request to be transferred
|
||||
* @list: a list_head used for request queueing
|
||||
* @dep: struct dwc3_ep owning this request
|
||||
* @first_trb_index: index to first trb used by this request
|
||||
* @epnum: endpoint number to which this request refers
|
||||
* @trb: pointer to struct dwc3_trb
|
||||
* @trb_dma: DMA address of @trb
|
||||
* @direction: IN or OUT direction flag
|
||||
* @mapped: true when request has been dma-mapped
|
||||
* @queued: true when request has been queued to HW
|
||||
*/
|
||||
struct dwc3_request {
|
||||
struct usb_request request;
|
||||
struct list_head list;
|
||||
struct dwc3_ep *dep;
|
||||
u32 start_slot;
|
||||
|
||||
u8 first_trb_index;
|
||||
u8 epnum;
|
||||
struct dwc3_trb *trb;
|
||||
dma_addr_t trb_dma;
|
||||
|
||||
unsigned direction:1;
|
||||
unsigned mapped:1;
|
||||
unsigned queued:1;
|
||||
unsigned started:1;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -667,7 +712,6 @@ struct dwc3_scratchpad_array {
|
||||
* @regs: base address for our registers
|
||||
* @regs_size: address space size
|
||||
* @nr_scratch: number of scratch buffers
|
||||
* @num_event_buffers: calculated number of event buffers
|
||||
* @u1u2: only used on revisions <1.83a for workaround
|
||||
* @maximum_speed: maximum speed requested (mainly for testing purposes)
|
||||
* @revision: revision register contents
|
||||
@ -709,9 +753,7 @@ struct dwc3_scratchpad_array {
|
||||
* 0 - utmi_sleep_n
|
||||
* 1 - utmi_l1_suspend_n
|
||||
* @is_fpga: true when we are using the FPGA board
|
||||
* @needs_fifo_resize: not all users might want fifo resizing, flag it
|
||||
* @pullups_connected: true when Run/Stop bit is set
|
||||
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
|
||||
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
|
||||
* @start_config_issued: true when StartConfig command has been issued
|
||||
* @three_stage_setup: set if we perform a three phase setup
|
||||
@ -756,7 +798,7 @@ struct dwc3 {
|
||||
struct platform_device *xhci;
|
||||
struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
|
||||
|
||||
struct dwc3_event_buffer **ev_buffs;
|
||||
struct dwc3_event_buffer *ev_buf;
|
||||
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
|
||||
|
||||
struct usb_gadget gadget;
|
||||
@ -780,7 +822,6 @@ struct dwc3 {
|
||||
u32 gctl;
|
||||
|
||||
u32 nr_scratch;
|
||||
u32 num_event_buffers;
|
||||
u32 u1u2;
|
||||
u32 maximum_speed;
|
||||
|
||||
@ -855,9 +896,7 @@ struct dwc3 {
|
||||
unsigned has_lpm_erratum:1;
|
||||
unsigned is_utmi_l1_suspend:1;
|
||||
unsigned is_fpga:1;
|
||||
unsigned needs_fifo_resize:1;
|
||||
unsigned pullups_connected:1;
|
||||
unsigned resize_fifos:1;
|
||||
unsigned setup_packet_pending:1;
|
||||
unsigned three_stage_setup:1;
|
||||
unsigned usb3_lpm_capable:1;
|
||||
@ -873,6 +912,7 @@ struct dwc3 {
|
||||
unsigned dis_u3_susphy_quirk:1;
|
||||
unsigned dis_u2_susphy_quirk:1;
|
||||
unsigned dis_enblslpm_quirk:1;
|
||||
unsigned dis_rxdet_inp3_quirk:1;
|
||||
|
||||
unsigned tx_de_emphasis_quirk:1;
|
||||
unsigned tx_de_emphasis:2;
|
||||
@ -938,6 +978,10 @@ struct dwc3_event_depevt {
|
||||
#define DEPEVT_STATUS_CONTROL_DATA 1
|
||||
#define DEPEVT_STATUS_CONTROL_STATUS 2
|
||||
|
||||
/* In response to Start Transfer */
|
||||
#define DEPEVT_TRANSFER_NO_RESOURCE 1
|
||||
#define DEPEVT_TRANSFER_BUS_EXPIRY 2
|
||||
|
||||
u32 parameters:16;
|
||||
} __packed;
|
||||
|
||||
@ -1025,7 +1069,7 @@ struct dwc3_gadget_ep_cmd_params {
|
||||
|
||||
/* prototypes */
|
||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
|
||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
|
||||
|
||||
/* check whether we are on the DWC_usb31 core */
|
||||
static inline bool dwc3_is_usb31(struct dwc3 *dwc)
|
||||
|
@ -217,11 +217,11 @@ static inline const char *dwc3_gadget_event_type_string(u8 event)
|
||||
void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern int dwc3_debugfs_init(struct dwc3 *);
|
||||
extern void dwc3_debugfs_init(struct dwc3 *);
|
||||
extern void dwc3_debugfs_exit(struct dwc3 *);
|
||||
#else
|
||||
static inline int dwc3_debugfs_init(struct dwc3 *d)
|
||||
{ return 0; }
|
||||
static inline void dwc3_debugfs_init(struct dwc3 *d)
|
||||
{ }
|
||||
static inline void dwc3_debugfs_exit(struct dwc3 *d)
|
||||
{ }
|
||||
#endif
|
||||
|
@ -618,24 +618,323 @@ static const struct file_operations dwc3_link_state_fops = {
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
int dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
int ret;
|
||||
struct dwc3_ep_file_map {
|
||||
char name[25];
|
||||
int (*show)(struct seq_file *s, void *unused);
|
||||
};
|
||||
|
||||
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
|
||||
if (!root) {
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_TXREQQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_RXREQQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_event_queue_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
val = dwc3_core_fifo_space(dep, DWC3_EVENTQ);
|
||||
seq_printf(s, "%u\n", val);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_ep_transfer_type_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
if (!(dep->flags & DWC3_EP_ENABLED) ||
|
||||
!dep->endpoint.desc) {
|
||||
seq_printf(s, "--\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (usb_endpoint_type(dep->endpoint.desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
seq_printf(s, "control\n");
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
seq_printf(s, "isochronous\n");
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
seq_printf(s, "bulk\n");
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
seq_printf(s, "interrupt\n");
|
||||
break;
|
||||
default:
|
||||
seq_printf(s, "--\n");
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb)
|
||||
{
|
||||
switch (DWC3_TRBCTL_TYPE(trb->ctrl)) {
|
||||
case DWC3_TRBCTL_NORMAL:
|
||||
return "normal";
|
||||
case DWC3_TRBCTL_CONTROL_SETUP:
|
||||
return "control-setup";
|
||||
case DWC3_TRBCTL_CONTROL_STATUS2:
|
||||
return "control-status2";
|
||||
case DWC3_TRBCTL_CONTROL_STATUS3:
|
||||
return "control-status3";
|
||||
case DWC3_TRBCTL_CONTROL_DATA:
|
||||
return "control-data";
|
||||
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
|
||||
return "isoc-first";
|
||||
case DWC3_TRBCTL_ISOCHRONOUS:
|
||||
return "isoc";
|
||||
case DWC3_TRBCTL_LINK_TRB:
|
||||
return "link";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct dwc3_ep *dep = s->private;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
if (dep->number <= 1) {
|
||||
seq_printf(s, "--\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
seq_printf(s, "enqueue pointer %d\n", dep->trb_enqueue);
|
||||
seq_printf(s, "dequeue pointer %d\n", dep->trb_dequeue);
|
||||
seq_printf(s, "\n--------------------------------------------------\n\n");
|
||||
seq_printf(s, "buffer_addr,size,type,ioc,isp_imi,csp,chn,lst,hwo\n");
|
||||
|
||||
for (i = 0; i < DWC3_TRB_NUM; i++) {
|
||||
struct dwc3_trb *trb = &dep->trb_pool[i];
|
||||
|
||||
seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n",
|
||||
trb->bph, trb->bpl, trb->size,
|
||||
dwc3_trb_type_string(trb),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_CHN),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_LST),
|
||||
!!(trb->ctrl & DWC3_TRB_CTRL_HWO));
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dwc3_ep_file_map map[] = {
|
||||
{ "tx_fifo_queue", dwc3_tx_fifo_queue_show, },
|
||||
{ "rx_fifo_queue", dwc3_rx_fifo_queue_show, },
|
||||
{ "tx_request_queue", dwc3_tx_request_queue_show, },
|
||||
{ "rx_request_queue", dwc3_rx_request_queue_show, },
|
||||
{ "rx_info_queue", dwc3_rx_info_queue_show, },
|
||||
{ "descriptor_fetch_queue", dwc3_descriptor_fetch_queue_show, },
|
||||
{ "event_queue", dwc3_event_queue_show, },
|
||||
{ "transfer_type", dwc3_ep_transfer_type_show, },
|
||||
{ "trb_ring", dwc3_ep_trb_ring_show, },
|
||||
};
|
||||
|
||||
static int dwc3_endpoint_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
const char *file_name = file_dentry(file)->d_iname;
|
||||
struct dwc3_ep_file_map *f_map;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(map); i++) {
|
||||
f_map = &map[i];
|
||||
|
||||
if (strcmp(f_map->name, file_name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return single_open(file, f_map->show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations dwc3_endpoint_fops = {
|
||||
.open = dwc3_endpoint_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static void dwc3_debugfs_create_endpoint_file(struct dwc3_ep *dep,
|
||||
struct dentry *parent, int type)
|
||||
{
|
||||
struct dentry *file;
|
||||
struct dwc3_ep_file_map *ep_file = &map[type];
|
||||
|
||||
file = debugfs_create_file(ep_file->name, S_IRUGO, parent, dep,
|
||||
&dwc3_endpoint_fops);
|
||||
}
|
||||
|
||||
static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
|
||||
struct dentry *parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(map); i++)
|
||||
dwc3_debugfs_create_endpoint_file(dep, parent, i);
|
||||
}
|
||||
|
||||
static void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep,
|
||||
struct dentry *parent)
|
||||
{
|
||||
struct dentry *dir;
|
||||
|
||||
dir = debugfs_create_dir(dep->name, parent);
|
||||
if (IS_ERR_OR_NULL(dir))
|
||||
return;
|
||||
|
||||
dwc3_debugfs_create_endpoint_files(dep, dir);
|
||||
}
|
||||
|
||||
static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
|
||||
struct dentry *parent)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dwc->num_in_eps; i++) {
|
||||
u8 epnum = (i << 1) | 1;
|
||||
struct dwc3_ep *dep = dwc->eps[epnum];
|
||||
|
||||
if (!dep)
|
||||
continue;
|
||||
|
||||
dwc3_debugfs_create_endpoint_dir(dep, parent);
|
||||
}
|
||||
|
||||
for (i = 0; i < dwc->num_out_eps; i++) {
|
||||
u8 epnum = (i << 1);
|
||||
struct dwc3_ep *dep = dwc->eps[epnum];
|
||||
|
||||
if (!dep)
|
||||
continue;
|
||||
|
||||
dwc3_debugfs_create_endpoint_dir(dep, parent);
|
||||
}
|
||||
}
|
||||
|
||||
void dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
{
|
||||
struct dentry *root;
|
||||
struct dentry *file;
|
||||
|
||||
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
|
||||
if (IS_ERR_OR_NULL(root)) {
|
||||
if (!root)
|
||||
dev_err(dwc->dev, "Can't create debugfs root\n");
|
||||
return;
|
||||
}
|
||||
dwc->root = root;
|
||||
|
||||
dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL);
|
||||
if (!dwc->regset) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
debugfs_remove_recursive(root);
|
||||
return;
|
||||
}
|
||||
|
||||
dwc->regset->regs = dwc3_regs;
|
||||
@ -643,47 +942,30 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
|
||||
dwc->regset->base = dwc->regs;
|
||||
|
||||
file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
if (!file)
|
||||
dev_dbg(dwc->dev, "Can't create debugfs regdump\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
|
||||
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_mode_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
if (!file)
|
||||
dev_dbg(dwc->dev, "Can't create debugfs mode\n");
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
|
||||
IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
|
||||
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_testmode_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
if (!file)
|
||||
dev_dbg(dwc->dev, "Can't create debugfs testmode\n");
|
||||
|
||||
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
|
||||
dwc, &dwc3_link_state_fops);
|
||||
if (!file) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR,
|
||||
root, dwc, &dwc3_link_state_fops);
|
||||
if (!file)
|
||||
dev_dbg(dwc->dev, "Can't create debugfs link_state\n");
|
||||
|
||||
dwc3_debugfs_create_endpoint_dirs(dwc, root);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
kfree(dwc->regset);
|
||||
|
||||
err1:
|
||||
debugfs_remove_recursive(root);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dwc3_debugfs_exit(struct dwc3 *dwc)
|
||||
|
@ -126,8 +126,6 @@ struct dwc3_omap {
|
||||
u32 debug_offset;
|
||||
u32 irq0_offset;
|
||||
|
||||
u32 dma_status:1;
|
||||
|
||||
struct extcon_dev *edev;
|
||||
struct notifier_block vbus_nb;
|
||||
struct notifier_block id_nb;
|
||||
@ -277,9 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
|
||||
|
||||
reg = dwc3_omap_read_irqmisc_status(omap);
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR)
|
||||
omap->dma_status = false;
|
||||
|
||||
dwc3_omap_write_irqmisc_status(omap, reg);
|
||||
|
||||
reg = dwc3_omap_read_irq0_status(omap);
|
||||
@ -331,8 +326,6 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
|
||||
dwc3_omap_write_irqmisc_clr(omap, reg);
|
||||
}
|
||||
|
||||
static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
static int dwc3_omap_id_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
@ -490,7 +483,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
omap->irq = irq;
|
||||
omap->base = base;
|
||||
omap->vbus_reg = vbus_reg;
|
||||
dev->dma_mask = &dwc3_omap_dma_mask;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
@ -504,7 +496,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
|
||||
/* check the DMA Status */
|
||||
reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
|
||||
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
|
||||
|
||||
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
|
||||
"dwc3-omap", omap);
|
||||
|
@ -47,7 +47,7 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static int dwc3_pci_quirks(struct pci_dev *pdev)
|
||||
static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3)
|
||||
{
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
|
||||
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
|
||||
@ -77,8 +77,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
|
||||
pdata.dis_u3_susphy_quirk = true;
|
||||
pdata.dis_u2_susphy_quirk = true;
|
||||
|
||||
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
|
||||
sizeof(pdata));
|
||||
return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
|
||||
}
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
||||
@ -123,8 +122,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
|
||||
pdata.has_lpm_erratum = true;
|
||||
pdata.dis_enblslpm_quirk = true;
|
||||
|
||||
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
|
||||
sizeof(pdata));
|
||||
return platform_device_add_data(dwc3, &pdata, sizeof(pdata));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -169,20 +167,20 @@ static int dwc3_pci_probe(struct pci_dev *pci,
|
||||
return ret;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci, dwc3);
|
||||
ret = dwc3_pci_quirks(pci);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
dwc3->dev.parent = dev;
|
||||
ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev));
|
||||
|
||||
ret = dwc3_pci_quirks(pci, dwc3);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = platform_device_add(dwc3);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register dwc3 device\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pci, dwc3);
|
||||
return 0;
|
||||
err:
|
||||
platform_device_put(dwc3);
|
||||
|
@ -70,10 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
||||
return 0;
|
||||
}
|
||||
|
||||
trb = &dwc->ep0_trb[dep->free_slot];
|
||||
trb = &dwc->ep0_trb[dep->trb_enqueue];
|
||||
|
||||
if (chain)
|
||||
dep->free_slot++;
|
||||
dep->trb_enqueue++;
|
||||
|
||||
trb->bpl = lower_32_bits(buf_dma);
|
||||
trb->bph = upper_32_bits(buf_dma);
|
||||
@ -124,7 +124,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
|
||||
req->request.status = -EINPROGRESS;
|
||||
req->epnum = dep->number;
|
||||
|
||||
list_add_tail(&req->list, &dep->request_list);
|
||||
list_add_tail(&req->list, &dep->pending_list);
|
||||
|
||||
/*
|
||||
* Gadget driver might not be quick enough to queue a request
|
||||
@ -240,7 +240,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
|
||||
}
|
||||
|
||||
/* we share one TRB for ep0/1 */
|
||||
if (!list_empty(&dep->request_list)) {
|
||||
if (!list_empty(&dep->pending_list)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
@ -272,10 +272,10 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
dwc->delayed_status = false;
|
||||
|
||||
if (!list_empty(&dep->request_list)) {
|
||||
if (!list_empty(&dep->pending_list)) {
|
||||
struct dwc3_request *req;
|
||||
|
||||
req = next_request(&dep->request_list);
|
||||
req = next_request(&dep->pending_list);
|
||||
dwc3_gadget_giveback(dep, req, -ECONNRESET);
|
||||
}
|
||||
|
||||
@ -463,8 +463,18 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
|
||||
if (!set)
|
||||
return -EINVAL;
|
||||
|
||||
dwc->test_mode_nr = wIndex >> 8;
|
||||
dwc->test_mode = true;
|
||||
switch (wIndex >> 8) {
|
||||
case TEST_J:
|
||||
case TEST_K:
|
||||
case TEST_SE0_NAK:
|
||||
case TEST_PACKET:
|
||||
case TEST_FORCE_EN:
|
||||
dwc->test_mode_nr = wIndex >> 8;
|
||||
dwc->test_mode = true;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -586,9 +596,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||||
reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
|
||||
dwc->resize_fifos = true;
|
||||
dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
|
||||
}
|
||||
break;
|
||||
|
||||
@ -809,7 +816,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
|
||||
trace_dwc3_complete_trb(ep0, trb);
|
||||
|
||||
r = next_request(&ep0->request_list);
|
||||
r = next_request(&ep0->pending_list);
|
||||
if (!r)
|
||||
return;
|
||||
|
||||
@ -848,7 +855,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
trb++;
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
ep0->free_slot = 0;
|
||||
ep0->trb_enqueue = 0;
|
||||
}
|
||||
|
||||
transfer_size = roundup((ur->length - transfer_size),
|
||||
@ -897,8 +904,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc,
|
||||
|
||||
trace_dwc3_complete_trb(dep, trb);
|
||||
|
||||
if (!list_empty(&dep->request_list)) {
|
||||
r = next_request(&dep->request_list);
|
||||
if (!list_empty(&dep->pending_list)) {
|
||||
r = next_request(&dep->pending_list);
|
||||
|
||||
dwc3_gadget_giveback(dep, r, 0);
|
||||
}
|
||||
@ -1027,12 +1034,6 @@ 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)
|
||||
{
|
||||
if (dwc->resize_fifos) {
|
||||
dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
|
||||
dwc3_gadget_resize_tx_fifos(dwc);
|
||||
dwc->resize_fifos = 0;
|
||||
}
|
||||
|
||||
WARN_ON(dwc3_ep0_start_control_status(dep));
|
||||
}
|
||||
|
||||
|
@ -145,90 +145,21 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
|
||||
* @dwc: pointer to our context structure
|
||||
*
|
||||
* This function will a best effort FIFO allocation in order
|
||||
* to improve FIFO usage and throughput, while still allowing
|
||||
* us to enable as many endpoints as possible.
|
||||
*
|
||||
* Keep in mind that this operation will be highly dependent
|
||||
* on the configured size for RAM1 - which contains TxFifo -,
|
||||
* the amount of endpoints enabled on coreConsultant tool, and
|
||||
* the width of the Master Bus.
|
||||
*
|
||||
* In the ideal world, we would always be able to satisfy the
|
||||
* following equation:
|
||||
*
|
||||
* ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
|
||||
* (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
|
||||
*
|
||||
* Unfortunately, due to many variables that's not always the case.
|
||||
*/
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
|
||||
static void dwc3_ep_inc_enq(struct dwc3_ep *dep)
|
||||
{
|
||||
int last_fifo_depth = 0;
|
||||
int ram1_depth;
|
||||
int fifo_size;
|
||||
int mdwidth;
|
||||
int num;
|
||||
dep->trb_enqueue++;
|
||||
dep->trb_enqueue %= DWC3_TRB_NUM;
|
||||
}
|
||||
|
||||
if (!dwc->needs_fifo_resize)
|
||||
return 0;
|
||||
static void dwc3_ep_inc_deq(struct dwc3_ep *dep)
|
||||
{
|
||||
dep->trb_dequeue++;
|
||||
dep->trb_dequeue %= DWC3_TRB_NUM;
|
||||
}
|
||||
|
||||
ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
|
||||
mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
|
||||
|
||||
/* MDWIDTH is represented in bits, we need it in bytes */
|
||||
mdwidth >>= 3;
|
||||
|
||||
/*
|
||||
* FIXME For now we will only allocate 1 wMaxPacketSize space
|
||||
* for each enabled endpoint, later patches will come to
|
||||
* improve this algorithm so that we better use the internal
|
||||
* FIFO space
|
||||
*/
|
||||
for (num = 0; num < dwc->num_in_eps; num++) {
|
||||
/* bit0 indicates direction; 1 means IN ep */
|
||||
struct dwc3_ep *dep = dwc->eps[(num << 1) | 1];
|
||||
int mult = 1;
|
||||
int tmp;
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED))
|
||||
continue;
|
||||
|
||||
if (usb_endpoint_xfer_bulk(dep->endpoint.desc)
|
||||
|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
mult = 3;
|
||||
|
||||
/*
|
||||
* REVISIT: the following assumes we will always have enough
|
||||
* space available on the FIFO RAM for all possible use cases.
|
||||
* Make sure that's true somehow and change FIFO allocation
|
||||
* accordingly.
|
||||
*
|
||||
* If we have Bulk or Isochronous endpoints, we want
|
||||
* them to be able to be very, very fast. So we're giving
|
||||
* those endpoints a fifo_size which is enough for 3 full
|
||||
* packets
|
||||
*/
|
||||
tmp = mult * (dep->endpoint.maxpacket + mdwidth);
|
||||
tmp += mdwidth;
|
||||
|
||||
fifo_size = DIV_ROUND_UP(tmp, mdwidth);
|
||||
|
||||
fifo_size |= (last_fifo_depth << 16);
|
||||
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
|
||||
dep->name, last_fifo_depth, fifo_size & 0xffff);
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
|
||||
|
||||
last_fifo_depth += (fifo_size & 0xffff);
|
||||
}
|
||||
|
||||
return 0;
|
||||
static int dwc3_ep_is_last_trb(unsigned int index)
|
||||
{
|
||||
return index == DWC3_TRB_NUM - 1;
|
||||
}
|
||||
|
||||
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
@ -237,21 +168,19 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
int i;
|
||||
|
||||
if (req->queued) {
|
||||
if (req->started) {
|
||||
i = 0;
|
||||
do {
|
||||
dep->busy_slot++;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
/*
|
||||
* Skip LINK TRB. We can't use req->trb and check for
|
||||
* DWC3_TRBCTL_LINK_TRB because it points the TRB we
|
||||
* just completed (not the LINK TRB).
|
||||
*/
|
||||
if (((dep->busy_slot & DWC3_TRB_MASK) ==
|
||||
DWC3_TRB_NUM- 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
dep->busy_slot++;
|
||||
if (dwc3_ep_is_last_trb(dep->trb_dequeue))
|
||||
dwc3_ep_inc_deq(dep);
|
||||
} while(++i < req->request.num_mapped_sgs);
|
||||
req->queued = false;
|
||||
req->started = false;
|
||||
}
|
||||
list_del(&req->list);
|
||||
req->trb = NULL;
|
||||
@ -307,6 +236,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
|
||||
|
||||
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
|
||||
{
|
||||
@ -314,8 +245,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
u32 timeout = 500;
|
||||
u32 reg;
|
||||
|
||||
int susphy = false;
|
||||
int ret = -EINVAL;
|
||||
|
||||
trace_dwc3_gadget_ep_cmd(dep, cmd, params);
|
||||
|
||||
/*
|
||||
* Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if
|
||||
* we're issuing an endpoint command, we must check if
|
||||
* GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it.
|
||||
*
|
||||
* We will also set SUSPHY bit to what it was before returning as stated
|
||||
* by the same section on Synopsys databook.
|
||||
*/
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
|
||||
susphy = true;
|
||||
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
}
|
||||
|
||||
if (cmd == DWC3_DEPCMD_STARTTRANSFER) {
|
||||
int needs_wakeup;
|
||||
|
||||
needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 ||
|
||||
dwc->link_state == DWC3_LINK_STATE_U2 ||
|
||||
dwc->link_state == DWC3_LINK_STATE_U3);
|
||||
|
||||
if (unlikely(needs_wakeup)) {
|
||||
ret = __dwc3_gadget_wakeup(dwc);
|
||||
dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
|
||||
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
|
||||
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
|
||||
@ -324,12 +287,40 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
do {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
|
||||
if (!(reg & DWC3_DEPCMD_CMDACT)) {
|
||||
int cmd_status = DWC3_DEPCMD_STATUS(reg);
|
||||
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Command Complete --> %d",
|
||||
DWC3_DEPCMD_STATUS(reg));
|
||||
if (DWC3_DEPCMD_STATUS(reg))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
cmd_status);
|
||||
|
||||
switch (cmd_status) {
|
||||
case 0:
|
||||
ret = 0;
|
||||
break;
|
||||
case DEPEVT_TRANSFER_NO_RESOURCE:
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: no resource available");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
case DEPEVT_TRANSFER_BUS_EXPIRY:
|
||||
/*
|
||||
* SW issues START TRANSFER command to
|
||||
* isochronous ep with future frame interval. If
|
||||
* future interval time has already passed when
|
||||
* core receives the command, it will respond
|
||||
* with an error status of 'Bus Expiry'.
|
||||
*
|
||||
* Instead of always returning -EINVAL, let's
|
||||
* give a hint to the gadget driver that this is
|
||||
* the case by returning -EAGAIN.
|
||||
*/
|
||||
dwc3_trace(trace_dwc3_gadget, "%s: bus expiry");
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
default:
|
||||
dev_WARN(dwc->dev, "UNKNOWN cmd status\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -340,11 +331,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
|
||||
if (!timeout) {
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"Command Timed Out");
|
||||
return -ETIMEDOUT;
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
udelay(1);
|
||||
} while (1);
|
||||
|
||||
if (unlikely(susphy)) {
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||||
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
|
||||
@ -464,9 +464,19 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
|
||||
/* Burst size is only needed in SuperSpeed mode */
|
||||
if (dwc->gadget.speed >= USB_SPEED_SUPER) {
|
||||
u32 burst = dep->endpoint.maxburst - 1;
|
||||
u32 burst = dep->endpoint.maxburst;
|
||||
u32 nump;
|
||||
u32 reg;
|
||||
|
||||
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst);
|
||||
/* update NumP */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
nump = DWC3_DCFG_NUMP(reg);
|
||||
nump = max(nump, burst);
|
||||
reg &= ~DWC3_DCFG_NUMP_MASK;
|
||||
reg |= nump << DWC3_DCFG_NUMP_SHIFT;
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1);
|
||||
}
|
||||
|
||||
if (ignore)
|
||||
@ -567,10 +577,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
||||
reg |= DWC3_DALEPENA_EP(dep->number);
|
||||
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
|
||||
|
||||
if (!usb_endpoint_xfer_isoc(desc))
|
||||
if (usb_endpoint_xfer_control(desc))
|
||||
goto out;
|
||||
|
||||
/* Link TRB for ISOC. The HWO bit is never reset */
|
||||
/* Link TRB. The HWO bit is never reset */
|
||||
trb_st_hw = &dep->trb_pool[0];
|
||||
|
||||
trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
|
||||
@ -608,19 +618,19 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_request *req;
|
||||
|
||||
if (!list_empty(&dep->req_queued)) {
|
||||
if (!list_empty(&dep->started_list)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
|
||||
/* - giveback all requests to gadget driver */
|
||||
while (!list_empty(&dep->req_queued)) {
|
||||
req = next_request(&dep->req_queued);
|
||||
while (!list_empty(&dep->started_list)) {
|
||||
req = next_request(&dep->started_list);
|
||||
|
||||
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
while (!list_empty(&dep->request_list)) {
|
||||
req = next_request(&dep->request_list);
|
||||
while (!list_empty(&dep->pending_list)) {
|
||||
req = next_request(&dep->pending_list);
|
||||
|
||||
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
|
||||
}
|
||||
@ -783,20 +793,19 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
chain ? " chain" : "");
|
||||
|
||||
|
||||
trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
|
||||
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||
|
||||
if (!req->trb) {
|
||||
dwc3_gadget_move_request_queued(req);
|
||||
dwc3_gadget_move_started_request(req);
|
||||
req->trb = trb;
|
||||
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
|
||||
req->start_slot = dep->free_slot & DWC3_TRB_MASK;
|
||||
req->first_trb_index = dep->trb_enqueue;
|
||||
}
|
||||
|
||||
dep->free_slot++;
|
||||
/* Skip the LINK-TRB on ISOC */
|
||||
if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
dep->free_slot++;
|
||||
dwc3_ep_inc_enq(dep);
|
||||
/* Skip the LINK-TRB */
|
||||
if (dwc3_ep_is_last_trb(dep->trb_enqueue))
|
||||
dwc3_ep_inc_enq(dep);
|
||||
|
||||
trb->size = DWC3_TRB_SIZE_LENGTH(length);
|
||||
trb->bpl = lower_32_bits(dma);
|
||||
@ -812,6 +821,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
|
||||
else
|
||||
trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS;
|
||||
|
||||
/* always enable Interrupt on Missed ISOC */
|
||||
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
@ -826,15 +838,14 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (!req->request.no_interrupt && !chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_IOC;
|
||||
/* always enable Continue on Short Packet */
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CSP;
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CSP;
|
||||
} else if (last) {
|
||||
if (!req->request.no_interrupt && !chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI;
|
||||
|
||||
if (last)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_LST;
|
||||
}
|
||||
|
||||
if (chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CHN;
|
||||
@ -860,55 +871,29 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
||||
{
|
||||
struct dwc3_request *req, *n;
|
||||
u32 trbs_left;
|
||||
u32 max;
|
||||
unsigned int last_one = 0;
|
||||
|
||||
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
|
||||
|
||||
/* the first request must not be queued */
|
||||
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
|
||||
|
||||
/* Can't wrap around on a non-isoc EP since there's no link TRB */
|
||||
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
|
||||
if (trbs_left > max)
|
||||
trbs_left = max;
|
||||
}
|
||||
trbs_left = dep->trb_dequeue - dep->trb_enqueue;
|
||||
|
||||
/*
|
||||
* If busy & slot are equal than it is either full or empty. If we are
|
||||
* starting to process requests then we are empty. Otherwise we are
|
||||
* If enqueue & dequeue are equal than it is either full or empty. If we
|
||||
* are starting to process requests then we are empty. Otherwise we are
|
||||
* full and don't do anything
|
||||
*/
|
||||
if (!trbs_left) {
|
||||
if (!starting)
|
||||
return;
|
||||
|
||||
trbs_left = DWC3_TRB_NUM;
|
||||
/*
|
||||
* In case we start from scratch, we queue the ISOC requests
|
||||
* starting from slot 1. This is done because we use ring
|
||||
* buffer and have no LST bit to stop us. Instead, we place
|
||||
* IOC bit every TRB_NUM/4. We try to avoid having an interrupt
|
||||
* after the first request so we start at slot 1 and have
|
||||
* 7 requests proceed before we hit the first IOC.
|
||||
* Other transfer types don't use the ring buffer and are
|
||||
* processed from the first TRB until the last one. Since we
|
||||
* don't wrap around we have to start at the beginning.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
dep->busy_slot = 1;
|
||||
dep->free_slot = 1;
|
||||
} else {
|
||||
dep->busy_slot = 0;
|
||||
dep->free_slot = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The last TRB is a link TRB, not used for xfer */
|
||||
if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
if (trbs_left <= 1)
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(req, n, &dep->request_list, list) {
|
||||
list_for_each_entry_safe(req, n, &dep->pending_list, list) {
|
||||
unsigned length;
|
||||
dma_addr_t dma;
|
||||
last_one = false;
|
||||
@ -927,7 +912,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
||||
|
||||
if (i == (request->num_mapped_sgs - 1) ||
|
||||
sg_is_last(s)) {
|
||||
if (list_empty(&dep->request_list))
|
||||
if (list_empty(&dep->pending_list))
|
||||
last_one = true;
|
||||
chain = false;
|
||||
}
|
||||
@ -957,7 +942,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
|
||||
last_one = 1;
|
||||
|
||||
/* Is this the last request? */
|
||||
if (list_is_last(&req->list, &dep->request_list))
|
||||
if (list_is_last(&req->list, &dep->pending_list))
|
||||
last_one = 1;
|
||||
|
||||
dwc3_prepare_one_trb(dep, req, dma, length,
|
||||
@ -988,18 +973,18 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
|
||||
* new requests as we try to set the IOC bit only on the last request.
|
||||
*/
|
||||
if (start_new) {
|
||||
if (list_empty(&dep->req_queued))
|
||||
if (list_empty(&dep->started_list))
|
||||
dwc3_prepare_trbs(dep, start_new);
|
||||
|
||||
/* req points to the first request which will be sent */
|
||||
req = next_request(&dep->req_queued);
|
||||
req = next_request(&dep->started_list);
|
||||
} else {
|
||||
dwc3_prepare_trbs(dep, start_new);
|
||||
|
||||
/*
|
||||
* req points to the first request where HWO changed from 0 to 1
|
||||
*/
|
||||
req = next_request(&dep->req_queued);
|
||||
req = next_request(&dep->started_list);
|
||||
}
|
||||
if (!req) {
|
||||
dep->flags |= DWC3_EP_PENDING_REQUEST;
|
||||
@ -1046,7 +1031,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
||||
{
|
||||
u32 uf;
|
||||
|
||||
if (list_empty(&dep->request_list)) {
|
||||
if (list_empty(&dep->pending_list)) {
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"ISOC ep %s run out for requests",
|
||||
dep->name);
|
||||
@ -1114,7 +1099,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_add_tail(&req->list, &dep->request_list);
|
||||
list_add_tail(&req->list, &dep->pending_list);
|
||||
|
||||
/*
|
||||
* If there are no pending requests and the endpoint isn't already
|
||||
@ -1149,7 +1134,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
* notion of current microframe.
|
||||
*/
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
|
||||
if (list_empty(&dep->req_queued)) {
|
||||
if (list_empty(&dep->started_list)) {
|
||||
dwc3_stop_active_transfer(dwc, dep->number, true);
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
}
|
||||
@ -1267,13 +1252,13 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
list_for_each_entry(r, &dep->request_list, list) {
|
||||
list_for_each_entry(r, &dep->pending_list, list) {
|
||||
if (r == req)
|
||||
break;
|
||||
}
|
||||
|
||||
if (r != req) {
|
||||
list_for_each_entry(r, &dep->req_queued, list) {
|
||||
list_for_each_entry(r, &dep->started_list, list) {
|
||||
if (r == req)
|
||||
break;
|
||||
}
|
||||
@ -1313,10 +1298,10 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
|
||||
|
||||
if (value) {
|
||||
if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) ||
|
||||
(!list_empty(&dep->req_queued) ||
|
||||
!list_empty(&dep->request_list)))) {
|
||||
(!list_empty(&dep->started_list) ||
|
||||
!list_empty(&dep->pending_list)))) {
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"%s: pending request, cannot halt\n",
|
||||
"%s: pending request, cannot halt",
|
||||
dep->name);
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -1417,22 +1402,16 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
|
||||
return DWC3_DSTS_SOFFN(reg);
|
||||
}
|
||||
|
||||
static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
|
||||
unsigned long timeout;
|
||||
unsigned long flags;
|
||||
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
u8 link_state;
|
||||
u8 speed;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
/*
|
||||
* According to the Databook Remote wakeup request should
|
||||
* be issued only when the device is in early suspend state.
|
||||
@ -1445,8 +1424,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
if ((speed == DWC3_DSTS_SUPERSPEED) ||
|
||||
(speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
|
||||
dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
link_state = DWC3_DSTS_USBLNKST(reg);
|
||||
@ -1459,14 +1437,13 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
dwc3_trace(trace_dwc3_gadget,
|
||||
"can't wakeup from '%s'\n",
|
||||
dwc3_gadget_link_string(link_state));
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
|
||||
if (ret < 0) {
|
||||
dev_err(dwc->dev, "failed to put link in Recovery\n");
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Recent versions do this automatically */
|
||||
@ -1490,10 +1467,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
|
||||
if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
|
||||
dev_err(dwc->dev, "failed to send remote wakeup\n");
|
||||
ret = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwc3_gadget_wakeup(struct usb_gadget *g)
|
||||
{
|
||||
struct dwc3 *dwc = gadget_to_dwc(g);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = __dwc3_gadget_wakeup(dwc);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
@ -1620,7 +1607,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
||||
|
||||
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
|
||||
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
|
||||
IRQF_SHARED, "dwc3", dwc);
|
||||
IRQF_SHARED, "dwc3", dwc->ev_buf);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
|
||||
irq, ret);
|
||||
@ -1682,6 +1669,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
|
||||
}
|
||||
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
|
||||
|
||||
/*
|
||||
* We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP
|
||||
* field instead of letting dwc3 itself calculate that automatically.
|
||||
*
|
||||
* This way, we maximize the chances that we'll be able to get several
|
||||
* bursts of data without going through any sort of endpoint throttling.
|
||||
*/
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
|
||||
reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
|
||||
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
|
||||
|
||||
/* Start with SuperSpeed Default */
|
||||
dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
|
||||
|
||||
@ -1720,7 +1718,7 @@ err2:
|
||||
err1:
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
free_irq(irq, dwc);
|
||||
free_irq(irq, dwc->ev_buf);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
@ -1743,7 +1741,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
|
||||
free_irq(irq, dwc);
|
||||
free_irq(irq, dwc->ev_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1815,8 +1813,8 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
||||
dep->endpoint.caps.dir_in = !!direction;
|
||||
dep->endpoint.caps.dir_out = !direction;
|
||||
|
||||
INIT_LIST_HEAD(&dep->request_list);
|
||||
INIT_LIST_HEAD(&dep->req_queued);
|
||||
INIT_LIST_HEAD(&dep->pending_list);
|
||||
INIT_LIST_HEAD(&dep->started_list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1913,11 +1911,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
* If there are still queued request
|
||||
* then wait, do not issue either END
|
||||
* or UPDATE TRANSFER, just attach next
|
||||
* request in request_list during
|
||||
* request in pending_list during
|
||||
* giveback.If any future queued request
|
||||
* is successfully transferred then we
|
||||
* will issue UPDATE TRANSFER for all
|
||||
* request in the request_list.
|
||||
* request in the pending_list.
|
||||
*/
|
||||
dep->flags |= DWC3_EP_MISSED_ISOC;
|
||||
} else {
|
||||
@ -1963,15 +1961,14 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
int ret;
|
||||
|
||||
do {
|
||||
req = next_request(&dep->req_queued);
|
||||
req = next_request(&dep->started_list);
|
||||
if (WARN_ON_ONCE(!req))
|
||||
return 1;
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
slot = req->start_slot + i;
|
||||
if ((slot == DWC3_TRB_NUM - 1) &&
|
||||
usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
slot = req->first_trb_index + i;
|
||||
if (slot == DWC3_TRB_NUM - 1)
|
||||
slot++;
|
||||
slot %= DWC3_TRB_NUM;
|
||||
trb = &dep->trb_pool[slot];
|
||||
@ -1989,8 +1986,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
||||
} while (1);
|
||||
|
||||
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
|
||||
list_empty(&dep->req_queued)) {
|
||||
if (list_empty(&dep->request_list)) {
|
||||
list_empty(&dep->started_list)) {
|
||||
if (list_empty(&dep->pending_list)) {
|
||||
/*
|
||||
* If there is no entry in request list then do
|
||||
* not issue END TRANSFER now. Just set PENDING
|
||||
@ -2039,7 +2036,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
|
||||
if (!(dep->flags & DWC3_EP_ENABLED))
|
||||
continue;
|
||||
|
||||
if (!list_empty(&dep->req_queued))
|
||||
if (!list_empty(&dep->started_list))
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2686,14 +2683,13 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
|
||||
static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
struct dwc3 *dwc = evt->dwc;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
int left;
|
||||
u32 reg;
|
||||
|
||||
evt = dwc->ev_buffs[buf];
|
||||
left = evt->count;
|
||||
|
||||
if (!(evt->flags & DWC3_EVENT_PENDING))
|
||||
@ -2718,7 +2714,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
|
||||
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
|
||||
left -= 4;
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 4);
|
||||
}
|
||||
|
||||
evt->count = 0;
|
||||
@ -2726,39 +2722,34 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
/* Unmask interrupt */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
|
||||
reg &= ~DWC3_GEVNTSIZ_INTMASK;
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
|
||||
static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt)
|
||||
{
|
||||
struct dwc3 *dwc = _dwc;
|
||||
struct dwc3_event_buffer *evt = _evt;
|
||||
struct dwc3 *dwc = evt->dwc;
|
||||
unsigned long flags;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
|
||||
for (i = 0; i < dwc->num_event_buffers; i++)
|
||||
ret |= dwc3_process_event_buf(dwc, i);
|
||||
|
||||
ret = dwc3_process_event_buf(evt);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
|
||||
static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
|
||||
{
|
||||
struct dwc3_event_buffer *evt;
|
||||
struct dwc3 *dwc = evt->dwc;
|
||||
u32 count;
|
||||
u32 reg;
|
||||
|
||||
evt = dwc->ev_buffs[buf];
|
||||
|
||||
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
|
||||
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
|
||||
count &= DWC3_GEVNTCOUNT_MASK;
|
||||
if (!count)
|
||||
return IRQ_NONE;
|
||||
@ -2767,28 +2758,18 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
|
||||
evt->flags |= DWC3_EVENT_PENDING;
|
||||
|
||||
/* Mask interrupt */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf));
|
||||
reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0));
|
||||
reg |= DWC3_GEVNTSIZ_INTMASK;
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
|
||||
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
|
||||
static irqreturn_t dwc3_interrupt(int irq, void *_evt)
|
||||
{
|
||||
struct dwc3 *dwc = _dwc;
|
||||
int i;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
struct dwc3_event_buffer *evt = _evt;
|
||||
|
||||
for (i = 0; i < dwc->num_event_buffers; i++) {
|
||||
irqreturn_t status;
|
||||
|
||||
status = dwc3_check_event_buf(dwc, i);
|
||||
if (status == IRQ_WAKE_THREAD)
|
||||
ret = status;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return dwc3_check_event_buf(evt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,12 +68,12 @@ static inline struct dwc3_request *next_request(struct list_head *list)
|
||||
return list_first_entry(list, struct dwc3_request, list);
|
||||
}
|
||||
|
||||
static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
|
||||
static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3_ep *dep = req->dep;
|
||||
|
||||
req->queued = true;
|
||||
list_move_tail(&req->list, &dep->req_queued);
|
||||
req->started = true;
|
||||
list_move_tail(&req->list, &dep->started_list);
|
||||
}
|
||||
|
||||
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
|
@ -23,7 +23,6 @@
|
||||
struct dwc3_platform_data {
|
||||
enum usb_device_speed maximum_speed;
|
||||
enum usb_dr_mode dr_mode;
|
||||
bool tx_fifo_resize;
|
||||
bool usb3_lpm_capable;
|
||||
|
||||
unsigned is_utmi_l1_suspend:1;
|
||||
@ -43,6 +42,7 @@ struct dwc3_platform_data {
|
||||
unsigned dis_u3_susphy_quirk:1;
|
||||
unsigned dis_u2_susphy_quirk:1;
|
||||
unsigned dis_enblslpm_quirk:1;
|
||||
unsigned dis_rxdet_inp3_quirk:1;
|
||||
|
||||
unsigned tx_de_emphasis_quirk:1;
|
||||
unsigned tx_de_emphasis:2;
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
menuconfig USB_GADGET
|
||||
tristate "USB Gadget Support"
|
||||
select USB_COMMON
|
||||
select NLS
|
||||
help
|
||||
USB is a master/slave protocol, organized with one master
|
||||
|
@ -66,20 +66,36 @@ function_descriptors(struct usb_function *f,
|
||||
{
|
||||
struct usb_descriptor_header **descriptors;
|
||||
|
||||
/*
|
||||
* NOTE: we try to help gadget drivers which might not be setting
|
||||
* max_speed appropriately.
|
||||
*/
|
||||
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER_PLUS:
|
||||
descriptors = f->ssp_descriptors;
|
||||
break;
|
||||
if (descriptors)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case USB_SPEED_SUPER:
|
||||
descriptors = f->ss_descriptors;
|
||||
break;
|
||||
if (descriptors)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case USB_SPEED_HIGH:
|
||||
descriptors = f->hs_descriptors;
|
||||
break;
|
||||
if (descriptors)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
descriptors = f->fs_descriptors;
|
||||
}
|
||||
|
||||
/*
|
||||
* if we can't find any descriptors at all, then this gadget deserves to
|
||||
* Oops with a NULL pointer dereference
|
||||
*/
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
|
@ -651,7 +651,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
|
||||
if (io_data->read && ret > 0) {
|
||||
use_mm(io_data->mm);
|
||||
ret = copy_to_iter(io_data->buf, ret, &io_data->data);
|
||||
if (iov_iter_count(&io_data->data))
|
||||
if (ret != io_data->req->actual && iov_iter_count(&io_data->data))
|
||||
ret = -EFAULT;
|
||||
unuse_mm(io_data->mm);
|
||||
}
|
||||
|
@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string);
|
||||
|
||||
int fsg_common_run_thread(struct fsg_common *common)
|
||||
{
|
||||
common->state = FSG_STATE_IDLE;
|
||||
/* Tell the thread to start working */
|
||||
common->thread_task =
|
||||
kthread_create(fsg_main_thread, common, "file-storage");
|
||||
if (IS_ERR(common->thread_task)) {
|
||||
common->state = FSG_STATE_TERMINATED;
|
||||
return PTR_ERR(common->thread_task);
|
||||
}
|
||||
|
||||
DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
|
||||
|
||||
wake_up_process(common->thread_task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_run_thread);
|
||||
|
||||
static void fsg_common_release(struct kref *ref)
|
||||
{
|
||||
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
|
||||
@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref)
|
||||
if (common->state != FSG_STATE_TERMINATED) {
|
||||
raise_exception(common, FSG_STATE_EXIT);
|
||||
wait_for_completion(&common->thread_notifier);
|
||||
common->thread_task = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
|
||||
@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (ret)
|
||||
return ret;
|
||||
fsg_common_set_inquiry_string(fsg->common, NULL, NULL);
|
||||
ret = fsg_common_run_thread(fsg->common);
|
||||
if (ret)
|
||||
}
|
||||
|
||||
if (!common->thread_task) {
|
||||
common->state = FSG_STATE_IDLE;
|
||||
common->thread_task =
|
||||
kthread_create(fsg_main_thread, common, "file-storage");
|
||||
if (IS_ERR(common->thread_task)) {
|
||||
int ret = PTR_ERR(common->thread_task);
|
||||
common->thread_task = NULL;
|
||||
common->state = FSG_STATE_TERMINATED;
|
||||
return ret;
|
||||
}
|
||||
DBG(common, "I/O thread pid: %d\n",
|
||||
task_pid_nr(common->thread_task));
|
||||
wake_up_process(common->thread_task);
|
||||
}
|
||||
|
||||
fsg->gadget = gadget;
|
||||
|
@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg);
|
||||
void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
|
||||
const char *pn);
|
||||
|
||||
int fsg_common_run_thread(struct fsg_common *common);
|
||||
|
||||
void fsg_config_from_params(struct fsg_config *cfg,
|
||||
const struct fsg_module_parameters *params,
|
||||
unsigned int fsg_num_buffers);
|
||||
|
@ -133,10 +133,6 @@ static int acm_ms_do_config(struct usb_configuration *c)
|
||||
if (status < 0)
|
||||
goto put_msg;
|
||||
|
||||
status = fsg_common_run_thread(opts->common);
|
||||
if (status)
|
||||
goto remove_acm;
|
||||
|
||||
status = usb_add_function(c, f_msg);
|
||||
if (status)
|
||||
goto remove_acm;
|
||||
|
@ -132,10 +132,6 @@ static int msg_do_config(struct usb_configuration *c)
|
||||
if (IS_ERR(f_msg))
|
||||
return PTR_ERR(f_msg);
|
||||
|
||||
ret = fsg_common_run_thread(opts->common);
|
||||
if (ret)
|
||||
goto put_func;
|
||||
|
||||
ret = usb_add_function(c, f_msg);
|
||||
if (ret)
|
||||
goto put_func;
|
||||
|
@ -137,7 +137,6 @@ static struct usb_function *f_msg_rndis;
|
||||
|
||||
static int rndis_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct fsg_opts *fsg_opts;
|
||||
int ret;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
@ -169,11 +168,6 @@ static int rndis_do_config(struct usb_configuration *c)
|
||||
goto err_fsg;
|
||||
}
|
||||
|
||||
fsg_opts = fsg_opts_from_func_inst(fi_msg);
|
||||
ret = fsg_common_run_thread(fsg_opts->common);
|
||||
if (ret)
|
||||
goto err_run;
|
||||
|
||||
ret = usb_add_function(c, f_msg_rndis);
|
||||
if (ret)
|
||||
goto err_run;
|
||||
@ -225,7 +219,6 @@ static struct usb_function *f_msg_multi;
|
||||
|
||||
static int cdc_do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct fsg_opts *fsg_opts;
|
||||
int ret;
|
||||
|
||||
if (gadget_is_otg(c->cdev->gadget)) {
|
||||
@ -258,11 +251,6 @@ static int cdc_do_config(struct usb_configuration *c)
|
||||
goto err_fsg;
|
||||
}
|
||||
|
||||
fsg_opts = fsg_opts_from_func_inst(fi_msg);
|
||||
ret = fsg_common_run_thread(fsg_opts->common);
|
||||
if (ret)
|
||||
goto err_run;
|
||||
|
||||
ret = usb_add_function(c, f_msg_multi);
|
||||
if (ret)
|
||||
goto err_run;
|
||||
|
@ -152,7 +152,6 @@ static int nokia_bind_config(struct usb_configuration *c)
|
||||
struct usb_function *f_ecm;
|
||||
struct usb_function *f_obex2 = NULL;
|
||||
struct usb_function *f_msg;
|
||||
struct fsg_opts *fsg_opts;
|
||||
int status = 0;
|
||||
int obex1_stat = -1;
|
||||
int obex2_stat = -1;
|
||||
@ -222,12 +221,6 @@ static int nokia_bind_config(struct usb_configuration *c)
|
||||
goto err_ecm;
|
||||
}
|
||||
|
||||
fsg_opts = fsg_opts_from_func_inst(fi_msg);
|
||||
|
||||
status = fsg_common_run_thread(fsg_opts->common);
|
||||
if (status)
|
||||
goto err_msg;
|
||||
|
||||
status = usb_add_function(c, f_msg);
|
||||
if (status)
|
||||
goto err_msg;
|
||||
|
@ -1726,10 +1726,7 @@ static int at91sam9261_udc_init(struct at91_udc *udc)
|
||||
|
||||
udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node,
|
||||
"atmel,matrix");
|
||||
if (IS_ERR(udc->matrix))
|
||||
return PTR_ERR(udc->matrix);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(udc->matrix);
|
||||
}
|
||||
|
||||
static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)
|
||||
|
@ -325,11 +325,8 @@ struct pch_vbus_gpio_data {
|
||||
* @pdev: reference to the PCI device
|
||||
* @ep: array of endpoints
|
||||
* @lock: protects all state
|
||||
* @active: enabled the PCI device
|
||||
* @stall: stall requested
|
||||
* @prot_stall: protcol stall requested
|
||||
* @irq_registered: irq registered with system
|
||||
* @mem_region: device memory mapped
|
||||
* @registered: driver registered with system
|
||||
* @suspended: driver in suspended state
|
||||
* @connected: gadget driver associated
|
||||
@ -339,12 +336,8 @@ struct pch_vbus_gpio_data {
|
||||
* @data_requests: DMA pool for data requests
|
||||
* @stp_requests: DMA pool for setup requests
|
||||
* @dma_addr: DMA pool for received
|
||||
* @ep0out_buf: Buffer for DMA
|
||||
* @setup_data: Received setup data
|
||||
* @phys_addr: of device memory
|
||||
* @base_addr: for mapped device memory
|
||||
* @bar: Indicates which PCI BAR for USB regs
|
||||
* @irq: IRQ line for the device
|
||||
* @cfg_data: current cfg, intf, and alt in use
|
||||
* @vbus_gpio: GPIO informaton for detecting VBUS
|
||||
*/
|
||||
@ -354,11 +347,9 @@ struct pch_udc_dev {
|
||||
struct pci_dev *pdev;
|
||||
struct pch_udc_ep ep[PCH_UDC_EP_NUM];
|
||||
spinlock_t lock; /* protects all state */
|
||||
unsigned active:1,
|
||||
unsigned
|
||||
stall:1,
|
||||
prot_stall:1,
|
||||
irq_registered:1,
|
||||
mem_region:1,
|
||||
suspended:1,
|
||||
connected:1,
|
||||
vbus_session:1,
|
||||
@ -367,12 +358,8 @@ struct pch_udc_dev {
|
||||
struct pci_pool *data_requests;
|
||||
struct pci_pool *stp_requests;
|
||||
dma_addr_t dma_addr;
|
||||
void *ep0out_buf;
|
||||
struct usb_ctrlrequest setup_data;
|
||||
unsigned long phys_addr;
|
||||
void __iomem *base_addr;
|
||||
unsigned bar;
|
||||
unsigned irq;
|
||||
struct pch_udc_cfg_data cfg_data;
|
||||
struct pch_vbus_gpio_data vbus_gpio;
|
||||
};
|
||||
@ -380,8 +367,10 @@ struct pch_udc_dev {
|
||||
|
||||
#define PCH_UDC_PCI_BAR_QUARK_X1000 0
|
||||
#define PCH_UDC_PCI_BAR 1
|
||||
#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939
|
||||
#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
|
||||
|
||||
#define PCI_VENDOR_ID_ROHM 0x10DB
|
||||
#define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D
|
||||
#define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808
|
||||
@ -1732,14 +1721,12 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
|
||||
static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
|
||||
{
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned long iflags;
|
||||
|
||||
if (!usbep)
|
||||
return -EINVAL;
|
||||
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
if ((usbep->name == ep0_string) || !ep->ep.desc)
|
||||
return -EINVAL;
|
||||
|
||||
@ -1770,12 +1757,10 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
|
||||
struct pch_udc_request *req;
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_data_dma_desc *dma_desc;
|
||||
struct pch_udc_dev *dev;
|
||||
|
||||
if (!usbep)
|
||||
return NULL;
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
req = kzalloc(sizeof *req, gfp);
|
||||
if (!req)
|
||||
return NULL;
|
||||
@ -1948,12 +1933,10 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
|
||||
{
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_request *req;
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
if (!usbep || !usbreq || (!ep->ep.desc && ep->num))
|
||||
return ret;
|
||||
req = container_of(usbreq, struct pch_udc_request, req);
|
||||
@ -1985,14 +1968,12 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
|
||||
static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
|
||||
{
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned long iflags;
|
||||
int ret;
|
||||
|
||||
if (!usbep)
|
||||
return -EINVAL;
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
if (!ep->ep.desc && !ep->num)
|
||||
return -EINVAL;
|
||||
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
|
||||
@ -2030,14 +2011,12 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
|
||||
static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
|
||||
{
|
||||
struct pch_udc_ep *ep;
|
||||
struct pch_udc_dev *dev;
|
||||
unsigned long iflags;
|
||||
int ret;
|
||||
|
||||
if (!usbep)
|
||||
return -EINVAL;
|
||||
ep = container_of(usbep, struct pch_udc_ep, ep);
|
||||
dev = ep->dev;
|
||||
if (!ep->ep.desc && !ep->num)
|
||||
return -EINVAL;
|
||||
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
|
||||
@ -2647,7 +2626,7 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
|
||||
static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
|
||||
{
|
||||
u32 reg, dev_stat = 0;
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
dev_stat = pch_udc_read_device_status(dev);
|
||||
dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >>
|
||||
@ -2676,7 +2655,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
|
||||
}
|
||||
dev->stall = 0;
|
||||
spin_lock(&dev->lock);
|
||||
ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
|
||||
dev->driver->setup(&dev->gadget, &dev->setup_data);
|
||||
spin_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
@ -2687,7 +2666,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
|
||||
*/
|
||||
static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
|
||||
{
|
||||
int i, ret;
|
||||
int i;
|
||||
u32 reg, dev_stat = 0;
|
||||
|
||||
dev_stat = pch_udc_read_device_status(dev);
|
||||
@ -2713,7 +2692,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
|
||||
|
||||
/* call gadget zero with setup data received */
|
||||
spin_lock(&dev->lock);
|
||||
ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
|
||||
dev->driver->setup(&dev->gadget, &dev->setup_data);
|
||||
spin_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
@ -2855,17 +2834,6 @@ static void pch_udc_setup_ep0(struct pch_udc_dev *dev)
|
||||
UDC_DEVINT_SI | UDC_DEVINT_SC);
|
||||
}
|
||||
|
||||
/**
|
||||
* gadget_release() - Free the gadget driver private data
|
||||
* @pdev reference to struct pci_dev
|
||||
*/
|
||||
static void gadget_release(struct device *pdev)
|
||||
{
|
||||
struct pch_udc_dev *dev = dev_get_drvdata(pdev);
|
||||
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* pch_udc_pcd_reinit() - This API initializes the endpoint structures
|
||||
* @dev: Reference to the driver structure
|
||||
@ -2949,6 +2917,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
||||
{
|
||||
struct pch_udc_stp_dma_desc *td_stp;
|
||||
struct pch_udc_data_dma_desc *td_data;
|
||||
void *ep0out_buf;
|
||||
|
||||
/* DMA setup */
|
||||
dev->data_requests = pci_pool_create("data_requests", dev->pdev,
|
||||
@ -2991,10 +2960,11 @@ static int init_dma_pools(struct pch_udc_dev *dev)
|
||||
dev->ep[UDC_EP0IN_IDX].td_data = NULL;
|
||||
dev->ep[UDC_EP0IN_IDX].td_data_phys = 0;
|
||||
|
||||
dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL);
|
||||
if (!dev->ep0out_buf)
|
||||
ep0out_buf = devm_kzalloc(&dev->pdev->dev, UDC_EP0OUT_BUFF_SIZE * 4,
|
||||
GFP_KERNEL);
|
||||
if (!ep0out_buf)
|
||||
return -ENOMEM;
|
||||
dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf,
|
||||
dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf,
|
||||
UDC_EP0OUT_BUFF_SIZE * 4,
|
||||
DMA_FROM_DEVICE);
|
||||
return 0;
|
||||
@ -3078,129 +3048,80 @@ static void pch_udc_remove(struct pci_dev *pdev)
|
||||
if (dev->dma_addr)
|
||||
dma_unmap_single(&dev->pdev->dev, dev->dma_addr,
|
||||
UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
|
||||
kfree(dev->ep0out_buf);
|
||||
|
||||
pch_vbus_gpio_free(dev);
|
||||
|
||||
pch_udc_exit(dev);
|
||||
|
||||
if (dev->irq_registered)
|
||||
free_irq(pdev->irq, dev);
|
||||
if (dev->base_addr)
|
||||
iounmap(dev->base_addr);
|
||||
if (dev->mem_region)
|
||||
release_mem_region(dev->phys_addr,
|
||||
pci_resource_len(pdev, dev->bar));
|
||||
if (dev->active)
|
||||
pci_disable_device(pdev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pch_udc_suspend(struct device *d)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(d);
|
||||
struct pch_udc_dev *dev = pci_get_drvdata(pdev);
|
||||
|
||||
pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
|
||||
pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
pci_enable_wake(pdev, PCI_D3hot, 0);
|
||||
|
||||
if (pci_save_state(pdev)) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s: could not save PCI config state\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pch_udc_resume(struct pci_dev *pdev)
|
||||
static int pch_udc_resume(struct device *d)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
pci_enable_wake(pdev, PCI_D3hot, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume);
|
||||
#define PCH_UDC_PM_OPS (&pch_udc_pm)
|
||||
#else
|
||||
#define pch_udc_suspend NULL
|
||||
#define pch_udc_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
#define PCH_UDC_PM_OPS NULL
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static int pch_udc_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
unsigned long resource;
|
||||
unsigned long len;
|
||||
int bar;
|
||||
int retval;
|
||||
struct pch_udc_dev *dev;
|
||||
|
||||
/* init */
|
||||
dev = kzalloc(sizeof *dev, GFP_KERNEL);
|
||||
if (!dev) {
|
||||
pr_err("%s: no memory for device structure\n", __func__);
|
||||
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* pci setup */
|
||||
if (pci_enable_device(pdev) < 0) {
|
||||
kfree(dev);
|
||||
pr_err("%s: pci_enable_device failed\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
dev->active = 1;
|
||||
retval = pcim_enable_device(pdev);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
/* Determine BAR based on PCI ID */
|
||||
if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC)
|
||||
dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000;
|
||||
bar = PCH_UDC_PCI_BAR_QUARK_X1000;
|
||||
else
|
||||
dev->bar = PCH_UDC_PCI_BAR;
|
||||
bar = PCH_UDC_PCI_BAR;
|
||||
|
||||
/* PCI resource allocation */
|
||||
resource = pci_resource_start(pdev, dev->bar);
|
||||
len = pci_resource_len(pdev, dev->bar);
|
||||
retval = pcim_iomap_regions(pdev, 1 << bar, pci_name(pdev));
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!request_mem_region(resource, len, KBUILD_MODNAME)) {
|
||||
dev_err(&pdev->dev, "%s: pci device used already\n", __func__);
|
||||
retval = -EBUSY;
|
||||
goto finished;
|
||||
}
|
||||
dev->phys_addr = resource;
|
||||
dev->mem_region = 1;
|
||||
dev->base_addr = pcim_iomap_table(pdev)[bar];
|
||||
|
||||
dev->base_addr = ioremap_nocache(resource, len);
|
||||
if (!dev->base_addr) {
|
||||
pr_err("%s: device memory cannot be mapped\n", __func__);
|
||||
retval = -ENOMEM;
|
||||
goto finished;
|
||||
}
|
||||
if (!pdev->irq) {
|
||||
dev_err(&pdev->dev, "%s: irq not set\n", __func__);
|
||||
retval = -ENODEV;
|
||||
goto finished;
|
||||
}
|
||||
/* initialize the hardware */
|
||||
if (pch_udc_pcd_init(dev)) {
|
||||
retval = -ENODEV;
|
||||
goto finished;
|
||||
}
|
||||
if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
|
||||
dev)) {
|
||||
if (pch_udc_pcd_init(dev))
|
||||
return -ENODEV;
|
||||
|
||||
pci_enable_msi(pdev);
|
||||
|
||||
retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr,
|
||||
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||
if (retval) {
|
||||
dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,
|
||||
pdev->irq);
|
||||
retval = -ENODEV;
|
||||
goto finished;
|
||||
}
|
||||
dev->irq = pdev->irq;
|
||||
dev->irq_registered = 1;
|
||||
|
||||
pci_set_master(pdev);
|
||||
pci_try_set_mwi(pdev);
|
||||
@ -3219,8 +3140,7 @@ static int pch_udc_probe(struct pci_dev *pdev,
|
||||
|
||||
/* Put the device in disconnected state till a driver is bound */
|
||||
pch_udc_set_disconnect(dev);
|
||||
retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
|
||||
gadget_release);
|
||||
retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
|
||||
if (retval)
|
||||
goto finished;
|
||||
return 0;
|
||||
@ -3262,9 +3182,10 @@ static struct pci_driver pch_udc_driver = {
|
||||
.id_table = pch_udc_pcidev_id,
|
||||
.probe = pch_udc_probe,
|
||||
.remove = pch_udc_remove,
|
||||
.suspend = pch_udc_suspend,
|
||||
.resume = pch_udc_resume,
|
||||
.shutdown = pch_udc_shutdown,
|
||||
.driver = {
|
||||
.pm = PCH_UDC_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
module_pci_driver(pch_udc_driver);
|
||||
|
@ -296,7 +296,7 @@ static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum,
|
||||
} while ((tmp & mask) != loop);
|
||||
}
|
||||
|
||||
static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
static void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
|
||||
{
|
||||
struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];
|
||||
|
||||
|
@ -61,11 +61,9 @@ static int udc_bind_to_driver(struct usb_udc *udc,
|
||||
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
|
||||
int usb_gadget_map_request(struct usb_gadget *gadget,
|
||||
int usb_gadget_map_request_by_dev(struct device *dev,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
struct device *dev = gadget->dev.parent;
|
||||
|
||||
if (req->length == 0)
|
||||
return 0;
|
||||
|
||||
@ -75,7 +73,7 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
|
||||
mapped = dma_map_sg(dev, req->sg, req->num_sgs,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
if (mapped == 0) {
|
||||
dev_err(&gadget->dev, "failed to map SGs\n");
|
||||
dev_err(dev, "failed to map SGs\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
@ -92,24 +90,38 @@ int usb_gadget_map_request(struct usb_gadget *gadget,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev);
|
||||
|
||||
int usb_gadget_map_request(struct usb_gadget *gadget,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_map_request);
|
||||
|
||||
void usb_gadget_unmap_request(struct usb_gadget *gadget,
|
||||
void usb_gadget_unmap_request_by_dev(struct device *dev,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
if (req->length == 0)
|
||||
return;
|
||||
|
||||
if (req->num_mapped_sgs) {
|
||||
dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs,
|
||||
dma_unmap_sg(dev, req->sg, req->num_mapped_sgs,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
|
||||
req->num_mapped_sgs = 0;
|
||||
} else {
|
||||
dma_unmap_single(gadget->dev.parent, req->dma, req->length,
|
||||
dma_unmap_single(dev, req->dma, req->length,
|
||||
is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev);
|
||||
|
||||
void usb_gadget_unmap_request(struct usb_gadget *gadget,
|
||||
struct usb_request *req, int is_in)
|
||||
{
|
||||
usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
|
||||
|
||||
#endif /* CONFIG_HAS_DMA */
|
||||
|
@ -240,10 +240,7 @@ static int phy_8x16_read_devicetree(struct phy_8x16 *qphy)
|
||||
|
||||
qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(qphy->switch_gpio))
|
||||
return PTR_ERR(qphy->switch_gpio);
|
||||
|
||||
return 0;
|
||||
return PTR_ERR_OR_ZERO(qphy->switch_gpio);
|
||||
}
|
||||
|
||||
static int phy_8x16_reboot_notify(struct notifier_block *this,
|
||||
|
@ -799,8 +799,10 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
||||
struct usbhs_pipe *pipe = pkt->pipe;
|
||||
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
|
||||
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
|
||||
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
|
||||
struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt);
|
||||
|
||||
return info->dma_map_ctrl(pkt, map);
|
||||
return info->dma_map_ctrl(chan->device->dev, pkt, map);
|
||||
}
|
||||
|
||||
static void usbhsf_dma_complete(void *arg);
|
||||
@ -881,12 +883,12 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
|
||||
if (!fifo)
|
||||
goto usbhsf_pio_prepare_push;
|
||||
|
||||
if (usbhsf_dma_map(pkt) < 0)
|
||||
goto usbhsf_pio_prepare_push;
|
||||
|
||||
ret = usbhsf_fifo_select(pipe, fifo, 0);
|
||||
if (ret < 0)
|
||||
goto usbhsf_pio_prepare_push_unmap;
|
||||
goto usbhsf_pio_prepare_push;
|
||||
|
||||
if (usbhsf_dma_map(pkt) < 0)
|
||||
goto usbhsf_pio_prepare_push_unselect;
|
||||
|
||||
pkt->trans = len;
|
||||
|
||||
@ -896,8 +898,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
|
||||
|
||||
return 0;
|
||||
|
||||
usbhsf_pio_prepare_push_unmap:
|
||||
usbhsf_dma_unmap(pkt);
|
||||
usbhsf_pio_prepare_push_unselect:
|
||||
usbhsf_fifo_unselect(pipe, fifo);
|
||||
usbhsf_pio_prepare_push:
|
||||
/*
|
||||
* change handler to PIO
|
||||
|
@ -191,13 +191,12 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,
|
||||
/*
|
||||
* dma map/unmap
|
||||
*/
|
||||
static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
||||
static int usbhsg_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt,
|
||||
int map)
|
||||
{
|
||||
struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
|
||||
struct usb_request *req = &ureq->req;
|
||||
struct usbhs_pipe *pipe = pkt->pipe;
|
||||
struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
|
||||
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
|
||||
enum dma_data_direction dir;
|
||||
int ret = 0;
|
||||
|
||||
@ -207,13 +206,13 @@ static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
||||
/* it can not use scatter/gather */
|
||||
WARN_ON(req->num_sgs);
|
||||
|
||||
ret = usb_gadget_map_request(&gpriv->gadget, req, dir);
|
||||
ret = usb_gadget_map_request_by_dev(dma_dev, req, dir);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pkt->dma = req->dma;
|
||||
} else {
|
||||
usb_gadget_unmap_request(&gpriv->gadget, req, dir);
|
||||
usb_gadget_unmap_request_by_dev(dma_dev, req, dir);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -929,7 +929,8 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
|
||||
/*
|
||||
* dma map functions
|
||||
*/
|
||||
static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
||||
static int usbhsh_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt,
|
||||
int map)
|
||||
{
|
||||
if (map) {
|
||||
struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);
|
||||
|
@ -655,7 +655,8 @@ static void usbhsp_put_pipe(struct usbhs_pipe *pipe)
|
||||
}
|
||||
|
||||
void usbhs_pipe_init(struct usbhs_priv *priv,
|
||||
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map))
|
||||
int (*dma_map_ctrl)(struct device *dma_dev,
|
||||
struct usbhs_pkt *pkt, int map))
|
||||
{
|
||||
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
|
||||
struct usbhs_pipe *pipe;
|
||||
|
@ -47,7 +47,8 @@ struct usbhs_pipe_info {
|
||||
struct usbhs_pipe *pipe;
|
||||
int size; /* array size of "pipe" */
|
||||
|
||||
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map);
|
||||
int (*dma_map_ctrl)(struct device *dma_dev, struct usbhs_pkt *pkt,
|
||||
int map);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -84,7 +85,8 @@ int usbhs_pipe_is_running(struct usbhs_pipe *pipe);
|
||||
void usbhs_pipe_running(struct usbhs_pipe *pipe, int running);
|
||||
|
||||
void usbhs_pipe_init(struct usbhs_priv *priv,
|
||||
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map));
|
||||
int (*dma_map_ctrl)(struct device *dma_dev,
|
||||
struct usbhs_pkt *pkt, int map));
|
||||
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
|
||||
void usbhs_pipe_clear(struct usbhs_pipe *pipe);
|
||||
int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
|
||||
|
@ -1223,9 +1223,13 @@ int usb_otg_descriptor_init(struct usb_gadget *gadget,
|
||||
|
||||
/* utility to simplify map/unmap of usb_requests to/from DMA */
|
||||
|
||||
extern int usb_gadget_map_request_by_dev(struct device *dev,
|
||||
struct usb_request *req, int is_in);
|
||||
extern int usb_gadget_map_request(struct usb_gadget *gadget,
|
||||
struct usb_request *req, int is_in);
|
||||
|
||||
extern void usb_gadget_unmap_request_by_dev(struct device *dev,
|
||||
struct usb_request *req, int is_in);
|
||||
extern void usb_gadget_unmap_request(struct usb_gadget *gadget,
|
||||
struct usb_request *req, int is_in);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user