Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ struct cppi41_dma_channel {
	u32 transferred;
	u32 packet_sz;
	struct list_head tx_check;
	struct work_struct dma_completion;
};

#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;
}

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_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)
{
	struct cppi41_dma_controller *controller;
@@ -228,6 +267,14 @@ static void cppi41_dma_callback(void *private_data)
			transferred < cppi41_channel->packet_sz)
		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);
	if (empty) {
		cppi41_trans_done(cppi41_channel);
@@ -264,6 +311,10 @@ static void cppi41_dma_callback(void *private_data)
				goto out;
			}
		}
		if (is_isoc(hw_ep, 0)) {
			schedule_work(&cppi41_channel->dma_completion);
			goto out;
		}
		list_add_tail(&cppi41_channel->tx_check,
				&controller->early_tx_list);
		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->is_tx = is_tx;
		INIT_LIST_HEAD(&cppi41_channel->tx_check);
		INIT_WORK(&cppi41_channel->dma_completion,
			  cppi_trans_done_work);

		musb_dma = &cppi41_channel->channel;
		musb_dma->private_data = cppi41_channel;