diff options
Diffstat (limited to 'drivers/usb/host/isp1760-hcd.c')
| -rw-r--r-- | drivers/usb/host/isp1760-hcd.c | 1638 | 
1 files changed, 773 insertions, 865 deletions
| diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 7b2e69aa2e98..55d3d5859ac5 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -8,6 +8,8 @@   *   * (c) 2007 Sebastian Siewior <[email protected]>   * + * (c) 2011 Arvid Brodin <[email protected]> + *   */  #include <linux/module.h>  #include <linux/kernel.h> @@ -26,14 +28,18 @@  static struct kmem_cache *qtd_cachep;  static struct kmem_cache *qh_cachep; +static struct kmem_cache *urb_listitem_cachep;  struct isp1760_hcd {  	u32 hcs_params;  	spinlock_t		lock; -	struct inter_packet_info atl_ints[32]; -	struct inter_packet_info int_ints[32]; +	struct slotinfo		atl_slots[32]; +	int			atl_done_map; +	struct slotinfo		int_slots[32]; +	int			int_done_map;  	struct memory_chunk memory_pool[BLOCKS]; -	u32 atl_queued; +	struct list_head	controlqhs, bulkqhs, interruptqhs; +	int active_ptds;  	/* periodic schedule support */  #define	DEFAULT_I_TDPS		1024 @@ -85,18 +91,34 @@ struct isp1760_qtd {  	struct list_head qtd_list;  	struct urb *urb;  	size_t length; - -	/* isp special*/ +	size_t actual_length; + +	/* QTD_ENQUEUED:	waiting for transfer (inactive) */ +	/* QTD_PAYLOAD_ALLOC:	chip mem has been allocated for payload */ +	/* QTD_XFER_STARTED:	valid ptd has been written to isp176x - only +				interrupt handler may touch this qtd! */ +	/* QTD_XFER_COMPLETE:	payload has been transferred successfully */ +	/* QTD_RETIRE:		transfer error/abort qtd */ +#define QTD_ENQUEUED		0 +#define QTD_PAYLOAD_ALLOC	1 +#define QTD_XFER_STARTED	2 +#define QTD_XFER_COMPLETE	3 +#define QTD_RETIRE		4  	u32 status; -#define URB_ENQUEUED		(1 << 1)  }; +/* Queue head, one for each active endpoint */  struct isp1760_qh { -	/* first part defined by EHCI spec */ +	struct list_head qh_list;  	struct list_head qtd_list; -  	u32 toggle;  	u32 ping; +	int slot; +}; + +struct urb_listitem { +	struct list_head urb_list; +	struct urb *urb;  };  /* @@ -272,7 +294,7 @@ static void init_memory(struct isp1760_hcd *priv)  		payload_addr += priv->memory_pool[curr + i].size;  	} -	BUG_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE); +	WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);  }  static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) @@ -280,7 +302,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)  	struct isp1760_hcd *priv = hcd_to_priv(hcd);  	int i; -	BUG_ON(qtd->payload_addr); +	WARN_ON(qtd->payload_addr);  	if (!qtd->length)  		return; @@ -293,19 +315,6 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)  			return;  		}  	} - -	dev_err(hcd->self.controller, -				"%s: Cannot allocate %zu bytes of memory\n" -				"Current memory map:\n", -				__func__, qtd->length); -	for (i = 0; i < BLOCKS; i++) { -		dev_err(hcd->self.controller, "Pool %2d size %4d status: %d\n", -				i, priv->memory_pool[i].size, -				priv->memory_pool[i].free); -	} -	/* XXX maybe -ENOMEM could be possible */ -	BUG(); -	return;  }  static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) @@ -318,7 +327,7 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)  	for (i = 0; i < BLOCKS; i++) {  		if (priv->memory_pool[i].start == qtd->payload_addr) { -			BUG_ON(priv->memory_pool[i].free); +			WARN_ON(priv->memory_pool[i].free);  			priv->memory_pool[i].free = 1;  			qtd->payload_addr = 0;  			return; @@ -327,19 +336,8 @@ static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)  	dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n",  						__func__, qtd->payload_addr); -	BUG(); -} - -static void isp1760_init_regs(struct usb_hcd *hcd) -{ -	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0); -	reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); -	reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); -	reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); - -	reg_write32(hcd->regs, HC_ATL_PTD_DONEMAP_REG, ~NO_TRANSFER_ACTIVE); -	reg_write32(hcd->regs, HC_INT_PTD_DONEMAP_REG, ~NO_TRANSFER_ACTIVE); -	reg_write32(hcd->regs, HC_ISO_PTD_DONEMAP_REG, ~NO_TRANSFER_ACTIVE); +	WARN_ON(1); +	qtd->payload_addr = 0;  }  static int handshake(struct usb_hcd *hcd, u32 reg, @@ -377,31 +375,27 @@ static int ehci_reset(struct usb_hcd *hcd)  	return retval;  } -static void qh_destroy(struct isp1760_qh *qh) -{ -	BUG_ON(!list_empty(&qh->qtd_list)); -	kmem_cache_free(qh_cachep, qh); -} - -static struct isp1760_qh *isp1760_qh_alloc(gfp_t flags) +static struct isp1760_qh *qh_alloc(gfp_t flags)  {  	struct isp1760_qh *qh;  	qh = kmem_cache_zalloc(qh_cachep, flags);  	if (!qh) -		return qh; +		return NULL; +	INIT_LIST_HEAD(&qh->qh_list);  	INIT_LIST_HEAD(&qh->qtd_list); +	qh->slot = -1; +  	return qh;  } -/* magic numbers that can affect system performance */ -#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */ -#define	EHCI_TUNE_RL_HS		4	/* nak throttle; see 4.9 */ -#define	EHCI_TUNE_RL_TT		0 -#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */ -#define	EHCI_TUNE_MULT_TT	1 -#define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */ +static void qh_free(struct isp1760_qh *qh) +{ +	WARN_ON(!list_empty(&qh->qtd_list)); +	WARN_ON(qh->slot > -1); +	kmem_cache_free(qh_cachep, qh); +}  /* one-time init, only for memory state */  static int priv_init(struct usb_hcd *hcd) @@ -411,6 +405,10 @@ static int priv_init(struct usb_hcd *hcd)  	spin_lock_init(&priv->lock); +	INIT_LIST_HEAD(&priv->interruptqhs); +	INIT_LIST_HEAD(&priv->controlqhs); +	INIT_LIST_HEAD(&priv->bulkqhs); +  	/*  	 * hw default: 1K periodic list heads, one per frame.  	 * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -468,7 +466,10 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)  	}  	/* pre reset */ -	isp1760_init_regs(hcd); +	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0); +	reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); +	reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); +	reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);  	/* reset */  	reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL); @@ -488,12 +489,15 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)  			   16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?  			   "analog" : "digital"); +	/* This is weird: at the first plug-in of a device there seems to be +	   one packet queued that never gets returned? */ +	priv->active_ptds = -1; +  	/* ATL reset */  	reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);  	mdelay(10);  	reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); -	reg_write32(hcd->regs, HC_INTERRUPT_REG, INTERRUPT_ENABLE_MASK);  	reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);  	/* @@ -516,14 +520,21 @@ static void isp1760_init_maps(struct usb_hcd *hcd)  	reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);  	reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);  	reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001); + +	reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff); +	reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff); +	reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff); + +	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, +						ATL_BUF_FILL | INT_BUF_FILL);  }  static void isp1760_enable_interrupts(struct usb_hcd *hcd)  {  	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0); -	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0); +	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);  	reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0); -	reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0); +	reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);  	reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);  	reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);  	/* step 23 passed */ @@ -548,8 +559,7 @@ static int isp1760_run(struct usb_hcd *hcd)  	command |= CMD_RUN;  	reg_write32(hcd->regs, HC_USBCMD, command); -	retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, -			250 * 1000); +	retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);  	if (retval)  		return retval; @@ -598,12 +608,19 @@ static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh)  	return (qtd->urb != urb);  } -static void transform_into_atl(struct isp1760_qh *qh, +/* magic numbers that can affect system performance */ +#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */ +#define	EHCI_TUNE_RL_HS		4	/* nak throttle; see 4.9 */ +#define	EHCI_TUNE_RL_TT		0 +#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */ +#define	EHCI_TUNE_MULT_TT	1 +#define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */ + +static void create_ptd_atl(struct isp1760_qh *qh,  			struct isp1760_qtd *qtd, struct ptd *ptd)  {  	u32 maxpacket;  	u32 multi; -	u32 pid_code;  	u32 rl = RL_COUNTER;  	u32 nak = NAK_COUNTER; @@ -616,67 +633,62 @@ static void transform_into_atl(struct isp1760_qh *qh,  	maxpacket &= 0x7ff;  	/* DW0 */ -	ptd->dw0 = PTD_VALID; -	ptd->dw0 |= PTD_LENGTH(qtd->length); -	ptd->dw0 |= PTD_MAXPACKET(maxpacket); -	ptd->dw0 |= PTD_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe)); +	ptd->dw0 = DW0_VALID_BIT; +	ptd->dw0 |= TO_DW0_LENGTH(qtd->length); +	ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket); +	ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));  	/* DW1 */  	ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1; -	ptd->dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe)); - -	pid_code = qtd->packet_type; -	ptd->dw1 |= PTD_PID_TOKEN(pid_code); +	ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe)); +	ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);  	if (usb_pipebulk(qtd->urb->pipe)) -		ptd->dw1 |= PTD_TRANS_BULK; +		ptd->dw1 |= DW1_TRANS_BULK;  	else if  (usb_pipeint(qtd->urb->pipe)) -		ptd->dw1 |= PTD_TRANS_INT; +		ptd->dw1 |= DW1_TRANS_INT;  	if (qtd->urb->dev->speed != USB_SPEED_HIGH) {  		/* split transaction */ -		ptd->dw1 |= PTD_TRANS_SPLIT; +		ptd->dw1 |= DW1_TRANS_SPLIT;  		if (qtd->urb->dev->speed == USB_SPEED_LOW) -			ptd->dw1 |= PTD_SE_USB_LOSPEED; +			ptd->dw1 |= DW1_SE_USB_LOSPEED; -		ptd->dw1 |= PTD_PORT_NUM(qtd->urb->dev->ttport); -		ptd->dw1 |= PTD_HUB_NUM(qtd->urb->dev->tt->hub->devnum); +		ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport); +		ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum);  		/* SE bit for Split INT transfers */  		if (usb_pipeint(qtd->urb->pipe) &&  				(qtd->urb->dev->speed == USB_SPEED_LOW))  			ptd->dw1 |= 2 << 16; -		ptd->dw3 = 0;  		rl = 0;  		nak = 0;  	} else { -		ptd->dw0 |= PTD_MULTI(multi); +		ptd->dw0 |= TO_DW0_MULTI(multi);  		if (usb_pipecontrol(qtd->urb->pipe) ||  						usb_pipebulk(qtd->urb->pipe)) -			ptd->dw3 = qh->ping; -		else -			ptd->dw3 = 0; +			ptd->dw3 |= TO_DW3_PING(qh->ping);  	}  	/* DW2 */  	ptd->dw2 = 0; -	ptd->dw2 |= PTD_DATA_START_ADDR(base_to_chip(qtd->payload_addr)); -	ptd->dw2 |= PTD_RL_CNT(rl); -	ptd->dw3 |= PTD_NAC_CNT(nak); +	ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr)); +	ptd->dw2 |= TO_DW2_RL(rl);  	/* DW3 */ -	ptd->dw3 |= qh->toggle; +	ptd->dw3 |= TO_DW3_NAKCOUNT(nak); +	ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle);  	if (usb_pipecontrol(qtd->urb->pipe)) {  		if (qtd->data_buffer == qtd->urb->setup_packet) -			ptd->dw3 &= ~PTD_DATA_TOGGLE(1); +			ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1);  		else if (last_qtd_of_urb(qtd, qh)) -			ptd->dw3 |= PTD_DATA_TOGGLE(1); +			ptd->dw3 |= TO_DW3_DATA_TOGGLE(1);  	} -	ptd->dw3 |= PTD_ACTIVE; +	ptd->dw3 |= DW3_ACTIVE_BIT;  	/* Cerr */ -	ptd->dw3 |= PTD_CERR(ERR_COUNTER); +	ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER);  }  static void transform_add_int(struct isp1760_qh *qh, @@ -731,197 +743,13 @@ static void transform_add_int(struct isp1760_qh *qh,  	ptd->dw4 = usof;  } -static void transform_into_int(struct isp1760_qh *qh, +static void create_ptd_int(struct isp1760_qh *qh,  			struct isp1760_qtd *qtd, struct ptd *ptd)  { -	transform_into_atl(qh, qtd, ptd); +	create_ptd_atl(qh, qtd, ptd);  	transform_add_int(qh, qtd, ptd);  } -static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len, -		u32 token) -{ -	int count; - -	qtd->data_buffer = databuffer; -	qtd->packet_type = GET_QTD_TOKEN_TYPE(token); - -	if (len > MAX_PAYLOAD_SIZE) -		count = MAX_PAYLOAD_SIZE; -	else -		count = len; - -	qtd->length = count; -	return count; -} - -static int check_error(struct usb_hcd *hcd, struct ptd *ptd) -{ -	int error = 0; - -	if (ptd->dw3 & DW3_HALT_BIT) { -		error = -EPIPE; - -		if (ptd->dw3 & DW3_ERROR_BIT) -			pr_err("error bit is set in DW3\n"); -	} - -	if (ptd->dw3 & DW3_QTD_ACTIVE) { -		dev_err(hcd->self.controller, "Transfer active bit is set DW3\n" -			"nak counter: %d, rl: %d\n", -			(ptd->dw3 >> 19) & 0xf, (ptd->dw2 >> 25) & 0xf); -	} - -	return error; -} - -static void check_int_err_status(struct usb_hcd *hcd, u32 dw4) -{ -	u32 i; - -	dw4 >>= 8; - -	for (i = 0; i < 8; i++) { -		switch (dw4 & 0x7) { -		case INT_UNDERRUN: -			dev_err(hcd->self.controller, "Underrun (%d)\n", i); -			break; - -		case INT_EXACT: -			dev_err(hcd->self.controller, -						"Transaction error (%d)\n", i); -			break; - -		case INT_BABBLE: -			dev_err(hcd->self.controller, "Babble error (%d)\n", i); -			break; -		} -		dw4 >>= 3; -	} -} - -static void enqueue_one_qtd(struct usb_hcd *hcd, struct isp1760_qtd *qtd) -{ -	if (qtd->length && (qtd->length <= MAX_PAYLOAD_SIZE)) { -		switch (qtd->packet_type) { -		case IN_PID: -			break; -		case OUT_PID: -		case SETUP_PID: -			mem_writes8(hcd->regs, qtd->payload_addr, -						qtd->data_buffer, qtd->length); -		} -	} -} - -static void enqueue_one_atl_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh, -					u32 slot, struct isp1760_qtd *qtd) -{ -	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	struct ptd ptd; - -	alloc_mem(hcd, qtd); -	transform_into_atl(qh, qtd, &ptd); -	ptd_write(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); -	enqueue_one_qtd(hcd, qtd); - -	priv->atl_ints[slot].qh = qh; -	priv->atl_ints[slot].qtd = qtd; -	qtd->status |= URB_ENQUEUED; -	qtd->status |= slot << 16; -} - -static void enqueue_one_int_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh, -					u32 slot, struct isp1760_qtd *qtd) -{ -	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	struct ptd ptd; - -	alloc_mem(hcd, qtd); -	transform_into_int(qh, qtd, &ptd); -	ptd_write(hcd->regs, INT_PTD_OFFSET, slot, &ptd); -	enqueue_one_qtd(hcd, qtd); - -	priv->int_ints[slot].qh = qh; -	priv->int_ints[slot].qtd = qtd; -	qtd->status |= URB_ENQUEUED; -	qtd->status |= slot << 16; -} - -static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, -				  struct isp1760_qtd *qtd) -{ -	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	u32 skip_map, or_map; -	u32 slot; -	u32 buffstatus; - -	/* -	 * When this function is called from the interrupt handler to enqueue -	 * a follow-up packet, the SKIP register gets written and read back -	 * almost immediately. With ISP1761, this register requires a delay of -	 * 195ns between a write and subsequent read (see section 15.1.1.3). -	 */ -	mmiowb(); -	ndelay(195); -	skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); - -	BUG_ON(!skip_map); -	slot = __ffs(skip_map); - -	enqueue_one_atl_qtd(hcd, qh, slot, qtd); - -	or_map = reg_read32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG); -	or_map |= (1 << slot); -	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, or_map); - -	skip_map &= ~(1 << slot); -	reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); - -	priv->atl_queued++; -	if (priv->atl_queued == 2) -		reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, -				INTERRUPT_ENABLE_SOT_MASK); - -	buffstatus = reg_read32(hcd->regs, HC_BUFFER_STATUS_REG); -	buffstatus |= ATL_BUFFER; -	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, buffstatus); -} - -static void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, -				  struct isp1760_qtd *qtd) -{ -	u32 skip_map, or_map; -	u32 slot; -	u32 buffstatus; - -	/* -	 * When this function is called from the interrupt handler to enqueue -	 * a follow-up packet, the SKIP register gets written and read back -	 * almost immediately. With ISP1761, this register requires a delay of -	 * 195ns between a write and subsequent read (see section 15.1.1.3). -	 */ -	mmiowb(); -	ndelay(195); -	skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); - -	BUG_ON(!skip_map); -	slot = __ffs(skip_map); - -	enqueue_one_int_qtd(hcd, qh, slot, qtd); - -	or_map = reg_read32(hcd->regs, HC_INT_IRQ_MASK_OR_REG); -	or_map |= (1 << slot); -	reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, or_map); - -	skip_map &= ~(1 << slot); -	reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); - -	buffstatus = reg_read32(hcd->regs, HC_BUFFER_STATUS_REG); -	buffstatus |= INT_BUFFER; -	reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, buffstatus); -} -  static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb)  __releases(priv->lock)  __acquires(priv->lock) @@ -948,557 +776,654 @@ __acquires(priv->lock)  	spin_lock(&priv->lock);  } -static void isp1760_qtd_free(struct isp1760_qtd *qtd) +static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb, +								u8 packet_type)  { -	BUG_ON(qtd->payload_addr); -	kmem_cache_free(qtd_cachep, qtd); +	struct isp1760_qtd *qtd; + +	qtd = kmem_cache_zalloc(qtd_cachep, flags); +	if (!qtd) +		return NULL; + +	INIT_LIST_HEAD(&qtd->qtd_list); +	qtd->urb = urb; +	qtd->packet_type = packet_type; +	qtd->status = QTD_ENQUEUED; +	qtd->actual_length = 0; + +	return qtd;  } -static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd, -							struct isp1760_qh *qh) +static void qtd_free(struct isp1760_qtd *qtd)  { -	struct isp1760_qtd *tmp_qtd; - -	if (list_is_last(&qtd->qtd_list, &qh->qtd_list)) -		tmp_qtd = NULL; -	else -		tmp_qtd = list_entry(qtd->qtd_list.next, struct isp1760_qtd, -								qtd_list); -	list_del(&qtd->qtd_list); -	isp1760_qtd_free(qtd); -	return tmp_qtd; +	WARN_ON(qtd->payload_addr); +	kmem_cache_free(qtd_cachep, qtd);  } -/* - * Remove this QTD from the QH list and free its memory. If this QTD - * isn't the last one than remove also his successor(s). - * Returns the QTD which is part of an new URB and should be enqueued. - */ -static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd, -							struct isp1760_qh *qh) +static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot, +				struct slotinfo *slots, struct isp1760_qtd *qtd, +				struct isp1760_qh *qh, struct ptd *ptd)  { -	struct urb *urb; +	struct isp1760_hcd *priv = hcd_to_priv(hcd); +	int skip_map; + +	WARN_ON((slot < 0) || (slot > 31)); +	WARN_ON(qtd->length && !qtd->payload_addr); +	WARN_ON(slots[slot].qtd); +	WARN_ON(slots[slot].qh); +	WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC); + +	slots[slot].qtd = qtd; +	slots[slot].qh = qh; +	qh->slot = slot; +	qtd->status = QTD_XFER_STARTED; /* Set this before writing ptd, since +		interrupt routine may preempt and expects this value. */ +	ptd_write(hcd->regs, ptd_offset, slot, ptd); +	priv->active_ptds++; + +	/* Make sure done map has not triggered from some unlinked transfer */ +	if (ptd_offset == ATL_PTD_OFFSET) { +		priv->atl_done_map |= reg_read32(hcd->regs, +						HC_ATL_PTD_DONEMAP_REG); +		priv->atl_done_map &= ~(1 << qh->slot); -	urb = qtd->urb; -	do { -		qtd = clean_this_qtd(qtd, qh); -	} while (qtd && (qtd->urb == urb)); +		skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); +		skip_map &= ~(1 << qh->slot); +		reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); +	} else { +		priv->int_done_map |= reg_read32(hcd->regs, +						HC_INT_PTD_DONEMAP_REG); +		priv->int_done_map &= ~(1 << qh->slot); -	return qtd; +		skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); +		skip_map &= ~(1 << qh->slot); +		reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); +	}  } -static void do_atl_int(struct usb_hcd *hcd) +static int is_short_bulk(struct isp1760_qtd *qtd)  { -	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	u32 done_map, skip_map; -	struct ptd ptd; -	struct urb *urb; -	u32 slot; -	u32 length; -	u32 or_map; -	u32 status = -EINVAL; -	int error; -	struct isp1760_qtd *qtd; -	struct isp1760_qh *qh; -	u32 rl; -	u32 nakcount; +	return (usb_pipebulk(qtd->urb->pipe) && +					(qtd->actual_length < qtd->length)); +} -	done_map = reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG); -	skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); +static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, +						struct list_head *urb_list) +{ +	int last_qtd; +	struct isp1760_qtd *qtd, *qtd_next; +	struct urb_listitem *urb_listitem; -	or_map = reg_read32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG); -	or_map &= ~done_map; -	reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, or_map); +	list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) { +		if (qtd->status < QTD_XFER_COMPLETE) +			break; -	while (done_map) { -		status = 0; -		priv->atl_queued--; +		if (list_is_last(&qtd->qtd_list, &qh->qtd_list)) +			last_qtd = 1; +		else +			last_qtd = qtd->urb != qtd_next->urb; + +		if ((!last_qtd) && (qtd->status == QTD_RETIRE)) +			qtd_next->status = QTD_RETIRE; + +		if (qtd->status == QTD_XFER_COMPLETE) { +			if (qtd->actual_length) { +				switch (qtd->packet_type) { +				case IN_PID: +					mem_reads8(hcd->regs, qtd->payload_addr, +							qtd->data_buffer, +							qtd->actual_length); +					/* Fall through (?) */ +				case OUT_PID: +					qtd->urb->actual_length += +							qtd->actual_length; +					/* Fall through ... */ +				case SETUP_PID: +					break; +				} +			} -		slot = __ffs(done_map); -		done_map &= ~(1 << slot); -		skip_map |= (1 << slot); +			if (is_short_bulk(qtd)) { +				if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK) +					qtd->urb->status = -EREMOTEIO; +				if (!last_qtd) +					qtd_next->status = QTD_RETIRE; +			} +		} -		qtd = priv->atl_ints[slot].qtd; -		qh = priv->atl_ints[slot].qh; +		if (qtd->payload_addr) +			free_mem(hcd, qtd); -		if (!qh) { -			dev_err(hcd->self.controller, "qh is 0\n"); -			continue; +		if (last_qtd) { +			if ((qtd->status == QTD_RETIRE) && +					(qtd->urb->status == -EINPROGRESS)) +				qtd->urb->status = -EPIPE; +			/* Defer calling of urb_done() since it releases lock */ +			urb_listitem = kmem_cache_zalloc(urb_listitem_cachep, +								GFP_ATOMIC); +			if (unlikely(!urb_listitem)) +				break; +			urb_listitem->urb = qtd->urb; +			list_add_tail(&urb_listitem->urb_list, urb_list);  		} -		ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); -		rl = (ptd.dw2 >> 25) & 0x0f; -		nakcount = (ptd.dw3 >> 19) & 0xf; - -		/* Transfer Error, *but* active and no HALT -> reload */ -		if ((ptd.dw3 & DW3_ERROR_BIT) && (ptd.dw3 & DW3_QTD_ACTIVE) && -				!(ptd.dw3 & DW3_HALT_BIT)) { - -			/* according to ppriv code, we have to -			 * reload this one if trasfered bytes != requested bytes -			 * else act like everything went smooth.. -			 * XXX This just doesn't feel right and hasn't -			 * triggered so far. -			 */ +		list_del(&qtd->qtd_list); +		qtd_free(qtd); +	} +} -			length = PTD_XFERRED_LENGTH(ptd.dw3); -			dev_err(hcd->self.controller, -					"Should reload now... transferred %d " -					"of %zu\n", length, qtd->length); -			BUG(); -		} +#define ENQUEUE_DEPTH	2 +static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) +{ +	struct isp1760_hcd *priv = hcd_to_priv(hcd); +	int ptd_offset; +	struct slotinfo *slots; +	int curr_slot, free_slot; +	int n; +	struct ptd ptd; +	struct isp1760_qtd *qtd; -		if (!nakcount && (ptd.dw3 & DW3_QTD_ACTIVE)) { -			u32 buffstatus; +	if (unlikely(list_empty(&qh->qtd_list))) { +		WARN_ON(1); +		return; +	} -			/* -			 * NAKs are handled in HW by the chip. Usually if the -			 * device is not able to send data fast enough. -			 * This happens mostly on slower hardware. -			 */ +	if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd, +							qtd_list)->urb->pipe)) { +		ptd_offset = INT_PTD_OFFSET; +		slots = priv->int_slots; +	} else { +		ptd_offset = ATL_PTD_OFFSET; +		slots = priv->atl_slots; +	} -			/* RL counter = ERR counter */ -			ptd.dw3 &= ~(0xf << 19); -			ptd.dw3 |= rl << 19; -			ptd.dw3 &= ~(3 << (55 - 32)); -			ptd.dw3 |= ERR_COUNTER << (55 - 32); - -			/* -			 * It is not needed to write skip map back because it -			 * is unchanged. Just make sure that this entry is -			 * unskipped once it gets written to the HW. -			 */ -			skip_map &= ~(1 << slot); -			or_map = reg_read32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG); -			or_map |= 1 << slot; -			reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, or_map); +	free_slot = -1; +	for (curr_slot = 0; curr_slot < 32; curr_slot++) { +		if ((free_slot == -1) && (slots[curr_slot].qtd == NULL)) +			free_slot = curr_slot; +		if (slots[curr_slot].qh == qh) +			break; +	} -			ptd.dw0 |= PTD_VALID; -			ptd_write(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); +	n = 0; +	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { +		if (qtd->status == QTD_ENQUEUED) { +			WARN_ON(qtd->payload_addr); +			alloc_mem(hcd, qtd); +			if ((qtd->length) && (!qtd->payload_addr)) +				break; -			priv->atl_queued++; -			if (priv->atl_queued == 2) -				reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, -						INTERRUPT_ENABLE_SOT_MASK); +			if ((qtd->length) && +			    ((qtd->packet_type == SETUP_PID) || +			     (qtd->packet_type == OUT_PID))) { +				mem_writes8(hcd->regs, qtd->payload_addr, +						qtd->data_buffer, qtd->length); +			} -			buffstatus = reg_read32(hcd->regs, -							HC_BUFFER_STATUS_REG); -			buffstatus |= ATL_BUFFER; -			reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, -								buffstatus); -			continue; +			qtd->status = QTD_PAYLOAD_ALLOC;  		} -		error = check_error(hcd, &ptd); -		if (error) { -			status = error; -			priv->atl_ints[slot].qh->toggle = 0; -			priv->atl_ints[slot].qh->ping = 0; -			qtd->urb->status = -EPIPE; - -#if 0 -			printk(KERN_ERR "Error in %s().\n", __func__); -			printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " -					"dw3: %08x dw4: %08x dw5: %08x dw6: " -					"%08x dw7: %08x\n", -					ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, -					ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); -#endif -		} else { -			priv->atl_ints[slot].qh->toggle = ptd.dw3 & (1 << 25); -			priv->atl_ints[slot].qh->ping = ptd.dw3 & (1 << 26); -		} +		if (qtd->status == QTD_PAYLOAD_ALLOC) { +/* +			if ((curr_slot > 31) && (free_slot == -1)) +				dev_dbg(hcd->self.controller, "%s: No slot " +					"available for transfer\n", __func__); +*/ +			/* Start xfer for this endpoint if not already done */ +			if ((curr_slot > 31) && (free_slot > -1)) { +				if (usb_pipeint(qtd->urb->pipe)) +					create_ptd_int(qh, qtd, &ptd); +				else +					create_ptd_atl(qh, qtd, &ptd); + +				start_bus_transfer(hcd, ptd_offset, free_slot, +							slots, qtd, qh, &ptd); +				curr_slot = free_slot; +			} -		length = PTD_XFERRED_LENGTH(ptd.dw3); -		if (length) { -			switch (DW1_GET_PID(ptd.dw1)) { -			case IN_PID: -				mem_reads8(hcd->regs, qtd->payload_addr, -						qtd->data_buffer, length); +			n++; +			if (n >= ENQUEUE_DEPTH) +				break; +		} +	} +} -			case OUT_PID: +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; + +	if (!hcd) { +		WARN_ON(1); +		return; +	} -				qtd->urb->actual_length += length; +	priv = hcd_to_priv(hcd); -			case SETUP_PID: -				break; +	/* +	 * check finished/retired xfers, transfer payloads, call urb_done() +	 */ +	ep_queue = &priv->interruptqhs; +	while (ep_queue) { +		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)) { +				list_del(&qh->qh_list); +				if (ep->hcpriv == NULL) { +					/* Endpoint has been disabled, so we +					can free the associated queue head. */ +					qh_free(qh); +				}  			}  		} -		priv->atl_ints[slot].qtd = NULL; -		priv->atl_ints[slot].qh = NULL; - -		free_mem(hcd, qtd); +		if (ep_queue == &priv->interruptqhs) +			ep_queue = &priv->controlqhs; +		else if (ep_queue == &priv->controlqhs) +			ep_queue = &priv->bulkqhs; +		else +			ep_queue = NULL; +	} -		reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); +	list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list, +								urb_list) { +		isp1760_urb_done(hcd, urb_listitem->urb); +		kmem_cache_free(urb_listitem_cachep, urb_listitem); +	} -		if (qtd->urb->status == -EPIPE) { -			/* HALT was received */ +	/* +	 * Schedule packets for transfer. +	 * +	 * According to USB2.0 specification: +	 * +	 * 1st prio: interrupt xfers, up to 80 % of bandwidth +	 * 2nd prio: control xfers +	 * 3rd prio: bulk xfers +	 * +	 * ... but let's use a simpler scheme here (mostly because ISP1761 doc +	 * is very unclear on how to prioritize traffic): +	 * +	 * 1) Enqueue any queued control transfers, as long as payload chip mem +	 *    and PTD ATL slots are available. +	 * 2) Enqueue any queued INT transfers, as long as payload chip mem +	 *    and PTD INT slots are available. +	 * 3) Enqueue any queued bulk transfers, as long as payload chip mem +	 *    and PTD ATL slots are available. +	 * +	 * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between +	 * conservation of chip mem and performance. +	 * +	 * I'm sure this scheme could be improved upon! +	 */ +	ep_queue = &priv->controlqhs; +	while (ep_queue) { +		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; +	} +} -			urb = qtd->urb; -			qtd = clean_up_qtdlist(qtd, qh); -			isp1760_urb_done(hcd, urb); +#define PTD_STATE_QTD_DONE	1 +#define PTD_STATE_QTD_RELOAD	2 +#define PTD_STATE_URB_RETIRE	3 -		} else if (usb_pipebulk(qtd->urb->pipe) && -						(length < qtd->length)) { -			/* short BULK received */ +static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd, +								struct urb *urb) +{ +	__dw dw4; +	int i; -			if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK) { -				qtd->urb->status = -EREMOTEIO; -				dev_dbg(hcd->self.controller, -						"short bulk, %d instead %zu " -						"with URB_SHORT_NOT_OK flag.\n", -						length, qtd->length); -			} +	dw4 = ptd->dw4; +	dw4 >>= 8; -			if (qtd->urb->status == -EINPROGRESS) -				qtd->urb->status = 0; +	/* FIXME: ISP1761 datasheet does not say what to do with these. Do we +	   need to handle these errors? Is it done in hardware? */ -			urb = qtd->urb; -			qtd = clean_up_qtdlist(qtd, qh); -			isp1760_urb_done(hcd, urb); +	if (ptd->dw3 & DW3_HALT_BIT) { -		} else if (last_qtd_of_urb(qtd, qh)) { -			/* that was the last qtd of that URB */ +		urb->status = -EPROTO; /* Default unknown error */ -			if (qtd->urb->status == -EINPROGRESS) -				qtd->urb->status = 0; +		for (i = 0; i < 8; i++) { +			switch (dw4 & 0x7) { +			case INT_UNDERRUN: +				dev_dbg(hcd->self.controller, "%s: underrun " +						"during uFrame %d\n", +						__func__, i); +				urb->status = -ECOMM; /* Could not write data */ +				break; +			case INT_EXACT: +				dev_dbg(hcd->self.controller, "%s: transaction " +						"error during uFrame %d\n", +						__func__, i); +				urb->status = -EPROTO; /* timeout, bad CRC, PID +							  error etc. */ +				break; +			case INT_BABBLE: +				dev_dbg(hcd->self.controller, "%s: babble " +						"error during uFrame %d\n", +						__func__, i); +				urb->status = -EOVERFLOW; +				break; +			} +			dw4 >>= 3; +		} -			urb = qtd->urb; -			qtd = clean_up_qtdlist(qtd, qh); -			isp1760_urb_done(hcd, urb); +		return PTD_STATE_URB_RETIRE; +	} -		} else { -			/* next QTD of this URB */ +	return PTD_STATE_QTD_DONE; +} -			qtd = clean_this_qtd(qtd, qh); -			BUG_ON(!qtd); -		} +static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd, +								struct urb *urb) +{ +	WARN_ON(!ptd); +	if (ptd->dw3 & DW3_HALT_BIT) { +		if (ptd->dw3 & DW3_BABBLE_BIT) +			urb->status = -EOVERFLOW; +		else if (FROM_DW3_CERR(ptd->dw3)) +			urb->status = -EPIPE;  /* Stall */ +		else if (ptd->dw3 & DW3_ERROR_BIT) +			urb->status = -EPROTO; /* XactErr */ +		else +			urb->status = -EPROTO; /* Unknown */ +/* +		dev_dbg(hcd->self.controller, "%s: ptd error:\n" +			"        dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n" +			"        dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n", +			__func__, +			ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3, +			ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7); +*/ +		return PTD_STATE_URB_RETIRE; +	} -		if (qtd) -			enqueue_an_ATL_packet(hcd, qh, qtd); +	if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) { +		/* Transfer Error, *but* active and no HALT -> reload */ +		dev_dbg(hcd->self.controller, "PID error; reloading ptd\n"); +		return PTD_STATE_QTD_RELOAD; +	} -		skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); +	if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) { +		/* +		 * NAKs are handled in HW by the chip. Usually if the +		 * device is not able to send data fast enough. +		 * This happens mostly on slower hardware. +		 */ +		return PTD_STATE_QTD_RELOAD;  	} -	if (priv->atl_queued <= 1) -		reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, -							INTERRUPT_ENABLE_MASK); + +	return PTD_STATE_QTD_DONE;  } -static void do_intl_int(struct usb_hcd *hcd) +static irqreturn_t isp1760_irq(struct usb_hcd *hcd)  {  	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	u32 done_map, skip_map; +	u32 imask; +	irqreturn_t irqret = IRQ_NONE;  	struct ptd ptd; -	struct urb *urb; -	u32 length; -	u32 or_map; -	int error; -	u32 slot; -	struct isp1760_qtd *qtd;  	struct isp1760_qh *qh; +	int slot; +	int state; +	struct slotinfo *slots; +	u32 ptd_offset; +	struct isp1760_qtd *qtd; +	int modified; +	static int last_active_ptds; +	int int_skip_map, atl_skip_map; -	done_map = reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG); -	skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); - -	or_map = reg_read32(hcd->regs, HC_INT_IRQ_MASK_OR_REG); -	or_map &= ~done_map; -	reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, or_map); - -	while (done_map) { -		slot = __ffs(done_map); -		done_map &= ~(1 << slot); -		skip_map |= (1 << slot); - -		qtd = priv->int_ints[slot].qtd; -		qh = priv->int_ints[slot].qh; - -		if (!qh) { -			dev_err(hcd->self.controller, "(INT) qh is 0\n"); -			continue; -		} +	spin_lock(&priv->lock); -		ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd); -		check_int_err_status(hcd, ptd.dw4); - -		error = check_error(hcd, &ptd); -		if (error) { -#if 0 -			printk(KERN_ERR "Error in %s().\n", __func__); -			printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " -					"dw3: %08x dw4: %08x dw5: %08x dw6: " -					"%08x dw7: %08x\n", -					ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, -					ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); -#endif -			qtd->urb->status = -EPIPE; -			priv->int_ints[slot].qh->toggle = 0; -			priv->int_ints[slot].qh->ping = 0; +	if (!(hcd->state & HC_STATE_RUNNING)) +		goto leave; +	imask = reg_read32(hcd->regs, HC_INTERRUPT_REG); +	if (unlikely(!imask)) +		goto leave; +	reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */ + +	int_skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); +	atl_skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); +	priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG); +	priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG); +	priv->int_done_map &= ~int_skip_map; +	priv->atl_done_map &= ~atl_skip_map; + +	modified = priv->int_done_map | priv->atl_done_map; + +	while (priv->int_done_map || priv->atl_done_map) { +		if (priv->int_done_map) { +			/* INT ptd */ +			slot = __ffs(priv->int_done_map); +			priv->int_done_map &= ~(1 << slot); +			slots = priv->int_slots; +			/* This should not trigger, and could be removed if +			   noone have any problems with it triggering: */ +			if (!slots[slot].qh) { +				WARN_ON(1); +				continue; +			} +			ptd_offset = INT_PTD_OFFSET; +			ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd); +			state = check_int_transfer(hcd, &ptd, +							slots[slot].qtd->urb);  		} else { -			priv->int_ints[slot].qh->toggle = ptd.dw3 & (1 << 25); -			priv->int_ints[slot].qh->ping = ptd.dw3 & (1 << 26); -		} - -		if (qtd->urb->dev->speed != USB_SPEED_HIGH) -			length = PTD_XFERRED_LENGTH_LO(ptd.dw3); -		else -			length = PTD_XFERRED_LENGTH(ptd.dw3); - -		if (length) { -			switch (DW1_GET_PID(ptd.dw1)) { -			case IN_PID: -				mem_reads8(hcd->regs, qtd->payload_addr, -						qtd->data_buffer, length); -			case OUT_PID: - -				qtd->urb->actual_length += length; - -			case SETUP_PID: -				break; +			/* ATL ptd */ +			slot = __ffs(priv->atl_done_map); +			priv->atl_done_map &= ~(1 << slot); +			slots = priv->atl_slots; +			/* This should not trigger, and could be removed if +			   noone have any problems with it triggering: */ +			if (!slots[slot].qh) { +				WARN_ON(1); +				continue;  			} +			ptd_offset = ATL_PTD_OFFSET; +			ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); +			state = check_atl_transfer(hcd, &ptd, +							slots[slot].qtd->urb);  		} -		priv->int_ints[slot].qtd = NULL; -		priv->int_ints[slot].qh = NULL; - -		reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); -		free_mem(hcd, qtd); - -		if (qtd->urb->status == -EPIPE) { -			/* HALT received */ - -			urb = qtd->urb; -			qtd = clean_up_qtdlist(qtd, qh); -			isp1760_urb_done(hcd, urb); - -		} else if (last_qtd_of_urb(qtd, qh)) { - -			if (qtd->urb->status == -EINPROGRESS) -				qtd->urb->status = 0; +		qtd = slots[slot].qtd; +		slots[slot].qtd = NULL; +		qh = slots[slot].qh; +		slots[slot].qh = NULL; +		priv->active_ptds--; +		qh->slot = -1; + +		WARN_ON(qtd->status != QTD_XFER_STARTED); + +		switch (state) { +		case PTD_STATE_QTD_DONE: +			if ((usb_pipeint(qtd->urb->pipe)) && +				       (qtd->urb->dev->speed != USB_SPEED_HIGH)) +				qtd->actual_length = +				       FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3); +			else +				qtd->actual_length = +					FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3); + +			qtd->status = QTD_XFER_COMPLETE; +			if (list_is_last(&qtd->qtd_list, &qh->qtd_list) || +							is_short_bulk(qtd)) +				qtd = NULL; +			else +				qtd = list_entry(qtd->qtd_list.next, +							typeof(*qtd), qtd_list); + +			qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3); +			qh->ping = FROM_DW3_PING(ptd.dw3); +			break; -			urb = qtd->urb; -			qtd = clean_up_qtdlist(qtd, qh); -			isp1760_urb_done(hcd, urb); +		case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */ +			qtd->status = QTD_PAYLOAD_ALLOC; +			ptd.dw0 |= DW0_VALID_BIT; +			/* RL counter = ERR counter */ +			ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf); +			ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2)); +			ptd.dw3 &= ~TO_DW3_CERR(3); +			ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER); +			qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3); +			qh->ping = FROM_DW3_PING(ptd.dw3); +			break; -		} else { -			/* next QTD of this URB */ +		case PTD_STATE_URB_RETIRE: +			qtd->status = QTD_RETIRE; +			qtd = NULL; +			qh->toggle = 0; +			qh->ping = 0; +			break; -			qtd = clean_this_qtd(qtd, qh); -			BUG_ON(!qtd); +		default: +			WARN_ON(1); +			continue;  		} -		if (qtd) -			enqueue_an_INT_packet(hcd, qh, qtd); +		if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) { +			if (slots == priv->int_slots) { +				if (state == PTD_STATE_QTD_RELOAD) +					dev_err(hcd->self.controller, +						"%s: PTD_STATE_QTD_RELOAD on " +						"interrupt packet\n", __func__); +				if (state != PTD_STATE_QTD_RELOAD) +					create_ptd_int(qh, qtd, &ptd); +			} else { +				if (state != PTD_STATE_QTD_RELOAD) +					create_ptd_atl(qh, qtd, &ptd); +			} -		skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); +			start_bus_transfer(hcd, ptd_offset, slot, slots, qtd, +				qh, &ptd); +		}  	} -} -static struct isp1760_qh *qh_make(struct usb_hcd *hcd, struct urb *urb, -		gfp_t flags) -{ -	struct isp1760_qh *qh; -	int is_input, type; +	if (modified) +		schedule_ptds(hcd); -	qh = isp1760_qh_alloc(flags); -	if (!qh) -		return qh; - -	/* -	 * init endpoint/device data for this QH -	 */ -	is_input = usb_pipein(urb->pipe); -	type = usb_pipetype(urb->pipe); +	/* ISP1760 Errata 2 explains that interrupts may be missed (or not +	   happen?) if two USB devices are running simultaneously. Perhaps +	   this happens when a PTD is finished during interrupt handling; +	   enable SOF interrupts if PTDs are still scheduled when exiting this +	   interrupt handler, just to be safe. */ -	if (!usb_pipecontrol(urb->pipe)) -		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, -				1); -	return qh; -} - -/* - * For control/bulk/interrupt, return QH with these TDs appended. - * Allocates and initializes the QH if necessary. - * Returns null if it can't allocate a QH it needs to. - * If the QH has TDs (urbs) already, that's great. - */ -static struct isp1760_qh *qh_append_tds(struct usb_hcd *hcd, -		struct urb *urb, struct list_head *qtd_list, int epnum, -		void **ptr) -{ -	struct isp1760_qh *qh; - -	qh = (struct isp1760_qh *)*ptr; -	if (!qh) { -		/* can't sleep here, we have priv->lock... */ -		qh = qh_make(hcd, urb, GFP_ATOMIC); -		if (!qh) -			return qh; -		*ptr = qh; +	if (priv->active_ptds != last_active_ptds) { +		if (priv->active_ptds > 0) +			reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, +						INTERRUPT_ENABLE_SOT_MASK); +		else +			reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, +						INTERRUPT_ENABLE_MASK); +		last_active_ptds = priv->active_ptds;  	} -	list_splice(qtd_list, qh->qtd_list.prev); +	irqret = IRQ_HANDLED; +leave: +	spin_unlock(&priv->lock); -	return qh; +	return irqret;  } -static void qtd_list_free(struct urb *urb, struct list_head *qtd_list) +static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)  { -	struct list_head *entry, *temp; +	qtd->data_buffer = databuffer; -	list_for_each_safe(entry, temp, qtd_list) { -		struct isp1760_qtd	*qtd; +	if (len > MAX_PAYLOAD_SIZE) +		len = MAX_PAYLOAD_SIZE; +	qtd->length = len; -		qtd = list_entry(entry, struct isp1760_qtd, qtd_list); -		list_del(&qtd->qtd_list); -		isp1760_qtd_free(qtd); -	} +	return qtd->length;  } -static int isp1760_prepare_enqueue(struct usb_hcd *hcd, struct urb *urb, -		struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p) +static void qtd_list_free(struct list_head *qtd_list)  { -	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	struct isp1760_qtd         *qtd; -	int                     epnum; -	unsigned long           flags; -	struct isp1760_qh          *qh = NULL; -	int                     rc; -	int qh_busy; - -	qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list); -	epnum = urb->ep->desc.bEndpointAddress; - -	spin_lock_irqsave(&priv->lock, flags); -	if (!HCD_HW_ACCESSIBLE(hcd)) { -		rc = -ESHUTDOWN; -		goto done; -	} -	rc = usb_hcd_link_urb_to_ep(hcd, urb); -	if (rc) -		goto done; - -	qh = urb->ep->hcpriv; -	if (qh) -		qh_busy = !list_empty(&qh->qtd_list); -	else -		qh_busy = 0; +	struct isp1760_qtd *qtd, *qtd_next; -	qh = qh_append_tds(hcd, urb, qtd_list, epnum, &urb->ep->hcpriv); -	if (!qh) { -		usb_hcd_unlink_urb_from_ep(hcd, urb); -		rc = -ENOMEM; -		goto done; +	list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) { +		list_del(&qtd->qtd_list); +		qtd_free(qtd);  	} - -	if (!qh_busy) -		p(hcd, qh, qtd); - -done: -	spin_unlock_irqrestore(&priv->lock, flags); -	if (!qh) -		qtd_list_free(urb, qtd_list); -	return rc; -} - -static struct isp1760_qtd *isp1760_qtd_alloc(gfp_t flags) -{ -	struct isp1760_qtd *qtd; - -	qtd = kmem_cache_zalloc(qtd_cachep, flags); -	if (qtd) -		INIT_LIST_HEAD(&qtd->qtd_list); - -	return qtd;  }  /* - * create a list of filled qtds for this URB; won't link into qh. + * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize. + * Also calculate the PID type (SETUP/IN/OUT) for each packet.   */  #define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) -static struct list_head *qh_urb_transaction(struct usb_hcd *hcd, +static void packetize_urb(struct usb_hcd *hcd,  		struct urb *urb, struct list_head *head, gfp_t flags)  {  	struct isp1760_qtd *qtd;  	void *buf; -	int len, maxpacket; -	int is_input; -	u32 token; +	int len, maxpacketsize; +	u8 packet_type;  	/*  	 * URBs map to sequences of QTDs:  one logical transaction  	 */ -	qtd = isp1760_qtd_alloc(flags); -	if (!qtd) -		return NULL; -	list_add_tail(&qtd->qtd_list, head); -	qtd->urb = urb; -	urb->status = -EINPROGRESS; +	if (!urb->transfer_buffer && urb->transfer_buffer_length) { +		/* XXX This looks like usb storage / SCSI bug */ +		dev_err(hcd->self.controller, +				"buf is null, dma is %08lx len is %d\n", +				(long unsigned)urb->transfer_dma, +				urb->transfer_buffer_length); +		WARN_ON(1); +	} -	token = 0; -	/* for split transactions, SplitXState initialized to zero */ +	if (usb_pipein(urb->pipe)) +		packet_type = IN_PID; +	else +		packet_type = OUT_PID; -	len = urb->transfer_buffer_length; -	is_input = usb_pipein(urb->pipe);  	if (usb_pipecontrol(urb->pipe)) { -		/* SETUP pid */ -		qtd_fill(qtd, urb->setup_packet, -				sizeof(struct usb_ctrlrequest), -				token | SETUP_PID); - -		/* ... and always at least one more pid */ -		qtd = isp1760_qtd_alloc(flags); +		qtd = qtd_alloc(flags, urb, SETUP_PID);  		if (!qtd)  			goto cleanup; -		qtd->urb = urb; +		qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest));  		list_add_tail(&qtd->qtd_list, head);  		/* for zero length DATA stages, STATUS is always IN */ -		if (len == 0) -			token |= IN_PID; +		if (urb->transfer_buffer_length == 0) +			packet_type = IN_PID;  	} -	/* -	 * data transfer stage:  buffer setup -	 */ -	buf = urb->transfer_buffer; - -	if (is_input) -		token |= IN_PID; -	else -		token |= OUT_PID; - -	maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); +	maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe, +						usb_pipeout(urb->pipe)));  	/*  	 * buffer gets wrapped in one or more qtds;  	 * last one may be "short" (including zero len)  	 * and may serve as a control status ack  	 */ +	buf = urb->transfer_buffer; +	len = urb->transfer_buffer_length; +  	for (;;) {  		int this_qtd_len; -		if (!buf && len) { -			/* XXX This looks like usb storage / SCSI bug */ -			dev_err(hcd->self.controller, "buf is null, dma is %08lx len is %d\n", -					(long unsigned)urb->transfer_dma, len); -			WARN_ON(1); -		} +		qtd = qtd_alloc(flags, urb, packet_type); +		if (!qtd) +			goto cleanup; +		this_qtd_len = qtd_fill(qtd, buf, len); +		list_add_tail(&qtd->qtd_list, head); -		this_qtd_len = qtd_fill(qtd, buf, len, token);  		len -= this_qtd_len;  		buf += this_qtd_len;  		if (len <= 0)  			break; - -		qtd = isp1760_qtd_alloc(flags); -		if (!qtd) -			goto cleanup; -		qtd->urb = urb; -		list_add_tail(&qtd->qtd_list, head);  	}  	/* @@ -1510,184 +1435,204 @@ static struct list_head *qh_urb_transaction(struct usb_hcd *hcd,  		if (usb_pipecontrol(urb->pipe)) {  			one_more = 1; -			/* "in" <--> "out"  */ -			token ^= IN_PID; +			if (packet_type == IN_PID) +				packet_type = OUT_PID; +			else +				packet_type = IN_PID;  		} else if (usb_pipebulk(urb->pipe)  				&& (urb->transfer_flags & URB_ZERO_PACKET) -				&& !(urb->transfer_buffer_length % maxpacket)) { +				&& !(urb->transfer_buffer_length % +							maxpacketsize)) {  			one_more = 1;  		}  		if (one_more) { -			qtd = isp1760_qtd_alloc(flags); +			qtd = qtd_alloc(flags, urb, packet_type);  			if (!qtd)  				goto cleanup; -			qtd->urb = urb; -			list_add_tail(&qtd->qtd_list, head);  			/* never any data in such packets */ -			qtd_fill(qtd, NULL, 0, token); +			qtd_fill(qtd, NULL, 0); +			list_add_tail(&qtd->qtd_list, head);  		}  	} -	qtd->status = 0; -	return head; +	return;  cleanup: -	qtd_list_free(urb, head); -	return NULL; +	qtd_list_free(head);  }  static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,  		gfp_t mem_flags)  { -	struct list_head qtd_list; -	packet_enqueue *pe; - -	INIT_LIST_HEAD(&qtd_list); +	struct isp1760_hcd *priv = hcd_to_priv(hcd); +	struct list_head *ep_queue; +	struct isp1760_qh *qh, *qhit; +	unsigned long spinflags; +	LIST_HEAD(new_qtds); +	int retval; +	int qh_in_queue;  	switch (usb_pipetype(urb->pipe)) {  	case PIPE_CONTROL: +		ep_queue = &priv->controlqhs; +		break;  	case PIPE_BULK: -		if (!qh_urb_transaction(hcd, urb, &qtd_list, mem_flags)) -			return -ENOMEM; -		pe =  enqueue_an_ATL_packet; +		ep_queue = &priv->bulkqhs;  		break; -  	case PIPE_INTERRUPT: -		if (!qh_urb_transaction(hcd, urb, &qtd_list, mem_flags)) -			return -ENOMEM; -		pe = enqueue_an_INT_packet; +		if (urb->interval < 0) +			return -EINVAL; +		/* FIXME: Check bandwidth  */ +		ep_queue = &priv->interruptqhs;  		break; -  	case PIPE_ISOCHRONOUS: -		dev_err(hcd->self.controller, "PIPE_ISOCHRONOUS ain't supported\n"); +		dev_err(hcd->self.controller, "%s: isochronous USB packets " +							"not yet supported\n", +							__func__); +		return -EPIPE;  	default: +		dev_err(hcd->self.controller, "%s: unknown pipe type\n", +							__func__);  		return -EPIPE;  	} -	return isp1760_prepare_enqueue(hcd, urb, &qtd_list, mem_flags, pe); -} - -static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ -	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	struct inter_packet_info *ints; -	u32 i; -	u32 reg_base, or_reg, skip_reg; -	unsigned long flags; -	struct ptd ptd; -	packet_enqueue *pe; +	if (usb_pipein(urb->pipe)) +		urb->actual_length = 0; -	switch (usb_pipetype(urb->pipe)) { -	case PIPE_ISOCHRONOUS: -		return -EPIPE; -		break; +	packetize_urb(hcd, urb, &new_qtds, mem_flags); +	if (list_empty(&new_qtds)) +		return -ENOMEM; +	urb->hcpriv = NULL; /* Used to signal unlink to interrupt handler */ -	case PIPE_INTERRUPT: -		ints = priv->int_ints; -		reg_base = INT_PTD_OFFSET; -		or_reg = HC_INT_IRQ_MASK_OR_REG; -		skip_reg = HC_INT_PTD_SKIPMAP_REG; -		pe = enqueue_an_INT_packet; -		break; +	retval = 0; +	spin_lock_irqsave(&priv->lock, spinflags); -	default: -		ints = priv->atl_ints; -		reg_base = ATL_PTD_OFFSET; -		or_reg = HC_ATL_IRQ_MASK_OR_REG; -		skip_reg = HC_ATL_PTD_SKIPMAP_REG; -		pe =  enqueue_an_ATL_packet; -		break; +	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { +		retval = -ESHUTDOWN; +		goto out;  	} +	retval = usb_hcd_link_urb_to_ep(hcd, urb); +	if (retval) +		goto out; -	memset(&ptd, 0, sizeof(ptd)); -	spin_lock_irqsave(&priv->lock, flags); - -	for (i = 0; i < 32; i++) { -		if (!ints[i].qh) -			continue; -		BUG_ON(!ints[i].qtd); +	qh = urb->ep->hcpriv; +	if (qh) { +		qh_in_queue = 0; +		list_for_each_entry(qhit, ep_queue, qh_list) { +			if (qhit == qh) { +				qh_in_queue = 1; +				break; +			} +		} +		if (!qh_in_queue) +			list_add_tail(&qh->qh_list, ep_queue); +	} else { +		qh = qh_alloc(GFP_ATOMIC); +		if (!qh) { +			retval = -ENOMEM; +			goto out; +		} +		list_add_tail(&qh->qh_list, ep_queue); +		urb->ep->hcpriv = qh; +	} -		if (ints[i].qtd->urb == urb) { -			u32 skip_map; -			u32 or_map; -			struct isp1760_qtd *qtd; -			struct isp1760_qh *qh; +	list_splice_tail(&new_qtds, &qh->qtd_list); +	schedule_ptds(hcd); -			skip_map = reg_read32(hcd->regs, skip_reg); -			skip_map |= 1 << i; -			reg_write32(hcd->regs, skip_reg, skip_map); +out: +	spin_unlock_irqrestore(&priv->lock, spinflags); +	return retval; +} -			or_map = reg_read32(hcd->regs, or_reg); -			or_map &= ~(1 << i); -			reg_write32(hcd->regs, or_reg, or_map); +static void kill_transfer(struct usb_hcd *hcd, struct urb *urb, +		struct isp1760_qh *qh) +{ +	struct isp1760_hcd *priv = hcd_to_priv(hcd); +	int skip_map; -			ptd_write(hcd->regs, reg_base, i, &ptd); +	WARN_ON(qh->slot == -1); -			qtd = ints[i].qtd; -			qh = ints[i].qh; +	/* We need to forcefully reclaim the slot since some transfers never +	   return, e.g. interrupt transfers and NAKed bulk transfers. */ +	if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) { +		skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); +		skip_map |= (1 << qh->slot); +		reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); +		priv->atl_slots[qh->slot].qh = NULL; +		priv->atl_slots[qh->slot].qtd = NULL; +	} else { +		skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); +		skip_map |= (1 << qh->slot); +		reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); +		priv->int_slots[qh->slot].qh = NULL; +		priv->int_slots[qh->slot].qtd = NULL; +	} -			free_mem(hcd, qtd); -			qtd = clean_up_qtdlist(qtd, qh); +	qh->slot = -1; +	priv->active_ptds--; +} -			ints[i].qh = NULL; -			ints[i].qtd = NULL; +static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, +		int status) +{ +	struct isp1760_hcd *priv = hcd_to_priv(hcd); +	unsigned long spinflags; +	struct isp1760_qh *qh; +	struct isp1760_qtd *qtd; +	int retval = 0; -			urb->status = status; -			isp1760_urb_done(hcd, urb); -			if (qtd) -				pe(hcd, qh, qtd); -			break; +	spin_lock_irqsave(&priv->lock, spinflags); -		} else { -			struct isp1760_qtd *qtd; - -			list_for_each_entry(qtd, &ints[i].qtd->qtd_list, -								qtd_list) { -				if (qtd->urb == urb) { -					clean_up_qtdlist(qtd, ints[i].qh); -					isp1760_urb_done(hcd, urb); -					qtd = NULL; -					break; -				} -			} +	qh = urb->ep->hcpriv; +	if (!qh) { +		retval = -EINVAL; +		goto out; +	} -			/* We found the urb before the last slot */ -			if (!qtd) -				break; +	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) +		if (qtd->urb == urb) { +			if (qtd->status == QTD_XFER_STARTED) +				kill_transfer(hcd, urb, qh); +			qtd->status = QTD_RETIRE;  		} -	} -	spin_unlock_irqrestore(&priv->lock, flags); -	return 0; +	urb->status = status; +	schedule_ptds(hcd); + +out: +	spin_unlock_irqrestore(&priv->lock, spinflags); +	return retval;  } -static irqreturn_t isp1760_irq(struct usb_hcd *hcd) +static void isp1760_endpoint_disable(struct usb_hcd *hcd, +		struct usb_host_endpoint *ep)  {  	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	u32 imask; -	irqreturn_t irqret = IRQ_NONE; +	unsigned long spinflags; +	struct isp1760_qh *qh; +	struct isp1760_qtd *qtd; -	spin_lock(&priv->lock); +	spin_lock_irqsave(&priv->lock, spinflags); -	if (!(hcd->state & HC_STATE_RUNNING)) -		goto leave; +	qh = ep->hcpriv; +	if (!qh) +		goto out; -	imask = reg_read32(hcd->regs, HC_INTERRUPT_REG); -	if (unlikely(!imask)) -		goto leave; +	list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { +		if (qtd->status == QTD_XFER_STARTED) +			kill_transfer(hcd, qtd->urb, qh); +		qtd->status = QTD_RETIRE; +		qtd->urb->status = -ECONNRESET; +	} -	reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); -	if (imask & (HC_ATL_INT | HC_SOT_INT)) -		do_atl_int(hcd); +	ep->hcpriv = NULL; +	/* Cannot free qh here since it will be parsed by schedule_ptds() */ -	if (imask & HC_INTL_INT) -		do_intl_int(hcd); +	schedule_ptds(hcd); -	irqret = IRQ_HANDLED; -leave: -	spin_unlock(&priv->lock); -	return irqret; +out: +	spin_unlock_irqrestore(&priv->lock, spinflags);  }  static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) @@ -1778,7 +1723,7 @@ static int check_reset_complete(struct usb_hcd *hcd, int index,  	/* if reset finished and it's still not enabled -- handoff */  	if (!(port_status & PORT_PE)) { -		dev_err(hcd->self.controller, +		dev_info(hcd->self.controller,  					"port %d full speed --> companion\n",  					index + 1); @@ -1787,7 +1732,7 @@ static int check_reset_complete(struct usb_hcd *hcd, int index,  		reg_write32(hcd->regs, HC_PORTSC1, port_status);  	} else -		dev_err(hcd->self.controller, "port %d high speed\n", +		dev_info(hcd->self.controller, "port %d high speed\n",  								index + 1);  	return port_status; @@ -2059,51 +2004,6 @@ error:  	return retval;  } -static void isp1760_endpoint_disable(struct usb_hcd *hcd, -		struct usb_host_endpoint *ep) -{ -	struct isp1760_hcd *priv = hcd_to_priv(hcd); -	struct isp1760_qh *qh; -	struct isp1760_qtd *qtd; -	unsigned long flags; - -	spin_lock_irqsave(&priv->lock, flags); -	qh = ep->hcpriv; -	if (!qh) -		goto out; - -	ep->hcpriv = NULL; -	do { -		/* more than entry might get removed */ -		if (list_empty(&qh->qtd_list)) -			break; - -		qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd, -				qtd_list); - -		if (qtd->status & URB_ENQUEUED) { -			spin_unlock_irqrestore(&priv->lock, flags); -			isp1760_urb_dequeue(hcd, qtd->urb, -ECONNRESET); -			spin_lock_irqsave(&priv->lock, flags); -		} else { -			struct urb *urb; - -			urb = qtd->urb; -			clean_up_qtdlist(qtd, qh); -			urb->status = -ECONNRESET; -			isp1760_urb_done(hcd, urb); -		} -	} while (1); - -	qh_destroy(qh); -	/* remove requests and leak them. -	 * ATL are pretty fast done, INT could take a while... -	 * The latter shoule be removed -	 */ -out: -	spin_unlock_irqrestore(&priv->lock, flags); -} -  static int isp1760_get_frame(struct usb_hcd *hcd)  {  	struct isp1760_hcd *priv = hcd_to_priv(hcd); @@ -2165,6 +2065,13 @@ static const struct hc_driver isp1760_hc_driver = {  int __init init_kmem_once(void)  { +	urb_listitem_cachep = kmem_cache_create("isp1760 urb_listitem", +			sizeof(struct urb_listitem), 0, SLAB_TEMPORARY | +			SLAB_MEM_SPREAD, NULL); + +	if (!urb_listitem_cachep) +		return -ENOMEM; +  	qtd_cachep = kmem_cache_create("isp1760_qtd",  			sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |  			SLAB_MEM_SPREAD, NULL); @@ -2187,6 +2094,7 @@ void deinit_kmem_cache(void)  {  	kmem_cache_destroy(qtd_cachep);  	kmem_cache_destroy(qh_cachep); +	kmem_cache_destroy(urb_listitem_cachep);  }  struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, |