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: George Cherian <george.cherian@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
parent
f82503f549
commit
1af54b7a40
|
@ -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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
Loading…
Reference in New Issue