usb: renesas_usbhs: add pipe/fifo link
renesas_usbhs has CFIFO which is for PIO transfer, and D0FIFO/D1FIFO which are for DMA transfer. The pipe selects one of these fifo when it send/recv data. But fifo must not be selected to different pipe in same time. This patch add pipe/fifo link for each other, and fifo is not selected by another pipe until it is unselected. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
d3af90a5e4
Коммит
d77e3f4e17
|
@ -21,6 +21,8 @@
|
|||
|
||||
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo))
|
||||
|
||||
#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
|
||||
|
||||
/*
|
||||
* packet info function
|
||||
*/
|
||||
|
@ -237,6 +239,15 @@ static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv,
|
|||
return usbhs_read(priv, fifo->ctr) & DTLN_MASK;
|
||||
}
|
||||
|
||||
static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe,
|
||||
struct usbhs_fifo *fifo)
|
||||
{
|
||||
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
|
||||
|
||||
usbhs_pipe_select_fifo(pipe, NULL);
|
||||
usbhs_write(priv, fifo->sel, 0);
|
||||
}
|
||||
|
||||
static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
|
||||
struct usbhs_fifo *fifo,
|
||||
int write)
|
||||
|
@ -247,6 +258,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
|
|||
u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */
|
||||
u16 base = usbhs_pipe_number(pipe); /* CURPIPE */
|
||||
|
||||
if (usbhs_pipe_is_busy(pipe) ||
|
||||
usbhsf_fifo_is_busy(fifo))
|
||||
return -EBUSY;
|
||||
|
||||
if (usbhs_pipe_is_dcp(pipe))
|
||||
base |= (1 == write) << 5; /* ISEL */
|
||||
|
||||
|
@ -255,8 +270,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
|
|||
|
||||
/* check ISEL and CURPIPE value */
|
||||
while (timeout--) {
|
||||
if (base == (mask & usbhs_read(priv, fifo->sel)))
|
||||
if (base == (mask & usbhs_read(priv, fifo->sel))) {
|
||||
usbhs_pipe_select_fifo(pipe, fifo);
|
||||
return 0;
|
||||
}
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
|
@ -283,7 +300,7 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done)
|
|||
|
||||
ret = usbhsf_fifo_select(pipe, fifo, 1);
|
||||
if (ret < 0)
|
||||
goto usbhs_fifo_write_busy;
|
||||
return 0;
|
||||
|
||||
ret = usbhs_pipe_is_accessible(pipe);
|
||||
if (ret < 0)
|
||||
|
@ -347,9 +364,13 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done)
|
|||
usbhs_dcp_control_transfer_done(pipe);
|
||||
}
|
||||
|
||||
usbhsf_fifo_unselect(pipe, fifo);
|
||||
|
||||
return 0;
|
||||
|
||||
usbhs_fifo_write_busy:
|
||||
usbhsf_fifo_unselect(pipe, fifo);
|
||||
|
||||
/*
|
||||
* pipe is busy.
|
||||
* retry in interrupt
|
||||
|
@ -367,16 +388,13 @@ struct usbhs_pkt_handle usbhs_fifo_push_handler = {
|
|||
static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
|
||||
{
|
||||
struct usbhs_pipe *pipe = pkt->pipe;
|
||||
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
|
||||
struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */
|
||||
int ret;
|
||||
|
||||
if (usbhs_pipe_is_busy(pipe))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* select pipe and enable it to prepare packet receive
|
||||
* pipe enable to prepare packet receive
|
||||
*/
|
||||
ret = usbhsf_fifo_select(pipe, fifo, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
usbhs_pipe_enable(pipe);
|
||||
usbhsf_rx_irq_ctrl(pipe, 1);
|
||||
|
@ -400,11 +418,11 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt, int *is_done)
|
|||
|
||||
ret = usbhsf_fifo_select(pipe, fifo, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
ret = usbhsf_fifo_barrier(priv, fifo);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto usbhs_fifo_read_busy;
|
||||
|
||||
rcv_len = usbhsf_fifo_rcv_len(priv, fifo);
|
||||
|
||||
|
@ -457,7 +475,10 @@ usbhs_fifo_read_end:
|
|||
usbhs_pipe_number(pipe),
|
||||
pkt->length, pkt->actual, *is_done, pkt->zero);
|
||||
|
||||
return 0;
|
||||
usbhs_fifo_read_busy:
|
||||
usbhsf_fifo_unselect(pipe, fifo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct usbhs_pkt_handle usbhs_fifo_pop_handler = {
|
||||
|
@ -551,11 +572,14 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv,
|
|||
void usbhs_fifo_init(struct usbhs_priv *priv)
|
||||
{
|
||||
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
|
||||
struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv);
|
||||
|
||||
mod->irq_empty = usbhsf_irq_empty;
|
||||
mod->irq_ready = usbhsf_irq_ready;
|
||||
mod->irq_bempsts = 0;
|
||||
mod->irq_brdysts = 0;
|
||||
|
||||
cfifo->pipe = NULL;
|
||||
}
|
||||
|
||||
void usbhs_fifo_quit(struct usbhs_priv *priv)
|
||||
|
|
|
@ -23,6 +23,8 @@ struct usbhs_fifo {
|
|||
u32 port; /* xFIFO */
|
||||
u32 sel; /* xFIFOSEL */
|
||||
u32 ctr; /* xFIFOCTR */
|
||||
|
||||
struct usbhs_pipe *pipe;
|
||||
};
|
||||
|
||||
struct usbhs_fifo_info {
|
||||
|
|
|
@ -562,6 +562,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv,
|
|||
info->bufnmb_last++;
|
||||
|
||||
usbhsp_flags_init(pipe);
|
||||
pipe->fifo = NULL;
|
||||
pipe->mod_private = NULL;
|
||||
INIT_LIST_HEAD(&pipe->list);
|
||||
|
||||
|
@ -620,6 +621,18 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
|
|||
return pipe;
|
||||
}
|
||||
|
||||
void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo)
|
||||
{
|
||||
if (pipe->fifo)
|
||||
pipe->fifo->pipe = NULL;
|
||||
|
||||
pipe->fifo = fifo;
|
||||
|
||||
if (fifo)
|
||||
fifo->pipe = pipe;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* dcp control
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@ struct usbhs_pipe {
|
|||
u32 pipe_type; /* USB_ENDPOINT_XFER_xxx */
|
||||
|
||||
struct usbhs_priv *priv;
|
||||
struct usbhs_fifo *fifo;
|
||||
struct list_head list;
|
||||
|
||||
u32 flags;
|
||||
|
@ -88,10 +89,13 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
|
|||
void usbhs_pipe_enable(struct usbhs_pipe *pipe);
|
||||
void usbhs_pipe_disable(struct usbhs_pipe *pipe);
|
||||
void usbhs_pipe_stall(struct usbhs_pipe *pipe);
|
||||
void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);
|
||||
|
||||
#define usbhs_pipe_to_priv(p) ((p)->priv)
|
||||
#define usbhs_pipe_number(p) (int)((p) - (p)->priv->pipe_info.pipe)
|
||||
#define usbhs_pipe_is_dcp(p) ((p)->priv->pipe_info.pipe == (p))
|
||||
#define usbhs_pipe_to_fifo(p) ((p)->fifo)
|
||||
#define usbhs_pipe_is_busy(p) usbhs_pipe_to_fifo(p)
|
||||
|
||||
/*
|
||||
* dcp control
|
||||
|
|
Загрузка…
Ссылка в новой задаче