diff options
Diffstat (limited to 'drivers/usb/host/isp1760-hcd.c')
| -rw-r--r-- | drivers/usb/host/isp1760-hcd.c | 2557 |
1 files changed, 1245 insertions, 1312 deletions
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index bdba8c5d844..51a0ae9cdd1 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -8,6 +8,8 @@ * * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> * + * (c) 2011 Arvid Brodin <arvid.brodin@enea.com> + * */ #include <linux/module.h> #include <linux/kernel.h> @@ -19,20 +21,33 @@ #include <linux/uaccess.h> #include <linux/io.h> #include <linux/mm.h> +#include <linux/timer.h> #include <asm/unaligned.h> #include <asm/cacheflush.h> +#include <linux/gpio.h> #include "isp1760-hcd.h" 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; - 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]; + struct list_head qh_list[QH_END]; /* periodic schedule support */ #define DEFAULT_I_TDPS 1024 @@ -41,16 +56,14 @@ struct isp1760_hcd { unsigned long reset_done; unsigned long next_statechange; unsigned int devflags; + + int rst_gpio; }; static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) { return (struct isp1760_hcd *) (hcd->hcd_priv); } -static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv) -{ - return container_of((void *) priv, struct usb_hcd, hcd_priv); -} /* Section 2.2 Host Controller Capability Registers */ #define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ @@ -80,217 +93,271 @@ static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv) #define PORT_RWC_BITS (PORT_CSC) struct isp1760_qtd { - struct isp1760_qtd *hw_next; u8 packet_type; - u8 toggle; - void *data_buffer; + u32 payload_addr; + /* the rest is HCD-private */ 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_COMPLETE_NOTIFY (1 << 0) -#define URB_ENQUEUED (1 << 1) -#define URB_TYPE_ATL (1 << 2) -#define URB_TYPE_INT (1 << 3) }; +/* 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; - struct isp1760_hcd *priv; - - /* periodic schedule info */ - unsigned short period; /* polling interval */ - struct usb_device *dev; - u32 toggle; u32 ping; + int slot; + int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */ }; -#define ehci_port_speed(priv, portsc) USB_PORT_STAT_HIGH_SPEED +struct urb_listitem { + struct list_head urb_list; + struct urb *urb; +}; -static unsigned int isp1760_readl(__u32 __iomem *regs) +/* + * Access functions for isp176x registers (addresses 0..0x03FF). + */ +static u32 reg_read32(void __iomem *base, u32 reg) { - return readl(regs); + return readl(base + reg); } -static void isp1760_writel(const unsigned int val, __u32 __iomem *regs) +static void reg_write32(void __iomem *base, u32 reg, u32 val) { - writel(val, regs); + writel(val, base + reg); } /* - * The next two copy via MMIO data to/from the device. memcpy_{to|from}io() + * Access functions for isp176x memory (offset >= 0x0400). + * + * bank_reads8() reads memory locations prefetched by an earlier write to + * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi- + * bank optimizations, you should use the more generic mem_reads8() below. + * + * For access to ptd memory, use the specialized ptd_read() and ptd_write() + * below. + * + * These functions copy via MMIO data to/from the device. memcpy_{to|from}io() * doesn't quite work because some people have to enforce 32-bit access */ -static void priv_read_copy(struct isp1760_hcd *priv, u32 *src, - __u32 __iomem *dst, u32 len) +static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr, + __u32 *dst, u32 bytes) { + __u32 __iomem *src; u32 val; - u8 *buff8; + __u8 *src_byteptr; + __u8 *dst_byteptr; - if (!src) { - printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len); - return; - } + src = src_base + (bank_addr | src_offset); - while (len >= 4) { - *src = __raw_readl(dst); - len -= 4; - src++; - dst++; + if (src_offset < PAYLOAD_OFFSET) { + while (bytes >= 4) { + *dst = le32_to_cpu(__raw_readl(src)); + bytes -= 4; + src++; + dst++; + } + } else { + while (bytes >= 4) { + *dst = __raw_readl(src); + bytes -= 4; + src++; + dst++; + } } - if (!len) + if (!bytes) return; /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully * allocated. */ - val = isp1760_readl(dst); - - buff8 = (u8 *)src; - while (len) { - - *buff8 = val; - val >>= 8; - len--; - buff8++; + if (src_offset < PAYLOAD_OFFSET) + val = le32_to_cpu(__raw_readl(src)); + else + val = __raw_readl(src); + + dst_byteptr = (void *) dst; + src_byteptr = (void *) &val; + while (bytes > 0) { + *dst_byteptr = *src_byteptr; + dst_byteptr++; + src_byteptr++; + bytes--; } } -static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src, - __u32 __iomem *dst, u32 len) +static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst, + u32 bytes) { - while (len >= 4) { - __raw_writel(*src, dst); - len -= 4; - src++; - dst++; + reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0)); + ndelay(90); + bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes); +} + +static void mem_writes8(void __iomem *dst_base, u32 dst_offset, + __u32 const *src, u32 bytes) +{ + __u32 __iomem *dst; + + dst = dst_base + dst_offset; + + if (dst_offset < PAYLOAD_OFFSET) { + while (bytes >= 4) { + __raw_writel(cpu_to_le32(*src), dst); + bytes -= 4; + src++; + dst++; + } + } else { + while (bytes >= 4) { + __raw_writel(*src, dst); + bytes -= 4; + src++; + dst++; + } } - if (!len) + if (!bytes) return; - /* in case we have 3, 2 or 1 by left. The buffer is allocated and the - * extra bytes should not be read by the HW + /* in case we have 3, 2 or 1 bytes left. The buffer is allocated and the + * extra bytes should not be read by the HW. */ - __raw_writel(*src, dst); + if (dst_offset < PAYLOAD_OFFSET) + __raw_writel(cpu_to_le32(*src), dst); + else + __raw_writel(*src, dst); +} + +/* + * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET, + * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32. + */ +static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot, + struct ptd *ptd) +{ + reg_write32(base, HC_MEMORY_REG, + ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd)); + ndelay(90); + bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0), + (void *) ptd, sizeof(*ptd)); +} + +static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot, + struct ptd *ptd) +{ + mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0), + &ptd->dw1, 7*sizeof(ptd->dw1)); + /* Make sure dw0 gets written last (after other dw's and after payload) + since it contains the enable bit */ + wmb(); + mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0, + sizeof(ptd->dw0)); } + /* memory management of the 60kb on the chip from 0x1000 to 0xffff */ static void init_memory(struct isp1760_hcd *priv) { - int i; - u32 payload; + int i, curr; + u32 payload_addr; - payload = 0x1000; + payload_addr = PAYLOAD_OFFSET; for (i = 0; i < BLOCK_1_NUM; i++) { - priv->memory_pool[i].start = payload; + priv->memory_pool[i].start = payload_addr; priv->memory_pool[i].size = BLOCK_1_SIZE; priv->memory_pool[i].free = 1; - payload += priv->memory_pool[i].size; + payload_addr += priv->memory_pool[i].size; } - - for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) { - priv->memory_pool[i].start = payload; - priv->memory_pool[i].size = BLOCK_2_SIZE; - priv->memory_pool[i].free = 1; - payload += priv->memory_pool[i].size; + curr = i; + for (i = 0; i < BLOCK_2_NUM; i++) { + priv->memory_pool[curr + i].start = payload_addr; + priv->memory_pool[curr + i].size = BLOCK_2_SIZE; + priv->memory_pool[curr + i].free = 1; + payload_addr += priv->memory_pool[curr + i].size; } - - for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) { - priv->memory_pool[i].start = payload; - priv->memory_pool[i].size = BLOCK_3_SIZE; - priv->memory_pool[i].free = 1; - payload += priv->memory_pool[i].size; + curr = i; + for (i = 0; i < BLOCK_3_NUM; i++) { + priv->memory_pool[curr + i].start = payload_addr; + priv->memory_pool[curr + i].size = BLOCK_3_SIZE; + priv->memory_pool[curr + i].free = 1; + payload_addr += priv->memory_pool[curr + i].size; } - BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE); + WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE); } -static u32 alloc_mem(struct isp1760_hcd *priv, u32 size) +static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) { + struct isp1760_hcd *priv = hcd_to_priv(hcd); int i; - if (!size) - return ISP1760_NULL_POINTER; + WARN_ON(qtd->payload_addr); + + if (!qtd->length) + return; for (i = 0; i < BLOCKS; i++) { - if (priv->memory_pool[i].size >= size && + if (priv->memory_pool[i].size >= qtd->length && priv->memory_pool[i].free) { - priv->memory_pool[i].free = 0; - return priv->memory_pool[i].start; + qtd->payload_addr = priv->memory_pool[i].start; + return; } } - - printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n", - size); - printk(KERN_ERR "Current memory map:\n"); - for (i = 0; i < BLOCKS; i++) { - printk(KERN_ERR "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 0; } -static void free_mem(struct isp1760_hcd *priv, u32 mem) +static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) { + struct isp1760_hcd *priv = hcd_to_priv(hcd); int i; - if (mem == ISP1760_NULL_POINTER) + if (!qtd->payload_addr) return; for (i = 0; i < BLOCKS; i++) { - if (priv->memory_pool[i].start == mem) { - - BUG_ON(priv->memory_pool[i].free); - + if (priv->memory_pool[i].start == qtd->payload_addr) { + WARN_ON(priv->memory_pool[i].free); priv->memory_pool[i].free = 1; - return ; + qtd->payload_addr = 0; + return; } } - printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n", - mem); - BUG(); + dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n", + __func__, qtd->payload_addr); + WARN_ON(1); + qtd->payload_addr = 0; } -static void isp1760_init_regs(struct usb_hcd *hcd) -{ - isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG); - isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + - HC_ATL_PTD_SKIPMAP_REG); - isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + - HC_INT_PTD_SKIPMAP_REG); - isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + - HC_ISO_PTD_SKIPMAP_REG); - - isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + - HC_ATL_PTD_DONEMAP_REG); - isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + - HC_INT_PTD_DONEMAP_REG); - isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + - HC_ISO_PTD_DONEMAP_REG); -} - -static int handshake(struct isp1760_hcd *priv, void __iomem *ptr, +static int handshake(struct usb_hcd *hcd, u32 reg, u32 mask, u32 done, int usec) { u32 result; do { - result = isp1760_readl(ptr); + result = reg_read32(hcd->regs, reg); if (result == ~0) return -ENODEV; result &= mask; @@ -303,57 +370,56 @@ static int handshake(struct isp1760_hcd *priv, void __iomem *ptr, } /* reset a non-running (STS_HALT == 1) controller */ -static int ehci_reset(struct isp1760_hcd *priv) +static int ehci_reset(struct usb_hcd *hcd) { int retval; - struct usb_hcd *hcd = priv_to_hcd(priv); - u32 command = isp1760_readl(hcd->regs + HC_USBCMD); + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + u32 command = reg_read32(hcd->regs, HC_USBCMD); command |= CMD_RESET; - isp1760_writel(command, hcd->regs + HC_USBCMD); + reg_write32(hcd->regs, HC_USBCMD, command); hcd->state = HC_STATE_HALT; priv->next_statechange = jiffies; - retval = handshake(priv, hcd->regs + HC_USBCMD, + retval = handshake(hcd, HC_USBCMD, CMD_RESET, 0, 250 * 1000); 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(struct isp1760_hcd *priv, - 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->priv = priv; + 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) { struct isp1760_hcd *priv = hcd_to_priv(hcd); u32 hcc_params; + int i; spin_lock_init(&priv->lock); + for (i = 0; i < QH_END; i++) + INIT_LIST_HEAD(&priv->qh_list[i]); + /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -361,7 +427,7 @@ static int priv_init(struct usb_hcd *hcd) priv->periodic_size = DEFAULT_I_TDPS; /* controllers may cache some of the periodic schedule ... */ - hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS); + hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS); /* full frame cache */ if (HCC_ISOC_CACHE(hcc_params)) priv->i_thresh = 8; @@ -377,6 +443,18 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) int result; u32 scratch, hwmode; + /* low-level chip reset */ + if (gpio_is_valid(priv->rst_gpio)) { + unsigned int rst_lvl; + + rst_lvl = (priv->devflags & + ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0; + + gpio_set_value(priv->rst_gpio, rst_lvl); + mdelay(50); + gpio_set_value(priv->rst_gpio, !rst_lvl); + } + /* Setup HW Mode Control: This assumes a level active-low interrupt */ hwmode = HW_DATA_BUS_32BIT; @@ -398,46 +476,48 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) * Write it twice to ensure correct upper bits if switching * to 16-bit mode. */ - isp1760_writel(hwmode, hcd->regs + HC_HW_MODE_CTRL); - isp1760_writel(hwmode, hcd->regs + HC_HW_MODE_CTRL); + reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); + reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); - isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG); + reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe); /* Change bus pattern */ - scratch = isp1760_readl(hcd->regs + HC_CHIP_ID_REG); - scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG); + scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG); + scratch = reg_read32(hcd->regs, HC_SCRATCH_REG); if (scratch != 0xdeadbabe) { - printk(KERN_ERR "ISP1760: Scratch test failed.\n"); + dev_err(hcd->self.controller, "Scratch test failed.\n"); return -ENODEV; } /* 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 */ - isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG); + reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL); mdelay(100); - isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG); + reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_HC); mdelay(100); - result = ehci_reset(priv); + result = ehci_reset(hcd); if (result) return result; /* Step 11 passed */ - isp1760_info(priv, "bus width: %d, oc: %s\n", + dev_info(hcd->self.controller, "bus width: %d, oc: %s\n", (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ? 16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ? "analog" : "digital"); /* ATL reset */ - isp1760_writel(hwmode | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL); + reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET); mdelay(10); - isp1760_writel(hwmode, hcd->regs + HC_HW_MODE_CTRL); + reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); - isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG); - isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE); + reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK); /* * PORT 1 Control register of the ISP1760 is the OTG control @@ -445,1149 +525,958 @@ static int isp1760_hc_setup(struct usb_hcd *hcd) * support in this driver, we use port 1 as a "normal" USB host port on * both chips. */ - isp1760_writel(PORT1_POWER | PORT1_INIT2, - hcd->regs + HC_PORT1_CTRL); + reg_write32(hcd->regs, HC_PORT1_CTRL, PORT1_POWER | PORT1_INIT2); mdelay(10); - priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS); + priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS); return priv_init(hcd); } -static void isp1760_init_maps(struct usb_hcd *hcd) -{ - /*set last maps, for iso its only 1, else 32 tds bitmap*/ - isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG); - isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG); - isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG); -} - -static void isp1760_enable_interrupts(struct usb_hcd *hcd) +static u32 base_to_chip(u32 base) { - isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG); - isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); - isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG); - isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG); - isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG); - isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG); - /* step 23 passed */ + return ((base - 0x400) >> 3); } -static int isp1760_run(struct usb_hcd *hcd) +static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh) { - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int retval; - u32 temp; - u32 command; - u32 chipid; - - hcd->uses_new_polling = 1; - - hcd->state = HC_STATE_RUNNING; - isp1760_enable_interrupts(hcd); - temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); - isp1760_writel(temp | HW_GLOBAL_INTR_EN, hcd->regs + HC_HW_MODE_CTRL); - - command = isp1760_readl(hcd->regs + HC_USBCMD); - command &= ~(CMD_LRESET|CMD_RESET); - command |= CMD_RUN; - isp1760_writel(command, hcd->regs + HC_USBCMD); - - retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN, - 250 * 1000); - if (retval) - return retval; - - /* - * XXX - * Spec says to write FLAG_CF as last config action, priv code grabs - * the semaphore while doing so. - */ - down_write(&ehci_cf_port_reset_rwsem); - isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG); - - retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF, - 250 * 1000); - up_write(&ehci_cf_port_reset_rwsem); - if (retval) - return retval; - - chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG); - isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff, - chipid >> 16); + struct urb *urb; - /* PTD Register Init Part 2, Step 28 */ - /* enable INTs */ - isp1760_init_maps(hcd); + if (list_is_last(&qtd->qtd_list, &qh->qtd_list)) + return 1; - /* GRR this is run-once init(), being done every time the HC starts. - * So long as they're part of class devices, we can't do it init() - * since the class device isn't created that early. - */ - return 0; + urb = qtd->urb; + qtd = list_entry(qtd->qtd_list.next, typeof(*qtd), qtd_list); + return (qtd->urb != urb); } -static u32 base_to_chip(u32 base) -{ - return ((base - 0x400) >> 3); -} +/* 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 transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh, - struct isp1760_qtd *qtd, struct urb *urb, - u32 payload, struct ptd *ptd) +static void create_ptd_atl(struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct ptd *ptd) { - u32 dw0; - u32 dw1; - u32 dw2; - u32 dw3; u32 maxpacket; u32 multi; - u32 pid_code; u32 rl = RL_COUNTER; u32 nak = NAK_COUNTER; + memset(ptd, 0, sizeof(*ptd)); + /* according to 3.6.2, max packet len can not be > 0x400 */ - maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe, + usb_pipeout(qtd->urb->pipe)); multi = 1 + ((maxpacket >> 11) & 0x3); maxpacket &= 0x7ff; /* DW0 */ - dw0 = PTD_VALID; - dw0 |= PTD_LENGTH(qtd->length); - dw0 |= PTD_MAXPACKET(maxpacket); - dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe)); - dw1 = usb_pipeendpoint(urb->pipe) >> 1; + 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 */ - dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe)); + ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1; + ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe)); + ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type); - pid_code = qtd->packet_type; - dw1 |= PTD_PID_TOKEN(pid_code); + if (usb_pipebulk(qtd->urb->pipe)) + ptd->dw1 |= DW1_TRANS_BULK; + else if (usb_pipeint(qtd->urb->pipe)) + ptd->dw1 |= DW1_TRANS_INT; - if (usb_pipebulk(urb->pipe)) - dw1 |= PTD_TRANS_BULK; - else if (usb_pipeint(urb->pipe)) - dw1 |= PTD_TRANS_INT; - - if (urb->dev->speed != USB_SPEED_HIGH) { + if (qtd->urb->dev->speed != USB_SPEED_HIGH) { /* split transaction */ - dw1 |= PTD_TRANS_SPLIT; - if (urb->dev->speed == USB_SPEED_LOW) - dw1 |= PTD_SE_USB_LOSPEED; + ptd->dw1 |= DW1_TRANS_SPLIT; + if (qtd->urb->dev->speed == USB_SPEED_LOW) + ptd->dw1 |= DW1_SE_USB_LOSPEED; - dw1 |= PTD_PORT_NUM(urb->dev->ttport); - dw1 |= PTD_HUB_NUM(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(urb->pipe) && - (urb->dev->speed == USB_SPEED_LOW)) - dw1 |= 2 << 16; + if (usb_pipeint(qtd->urb->pipe) && + (qtd->urb->dev->speed == USB_SPEED_LOW)) + ptd->dw1 |= 2 << 16; - dw3 = 0; rl = 0; nak = 0; } else { - dw0 |= PTD_MULTI(multi); - if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) - dw3 = qh->ping; - else - dw3 = 0; + ptd->dw0 |= TO_DW0_MULTI(multi); + if (usb_pipecontrol(qtd->urb->pipe) || + usb_pipebulk(qtd->urb->pipe)) + ptd->dw3 |= TO_DW3_PING(qh->ping); } /* DW2 */ - dw2 = 0; - dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload)); - dw2 |= PTD_RL_CNT(rl); - dw3 |= PTD_NAC_CNT(nak); + ptd->dw2 = 0; + ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr)); + ptd->dw2 |= TO_DW2_RL(rl); /* DW3 */ - if (usb_pipecontrol(urb->pipe)) - dw3 |= PTD_DATA_TOGGLE(qtd->toggle); - else - 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 &= ~TO_DW3_DATA_TOGGLE(1); + else if (last_qtd_of_urb(qtd, qh)) + ptd->dw3 |= TO_DW3_DATA_TOGGLE(1); + } - dw3 |= PTD_ACTIVE; + ptd->dw3 |= DW3_ACTIVE_BIT; /* Cerr */ - dw3 |= PTD_CERR(ERR_COUNTER); - - memset(ptd, 0, sizeof(*ptd)); - - ptd->dw0 = cpu_to_le32(dw0); - ptd->dw1 = cpu_to_le32(dw1); - ptd->dw2 = cpu_to_le32(dw2); - ptd->dw3 = cpu_to_le32(dw3); + ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER); } -static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, - struct isp1760_qtd *qtd, struct urb *urb, - u32 payload, struct ptd *ptd) +static void transform_add_int(struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct ptd *ptd) { - u32 maxpacket; - u32 multi; - u32 numberofusofs; - u32 i; - u32 usofmask, usof; + u32 usof; u32 period; - maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); - multi = 1 + ((maxpacket >> 11) & 0x3); - maxpacket &= 0x7ff; - /* length of the data per uframe */ - maxpacket = multi * maxpacket; - - numberofusofs = urb->transfer_buffer_length / maxpacket; - if (urb->transfer_buffer_length % maxpacket) - numberofusofs += 1; - - usofmask = 1; - usof = 0; - for (i = 0; i < numberofusofs; i++) { - usof |= usofmask; - usofmask <<= 1; - } - - if (urb->dev->speed != USB_SPEED_HIGH) { - /* split */ - ptd->dw5 = cpu_to_le32(0x1c); + /* + * Most of this is guessing. ISP1761 datasheet is quite unclear, and + * the algorithm from the original Philips driver code, which was + * pretty much used in this driver before as well, is quite horrendous + * and, i believe, incorrect. The code below follows the datasheet and + * USB2.0 spec as far as I can tell, and plug/unplug seems to be much + * more reliable this way (fingers crossed...). + */ - if (qh->period >= 32) - period = qh->period / 2; + if (qtd->urb->dev->speed == USB_SPEED_HIGH) { + /* urb->interval is in units of microframes (1/8 ms) */ + period = qtd->urb->interval >> 3; + + if (qtd->urb->interval > 4) + usof = 0x01; /* One bit set => + interval 1 ms * uFrame-match */ + else if (qtd->urb->interval > 2) + usof = 0x22; /* Two bits set => interval 1/2 ms */ + else if (qtd->urb->interval > 1) + usof = 0x55; /* Four bits set => interval 1/4 ms */ else - period = qh->period; - + usof = 0xff; /* All bits set => interval 1/8 ms */ } else { + /* urb->interval is in units of frames (1 ms) */ + period = qtd->urb->interval; + usof = 0x0f; /* Execute Start Split on any of the + four first uFrames */ - if (qh->period >= 8) - period = qh->period/8; - else - period = qh->period; - - if (period >= 32) - period = 16; - - if (qh->period >= 8) { - /* millisecond period */ - period = (period << 3); - } else { - /* usof based tranmsfers */ - /* minimum 4 usofs */ - usof = 0x11; - } + /* + * First 8 bits in dw5 is uSCS and "specifies which uSOF the + * complete split needs to be sent. Valid only for IN." Also, + * "All bits can be set to one for every transfer." (p 82, + * ISP1761 data sheet.) 0x1c is from Philips driver. Where did + * that number come from? 0xff seems to work fine... + */ + /* ptd->dw5 = 0x1c; */ + ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */ } - ptd->dw2 |= cpu_to_le32(period); - ptd->dw4 = cpu_to_le32(usof); -} + period = period >> 1;/* Ensure equal or shorter period than requested */ + period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */ -static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, - struct isp1760_qtd *qtd, struct urb *urb, - u32 payload, struct ptd *ptd) -{ - transform_into_atl(priv, qh, qtd, urb, payload, ptd); - transform_add_int(priv, qh, qtd, urb, payload, ptd); + ptd->dw2 |= period; + ptd->dw4 = usof; } -static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len, - u32 token) +static void create_ptd_int(struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct ptd *ptd) { - int count; - - qtd->data_buffer = databuffer; - qtd->packet_type = GET_QTD_TOKEN_TYPE(token); - qtd->toggle = GET_DATA_TOGGLE(token); - - if (len > HC_ATL_PL_SIZE) - count = HC_ATL_PL_SIZE; - else - count = len; - - qtd->length = count; - return count; + create_ptd_atl(qh, qtd, ptd); + transform_add_int(qh, qtd, ptd); } -static int check_error(struct ptd *ptd) +static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb) +__releases(priv->lock) +__acquires(priv->lock) { - int error = 0; - u32 dw3; - - dw3 = le32_to_cpu(ptd->dw3); - if (dw3 & DW3_HALT_BIT) { - error = -EPIPE; + struct isp1760_hcd *priv = hcd_to_priv(hcd); - if (dw3 & DW3_ERROR_BIT) - pr_err("error bit is set in DW3\n"); + if (!urb->unlinked) { + if (urb->status == -EINPROGRESS) + urb->status = 0; } - if (dw3 & DW3_QTD_ACTIVE) { - printk(KERN_ERR "transfer active bit is set DW3\n"); - printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf, - (le32_to_cpu(ptd->dw2) >> 25) & 0xf); + if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) { + void *ptr; + for (ptr = urb->transfer_buffer; + ptr < urb->transfer_buffer + urb->transfer_buffer_length; + ptr += PAGE_SIZE) + flush_dcache_page(virt_to_page(ptr)); } - return error; + /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(hcd, urb); + spin_unlock(&priv->lock); + usb_hcd_giveback_urb(hcd, urb, urb->status); + spin_lock(&priv->lock); } -static void check_int_err_status(u32 dw4) +static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb, + u8 packet_type) { - u32 i; - - dw4 >>= 8; + struct isp1760_qtd *qtd; - for (i = 0; i < 8; i++) { - switch (dw4 & 0x7) { - case INT_UNDERRUN: - printk(KERN_ERR "ERROR: under run , %d\n", i); - break; + qtd = kmem_cache_zalloc(qtd_cachep, flags); + if (!qtd) + return NULL; - case INT_EXACT: - printk(KERN_ERR "ERROR: transaction error, %d\n", i); - break; + INIT_LIST_HEAD(&qtd->qtd_list); + qtd->urb = urb; + qtd->packet_type = packet_type; + qtd->status = QTD_ENQUEUED; + qtd->actual_length = 0; - case INT_BABBLE: - printk(KERN_ERR "ERROR: babble error, %d\n", i); - break; - } - dw4 >>= 3; - } + return qtd; } -static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv, - u32 payload) +static void qtd_free(struct isp1760_qtd *qtd) { - u32 token; - struct usb_hcd *hcd = priv_to_hcd(priv); - - token = qtd->packet_type; - - if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) { - switch (token) { - case IN_PID: - break; - case OUT_PID: - case SETUP_PID: - priv_write_copy(priv, qtd->data_buffer, - hcd->regs + payload, - qtd->length); - } - } + WARN_ON(qtd->payload_addr); + kmem_cache_free(qtd_cachep, qtd); } -static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload, - struct isp1760_hcd *priv, struct isp1760_qh *qh, - struct urb *urb, u32 slot, struct isp1760_qtd *qtd) +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 ptd ptd; - struct usb_hcd *hcd = priv_to_hcd(priv); - - transform_into_atl(priv, qh, qtd, urb, payload, &ptd); - priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd)); - enqueue_one_qtd(qtd, priv, payload); - - priv->atl_ints[slot].urb = urb; - priv->atl_ints[slot].qh = qh; - priv->atl_ints[slot].qtd = qtd; - priv->atl_ints[slot].data_buffer = qtd->data_buffer; - priv->atl_ints[slot].payload = payload; - qtd->status |= URB_ENQUEUED | URB_TYPE_ATL; - qtd->status |= slot << 16; + 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); + + /* 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 << slot); + } else { + priv->int_done_map |= reg_read32(hcd->regs, + HC_INT_PTD_DONEMAP_REG); + priv->int_done_map &= ~(1 << slot); + } + + qh->slot = slot; + qtd->status = QTD_XFER_STARTED; + slots[slot].timestamp = jiffies; + slots[slot].qtd = qtd; + slots[slot].qh = qh; + ptd_write(hcd->regs, ptd_offset, slot, ptd); + + if (ptd_offset == ATL_PTD_OFFSET) { + 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 { + 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 enqueue_one_int_qtd(u32 int_regs, u32 payload, - struct isp1760_hcd *priv, struct isp1760_qh *qh, - struct urb *urb, u32 slot, struct isp1760_qtd *qtd) +static int is_short_bulk(struct isp1760_qtd *qtd) { - struct ptd ptd; - struct usb_hcd *hcd = priv_to_hcd(priv); - - transform_into_int(priv, qh, qtd, urb, payload, &ptd); - priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd)); - enqueue_one_qtd(qtd, priv, payload); - - priv->int_ints[slot].urb = urb; - priv->int_ints[slot].qh = qh; - priv->int_ints[slot].qtd = qtd; - priv->int_ints[slot].data_buffer = qtd->data_buffer; - priv->int_ints[slot].payload = payload; - qtd->status |= URB_ENQUEUED | URB_TYPE_INT; - qtd->status |= slot << 16; + return (usb_pipebulk(qtd->urb->pipe) && + (qtd->actual_length < qtd->length)); } -static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, - struct isp1760_qtd *qtd) +static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct list_head *urb_list) { - struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 skip_map, or_map; - u32 queue_entry; - u32 slot; - u32 atl_regs, payload; - 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 = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG); - - BUG_ON(!skip_map); - slot = __ffs(skip_map); - queue_entry = 1 << slot; + int last_qtd; + struct isp1760_qtd *qtd, *qtd_next; + struct urb_listitem *urb_listitem; - atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd); - - payload = alloc_mem(priv, qtd->length); + list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) { + if (qtd->status < QTD_XFER_COMPLETE) + break; - enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd); + last_qtd = last_qtd_of_urb(qtd, qh); + + 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; + } + } - or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG); - or_map |= queue_entry; - isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + 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; + } + } - skip_map &= ~queue_entry; - isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG); + if (qtd->payload_addr) + free_mem(hcd, qtd); + + 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; /* Try again on next call */ + urb_listitem->urb = qtd->urb; + list_add_tail(&urb_listitem->urb_list, urb_list); + } - buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); - buffstatus |= ATL_BUFFER; - isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); + list_del(&qtd->qtd_list); + qtd_free(qtd); + } } -static void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, - struct isp1760_qtd *qtd) +#define ENQUEUE_DEPTH 2 +static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) { struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 skip_map, or_map; - u32 queue_entry; - u32 slot; - u32 int_regs, payload; - 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 = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG); - - BUG_ON(!skip_map); - slot = __ffs(skip_map); - queue_entry = 1 << slot; - - int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd); - - payload = alloc_mem(priv, qtd->length); - - enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd); - - or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG); - or_map |= queue_entry; - isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG); + int ptd_offset; + struct slotinfo *slots; + int curr_slot, free_slot; + int n; + struct ptd ptd; + struct isp1760_qtd *qtd; - skip_map &= ~queue_entry; - isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG); + if (unlikely(list_empty(&qh->qtd_list))) { + WARN_ON(1); + return; + } - buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); - buffstatus |= INT_BUFFER; - isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); -} + /* Make sure this endpoint's TT buffer is clean before queueing ptds */ + if (qh->tt_buffer_dirty) + return; -static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status) -__releases(priv->lock) -__acquires(priv->lock) -{ - if (!urb->unlinked) { - if (status == -EINPROGRESS) - status = 0; + 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; } - if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) { - void *ptr; - for (ptr = urb->transfer_buffer; - ptr < urb->transfer_buffer + urb->transfer_buffer_length; - ptr += PAGE_SIZE) - flush_dcache_page(virt_to_page(ptr)); + 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; } - /* complete() can reenter this HCD */ - usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); - spin_unlock(&priv->lock); - usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status); - spin_lock(&priv->lock); -} - -static void isp1760_qtd_free(struct isp1760_qtd *qtd) -{ - kmem_cache_free(qtd_cachep, qtd); -} + 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; -static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd) -{ - struct isp1760_qtd *tmp_qtd; + 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); + } - tmp_qtd = qtd->hw_next; - list_del(&qtd->qtd_list); - isp1760_qtd_free(qtd); - return tmp_qtd; -} + qtd->status = QTD_PAYLOAD_ALLOC; + } + if (qtd->status == QTD_PAYLOAD_ALLOC) { /* - * 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_qtd *tmp_qtd; - int last_one; - - do { - tmp_qtd = qtd->hw_next; - last_one = qtd->status & URB_COMPLETE_NOTIFY; - list_del(&qtd->qtd_list); - isp1760_qtd_free(qtd); - qtd = tmp_qtd; - } while (!last_one && qtd); + 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; + } - return qtd; + n++; + if (n >= ENQUEUE_DEPTH) + break; + } + } } -static void do_atl_int(struct usb_hcd *usb_hcd) +static void schedule_ptds(struct usb_hcd *hcd) { - struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); - u32 done_map, skip_map; - struct ptd ptd; - struct urb *urb = NULL; - u32 atl_regs_base; - u32 atl_regs; - u32 queue_entry; - u32 payload; - u32 length; - u32 or_map; - u32 status = -EINVAL; - int error; - struct isp1760_qtd *qtd; - struct isp1760_qh *qh; - u32 rl; - u32 nakcount; - - done_map = isp1760_readl(usb_hcd->regs + - HC_ATL_PTD_DONEMAP_REG); - skip_map = isp1760_readl(usb_hcd->regs + - HC_ATL_PTD_SKIPMAP_REG); - - or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); - or_map &= ~done_map; - isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); - - atl_regs_base = ATL_REGS_OFFSET; - while (done_map) { - u32 dw1; - u32 dw2; - u32 dw3; - - status = 0; - - queue_entry = __ffs(done_map); - done_map &= ~(1 << queue_entry); - skip_map |= 1 << queue_entry; + struct isp1760_hcd *priv; + struct isp1760_qh *qh, *qh_next; + struct list_head *ep_queue; + LIST_HEAD(urb_list); + struct urb_listitem *urb_listitem, *urb_listitem_next; + int i; - atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd); + if (!hcd) { + WARN_ON(1); + return; + } - urb = priv->atl_ints[queue_entry].urb; - qtd = priv->atl_ints[queue_entry].qtd; - qh = priv->atl_ints[queue_entry].qh; - payload = priv->atl_ints[queue_entry].payload; + priv = hcd_to_priv(hcd); - if (!qh) { - printk(KERN_ERR "qh is 0\n"); - continue; + /* + * check finished/retired xfers, transfer payloads, call urb_done() + */ + 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) { + collect_qtds(hcd, qh, &urb_list); + if (list_empty(&qh->qtd_list)) + list_del(&qh->qh_list); } - isp1760_writel(atl_regs + ISP_BANK(0), usb_hcd->regs + - HC_MEMORY_REG); - isp1760_writel(payload + ISP_BANK(1), usb_hcd->regs + - HC_MEMORY_REG); - /* - * write bank1 address twice to ensure the 90ns delay (time - * between BANK0 write and the priv_read_copy() call is at - * least 3*t_WHWL + 2*t_w11 = 3*25ns + 2*17ns = 109ns) - */ - isp1760_writel(payload + ISP_BANK(1), usb_hcd->regs + - HC_MEMORY_REG); - - priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs + - ISP_BANK(0), sizeof(ptd)); - - dw1 = le32_to_cpu(ptd.dw1); - dw2 = le32_to_cpu(ptd.dw2); - dw3 = le32_to_cpu(ptd.dw3); - rl = (dw2 >> 25) & 0x0f; - nakcount = (dw3 >> 19) & 0xf; - - /* Transfer Error, *but* active and no HALT -> reload */ - if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) && - !(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. - */ + } - length = PTD_XFERRED_LENGTH(dw3); - printk(KERN_ERR "Should reload now.... transfered %d " - "of %zu\n", length, qtd->length); - BUG(); - } + 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 (!nakcount && (dw3 & DW3_QTD_ACTIVE)) { - u32 buffstatus; + /* + * 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! + */ + 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); + } +} - /* - * 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. - */ - printk(KERN_NOTICE "Reloading ptd %p/%p... qh %p read: " - "%d of %zu done: %08x cur: %08x\n", qtd, - urb, qh, PTD_XFERRED_LENGTH(dw3), - qtd->length, done_map, - (1 << queue_entry)); +#define PTD_STATE_QTD_DONE 1 +#define PTD_STATE_QTD_RELOAD 2 +#define PTD_STATE_URB_RETIRE 3 - /* RL counter = ERR counter */ - dw3 &= ~(0xf << 19); - dw3 |= rl << 19; - dw3 &= ~(3 << (55 - 32)); - 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 << queue_entry); - or_map = isp1760_readl(usb_hcd->regs + - HC_ATL_IRQ_MASK_OR_REG); - or_map |= 1 << queue_entry; - isp1760_writel(or_map, usb_hcd->regs + - HC_ATL_IRQ_MASK_OR_REG); - - ptd.dw3 = cpu_to_le32(dw3); - priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + - atl_regs, sizeof(ptd)); - - ptd.dw0 |= cpu_to_le32(PTD_VALID); - priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + - atl_regs, sizeof(ptd)); - - buffstatus = isp1760_readl(usb_hcd->regs + - HC_BUFFER_STATUS_REG); - buffstatus |= ATL_BUFFER; - isp1760_writel(buffstatus, usb_hcd->regs + - HC_BUFFER_STATUS_REG); - continue; - } +static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd, + struct urb *urb) +{ + __dw dw4; + int i; - error = check_error(&ptd); - if (error) { - status = error; - priv->atl_ints[queue_entry].qh->toggle = 0; - priv->atl_ints[queue_entry].qh->ping = 0; - 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 { - if (usb_pipetype(urb->pipe) == PIPE_BULK) { - priv->atl_ints[queue_entry].qh->toggle = dw3 & - (1 << 25); - priv->atl_ints[queue_entry].qh->ping = dw3 & - (1 << 26); - } - } + dw4 = ptd->dw4; + dw4 >>= 8; - length = PTD_XFERRED_LENGTH(dw3); - if (length) { - switch (DW1_GET_PID(dw1)) { - case IN_PID: - priv_read_copy(priv, - priv->atl_ints[queue_entry].data_buffer, - usb_hcd->regs + payload + ISP_BANK(1), - length); + /* FIXME: ISP1761 datasheet does not say what to do with these. Do we + need to handle these errors? Is it done in hardware? */ - case OUT_PID: + if (ptd->dw3 & DW3_HALT_BIT) { - urb->actual_length += length; + urb->status = -EPROTO; /* Default unknown error */ - case SETUP_PID: + 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; } - priv->atl_ints[queue_entry].data_buffer = NULL; - priv->atl_ints[queue_entry].urb = NULL; - priv->atl_ints[queue_entry].qtd = NULL; - priv->atl_ints[queue_entry].qh = NULL; - - free_mem(priv, payload); - - isp1760_writel(skip_map, usb_hcd->regs + - HC_ATL_PTD_SKIPMAP_REG); - - if (urb->status == -EPIPE) { - /* HALT was received */ - - qtd = clean_up_qtdlist(qtd); - isp1760_urb_done(priv, urb, urb->status); - - } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) { - /* short BULK received */ - - if (urb->transfer_flags & URB_SHORT_NOT_OK) { - urb->status = -EREMOTEIO; - isp1760_dbg(priv, "short bulk, %d instead %zu " - "with URB_SHORT_NOT_OK flag.\n", - length, qtd->length); - } - - if (urb->status == -EINPROGRESS) - urb->status = 0; - - qtd = clean_up_qtdlist(qtd); - - isp1760_urb_done(priv, urb, urb->status); - - } else if (qtd->status & URB_COMPLETE_NOTIFY) { - /* that was the last qtd of that URB */ - - if (urb->status == -EINPROGRESS) - urb->status = 0; - - qtd = clean_this_qtd(qtd); - isp1760_urb_done(priv, urb, urb->status); + return PTD_STATE_URB_RETIRE; + } - } else { - /* next QTD of this URB */ + return PTD_STATE_QTD_DONE; +} - qtd = clean_this_qtd(qtd); - 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(usb_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 = isp1760_readl(usb_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; } + + return PTD_STATE_QTD_DONE; } -static void do_intl_int(struct usb_hcd *usb_hcd) +static void handle_done_ptds(struct usb_hcd *hcd) { - struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); - u32 done_map, skip_map; + struct isp1760_hcd *priv = hcd_to_priv(hcd); struct ptd ptd; - struct urb *urb = NULL; - u32 int_regs; - u32 int_regs_base; - u32 payload; - u32 length; - u32 or_map; - int error; - u32 queue_entry; - struct isp1760_qtd *qtd; struct isp1760_qh *qh; + int slot; + int state; + struct slotinfo *slots; + u32 ptd_offset; + struct isp1760_qtd *qtd; + int modified; + int skip_map; + + skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); + priv->int_done_map &= ~skip_map; + skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); + priv->atl_done_map &= ~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 { + /* 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); + } - done_map = isp1760_readl(usb_hcd->regs + - HC_INT_PTD_DONEMAP_REG); - skip_map = isp1760_readl(usb_hcd->regs + - HC_INT_PTD_SKIPMAP_REG); - - or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); - or_map &= ~done_map; - isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); - - int_regs_base = INT_REGS_OFFSET; - - while (done_map) { - u32 dw1; - u32 dw3; + qtd = slots[slot].qtd; + slots[slot].qtd = NULL; + qh = slots[slot].qh; + slots[slot].qh = NULL; + 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; - queue_entry = __ffs(done_map); - done_map &= ~(1 << queue_entry); - skip_map |= 1 << queue_entry; + 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; - int_regs = int_regs_base + queue_entry * sizeof(struct ptd); - urb = priv->int_ints[queue_entry].urb; - qtd = priv->int_ints[queue_entry].qtd; - qh = priv->int_ints[queue_entry].qh; - payload = priv->int_ints[queue_entry].payload; + case PTD_STATE_URB_RETIRE: + qtd->status = QTD_RETIRE; + if ((qtd->urb->dev->speed != USB_SPEED_HIGH) && + (qtd->urb->status != -EPIPE) && + (qtd->urb->status != -EREMOTEIO)) { + qh->tt_buffer_dirty = 1; + if (usb_hub_clear_tt_buffer(qtd->urb)) + /* Clear failed; let's hope things work + anyway */ + qh->tt_buffer_dirty = 0; + } + qtd = NULL; + qh->toggle = 0; + qh->ping = 0; + break; - if (!qh) { - printk(KERN_ERR "(INT) qh is 0\n"); + default: + WARN_ON(1); continue; } - isp1760_writel(int_regs + ISP_BANK(0), usb_hcd->regs + - HC_MEMORY_REG); - isp1760_writel(payload + ISP_BANK(1), usb_hcd->regs + - HC_MEMORY_REG); - /* - * write bank1 address twice to ensure the 90ns delay (time - * between BANK0 write and the priv_read_copy() call is at - * least 3*t_WHWL + 2*t_w11 = 3*25ns + 2*17ns = 92ns) - */ - isp1760_writel(payload + ISP_BANK(1), usb_hcd->regs + - HC_MEMORY_REG); - - priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs + - ISP_BANK(0), sizeof(ptd)); - dw1 = le32_to_cpu(ptd.dw1); - dw3 = le32_to_cpu(ptd.dw3); - check_int_err_status(le32_to_cpu(ptd.dw4)); - - error = check_error(&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 - urb->status = -EPIPE; - priv->int_ints[queue_entry].qh->toggle = 0; - priv->int_ints[queue_entry].qh->ping = 0; + 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); + } - } else { - priv->int_ints[queue_entry].qh->toggle = - dw3 & (1 << 25); - priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26); + start_bus_transfer(hcd, ptd_offset, slot, slots, qtd, + qh, &ptd); } + } - if (urb->dev->speed != USB_SPEED_HIGH) - length = PTD_XFERRED_LENGTH_LO(dw3); - else - length = PTD_XFERRED_LENGTH(dw3); - - if (length) { - switch (DW1_GET_PID(dw1)) { - case IN_PID: - priv_read_copy(priv, - priv->int_ints[queue_entry].data_buffer, - usb_hcd->regs + payload + ISP_BANK(1), - length); - case OUT_PID: - - urb->actual_length += length; + if (modified) + schedule_ptds(hcd); +} - case SETUP_PID: - break; - } - } +static irqreturn_t isp1760_irq(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 imask; + irqreturn_t irqret = IRQ_NONE; - priv->int_ints[queue_entry].data_buffer = NULL; - priv->int_ints[queue_entry].urb = NULL; - priv->int_ints[queue_entry].qtd = NULL; - priv->int_ints[queue_entry].qh = NULL; + spin_lock(&priv->lock); - isp1760_writel(skip_map, usb_hcd->regs + - HC_INT_PTD_SKIPMAP_REG); - free_mem(priv, payload); + if (!(hcd->state & HC_STATE_RUNNING)) + goto leave; - if (urb->status == -EPIPE) { - /* HALT received */ + imask = reg_read32(hcd->regs, HC_INTERRUPT_REG); + if (unlikely(!imask)) + goto leave; + reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */ - qtd = clean_up_qtdlist(qtd); - isp1760_urb_done(priv, urb, urb->status); + 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); - } else if (qtd->status & URB_COMPLETE_NOTIFY) { + handle_done_ptds(hcd); - if (urb->status == -EINPROGRESS) - urb->status = 0; + irqret = IRQ_HANDLED; +leave: + spin_unlock(&priv->lock); - qtd = clean_this_qtd(qtd); - isp1760_urb_done(priv, urb, urb->status); + return irqret; +} - } else { - /* next QTD of this URB */ +/* + * Workaround for problem described in chip errata 2: + * + * Sometimes interrupts are not generated when ATL (not INT?) completion occurs. + * One solution suggested in the errata is to use SOF interrupts _instead_of_ + * ATL done interrupts (the "instead of" might be important since it seems + * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget" + * to set the PTD's done bit in addition to not generating an interrupt!). + * + * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their + * done bit is not being set. This is bad - it blocks the endpoint until reboot. + * + * If we use SOF interrupts only, we get latency between ptd completion and the + * actual handling. This is very noticeable in testusb runs which takes several + * minutes longer without ATL interrupts. + * + * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it + * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the + * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered + * completed and its done map bit is set. + * + * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen + * not to cause too much lag when this HW bug occurs, while still hopefully + * ensuring that the check does not falsely trigger. + */ +#define SLOT_TIMEOUT 300 +#define SLOT_CHECK_PERIOD 200 +static struct timer_list errata2_timer; - qtd = clean_this_qtd(qtd); - BUG_ON(!qtd); +static void errata2_function(unsigned long data) +{ + struct usb_hcd *hcd = (struct usb_hcd *) data; + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int slot; + struct ptd ptd; + unsigned long spinflags; + + spin_lock_irqsave(&priv->lock, spinflags); + + for (slot = 0; slot < 32; slot++) + if (priv->atl_slots[slot].qh && time_after(jiffies, + priv->atl_slots[slot].timestamp + + SLOT_TIMEOUT * HZ / 1000)) { + ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); + if (!FROM_DW0_VALID(ptd.dw0) && + !FROM_DW3_ACTIVE(ptd.dw3)) + priv->atl_done_map |= 1 << slot; } - if (qtd) - enqueue_an_INT_packet(usb_hcd, qh, qtd); + if (priv->atl_done_map) + handle_done_ptds(hcd); - skip_map = isp1760_readl(usb_hcd->regs + - HC_INT_PTD_SKIPMAP_REG); - } + spin_unlock_irqrestore(&priv->lock, spinflags); + + errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000; + add_timer(&errata2_timer); } -#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) -static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb, - gfp_t flags) +static int isp1760_run(struct usb_hcd *hcd) { - struct isp1760_qh *qh; - int is_input, type; - - qh = isp1760_qh_alloc(priv, flags); - if (!qh) - return qh; - - /* - * init endpoint/device data for this QH - */ - is_input = usb_pipein(urb->pipe); - type = usb_pipetype(urb->pipe); + int retval; + u32 temp; + u32 command; + u32 chipid; - if (type == PIPE_INTERRUPT) { + hcd->uses_new_polling = 1; - if (urb->dev->speed == USB_SPEED_HIGH) { + hcd->state = HC_STATE_RUNNING; - qh->period = urb->interval >> 3; - if (qh->period == 0 && urb->interval != 1) { - /* NOTE interval 2 or 4 uframes could work. - * But interval 1 scheduling is simpler, and - * includes high bandwidth. - */ - printk(KERN_ERR "intr period %d uframes, NYET!", - urb->interval); - qh_destroy(qh); - return NULL; - } - } else { - qh->period = urb->interval; - } - } + /* Set PTD interrupt AND & OR maps */ + reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_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, 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 */ - /* support for tt scheduling, and access to toggles */ - qh->dev = urb->dev; + temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); + reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN); - if (!usb_pipecontrol(urb->pipe)) - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, - 1); - return qh; -} + command = reg_read32(hcd->regs, HC_USBCMD); + command &= ~(CMD_LRESET|CMD_RESET); + command |= CMD_RUN; + reg_write32(hcd->regs, HC_USBCMD, command); -/* - * 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 isp1760_hcd *priv, - struct urb *urb, struct list_head *qtd_list, int epnum, - void **ptr) -{ - struct isp1760_qh *qh; - struct isp1760_qtd *qtd; - struct isp1760_qtd *prev_qtd; + retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000); + if (retval) + return retval; - qh = (struct isp1760_qh *)*ptr; - if (!qh) { - /* can't sleep here, we have priv->lock... */ - qh = qh_make(priv, urb, GFP_ATOMIC); - if (!qh) - return qh; - *ptr = qh; - } + /* + * XXX + * Spec says to write FLAG_CF as last config action, priv code grabs + * the semaphore while doing so. + */ + down_write(&ehci_cf_port_reset_rwsem); + reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF); - qtd = list_entry(qtd_list->next, struct isp1760_qtd, - qtd_list); - if (!list_empty(&qh->qtd_list)) - prev_qtd = list_entry(qh->qtd_list.prev, - struct isp1760_qtd, qtd_list); - else - prev_qtd = NULL; + retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000); + up_write(&ehci_cf_port_reset_rwsem); + if (retval) + return retval; - list_splice(qtd_list, qh->qtd_list.prev); - if (prev_qtd) { - BUG_ON(prev_qtd->hw_next); - prev_qtd->hw_next = qtd; - } + init_timer(&errata2_timer); + errata2_timer.function = errata2_function; + errata2_timer.data = (unsigned long) hcd; + errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000; + add_timer(&errata2_timer); - urb->hcpriv = qh; - return qh; -} + chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG); + dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n", + chipid & 0xffff, chipid >> 16); -static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb, - struct list_head *qtd_list) -{ - struct list_head *entry, *temp; + /* PTD Register Init Part 2, Step 28 */ - list_for_each_safe(entry, temp, qtd_list) { - struct isp1760_qtd *qtd; + /* Setup registers controlling PTD checking */ + 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); - qtd = list_entry(entry, struct isp1760_qtd, qtd_list); - list_del(&qtd->qtd_list); - isp1760_qtd_free(qtd); - } + /* GRR this is run-once init(), being done every time the HC starts. + * So long as they're part of class devices, we can't do it init() + * since the class device isn't created that early. + */ + return 0; } -static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb, - struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p) +static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len) { - 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(priv_to_hcd(priv))) { - rc = -ESHUTDOWN; - goto done; - } - rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb); - if (rc) - goto done; - - qh = urb->ep->hcpriv; - if (qh) - qh_busy = !list_empty(&qh->qtd_list); - else - qh_busy = 0; - - qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv); - if (!qh) { - usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); - rc = -ENOMEM; - goto done; - } + qtd->data_buffer = databuffer; - if (!qh_busy) - p(priv_to_hcd(priv), qh, qtd); + if (len > MAX_PAYLOAD_SIZE) + len = MAX_PAYLOAD_SIZE; + qtd->length = len; -done: - spin_unlock_irqrestore(&priv->lock, flags); - if (!qh) - qtd_list_free(priv, urb, qtd_list); - return rc; + return qtd->length; } -static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv, - gfp_t flags) +static void qtd_list_free(struct list_head *qtd_list) { - struct isp1760_qtd *qtd; - - qtd = kmem_cache_zalloc(qtd_cachep, flags); - if (qtd) - INIT_LIST_HEAD(&qtd->qtd_list); + struct isp1760_qtd *qtd, *qtd_next; - return qtd; + list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) { + list_del(&qtd->qtd_list); + qtd_free(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. */ -static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv, +#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) +static void packetize_urb(struct usb_hcd *hcd, struct urb *urb, struct list_head *head, gfp_t flags) { - struct isp1760_qtd *qtd, *qtd_prev; + 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(priv, 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 */ - token ^= DATA_TOGGLE; - qtd_prev = qtd; - qtd = isp1760_qtd_alloc(priv, flags); + qtd = qtd_alloc(flags, urb, SETUP_PID); if (!qtd) goto cleanup; - qtd->urb = urb; - qtd_prev->hw_next = qtd; + 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 */ - printk(KERN_ERR "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; - /* qh makes control packets use qtd toggle; maybe switch it */ - if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) - token ^= DATA_TOGGLE; - if (len <= 0) break; - - qtd_prev = qtd; - qtd = isp1760_qtd_alloc(priv, flags); - if (!qtd) - goto cleanup; - qtd->urb = urb; - qtd_prev->hw_next = qtd; - list_add_tail(&qtd->qtd_list, head); } /* @@ -1599,187 +1488,247 @@ static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv, if (usb_pipecontrol(urb->pipe)) { one_more = 1; - /* "in" <--> "out" */ - token ^= IN_PID; - /* force DATA1 */ - token |= DATA_TOGGLE; + 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_prev = qtd; - qtd = isp1760_qtd_alloc(priv, flags); + qtd = qtd_alloc(flags, urb, packet_type); if (!qtd) goto cleanup; - qtd->urb = urb; - qtd_prev->hw_next = qtd; - 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 = URB_COMPLETE_NOTIFY; - return head; + return; cleanup: - qtd_list_free(priv, 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 isp1760_hcd *priv = hcd_to_priv(hcd); - struct list_head qtd_list; - packet_enqueue *pe; - - INIT_LIST_HEAD(&qtd_list); + 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->qh_list[QH_CONTROL]; + break; case PIPE_BULK: - - if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) - return -ENOMEM; - pe = enqueue_an_ATL_packet; + ep_queue = &priv->qh_list[QH_BULK]; break; - case PIPE_INTERRUPT: - if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) - return -ENOMEM; - pe = enqueue_an_INT_packet; + if (urb->interval < 0) + return -EINVAL; + /* FIXME: Check bandwidth */ + ep_queue = &priv->qh_list[QH_INTERRUPT]; break; - case PIPE_ISOCHRONOUS: - printk(KERN_ERR "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(priv, urb, &qtd_list, mem_flags, pe); + if (usb_pipein(urb->pipe)) + urb->actual_length = 0; + + packetize_urb(hcd, urb, &new_qtds, mem_flags); + if (list_empty(&new_qtds)) + return -ENOMEM; + + retval = 0; + spin_lock_irqsave(&priv->lock, spinflags); + + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + retval = -ESHUTDOWN; + qtd_list_free(&new_qtds); + goto out; + } + retval = usb_hcd_link_urb_to_ep(hcd, urb); + if (retval) { + qtd_list_free(&new_qtds); + goto out; + } + + 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; + usb_hcd_unlink_urb_from_ep(hcd, urb); + qtd_list_free(&new_qtds); + goto out; + } + list_add_tail(&qh->qh_list, ep_queue); + urb->ep->hcpriv = qh; + } + + list_splice_tail(&new_qtds, &qh->qtd_list); + schedule_ptds(hcd); + +out: + spin_unlock_irqrestore(&priv->lock, spinflags); + return retval; } -static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, - int status) +static void kill_transfer(struct usb_hcd *hcd, struct urb *urb, + struct isp1760_qh *qh) { 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; + int skip_map; + + WARN_ON(qh->slot == -1); + + /* 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; + } - switch (usb_pipetype(urb->pipe)) { - case PIPE_ISOCHRONOUS: - return -EPIPE; - break; + qh->slot = -1; +} - case PIPE_INTERRUPT: - ints = priv->int_ints; - reg_base = INT_REGS_OFFSET; - or_reg = HC_INT_IRQ_MASK_OR_REG; - skip_reg = HC_INT_PTD_SKIPMAP_REG; - pe = enqueue_an_INT_packet; - break; +/* + * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing + * any active transfer belonging to the urb in the process. + */ +static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd) +{ + struct urb *urb; + int urb_was_running; - default: - ints = priv->atl_ints; - reg_base = ATL_REGS_OFFSET; - or_reg = HC_ATL_IRQ_MASK_OR_REG; - skip_reg = HC_ATL_PTD_SKIPMAP_REG; - pe = enqueue_an_ATL_packet; - break; + urb = qtd->urb; + urb_was_running = 0; + list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) { + if (qtd->urb != urb) + break; + + if (qtd->status >= QTD_XFER_STARTED) + urb_was_running = 1; + if (last_qtd_of_urb(qtd, qh) && + (qtd->status >= QTD_XFER_COMPLETE)) + urb_was_running = 0; + + if (qtd->status == QTD_XFER_STARTED) + kill_transfer(hcd, urb, qh); + qtd->status = QTD_RETIRE; } - memset(&ptd, 0, sizeof(ptd)); - spin_lock_irqsave(&priv->lock, flags); + if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) { + qh->tt_buffer_dirty = 1; + if (usb_hub_clear_tt_buffer(urb)) + /* Clear failed; let's hope things work anyway */ + qh->tt_buffer_dirty = 0; + } +} - for (i = 0; i < 32; i++) { - if (ints->urb == urb) { - u32 skip_map; - u32 or_map; - struct isp1760_qtd *qtd; - struct isp1760_qh *qh = ints->qh; - - skip_map = isp1760_readl(hcd->regs + skip_reg); - skip_map |= 1 << i; - isp1760_writel(skip_map, hcd->regs + skip_reg); - - or_map = isp1760_readl(hcd->regs + or_reg); - or_map &= ~(1 << i); - isp1760_writel(or_map, hcd->regs + or_reg); - - priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base - + i * sizeof(ptd), sizeof(ptd)); - qtd = ints->qtd; - qtd = clean_up_qtdlist(qtd); - - free_mem(priv, ints->payload); - - ints->urb = NULL; - ints->qh = NULL; - ints->qtd = NULL; - ints->data_buffer = NULL; - ints->payload = 0; - - isp1760_urb_done(priv, urb, status); - if (qtd) - pe(hcd, qh, qtd); - break; +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; - } else if (ints->qtd) { - struct isp1760_qtd *qtd, *prev_qtd = ints->qtd; + spin_lock_irqsave(&priv->lock, spinflags); + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (retval) + goto out; - for (qtd = ints->qtd->hw_next; qtd; qtd = qtd->hw_next) { - if (qtd->urb == urb) { - prev_qtd->hw_next = clean_up_qtdlist(qtd); - isp1760_urb_done(priv, urb, status); - break; - } - prev_qtd = qtd; - } - /* we found the urb before the end of the list */ - if (qtd) - break; - } - ints++; + qh = urb->ep->hcpriv; + if (!qh) { + retval = -EINVAL; + goto out; } - spin_unlock_irqrestore(&priv->lock, flags); - return 0; + list_for_each_entry(qtd, &qh->qtd_list, qtd_list) + if (qtd->urb == urb) { + dequeue_urb_from_qtd(hcd, qh, qtd); + list_move(&qtd->qtd_list, &qh->qtd_list); + break; + } + + urb->status = status; + schedule_ptds(hcd); + +out: + spin_unlock_irqrestore(&priv->lock, spinflags); + return retval; } -static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd) +static void isp1760_endpoint_disable(struct usb_hcd *hcd, + struct usb_host_endpoint *ep) { - struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); - u32 imask; - irqreturn_t irqret = IRQ_NONE; + struct isp1760_hcd *priv = hcd_to_priv(hcd); + unsigned long spinflags; + struct isp1760_qh *qh, *qh_iter; + int i; - spin_lock(&priv->lock); + spin_lock_irqsave(&priv->lock, spinflags); - if (!(usb_hcd->state & HC_STATE_RUNNING)) - goto leave; + qh = ep->hcpriv; + if (!qh) + goto out; - imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG); - if (unlikely(!imask)) - goto leave; + WARN_ON(!list_empty(&qh->qtd_list)); - isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG); - if (imask & HC_ATL_INT) - do_atl_int(usb_hcd); + 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; - if (imask & HC_INTL_INT) - do_intl_int(usb_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) @@ -1790,7 +1739,7 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) int retval = 1; unsigned long flags; - /* if !USB_SUSPEND, root hub timers won't get shut down ... */ + /* if !PM_RUNTIME, root hub timers won't get shut down ... */ if (!HC_IS_RUNNING(hcd->state)) return 0; @@ -1799,12 +1748,12 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) mask = PORT_CSC; spin_lock_irqsave(&priv->lock, flags); - temp = isp1760_readl(hcd->regs + HC_PORTSC1); + temp = reg_read32(hcd->regs, HC_PORTSC1); if (temp & PORT_OWNER) { if (temp & PORT_CSC) { temp &= ~PORT_CSC; - isp1760_writel(temp, hcd->regs + HC_PORTSC1); + reg_write32(hcd->regs, HC_PORTSC1, temp); goto done; } } @@ -1844,9 +1793,9 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv, temp = 1 + (ports / 8); desc->bDescLength = 7 + 2 * temp; - /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&desc->bitmap[0], 0, temp); - memset(&desc->bitmap[temp], 0xff, temp); + /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset(&desc->u.hs.DeviceRemovable[0], 0, temp); + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); /* per-port overcurrent reporting */ temp = 0x0008; @@ -1861,8 +1810,8 @@ static void isp1760_hub_descriptor(struct isp1760_hcd *priv, #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) -static int check_reset_complete(struct isp1760_hcd *priv, int index, - u32 __iomem *status_reg, int port_status) +static int check_reset_complete(struct usb_hcd *hcd, int index, + int port_status) { if (!(port_status & PORT_CONNECT)) return port_status; @@ -1870,15 +1819,17 @@ static int check_reset_complete(struct isp1760_hcd *priv, int index, /* if reset finished and it's still not enabled -- handoff */ if (!(port_status & PORT_PE)) { - printk(KERN_ERR "port %d full speed --> companion\n", - index + 1); + dev_info(hcd->self.controller, + "port %d full speed --> companion\n", + index + 1); port_status |= PORT_OWNER; port_status &= ~PORT_RWC_BITS; - isp1760_writel(port_status, status_reg); + reg_write32(hcd->regs, HC_PORTSC1, port_status); } else - printk(KERN_ERR "port %d high speed\n", index + 1); + dev_info(hcd->self.controller, "port %d high speed\n", + index + 1); return port_status; } @@ -1888,7 +1839,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, { struct isp1760_hcd *priv = hcd_to_priv(hcd); int ports = HCS_N_PORTS(priv->hcs_params); - u32 __iomem *status_reg = hcd->regs + HC_PORTSC1; u32 temp, status; unsigned long flags; int retval = 0; @@ -1917,7 +1867,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = isp1760_readl(status_reg); + temp = reg_read32(hcd->regs, HC_PORTSC1); /* * Even if OWNER is set, so the port is owned by the @@ -1928,7 +1878,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, switch (wValue) { case USB_PORT_FEAT_ENABLE: - isp1760_writel(temp & ~PORT_PE, status_reg); + reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE); break; case USB_PORT_FEAT_C_ENABLE: /* XXX error? */ @@ -1942,8 +1892,8 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, goto error; /* resume signaling for 20 msec */ temp &= ~(PORT_RWC_BITS); - isp1760_writel(temp | PORT_RESUME, - status_reg); + reg_write32(hcd->regs, HC_PORTSC1, + temp | PORT_RESUME); priv->reset_done = jiffies + msecs_to_jiffies(20); } @@ -1953,11 +1903,11 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, break; case USB_PORT_FEAT_POWER: if (HCS_PPC(priv->hcs_params)) - isp1760_writel(temp & ~PORT_POWER, status_reg); + reg_write32(hcd->regs, HC_PORTSC1, + temp & ~PORT_POWER); break; case USB_PORT_FEAT_C_CONNECTION: - isp1760_writel(temp | PORT_CSC, - status_reg); + reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC); break; case USB_PORT_FEAT_C_OVER_CURRENT: /* XXX error ?*/ @@ -1968,7 +1918,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, default: goto error; } - isp1760_readl(hcd->regs + HC_USBCMD); + reg_read32(hcd->regs, HC_USBCMD); break; case GetHubDescriptor: isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *) @@ -1983,7 +1933,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, goto error; wIndex--; status = 0; - temp = isp1760_readl(status_reg); + temp = reg_read32(hcd->regs, HC_PORTSC1); /* wPortChange bits */ if (temp & PORT_CSC) @@ -1992,7 +1942,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, /* whoever resumes must GetPortStatus to complete it!! */ if (temp & PORT_RESUME) { - printk(KERN_ERR "Port resume should be skipped.\n"); + dev_err(hcd->self.controller, "Port resume should be skipped.\n"); /* Remote Wakeup received? */ if (!priv->reset_done) { @@ -2000,8 +1950,7 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, priv->reset_done = jiffies + msecs_to_jiffies(20); /* check the port again */ - mod_timer(&priv_to_hcd(priv)->rh_timer, - priv->reset_done); + mod_timer(&hcd->rh_timer, priv->reset_done); } /* resume completed? */ @@ -2011,14 +1960,13 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, priv->reset_done = 0; /* stop resume signaling */ - temp = isp1760_readl(status_reg); - isp1760_writel( - temp & ~(PORT_RWC_BITS | PORT_RESUME), - status_reg); - retval = handshake(priv, status_reg, + temp = reg_read32(hcd->regs, HC_PORTSC1); + reg_write32(hcd->regs, HC_PORTSC1, + temp & ~(PORT_RWC_BITS | PORT_RESUME)); + retval = handshake(hcd, HC_PORTSC1, PORT_RESUME, 0, 2000 /* 2msec */); if (retval != 0) { - isp1760_err(priv, + dev_err(hcd->self.controller, "port %d resume error %d\n", wIndex + 1, retval); goto error; @@ -2035,22 +1983,21 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, priv->reset_done = 0; /* force reset to complete */ - isp1760_writel(temp & ~PORT_RESET, - status_reg); + reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET); /* REVISIT: some hardware needs 550+ usec to clear * this bit; seems too long to spin routinely... */ - retval = handshake(priv, status_reg, + retval = handshake(hcd, HC_PORTSC1, PORT_RESET, 0, 750); if (retval != 0) { - isp1760_err(priv, "port %d reset error %d\n", + dev_err(hcd->self.controller, "port %d reset error %d\n", wIndex + 1, retval); goto error; } /* see what we found out */ - temp = check_reset_complete(priv, wIndex, status_reg, - isp1760_readl(status_reg)); + temp = check_reset_complete(hcd, wIndex, + reg_read32(hcd->regs, HC_PORTSC1)); } /* * Even if OWNER is set, there's no harm letting khubd @@ -2059,12 +2006,12 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, */ if (temp & PORT_OWNER) - printk(KERN_ERR "Warning: PORT_OWNER is set\n"); + dev_err(hcd->self.controller, "PORT_OWNER is set\n"); if (temp & PORT_CONNECT) { status |= USB_PORT_STAT_CONNECTION; /* status may be from integrated TT */ - status |= ehci_port_speed(priv, temp); + status |= USB_PORT_STAT_HIGH_SPEED; } if (temp & PORT_PE) status |= USB_PORT_STAT_ENABLE; @@ -2093,14 +2040,14 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, if (!wIndex || wIndex > ports) goto error; wIndex--; - temp = isp1760_readl(status_reg); + temp = reg_read32(hcd->regs, HC_PORTSC1); if (temp & PORT_OWNER) break; /* temp &= ~PORT_RWC_BITS; */ switch (wValue) { case USB_PORT_FEAT_ENABLE: - isp1760_writel(temp | PORT_PE, status_reg); + reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE); break; case USB_PORT_FEAT_SUSPEND: @@ -2108,12 +2055,12 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, || (temp & PORT_RESET) != 0) goto error; - isp1760_writel(temp | PORT_SUSPEND, status_reg); + reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND); break; case USB_PORT_FEAT_POWER: if (HCS_PPC(priv->hcs_params)) - isp1760_writel(temp | PORT_POWER, - status_reg); + reg_write32(hcd->regs, HC_PORTSC1, + temp | PORT_POWER); break; case USB_PORT_FEAT_RESET: if (temp & PORT_RESUME) @@ -2136,12 +2083,12 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, priv->reset_done = jiffies + msecs_to_jiffies(50); } - isp1760_writel(temp, status_reg); + reg_write32(hcd->regs, HC_PORTSC1, temp); break; default: goto error; } - isp1760_readl(hcd->regs + HC_USBCMD); + reg_read32(hcd->regs, HC_USBCMD); break; default: @@ -2153,57 +2100,12 @@ error: return retval; } -static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd, - struct usb_host_endpoint *ep) -{ - struct isp1760_hcd *priv = hcd_to_priv(usb_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(usb_hcd, qtd->urb, -ECONNRESET); - spin_lock_irqsave(&priv->lock, flags); - } else { - struct urb *urb; - - urb = qtd->urb; - clean_up_qtdlist(qtd); - isp1760_urb_done(priv, urb, -ECONNRESET); - } - } 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); u32 fr; - fr = isp1760_readl(hcd->regs + HC_FRINDEX); + fr = reg_read32(hcd->regs, HC_FRINDEX); return (fr >> 3) % priv->periodic_size; } @@ -2212,18 +2114,20 @@ static void isp1760_stop(struct usb_hcd *hcd) struct isp1760_hcd *priv = hcd_to_priv(hcd); u32 temp; + del_timer(&errata2_timer); + isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, NULL, 0); mdelay(20); spin_lock_irq(&priv->lock); - ehci_reset(priv); + ehci_reset(hcd); /* Disable IRQ */ - temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); - isp1760_writel(temp &= ~HW_GLOBAL_INTR_EN, hcd->regs + HC_HW_MODE_CTRL); + temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); + reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN); spin_unlock_irq(&priv->lock); - isp1760_writel(0, hcd->regs + HC_CONFIGFLAG); + reg_write32(hcd->regs, HC_CONFIGFLAG, 0); } static void isp1760_shutdown(struct usb_hcd *hcd) @@ -2231,14 +2135,31 @@ static void isp1760_shutdown(struct usb_hcd *hcd) u32 command, temp; isp1760_stop(hcd); - temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); - isp1760_writel(temp &= ~HW_GLOBAL_INTR_EN, hcd->regs + HC_HW_MODE_CTRL); + temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); + reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN); - command = isp1760_readl(hcd->regs + HC_USBCMD); + command = reg_read32(hcd->regs, HC_USBCMD); command &= ~CMD_RUN; - isp1760_writel(command, hcd->regs + HC_USBCMD); + reg_write32(hcd->regs, HC_USBCMD, command); +} + +static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd, + struct usb_host_endpoint *ep) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + struct isp1760_qh *qh = ep->hcpriv; + unsigned long spinflags; + + if (!qh) + return; + + spin_lock_irqsave(&priv->lock, spinflags); + qh->tt_buffer_dirty = 0; + schedule_ptds(hcd); + spin_unlock_irqrestore(&priv->lock, spinflags); } + static const struct hc_driver isp1760_hc_driver = { .description = "isp1760-hcd", .product_desc = "NXP ISP1760 USB Host Controller", @@ -2255,10 +2176,18 @@ static const struct hc_driver isp1760_hc_driver = { .get_frame_number = isp1760_get_frame, .hub_status_data = isp1760_hub_status_data, .hub_control = isp1760_hub_control, + .clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete, }; 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); @@ -2281,10 +2210,12 @@ 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, int irq, unsigned long irqflags, + int rst_gpio, struct device *dev, const char *busname, unsigned int devflags) { @@ -2304,6 +2235,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, priv = hcd_to_priv(hcd); priv->devflags = devflags; + priv->rst_gpio = rst_gpio; init_memory(priv); hcd->regs = ioremap(res_start, res_len); if (!hcd->regs) { @@ -2318,6 +2250,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, ret = usb_add_hcd(hcd, irq, irqflags); if (ret) goto err_unmap; + device_wakeup_enable(hcd->self.controller); return hcd; |
