1 // SPDX-License-Identifier: GPL-2.0+
3 * Freescale QUICC Engine USB Host Controller Driver
5 * Copyright (c) Freescale Semicondutor, Inc. 2006.
6 * Shlomi Gridish <gridish@freescale.com>
7 * Jerry Huang <Chang-Ming.Huang@freescale.com>
8 * Copyright (c) Logic Product Development, Inc. 2007
9 * Peter Barada <peterb@logicpd.com>
10 * Copyright (c) MontaVista Software, Inc. 2008.
11 * Anton Vorontsov <avorontsov@ru.mvista.com>
14 #include <linux/kernel.h>
15 #include <linux/types.h>
16 #include <linux/spinlock.h>
17 #include <linux/errno.h>
18 #include <linux/slab.h>
19 #include <linux/list.h>
20 #include <linux/usb.h>
21 #include <linux/usb/hcd.h>
24 /* maps the hardware error code to the USB error code */
25 static int status_to_error(u32 status
)
27 if (status
== USB_TD_OK
)
29 else if (status
& USB_TD_RX_ER_CRC
)
31 else if (status
& USB_TD_RX_ER_NONOCT
)
33 else if (status
& USB_TD_RX_ER_OVERUN
)
35 else if (status
& USB_TD_RX_ER_BITSTUFF
)
37 else if (status
& USB_TD_RX_ER_PID
)
39 else if (status
& (USB_TD_TX_ER_NAK
| USB_TD_TX_ER_TIMEOUT
))
41 else if (status
& USB_TD_TX_ER_STALL
)
43 else if (status
& USB_TD_TX_ER_UNDERUN
)
45 else if (status
& USB_TD_RX_DATA_UNDERUN
)
47 else if (status
& USB_TD_RX_DATA_OVERUN
)
53 void fhci_add_td_to_frame(struct fhci_time_frame
*frame
, struct td
*td
)
55 list_add_tail(&td
->frame_lh
, &frame
->tds_list
);
58 void fhci_add_tds_to_ed(struct ed
*ed
, struct td
**td_list
, int number
)
62 for (i
= 0; i
< number
; i
++) {
63 struct td
*td
= td_list
[i
];
64 list_add_tail(&td
->node
, &ed
->td_list
);
66 if (ed
->td_head
== NULL
)
67 ed
->td_head
= td_list
[0];
70 static struct td
*peek_td_from_ed(struct ed
*ed
)
74 if (!list_empty(&ed
->td_list
))
75 td
= list_entry(ed
->td_list
.next
, struct td
, node
);
82 struct td
*fhci_remove_td_from_frame(struct fhci_time_frame
*frame
)
86 if (!list_empty(&frame
->tds_list
)) {
87 td
= list_entry(frame
->tds_list
.next
, struct td
, frame_lh
);
88 list_del_init(frame
->tds_list
.next
);
95 struct td
*fhci_peek_td_from_frame(struct fhci_time_frame
*frame
)
99 if (!list_empty(&frame
->tds_list
))
100 td
= list_entry(frame
->tds_list
.next
, struct td
, frame_lh
);
107 struct td
*fhci_remove_td_from_ed(struct ed
*ed
)
111 if (!list_empty(&ed
->td_list
)) {
112 td
= list_entry(ed
->td_list
.next
, struct td
, node
);
113 list_del_init(ed
->td_list
.next
);
115 /* if this TD was the ED's head, find next TD */
116 if (!list_empty(&ed
->td_list
))
117 ed
->td_head
= list_entry(ed
->td_list
.next
, struct td
,
127 struct td
*fhci_remove_td_from_done_list(struct fhci_controller_list
*p_list
)
131 if (!list_empty(&p_list
->done_list
)) {
132 td
= list_entry(p_list
->done_list
.next
, struct td
, node
);
133 list_del_init(p_list
->done_list
.next
);
140 void fhci_move_td_from_ed_to_done_list(struct fhci_usb
*usb
, struct ed
*ed
)
145 list_del_init(&td
->node
);
147 /* If this TD was the ED's head,find next TD */
148 if (!list_empty(&ed
->td_list
))
149 ed
->td_head
= list_entry(ed
->td_list
.next
, struct td
, node
);
152 ed
->state
= FHCI_ED_SKIP
;
154 ed
->toggle_carry
= td
->toggle
;
155 list_add_tail(&td
->node
, &usb
->hc_list
->done_list
);
157 usb
->transfer_confirm(usb
->fhci
);
160 /* free done FHCI URB resource such as ED and TD */
161 static void free_urb_priv(struct fhci_hcd
*fhci
, struct urb
*urb
)
164 struct urb_priv
*urb_priv
= urb
->hcpriv
;
165 struct ed
*ed
= urb_priv
->ed
;
167 for (i
= 0; i
< urb_priv
->num_of_tds
; i
++) {
168 list_del_init(&urb_priv
->tds
[i
]->node
);
169 fhci_recycle_empty_td(fhci
, urb_priv
->tds
[i
]);
172 /* if this TD was the ED's head,find the next TD */
173 if (!list_empty(&ed
->td_list
))
174 ed
->td_head
= list_entry(ed
->td_list
.next
, struct td
, node
);
178 kfree(urb_priv
->tds
);
182 /* if this TD was the ED's head,find next TD */
183 if (ed
->td_head
== NULL
)
184 list_del_init(&ed
->node
);
188 /* this routine called to complete and free done URB */
189 void fhci_urb_complete_free(struct fhci_hcd
*fhci
, struct urb
*urb
)
191 free_urb_priv(fhci
, urb
);
193 if (urb
->status
== -EINPROGRESS
) {
194 if (urb
->actual_length
!= urb
->transfer_buffer_length
&&
195 urb
->transfer_flags
& URB_SHORT_NOT_OK
)
196 urb
->status
= -EREMOTEIO
;
201 usb_hcd_unlink_urb_from_ep(fhci_to_hcd(fhci
), urb
);
203 spin_unlock(&fhci
->lock
);
205 usb_hcd_giveback_urb(fhci_to_hcd(fhci
), urb
, urb
->status
);
207 spin_lock(&fhci
->lock
);
211 * caculate transfer length/stats and update the urb
212 * Precondition: irqsafe(only for urb-?status locking)
214 void fhci_done_td(struct urb
*urb
, struct td
*td
)
216 struct ed
*ed
= td
->ed
;
219 /* ISO...drivers see per-TD length/status */
220 if (ed
->mode
== FHCI_TF_ISO
) {
222 if (!(urb
->transfer_flags
& URB_SHORT_NOT_OK
&&
223 cc
== USB_TD_RX_DATA_UNDERUN
))
226 if (usb_pipeout(urb
->pipe
))
227 len
= urb
->iso_frame_desc
[td
->iso_index
].length
;
229 len
= td
->actual_len
;
231 urb
->actual_length
+= len
;
232 urb
->iso_frame_desc
[td
->iso_index
].actual_length
= len
;
233 urb
->iso_frame_desc
[td
->iso_index
].status
=
237 /* BULK,INT,CONTROL... drivers see aggregate length/status,
238 * except that "setup" bytes aren't counted and "short" transfers
239 * might not be reported as errors.
242 if (td
->error_cnt
>= 3)
243 urb
->error_count
= 3;
245 /* control endpoint only have soft stalls */
247 /* update packet status if needed(short may be ok) */
248 if (!(urb
->transfer_flags
& URB_SHORT_NOT_OK
) &&
249 cc
== USB_TD_RX_DATA_UNDERUN
) {
250 ed
->state
= FHCI_ED_OPER
;
253 if (cc
!= USB_TD_OK
) {
254 if (urb
->status
== -EINPROGRESS
)
255 urb
->status
= status_to_error(cc
);
258 /* count all non-empty packets except control SETUP packet */
259 if (td
->type
!= FHCI_TA_SETUP
|| td
->iso_index
!= 0)
260 urb
->actual_length
+= td
->actual_len
;
264 /* there are some pedning request to unlink */
265 void fhci_del_ed_list(struct fhci_hcd
*fhci
, struct ed
*ed
)
267 struct td
*td
= peek_td_from_ed(ed
);
268 struct urb
*urb
= td
->urb
;
269 struct urb_priv
*urb_priv
= urb
->hcpriv
;
271 if (urb_priv
->state
== URB_DEL
) {
272 td
= fhci_remove_td_from_ed(ed
);
273 /* HC may have partly processed this TD */
274 if (td
->status
!= USB_TD_INPROGRESS
)
275 fhci_done_td(urb
, td
);
277 /* URB is done;clean up */
278 if (++(urb_priv
->tds_cnt
) == urb_priv
->num_of_tds
)
279 fhci_urb_complete_free(fhci
, urb
);