Commit 1af54b7a authored by George Cherian's avatar George Cherian Committed by Felipe Balbi

usb: musb: musb_cppi41: Handle ISOCH differently and not use the hrtimer.

In case of ISOCH transfers the hrtimer workaround for the hardware issue
is not very reliable. Instead of checking musb_is_tx_fifo_empty() in hrtimer
routine, schedule a completion work and check the same in completion work.
Signed-off-by: default avatarGeorge Cherian <george.cherian@ti.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent f82503f5
...@@ -39,6 +39,7 @@ struct cppi41_dma_channel { ...@@ -39,6 +39,7 @@ struct cppi41_dma_channel {
u32 transferred; u32 transferred;
u32 packet_sz; u32 packet_sz;
struct list_head tx_check; struct list_head tx_check;
struct work_struct dma_completion;
}; };
#define MUSB_DMA_NUM_CHANNELS 15 #define MUSB_DMA_NUM_CHANNELS 15
...@@ -112,6 +113,18 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) ...@@ -112,6 +113,18 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)
return true; return true;
} }
static bool is_isoc(struct musb_hw_ep *hw_ep, bool in)
{
if (in && hw_ep->in_qh) {
if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC)
return true;
} else if (hw_ep->out_qh) {
if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC)
return true;
}
return false;
}
static void cppi41_dma_callback(void *private_data); static void cppi41_dma_callback(void *private_data);
static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
...@@ -165,6 +178,32 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) ...@@ -165,6 +178,32 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
} }
} }
static void cppi_trans_done_work(struct work_struct *work)
{
unsigned long flags;
struct cppi41_dma_channel *cppi41_channel =
container_of(work, struct cppi41_dma_channel, dma_completion);
struct cppi41_dma_controller *controller = cppi41_channel->controller;
struct musb *musb = controller->musb;
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
bool empty;
if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) {
spin_lock_irqsave(&musb->lock, flags);
cppi41_trans_done(cppi41_channel);
spin_unlock_irqrestore(&musb->lock, flags);
} else {
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) {
spin_lock_irqsave(&musb->lock, flags);
cppi41_trans_done(cppi41_channel);
spin_unlock_irqrestore(&musb->lock, flags);
} else {
schedule_work(&cppi41_channel->dma_completion);
}
}
}
static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer)
{ {
struct cppi41_dma_controller *controller; struct cppi41_dma_controller *controller;
...@@ -228,6 +267,14 @@ static void cppi41_dma_callback(void *private_data) ...@@ -228,6 +267,14 @@ static void cppi41_dma_callback(void *private_data)
transferred < cppi41_channel->packet_sz) transferred < cppi41_channel->packet_sz)
cppi41_channel->prog_len = 0; cppi41_channel->prog_len = 0;
if (!cppi41_channel->is_tx) {
if (is_isoc(hw_ep, 1))
schedule_work(&cppi41_channel->dma_completion);
else
cppi41_trans_done(cppi41_channel);
goto out;
}
empty = musb_is_tx_fifo_empty(hw_ep); empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) { if (empty) {
cppi41_trans_done(cppi41_channel); cppi41_trans_done(cppi41_channel);
...@@ -264,6 +311,10 @@ static void cppi41_dma_callback(void *private_data) ...@@ -264,6 +311,10 @@ static void cppi41_dma_callback(void *private_data)
goto out; goto out;
} }
} }
if (is_isoc(hw_ep, 0)) {
schedule_work(&cppi41_channel->dma_completion);
goto out;
}
list_add_tail(&cppi41_channel->tx_check, list_add_tail(&cppi41_channel->tx_check,
&controller->early_tx_list); &controller->early_tx_list);
if (!hrtimer_active(&controller->early_tx)) { if (!hrtimer_active(&controller->early_tx)) {
...@@ -620,6 +671,8 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) ...@@ -620,6 +671,8 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
cppi41_channel->port_num = port; cppi41_channel->port_num = port;
cppi41_channel->is_tx = is_tx; cppi41_channel->is_tx = is_tx;
INIT_LIST_HEAD(&cppi41_channel->tx_check); INIT_LIST_HEAD(&cppi41_channel->tx_check);
INIT_WORK(&cppi41_channel->dma_completion,
cppi_trans_done_work);
musb_dma = &cppi41_channel->channel; musb_dma = &cppi41_channel->channel;
musb_dma->private_data = cppi41_channel; musb_dma->private_data = cppi41_channel;
......
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