diff options
Diffstat (limited to 'drivers/usb/host/isp1760-hcd.c')
| -rw-r--r-- | drivers/usb/host/isp1760-hcd.c | 74 | 
1 files changed, 31 insertions, 43 deletions
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 27dfab80ed8..fc72d44bf78 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -32,6 +32,13 @@ static struct kmem_cache *qtd_cachep;  static struct kmem_cache *qh_cachep;  static struct kmem_cache *urb_listitem_cachep; +enum queue_head_types { +	QH_CONTROL, +	QH_BULK, +	QH_INTERRUPT, +	QH_END +}; +  struct isp1760_hcd {  	u32 hcs_params;  	spinlock_t		lock; @@ -40,7 +47,7 @@ struct isp1760_hcd {  	struct slotinfo		int_slots[32];  	int			int_done_map;  	struct memory_chunk memory_pool[BLOCKS]; -	struct list_head	controlqhs, bulkqhs, interruptqhs; +	struct list_head	qh_list[QH_END];  	/* periodic schedule support */  #define	DEFAULT_I_TDPS		1024 @@ -406,12 +413,12 @@ static int priv_init(struct usb_hcd *hcd)  {  	struct isp1760_hcd		*priv = hcd_to_priv(hcd);  	u32			hcc_params; +	int i;  	spin_lock_init(&priv->lock); -	INIT_LIST_HEAD(&priv->interruptqhs); -	INIT_LIST_HEAD(&priv->controlqhs); -	INIT_LIST_HEAD(&priv->bulkqhs); +	for (i = 0; i < QH_END; i++) +		INIT_LIST_HEAD(&priv->qh_list[i]);  	/*  	 * hw default: 1K periodic list heads, one per frame. @@ -930,9 +937,9 @@ void schedule_ptds(struct usb_hcd *hcd)  	struct isp1760_hcd *priv;  	struct isp1760_qh *qh, *qh_next;  	struct list_head *ep_queue; -	struct usb_host_endpoint *ep;  	LIST_HEAD(urb_list);  	struct urb_listitem *urb_listitem, *urb_listitem_next; +	int i;  	if (!hcd) {  		WARN_ON(1); @@ -944,28 +951,13 @@ void schedule_ptds(struct usb_hcd *hcd)  	/*  	 * check finished/retired xfers, transfer payloads, call urb_done()  	 */ -	ep_queue = &priv->interruptqhs; -	while (ep_queue) { +	for (i = 0; i < QH_END; i++) { +		ep_queue = &priv->qh_list[i];  		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) { -			ep = list_entry(qh->qtd_list.next, struct isp1760_qtd, -							qtd_list)->urb->ep;  			collect_qtds(hcd, qh, &urb_list); -			if (list_empty(&qh->qtd_list)) { +			if (list_empty(&qh->qtd_list))  				list_del(&qh->qh_list); -				if (ep->hcpriv == NULL) { -					/* Endpoint has been disabled, so we -					can free the associated queue head. */ -					qh_free(qh); -				} -			}  		} - -		if (ep_queue == &priv->interruptqhs) -			ep_queue = &priv->controlqhs; -		else if (ep_queue == &priv->controlqhs) -			ep_queue = &priv->bulkqhs; -		else -			ep_queue = NULL;  	}  	list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list, @@ -998,17 +990,10 @@ void schedule_ptds(struct usb_hcd *hcd)  	 *  	 * I'm sure this scheme could be improved upon!  	 */ -	ep_queue = &priv->controlqhs; -	while (ep_queue) { +	for (i = 0; i < QH_END; i++) { +		ep_queue = &priv->qh_list[i];  		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)  			enqueue_qtds(hcd, qh); - -		if (ep_queue == &priv->controlqhs) -			ep_queue = &priv->interruptqhs; -		else if (ep_queue == &priv->interruptqhs) -			ep_queue = &priv->bulkqhs; -		else -			ep_queue = NULL;  	}  } @@ -1543,16 +1528,16 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,  	switch (usb_pipetype(urb->pipe)) {  	case PIPE_CONTROL: -		ep_queue = &priv->controlqhs; +		ep_queue = &priv->qh_list[QH_CONTROL];  		break;  	case PIPE_BULK: -		ep_queue = &priv->bulkqhs; +		ep_queue = &priv->qh_list[QH_BULK];  		break;  	case PIPE_INTERRUPT:  		if (urb->interval < 0)  			return -EINVAL;  		/* FIXME: Check bandwidth  */ -		ep_queue = &priv->interruptqhs; +		ep_queue = &priv->qh_list[QH_INTERRUPT];  		break;  	case PIPE_ISOCHRONOUS:  		dev_err(hcd->self.controller, "%s: isochronous USB packets " @@ -1714,8 +1699,8 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,  {  	struct isp1760_hcd *priv = hcd_to_priv(hcd);  	unsigned long spinflags; -	struct isp1760_qh *qh; -	struct isp1760_qtd *qtd; +	struct isp1760_qh *qh, *qh_iter; +	int i;  	spin_lock_irqsave(&priv->lock, spinflags); @@ -1723,14 +1708,17 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,  	if (!qh)  		goto out; -	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) -		if (qtd->status != QTD_RETIRE) { -			dequeue_urb_from_qtd(hcd, qh, qtd); -			qtd->urb->status = -ECONNRESET; -		} +	WARN_ON(!list_empty(&qh->qtd_list)); +	for (i = 0; i < QH_END; i++) +		list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list) +			if (qh_iter == qh) { +				list_del(&qh_iter->qh_list); +				i = QH_END; +				break; +			} +	qh_free(qh);  	ep->hcpriv = NULL; -	/* Cannot free qh here since it will be parsed by schedule_ptds() */  	schedule_ptds(hcd);  |