Commit 5ac93d0c authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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()
  ...
parents ed0a773b 4fe4f9fe
......@@ -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
......
......@@ -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));
......
......@@ -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;
......
......@@ -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);
......
......@@ -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)
......
......@@ -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",
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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
......
......@@ -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 @@ static int dwc3_trb_ring_show(struct seq_file *s, void *unused)
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);
......
......@@ -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);
......
......@@ -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);
}
}
......
This diff is collapsed.
......@@ -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);
......
......@@ -46,7 +46,7 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
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.
......
......@@ -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; }),
......
......@@ -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 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
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;
......
......@@ -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,
......
......@@ -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,
......
......@@ -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;
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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 = {
......
/*
* 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 */
......@@ -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;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment