提交 d77e3f4e 编写于 作者: K Kuninori Morimoto 提交者: Greg Kroah-Hartman

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: NKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 d3af90a5
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) #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 * packet info function
*/ */
...@@ -237,6 +239,15 @@ static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, ...@@ -237,6 +239,15 @@ static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv,
return usbhs_read(priv, fifo->ctr) & DTLN_MASK; 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, static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
struct usbhs_fifo *fifo, struct usbhs_fifo *fifo,
int write) int write)
...@@ -247,6 +258,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe, ...@@ -247,6 +258,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */
u16 base = usbhs_pipe_number(pipe); /* 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)) if (usbhs_pipe_is_dcp(pipe))
base |= (1 == write) << 5; /* ISEL */ base |= (1 == write) << 5; /* ISEL */
...@@ -255,8 +270,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe, ...@@ -255,8 +270,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
/* check ISEL and CURPIPE value */ /* check ISEL and CURPIPE value */
while (timeout--) { 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; return 0;
}
udelay(10); udelay(10);
} }
...@@ -283,7 +300,7 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done) ...@@ -283,7 +300,7 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done)
ret = usbhsf_fifo_select(pipe, fifo, 1); ret = usbhsf_fifo_select(pipe, fifo, 1);
if (ret < 0) if (ret < 0)
goto usbhs_fifo_write_busy; return 0;
ret = usbhs_pipe_is_accessible(pipe); ret = usbhs_pipe_is_accessible(pipe);
if (ret < 0) if (ret < 0)
...@@ -347,9 +364,13 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done) ...@@ -347,9 +364,13 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done)
usbhs_dcp_control_transfer_done(pipe); usbhs_dcp_control_transfer_done(pipe);
} }
usbhsf_fifo_unselect(pipe, fifo);
return 0; return 0;
usbhs_fifo_write_busy: usbhs_fifo_write_busy:
usbhsf_fifo_unselect(pipe, fifo);
/* /*
* pipe is busy. * pipe is busy.
* retry in interrupt * retry in interrupt
...@@ -367,16 +388,13 @@ struct usbhs_pkt_handle usbhs_fifo_push_handler = { ...@@ -367,16 +388,13 @@ struct usbhs_pkt_handle usbhs_fifo_push_handler = {
static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
{ {
struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ if (usbhs_pipe_is_busy(pipe))
int ret; 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); usbhs_pipe_enable(pipe);
usbhsf_rx_irq_ctrl(pipe, 1); usbhsf_rx_irq_ctrl(pipe, 1);
...@@ -400,11 +418,11 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt, int *is_done) ...@@ -400,11 +418,11 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt, int *is_done)
ret = usbhsf_fifo_select(pipe, fifo, 0); ret = usbhsf_fifo_select(pipe, fifo, 0);
if (ret < 0) if (ret < 0)
return ret; return 0;
ret = usbhsf_fifo_barrier(priv, fifo); ret = usbhsf_fifo_barrier(priv, fifo);
if (ret < 0) if (ret < 0)
return ret; goto usbhs_fifo_read_busy;
rcv_len = usbhsf_fifo_rcv_len(priv, fifo); rcv_len = usbhsf_fifo_rcv_len(priv, fifo);
...@@ -457,7 +475,10 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt, int *is_done) ...@@ -457,7 +475,10 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt, int *is_done)
usbhs_pipe_number(pipe), usbhs_pipe_number(pipe),
pkt->length, pkt->actual, *is_done, pkt->zero); 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 = { struct usbhs_pkt_handle usbhs_fifo_pop_handler = {
...@@ -551,11 +572,14 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv, ...@@ -551,11 +572,14 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv,
void usbhs_fifo_init(struct usbhs_priv *priv) void usbhs_fifo_init(struct usbhs_priv *priv)
{ {
struct usbhs_mod *mod = usbhs_mod_get_current(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_empty = usbhsf_irq_empty;
mod->irq_ready = usbhsf_irq_ready; mod->irq_ready = usbhsf_irq_ready;
mod->irq_bempsts = 0; mod->irq_bempsts = 0;
mod->irq_brdysts = 0; mod->irq_brdysts = 0;
cfifo->pipe = NULL;
} }
void usbhs_fifo_quit(struct usbhs_priv *priv) void usbhs_fifo_quit(struct usbhs_priv *priv)
......
...@@ -23,6 +23,8 @@ struct usbhs_fifo { ...@@ -23,6 +23,8 @@ struct usbhs_fifo {
u32 port; /* xFIFO */ u32 port; /* xFIFO */
u32 sel; /* xFIFOSEL */ u32 sel; /* xFIFOSEL */
u32 ctr; /* xFIFOCTR */ u32 ctr; /* xFIFOCTR */
struct usbhs_pipe *pipe;
}; };
struct usbhs_fifo_info { struct usbhs_fifo_info {
......
...@@ -562,6 +562,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv, ...@@ -562,6 +562,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv,
info->bufnmb_last++; info->bufnmb_last++;
usbhsp_flags_init(pipe); usbhsp_flags_init(pipe);
pipe->fifo = NULL;
pipe->mod_private = NULL; pipe->mod_private = NULL;
INIT_LIST_HEAD(&pipe->list); INIT_LIST_HEAD(&pipe->list);
...@@ -620,6 +621,18 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, ...@@ -620,6 +621,18 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
return pipe; 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 * dcp control
*/ */
......
...@@ -27,6 +27,7 @@ struct usbhs_pipe { ...@@ -27,6 +27,7 @@ struct usbhs_pipe {
u32 pipe_type; /* USB_ENDPOINT_XFER_xxx */ u32 pipe_type; /* USB_ENDPOINT_XFER_xxx */
struct usbhs_priv *priv; struct usbhs_priv *priv;
struct usbhs_fifo *fifo;
struct list_head list; struct list_head list;
u32 flags; u32 flags;
...@@ -88,10 +89,13 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); ...@@ -88,10 +89,13 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
void usbhs_pipe_enable(struct usbhs_pipe *pipe); void usbhs_pipe_enable(struct usbhs_pipe *pipe);
void usbhs_pipe_disable(struct usbhs_pipe *pipe); void usbhs_pipe_disable(struct usbhs_pipe *pipe);
void usbhs_pipe_stall(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_to_priv(p) ((p)->priv)
#define usbhs_pipe_number(p) (int)((p) - (p)->priv->pipe_info.pipe) #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_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 * dcp control
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册