Skip to content

Commit

Permalink
usb: renesas_usbhs: care pipe sequence
Browse files Browse the repository at this point in the history
driver has to re-use the limited pipe for each device/endpoint
when it is USB host hub mode, since number of pipe has limitation.

Then, each pipe should care own pipe sequence for next packet.
This patch adds sequence control.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
  • Loading branch information
Kuninori Morimoto authored and Felipe Balbi committed Dec 13, 2011
1 parent e5679d0 commit 3edeee3
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 20 deletions.
9 changes: 8 additions & 1 deletion drivers/usb/renesas_usbhs/fifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ static struct usbhs_pkt_handle usbhsf_null_handler = {
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
void (*done)(struct usbhs_priv *priv,
struct usbhs_pkt *pkt),
void *buf, int len, int zero)
void *buf, int len, int zero, int sequence)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
struct device *dev = usbhs_priv_to_dev(priv);
Expand Down Expand Up @@ -90,6 +90,7 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
pkt->zero = zero;
pkt->actual = 0;
pkt->done = done;
pkt->sequence = sequence;

usbhs_unlock(priv, flags);
/******************** spin unlock ******************/
Expand Down Expand Up @@ -481,6 +482,9 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
int i, ret, len;
int is_short;

usbhs_pipe_data_sequence(pipe, pkt->sequence);
pkt->sequence = -1; /* -1 sequence will be ignored */

ret = usbhsf_fifo_select(pipe, fifo, 1);
if (ret < 0)
return 0;
Expand Down Expand Up @@ -584,6 +588,8 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
/*
* pipe enable to prepare packet receive
*/
usbhs_pipe_data_sequence(pipe, pkt->sequence);
pkt->sequence = -1; /* -1 sequence will be ignored */

usbhs_pipe_enable(pipe);
usbhsf_rx_irq_ctrl(pipe, 1);
Expand Down Expand Up @@ -641,6 +647,7 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
* "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
*/
if (0 == rcv_len) {
pkt->zero = 1;
usbhsf_fifo_clear(pipe, fifo);
goto usbhs_fifo_read_end;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/renesas_usbhs/fifo.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ struct usbhs_pkt {
int trans;
int actual;
int zero;
int sequence;
};

struct usbhs_pkt_handle {
Expand Down Expand Up @@ -95,7 +96,7 @@ void usbhs_pkt_init(struct usbhs_pkt *pkt);
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
void (*done)(struct usbhs_priv *priv,
struct usbhs_pkt *pkt),
void *buf, int len, int zero);
void *buf, int len, int zero, int sequence);
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
void usbhs_pkt_start(struct usbhs_pipe *pipe);

Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/renesas_usbhs/mod_gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,
req->actual = 0;
req->status = -EINPROGRESS;
usbhs_pkt_push(pipe, pkt, usbhsg_queue_done,
req->buf, req->length, req->zero);
req->buf, req->length, req->zero, -1);
usbhs_pkt_start(pipe);

dev_dbg(dev, "pipe %d : queue push (%d)\n",
Expand Down
71 changes: 56 additions & 15 deletions drivers/usb/renesas_usbhs/mod_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,48 @@ static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv,
/*
* pipe control
*/
static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv,
struct urb *urb,
struct usbhs_pkt *pkt)
{
int len = urb->actual_length;
int maxp = usb_endpoint_maxp(&urb->ep->desc);
int t = 0;

/* DCP is out of sequence control */
if (usb_pipecontrol(urb->pipe))
return;

/*
* renesas_usbhs pipe has a limitation in a number.
* So, driver should re-use the limited pipe for each device/endpoint.
* DATA0/1 sequence should be saved for it.
* see [image of mod_host]
* [HARDWARE LIMITATION]
*/

/*
* next sequence depends on actual_length
*
* ex) actual_length = 1147, maxp = 512
* data0 : 512
* data1 : 512
* data0 : 123
* data1 is the next sequence
*/
t = len / maxp;
if (len % maxp)
t++;
if (pkt->zero)
t++;
t %= 2;

if (t)
usb_dotoggle(urb->dev,
usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));
}

static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv,
struct urb *urb);

Expand Down Expand Up @@ -247,15 +289,6 @@ static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv,
usbhsh_uep_to_pipe(uep) = pipe;
usbhsh_pipe_to_uep(pipe) = uep;

if (!usb_gettoggle(urb->dev,
usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe))) {
usbhs_pipe_sequence_data0(pipe);
usb_settoggle(urb->dev,
usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), 1);
}

usbhs_pipe_config_update(pipe,
usbhsh_device_number(hpriv, udev),
usb_endpoint_num(desc),
Expand Down Expand Up @@ -598,10 +631,11 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
urb->actual_length = pkt->actual;
usbhsh_ureq_free(hpriv, ureq);

usbhsh_endpoint_sequence_save(hpriv, urb, pkt);
usbhsh_pipe_detach(hpriv, uep);

usb_hcd_unlink_urb_from_ep(hcd, urb);
usb_hcd_giveback_urb(hcd, urb, 0);

usbhsh_pipe_detach(hpriv, uep);
}

static int usbhsh_queue_push(struct usb_hcd *hcd,
Expand All @@ -614,7 +648,7 @@ static int usbhsh_queue_push(struct usb_hcd *hcd,
struct device *dev = usbhsh_hcd_to_dev(hcd);
struct usbhsh_request *ureq;
void *buf;
int len;
int len, sequence;

if (usb_pipeisoc(urb->pipe)) {
dev_err(dev, "pipe iso is not supported now\n");
Expand All @@ -636,9 +670,15 @@ static int usbhsh_queue_push(struct usb_hcd *hcd,
buf = (void *)(urb->transfer_buffer + urb->actual_length);
len = urb->transfer_buffer_length - urb->actual_length;

sequence = usb_gettoggle(urb->dev,
usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));

dev_dbg(dev, "%s\n", __func__);
usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done,
buf, len, (urb->transfer_flags & URB_ZERO_PACKET));
buf, len, (urb->transfer_flags & URB_ZERO_PACKET),
sequence);

usbhs_pkt_start(pipe);

return 0;
Expand Down Expand Up @@ -741,7 +781,8 @@ static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv,
usbhsh_data_stage_packet_done,
urb->transfer_buffer,
urb->transfer_buffer_length,
(urb->transfer_flags & URB_ZERO_PACKET));
(urb->transfer_flags & URB_ZERO_PACKET),
-1);

return 0;
}
Expand Down Expand Up @@ -770,7 +811,7 @@ static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv,
usbhsh_queue_done,
NULL,
urb->transfer_buffer_length,
0);
0, -1);

return 0;
}
Expand Down
21 changes: 19 additions & 2 deletions drivers/usb/renesas_usbhs/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,10 +478,27 @@ int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe)
return usbhsp_flags_has(pipe, IS_DIR_HOST);
}

void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data)
void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
{
u16 mask = (SQCLR | SQSET);
u16 val = (data) ? SQSET : SQCLR;
u16 val;

/*
* sequence
* 0 : data0
* 1 : data1
* -1 : no change
*/
switch (sequence) {
case 0:
val = SQCLR;
break;
case 1:
val = SQSET;
break;
default:
return;
}

usbhsp_pipectrl_set(pipe, mask, val);
}
Expand Down

0 comments on commit 3edeee3

Please sign in to comment.