summaryrefslogtreecommitdiff
path: root/drivers/usb/chipidea/udc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/chipidea/udc.c')
-rw-r--r--drivers/usb/chipidea/udc.c58
1 files changed, 32 insertions, 26 deletions
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 065f5d97aa67..661f43fe0f9e 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -59,7 +59,7 @@ ctrl_endpt_in_desc = {
*/
static inline int hw_ep_bit(int num, int dir)
{
- return num + (dir ? 16 : 0);
+ return num + ((dir == TX) ? 16 : 0);
}
static inline int ep_to_bit(struct ci_hdrc *ci, int n)
@@ -121,9 +121,8 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir)
*/
static int hw_ep_disable(struct ci_hdrc *ci, int num, int dir)
{
- hw_ep_flush(ci, num, dir);
hw_write(ci, OP_ENDPTCTRL + num,
- dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
+ (dir == TX) ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
return 0;
}
@@ -139,7 +138,7 @@ static int hw_ep_enable(struct ci_hdrc *ci, int num, int dir, int type)
{
u32 mask, data;
- if (dir) {
+ if (dir == TX) {
mask = ENDPTCTRL_TXT; /* type */
data = type << __ffs(mask);
@@ -171,7 +170,7 @@ static int hw_ep_enable(struct ci_hdrc *ci, int num, int dir, int type)
*/
static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir)
{
- u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+ u32 mask = (dir == TX) ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
return hw_read(ci, OP_ENDPTCTRL + num, mask) ? 1 : 0;
}
@@ -188,6 +187,9 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)
{
int n = hw_ep_bit(num, dir);
+ /* Synchronize before ep prime */
+ wmb();
+
if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num)))
return -EAGAIN;
@@ -218,8 +220,8 @@ static int hw_ep_set_halt(struct ci_hdrc *ci, int num, int dir, int value)
do {
enum ci_hw_regs reg = OP_ENDPTCTRL + num;
- u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
- u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
+ u32 mask_xs = (dir == TX) ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+ u32 mask_xr = (dir == TX) ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
/* data toggle - reserved for EP0 but it's in ESS */
hw_write(ci, reg, mask_xs|mask_xr,
@@ -348,8 +350,7 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,
if (node == NULL)
return -ENOMEM;
- node->ptr = dma_pool_zalloc(hwep->td_pool, GFP_ATOMIC,
- &node->dma);
+ node->ptr = dma_pool_zalloc(hwep->td_pool, GFP_ATOMIC, &node->dma);
if (node->ptr == NULL) {
kfree(node);
return -ENOMEM;
@@ -506,8 +507,6 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
hwep->qh.ptr->cap |= mul << __ffs(QH_MULT);
}
- wmb(); /* synchronize before ep prime */
-
ret = hw_ep_prime(ci, hwep->num, hwep->dir,
hwep->type == USB_ENDPOINT_XFER_CONTROL);
done:
@@ -534,9 +533,6 @@ static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep,
hwep->qh.ptr->td.token &=
cpu_to_le32(~(TD_STATUS_HALTED | TD_STATUS_ACTIVE));
- /* Synchronize before ep prime */
- wmb();
-
return hw_ep_prime(ci, hwep->num, hwep->dir,
hwep->type == USB_ENDPOINT_XFER_CONTROL);
}
@@ -590,7 +586,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
}
if (remaining_length) {
- if (hwep->dir) {
+ if (hwep->dir == TX) {
hwreq->req.status = -EPROTO;
break;
}
@@ -949,6 +945,15 @@ static int isr_setup_status_phase(struct ci_hdrc *ci)
int retval;
struct ci_hw_ep *hwep;
+ /*
+ * Unexpected USB controller behavior, caused by bad signal integrity
+ * or ground reference problems, can lead to isr_setup_status_phase
+ * being called with ci->status equal to NULL.
+ * If this situation occurs, you should review your USB hardware design.
+ */
+ if (WARN_ON_ONCE(!ci->status))
+ return -EPIPE;
+
hwep = (ci->ep0_dir == TX) ? ci->ep0out : ci->ep0in;
ci->status->context = ci;
ci->status->complete = isr_setup_status_complete;
@@ -1042,9 +1047,9 @@ __acquires(ci->lock)
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
- dir = num & USB_ENDPOINT_DIR_MASK;
+ dir = (num & USB_ENDPOINT_DIR_MASK) ? TX : RX;
num &= USB_ENDPOINT_NUMBER_MASK;
- if (dir) /* TX */
+ if (dir == TX)
num += ci->hw_ep_max / 2;
if (!ci->ci_hw_ep[num].wedge) {
spin_unlock(&ci->lock);
@@ -1094,9 +1099,9 @@ __acquires(ci->lock)
if (req.wLength != 0)
break;
num = le16_to_cpu(req.wIndex);
- dir = num & USB_ENDPOINT_DIR_MASK;
+ dir = (num & USB_ENDPOINT_DIR_MASK) ? TX : RX;
num &= USB_ENDPOINT_NUMBER_MASK;
- if (dir) /* TX */
+ if (dir == TX)
num += ci->hw_ep_max / 2;
spin_unlock(&ci->lock);
@@ -1596,8 +1601,11 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
- /* Data+ pullup controlled by OTG state machine in OTG fsm mode */
- if (ci_otg_is_fsm_mode(ci))
+ /*
+ * Data+ pullup controlled by OTG state machine in OTG fsm mode;
+ * and don't touch Data+ in host mode for dual role config.
+ */
+ if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST)
return 0;
pm_runtime_get_sync(&ci->gadget.dev);
@@ -1668,12 +1676,10 @@ static int init_eps(struct ci_hdrc *ci)
usb_ep_set_maxpacket_limit(&hwep->ep, (unsigned short)~0);
INIT_LIST_HEAD(&hwep->qh.queue);
- hwep->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL,
- &hwep->qh.dma);
+ hwep->qh.ptr = dma_pool_zalloc(ci->qh_pool, GFP_KERNEL,
+ &hwep->qh.dma);
if (hwep->qh.ptr == NULL)
retval = -ENOMEM;
- else
- memset(hwep->qh.ptr, 0, sizeof(*hwep->qh.ptr));
/*
* set up shorthands for ep0 out and in endpoints,
@@ -1987,7 +1993,7 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
return -ENXIO;
- rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
+ rdrv = devm_kzalloc(ci->dev, sizeof(*rdrv), GFP_KERNEL);
if (!rdrv)
return -ENOMEM;