USB changes for v4.21

So it looks like folks are interested in dwc3 again. Almost 64% of the
 changes are in dwc3 this time around with some other bits in gadget
 functions and dwc2.
 
 There are two important parts here: a. removal of the waitqueue from
 dwc3's dequeue implementation, which will guarantee that gadget
 functions can dequeue from any context and; b. better method for
 starting isochronous transfers to avoid, as much as possible, missed
 isoc frames.
 
 Apart from these, we have the usual set of non-critical fixes and new
 features all over the place.
 -----BEGIN PGP SIGNATURE-----
 
 iQJRBAABCAA7FiEElLzh7wn96CXwjh2IzL64meEamQYFAlwQ7sQdHGZlbGlwZS5i
 YWxiaUBsaW51eC5pbnRlbC5jb20ACgkQzL64meEamQbioA//fSpx5SV7undE1skG
 lgjx7Uv2lqnU1kJxhTtyH54tZVhGMmaz4mDVJ3bRk4xotdh3BGQ7nRuui9PDGZmC
 81bSjRBVvHXG0xtQQ1AjNc6vTf5h2MVRAZ4U2dp7pkNOgkoWQSakyH3Tz4Brhpfh
 UWHLaVYrCb2R68b1pmQbJ6ckSkOu9Wt1yj3SJxvSOkRdbSgb9+khTNZJyyWuGort
 zw6pcK33AuLwfOuz7qk8Wihqwi6BOgSrCGU8UfspBRfGhZrw3DSTnS3wYZjdR0QF
 2/jwoBwt59i2hpFsMHmMYGU+307oVQ6Y9b/PXpnj4KqIG2CROB8eirDFkToxe4hC
 Udy06IA70HUTBKzFmK1gCKZCZW3t2sB+zHtoVHJ8EARlFHWdLxLp83hA9p2Llfon
 41iKnkf9CTiO2koEEzuOUOQW+KctIawryiUi4m+C5ZhJBKNk4GvIpXAg1JC9QX9E
 GyqEICkg1dvc3GG5HYjPU7xq8mEdcHVOrHoiUci4zo9hMh6nHt7dboNeXQ13LNU9
 joEqLvKEhUsm0J7cKWYOpxlHmNWGWNgqRas4Mot9zLUP7yYrxqLT5b2hD3PcjPl4
 Jl+rbm4/2YMztWAnCU85EEPwVgJx9k7uyAEtXtQaWUValsVsWUWI1/F//IjYeLZI
 AUx1euoarbCp6mXIoHLsOHV02uc=
 =n8VS
 -----END PGP SIGNATURE-----

Merge tag 'usb-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

Felipe writes:

USB changes for v4.21

So it looks like folks are interested in dwc3 again. Almost 64% of the
changes are in dwc3 this time around with some other bits in gadget
functions and dwc2.

There are two important parts here: a. removal of the waitqueue from
dwc3's dequeue implementation, which will guarantee that gadget
functions can dequeue from any context and; b. better method for
starting isochronous transfers to avoid, as much as possible, missed
isoc frames.

Apart from these, we have the usual set of non-critical fixes and new
features all over the place.

* tag 'usb-for-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (56 commits)
  usb: dwc2: Fix disable all EP's on disconnect
  usb: dwc3: gadget: Disable CSP for stream OUT ep
  usb: dwc2: disable power_down on Amlogic devices
  Revert "usb: dwc3: pci: Use devm functions to get the phy GPIOs"
  USB: gadget: udc: s3c2410_udc: convert to DEFINE_SHOW_ATTRIBUTE
  usb: mtu3: fix dbginfo in qmu_tx_zlp_error_handler
  usb: dwc3: trace: add missing break statement to make compiler happy
  usb: dwc3: gadget: Report isoc transfer frame number
  usb: gadget: Introduce frame_number to usb_request
  usb: renesas_usbhs: Use SIMPLE_DEV_PM_OPS macro
  usb: renesas_usbhs: Remove dummy runtime PM callbacks
  usb: dwc2: host: use hrtimer for NAK retries
  usb: mtu3: clear SOFTCONN when clear USB3_EN if work as HS mode
  usb: mtu3: enable SETUPENDISR interrupt
  usb: mtu3: fix the issue about SetFeature(U1/U2_Enable)
  usb: mtu3: enable hardware remote wakeup from L1 automatically
  usb: mtu3: remove QMU checksum
  usb/mtu3: power down device ip at setup
  usb: dwc2: Disable power down feature on Samsung SoCs
  usb: dwc3: Correct the logic for checking TRB full in __dwc3_prepare_one_trb()
  ...
This commit is contained in:
Greg Kroah-Hartman 2018-12-12 12:29:23 +01:00
commit 5ac93d0c5d
25 changed files with 777 additions and 241 deletions

View File

@ -37,7 +37,11 @@ Optional properties:
- phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
or "usb3-phy".
- resets: a single pair of phandle and reset specifier
- snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
- snps,dis-start-transfer-quirk: when set, disable isoc START TRANSFER command
failure SW work-around for DWC_usb31 version 1.70a-ea06
and prior.
- snps,disable_scramble_quirk: true when SW should disable data scrambling.
Only really useful for FPGA builds.
- snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled

View File

@ -262,7 +262,7 @@ static void dwc2_gadget_wkup_alert_handler(struct dwc2_hsotg *hsotg)
if (gintsts2 & GINTSTS2_WKUP_ALERT_INT) {
dev_dbg(hsotg->dev, "%s: Wkup_Alert_Int\n", __func__);
dwc2_clear_bit(hsotg, GINTSTS2, GINTSTS2_WKUP_ALERT_INT);
dwc2_set_bit(hsotg, DCFG, DCTL_RMTWKUPSIG);
dwc2_set_bit(hsotg, DCTL, DCTL_RMTWKUPSIG);
}
}
@ -3165,8 +3165,6 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg,
dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index);
}
static int dwc2_hsotg_ep_disable(struct usb_ep *ep);
/**
* dwc2_hsotg_disconnect - disconnect service
* @hsotg: The device state.
@ -3188,9 +3186,11 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
/* all endpoints should be shutdown */
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
kill_all_requests(hsotg, hsotg->eps_in[ep],
-ESHUTDOWN);
if (hsotg->eps_out[ep])
dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
kill_all_requests(hsotg, hsotg->eps_out[ep],
-ESHUTDOWN);
}
call_gadget(hsotg, disconnect);
@ -3234,6 +3234,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
GINTSTS_PTXFEMP | \
GINTSTS_RXFLVL)
static int dwc2_hsotg_ep_disable(struct usb_ep *ep);
/**
* dwc2_hsotg_core_init - issue softreset to the core
* @hsotg: The device state
@ -4069,10 +4070,8 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
struct dwc2_hsotg *hsotg = hs_ep->parent;
int dir_in = hs_ep->dir_in;
int index = hs_ep->index;
unsigned long flags;
u32 epctrl_reg;
u32 ctrl;
int locked;
dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep);
@ -4088,10 +4087,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
locked = spin_is_locked(&hsotg->lock);
if (!locked)
spin_lock_irqsave(&hsotg->lock, flags);
ctrl = dwc2_readl(hsotg, epctrl_reg);
if (ctrl & DXEPCTL_EPENA)
@ -4114,12 +4109,22 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
hs_ep->fifo_index = 0;
hs_ep->fifo_size = 0;
if (!locked)
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
}
static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep)
{
struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hsotg = hs_ep->parent;
unsigned long flags;
int ret;
spin_lock_irqsave(&hsotg->lock, flags);
ret = dwc2_hsotg_ep_disable(ep);
spin_unlock_irqrestore(&hsotg->lock, flags);
return ret;
}
/**
* on_list - check request is on the given endpoint
* @ep: The endpoint to check.
@ -4267,7 +4272,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
static const struct usb_ep_ops dwc2_hsotg_ep_ops = {
.enable = dwc2_hsotg_ep_enable,
.disable = dwc2_hsotg_ep_disable,
.disable = dwc2_hsotg_ep_disable_lock,
.alloc_request = dwc2_hsotg_ep_alloc_request,
.free_request = dwc2_hsotg_ep_free_request,
.queue = dwc2_hsotg_ep_queue_lock,
@ -4407,9 +4412,9 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
/* all endpoints should be shutdown */
for (ep = 1; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
if (hsotg->eps_out[ep])
dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep);
}
spin_lock_irqsave(&hsotg->lock, flags);
@ -4857,9 +4862,9 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
if (hsotg->eps_out[ep])
dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep);
}
}
@ -5026,6 +5031,7 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg)
val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0;
val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT;
val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0;
val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC;
dwc2_writel(hsotg, val, GLPMCFG);
dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG));

View File

@ -366,7 +366,7 @@ struct dwc2_qh {
u32 desc_list_sz;
u32 *n_bytes;
struct timer_list unreserve_timer;
struct timer_list wait_timer;
struct hrtimer wait_timer;
struct dwc2_tt *dwc_tt;
int ttport;
unsigned tt_buffer_dirty:1;

View File

@ -59,7 +59,7 @@
#define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5))
/* If we get a NAK, wait this long before retrying */
#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1))
#define DWC2_RETRY_WAIT_DELAY 1*1E6L
/**
* dwc2_periodic_channel_available() - Checks that a channel is available for a
@ -1464,10 +1464,12 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
* qh back to the "inactive" list, then queues transactions.
*
* @t: Pointer to wait_timer in a qh.
*
* Return: HRTIMER_NORESTART to not automatically restart this timer.
*/
static void dwc2_wait_timer_fn(struct timer_list *t)
static enum hrtimer_restart dwc2_wait_timer_fn(struct hrtimer *t)
{
struct dwc2_qh *qh = from_timer(qh, t, wait_timer);
struct dwc2_qh *qh = container_of(t, struct dwc2_qh, wait_timer);
struct dwc2_hsotg *hsotg = qh->hsotg;
unsigned long flags;
@ -1491,6 +1493,7 @@ static void dwc2_wait_timer_fn(struct timer_list *t)
}
spin_unlock_irqrestore(&hsotg->lock, flags);
return HRTIMER_NORESTART;
}
/**
@ -1521,7 +1524,8 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
/* Initialize QH */
qh->hsotg = hsotg;
timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0);
timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0);
hrtimer_init(&qh->wait_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
qh->wait_timer.function = &dwc2_wait_timer_fn;
qh->ep_type = ep_type;
qh->ep_is_in = ep_is_in;
@ -1690,7 +1694,7 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
* won't do anything anyway, but we want it to finish before we free
* memory.
*/
del_timer_sync(&qh->wait_timer);
hrtimer_cancel(&qh->wait_timer);
dwc2_host_put_tt_info(hsotg, qh->dwc_tt);
@ -1716,6 +1720,7 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
int status;
u32 intr_mask;
ktime_t delay;
if (dbg_qh(qh))
dev_vdbg(hsotg->dev, "%s()\n", __func__);
@ -1734,8 +1739,8 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_waiting);
qh->wait_timer_cancel = false;
mod_timer(&qh->wait_timer,
jiffies + DWC2_RETRY_WAIT_DELAY + 1);
delay = ktime_set(0, DWC2_RETRY_WAIT_DELAY);
hrtimer_start(&qh->wait_timer, delay, HRTIMER_MODE_REL);
} else {
list_add_tail(&qh->qh_list_entry,
&hsotg->non_periodic_sched_inactive);

View File

@ -333,6 +333,8 @@
#define GLPMCFG_SNDLPM BIT(24)
#define GLPMCFG_RETRY_CNT_MASK (0x7 << 21)
#define GLPMCFG_RETRY_CNT_SHIFT 21
#define GLPMCFG_LPM_ACCEPT_CTRL_CONTROL BIT(21)
#define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22)
#define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17)
#define GLPMCFG_LPM_CHNL_INDX_SHIFT 17
#define GLPMCFG_L1RESUMEOK BIT(16)

View File

@ -71,6 +71,13 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
p->power_down = false;
}
static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->power_down = 0;
}
static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
@ -111,6 +118,7 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg)
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 <<
GAHBCFG_HBSTLEN_SHIFT;
p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
}
static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
@ -151,7 +159,8 @@ const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
{ .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
{ .compatible = "snps,dwc2" },
{ .compatible = "samsung,s3c6400-hsotg" },
{ .compatible = "samsung,s3c6400-hsotg",
.data = dwc2_set_s3c6400_params },
{ .compatible = "amlogic,meson8-usb",
.data = dwc2_set_amlogic_params },
{ .compatible = "amlogic,meson8b-usb",

View File

@ -80,11 +80,12 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
mode = USB_DR_MODE_PERIPHERAL;
/*
* dwc_usb31 does not support OTG mode. If the controller
* supports DRD but the dr_mode is not specified or set to OTG,
* then set the mode to peripheral.
* DWC_usb31 and DWC_usb3 v3.30a and higher do not support OTG
* mode. If the controller supports DRD but the dr_mode is not
* specified or set to OTG, then set the mode to peripheral.
*/
if (mode == USB_DR_MODE_OTG && dwc3_is_usb31(dwc))
if (mode == USB_DR_MODE_OTG &&
dwc->revision >= DWC3_REVISION_330A)
mode = USB_DR_MODE_PERIPHERAL;
}
@ -661,6 +662,8 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
if (dwc->dis_enblslpm_quirk)
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
else
reg |= DWC3_GUSB2PHYCFG_ENBLSLPM;
if (dwc->dis_u2_freeclk_exists_quirk)
reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
@ -702,6 +705,7 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc)
/* Detected DWC_usb31 IP */
dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
dwc->revision |= DWC3_REVISION_IS_DWC31;
dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE);
} else {
return false;
}
@ -1244,8 +1248,12 @@ static void dwc3_get_properties(struct dwc3 *dwc)
"snps,is-utmi-l1-suspend");
device_property_read_u8(dev, "snps,hird-threshold",
&hird_threshold);
dwc->dis_start_transfer_quirk = device_property_read_bool(dev,
"snps,dis-start-transfer-quirk");
dwc->usb3_lpm_capable = device_property_read_bool(dev,
"snps,usb3_lpm_capable");
dwc->usb2_lpm_disable = device_property_read_bool(dev,
"snps,usb2-lpm-disable");
device_property_read_u8(dev, "snps,rx-thr-num-pkt-prd",
&rx_thr_num_pkt_prd);
device_property_read_u8(dev, "snps,rx-max-burst-prd",
@ -1482,7 +1490,8 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_core_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize core\n");
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize core: %d\n", ret);
goto err4;
}

View File

@ -37,6 +37,7 @@
#define DWC3_EP0_SETUP_SIZE 512
#define DWC3_ENDPOINTS_NUM 32
#define DWC3_XHCI_RESOURCES_NUM 2
#define DWC3_ISOC_MAX_RETRIES 5
#define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */
#define DWC3_EVENT_BUFFERS_SIZE 4096
@ -174,13 +175,19 @@
#define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */
#define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff
/* Global Debug LSP MUX Select */
#define DWC3_GDBGLSPMUX_ENDBC BIT(15) /* Host only */
#define DWC3_GDBGLSPMUX_HOSTSELECT(n) ((n) & 0x3fff)
#define DWC3_GDBGLSPMUX_DEVSELECT(n) (((n) & 0xf) << 4)
#define DWC3_GDBGLSPMUX_EPSELECT(n) ((n) & 0xf)
/* 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 0
#define DWC3_RXFIFOQ 1
#define DWC3_TXFIFO 0
#define DWC3_RXFIFO 1
#define DWC3_TXREQQ 2
#define DWC3_RXREQQ 3
#define DWC3_RXINFOQ 4
@ -253,6 +260,9 @@
#define DWC3_GSTS_DEVICE_IP BIT(6)
#define DWC3_GSTS_CSR_TIMEOUT BIT(5)
#define DWC3_GSTS_BUS_ERR_ADDR_VLD BIT(4)
#define DWC3_GSTS_CURMOD(n) ((n) & 0x3)
#define DWC3_GSTS_CURMOD_DEVICE 0
#define DWC3_GSTS_CURMOD_HOST 1
/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31)
@ -321,6 +331,7 @@
#define DWC3_GHWPARAMS1_EN_PWROPT_HIB 2
#define DWC3_GHWPARAMS1_PWROPT(n) ((n) << 24)
#define DWC3_GHWPARAMS1_PWROPT_MASK DWC3_GHWPARAMS1_PWROPT(3)
#define DWC3_GHWPARAMS1_ENDBC BIT(31)
/* Global HWPARAMS3 Register */
#define DWC3_GHWPARAMS3_SSPHY_IFC(n) ((n) & 3)
@ -636,9 +647,9 @@ struct dwc3_event_buffer {
/**
* struct dwc3_ep - device side endpoint representation
* @endpoint: usb endpoint
* @cancelled_list: list of cancelled requests for this endpoint
* @pending_list: list of pending requests for this endpoint
* @started_list: list of started requests on this endpoint
* @wait_end_transfer: wait_queue_head_t for waiting on End Transfer complete
* @lock: spinlock for endpoint request queue traversal
* @regs: pointer to first endpoint register
* @trb_pool: array of transaction buffers
@ -656,14 +667,17 @@ struct dwc3_event_buffer {
* @name: a human readable name e.g. ep1out-bulk
* @direction: true for TX, false for RX
* @stream_capable: true when streams are enabled
* @combo_num: the test combination BIT[15:14] of the frame number to test
* isochronous START TRANSFER command failure workaround
* @start_cmd_status: the status of testing START TRANSFER command with
* combo_num = 'b00
*/
struct dwc3_ep {
struct usb_ep endpoint;
struct list_head cancelled_list;
struct list_head pending_list;
struct list_head started_list;
wait_queue_head_t wait_end_transfer;
spinlock_t lock;
void __iomem *regs;
@ -705,6 +719,10 @@ struct dwc3_ep {
unsigned direction:1;
unsigned stream_capable:1;
/* For isochronous START TRANSFER workaround only */
u8 combo_num;
int start_cmd_status;
};
enum dwc3_phy {
@ -766,6 +784,7 @@ enum dwc3_link_state {
#define DWC3_TRB_CTRL_ISP_IMI BIT(10)
#define DWC3_TRB_CTRL_IOC BIT(11)
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
#define DWC3_TRB_CTRL_GET_SID_SOFN(n) (((n) & (0xffff << 14)) >> 14)
#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4))
#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1)
@ -847,11 +866,12 @@ struct dwc3_hwparams {
* @epnum: endpoint number to which this request refers
* @trb: pointer to struct dwc3_trb
* @trb_dma: DMA address of @trb
* @unaligned: true for OUT endpoints with length not divisible by maxp
* @num_trbs: number of TRBs used by this request
* @needs_extra_trb: true when request needs one extra TRB (either due to ZLP
* or unaligned OUT)
* @direction: IN or OUT direction flag
* @mapped: true when request has been dma-mapped
* @started: request is started
* @zero: wants a ZLP
*/
struct dwc3_request {
struct usb_request request;
@ -867,11 +887,12 @@ struct dwc3_request {
struct dwc3_trb *trb;
dma_addr_t trb_dma;
unsigned unaligned:1;
unsigned num_trbs;
unsigned needs_extra_trb:1;
unsigned direction:1;
unsigned mapped:1;
unsigned started:1;
unsigned zero:1;
};
/*
@ -918,6 +939,7 @@ struct dwc3_scratchpad_array {
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
* @revision: revision register contents
* @version_type: VERSIONTYPE register contents, a sub release of a revision
* @dr_mode: requested mode of operation
* @current_dr_role: current role of operation when in dual-role mode
* @desired_dr_role: desired role of operation when in dual-role mode
@ -945,6 +967,7 @@ struct dwc3_scratchpad_array {
* @hwparams: copy of hwparams registers
* @root: debugfs root folder pointer
* @regset: debugfs pointer to regdump file
* @dbg_lsp_select: current debug lsp mux register selection
* @test_mode: true when we're entering a USB test mode
* @test_mode_nr: test feature selector
* @lpm_nyet_threshold: LPM NYET response threshold
@ -970,7 +993,10 @@ struct dwc3_scratchpad_array {
* @pullups_connected: true when Run/Stop bit is set
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @three_stage_setup: set if we perform a three phase setup
* @dis_start_transfer_quirk: set if start_transfer failure SW workaround is
* not needed for DWC_usb31 version 1.70a-ea06 and below
* @usb3_lpm_capable: set if hadrware supports Link Power Management
* @usb2_lpm_disable: set to disable usb2 lpm
* @disable_scramble_quirk: set if we enable the disable scramble quirk
* @u2exit_lfps_quirk: set if we enable u2exit lfps quirk
* @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk
@ -1095,6 +1121,7 @@ struct dwc3 {
#define DWC3_REVISION_290A 0x5533290a
#define DWC3_REVISION_300A 0x5533300a
#define DWC3_REVISION_310A 0x5533310a
#define DWC3_REVISION_330A 0x5533330a
/*
* NOTICE: we're using bit 31 as a "is usb 3.1" flag. This is really
@ -1103,6 +1130,17 @@ struct dwc3 {
#define DWC3_REVISION_IS_DWC31 0x80000000
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31)
#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31)
#define DWC3_USB31_REVISION_160A (0x3136302a | DWC3_REVISION_IS_DWC31)
#define DWC3_USB31_REVISION_170A (0x3137302a | DWC3_REVISION_IS_DWC31)
u32 version_type;
#define DWC31_VERSIONTYPE_EA01 0x65613031
#define DWC31_VERSIONTYPE_EA02 0x65613032
#define DWC31_VERSIONTYPE_EA03 0x65613033
#define DWC31_VERSIONTYPE_EA04 0x65613034
#define DWC31_VERSIONTYPE_EA05 0x65613035
#define DWC31_VERSIONTYPE_EA06 0x65613036
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@ -1121,6 +1159,8 @@ struct dwc3 {
struct dentry *root;
struct debugfs_regset32 *regset;
u32 dbg_lsp_select;
u8 test_mode;
u8 test_mode_nr;
u8 lpm_nyet_threshold;
@ -1145,7 +1185,9 @@ struct dwc3 {
unsigned pullups_connected:1;
unsigned setup_packet_pending:1;
unsigned three_stage_setup:1;
unsigned dis_start_transfer_quirk:1;
unsigned usb3_lpm_capable:1;
unsigned usb2_lpm_disable:1;
unsigned disable_scramble_quirk:1;
unsigned u2exit_lfps_quirk:1;

View File

@ -116,6 +116,35 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
}
}
/**
* dwc3_gadget_hs_link_string - returns highspeed and below link name
* @link_state: link state code
*/
static inline const char *
dwc3_gadget_hs_link_string(enum dwc3_link_state link_state)
{
switch (link_state) {
case DWC3_LINK_STATE_U0:
return "On";
case DWC3_LINK_STATE_U2:
return "Sleep";
case DWC3_LINK_STATE_U3:
return "Suspend";
case DWC3_LINK_STATE_SS_DIS:
return "Disconnected";
case DWC3_LINK_STATE_RX_DET:
return "Early Suspend";
case DWC3_LINK_STATE_RECOV:
return "Recovery";
case DWC3_LINK_STATE_RESET:
return "Reset";
case DWC3_LINK_STATE_RESUME:
return "Resume";
default:
return "UNKNOWN link state\n";
}
}
/**
* dwc3_trb_type_string - returns TRB type as a string
* @type: the type of the TRB

View File

@ -25,6 +25,8 @@
#include "io.h"
#include "debug.h"
#define DWC3_LSP_MUX_UNSELECTED 0xfffff
#define dump_register(nm) \
{ \
.name = __stringify(nm), \
@ -82,10 +84,6 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GDBGFIFOSPACE),
dump_register(GDBGLTSSM),
dump_register(GDBGBMU),
dump_register(GDBGLSPMUX),
dump_register(GDBGLSP),
dump_register(GDBGEPINFO0),
dump_register(GDBGEPINFO1),
dump_register(GPRTBIMAP_HS0),
dump_register(GPRTBIMAP_HS1),
dump_register(GPRTBIMAP_FS0),
@ -279,6 +277,114 @@ static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(OSTS),
};
static void dwc3_host_lsp(struct seq_file *s)
{
struct dwc3 *dwc = s->private;
bool dbc_enabled;
u32 sel;
u32 reg;
u32 val;
dbc_enabled = !!(dwc->hwparams.hwparams1 & DWC3_GHWPARAMS1_ENDBC);
sel = dwc->dbg_lsp_select;
if (sel == DWC3_LSP_MUX_UNSELECTED) {
seq_puts(s, "Write LSP selection to print for host\n");
return;
}
reg = DWC3_GDBGLSPMUX_HOSTSELECT(sel);
dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
val = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", sel, val);
if (dbc_enabled && sel < 256) {
reg |= DWC3_GDBGLSPMUX_ENDBC;
dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
val = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
seq_printf(s, "GDBGLSP_DBC[%d] = 0x%08x\n", sel, val);
}
}
static void dwc3_gadget_lsp(struct seq_file *s)
{
struct dwc3 *dwc = s->private;
int i;
u32 reg;
for (i = 0; i < 16; i++) {
reg = DWC3_GDBGLSPMUX_DEVSELECT(i);
dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
reg = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", i, reg);
}
}
static int dwc3_lsp_show(struct seq_file *s, void *unused)
{
struct dwc3 *dwc = s->private;
unsigned int current_mode;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS);
current_mode = DWC3_GSTS_CURMOD(reg);
switch (current_mode) {
case DWC3_GSTS_CURMOD_HOST:
dwc3_host_lsp(s);
break;
case DWC3_GSTS_CURMOD_DEVICE:
dwc3_gadget_lsp(s);
break;
default:
seq_puts(s, "Mode is unknown, no LSP register printed\n");
break;
}
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
static int dwc3_lsp_open(struct inode *inode, struct file *file)
{
return single_open(file, dwc3_lsp_show, inode->i_private);
}
static ssize_t dwc3_lsp_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct dwc3 *dwc = s->private;
unsigned long flags;
char buf[32] = { 0 };
u32 sel;
int ret;
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
ret = kstrtouint(buf, 0, &sel);
if (ret)
return ret;
spin_lock_irqsave(&dwc->lock, flags);
dwc->dbg_lsp_select = sel;
spin_unlock_irqrestore(&dwc->lock, flags);
return count;
}
static const struct file_operations dwc3_lsp_fops = {
.open = dwc3_lsp_open,
.write = dwc3_lsp_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int dwc3_mode_show(struct seq_file *s, void *unused)
{
struct dwc3 *dwc = s->private;
@ -433,13 +539,24 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
unsigned long flags;
enum dwc3_link_state state;
u32 reg;
u8 speed;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS);
if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) {
seq_puts(s, "Not available\n");
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
state = DWC3_DSTS_USBLNKST(reg);
spin_unlock_irqrestore(&dwc->lock, flags);
speed = reg & DWC3_DSTS_CONNECTSPD;
seq_printf(s, "%s\n", dwc3_gadget_link_string(state));
seq_printf(s, "%s\n", (speed >= DWC3_DSTS_SUPERSPEED) ?
dwc3_gadget_link_string(state) :
dwc3_gadget_hs_link_string(state));
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
@ -457,6 +574,8 @@ static ssize_t dwc3_link_state_write(struct file *file,
unsigned long flags;
enum dwc3_link_state state = 0;
char buf[32];
u32 reg;
u8 speed;
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
@ -477,6 +596,21 @@ static ssize_t dwc3_link_state_write(struct file *file,
return -EINVAL;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS);
if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) {
spin_unlock_irqrestore(&dwc->lock, flags);
return -EINVAL;
}
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
speed = reg & DWC3_DSTS_CONNECTSPD;
if (speed < DWC3_DSTS_SUPERSPEED &&
state != DWC3_LINK_STATE_RECOV) {
spin_unlock_irqrestore(&dwc->lock, flags);
return -EINVAL;
}
dwc3_gadget_set_link_state(dwc, state);
spin_unlock_irqrestore(&dwc->lock, flags);
@ -496,7 +630,7 @@ struct dwc3_ep_file_map {
const struct file_operations *const fops;
};
static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused)
static int dwc3_tx_fifo_size_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
@ -504,14 +638,18 @@ static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused)
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ);
val = dwc3_core_fifo_space(dep, DWC3_TXFIFO);
/* Convert to bytes */
val *= DWC3_MDWIDTH(dwc->hwparams.hwparams0);
val >>= 3;
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)
static int dwc3_rx_fifo_size_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
@ -519,7 +657,11 @@ static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused)
u32 val;
spin_lock_irqsave(&dwc->lock, flags);
val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ);
val = dwc3_core_fifo_space(dep, DWC3_RXFIFO);
/* Convert to bytes */
val *= DWC3_MDWIDTH(dwc->hwparams.hwparams0);
val >>= 3;
seq_printf(s, "%u\n", val);
spin_unlock_irqrestore(&dwc->lock, flags);
@ -675,8 +817,32 @@ out:
return 0;
}
DEFINE_SHOW_ATTRIBUTE(dwc3_tx_fifo_queue);
DEFINE_SHOW_ATTRIBUTE(dwc3_rx_fifo_queue);
static int dwc3_ep_info_register_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
struct dwc3 *dwc = dep->dwc;
unsigned long flags;
u64 ep_info;
u32 lower_32_bits;
u32 upper_32_bits;
u32 reg;
spin_lock_irqsave(&dwc->lock, flags);
reg = DWC3_GDBGLSPMUX_EPSELECT(dep->number);
dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
lower_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO0);
upper_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO1);
ep_info = ((u64)upper_32_bits << 32) | lower_32_bits;
seq_printf(s, "0x%016llx\n", ep_info);
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(dwc3_tx_fifo_size);
DEFINE_SHOW_ATTRIBUTE(dwc3_rx_fifo_size);
DEFINE_SHOW_ATTRIBUTE(dwc3_tx_request_queue);
DEFINE_SHOW_ATTRIBUTE(dwc3_rx_request_queue);
DEFINE_SHOW_ATTRIBUTE(dwc3_rx_info_queue);
@ -684,10 +850,11 @@ DEFINE_SHOW_ATTRIBUTE(dwc3_descriptor_fetch_queue);
DEFINE_SHOW_ATTRIBUTE(dwc3_event_queue);
DEFINE_SHOW_ATTRIBUTE(dwc3_transfer_type);
DEFINE_SHOW_ATTRIBUTE(dwc3_trb_ring);
DEFINE_SHOW_ATTRIBUTE(dwc3_ep_info_register);
static const struct dwc3_ep_file_map dwc3_ep_file_map[] = {
{ "tx_fifo_queue", &dwc3_tx_fifo_queue_fops, },
{ "rx_fifo_queue", &dwc3_rx_fifo_queue_fops, },
{ "tx_fifo_size", &dwc3_tx_fifo_size_fops, },
{ "rx_fifo_size", &dwc3_rx_fifo_size_fops, },
{ "tx_request_queue", &dwc3_tx_request_queue_fops, },
{ "rx_request_queue", &dwc3_rx_request_queue_fops, },
{ "rx_info_queue", &dwc3_rx_info_queue_fops, },
@ -695,6 +862,7 @@ static const struct dwc3_ep_file_map dwc3_ep_file_map[] = {
{ "event_queue", &dwc3_event_queue_fops, },
{ "transfer_type", &dwc3_transfer_type_fops, },
{ "trb_ring", &dwc3_trb_ring_fops, },
{ "GDBGEPINFO", &dwc3_ep_info_register_fops, },
};
static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep,
@ -742,6 +910,8 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
if (!dwc->regset)
return;
dwc->dbg_lsp_select = DWC3_LSP_MUX_UNSELECTED;
dwc->regset->regs = dwc3_regs;
dwc->regset->nregs = ARRAY_SIZE(dwc3_regs);
dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START;
@ -751,6 +921,9 @@ void dwc3_debugfs_init(struct dwc3 *dwc)
debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset);
debugfs_create_file("lsp_dump", S_IRUGO | S_IWUSR, root, dwc,
&dwc3_lsp_fops);
if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, dwc,
&dwc3_mode_fops);

View File

@ -10,6 +10,7 @@
#include <linux/extcon.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include "debug.h"
#include "core.h"
@ -445,9 +446,19 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
struct device *dev = dwc->dev;
struct device_node *np_phy, *np_conn;
struct extcon_dev *edev;
const char *name;
if (of_property_read_bool(dev->of_node, "extcon"))
return extcon_get_edev_by_phandle(dwc->dev, 0);
if (device_property_read_bool(dev, "extcon"))
return extcon_get_edev_by_phandle(dev, 0);
/*
* Device tree platforms should get extcon via phandle.
* On ACPI platforms, we get the name from a device property.
* This device property is for kernel internal use only and
* is expected to be set by the glue code.
*/
if (device_property_read_string(dev, "linux,extcon-name", &name) == 0)
return extcon_get_extcon_dev(name);
np_phy = of_parse_phandle(dev->of_node, "phys", 0);
np_conn = of_graph_get_remote_node(np_phy, -1, -1);

View File

@ -170,20 +170,20 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
* put the gpio descriptors again here because the phy driver
* might want to grab them, too.
*/
gpio = devm_gpiod_get_optional(&pdev->dev, "cs",
GPIOD_OUT_LOW);
gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
gpiod_set_value_cansleep(gpio, 1);
gpiod_put(gpio);
gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
GPIOD_OUT_LOW);
gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
if (gpio) {
gpiod_set_value_cansleep(gpio, 1);
gpiod_put(gpio);
usleep_range(10000, 11000);
}
}

View File

@ -27,7 +27,7 @@
#include "gadget.h"
#include "io.h"
#define DWC3_ALIGN_FRAME(d) (((d)->frame_number + (d)->interval) \
#define DWC3_ALIGN_FRAME(d, n) (((d)->frame_number + ((d)->interval * (n))) \
& ~((d)->interval - 1))
/**
@ -647,8 +647,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
reg |= DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
init_waitqueue_head(&dep->wait_end_transfer);
if (usb_endpoint_xfer_control(desc))
goto out;
@ -672,7 +670,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
* Issue StartTransfer here with no-op TRB so we can always rely on No
* Response Update Transfer command.
*/
if (usb_endpoint_xfer_bulk(desc) ||
if ((usb_endpoint_xfer_bulk(desc) && !dep->stream_capable) ||
usb_endpoint_xfer_int(desc)) {
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_trb *trb;
@ -919,8 +917,6 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
struct usb_gadget *gadget = &dwc->gadget;
enum usb_device_speed speed = gadget->speed;
dwc3_ep_inc_enq(dep);
trb->size = DWC3_TRB_SIZE_LENGTH(length);
trb->bpl = lower_32_bits(dma);
trb->bph = upper_32_bits(dma);
@ -990,16 +986,20 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
usb_endpoint_type(dep->endpoint.desc));
}
/* always enable Continue on Short Packet */
/*
* Enable Continue on Short Packet
* when endpoint is not a stream capable
*/
if (usb_endpoint_dir_out(dep->endpoint.desc)) {
trb->ctrl |= DWC3_TRB_CTRL_CSP;
if (!dep->stream_capable)
trb->ctrl |= DWC3_TRB_CTRL_CSP;
if (short_not_ok)
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
}
if ((!no_interrupt && !chain) ||
(dwc3_calc_trbs_left(dep) == 0))
(dwc3_calc_trbs_left(dep) == 1))
trb->ctrl |= DWC3_TRB_CTRL_IOC;
if (chain)
@ -1010,6 +1010,8 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb,
trb->ctrl |= DWC3_TRB_CTRL_HWO;
dwc3_ep_inc_enq(dep);
trace_dwc3_prepare_trb(dep, trb);
}
@ -1046,6 +1048,8 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
}
req->num_trbs++;
__dwc3_prepare_one_trb(dep, trb, dma, length, chain, node,
stream_id, short_not_ok, no_interrupt);
}
@ -1073,13 +1077,14 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb;
req->unaligned = true;
req->needs_extra_trb = true;
/* prepare normal TRB */
dwc3_prepare_one_trb(dep, req, true, i);
/* Now prepare one extra TRB to align transfer size */
trb = &dep->trb_pool[dep->trb_enqueue];
req->num_trbs++;
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr,
maxp - rem, false, 1,
req->request.stream_id,
@ -1117,13 +1122,14 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb;
req->unaligned = true;
req->needs_extra_trb = true;
/* prepare normal TRB */
dwc3_prepare_one_trb(dep, req, true, 0);
/* Now prepare one extra TRB to align transfer size */
trb = &dep->trb_pool[dep->trb_enqueue];
req->num_trbs++;
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem,
false, 1, req->request.stream_id,
req->request.short_not_ok,
@ -1133,13 +1139,14 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb;
req->zero = true;
req->needs_extra_trb = true;
/* prepare normal TRB */
dwc3_prepare_one_trb(dep, req, true, 0);
/* Now prepare one extra TRB to handle ZLP */
trb = &dep->trb_pool[dep->trb_enqueue];
req->num_trbs++;
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
false, 1, req->request.stream_id,
req->request.short_not_ok,
@ -1232,6 +1239,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
params.param1 = lower_32_bits(req->trb_dma);
cmd = DWC3_DEPCMD_STARTTRANSFER;
if (dep->stream_capable)
cmd |= DWC3_DEPCMD_PARAM(req->request.stream_id);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
cmd |= DWC3_DEPCMD_PARAM(dep->frame_number);
} else {
@ -1263,17 +1273,151 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
return DWC3_DSTS_SOFFN(reg);
}
static void __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
/**
* dwc3_gadget_start_isoc_quirk - workaround invalid frame number
* @dep: isoc endpoint
*
* This function tests for the correct combination of BIT[15:14] from the 16-bit
* microframe number reported by the XferNotReady event for the future frame
* number to start the isoc transfer.
*
* In DWC_usb31 version 1.70a-ea06 and prior, for highspeed and fullspeed
* isochronous IN, BIT[15:14] of the 16-bit microframe number reported by the
* XferNotReady event are invalid. The driver uses this number to schedule the
* isochronous transfer and passes it to the START TRANSFER command. Because
* this number is invalid, the command may fail. If BIT[15:14] matches the
* internal 16-bit microframe, the START TRANSFER command will pass and the
* transfer will start at the scheduled time, if it is off by 1, the command
* will still pass, but the transfer will start 2 seconds in the future. For all
* other conditions, the START TRANSFER command will fail with bus-expiry.
*
* In order to workaround this issue, we can test for the correct combination of
* BIT[15:14] by sending START TRANSFER commands with different values of
* BIT[15:14]: 'b00, 'b01, 'b10, and 'b11. Each combination is 2^14 uframe apart
* (or 2 seconds). 4 seconds into the future will result in a bus-expiry status.
* As the result, within the 4 possible combinations for BIT[15:14], there will
* be 2 successful and 2 failure START COMMAND status. One of the 2 successful
* command status will result in a 2-second delay start. The smaller BIT[15:14]
* value is the correct combination.
*
* Since there are only 4 outcomes and the results are ordered, we can simply
* test 2 START TRANSFER commands with BIT[15:14] combinations 'b00 and 'b01 to
* deduce the smaller successful combination.
*
* Let test0 = test status for combination 'b00 and test1 = test status for 'b01
* of BIT[15:14]. The correct combination is as follow:
*
* if test0 fails and test1 passes, BIT[15:14] is 'b01
* if test0 fails and test1 fails, BIT[15:14] is 'b10
* if test0 passes and test1 fails, BIT[15:14] is 'b11
* if test0 passes and test1 passes, BIT[15:14] is 'b00
*
* Synopsys STAR 9001202023: Wrong microframe number for isochronous IN
* endpoints.
*/
static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)
{
if (list_empty(&dep->pending_list)) {
dev_info(dep->dwc->dev, "%s: ran out of requests\n",
dep->name);
dep->flags |= DWC3_EP_PENDING_REQUEST;
return;
int cmd_status = 0;
bool test0;
bool test1;
while (dep->combo_num < 2) {
struct dwc3_gadget_ep_cmd_params params;
u32 test_frame_number;
u32 cmd;
/*
* Check if we can start isoc transfer on the next interval or
* 4 uframes in the future with BIT[15:14] as dep->combo_num
*/
test_frame_number = dep->frame_number & 0x3fff;
test_frame_number |= dep->combo_num << 14;
test_frame_number += max_t(u32, 4, dep->interval);
params.param0 = upper_32_bits(dep->dwc->bounce_addr);
params.param1 = lower_32_bits(dep->dwc->bounce_addr);
cmd = DWC3_DEPCMD_STARTTRANSFER;
cmd |= DWC3_DEPCMD_PARAM(test_frame_number);
cmd_status = dwc3_send_gadget_ep_cmd(dep, cmd, &params);
/* Redo if some other failure beside bus-expiry is received */
if (cmd_status && cmd_status != -EAGAIN) {
dep->start_cmd_status = 0;
dep->combo_num = 0;
return 0;
}
/* Store the first test status */
if (dep->combo_num == 0)
dep->start_cmd_status = cmd_status;
dep->combo_num++;
/*
* End the transfer if the START_TRANSFER command is successful
* to wait for the next XferNotReady to test the command again
*/
if (cmd_status == 0) {
dwc3_stop_active_transfer(dep, true);
return 0;
}
}
dep->frame_number = DWC3_ALIGN_FRAME(dep);
__dwc3_gadget_kick_transfer(dep);
/* test0 and test1 are both completed at this point */
test0 = (dep->start_cmd_status == 0);
test1 = (cmd_status == 0);
if (!test0 && test1)
dep->combo_num = 1;
else if (!test0 && !test1)
dep->combo_num = 2;
else if (test0 && !test1)
dep->combo_num = 3;
else if (test0 && test1)
dep->combo_num = 0;
dep->frame_number &= 0x3fff;
dep->frame_number |= dep->combo_num << 14;
dep->frame_number += max_t(u32, 4, dep->interval);
/* Reinitialize test variables */
dep->start_cmd_status = 0;
dep->combo_num = 0;
return __dwc3_gadget_kick_transfer(dep);
}
static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
{
struct dwc3 *dwc = dep->dwc;
int ret;
int i;
if (list_empty(&dep->pending_list)) {
dep->flags |= DWC3_EP_PENDING_REQUEST;
return -EAGAIN;
}
if (!dwc->dis_start_transfer_quirk && dwc3_is_usb31(dwc) &&
(dwc->revision <= DWC3_USB31_REVISION_160A ||
(dwc->revision == DWC3_USB31_REVISION_170A &&
dwc->version_type >= DWC31_VERSIONTYPE_EA01 &&
dwc->version_type <= DWC31_VERSIONTYPE_EA06))) {
if (dwc->gadget.speed <= USB_SPEED_HIGH && dep->direction)
return dwc3_gadget_start_isoc_quirk(dep);
}
for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) {
dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1);
ret = __dwc3_gadget_kick_transfer(dep);
if (ret != -EAGAIN)
break;
}
return ret;
}
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
@ -1314,8 +1458,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
if ((dep->flags & DWC3_EP_PENDING_REQUEST)) {
if (!(dep->flags & DWC3_EP_TRANSFER_STARTED)) {
__dwc3_gadget_start_isoc(dep);
return 0;
return __dwc3_gadget_start_isoc(dep);
}
}
}
@ -1341,6 +1484,40 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
return ret;
}
static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *req)
{
int i;
/*
* If request was already started, this means we had to
* stop the transfer. With that we also need to ignore
* all TRBs used by the request, however TRBs can only
* be modified after completion of END_TRANSFER
* command. So what we do here is that we wait for
* END_TRANSFER completion and only after that, we jump
* over TRBs by clearing HWO and incrementing dequeue
* pointer.
*/
for (i = 0; i < req->num_trbs; i++) {
struct dwc3_trb *trb;
trb = req->trb + i;
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
dwc3_ep_inc_deq(dep);
}
}
static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep)
{
struct dwc3_request *req;
struct dwc3_request *tmp;
list_for_each_entry_safe(req, tmp, &dep->cancelled_list, list) {
dwc3_gadget_ep_skip_trbs(dep, req);
dwc3_gadget_giveback(dep, req, -ECONNRESET);
}
}
static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
struct usb_request *request)
{
@ -1371,68 +1548,11 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
/* wait until it is processed */
dwc3_stop_active_transfer(dep, true);
/*
* If request was already started, this means we had to
* stop the transfer. With that we also need to ignore
* all TRBs used by the request, however TRBs can only
* be modified after completion of END_TRANSFER
* command. So what we do here is that we wait for
* END_TRANSFER completion and only after that, we jump
* over TRBs by clearing HWO and incrementing dequeue
* pointer.
*
* Note that we have 2 possible types of transfers here:
*
* i) Linear buffer request
* ii) SG-list based request
*
* SG-list based requests will have r->num_pending_sgs
* set to a valid number (> 0). Linear requests,
* normally use a single TRB.
*
* For each of these two cases, if r->unaligned flag is
* set, one extra TRB has been used to align transfer
* size to wMaxPacketSize.
*
* All of these cases need to be taken into
* consideration so we don't mess up our TRB ring
* pointers.
*/
wait_event_lock_irq(dep->wait_end_transfer,
!(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
dwc->lock);
if (!r->trb)
goto out0;
if (r->num_pending_sgs) {
struct dwc3_trb *trb;
int i = 0;
for (i = 0; i < r->num_pending_sgs; i++) {
trb = r->trb + i;
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
dwc3_ep_inc_deq(dep);
}
if (r->unaligned || r->zero) {
trb = r->trb + r->num_pending_sgs + 1;
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
dwc3_ep_inc_deq(dep);
}
} else {
struct dwc3_trb *trb = r->trb;
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
dwc3_ep_inc_deq(dep);
if (r->unaligned || r->zero) {
trb = r->trb + 1;
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
dwc3_ep_inc_deq(dep);
}
}
goto out1;
dwc3_gadget_move_cancelled_request(req);
goto out0;
}
dev_err(dwc->dev, "request %pK was not queued to %s\n",
request, ep->name);
@ -1440,9 +1560,6 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
goto out0;
}
out1:
/* giveback the request */
dwc3_gadget_giveback(dep, req, -ECONNRESET);
out0:
@ -1934,8 +2051,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
int epnum;
u32 tmo_eps = 0;
spin_lock_irqsave(&dwc->lock, flags);
@ -1944,36 +2059,6 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
__dwc3_gadget_stop(dwc);
for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
struct dwc3_ep *dep = dwc->eps[epnum];
int ret;
if (!dep)
continue;
if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
continue;
ret = wait_event_interruptible_lock_irq_timeout(dep->wait_end_transfer,
!(dep->flags & DWC3_EP_END_TRANSFER_PENDING),
dwc->lock, msecs_to_jiffies(5));
if (ret <= 0) {
/* Timed out or interrupted! There's nothing much
* we can do so we just log here and print which
* endpoints timed out at the end.
*/
tmo_eps |= 1 << epnum;
dep->flags &= DWC3_EP_END_TRANSFER_PENDING;
}
}
if (tmo_eps) {
dev_err(dwc->dev,
"end transfer timed out on endpoints 0x%x [bitmap]\n",
tmo_eps);
}
out:
dwc->gadget_driver = NULL;
spin_unlock_irqrestore(&dwc->lock, flags);
@ -2148,6 +2233,8 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
dep->direction = direction;
dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
dwc->eps[epnum] = dep;
dep->combo_num = 0;
dep->start_cmd_status = 0;
snprintf(dep->name, sizeof(dep->name), "ep%u%s", num,
direction ? "in" : "out");
@ -2176,6 +2263,7 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
INIT_LIST_HEAD(&dep->pending_list);
INIT_LIST_HEAD(&dep->started_list);
INIT_LIST_HEAD(&dep->cancelled_list);
return 0;
}
@ -2235,6 +2323,7 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep,
dwc3_ep_inc_deq(dep);
trace_dwc3_complete_trb(dep, trb);
req->num_trbs--;
/*
* If we're in the middle of series of chained TRBs and we
@ -2249,12 +2338,26 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep,
if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO))
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
/*
* For isochronous transfers, the first TRB in a service interval must
* have the Isoc-First type. Track and report its interval frame number.
*/
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
(trb->ctrl & DWC3_TRBCTL_ISOCHRONOUS_FIRST)) {
unsigned int frame_number;
frame_number = DWC3_TRB_CTRL_GET_SID_SOFN(trb->ctrl);
frame_number &= ~(dep->interval - 1);
req->request.frame_number = frame_number;
}
/*
* If we're dealing with unaligned size OUT transfer, we will be left
* with one TRB pending in the ring. We need to manually clear HWO bit
* from that TRB.
*/
if ((req->zero || req->unaligned) && !(trb->ctrl & DWC3_TRB_CTRL_CHN)) {
if (req->needs_extra_trb && !(trb->ctrl & DWC3_TRB_CTRL_CHN)) {
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
return 1;
}
@ -2331,11 +2434,10 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,
ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
status);
if (req->unaligned || req->zero) {
if (req->needs_extra_trb) {
ret = dwc3_gadget_ep_reclaim_trb_linear(dep, req, event,
status);
req->unaligned = false;
req->zero = false;
req->needs_extra_trb = false;
}
req->request.actual = req->request.length - req->remaining;
@ -2430,7 +2532,7 @@ static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep,
const struct dwc3_event_depevt *event)
{
dwc3_gadget_endpoint_frame_from_event(dep, event);
__dwc3_gadget_start_isoc(dep);
(void) __dwc3_gadget_start_isoc(dep);
}
static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
@ -2468,7 +2570,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
if (cmd == DWC3_DEPCMD_ENDTRANSFER) {
dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
wake_up(&dep->wait_end_transfer);
dwc3_gadget_ep_cleanup_cancelled_requests(dep);
}
break;
case DWC3_DEPEVT_STREAMEVT:

View File

@ -79,6 +79,21 @@ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
list_move_tail(&req->list, &dep->started_list);
}
/**
* dwc3_gadget_move_cancelled_request - move @req to the cancelled_list
* @req: the request to be moved
*
* Caller should take care of locking. This function will move @req from its
* current list to the endpoint's cancelled_list.
*/
static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req)
{
struct dwc3_ep *dep = req->dep;
req->started = false;
list_move_tail(&req->list, &dep->cancelled_list);
}
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status);

View File

@ -46,7 +46,7 @@ out:
int dwc3_host_init(struct dwc3 *dwc)
{
struct property_entry props[3];
struct property_entry props[4];
struct platform_device *xhci;
int ret, irq;
struct resource *res;
@ -93,6 +93,9 @@ int dwc3_host_init(struct dwc3 *dwc)
if (dwc->usb3_lpm_capable)
props[prop_idx++].name = "usb3-lpm-capable";
if (dwc->usb2_lpm_disable)
props[prop_idx++].name = "usb2-lpm-disable";
/**
* WORKAROUND: dwc3 revisions <=3.00a have a limitation
* where Port Disable command doesn't work.

View File

@ -199,7 +199,7 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
__entry->param2 = params->param2;
__entry->cmd_status = cmd_status;
),
TP_printk("%s: cmd '%s' [%d] params %08x %08x %08x --> status: %s",
TP_printk("%s: cmd '%s' [%x] params %08x %08x %08x --> status: %s",
__get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
__entry->cmd, __entry->param0,
__entry->param1, __entry->param2,
@ -251,9 +251,11 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
s = "2x ";
break;
case 3:
default:
s = "3x ";
break;
}
break;
default:
s = "";
} s; }),

View File

@ -18,11 +18,15 @@
#include <linux/pagemap.h>
#include <linux/export.h>
#include <linux/hid.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/sched/signal.h>
#include <linux/uio.h>
#include <linux/vmalloc.h>
#include <asm/unaligned.h>
#include <linux/usb/ccid.h>
#include <linux/usb/composite.h>
#include <linux/usb/functionfs.h>
@ -218,6 +222,8 @@ struct ffs_io_data {
struct usb_ep *ep;
struct usb_request *req;
struct sg_table sgt;
bool use_sg;
struct ffs_data *ffs;
};
@ -749,6 +755,65 @@ static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter)
return ret;
}
/*
* allocate a virtually contiguous buffer and create a scatterlist describing it
* @sg_table - pointer to a place to be filled with sg_table contents
* @size - required buffer size
*/
static void *ffs_build_sg_list(struct sg_table *sgt, size_t sz)
{
struct page **pages;
void *vaddr, *ptr;
unsigned int n_pages;
int i;
vaddr = vmalloc(sz);
if (!vaddr)
return NULL;
n_pages = PAGE_ALIGN(sz) >> PAGE_SHIFT;
pages = kvmalloc_array(n_pages, sizeof(struct page *), GFP_KERNEL);
if (!pages) {
vfree(vaddr);
return NULL;
}
for (i = 0, ptr = vaddr; i < n_pages; ++i, ptr += PAGE_SIZE)
pages[i] = vmalloc_to_page(ptr);
if (sg_alloc_table_from_pages(sgt, pages, n_pages, 0, sz, GFP_KERNEL)) {
kvfree(pages);
vfree(vaddr);
return NULL;
}
kvfree(pages);
return vaddr;
}
static inline void *ffs_alloc_buffer(struct ffs_io_data *io_data,
size_t data_len)
{
if (io_data->use_sg)
return ffs_build_sg_list(&io_data->sgt, data_len);
return kmalloc(data_len, GFP_KERNEL);
}
static inline void ffs_free_buffer(struct ffs_io_data *io_data)
{
if (!io_data->buf)
return;
if (io_data->use_sg) {
sg_free_table(&io_data->sgt);
vfree(io_data->buf);
} else {
kfree(io_data->buf);
}
}
static void ffs_user_copy_worker(struct work_struct *work)
{
struct ffs_io_data *io_data = container_of(work, struct ffs_io_data,
@ -776,7 +841,7 @@ static void ffs_user_copy_worker(struct work_struct *work)
if (io_data->read)
kfree(io_data->to_free);
kfree(io_data->buf);
ffs_free_buffer(io_data);
kfree(io_data);
}
@ -932,6 +997,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
* earlier
*/
gadget = epfile->ffs->gadget;
io_data->use_sg = gadget->sg_supported && data_len > PAGE_SIZE;
spin_lock_irq(&epfile->ffs->eps_lock);
/* In the meantime, endpoint got disabled or changed. */
@ -948,7 +1014,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
data_len = usb_ep_align_maybe(gadget, ep->ep, data_len);
spin_unlock_irq(&epfile->ffs->eps_lock);
data = kmalloc(data_len, GFP_KERNEL);
data = ffs_alloc_buffer(io_data, data_len);
if (unlikely(!data)) {
ret = -ENOMEM;
goto error_mutex;
@ -988,8 +1054,16 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
bool interrupted = false;
req = ep->req;
req->buf = data;
req->length = data_len;
if (io_data->use_sg) {
req->buf = NULL;
req->sg = io_data->sgt.sgl;
req->num_sgs = io_data->sgt.nents;
} else {
req->buf = data;
}
req->length = data_len;
io_data->buf = data;
req->context = &done;
req->complete = ffs_epfile_io_complete;
@ -1022,8 +1096,14 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
} else if (!(req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC))) {
ret = -ENOMEM;
} else {
req->buf = data;
req->length = data_len;
if (io_data->use_sg) {
req->buf = NULL;
req->sg = io_data->sgt.sgl;
req->num_sgs = io_data->sgt.nents;
} else {
req->buf = data;
}
req->length = data_len;
io_data->buf = data;
io_data->ep = ep->ep;
@ -1052,7 +1132,7 @@ error_lock:
error_mutex:
mutex_unlock(&epfile->mutex);
error:
kfree(data);
ffs_free_buffer(io_data);
return ret;
}
@ -1926,7 +2006,7 @@ typedef int (*ffs_os_desc_callback)(enum ffs_os_desc_type entity,
static int __must_check ffs_do_single_desc(char *data, unsigned len,
ffs_entity_callback entity,
void *priv)
void *priv, int *current_class)
{
struct usb_descriptor_header *_ds = (void *)data;
u8 length;
@ -1984,6 +2064,7 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len,
__entity(INTERFACE, ds->bInterfaceNumber);
if (ds->iInterface)
__entity(STRING, ds->iInterface);
*current_class = ds->bInterfaceClass;
}
break;
@ -1997,11 +2078,22 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len,
}
break;
case HID_DT_HID:
pr_vdebug("hid descriptor\n");
if (length != sizeof(struct hid_descriptor))
goto inv_length;
break;
case USB_TYPE_CLASS | 0x01:
if (*current_class == USB_INTERFACE_CLASS_HID) {
pr_vdebug("hid descriptor\n");
if (length != sizeof(struct hid_descriptor))
goto inv_length;
break;
} else if (*current_class == USB_INTERFACE_CLASS_CCID) {
pr_vdebug("ccid descriptor\n");
if (length != sizeof(struct ccid_descriptor))
goto inv_length;
break;
} else {
pr_vdebug("unknown descriptor: %d for class %d\n",
_ds->bDescriptorType, *current_class);
return -EINVAL;
}
case USB_DT_OTG:
if (length != sizeof(struct usb_otg_descriptor))
@ -2058,6 +2150,7 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
{
const unsigned _len = len;
unsigned long num = 0;
int current_class = -1;
ENTER();
@ -2078,7 +2171,8 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
if (!data)
return _len - len;
ret = ffs_do_single_desc(data, len, entity, priv);
ret = ffs_do_single_desc(data, len, entity, priv,
&current_class);
if (unlikely(ret < 0)) {
pr_debug("%s returns %d\n", __func__, ret);
return ret;

View File

@ -102,7 +102,7 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&queue->irqlock, flags);
}
static struct vb2_ops uvc_queue_qops = {
static const struct vb2_ops uvc_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,

View File

@ -438,7 +438,7 @@ static int ast_vhub_udc_stop(struct usb_gadget *gadget)
return 0;
}
static struct usb_gadget_ops ast_vhub_udc_ops = {
static const struct usb_gadget_ops ast_vhub_udc_ops = {
.get_frame = ast_vhub_udc_get_frame,
.wakeup = ast_vhub_udc_wakeup,
.pullup = ast_vhub_udc_pullup,

View File

@ -358,6 +358,7 @@ struct renesas_usb3 {
bool extcon_host; /* check id and set EXTCON_USB_HOST */
bool extcon_usb; /* check vbus and set EXTCON_USB */
bool forced_b_device;
bool start_to_connect;
};
#define gadget_to_renesas_usb3(_gadget) \
@ -476,7 +477,8 @@ static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
static void usb3_init_epc_registers(struct renesas_usb3 *usb3)
{
usb3_write(usb3, ~0, USB3_USB_INT_STA_1);
usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG);
if (!usb3->workaround_for_vbus)
usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG);
}
static bool usb3_wakeup_usb2_phy(struct renesas_usb3 *usb3)
@ -700,8 +702,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
usb3_set_mode_by_role_sw(usb3, host);
usb3_vbus_out(usb3, a_dev);
/* for A-Peripheral or forced B-device mode */
if ((!host && a_dev) ||
(usb3->workaround_for_vbus && usb3->forced_b_device))
if ((!host && a_dev) || usb3->start_to_connect)
usb3_connect(usb3);
spin_unlock_irqrestore(&usb3->lock, flags);
}
@ -2432,7 +2433,11 @@ static ssize_t renesas_usb3_b_device_write(struct file *file,
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (!strncmp(buf, "1", 1))
usb3->start_to_connect = false;
if (usb3->workaround_for_vbus && usb3->forced_b_device &&
!strncmp(buf, "2", 1))
usb3->start_to_connect = true;
else if (!strncmp(buf, "1", 1))
usb3->forced_b_device = true;
else
usb3->forced_b_device = false;
@ -2440,7 +2445,7 @@ static ssize_t renesas_usb3_b_device_write(struct file *file,
if (usb3->workaround_for_vbus)
usb3_disconnect(usb3);
/* Let this driver call usb3_connect() anyway */
/* Let this driver call usb3_connect() if needed */
usb3_check_id(usb3);
return count;

View File

@ -119,7 +119,7 @@ static void dprintk(int level, const char *fmt, ...)
}
#endif
static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
static int s3c2410_udc_debugfs_show(struct seq_file *m, void *p)
{
u32 addr_reg, pwr_reg, ep_int_reg, usb_int_reg;
u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;
@ -168,20 +168,7 @@ static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
return 0;
}
static int s3c2410_udc_debugfs_fops_open(struct inode *inode,
struct file *file)
{
return single_open(file, s3c2410_udc_debugfs_seq_show, NULL);
}
static const struct file_operations s3c2410_udc_debugfs_fops = {
.open = s3c2410_udc_debugfs_fops_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
DEFINE_SHOW_ATTRIBUTE(s3c2410_udc_debugfs);
/* io macros */

View File

@ -402,7 +402,7 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
return;
}
dev_dbg(mtu->dev, "%s send ZLP for req=%p\n", __func__, mreq);
dev_dbg(mtu->dev, "%s send ZLP for req=%p\n", __func__, req);
mtu3_clrbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN);

View File

@ -874,24 +874,7 @@ static int usbhsc_resume(struct device *dev)
return 0;
}
static int usbhsc_runtime_nop(struct device *dev)
{
/* Runtime PM callback shared between ->runtime_suspend()
* and ->runtime_resume(). Simply returns success.
*
* This driver re-initializes all registers after
* pm_runtime_get_sync() anyway so there is no need
* to save and restore registers here.
*/
return 0;
}
static const struct dev_pm_ops usbhsc_pm_ops = {
.suspend = usbhsc_suspend,
.resume = usbhsc_resume,
.runtime_suspend = usbhsc_runtime_nop,
.runtime_resume = usbhsc_runtime_nop,
};
static SIMPLE_DEV_PM_OPS(usbhsc_pm_ops, usbhsc_suspend, usbhsc_resume);
static struct platform_driver renesas_usbhs_driver = {
.driver = {

51
include/linux/usb/ccid.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2018 Vincent Pelletier
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CCID_H
#define __CCID_H
#include <linux/types.h>
#define USB_INTERFACE_CLASS_CCID 0x0b
struct ccid_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdCCID;
__u8 bMaxSlotIndex;
__u8 bVoltageSupport;
__le32 dwProtocols;
__le32 dwDefaultClock;
__le32 dwMaximumClock;
__u8 bNumClockSupported;
__le32 dwDataRate;
__le32 dwMaxDataRate;
__u8 bNumDataRatesSupported;
__le32 dwMaxIFSD;
__le32 dwSynchProtocols;
__le32 dwMechanical;
__le32 dwFeatures;
__le32 dwMaxCCIDMessageLength;
__u8 bClassGetResponse;
__u8 bClassEnvelope;
__le16 wLcdLayout;
__u8 bPINSupport;
__u8 bMaxCCIDBusySlots;
} __attribute__ ((packed));
#endif /* __CCID_H */

View File

@ -61,6 +61,8 @@ struct usb_ep;
* invalidated by the error may first be dequeued.
* @context: For use by the completion callback
* @list: For use by the gadget driver.
* @frame_number: Reports the interval number in (micro)frame in which the
* isochronous transfer was transmitted or received.
* @status: Reports completion code, zero or a negative errno.
* Normally, faults block the transfer queue from advancing until
* the completion callback returns.
@ -112,6 +114,8 @@ struct usb_request {
void *context;
struct list_head list;
unsigned frame_number; /* ISO ONLY */
int status;
unsigned actual;
};