diff options
Diffstat (limited to 'drivers/usb/host')
| -rw-r--r-- | drivers/usb/host/Kconfig | 39 | ||||
| -rw-r--r-- | drivers/usb/host/Makefile | 4 | ||||
| -rw-r--r-- | drivers/usb/host/isp1760-hcd.c | 2231 | ||||
| -rw-r--r-- | drivers/usb/host/isp1760-hcd.h | 206 | ||||
| -rw-r--r-- | drivers/usb/host/isp1760-if.c | 298 | ||||
| -rw-r--r-- | drivers/usb/host/ohci-hub.c | 2 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-hcd.c | 74 | ||||
| -rw-r--r-- | drivers/usb/host/uhci-hcd.h | 5 |
8 files changed, 2839 insertions, 20 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 0b87480dd713..33b467a8352d 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
| @@ -4,6 +4,19 @@ | |||
| 4 | comment "USB Host Controller Drivers" | 4 | comment "USB Host Controller Drivers" |
| 5 | depends on USB | 5 | depends on USB |
| 6 | 6 | ||
| 7 | config USB_C67X00_HCD | ||
| 8 | tristate "Cypress C67x00 HCD support" | ||
| 9 | depends on USB | ||
| 10 | help | ||
| 11 | The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role | ||
| 12 | host/peripheral/OTG USB controllers. | ||
| 13 | |||
| 14 | Enable this option to support this chip in host controller mode. | ||
| 15 | If unsure, say N. | ||
| 16 | |||
| 17 | To compile this driver as a module, choose M here: the | ||
| 18 | module will be called c67x00. | ||
| 19 | |||
| 7 | config USB_EHCI_HCD | 20 | config USB_EHCI_HCD |
| 8 | tristate "EHCI HCD (USB 2.0) support" | 21 | tristate "EHCI HCD (USB 2.0) support" |
| 9 | depends on USB && USB_ARCH_HAS_EHCI | 22 | depends on USB && USB_ARCH_HAS_EHCI |
| @@ -95,6 +108,32 @@ config USB_ISP116X_HCD | |||
| 95 | To compile this driver as a module, choose M here: the | 108 | To compile this driver as a module, choose M here: the |
| 96 | module will be called isp116x-hcd. | 109 | module will be called isp116x-hcd. |
| 97 | 110 | ||
| 111 | config USB_ISP1760_HCD | ||
| 112 | tristate "ISP 1760 HCD support" | ||
| 113 | depends on USB && EXPERIMENTAL | ||
| 114 | ---help--- | ||
| 115 | The ISP1760 chip is a USB 2.0 host controller. | ||
| 116 | |||
| 117 | This driver does not support isochronous transfers or OTG. | ||
| 118 | |||
| 119 | To compile this driver as a module, choose M here: the | ||
| 120 | module will be called isp1760-hcd. | ||
| 121 | |||
| 122 | config USB_ISP1760_PCI | ||
| 123 | bool "Support for the PCI bus" | ||
| 124 | depends on USB_ISP1760_HCD && PCI | ||
| 125 | ---help--- | ||
| 126 | Enables support for the device present on the PCI bus. | ||
| 127 | This should only be required if you happen to have the eval kit from | ||
| 128 | NXP and you are going to test it. | ||
| 129 | |||
| 130 | config USB_ISP1760_OF | ||
| 131 | bool "Support for the OF platform bus" | ||
| 132 | depends on USB_ISP1760_HCD && OF | ||
| 133 | ---help--- | ||
| 134 | Enables support for the device present on the PowerPC | ||
| 135 | OpenFirmware platform bus. | ||
| 136 | |||
| 98 | config USB_OHCI_HCD | 137 | config USB_OHCI_HCD |
| 99 | tristate "OHCI HCD support" | 138 | tristate "OHCI HCD support" |
| 100 | depends on USB && USB_ARCH_HAS_OHCI | 139 | depends on USB && USB_ARCH_HAS_OHCI |
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index bb8e9d44f371..f1edda2dcfde 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile | |||
| @@ -6,6 +6,8 @@ ifeq ($(CONFIG_USB_DEBUG),y) | |||
| 6 | EXTRA_CFLAGS += -DDEBUG | 6 | EXTRA_CFLAGS += -DDEBUG |
| 7 | endif | 7 | endif |
| 8 | 8 | ||
| 9 | isp1760-objs := isp1760-hcd.o isp1760-if.o | ||
| 10 | |||
| 9 | obj-$(CONFIG_PCI) += pci-quirks.o | 11 | obj-$(CONFIG_PCI) += pci-quirks.o |
| 10 | 12 | ||
| 11 | obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o | 13 | obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o |
| @@ -16,4 +18,4 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o | |||
| 16 | obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o | 18 | obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o |
| 17 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o | 19 | obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o |
| 18 | obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o | 20 | obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o |
| 19 | 21 | obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o | |
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c new file mode 100644 index 000000000000..4ba96c1e060c --- /dev/null +++ b/drivers/usb/host/isp1760-hcd.c | |||
| @@ -0,0 +1,2231 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the NXP ISP1760 chip | ||
| 3 | * | ||
| 4 | * However, the code might contain some bugs. What doesn't work for sure is: | ||
| 5 | * - ISO | ||
| 6 | * - OTG | ||
| 7 | e The interrupt line is configured as active low, level. | ||
| 8 | * | ||
| 9 | * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | #include <linux/usb.h> | ||
| 17 | #include <linux/debugfs.h> | ||
| 18 | #include <linux/uaccess.h> | ||
| 19 | #include <linux/io.h> | ||
| 20 | #include <asm/unaligned.h> | ||
| 21 | |||
| 22 | #include "../core/hcd.h" | ||
| 23 | #include "isp1760-hcd.h" | ||
| 24 | |||
| 25 | static struct kmem_cache *qtd_cachep; | ||
| 26 | static struct kmem_cache *qh_cachep; | ||
| 27 | |||
| 28 | struct isp1760_hcd { | ||
| 29 | u32 hcs_params; | ||
| 30 | spinlock_t lock; | ||
| 31 | struct inter_packet_info atl_ints[32]; | ||
| 32 | struct inter_packet_info int_ints[32]; | ||
| 33 | struct memory_chunk memory_pool[BLOCKS]; | ||
| 34 | |||
| 35 | /* periodic schedule support */ | ||
| 36 | #define DEFAULT_I_TDPS 1024 | ||
| 37 | unsigned periodic_size; | ||
| 38 | unsigned i_thresh; | ||
| 39 | unsigned long reset_done; | ||
| 40 | unsigned long next_statechange; | ||
| 41 | }; | ||
| 42 | |||
| 43 | static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) | ||
| 44 | { | ||
| 45 | return (struct isp1760_hcd *) (hcd->hcd_priv); | ||
| 46 | } | ||
| 47 | static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv) | ||
| 48 | { | ||
| 49 | return container_of((void *) priv, struct usb_hcd, hcd_priv); | ||
| 50 | } | ||
| 51 | |||
| 52 | /* Section 2.2 Host Controller Capability Registers */ | ||
| 53 | #define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ | ||
| 54 | #define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ | ||
| 55 | #define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ | ||
| 56 | #define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ | ||
| 57 | #define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ | ||
| 58 | #define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ | ||
| 59 | #define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ | ||
| 60 | |||
| 61 | /* Section 2.3 Host Controller Operational Registers */ | ||
| 62 | #define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ | ||
| 63 | #define CMD_RESET (1<<1) /* reset HC not bus */ | ||
| 64 | #define CMD_RUN (1<<0) /* start/stop HC */ | ||
| 65 | #define STS_PCD (1<<2) /* port change detect */ | ||
| 66 | #define FLAG_CF (1<<0) /* true: we'll support "high speed" */ | ||
| 67 | |||
| 68 | #define PORT_OWNER (1<<13) /* true: companion hc owns this port */ | ||
| 69 | #define PORT_POWER (1<<12) /* true: has power (see PPC) */ | ||
| 70 | #define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */ | ||
| 71 | #define PORT_RESET (1<<8) /* reset port */ | ||
| 72 | #define PORT_SUSPEND (1<<7) /* suspend port */ | ||
| 73 | #define PORT_RESUME (1<<6) /* resume it */ | ||
| 74 | #define PORT_PE (1<<2) /* port enable */ | ||
| 75 | #define PORT_CSC (1<<1) /* connect status change */ | ||
| 76 | #define PORT_CONNECT (1<<0) /* device connected */ | ||
| 77 | #define PORT_RWC_BITS (PORT_CSC) | ||
| 78 | |||
| 79 | struct isp1760_qtd { | ||
| 80 | struct isp1760_qtd *hw_next; | ||
| 81 | u8 packet_type; | ||
| 82 | u8 toggle; | ||
| 83 | |||
| 84 | void *data_buffer; | ||
| 85 | /* the rest is HCD-private */ | ||
| 86 | struct list_head qtd_list; | ||
| 87 | struct urb *urb; | ||
| 88 | size_t length; | ||
| 89 | |||
| 90 | /* isp special*/ | ||
| 91 | u32 status; | ||
| 92 | #define URB_COMPLETE_NOTIFY (1 << 0) | ||
| 93 | #define URB_ENQUEUED (1 << 1) | ||
| 94 | #define URB_TYPE_ATL (1 << 2) | ||
| 95 | #define URB_TYPE_INT (1 << 3) | ||
| 96 | }; | ||
| 97 | |||
| 98 | struct isp1760_qh { | ||
| 99 | /* first part defined by EHCI spec */ | ||
| 100 | struct list_head qtd_list; | ||
| 101 | struct isp1760_hcd *priv; | ||
| 102 | |||
| 103 | /* periodic schedule info */ | ||
| 104 | unsigned short period; /* polling interval */ | ||
| 105 | struct usb_device *dev; | ||
| 106 | |||
| 107 | u32 toggle; | ||
| 108 | u32 ping; | ||
| 109 | }; | ||
| 110 | |||
| 111 | #define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED) | ||
| 112 | |||
| 113 | static unsigned int isp1760_readl(__u32 __iomem *regs) | ||
| 114 | { | ||
| 115 | return readl(regs); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void isp1760_writel(const unsigned int val, __u32 __iomem *regs) | ||
| 119 | { | ||
| 120 | writel(val, regs); | ||
| 121 | } | ||
| 122 | |||
| 123 | /* | ||
| 124 | * The next two copy via MMIO data to/from the device. memcpy_{to|from}io() | ||
| 125 | * doesn't quite work because some people have to enforce 32-bit access | ||
| 126 | */ | ||
| 127 | static void priv_read_copy(struct isp1760_hcd *priv, u32 *src, | ||
| 128 | __u32 __iomem *dst, u32 offset, u32 len) | ||
| 129 | { | ||
| 130 | struct usb_hcd *hcd = priv_to_hcd(priv); | ||
| 131 | u32 val; | ||
| 132 | u8 *buff8; | ||
| 133 | |||
| 134 | if (!src) { | ||
| 135 | printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len); | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | isp1760_writel(offset, hcd->regs + HC_MEMORY_REG); | ||
| 139 | /* XXX | ||
| 140 | * 90nsec delay, the spec says something how this could be avoided. | ||
| 141 | */ | ||
| 142 | mdelay(1); | ||
| 143 | |||
| 144 | while (len >= 4) { | ||
| 145 | *src = __raw_readl(dst); | ||
| 146 | len -= 4; | ||
| 147 | src++; | ||
| 148 | dst++; | ||
| 149 | } | ||
| 150 | |||
| 151 | if (!len) | ||
| 152 | return; | ||
| 153 | |||
| 154 | /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully | ||
| 155 | * allocated. | ||
| 156 | */ | ||
| 157 | val = isp1760_readl(dst); | ||
| 158 | |||
| 159 | buff8 = (u8 *)src; | ||
| 160 | while (len) { | ||
| 161 | |||
| 162 | *buff8 = val; | ||
| 163 | val >>= 8; | ||
| 164 | len--; | ||
| 165 | buff8++; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src, | ||
| 170 | __u32 __iomem *dst, u32 len) | ||
| 171 | { | ||
| 172 | while (len >= 4) { | ||
| 173 | __raw_writel(*src, dst); | ||
| 174 | len -= 4; | ||
| 175 | src++; | ||
| 176 | dst++; | ||
| 177 | } | ||
| 178 | |||
| 179 | if (!len) | ||
| 180 | return; | ||
| 181 | /* in case we have 3, 2 or 1 by left. The buffer is allocated and the | ||
| 182 | * extra bytes should not be read by the HW | ||
| 183 | */ | ||
| 184 | |||
| 185 | __raw_writel(*src, dst); | ||
| 186 | } | ||
| 187 | |||
| 188 | /* memory management of the 60kb on the chip from 0x1000 to 0xffff */ | ||
| 189 | static void init_memory(struct isp1760_hcd *priv) | ||
| 190 | { | ||
| 191 | int i; | ||
| 192 | u32 payload; | ||
| 193 | |||
| 194 | payload = 0x1000; | ||
| 195 | for (i = 0; i < BLOCK_1_NUM; i++) { | ||
| 196 | priv->memory_pool[i].start = payload; | ||
| 197 | priv->memory_pool[i].size = BLOCK_1_SIZE; | ||
| 198 | priv->memory_pool[i].free = 1; | ||
| 199 | payload += priv->memory_pool[i].size; | ||
| 200 | } | ||
| 201 | |||
| 202 | |||
| 203 | for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) { | ||
| 204 | priv->memory_pool[i].start = payload; | ||
| 205 | priv->memory_pool[i].size = BLOCK_2_SIZE; | ||
| 206 | priv->memory_pool[i].free = 1; | ||
| 207 | payload += priv->memory_pool[i].size; | ||
| 208 | } | ||
| 209 | |||
| 210 | |||
| 211 | for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) { | ||
| 212 | priv->memory_pool[i].start = payload; | ||
| 213 | priv->memory_pool[i].size = BLOCK_3_SIZE; | ||
| 214 | priv->memory_pool[i].free = 1; | ||
| 215 | payload += priv->memory_pool[i].size; | ||
| 216 | } | ||
| 217 | |||
| 218 | BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE); | ||
| 219 | } | ||
| 220 | |||
| 221 | static u32 alloc_mem(struct isp1760_hcd *priv, u32 size) | ||
| 222 | { | ||
| 223 | int i; | ||
| 224 | |||
| 225 | if (!size) | ||
| 226 | return ISP1760_NULL_POINTER; | ||
| 227 | |||
| 228 | for (i = 0; i < BLOCKS; i++) { | ||
| 229 | if (priv->memory_pool[i].size >= size && | ||
| 230 | priv->memory_pool[i].free) { | ||
| 231 | |||
| 232 | priv->memory_pool[i].free = 0; | ||
| 233 | return priv->memory_pool[i].start; | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n", | ||
| 238 | size); | ||
| 239 | printk(KERN_ERR "Current memory map:\n"); | ||
| 240 | for (i = 0; i < BLOCKS; i++) { | ||
| 241 | printk(KERN_ERR "Pool %2d size %4d status: %d\n", | ||
| 242 | i, priv->memory_pool[i].size, | ||
| 243 | priv->memory_pool[i].free); | ||
| 244 | } | ||
| 245 | /* XXX maybe -ENOMEM could be possible */ | ||
| 246 | BUG(); | ||
| 247 | return 0; | ||
| 248 | } | ||
| 249 | |||
| 250 | static void free_mem(struct isp1760_hcd *priv, u32 mem) | ||
| 251 | { | ||
| 252 | int i; | ||
| 253 | |||
| 254 | if (mem == ISP1760_NULL_POINTER) | ||
| 255 | return; | ||
| 256 | |||
| 257 | for (i = 0; i < BLOCKS; i++) { | ||
| 258 | if (priv->memory_pool[i].start == mem) { | ||
| 259 | |||
| 260 | BUG_ON(priv->memory_pool[i].free); | ||
| 261 | |||
| 262 | priv->memory_pool[i].free = 1; | ||
| 263 | return ; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n", | ||
| 268 | mem); | ||
| 269 | BUG(); | ||
| 270 | } | ||
| 271 | |||
| 272 | static void isp1760_init_regs(struct usb_hcd *hcd) | ||
| 273 | { | ||
| 274 | isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG); | ||
| 275 | isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + | ||
| 276 | HC_ATL_PTD_SKIPMAP_REG); | ||
| 277 | isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + | ||
| 278 | HC_INT_PTD_SKIPMAP_REG); | ||
| 279 | isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + | ||
| 280 | HC_ISO_PTD_SKIPMAP_REG); | ||
| 281 | |||
| 282 | isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + | ||
| 283 | HC_ATL_PTD_DONEMAP_REG); | ||
| 284 | isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + | ||
| 285 | HC_INT_PTD_DONEMAP_REG); | ||
| 286 | isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + | ||
| 287 | HC_ISO_PTD_DONEMAP_REG); | ||
| 288 | } | ||
| 289 | |||
| 290 | static int handshake(struct isp1760_hcd *priv, void __iomem *ptr, | ||
| 291 | u32 mask, u32 done, int usec) | ||
| 292 | { | ||
| 293 | u32 result; | ||
| 294 | |||
| 295 | do { | ||
| 296 | result = isp1760_readl(ptr); | ||
| 297 | if (result == ~0) | ||
| 298 | return -ENODEV; | ||
| 299 | result &= mask; | ||
| 300 | if (result == done) | ||
| 301 | return 0; | ||
| 302 | udelay(1); | ||
| 303 | usec--; | ||
| 304 | } while (usec > 0); | ||
| 305 | return -ETIMEDOUT; | ||
| 306 | } | ||
| 307 | |||
| 308 | /* reset a non-running (STS_HALT == 1) controller */ | ||
| 309 | static int ehci_reset(struct isp1760_hcd *priv) | ||
| 310 | { | ||
| 311 | int retval; | ||
| 312 | struct usb_hcd *hcd = priv_to_hcd(priv); | ||
| 313 | u32 command = isp1760_readl(hcd->regs + HC_USBCMD); | ||
| 314 | |||
| 315 | command |= CMD_RESET; | ||
| 316 | isp1760_writel(command, hcd->regs + HC_USBCMD); | ||
| 317 | hcd->state = HC_STATE_HALT; | ||
| 318 | priv->next_statechange = jiffies; | ||
| 319 | retval = handshake(priv, hcd->regs + HC_USBCMD, | ||
| 320 | CMD_RESET, 0, 250 * 1000); | ||
| 321 | return retval; | ||
| 322 | } | ||
| 323 | |||
| 324 | static void qh_destroy(struct isp1760_qh *qh) | ||
| 325 | { | ||
| 326 | BUG_ON(!list_empty(&qh->qtd_list)); | ||
| 327 | kmem_cache_free(qh_cachep, qh); | ||
| 328 | } | ||
| 329 | |||
| 330 | static struct isp1760_qh *isp1760_qh_alloc(struct isp1760_hcd *priv, | ||
| 331 | gfp_t flags) | ||
| 332 | { | ||
| 333 | struct isp1760_qh *qh; | ||
| 334 | |||
| 335 | qh = kmem_cache_zalloc(qh_cachep, flags); | ||
| 336 | if (!qh) | ||
| 337 | return qh; | ||
| 338 | |||
| 339 | INIT_LIST_HEAD(&qh->qtd_list); | ||
| 340 | qh->priv = priv; | ||
| 341 | return qh; | ||
| 342 | } | ||
| 343 | |||
| 344 | /* magic numbers that can affect system performance */ | ||
| 345 | #define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ | ||
| 346 | #define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ | ||
| 347 | #define EHCI_TUNE_RL_TT 0 | ||
| 348 | #define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ | ||
| 349 | #define EHCI_TUNE_MULT_TT 1 | ||
| 350 | #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ | ||
| 351 | |||
| 352 | /* one-time init, only for memory state */ | ||
| 353 | static int priv_init(struct usb_hcd *hcd) | ||
| 354 | { | ||
| 355 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 356 | u32 hcc_params; | ||
| 357 | |||
| 358 | spin_lock_init(&priv->lock); | ||
| 359 | |||
| 360 | /* | ||
| 361 | * hw default: 1K periodic list heads, one per frame. | ||
| 362 | * periodic_size can shrink by USBCMD update if hcc_params allows. | ||
| 363 | */ | ||
| 364 | priv->periodic_size = DEFAULT_I_TDPS; | ||
| 365 | |||
| 366 | /* controllers may cache some of the periodic schedule ... */ | ||
| 367 | hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS); | ||
| 368 | /* full frame cache */ | ||
| 369 | if (HCC_ISOC_CACHE(hcc_params)) | ||
| 370 | priv->i_thresh = 8; | ||
| 371 | else /* N microframes cached */ | ||
| 372 | priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); | ||
| 373 | |||
| 374 | return 0; | ||
| 375 | } | ||
| 376 | |||
| 377 | static int isp1760_hc_setup(struct usb_hcd *hcd) | ||
| 378 | { | ||
| 379 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 380 | int result; | ||
| 381 | u32 scratch; | ||
| 382 | |||
| 383 | isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG); | ||
| 384 | scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG); | ||
| 385 | if (scratch != 0xdeadbabe) { | ||
| 386 | printk(KERN_ERR "ISP1760: Scratch test failed.\n"); | ||
| 387 | return -ENODEV; | ||
| 388 | } | ||
| 389 | |||
| 390 | /* pre reset */ | ||
| 391 | isp1760_init_regs(hcd); | ||
| 392 | |||
| 393 | /* reset */ | ||
| 394 | isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG); | ||
| 395 | mdelay(100); | ||
| 396 | |||
| 397 | isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG); | ||
| 398 | mdelay(100); | ||
| 399 | |||
| 400 | result = ehci_reset(priv); | ||
| 401 | if (result) | ||
| 402 | return result; | ||
| 403 | |||
| 404 | /* Step 11 passed */ | ||
| 405 | |||
| 406 | isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG); | ||
| 407 | isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE); | ||
| 408 | |||
| 409 | /* ATL reset */ | ||
| 410 | scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); | ||
| 411 | isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL); | ||
| 412 | mdelay(10); | ||
| 413 | isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL); | ||
| 414 | |||
| 415 | isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL); | ||
| 416 | mdelay(10); | ||
| 417 | |||
| 418 | priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS); | ||
| 419 | |||
| 420 | return priv_init(hcd); | ||
| 421 | } | ||
| 422 | |||
| 423 | static void isp1760_init_maps(struct usb_hcd *hcd) | ||
| 424 | { | ||
| 425 | /*set last maps, for iso its only 1, else 32 tds bitmap*/ | ||
| 426 | isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG); | ||
| 427 | isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG); | ||
| 428 | isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG); | ||
| 429 | } | ||
| 430 | |||
| 431 | static void isp1760_enable_interrupts(struct usb_hcd *hcd) | ||
| 432 | { | ||
| 433 | isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG); | ||
| 434 | isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); | ||
| 435 | isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG); | ||
| 436 | isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG); | ||
| 437 | isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG); | ||
| 438 | isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG); | ||
| 439 | /* step 23 passed */ | ||
| 440 | } | ||
| 441 | |||
| 442 | static int isp1760_run(struct usb_hcd *hcd) | ||
| 443 | { | ||
| 444 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 445 | int retval; | ||
| 446 | u32 temp; | ||
| 447 | u32 command; | ||
| 448 | u32 chipid; | ||
| 449 | |||
| 450 | hcd->uses_new_polling = 1; | ||
| 451 | hcd->poll_rh = 0; | ||
| 452 | |||
| 453 | hcd->state = HC_STATE_RUNNING; | ||
| 454 | isp1760_enable_interrupts(hcd); | ||
| 455 | temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); | ||
| 456 | temp |= FINAL_HW_CONFIG; | ||
| 457 | isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL); | ||
| 458 | |||
| 459 | command = isp1760_readl(hcd->regs + HC_USBCMD); | ||
| 460 | command &= ~(CMD_LRESET|CMD_RESET); | ||
| 461 | command |= CMD_RUN; | ||
| 462 | isp1760_writel(command, hcd->regs + HC_USBCMD); | ||
| 463 | |||
| 464 | retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN, | ||
| 465 | 250 * 1000); | ||
| 466 | if (retval) | ||
| 467 | return retval; | ||
| 468 | |||
| 469 | /* | ||
| 470 | * XXX | ||
| 471 | * Spec says to write FLAG_CF as last config action, priv code grabs | ||
| 472 | * the semaphore while doing so. | ||
| 473 | */ | ||
| 474 | down_write(&ehci_cf_port_reset_rwsem); | ||
| 475 | isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG); | ||
| 476 | |||
| 477 | retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF, | ||
| 478 | 250 * 1000); | ||
| 479 | up_write(&ehci_cf_port_reset_rwsem); | ||
| 480 | if (retval) | ||
| 481 | return retval; | ||
| 482 | |||
| 483 | chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG); | ||
| 484 | isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff, | ||
| 485 | chipid >> 16); | ||
| 486 | |||
| 487 | /* PTD Register Init Part 2, Step 28 */ | ||
| 488 | /* enable INTs */ | ||
| 489 | isp1760_init_maps(hcd); | ||
| 490 | |||
| 491 | /* GRR this is run-once init(), being done every time the HC starts. | ||
| 492 | * So long as they're part of class devices, we can't do it init() | ||
| 493 | * since the class device isn't created that early. | ||
| 494 | */ | ||
| 495 | return 0; | ||
| 496 | } | ||
| 497 | |||
| 498 | static u32 base_to_chip(u32 base) | ||
| 499 | { | ||
| 500 | return ((base - 0x400) >> 3); | ||
| 501 | } | ||
| 502 | |||
| 503 | static void transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh, | ||
| 504 | struct isp1760_qtd *qtd, struct urb *urb, | ||
| 505 | u32 payload, struct ptd *ptd) | ||
| 506 | { | ||
| 507 | u32 dw0; | ||
| 508 | u32 dw1; | ||
| 509 | u32 dw2; | ||
| 510 | u32 dw3; | ||
| 511 | u32 maxpacket; | ||
| 512 | u32 multi; | ||
| 513 | u32 pid_code; | ||
| 514 | u32 rl = RL_COUNTER; | ||
| 515 | u32 nak = NAK_COUNTER; | ||
| 516 | |||
| 517 | /* according to 3.6.2, max packet len can not be > 0x400 */ | ||
| 518 | maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); | ||
| 519 | multi = 1 + ((maxpacket >> 11) & 0x3); | ||
| 520 | maxpacket &= 0x7ff; | ||
| 521 | |||
| 522 | /* DW0 */ | ||
| 523 | dw0 = PTD_VALID; | ||
| 524 | dw0 |= PTD_LENGTH(qtd->length); | ||
| 525 | dw0 |= PTD_MAXPACKET(maxpacket); | ||
| 526 | dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe)); | ||
| 527 | dw1 = usb_pipeendpoint(urb->pipe) >> 1; | ||
| 528 | |||
| 529 | /* DW1 */ | ||
| 530 | dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe)); | ||
| 531 | |||
| 532 | pid_code = qtd->packet_type; | ||
| 533 | dw1 |= PTD_PID_TOKEN(pid_code); | ||
| 534 | |||
| 535 | if (usb_pipebulk(urb->pipe)) | ||
| 536 | dw1 |= PTD_TRANS_BULK; | ||
| 537 | else if (usb_pipeint(urb->pipe)) | ||
| 538 | dw1 |= PTD_TRANS_INT; | ||
| 539 | |||
| 540 | if (urb->dev->speed != USB_SPEED_HIGH) { | ||
| 541 | /* split transaction */ | ||
| 542 | |||
| 543 | dw1 |= PTD_TRANS_SPLIT; | ||
| 544 | if (urb->dev->speed == USB_SPEED_LOW) | ||
| 545 | dw1 |= PTD_SE_USB_LOSPEED; | ||
| 546 | |||
| 547 | dw1 |= PTD_PORT_NUM(urb->dev->ttport); | ||
| 548 | dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum); | ||
| 549 | |||
| 550 | /* SE bit for Split INT transfers */ | ||
| 551 | if (usb_pipeint(urb->pipe) && | ||
| 552 | (urb->dev->speed == USB_SPEED_LOW)) | ||
| 553 | dw1 |= 2 << 16; | ||
| 554 | |||
| 555 | dw3 = 0; | ||
| 556 | rl = 0; | ||
| 557 | nak = 0; | ||
| 558 | } else { | ||
| 559 | dw0 |= PTD_MULTI(multi); | ||
| 560 | if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) | ||
| 561 | dw3 = qh->ping; | ||
| 562 | else | ||
| 563 | dw3 = 0; | ||
| 564 | } | ||
| 565 | /* DW2 */ | ||
| 566 | dw2 = 0; | ||
| 567 | dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload)); | ||
| 568 | dw2 |= PTD_RL_CNT(rl); | ||
| 569 | dw3 |= PTD_NAC_CNT(nak); | ||
| 570 | |||
| 571 | /* DW3 */ | ||
| 572 | if (usb_pipecontrol(urb->pipe)) | ||
| 573 | dw3 |= PTD_DATA_TOGGLE(qtd->toggle); | ||
| 574 | else | ||
| 575 | dw3 |= qh->toggle; | ||
| 576 | |||
| 577 | |||
| 578 | dw3 |= PTD_ACTIVE; | ||
| 579 | /* Cerr */ | ||
| 580 | dw3 |= PTD_CERR(ERR_COUNTER); | ||
| 581 | |||
| 582 | memset(ptd, 0, sizeof(*ptd)); | ||
| 583 | |||
| 584 | ptd->dw0 = cpu_to_le32(dw0); | ||
| 585 | ptd->dw1 = cpu_to_le32(dw1); | ||
| 586 | ptd->dw2 = cpu_to_le32(dw2); | ||
| 587 | ptd->dw3 = cpu_to_le32(dw3); | ||
| 588 | } | ||
| 589 | |||
| 590 | static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, | ||
| 591 | struct isp1760_qtd *qtd, struct urb *urb, | ||
| 592 | u32 payload, struct ptd *ptd) | ||
| 593 | { | ||
| 594 | u32 maxpacket; | ||
| 595 | u32 multi; | ||
| 596 | u32 numberofusofs; | ||
| 597 | u32 i; | ||
| 598 | u32 usofmask, usof; | ||
| 599 | u32 period; | ||
| 600 | |||
| 601 | maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); | ||
| 602 | multi = 1 + ((maxpacket >> 11) & 0x3); | ||
| 603 | maxpacket &= 0x7ff; | ||
| 604 | /* length of the data per uframe */ | ||
| 605 | maxpacket = multi * maxpacket; | ||
| 606 | |||
| 607 | numberofusofs = urb->transfer_buffer_length / maxpacket; | ||
| 608 | if (urb->transfer_buffer_length % maxpacket) | ||
| 609 | numberofusofs += 1; | ||
| 610 | |||
| 611 | usofmask = 1; | ||
| 612 | usof = 0; | ||
| 613 | for (i = 0; i < numberofusofs; i++) { | ||
| 614 | usof |= usofmask; | ||
| 615 | usofmask <<= 1; | ||
| 616 | } | ||
| 617 | |||
| 618 | if (urb->dev->speed != USB_SPEED_HIGH) { | ||
| 619 | /* split */ | ||
| 620 | ptd->dw5 = __constant_cpu_to_le32(0x1c); | ||
| 621 | |||
| 622 | if (qh->period >= 32) | ||
| 623 | period = qh->period / 2; | ||
| 624 | else | ||
| 625 | period = qh->period; | ||
| 626 | |||
| 627 | } else { | ||
| 628 | |||
| 629 | if (qh->period >= 8) | ||
| 630 | period = qh->period/8; | ||
| 631 | else | ||
| 632 | period = qh->period; | ||
| 633 | |||
| 634 | if (period >= 32) | ||
| 635 | period = 16; | ||
| 636 | |||
| 637 | if (qh->period >= 8) { | ||
| 638 | /* millisecond period */ | ||
| 639 | period = (period << 3); | ||
| 640 | } else { | ||
| 641 | /* usof based tranmsfers */ | ||
| 642 | /* minimum 4 usofs */ | ||
| 643 | usof = 0x11; | ||
| 644 | } | ||
| 645 | } | ||
| 646 | |||
| 647 | ptd->dw2 |= cpu_to_le32(period); | ||
| 648 | ptd->dw4 = cpu_to_le32(usof); | ||
| 649 | } | ||
| 650 | |||
| 651 | static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, | ||
| 652 | struct isp1760_qtd *qtd, struct urb *urb, | ||
| 653 | u32 payload, struct ptd *ptd) | ||
| 654 | { | ||
| 655 | transform_into_atl(priv, qh, qtd, urb, payload, ptd); | ||
| 656 | transform_add_int(priv, qh, qtd, urb, payload, ptd); | ||
| 657 | } | ||
| 658 | |||
| 659 | static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len, | ||
| 660 | u32 token) | ||
| 661 | { | ||
| 662 | int count; | ||
| 663 | |||
| 664 | qtd->data_buffer = databuffer; | ||
| 665 | qtd->packet_type = GET_QTD_TOKEN_TYPE(token); | ||
| 666 | qtd->toggle = GET_DATA_TOGGLE(token); | ||
| 667 | |||
| 668 | if (len > HC_ATL_PL_SIZE) | ||
| 669 | count = HC_ATL_PL_SIZE; | ||
| 670 | else | ||
| 671 | count = len; | ||
| 672 | |||
| 673 | qtd->length = count; | ||
| 674 | return count; | ||
| 675 | } | ||
| 676 | |||
| 677 | static int check_error(struct ptd *ptd) | ||
| 678 | { | ||
| 679 | int error = 0; | ||
| 680 | u32 dw3; | ||
| 681 | |||
| 682 | dw3 = le32_to_cpu(ptd->dw3); | ||
| 683 | if (dw3 & DW3_HALT_BIT) | ||
| 684 | error = -EPIPE; | ||
| 685 | |||
| 686 | if (dw3 & DW3_ERROR_BIT) { | ||
| 687 | printk(KERN_ERR "error bit is set in DW3\n"); | ||
| 688 | error = -EPIPE; | ||
| 689 | } | ||
| 690 | |||
| 691 | if (dw3 & DW3_QTD_ACTIVE) { | ||
| 692 | printk(KERN_ERR "transfer active bit is set DW3\n"); | ||
| 693 | printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf, | ||
| 694 | (le32_to_cpu(ptd->dw2) >> 25) & 0xf); | ||
| 695 | } | ||
| 696 | |||
| 697 | return error; | ||
| 698 | } | ||
| 699 | |||
| 700 | static void check_int_err_status(u32 dw4) | ||
| 701 | { | ||
| 702 | u32 i; | ||
| 703 | |||
| 704 | dw4 >>= 8; | ||
| 705 | |||
| 706 | for (i = 0; i < 8; i++) { | ||
| 707 | switch (dw4 & 0x7) { | ||
| 708 | case INT_UNDERRUN: | ||
| 709 | printk(KERN_ERR "ERROR: under run , %d\n", i); | ||
| 710 | break; | ||
| 711 | |||
| 712 | case INT_EXACT: | ||
| 713 | printk(KERN_ERR "ERROR: transaction error, %d\n", i); | ||
| 714 | break; | ||
| 715 | |||
| 716 | case INT_BABBLE: | ||
| 717 | printk(KERN_ERR "ERROR: babble error, %d\n", i); | ||
| 718 | break; | ||
| 719 | } | ||
| 720 | dw4 >>= 3; | ||
| 721 | } | ||
| 722 | } | ||
| 723 | |||
| 724 | static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv, | ||
| 725 | u32 payload) | ||
| 726 | { | ||
| 727 | u32 token; | ||
| 728 | struct usb_hcd *hcd = priv_to_hcd(priv); | ||
| 729 | |||
| 730 | token = qtd->packet_type; | ||
| 731 | |||
| 732 | if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) { | ||
| 733 | switch (token) { | ||
| 734 | case IN_PID: | ||
| 735 | break; | ||
| 736 | case OUT_PID: | ||
| 737 | case SETUP_PID: | ||
| 738 | priv_write_copy(priv, qtd->data_buffer, | ||
| 739 | hcd->regs + payload, | ||
| 740 | qtd->length); | ||
| 741 | } | ||
| 742 | } | ||
| 743 | } | ||
| 744 | |||
| 745 | static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload, | ||
| 746 | struct isp1760_hcd *priv, struct isp1760_qh *qh, | ||
| 747 | struct urb *urb, u32 slot, struct isp1760_qtd *qtd) | ||
| 748 | { | ||
| 749 | struct ptd ptd; | ||
| 750 | struct usb_hcd *hcd = priv_to_hcd(priv); | ||
| 751 | |||
| 752 | transform_into_atl(priv, qh, qtd, urb, payload, &ptd); | ||
| 753 | priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd)); | ||
| 754 | enqueue_one_qtd(qtd, priv, payload); | ||
| 755 | |||
| 756 | priv->atl_ints[slot].urb = urb; | ||
| 757 | priv->atl_ints[slot].qh = qh; | ||
| 758 | priv->atl_ints[slot].qtd = qtd; | ||
| 759 | priv->atl_ints[slot].data_buffer = qtd->data_buffer; | ||
| 760 | priv->atl_ints[slot].payload = payload; | ||
| 761 | qtd->status |= URB_ENQUEUED | URB_TYPE_ATL; | ||
| 762 | qtd->status |= slot << 16; | ||
| 763 | } | ||
| 764 | |||
| 765 | static void enqueue_one_int_qtd(u32 int_regs, u32 payload, | ||
| 766 | struct isp1760_hcd *priv, struct isp1760_qh *qh, | ||
| 767 | struct urb *urb, u32 slot, struct isp1760_qtd *qtd) | ||
| 768 | { | ||
| 769 | struct ptd ptd; | ||
| 770 | struct usb_hcd *hcd = priv_to_hcd(priv); | ||
| 771 | |||
| 772 | transform_into_int(priv, qh, qtd, urb, payload, &ptd); | ||
| 773 | priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd)); | ||
| 774 | enqueue_one_qtd(qtd, priv, payload); | ||
| 775 | |||
| 776 | priv->int_ints[slot].urb = urb; | ||
| 777 | priv->int_ints[slot].qh = qh; | ||
| 778 | priv->int_ints[slot].qtd = qtd; | ||
| 779 | priv->int_ints[slot].data_buffer = qtd->data_buffer; | ||
| 780 | priv->int_ints[slot].payload = payload; | ||
| 781 | qtd->status |= URB_ENQUEUED | URB_TYPE_INT; | ||
| 782 | qtd->status |= slot << 16; | ||
| 783 | } | ||
| 784 | |||
| 785 | void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, | ||
| 786 | struct isp1760_qtd *qtd) | ||
| 787 | { | ||
| 788 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 789 | u32 skip_map, or_map; | ||
| 790 | u32 queue_entry; | ||
| 791 | u32 slot; | ||
| 792 | u32 atl_regs, payload; | ||
| 793 | u32 buffstatus; | ||
| 794 | |||
| 795 | skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG); | ||
| 796 | |||
| 797 | BUG_ON(!skip_map); | ||
| 798 | slot = __ffs(skip_map); | ||
| 799 | queue_entry = 1 << slot; | ||
| 800 | |||
| 801 | atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd); | ||
| 802 | |||
| 803 | payload = alloc_mem(priv, qtd->length); | ||
| 804 | |||
| 805 | enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd); | ||
| 806 | |||
| 807 | or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG); | ||
| 808 | or_map |= queue_entry; | ||
| 809 | isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); | ||
| 810 | |||
| 811 | skip_map &= ~queue_entry; | ||
| 812 | isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG); | ||
| 813 | |||
| 814 | buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); | ||
| 815 | buffstatus |= ATL_BUFFER; | ||
| 816 | isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); | ||
| 817 | } | ||
| 818 | |||
| 819 | void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, | ||
| 820 | struct isp1760_qtd *qtd) | ||
| 821 | { | ||
| 822 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 823 | u32 skip_map, or_map; | ||
| 824 | u32 queue_entry; | ||
| 825 | u32 slot; | ||
| 826 | u32 int_regs, payload; | ||
| 827 | u32 buffstatus; | ||
| 828 | |||
| 829 | skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG); | ||
| 830 | |||
| 831 | BUG_ON(!skip_map); | ||
| 832 | slot = __ffs(skip_map); | ||
| 833 | queue_entry = 1 << slot; | ||
| 834 | |||
| 835 | int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd); | ||
| 836 | |||
| 837 | payload = alloc_mem(priv, qtd->length); | ||
| 838 | |||
| 839 | enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd); | ||
| 840 | |||
| 841 | or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG); | ||
| 842 | or_map |= queue_entry; | ||
| 843 | isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG); | ||
| 844 | |||
| 845 | skip_map &= ~queue_entry; | ||
| 846 | isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG); | ||
| 847 | |||
| 848 | buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); | ||
| 849 | buffstatus |= INT_BUFFER; | ||
| 850 | isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); | ||
| 851 | } | ||
| 852 | |||
| 853 | static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status) | ||
| 854 | __releases(priv->lock) | ||
| 855 | __acquires(priv->lock) | ||
| 856 | { | ||
| 857 | if (!urb->unlinked) { | ||
| 858 | if (status == -EINPROGRESS) | ||
| 859 | status = 0; | ||
| 860 | } | ||
| 861 | |||
| 862 | /* complete() can reenter this HCD */ | ||
| 863 | usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); | ||
| 864 | spin_unlock(&priv->lock); | ||
| 865 | usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status); | ||
| 866 | spin_lock(&priv->lock); | ||
| 867 | } | ||
| 868 | |||
| 869 | static void isp1760_qtd_free(struct isp1760_qtd *qtd) | ||
| 870 | { | ||
| 871 | kmem_cache_free(qtd_cachep, qtd); | ||
| 872 | } | ||
| 873 | |||
| 874 | static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd) | ||
| 875 | { | ||
| 876 | struct isp1760_qtd *tmp_qtd; | ||
| 877 | |||
| 878 | tmp_qtd = qtd->hw_next; | ||
| 879 | list_del(&qtd->qtd_list); | ||
| 880 | isp1760_qtd_free(qtd); | ||
| 881 | return tmp_qtd; | ||
| 882 | } | ||
| 883 | |||
| 884 | /* | ||
| 885 | * Remove this QTD from the QH list and free its memory. If this QTD | ||
| 886 | * isn't the last one than remove also his successor(s). | ||
| 887 | * Returns the QTD which is part of an new URB and should be enqueued. | ||
| 888 | */ | ||
| 889 | static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd) | ||
| 890 | { | ||
| 891 | struct isp1760_qtd *tmp_qtd; | ||
| 892 | int last_one; | ||
| 893 | |||
| 894 | do { | ||
| 895 | tmp_qtd = qtd->hw_next; | ||
| 896 | last_one = qtd->status & URB_COMPLETE_NOTIFY; | ||
| 897 | list_del(&qtd->qtd_list); | ||
| 898 | isp1760_qtd_free(qtd); | ||
| 899 | qtd = tmp_qtd; | ||
| 900 | } while (!last_one && qtd); | ||
| 901 | |||
| 902 | return qtd; | ||
| 903 | } | ||
| 904 | |||
| 905 | static void do_atl_int(struct usb_hcd *usb_hcd) | ||
| 906 | { | ||
| 907 | struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); | ||
| 908 | u32 done_map, skip_map; | ||
| 909 | struct ptd ptd; | ||
| 910 | struct urb *urb = NULL; | ||
| 911 | u32 atl_regs_base; | ||
| 912 | u32 atl_regs; | ||
| 913 | u32 queue_entry; | ||
| 914 | u32 payload; | ||
| 915 | u32 length; | ||
| 916 | u32 or_map; | ||
| 917 | u32 status = -EINVAL; | ||
| 918 | int error; | ||
| 919 | struct isp1760_qtd *qtd; | ||
| 920 | struct isp1760_qh *qh; | ||
| 921 | u32 rl; | ||
| 922 | u32 nakcount; | ||
| 923 | |||
| 924 | done_map = isp1760_readl(usb_hcd->regs + | ||
| 925 | HC_ATL_PTD_DONEMAP_REG); | ||
| 926 | skip_map = isp1760_readl(usb_hcd->regs + | ||
| 927 | HC_ATL_PTD_SKIPMAP_REG); | ||
| 928 | |||
| 929 | or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); | ||
| 930 | or_map &= ~done_map; | ||
| 931 | isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); | ||
| 932 | |||
| 933 | atl_regs_base = ATL_REGS_OFFSET; | ||
| 934 | while (done_map) { | ||
| 935 | u32 dw1; | ||
| 936 | u32 dw2; | ||
| 937 | u32 dw3; | ||
| 938 | |||
| 939 | status = 0; | ||
| 940 | |||
| 941 | queue_entry = __ffs(done_map); | ||
| 942 | done_map &= ~(1 << queue_entry); | ||
| 943 | skip_map |= 1 << queue_entry; | ||
| 944 | |||
| 945 | atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd); | ||
| 946 | |||
| 947 | urb = priv->atl_ints[queue_entry].urb; | ||
| 948 | qtd = priv->atl_ints[queue_entry].qtd; | ||
| 949 | qh = priv->atl_ints[queue_entry].qh; | ||
| 950 | payload = priv->atl_ints[queue_entry].payload; | ||
| 951 | |||
| 952 | if (!qh) { | ||
| 953 | printk(KERN_ERR "qh is 0\n"); | ||
| 954 | continue; | ||
| 955 | } | ||
| 956 | priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs, | ||
| 957 | atl_regs, sizeof(ptd)); | ||
| 958 | |||
| 959 | dw1 = le32_to_cpu(ptd.dw1); | ||
| 960 | dw2 = le32_to_cpu(ptd.dw2); | ||
| 961 | dw3 = le32_to_cpu(ptd.dw3); | ||
| 962 | rl = (dw2 >> 25) & 0x0f; | ||
| 963 | nakcount = (dw3 >> 19) & 0xf; | ||
| 964 | |||
| 965 | /* Transfer Error, *but* active and no HALT -> reload */ | ||
| 966 | if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) && | ||
| 967 | !(dw3 & DW3_HALT_BIT)) { | ||
| 968 | |||
| 969 | /* according to ppriv code, we have to | ||
| 970 | * reload this one if trasfered bytes != requested bytes | ||
| 971 | * else act like everything went smooth.. | ||
| 972 | * XXX This just doesn't feel right and hasn't | ||
| 973 | * triggered so far. | ||
| 974 | */ | ||
| 975 | |||
| 976 | length = PTD_XFERRED_LENGTH(dw3); | ||
| 977 | printk(KERN_ERR "Should reload now.... transfered %d " | ||
| 978 | "of %zu\n", length, qtd->length); | ||
| 979 | BUG(); | ||
| 980 | } | ||
| 981 | |||
| 982 | if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) { | ||
| 983 | u32 buffstatus; | ||
| 984 | |||
| 985 | /* XXX | ||
| 986 | * NAKs are handled in HW by the chip. Usually if the | ||
| 987 | * device is not able to send data fast enough. | ||
| 988 | * This did not trigger for a long time now. | ||
| 989 | */ | ||
| 990 | printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: " | ||
| 991 | "%d of %d done: %08x cur: %08x\n", qtd, | ||
| 992 | urb, qh, PTD_XFERRED_LENGTH(dw3), | ||
| 993 | qtd->length, done_map, | ||
| 994 | (1 << queue_entry)); | ||
| 995 | |||
| 996 | /* RL counter = ERR counter */ | ||
| 997 | dw3 &= ~(0xf << 19); | ||
| 998 | dw3 |= rl << 19; | ||
| 999 | dw3 &= ~(3 << (55 - 32)); | ||
| 1000 | dw3 |= ERR_COUNTER << (55 - 32); | ||
| 1001 | |||
| 1002 | /* | ||
| 1003 | * It is not needed to write skip map back because it | ||
| 1004 | * is unchanged. Just make sure that this entry is | ||
| 1005 | * unskipped once it gets written to the HW. | ||
| 1006 | */ | ||
| 1007 | skip_map &= ~(1 << queue_entry); | ||
| 1008 | or_map = isp1760_readl(usb_hcd->regs + | ||
| 1009 | HC_ATL_IRQ_MASK_OR_REG); | ||
| 1010 | or_map |= 1 << queue_entry; | ||
| 1011 | isp1760_writel(or_map, usb_hcd->regs + | ||
| 1012 | HC_ATL_IRQ_MASK_OR_REG); | ||
| 1013 | |||
| 1014 | ptd.dw3 = cpu_to_le32(dw3); | ||
| 1015 | priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + | ||
| 1016 | atl_regs, sizeof(ptd)); | ||
| 1017 | |||
| 1018 | ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID); | ||
| 1019 | priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + | ||
| 1020 | atl_regs, sizeof(ptd)); | ||
| 1021 | |||
| 1022 | buffstatus = isp1760_readl(usb_hcd->regs + | ||
| 1023 | HC_BUFFER_STATUS_REG); | ||
| 1024 | buffstatus |= ATL_BUFFER; | ||
| 1025 | isp1760_writel(buffstatus, usb_hcd->regs + | ||
| 1026 | HC_BUFFER_STATUS_REG); | ||
| 1027 | continue; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | error = check_error(&ptd); | ||
| 1031 | if (error) { | ||
| 1032 | status = error; | ||
| 1033 | priv->atl_ints[queue_entry].qh->toggle = 0; | ||
| 1034 | priv->atl_ints[queue_entry].qh->ping = 0; | ||
| 1035 | urb->status = -EPIPE; | ||
| 1036 | |||
| 1037 | #if 0 | ||
| 1038 | printk(KERN_ERR "Error in %s().\n", __func__); | ||
| 1039 | printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " | ||
| 1040 | "dw3: %08x dw4: %08x dw5: %08x dw6: " | ||
| 1041 | "%08x dw7: %08x\n", | ||
| 1042 | ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, | ||
| 1043 | ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); | ||
| 1044 | #endif | ||
| 1045 | } else { | ||
| 1046 | if (usb_pipetype(urb->pipe) == PIPE_BULK) { | ||
| 1047 | priv->atl_ints[queue_entry].qh->toggle = dw3 & | ||
| 1048 | (1 << 25); | ||
| 1049 | priv->atl_ints[queue_entry].qh->ping = dw3 & | ||
| 1050 | (1 << 26); | ||
| 1051 | } | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | length = PTD_XFERRED_LENGTH(dw3); | ||
| 1055 | if (length) { | ||
| 1056 | switch (DW1_GET_PID(dw1)) { | ||
| 1057 | case IN_PID: | ||
| 1058 | priv_read_copy(priv, | ||
| 1059 | priv->atl_ints[queue_entry].data_buffer, | ||
| 1060 | usb_hcd->regs + payload, payload, | ||
| 1061 | length); | ||
| 1062 | |||
| 1063 | case OUT_PID: | ||
| 1064 | |||
| 1065 | urb->actual_length += length; | ||
| 1066 | |||
| 1067 | case SETUP_PID: | ||
| 1068 | break; | ||
| 1069 | } | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | priv->atl_ints[queue_entry].data_buffer = NULL; | ||
| 1073 | priv->atl_ints[queue_entry].urb = NULL; | ||
| 1074 | priv->atl_ints[queue_entry].qtd = NULL; | ||
| 1075 | priv->atl_ints[queue_entry].qh = NULL; | ||
| 1076 | |||
| 1077 | free_mem(priv, payload); | ||
| 1078 | |||
| 1079 | isp1760_writel(skip_map, usb_hcd->regs + | ||
| 1080 | HC_ATL_PTD_SKIPMAP_REG); | ||
| 1081 | |||
| 1082 | if (urb->status == -EPIPE) { | ||
| 1083 | /* HALT was received */ | ||
| 1084 | |||
| 1085 | qtd = clean_up_qtdlist(qtd); | ||
| 1086 | isp1760_urb_done(priv, urb, urb->status); | ||
| 1087 | |||
| 1088 | } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) { | ||
| 1089 | /* short BULK received */ | ||
| 1090 | |||
| 1091 | printk(KERN_ERR "short bulk, %d instead %d\n", length, | ||
| 1092 | qtd->length); | ||
| 1093 | if (urb->transfer_flags & URB_SHORT_NOT_OK) { | ||
| 1094 | urb->status = -EREMOTEIO; | ||
| 1095 | printk(KERN_ERR "not okey\n"); | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | if (urb->status == -EINPROGRESS) | ||
| 1099 | urb->status = 0; | ||
| 1100 | |||
| 1101 | qtd = clean_up_qtdlist(qtd); | ||
| 1102 | |||
| 1103 | isp1760_urb_done(priv, urb, urb->status); | ||
| 1104 | |||
| 1105 | } else if (qtd->status & URB_COMPLETE_NOTIFY) { | ||
| 1106 | /* that was the last qtd of that URB */ | ||
| 1107 | |||
| 1108 | if (urb->status == -EINPROGRESS) | ||
| 1109 | urb->status = 0; | ||
| 1110 | |||
| 1111 | qtd = clean_this_qtd(qtd); | ||
| 1112 | isp1760_urb_done(priv, urb, urb->status); | ||
| 1113 | |||
| 1114 | } else { | ||
| 1115 | /* next QTD of this URB */ | ||
| 1116 | |||
| 1117 | qtd = clean_this_qtd(qtd); | ||
| 1118 | BUG_ON(!qtd); | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | if (qtd) | ||
| 1122 | enqueue_an_ATL_packet(usb_hcd, qh, qtd); | ||
| 1123 | |||
| 1124 | skip_map = isp1760_readl(usb_hcd->regs + | ||
| 1125 | HC_ATL_PTD_SKIPMAP_REG); | ||
| 1126 | } | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | static void do_intl_int(struct usb_hcd *usb_hcd) | ||
| 1130 | { | ||
| 1131 | struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); | ||
| 1132 | u32 done_map, skip_map; | ||
| 1133 | struct ptd ptd; | ||
| 1134 | struct urb *urb = NULL; | ||
| 1135 | u32 int_regs; | ||
| 1136 | u32 int_regs_base; | ||
| 1137 | u32 payload; | ||
| 1138 | u32 length; | ||
| 1139 | u32 or_map; | ||
| 1140 | int error; | ||
| 1141 | u32 queue_entry; | ||
| 1142 | struct isp1760_qtd *qtd; | ||
| 1143 | struct isp1760_qh *qh; | ||
| 1144 | |||
| 1145 | done_map = isp1760_readl(usb_hcd->regs + | ||
| 1146 | HC_INT_PTD_DONEMAP_REG); | ||
| 1147 | skip_map = isp1760_readl(usb_hcd->regs + | ||
| 1148 | HC_INT_PTD_SKIPMAP_REG); | ||
| 1149 | |||
| 1150 | or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); | ||
| 1151 | or_map &= ~done_map; | ||
| 1152 | isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); | ||
| 1153 | |||
| 1154 | int_regs_base = INT_REGS_OFFSET; | ||
| 1155 | |||
| 1156 | while (done_map) { | ||
| 1157 | u32 dw1; | ||
| 1158 | u32 dw3; | ||
| 1159 | |||
| 1160 | queue_entry = __ffs(done_map); | ||
| 1161 | done_map &= ~(1 << queue_entry); | ||
| 1162 | skip_map |= 1 << queue_entry; | ||
| 1163 | |||
| 1164 | int_regs = int_regs_base + queue_entry * sizeof(struct ptd); | ||
| 1165 | urb = priv->int_ints[queue_entry].urb; | ||
| 1166 | qtd = priv->int_ints[queue_entry].qtd; | ||
| 1167 | qh = priv->int_ints[queue_entry].qh; | ||
| 1168 | payload = priv->int_ints[queue_entry].payload; | ||
| 1169 | |||
| 1170 | if (!qh) { | ||
| 1171 | printk(KERN_ERR "(INT) qh is 0\n"); | ||
| 1172 | continue; | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs, | ||
| 1176 | int_regs, sizeof(ptd)); | ||
| 1177 | dw1 = le32_to_cpu(ptd.dw1); | ||
| 1178 | dw3 = le32_to_cpu(ptd.dw3); | ||
| 1179 | check_int_err_status(le32_to_cpu(ptd.dw4)); | ||
| 1180 | |||
| 1181 | error = check_error(&ptd); | ||
| 1182 | if (error) { | ||
| 1183 | #if 0 | ||
| 1184 | printk(KERN_ERR "Error in %s().\n", __func__); | ||
| 1185 | printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " | ||
| 1186 | "dw3: %08x dw4: %08x dw5: %08x dw6: " | ||
| 1187 | "%08x dw7: %08x\n", | ||
| 1188 | ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, | ||
| 1189 | ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); | ||
| 1190 | #endif | ||
| 1191 | urb->status = -EPIPE; | ||
| 1192 | priv->int_ints[queue_entry].qh->toggle = 0; | ||
| 1193 | priv->int_ints[queue_entry].qh->ping = 0; | ||
| 1194 | |||
| 1195 | } else { | ||
| 1196 | priv->int_ints[queue_entry].qh->toggle = | ||
| 1197 | dw3 & (1 << 25); | ||
| 1198 | priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26); | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | if (urb->dev->speed != USB_SPEED_HIGH) | ||
| 1202 | length = PTD_XFERRED_LENGTH_LO(dw3); | ||
| 1203 | else | ||
| 1204 | length = PTD_XFERRED_LENGTH(dw3); | ||
| 1205 | |||
| 1206 | if (length) { | ||
| 1207 | switch (DW1_GET_PID(dw1)) { | ||
| 1208 | case IN_PID: | ||
| 1209 | priv_read_copy(priv, | ||
| 1210 | priv->int_ints[queue_entry].data_buffer, | ||
| 1211 | usb_hcd->regs + payload , payload, | ||
| 1212 | length); | ||
| 1213 | case OUT_PID: | ||
| 1214 | |||
| 1215 | urb->actual_length += length; | ||
| 1216 | |||
| 1217 | case SETUP_PID: | ||
| 1218 | break; | ||
| 1219 | } | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | priv->int_ints[queue_entry].data_buffer = NULL; | ||
| 1223 | priv->int_ints[queue_entry].urb = NULL; | ||
| 1224 | priv->int_ints[queue_entry].qtd = NULL; | ||
| 1225 | priv->int_ints[queue_entry].qh = NULL; | ||
| 1226 | |||
| 1227 | isp1760_writel(skip_map, usb_hcd->regs + | ||
| 1228 | HC_INT_PTD_SKIPMAP_REG); | ||
| 1229 | free_mem(priv, payload); | ||
| 1230 | |||
| 1231 | if (urb->status == -EPIPE) { | ||
| 1232 | /* HALT received */ | ||
| 1233 | |||
| 1234 | qtd = clean_up_qtdlist(qtd); | ||
| 1235 | isp1760_urb_done(priv, urb, urb->status); | ||
| 1236 | |||
| 1237 | } else if (qtd->status & URB_COMPLETE_NOTIFY) { | ||
| 1238 | |||
| 1239 | if (urb->status == -EINPROGRESS) | ||
| 1240 | urb->status = 0; | ||
| 1241 | |||
| 1242 | qtd = clean_this_qtd(qtd); | ||
| 1243 | isp1760_urb_done(priv, urb, urb->status); | ||
| 1244 | |||
| 1245 | } else { | ||
| 1246 | /* next QTD of this URB */ | ||
| 1247 | |||
| 1248 | qtd = clean_this_qtd(qtd); | ||
| 1249 | BUG_ON(!qtd); | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | if (qtd) | ||
| 1253 | enqueue_an_INT_packet(usb_hcd, qh, qtd); | ||
| 1254 | |||
| 1255 | skip_map = isp1760_readl(usb_hcd->regs + | ||
| 1256 | HC_INT_PTD_SKIPMAP_REG); | ||
| 1257 | } | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | #define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) | ||
| 1261 | static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb, | ||
| 1262 | gfp_t flags) | ||
| 1263 | { | ||
| 1264 | struct isp1760_qh *qh; | ||
| 1265 | int is_input, type; | ||
| 1266 | |||
| 1267 | qh = isp1760_qh_alloc(priv, flags); | ||
| 1268 | if (!qh) | ||
| 1269 | return qh; | ||
| 1270 | |||
| 1271 | /* | ||
| 1272 | * init endpoint/device data for this QH | ||
| 1273 | */ | ||
| 1274 | is_input = usb_pipein(urb->pipe); | ||
| 1275 | type = usb_pipetype(urb->pipe); | ||
| 1276 | |||
| 1277 | if (type == PIPE_INTERRUPT) { | ||
| 1278 | |||
| 1279 | if (urb->dev->speed == USB_SPEED_HIGH) { | ||
| 1280 | |||
| 1281 | qh->period = urb->interval >> 3; | ||
| 1282 | if (qh->period == 0 && urb->interval != 1) { | ||
| 1283 | /* NOTE interval 2 or 4 uframes could work. | ||
| 1284 | * But interval 1 scheduling is simpler, and | ||
| 1285 | * includes high bandwidth. | ||
| 1286 | */ | ||
| 1287 | printk(KERN_ERR "intr period %d uframes, NYET!", | ||
| 1288 | urb->interval); | ||
| 1289 | qh_destroy(qh); | ||
| 1290 | return NULL; | ||
| 1291 | } | ||
| 1292 | } else { | ||
| 1293 | qh->period = urb->interval; | ||
| 1294 | } | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | /* support for tt scheduling, and access to toggles */ | ||
| 1298 | qh->dev = urb->dev; | ||
| 1299 | |||
| 1300 | if (!usb_pipecontrol(urb->pipe)) | ||
| 1301 | usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, | ||
| 1302 | 1); | ||
| 1303 | return qh; | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | /* | ||
| 1307 | * For control/bulk/interrupt, return QH with these TDs appended. | ||
| 1308 | * Allocates and initializes the QH if necessary. | ||
| 1309 | * Returns null if it can't allocate a QH it needs to. | ||
| 1310 | * If the QH has TDs (urbs) already, that's great. | ||
| 1311 | */ | ||
| 1312 | static struct isp1760_qh *qh_append_tds(struct isp1760_hcd *priv, | ||
| 1313 | struct urb *urb, struct list_head *qtd_list, int epnum, | ||
| 1314 | void **ptr) | ||
| 1315 | { | ||
| 1316 | struct isp1760_qh *qh; | ||
| 1317 | struct isp1760_qtd *qtd; | ||
| 1318 | struct isp1760_qtd *prev_qtd; | ||
| 1319 | |||
| 1320 | qh = (struct isp1760_qh *)*ptr; | ||
| 1321 | if (!qh) { | ||
| 1322 | /* can't sleep here, we have priv->lock... */ | ||
| 1323 | qh = qh_make(priv, urb, GFP_ATOMIC); | ||
| 1324 | if (!qh) | ||
| 1325 | return qh; | ||
| 1326 | *ptr = qh; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | qtd = list_entry(qtd_list->next, struct isp1760_qtd, | ||
| 1330 | qtd_list); | ||
| 1331 | if (!list_empty(&qh->qtd_list)) | ||
| 1332 | prev_qtd = list_entry(qh->qtd_list.prev, | ||
| 1333 | struct isp1760_qtd, qtd_list); | ||
| 1334 | else | ||
| 1335 | prev_qtd = NULL; | ||
| 1336 | |||
| 1337 | list_splice(qtd_list, qh->qtd_list.prev); | ||
| 1338 | if (prev_qtd) { | ||
| 1339 | BUG_ON(prev_qtd->hw_next); | ||
| 1340 | prev_qtd->hw_next = qtd; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | urb->hcpriv = qh; | ||
| 1344 | return qh; | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb, | ||
| 1348 | struct list_head *qtd_list) | ||
| 1349 | { | ||
| 1350 | struct list_head *entry, *temp; | ||
| 1351 | |||
| 1352 | list_for_each_safe(entry, temp, qtd_list) { | ||
| 1353 | struct isp1760_qtd *qtd; | ||
| 1354 | |||
| 1355 | qtd = list_entry(entry, struct isp1760_qtd, qtd_list); | ||
| 1356 | list_del(&qtd->qtd_list); | ||
| 1357 | isp1760_qtd_free(qtd); | ||
| 1358 | } | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb, | ||
| 1362 | struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p) | ||
| 1363 | { | ||
| 1364 | struct isp1760_qtd *qtd; | ||
| 1365 | int epnum; | ||
| 1366 | unsigned long flags; | ||
| 1367 | struct isp1760_qh *qh = NULL; | ||
| 1368 | int rc; | ||
| 1369 | int qh_busy; | ||
| 1370 | |||
| 1371 | qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list); | ||
| 1372 | epnum = urb->ep->desc.bEndpointAddress; | ||
| 1373 | |||
| 1374 | spin_lock_irqsave(&priv->lock, flags); | ||
| 1375 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) { | ||
| 1376 | rc = -ESHUTDOWN; | ||
| 1377 | goto done; | ||
| 1378 | } | ||
| 1379 | rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb); | ||
| 1380 | if (rc) | ||
| 1381 | goto done; | ||
| 1382 | |||
| 1383 | qh = urb->ep->hcpriv; | ||
| 1384 | if (qh) | ||
| 1385 | qh_busy = !list_empty(&qh->qtd_list); | ||
| 1386 | else | ||
| 1387 | qh_busy = 0; | ||
| 1388 | |||
| 1389 | qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv); | ||
| 1390 | if (!qh) { | ||
| 1391 | usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); | ||
| 1392 | rc = -ENOMEM; | ||
| 1393 | goto done; | ||
| 1394 | } | ||
| 1395 | |||
| 1396 | if (!qh_busy) | ||
| 1397 | p(priv_to_hcd(priv), qh, qtd); | ||
| 1398 | |||
| 1399 | done: | ||
| 1400 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 1401 | if (!qh) | ||
| 1402 | qtd_list_free(priv, urb, qtd_list); | ||
| 1403 | return rc; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv, | ||
| 1407 | gfp_t flags) | ||
| 1408 | { | ||
| 1409 | struct isp1760_qtd *qtd; | ||
| 1410 | |||
| 1411 | qtd = kmem_cache_zalloc(qtd_cachep, flags); | ||
| 1412 | if (qtd) | ||
| 1413 | INIT_LIST_HEAD(&qtd->qtd_list); | ||
| 1414 | |||
| 1415 | return qtd; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | /* | ||
| 1419 | * create a list of filled qtds for this URB; won't link into qh. | ||
| 1420 | */ | ||
| 1421 | static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv, | ||
| 1422 | struct urb *urb, struct list_head *head, gfp_t flags) | ||
| 1423 | { | ||
| 1424 | struct isp1760_qtd *qtd, *qtd_prev; | ||
| 1425 | void *buf; | ||
| 1426 | int len, maxpacket; | ||
| 1427 | int is_input; | ||
| 1428 | u32 token; | ||
| 1429 | |||
| 1430 | /* | ||
| 1431 | * URBs map to sequences of QTDs: one logical transaction | ||
| 1432 | */ | ||
| 1433 | qtd = isp1760_qtd_alloc(priv, flags); | ||
| 1434 | if (!qtd) | ||
| 1435 | return NULL; | ||
| 1436 | |||
| 1437 | list_add_tail(&qtd->qtd_list, head); | ||
| 1438 | qtd->urb = urb; | ||
| 1439 | urb->status = -EINPROGRESS; | ||
| 1440 | |||
| 1441 | token = 0; | ||
| 1442 | /* for split transactions, SplitXState initialized to zero */ | ||
| 1443 | |||
| 1444 | len = urb->transfer_buffer_length; | ||
| 1445 | is_input = usb_pipein(urb->pipe); | ||
| 1446 | if (usb_pipecontrol(urb->pipe)) { | ||
| 1447 | /* SETUP pid */ | ||
| 1448 | qtd_fill(qtd, urb->setup_packet, | ||
| 1449 | sizeof(struct usb_ctrlrequest), | ||
| 1450 | token | SETUP_PID); | ||
| 1451 | |||
| 1452 | /* ... and always at least one more pid */ | ||
| 1453 | token ^= DATA_TOGGLE; | ||
| 1454 | qtd_prev = qtd; | ||
| 1455 | qtd = isp1760_qtd_alloc(priv, flags); | ||
| 1456 | if (!qtd) | ||
| 1457 | goto cleanup; | ||
| 1458 | qtd->urb = urb; | ||
| 1459 | qtd_prev->hw_next = qtd; | ||
| 1460 | list_add_tail(&qtd->qtd_list, head); | ||
| 1461 | |||
| 1462 | /* for zero length DATA stages, STATUS is always IN */ | ||
| 1463 | if (len == 0) | ||
| 1464 | token |= IN_PID; | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | /* | ||
| 1468 | * data transfer stage: buffer setup | ||
| 1469 | */ | ||
| 1470 | buf = urb->transfer_buffer; | ||
| 1471 | |||
| 1472 | if (is_input) | ||
| 1473 | token |= IN_PID; | ||
| 1474 | else | ||
| 1475 | token |= OUT_PID; | ||
| 1476 | |||
| 1477 | maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); | ||
| 1478 | |||
| 1479 | /* | ||
| 1480 | * buffer gets wrapped in one or more qtds; | ||
| 1481 | * last one may be "short" (including zero len) | ||
| 1482 | * and may serve as a control status ack | ||
| 1483 | */ | ||
| 1484 | for (;;) { | ||
| 1485 | int this_qtd_len; | ||
| 1486 | |||
| 1487 | if (!buf && len) { | ||
| 1488 | /* XXX This looks like usb storage / SCSI bug */ | ||
| 1489 | printk(KERN_ERR "buf is null, dma is %08lx len is %d\n", | ||
| 1490 | (long unsigned)urb->transfer_dma, len); | ||
| 1491 | WARN_ON(1); | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | this_qtd_len = qtd_fill(qtd, buf, len, token); | ||
| 1495 | len -= this_qtd_len; | ||
| 1496 | buf += this_qtd_len; | ||
| 1497 | |||
| 1498 | /* qh makes control packets use qtd toggle; maybe switch it */ | ||
| 1499 | if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) | ||
| 1500 | token ^= DATA_TOGGLE; | ||
| 1501 | |||
| 1502 | if (len <= 0) | ||
| 1503 | break; | ||
| 1504 | |||
| 1505 | qtd_prev = qtd; | ||
| 1506 | qtd = isp1760_qtd_alloc(priv, flags); | ||
| 1507 | if (!qtd) | ||
| 1508 | goto cleanup; | ||
| 1509 | qtd->urb = urb; | ||
| 1510 | qtd_prev->hw_next = qtd; | ||
| 1511 | list_add_tail(&qtd->qtd_list, head); | ||
| 1512 | } | ||
| 1513 | |||
| 1514 | /* | ||
| 1515 | * control requests may need a terminating data "status" ack; | ||
| 1516 | * bulk ones may need a terminating short packet (zero length). | ||
| 1517 | */ | ||
| 1518 | if (urb->transfer_buffer_length != 0) { | ||
| 1519 | int one_more = 0; | ||
| 1520 | |||
| 1521 | if (usb_pipecontrol(urb->pipe)) { | ||
| 1522 | one_more = 1; | ||
| 1523 | /* "in" <--> "out" */ | ||
| 1524 | token ^= IN_PID; | ||
| 1525 | /* force DATA1 */ | ||
| 1526 | token |= DATA_TOGGLE; | ||
| 1527 | } else if (usb_pipebulk(urb->pipe) | ||
| 1528 | && (urb->transfer_flags & URB_ZERO_PACKET) | ||
| 1529 | && !(urb->transfer_buffer_length % maxpacket)) { | ||
| 1530 | one_more = 1; | ||
| 1531 | } | ||
| 1532 | if (one_more) { | ||
| 1533 | qtd_prev = qtd; | ||
| 1534 | qtd = isp1760_qtd_alloc(priv, flags); | ||
| 1535 | if (!qtd) | ||
| 1536 | goto cleanup; | ||
| 1537 | qtd->urb = urb; | ||
| 1538 | qtd_prev->hw_next = qtd; | ||
| 1539 | list_add_tail(&qtd->qtd_list, head); | ||
| 1540 | |||
| 1541 | /* never any data in such packets */ | ||
| 1542 | qtd_fill(qtd, NULL, 0, token); | ||
| 1543 | } | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | qtd->status = URB_COMPLETE_NOTIFY; | ||
| 1547 | return head; | ||
| 1548 | |||
| 1549 | cleanup: | ||
| 1550 | qtd_list_free(priv, urb, head); | ||
| 1551 | return NULL; | ||
| 1552 | } | ||
| 1553 | |||
| 1554 | static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, | ||
| 1555 | gfp_t mem_flags) | ||
| 1556 | { | ||
| 1557 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 1558 | struct list_head qtd_list; | ||
| 1559 | packet_enqueue *pe; | ||
| 1560 | |||
| 1561 | INIT_LIST_HEAD(&qtd_list); | ||
| 1562 | |||
| 1563 | switch (usb_pipetype(urb->pipe)) { | ||
| 1564 | case PIPE_CONTROL: | ||
| 1565 | case PIPE_BULK: | ||
| 1566 | |||
| 1567 | if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) | ||
| 1568 | return -ENOMEM; | ||
| 1569 | pe = enqueue_an_ATL_packet; | ||
| 1570 | break; | ||
| 1571 | |||
| 1572 | case PIPE_INTERRUPT: | ||
| 1573 | if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) | ||
| 1574 | return -ENOMEM; | ||
| 1575 | pe = enqueue_an_INT_packet; | ||
| 1576 | break; | ||
| 1577 | |||
| 1578 | case PIPE_ISOCHRONOUS: | ||
| 1579 | printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n"); | ||
| 1580 | default: | ||
| 1581 | return -EPIPE; | ||
| 1582 | } | ||
| 1583 | |||
| 1584 | isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe); | ||
| 1585 | return 0; | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, | ||
| 1589 | int status) | ||
| 1590 | { | ||
| 1591 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 1592 | struct inter_packet_info *ints; | ||
| 1593 | u32 i; | ||
| 1594 | u32 reg_base, or_reg, skip_reg; | ||
| 1595 | int flags; | ||
| 1596 | struct ptd ptd; | ||
| 1597 | |||
| 1598 | switch (usb_pipetype(urb->pipe)) { | ||
| 1599 | case PIPE_ISOCHRONOUS: | ||
| 1600 | return -EPIPE; | ||
| 1601 | break; | ||
| 1602 | |||
| 1603 | case PIPE_INTERRUPT: | ||
| 1604 | ints = priv->int_ints; | ||
| 1605 | reg_base = INT_REGS_OFFSET; | ||
| 1606 | or_reg = HC_INT_IRQ_MASK_OR_REG; | ||
| 1607 | skip_reg = HC_INT_PTD_SKIPMAP_REG; | ||
| 1608 | break; | ||
| 1609 | |||
| 1610 | default: | ||
| 1611 | ints = priv->atl_ints; | ||
| 1612 | reg_base = ATL_REGS_OFFSET; | ||
| 1613 | or_reg = HC_ATL_IRQ_MASK_OR_REG; | ||
| 1614 | skip_reg = HC_ATL_PTD_SKIPMAP_REG; | ||
| 1615 | break; | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | memset(&ptd, 0, sizeof(ptd)); | ||
| 1619 | spin_lock_irqsave(&priv->lock, flags); | ||
| 1620 | |||
| 1621 | for (i = 0; i < 32; i++) { | ||
| 1622 | if (ints->urb == urb) { | ||
| 1623 | u32 skip_map; | ||
| 1624 | u32 or_map; | ||
| 1625 | struct isp1760_qtd *qtd; | ||
| 1626 | |||
| 1627 | skip_map = isp1760_readl(hcd->regs + skip_reg); | ||
| 1628 | skip_map |= 1 << i; | ||
| 1629 | isp1760_writel(skip_map, hcd->regs + skip_reg); | ||
| 1630 | |||
| 1631 | or_map = isp1760_readl(hcd->regs + or_reg); | ||
| 1632 | or_map &= ~(1 << i); | ||
| 1633 | isp1760_writel(or_map, hcd->regs + or_reg); | ||
| 1634 | |||
| 1635 | priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base | ||
| 1636 | + i * sizeof(ptd), sizeof(ptd)); | ||
| 1637 | qtd = ints->qtd; | ||
| 1638 | |||
| 1639 | clean_up_qtdlist(qtd); | ||
| 1640 | |||
| 1641 | free_mem(priv, ints->payload); | ||
| 1642 | |||
| 1643 | ints->urb = NULL; | ||
| 1644 | ints->qh = NULL; | ||
| 1645 | ints->qtd = NULL; | ||
| 1646 | ints->data_buffer = NULL; | ||
| 1647 | ints->payload = 0; | ||
| 1648 | |||
| 1649 | isp1760_urb_done(priv, urb, status); | ||
| 1650 | break; | ||
| 1651 | } | ||
| 1652 | ints++; | ||
| 1653 | } | ||
| 1654 | |||
| 1655 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 1656 | return 0; | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd) | ||
| 1660 | { | ||
| 1661 | struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); | ||
| 1662 | u32 imask; | ||
| 1663 | irqreturn_t irqret = IRQ_NONE; | ||
| 1664 | |||
| 1665 | spin_lock(&priv->lock); | ||
| 1666 | |||
| 1667 | if (!(usb_hcd->state & HC_STATE_RUNNING)) | ||
| 1668 | goto leave; | ||
| 1669 | |||
| 1670 | imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG); | ||
| 1671 | if (unlikely(!imask)) | ||
| 1672 | goto leave; | ||
| 1673 | |||
| 1674 | isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG); | ||
| 1675 | if (imask & HC_ATL_INT) | ||
| 1676 | do_atl_int(usb_hcd); | ||
| 1677 | |||
| 1678 | if (imask & HC_INTL_INT) | ||
| 1679 | do_intl_int(usb_hcd); | ||
| 1680 | |||
| 1681 | irqret = IRQ_HANDLED; | ||
| 1682 | leave: | ||
| 1683 | spin_unlock(&priv->lock); | ||
| 1684 | return irqret; | ||
| 1685 | } | ||
| 1686 | |||
| 1687 | static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) | ||
| 1688 | { | ||
| 1689 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 1690 | u32 temp, status = 0; | ||
| 1691 | u32 mask; | ||
| 1692 | int retval = 1; | ||
| 1693 | unsigned long flags; | ||
| 1694 | |||
| 1695 | /* if !USB_SUSPEND, root hub timers won't get shut down ... */ | ||
| 1696 | if (!HC_IS_RUNNING(hcd->state)) | ||
| 1697 | return 0; | ||
| 1698 | |||
| 1699 | /* init status to no-changes */ | ||
| 1700 | buf[0] = 0; | ||
| 1701 | mask = PORT_CSC; | ||
| 1702 | |||
| 1703 | spin_lock_irqsave(&priv->lock, flags); | ||
| 1704 | temp = isp1760_readl(hcd->regs + HC_PORTSC1); | ||
| 1705 | |||
| 1706 | if (temp & PORT_OWNER) { | ||
| 1707 | if (temp & PORT_CSC) { | ||
| 1708 | temp &= ~PORT_CSC; | ||
| 1709 | isp1760_writel(temp, hcd->regs + HC_PORTSC1); | ||
| 1710 | goto done; | ||
| 1711 | } | ||
| 1712 | } | ||
| 1713 | |||
| 1714 | /* | ||
| 1715 | * Return status information even for ports with OWNER set. | ||
| 1716 | * Otherwise khubd wouldn't see the disconnect event when a | ||
| 1717 | * high-speed device is switched over to the companion | ||
| 1718 | * controller by the user. | ||
| 1719 | */ | ||
| 1720 | |||
| 1721 | if ((temp & mask) != 0 | ||
| 1722 | || ((temp & PORT_RESUME) != 0 | ||
| 1723 | && time_after_eq(jiffies, | ||
| 1724 | priv->reset_done))) { | ||
| 1725 | buf [0] |= 1 << (0 + 1); | ||
| 1726 | status = STS_PCD; | ||
| 1727 | } | ||
| 1728 | /* FIXME autosuspend idle root hubs */ | ||
| 1729 | done: | ||
| 1730 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 1731 | return status ? retval : 0; | ||
| 1732 | } | ||
| 1733 | |||
| 1734 | static void isp1760_hub_descriptor(struct isp1760_hcd *priv, | ||
| 1735 | struct usb_hub_descriptor *desc) | ||
| 1736 | { | ||
| 1737 | int ports = HCS_N_PORTS(priv->hcs_params); | ||
| 1738 | u16 temp; | ||
| 1739 | |||
| 1740 | desc->bDescriptorType = 0x29; | ||
| 1741 | /* priv 1.0, 2.3.9 says 20ms max */ | ||
| 1742 | desc->bPwrOn2PwrGood = 10; | ||
| 1743 | desc->bHubContrCurrent = 0; | ||
| 1744 | |||
| 1745 | desc->bNbrPorts = ports; | ||
| 1746 | temp = 1 + (ports / 8); | ||
| 1747 | desc->bDescLength = 7 + 2 * temp; | ||
| 1748 | |||
| 1749 | /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ | ||
| 1750 | memset(&desc->bitmap[0], 0, temp); | ||
| 1751 | memset(&desc->bitmap[temp], 0xff, temp); | ||
| 1752 | |||
| 1753 | /* per-port overcurrent reporting */ | ||
| 1754 | temp = 0x0008; | ||
| 1755 | if (HCS_PPC(priv->hcs_params)) | ||
| 1756 | /* per-port power control */ | ||
| 1757 | temp |= 0x0001; | ||
| 1758 | else | ||
| 1759 | /* no power switching */ | ||
| 1760 | temp |= 0x0002; | ||
| 1761 | desc->wHubCharacteristics = cpu_to_le16(temp); | ||
| 1762 | } | ||
| 1763 | |||
| 1764 | #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) | ||
| 1765 | |||
| 1766 | static int check_reset_complete(struct isp1760_hcd *priv, int index, | ||
| 1767 | u32 __iomem *status_reg, int port_status) | ||
| 1768 | { | ||
| 1769 | if (!(port_status & PORT_CONNECT)) | ||
| 1770 | return port_status; | ||
| 1771 | |||
| 1772 | /* if reset finished and it's still not enabled -- handoff */ | ||
| 1773 | if (!(port_status & PORT_PE)) { | ||
| 1774 | |||
| 1775 | printk(KERN_ERR "port %d full speed --> companion\n", | ||
| 1776 | index + 1); | ||
| 1777 | |||
| 1778 | port_status |= PORT_OWNER; | ||
| 1779 | port_status &= ~PORT_RWC_BITS; | ||
| 1780 | isp1760_writel(port_status, status_reg); | ||
| 1781 | |||
| 1782 | } else | ||
| 1783 | printk(KERN_ERR "port %d high speed\n", index + 1); | ||
| 1784 | |||
| 1785 | return port_status; | ||
| 1786 | } | ||
| 1787 | |||
| 1788 | static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, | ||
| 1789 | u16 wValue, u16 wIndex, char *buf, u16 wLength) | ||
| 1790 | { | ||
| 1791 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 1792 | int ports = HCS_N_PORTS(priv->hcs_params); | ||
| 1793 | u32 __iomem *status_reg = hcd->regs + HC_PORTSC1; | ||
| 1794 | u32 temp, status; | ||
| 1795 | unsigned long flags; | ||
| 1796 | int retval = 0; | ||
| 1797 | unsigned selector; | ||
| 1798 | |||
| 1799 | /* | ||
| 1800 | * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. | ||
| 1801 | * HCS_INDICATOR may say we can change LEDs to off/amber/green. | ||
| 1802 | * (track current state ourselves) ... blink for diagnostics, | ||
| 1803 | * power, "this is the one", etc. EHCI spec supports this. | ||
| 1804 | */ | ||
| 1805 | |||
| 1806 | spin_lock_irqsave(&priv->lock, flags); | ||
| 1807 | switch (typeReq) { | ||
| 1808 | case ClearHubFeature: | ||
| 1809 | switch (wValue) { | ||
| 1810 | case C_HUB_LOCAL_POWER: | ||
| 1811 | case C_HUB_OVER_CURRENT: | ||
| 1812 | /* no hub-wide feature/status flags */ | ||
| 1813 | break; | ||
| 1814 | default: | ||
| 1815 | goto error; | ||
| 1816 | } | ||
| 1817 | break; | ||
| 1818 | case ClearPortFeature: | ||
| 1819 | if (!wIndex || wIndex > ports) | ||
| 1820 | goto error; | ||
| 1821 | wIndex--; | ||
| 1822 | temp = isp1760_readl(status_reg); | ||
| 1823 | |||
| 1824 | /* | ||
| 1825 | * Even if OWNER is set, so the port is owned by the | ||
| 1826 | * companion controller, khubd needs to be able to clear | ||
| 1827 | * the port-change status bits (especially | ||
| 1828 | * USB_PORT_FEAT_C_CONNECTION). | ||
| 1829 | */ | ||
| 1830 | |||
| 1831 | switch (wValue) { | ||
| 1832 | case USB_PORT_FEAT_ENABLE: | ||
| 1833 | isp1760_writel(temp & ~PORT_PE, status_reg); | ||
| 1834 | break; | ||
| 1835 | case USB_PORT_FEAT_C_ENABLE: | ||
| 1836 | /* XXX error? */ | ||
| 1837 | break; | ||
| 1838 | case USB_PORT_FEAT_SUSPEND: | ||
| 1839 | if (temp & PORT_RESET) | ||
| 1840 | goto error; | ||
| 1841 | |||
| 1842 | if (temp & PORT_SUSPEND) { | ||
| 1843 | if ((temp & PORT_PE) == 0) | ||
| 1844 | goto error; | ||
| 1845 | /* resume signaling for 20 msec */ | ||
| 1846 | temp &= ~(PORT_RWC_BITS); | ||
| 1847 | isp1760_writel(temp | PORT_RESUME, | ||
| 1848 | status_reg); | ||
| 1849 | priv->reset_done = jiffies + | ||
| 1850 | msecs_to_jiffies(20); | ||
| 1851 | } | ||
| 1852 | break; | ||
| 1853 | case USB_PORT_FEAT_C_SUSPEND: | ||
| 1854 | /* we auto-clear this feature */ | ||
| 1855 | break; | ||
| 1856 | case USB_PORT_FEAT_POWER: | ||
| 1857 | if (HCS_PPC(priv->hcs_params)) | ||
| 1858 | isp1760_writel(temp & ~PORT_POWER, status_reg); | ||
| 1859 | break; | ||
| 1860 | case USB_PORT_FEAT_C_CONNECTION: | ||
| 1861 | isp1760_writel(temp | PORT_CSC, | ||
| 1862 | status_reg); | ||
| 1863 | break; | ||
| 1864 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
| 1865 | /* XXX error ?*/ | ||
| 1866 | break; | ||
| 1867 | case USB_PORT_FEAT_C_RESET: | ||
| 1868 | /* GetPortStatus clears reset */ | ||
| 1869 | break; | ||
| 1870 | default: | ||
| 1871 | goto error; | ||
| 1872 | } | ||
| 1873 | isp1760_readl(hcd->regs + HC_USBCMD); | ||
| 1874 | break; | ||
| 1875 | case GetHubDescriptor: | ||
| 1876 | isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *) | ||
| 1877 | buf); | ||
| 1878 | break; | ||
| 1879 | case GetHubStatus: | ||
| 1880 | /* no hub-wide feature/status flags */ | ||
| 1881 | memset(buf, 0, 4); | ||
| 1882 | break; | ||
| 1883 | case GetPortStatus: | ||
| 1884 | if (!wIndex || wIndex > ports) | ||
| 1885 | goto error; | ||
| 1886 | wIndex--; | ||
| 1887 | status = 0; | ||
| 1888 | temp = isp1760_readl(status_reg); | ||
| 1889 | |||
| 1890 | /* wPortChange bits */ | ||
| 1891 | if (temp & PORT_CSC) | ||
| 1892 | status |= 1 << USB_PORT_FEAT_C_CONNECTION; | ||
| 1893 | |||
| 1894 | |||
| 1895 | /* whoever resumes must GetPortStatus to complete it!! */ | ||
| 1896 | if (temp & PORT_RESUME) { | ||
| 1897 | printk(KERN_ERR "Port resume should be skipped.\n"); | ||
| 1898 | |||
| 1899 | /* Remote Wakeup received? */ | ||
| 1900 | if (!priv->reset_done) { | ||
| 1901 | /* resume signaling for 20 msec */ | ||
| 1902 | priv->reset_done = jiffies | ||
| 1903 | + msecs_to_jiffies(20); | ||
| 1904 | /* check the port again */ | ||
| 1905 | mod_timer(&priv_to_hcd(priv)->rh_timer, | ||
| 1906 | priv->reset_done); | ||
| 1907 | } | ||
| 1908 | |||
| 1909 | /* resume completed? */ | ||
| 1910 | else if (time_after_eq(jiffies, | ||
| 1911 | priv->reset_done)) { | ||
| 1912 | status |= 1 << USB_PORT_FEAT_C_SUSPEND; | ||
| 1913 | priv->reset_done = 0; | ||
| 1914 | |||
| 1915 | /* stop resume signaling */ | ||
| 1916 | temp = isp1760_readl(status_reg); | ||
| 1917 | isp1760_writel( | ||
| 1918 | temp & ~(PORT_RWC_BITS | PORT_RESUME), | ||
| 1919 | status_reg); | ||
| 1920 | retval = handshake(priv, status_reg, | ||
| 1921 | PORT_RESUME, 0, 2000 /* 2msec */); | ||
| 1922 | if (retval != 0) { | ||
| 1923 | isp1760_err(priv, | ||
| 1924 | "port %d resume error %d\n", | ||
| 1925 | wIndex + 1, retval); | ||
| 1926 | goto error; | ||
| 1927 | } | ||
| 1928 | temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); | ||
| 1929 | } | ||
| 1930 | } | ||
| 1931 | |||
| 1932 | /* whoever resets must GetPortStatus to complete it!! */ | ||
| 1933 | if ((temp & PORT_RESET) | ||
| 1934 | && time_after_eq(jiffies, | ||
| 1935 | priv->reset_done)) { | ||
| 1936 | status |= 1 << USB_PORT_FEAT_C_RESET; | ||
| 1937 | priv->reset_done = 0; | ||
| 1938 | |||
| 1939 | /* force reset to complete */ | ||
| 1940 | isp1760_writel(temp & ~PORT_RESET, | ||
| 1941 | status_reg); | ||
| 1942 | /* REVISIT: some hardware needs 550+ usec to clear | ||
| 1943 | * this bit; seems too long to spin routinely... | ||
| 1944 | */ | ||
| 1945 | retval = handshake(priv, status_reg, | ||
| 1946 | PORT_RESET, 0, 750); | ||
| 1947 | if (retval != 0) { | ||
| 1948 | isp1760_err(priv, "port %d reset error %d\n", | ||
| 1949 | wIndex + 1, retval); | ||
| 1950 | goto error; | ||
| 1951 | } | ||
| 1952 | |||
| 1953 | /* see what we found out */ | ||
| 1954 | temp = check_reset_complete(priv, wIndex, status_reg, | ||
| 1955 | isp1760_readl(status_reg)); | ||
| 1956 | } | ||
| 1957 | /* | ||
| 1958 | * Even if OWNER is set, there's no harm letting khubd | ||
| 1959 | * see the wPortStatus values (they should all be 0 except | ||
| 1960 | * for PORT_POWER anyway). | ||
| 1961 | */ | ||
| 1962 | |||
| 1963 | if (temp & PORT_OWNER) | ||
| 1964 | printk(KERN_ERR "Warning: PORT_OWNER is set\n"); | ||
| 1965 | |||
| 1966 | if (temp & PORT_CONNECT) { | ||
| 1967 | status |= 1 << USB_PORT_FEAT_CONNECTION; | ||
| 1968 | /* status may be from integrated TT */ | ||
| 1969 | status |= ehci_port_speed(priv, temp); | ||
| 1970 | } | ||
| 1971 | if (temp & PORT_PE) | ||
| 1972 | status |= 1 << USB_PORT_FEAT_ENABLE; | ||
| 1973 | if (temp & (PORT_SUSPEND|PORT_RESUME)) | ||
| 1974 | status |= 1 << USB_PORT_FEAT_SUSPEND; | ||
| 1975 | if (temp & PORT_RESET) | ||
| 1976 | status |= 1 << USB_PORT_FEAT_RESET; | ||
| 1977 | if (temp & PORT_POWER) | ||
| 1978 | status |= 1 << USB_PORT_FEAT_POWER; | ||
| 1979 | |||
| 1980 | put_unaligned(cpu_to_le32(status), (__le32 *) buf); | ||
| 1981 | break; | ||
| 1982 | case SetHubFeature: | ||
| 1983 | switch (wValue) { | ||
| 1984 | case C_HUB_LOCAL_POWER: | ||
| 1985 | case C_HUB_OVER_CURRENT: | ||
| 1986 | /* no hub-wide feature/status flags */ | ||
| 1987 | break; | ||
| 1988 | default: | ||
| 1989 | goto error; | ||
| 1990 | } | ||
| 1991 | break; | ||
| 1992 | case SetPortFeature: | ||
| 1993 | selector = wIndex >> 8; | ||
| 1994 | wIndex &= 0xff; | ||
| 1995 | if (!wIndex || wIndex > ports) | ||
| 1996 | goto error; | ||
| 1997 | wIndex--; | ||
| 1998 | temp = isp1760_readl(status_reg); | ||
| 1999 | if (temp & PORT_OWNER) | ||
| 2000 | break; | ||
| 2001 | |||
| 2002 | /* temp &= ~PORT_RWC_BITS; */ | ||
| 2003 | switch (wValue) { | ||
| 2004 | case USB_PORT_FEAT_ENABLE: | ||
| 2005 | isp1760_writel(temp | PORT_PE, status_reg); | ||
| 2006 | break; | ||
| 2007 | |||
| 2008 | case USB_PORT_FEAT_SUSPEND: | ||
| 2009 | if ((temp & PORT_PE) == 0 | ||
| 2010 | || (temp & PORT_RESET) != 0) | ||
| 2011 | goto error; | ||
| 2012 | |||
| 2013 | isp1760_writel(temp | PORT_SUSPEND, status_reg); | ||
| 2014 | break; | ||
| 2015 | case USB_PORT_FEAT_POWER: | ||
| 2016 | if (HCS_PPC(priv->hcs_params)) | ||
| 2017 | isp1760_writel(temp | PORT_POWER, | ||
| 2018 | status_reg); | ||
| 2019 | break; | ||
| 2020 | case USB_PORT_FEAT_RESET: | ||
| 2021 | if (temp & PORT_RESUME) | ||
| 2022 | goto error; | ||
| 2023 | /* line status bits may report this as low speed, | ||
| 2024 | * which can be fine if this root hub has a | ||
| 2025 | * transaction translator built in. | ||
| 2026 | */ | ||
| 2027 | if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT | ||
| 2028 | && PORT_USB11(temp)) { | ||
| 2029 | temp |= PORT_OWNER; | ||
| 2030 | } else { | ||
| 2031 | temp |= PORT_RESET; | ||
| 2032 | temp &= ~PORT_PE; | ||
| 2033 | |||
| 2034 | /* | ||
| 2035 | * caller must wait, then call GetPortStatus | ||
| 2036 | * usb 2.0 spec says 50 ms resets on root | ||
| 2037 | */ | ||
| 2038 | priv->reset_done = jiffies + | ||
| 2039 | msecs_to_jiffies(50); | ||
| 2040 | } | ||
| 2041 | isp1760_writel(temp, status_reg); | ||
| 2042 | break; | ||
| 2043 | default: | ||
| 2044 | goto error; | ||
| 2045 | } | ||
| 2046 | isp1760_readl(hcd->regs + HC_USBCMD); | ||
| 2047 | break; | ||
| 2048 | |||
| 2049 | default: | ||
| 2050 | error: | ||
| 2051 | /* "stall" on error */ | ||
| 2052 | retval = -EPIPE; | ||
| 2053 | } | ||
| 2054 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 2055 | return retval; | ||
| 2056 | } | ||
| 2057 | |||
| 2058 | static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd, | ||
| 2059 | struct usb_host_endpoint *ep) | ||
| 2060 | { | ||
| 2061 | struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); | ||
| 2062 | struct isp1760_qh *qh; | ||
| 2063 | struct isp1760_qtd *qtd; | ||
| 2064 | u32 flags; | ||
| 2065 | |||
| 2066 | spin_lock_irqsave(&priv->lock, flags); | ||
| 2067 | qh = ep->hcpriv; | ||
| 2068 | if (!qh) | ||
| 2069 | goto out; | ||
| 2070 | |||
| 2071 | ep->hcpriv = NULL; | ||
| 2072 | do { | ||
| 2073 | /* more than entry might get removed */ | ||
| 2074 | if (list_empty(&qh->qtd_list)) | ||
| 2075 | break; | ||
| 2076 | |||
| 2077 | qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd, | ||
| 2078 | qtd_list); | ||
| 2079 | |||
| 2080 | if (qtd->status & URB_ENQUEUED) { | ||
| 2081 | |||
| 2082 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 2083 | isp1760_urb_dequeue(usb_hcd, qtd->urb, -ECONNRESET); | ||
| 2084 | spin_lock_irqsave(&priv->lock, flags); | ||
| 2085 | } else { | ||
| 2086 | struct urb *urb; | ||
| 2087 | |||
| 2088 | urb = qtd->urb; | ||
| 2089 | clean_up_qtdlist(qtd); | ||
| 2090 | isp1760_urb_done(priv, urb, -ECONNRESET); | ||
| 2091 | } | ||
| 2092 | } while (1); | ||
| 2093 | |||
| 2094 | qh_destroy(qh); | ||
| 2095 | /* remove requests and leak them. | ||
| 2096 | * ATL are pretty fast done, INT could take a while... | ||
| 2097 | * The latter shoule be removed | ||
| 2098 | */ | ||
| 2099 | out: | ||
| 2100 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | static int isp1760_get_frame(struct usb_hcd *hcd) | ||
| 2104 | { | ||
| 2105 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 2106 | u32 fr; | ||
| 2107 | |||
| 2108 | fr = isp1760_readl(hcd->regs + HC_FRINDEX); | ||
| 2109 | return (fr >> 3) % priv->periodic_size; | ||
| 2110 | } | ||
| 2111 | |||
| 2112 | static void isp1760_stop(struct usb_hcd *hcd) | ||
| 2113 | { | ||
| 2114 | struct isp1760_hcd *priv = hcd_to_priv(hcd); | ||
| 2115 | |||
| 2116 | isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, | ||
| 2117 | NULL, 0); | ||
| 2118 | mdelay(20); | ||
| 2119 | |||
| 2120 | spin_lock_irq(&priv->lock); | ||
| 2121 | ehci_reset(priv); | ||
| 2122 | /* Disable IRQ */ | ||
| 2123 | isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); | ||
| 2124 | spin_unlock_irq(&priv->lock); | ||
| 2125 | |||
| 2126 | isp1760_writel(0, hcd->regs + HC_CONFIGFLAG); | ||
| 2127 | } | ||
| 2128 | |||
| 2129 | static void isp1760_shutdown(struct usb_hcd *hcd) | ||
| 2130 | { | ||
| 2131 | u32 command; | ||
| 2132 | |||
| 2133 | isp1760_stop(hcd); | ||
| 2134 | isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); | ||
| 2135 | |||
| 2136 | command = isp1760_readl(hcd->regs + HC_USBCMD); | ||
| 2137 | command &= ~CMD_RUN; | ||
| 2138 | isp1760_writel(command, hcd->regs + HC_USBCMD); | ||
| 2139 | } | ||
| 2140 | |||
| 2141 | static const struct hc_driver isp1760_hc_driver = { | ||
| 2142 | .description = "isp1760-hcd", | ||
| 2143 | .product_desc = "NXP ISP1760 USB Host Controller", | ||
| 2144 | .hcd_priv_size = sizeof(struct isp1760_hcd), | ||
| 2145 | .irq = isp1760_irq, | ||
| 2146 | .flags = HCD_MEMORY | HCD_USB2, | ||
| 2147 | .reset = isp1760_hc_setup, | ||
| 2148 | .start = isp1760_run, | ||
| 2149 | .stop = isp1760_stop, | ||
| 2150 | .shutdown = isp1760_shutdown, | ||
| 2151 | .urb_enqueue = isp1760_urb_enqueue, | ||
| 2152 | .urb_dequeue = isp1760_urb_dequeue, | ||
| 2153 | .endpoint_disable = isp1760_endpoint_disable, | ||
| 2154 | .get_frame_number = isp1760_get_frame, | ||
| 2155 | .hub_status_data = isp1760_hub_status_data, | ||
| 2156 | .hub_control = isp1760_hub_control, | ||
| 2157 | }; | ||
| 2158 | |||
| 2159 | int __init init_kmem_once(void) | ||
| 2160 | { | ||
| 2161 | qtd_cachep = kmem_cache_create("isp1760_qtd", | ||
| 2162 | sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY | | ||
| 2163 | SLAB_MEM_SPREAD, NULL); | ||
| 2164 | |||
| 2165 | if (!qtd_cachep) | ||
| 2166 | return -ENOMEM; | ||
| 2167 | |||
| 2168 | qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh), | ||
| 2169 | 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); | ||
| 2170 | |||
| 2171 | if (!qh_cachep) { | ||
| 2172 | kmem_cache_destroy(qtd_cachep); | ||
| 2173 | return -ENOMEM; | ||
| 2174 | } | ||
| 2175 | |||
| 2176 | return 0; | ||
| 2177 | } | ||
| 2178 | |||
| 2179 | void deinit_kmem_cache(void) | ||
| 2180 | { | ||
| 2181 | kmem_cache_destroy(qtd_cachep); | ||
| 2182 | kmem_cache_destroy(qh_cachep); | ||
| 2183 | } | ||
| 2184 | |||
| 2185 | struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, | ||
| 2186 | u64 irqflags, struct device *dev, const char *busname) | ||
| 2187 | { | ||
| 2188 | struct usb_hcd *hcd; | ||
| 2189 | struct isp1760_hcd *priv; | ||
| 2190 | int ret; | ||
| 2191 | |||
| 2192 | if (usb_disabled()) | ||
| 2193 | return ERR_PTR(-ENODEV); | ||
| 2194 | |||
| 2195 | /* prevent usb-core allocating DMA pages */ | ||
| 2196 | dev->dma_mask = NULL; | ||
| 2197 | |||
| 2198 | hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev->bus_id); | ||
| 2199 | if (!hcd) | ||
| 2200 | return ERR_PTR(-ENOMEM); | ||
| 2201 | |||
| 2202 | priv = hcd_to_priv(hcd); | ||
| 2203 | init_memory(priv); | ||
| 2204 | hcd->regs = ioremap(res_start, res_len); | ||
| 2205 | if (!hcd->regs) { | ||
| 2206 | ret = -EIO; | ||
| 2207 | goto err_put; | ||
| 2208 | } | ||
| 2209 | |||
| 2210 | ret = usb_add_hcd(hcd, irq, irqflags); | ||
| 2211 | if (ret) | ||
| 2212 | goto err_unmap; | ||
| 2213 | |||
| 2214 | hcd->irq = irq; | ||
| 2215 | hcd->rsrc_start = res_start; | ||
| 2216 | hcd->rsrc_len = res_len; | ||
| 2217 | |||
| 2218 | return hcd; | ||
| 2219 | |||
| 2220 | err_unmap: | ||
| 2221 | iounmap(hcd->regs); | ||
| 2222 | |||
| 2223 | err_put: | ||
| 2224 | usb_put_hcd(hcd); | ||
| 2225 | |||
| 2226 | return ERR_PTR(ret); | ||
| 2227 | } | ||
| 2228 | |||
| 2229 | MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP"); | ||
| 2230 | MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>"); | ||
| 2231 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h new file mode 100644 index 000000000000..3d86d0f6b147 --- /dev/null +++ b/drivers/usb/host/isp1760-hcd.h | |||
| @@ -0,0 +1,206 @@ | |||
| 1 | #ifndef _ISP1760_HCD_H_ | ||
| 2 | #define _ISP1760_HCD_H_ | ||
| 3 | |||
| 4 | /* exports for if */ | ||
| 5 | struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, | ||
| 6 | u64 irqflags, struct device *dev, const char *busname); | ||
| 7 | int init_kmem_once(void); | ||
| 8 | void deinit_kmem_cache(void); | ||
| 9 | |||
| 10 | /* EHCI capability registers */ | ||
| 11 | #define HC_CAPLENGTH 0x00 | ||
| 12 | #define HC_HCSPARAMS 0x04 | ||
| 13 | #define HC_HCCPARAMS 0x08 | ||
| 14 | |||
| 15 | /* EHCI operational registers */ | ||
| 16 | #define HC_USBCMD 0x20 | ||
| 17 | #define HC_USBSTS 0x24 | ||
| 18 | #define HC_FRINDEX 0x2c | ||
| 19 | #define HC_CONFIGFLAG 0x60 | ||
| 20 | #define HC_PORTSC1 0x64 | ||
| 21 | #define HC_ISO_PTD_DONEMAP_REG 0x130 | ||
| 22 | #define HC_ISO_PTD_SKIPMAP_REG 0x134 | ||
| 23 | #define HC_ISO_PTD_LASTPTD_REG 0x138 | ||
| 24 | #define HC_INT_PTD_DONEMAP_REG 0x140 | ||
| 25 | #define HC_INT_PTD_SKIPMAP_REG 0x144 | ||
| 26 | #define HC_INT_PTD_LASTPTD_REG 0x148 | ||
| 27 | #define HC_ATL_PTD_DONEMAP_REG 0x150 | ||
| 28 | #define HC_ATL_PTD_SKIPMAP_REG 0x154 | ||
| 29 | #define HC_ATL_PTD_LASTPTD_REG 0x158 | ||
| 30 | |||
| 31 | /* Configuration Register */ | ||
| 32 | #define HC_HW_MODE_CTRL 0x300 | ||
| 33 | #define ALL_ATX_RESET (1 << 31) | ||
| 34 | #define HW_DATA_BUS_32BIT (1 << 8) | ||
| 35 | #define HW_DACK_POL_HIGH (1 << 6) | ||
| 36 | #define HW_DREQ_POL_HIGH (1 << 5) | ||
| 37 | #define HW_INTR_HIGH_ACT (1 << 2) | ||
| 38 | #define HW_INTR_EDGE_TRIG (1 << 1) | ||
| 39 | #define HW_GLOBAL_INTR_EN (1 << 0) | ||
| 40 | |||
| 41 | #define HC_CHIP_ID_REG 0x304 | ||
| 42 | #define HC_SCRATCH_REG 0x308 | ||
| 43 | |||
| 44 | #define HC_RESET_REG 0x30c | ||
| 45 | #define SW_RESET_RESET_HC (1 << 1) | ||
| 46 | #define SW_RESET_RESET_ALL (1 << 0) | ||
| 47 | |||
| 48 | #define HC_BUFFER_STATUS_REG 0x334 | ||
| 49 | #define ATL_BUFFER 0x1 | ||
| 50 | #define INT_BUFFER 0x2 | ||
| 51 | #define ISO_BUFFER 0x4 | ||
| 52 | #define BUFFER_MAP 0x7 | ||
| 53 | |||
| 54 | #define HC_MEMORY_REG 0x33c | ||
| 55 | #define HC_PORT1_CTRL 0x374 | ||
| 56 | #define PORT1_POWER (3 << 3) | ||
| 57 | #define PORT1_INIT1 (1 << 7) | ||
| 58 | #define PORT1_INIT2 (1 << 23) | ||
| 59 | |||
| 60 | /* Interrupt Register */ | ||
| 61 | #define HC_INTERRUPT_REG 0x310 | ||
| 62 | |||
| 63 | #define HC_INTERRUPT_ENABLE 0x314 | ||
| 64 | #define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT) | ||
| 65 | #define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT) | ||
| 66 | |||
| 67 | #define HC_ISO_INT (1 << 9) | ||
| 68 | #define HC_ATL_INT (1 << 8) | ||
| 69 | #define HC_INTL_INT (1 << 7) | ||
| 70 | #define HC_EOT_INT (1 << 3) | ||
| 71 | #define HC_SOT_INT (1 << 1) | ||
| 72 | |||
| 73 | #define HC_ISO_IRQ_MASK_OR_REG 0x318 | ||
| 74 | #define HC_INT_IRQ_MASK_OR_REG 0x31C | ||
| 75 | #define HC_ATL_IRQ_MASK_OR_REG 0x320 | ||
| 76 | #define HC_ISO_IRQ_MASK_AND_REG 0x324 | ||
| 77 | #define HC_INT_IRQ_MASK_AND_REG 0x328 | ||
| 78 | #define HC_ATL_IRQ_MASK_AND_REG 0x32C | ||
| 79 | |||
| 80 | /* Register sets */ | ||
| 81 | #define HC_BEGIN_OF_ATL 0x0c00 | ||
| 82 | #define HC_BEGIN_OF_INT 0x0800 | ||
| 83 | #define HC_BEGIN_OF_ISO 0x0400 | ||
| 84 | #define HC_BEGIN_OF_PAYLOAD 0x1000 | ||
| 85 | |||
| 86 | /* urb state*/ | ||
| 87 | #define DELETE_URB (0x0008) | ||
| 88 | #define NO_TRANSFER_ACTIVE (0xffffffff) | ||
| 89 | |||
| 90 | #define ATL_REGS_OFFSET (0xc00) | ||
| 91 | #define INT_REGS_OFFSET (0x800) | ||
| 92 | |||
| 93 | /* Philips Transfer Descriptor (PTD) */ | ||
| 94 | struct ptd { | ||
| 95 | __le32 dw0; | ||
| 96 | __le32 dw1; | ||
| 97 | __le32 dw2; | ||
| 98 | __le32 dw3; | ||
| 99 | __le32 dw4; | ||
| 100 | __le32 dw5; | ||
| 101 | __le32 dw6; | ||
| 102 | __le32 dw7; | ||
| 103 | }; | ||
| 104 | |||
| 105 | struct inter_packet_info { | ||
| 106 | void *data_buffer; | ||
| 107 | u32 payload; | ||
| 108 | #define PTD_FIRE_NEXT (1 << 0) | ||
| 109 | #define PTD_URB_FINISHED (1 << 1) | ||
| 110 | struct urb *urb; | ||
| 111 | struct isp1760_qh *qh; | ||
| 112 | struct isp1760_qtd *qtd; | ||
| 113 | }; | ||
| 114 | |||
| 115 | |||
| 116 | typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh, | ||
| 117 | struct isp1760_qtd *qtd); | ||
| 118 | |||
| 119 | #define isp1760_info(priv, fmt, args...) \ | ||
| 120 | dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args) | ||
| 121 | |||
| 122 | #define isp1760_err(priv, fmt, args...) \ | ||
| 123 | dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args) | ||
| 124 | |||
| 125 | /* chip memory management */ | ||
| 126 | struct memory_chunk { | ||
| 127 | unsigned int start; | ||
| 128 | unsigned int size; | ||
| 129 | unsigned int free; | ||
| 130 | }; | ||
| 131 | |||
| 132 | /* | ||
| 133 | * 60kb divided in: | ||
| 134 | * - 32 blocks @ 256 bytes | ||
| 135 | * - 20 blocks @ 1024 bytes | ||
| 136 | * - 4 blocks @ 8192 bytes | ||
| 137 | */ | ||
| 138 | |||
| 139 | #define BLOCK_1_NUM 32 | ||
| 140 | #define BLOCK_2_NUM 20 | ||
| 141 | #define BLOCK_3_NUM 4 | ||
| 142 | |||
| 143 | #define BLOCK_1_SIZE 256 | ||
| 144 | #define BLOCK_2_SIZE 1024 | ||
| 145 | #define BLOCK_3_SIZE 8192 | ||
| 146 | #define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM) | ||
| 147 | #define PAYLOAD_SIZE 0xf000 | ||
| 148 | |||
| 149 | /* I saw if some reloads if the pointer was negative */ | ||
| 150 | #define ISP1760_NULL_POINTER (0x400) | ||
| 151 | |||
| 152 | /* ATL */ | ||
| 153 | /* DW0 */ | ||
| 154 | #define PTD_VALID 1 | ||
| 155 | #define PTD_LENGTH(x) (((u32) x) << 3) | ||
| 156 | #define PTD_MAXPACKET(x) (((u32) x) << 18) | ||
| 157 | #define PTD_MULTI(x) (((u32) x) << 29) | ||
| 158 | #define PTD_ENDPOINT(x) (((u32) x) << 31) | ||
| 159 | /* DW1 */ | ||
| 160 | #define PTD_DEVICE_ADDR(x) (((u32) x) << 3) | ||
| 161 | #define PTD_PID_TOKEN(x) (((u32) x) << 10) | ||
| 162 | #define PTD_TRANS_BULK ((u32) 2 << 12) | ||
| 163 | #define PTD_TRANS_INT ((u32) 3 << 12) | ||
| 164 | #define PTD_TRANS_SPLIT ((u32) 1 << 14) | ||
| 165 | #define PTD_SE_USB_LOSPEED ((u32) 2 << 16) | ||
| 166 | #define PTD_PORT_NUM(x) (((u32) x) << 18) | ||
| 167 | #define PTD_HUB_NUM(x) (((u32) x) << 25) | ||
| 168 | #define PTD_PING(x) (((u32) x) << 26) | ||
| 169 | /* DW2 */ | ||
| 170 | #define PTD_RL_CNT(x) (((u32) x) << 25) | ||
| 171 | #define PTD_DATA_START_ADDR(x) (((u32) x) << 8) | ||
| 172 | #define BASE_ADDR 0x1000 | ||
| 173 | /* DW3 */ | ||
| 174 | #define PTD_CERR(x) (((u32) x) << 23) | ||
| 175 | #define PTD_NAC_CNT(x) (((u32) x) << 19) | ||
| 176 | #define PTD_ACTIVE ((u32) 1 << 31) | ||
| 177 | #define PTD_DATA_TOGGLE(x) (((u32) x) << 25) | ||
| 178 | |||
| 179 | #define DW3_HALT_BIT (1 << 30) | ||
| 180 | #define DW3_ERROR_BIT (1 << 28) | ||
| 181 | #define DW3_QTD_ACTIVE (1 << 31) | ||
| 182 | |||
| 183 | #define INT_UNDERRUN (1 << 2) | ||
| 184 | #define INT_BABBLE (1 << 1) | ||
| 185 | #define INT_EXACT (1 << 0) | ||
| 186 | |||
| 187 | #define DW1_GET_PID(x) (((x) >> 10) & 0x3) | ||
| 188 | #define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff) | ||
| 189 | #define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff) | ||
| 190 | |||
| 191 | #define SETUP_PID (2) | ||
| 192 | #define IN_PID (1) | ||
| 193 | #define OUT_PID (0) | ||
| 194 | #define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3) | ||
| 195 | |||
| 196 | #define DATA_TOGGLE (1 << 31) | ||
| 197 | #define GET_DATA_TOGGLE(x) ((x) >> 31) | ||
| 198 | |||
| 199 | /* Errata 1 */ | ||
| 200 | #define RL_COUNTER (0) | ||
| 201 | #define NAK_COUNTER (0) | ||
| 202 | #define ERR_COUNTER (2) | ||
| 203 | |||
| 204 | #define HC_ATL_PL_SIZE (8192) | ||
| 205 | |||
| 206 | #endif | ||
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c new file mode 100644 index 000000000000..73fb2a38f1e4 --- /dev/null +++ b/drivers/usb/host/isp1760-if.c | |||
| @@ -0,0 +1,298 @@ | |||
| 1 | /* | ||
| 2 | * Glue code for the ISP1760 driver and bus | ||
| 3 | * Currently there is support for | ||
| 4 | * - OpenFirmware | ||
| 5 | * - PCI | ||
| 6 | * | ||
| 7 | * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> | ||
| 8 | * | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/usb.h> | ||
| 12 | #include <linux/io.h> | ||
| 13 | |||
| 14 | #include "../core/hcd.h" | ||
| 15 | #include "isp1760-hcd.h" | ||
| 16 | |||
| 17 | #ifdef CONFIG_USB_ISP1760_OF | ||
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/of_platform.h> | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #ifdef CONFIG_USB_ISP1760_PCI | ||
| 23 | #include <linux/pci.h> | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #ifdef CONFIG_USB_ISP1760_OF | ||
| 27 | static int of_isp1760_probe(struct of_device *dev, | ||
| 28 | const struct of_device_id *match) | ||
| 29 | { | ||
| 30 | struct usb_hcd *hcd; | ||
| 31 | struct device_node *dp = dev->node; | ||
| 32 | struct resource *res; | ||
| 33 | struct resource memory; | ||
| 34 | struct of_irq oirq; | ||
| 35 | int virq; | ||
| 36 | u64 res_len; | ||
| 37 | int ret; | ||
| 38 | |||
| 39 | ret = of_address_to_resource(dp, 0, &memory); | ||
| 40 | if (ret) | ||
| 41 | return -ENXIO; | ||
| 42 | |||
| 43 | res = request_mem_region(memory.start, memory.end - memory.start + 1, | ||
| 44 | dev->dev.bus_id); | ||
| 45 | if (!res) | ||
| 46 | return -EBUSY; | ||
| 47 | |||
| 48 | res_len = memory.end - memory.start + 1; | ||
| 49 | |||
| 50 | if (of_irq_map_one(dp, 0, &oirq)) { | ||
| 51 | ret = -ENODEV; | ||
| 52 | goto release_reg; | ||
| 53 | } | ||
| 54 | |||
| 55 | virq = irq_create_of_mapping(oirq.controller, oirq.specifier, | ||
| 56 | oirq.size); | ||
| 57 | |||
| 58 | hcd = isp1760_register(memory.start, res_len, virq, | ||
| 59 | IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); | ||
| 60 | if (IS_ERR(hcd)) { | ||
| 61 | ret = PTR_ERR(hcd); | ||
| 62 | goto release_reg; | ||
| 63 | } | ||
| 64 | |||
| 65 | dev_set_drvdata(&dev->dev, hcd); | ||
| 66 | return ret; | ||
| 67 | |||
| 68 | release_reg: | ||
| 69 | release_mem_region(memory.start, memory.end - memory.start + 1); | ||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int of_isp1760_remove(struct of_device *dev) | ||
| 74 | { | ||
| 75 | struct usb_hcd *hcd = dev_get_drvdata(&dev->dev); | ||
| 76 | |||
| 77 | dev_set_drvdata(&dev->dev, NULL); | ||
| 78 | |||
| 79 | usb_remove_hcd(hcd); | ||
| 80 | iounmap(hcd->regs); | ||
| 81 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
| 82 | usb_put_hcd(hcd); | ||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static struct of_device_id of_isp1760_match[] = { | ||
| 87 | { | ||
| 88 | .compatible = "nxp,usb-isp1760", | ||
| 89 | }, | ||
| 90 | { }, | ||
| 91 | }; | ||
| 92 | MODULE_DEVICE_TABLE(of, of_isp1760_match); | ||
| 93 | |||
| 94 | static struct of_platform_driver isp1760_of_driver = { | ||
| 95 | .name = "nxp-isp1760", | ||
| 96 | .match_table = of_isp1760_match, | ||
| 97 | .probe = of_isp1760_probe, | ||
| 98 | .remove = of_isp1760_remove, | ||
| 99 | }; | ||
| 100 | #endif | ||
| 101 | |||
| 102 | #ifdef CONFIG_USB_ISP1760_PCI | ||
| 103 | static u32 nxp_pci_io_base; | ||
| 104 | static u32 iolength; | ||
| 105 | static u32 pci_mem_phy0; | ||
| 106 | static u32 length; | ||
| 107 | static u8 *chip_addr; | ||
| 108 | static u8 *iobase; | ||
| 109 | |||
| 110 | static int __devinit isp1761_pci_probe(struct pci_dev *dev, | ||
| 111 | const struct pci_device_id *id) | ||
| 112 | { | ||
| 113 | u8 latency, limit; | ||
| 114 | __u32 reg_data; | ||
| 115 | int retry_count; | ||
| 116 | int length; | ||
| 117 | int status = 1; | ||
| 118 | struct usb_hcd *hcd; | ||
| 119 | |||
| 120 | if (usb_disabled()) | ||
| 121 | return -ENODEV; | ||
| 122 | |||
| 123 | if (pci_enable_device(dev) < 0) | ||
| 124 | return -ENODEV; | ||
| 125 | |||
| 126 | if (!dev->irq) | ||
| 127 | return -ENODEV; | ||
| 128 | |||
| 129 | /* Grab the PLX PCI mem maped port start address we need */ | ||
| 130 | nxp_pci_io_base = pci_resource_start(dev, 0); | ||
| 131 | iolength = pci_resource_len(dev, 0); | ||
| 132 | |||
| 133 | if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) { | ||
| 134 | printk(KERN_ERR "request region #1\n"); | ||
| 135 | return -EBUSY; | ||
| 136 | } | ||
| 137 | |||
| 138 | iobase = ioremap_nocache(nxp_pci_io_base, iolength); | ||
| 139 | if (!iobase) { | ||
| 140 | printk(KERN_ERR "ioremap #1\n"); | ||
| 141 | release_mem_region(nxp_pci_io_base, iolength); | ||
| 142 | return -ENOMEM; | ||
| 143 | } | ||
| 144 | /* Grab the PLX PCI shared memory of the ISP 1761 we need */ | ||
| 145 | pci_mem_phy0 = pci_resource_start(dev, 3); | ||
| 146 | length = pci_resource_len(dev, 3); | ||
| 147 | |||
| 148 | if (length < 0xffff) { | ||
| 149 | printk(KERN_ERR "memory length for this resource is less than " | ||
| 150 | "required\n"); | ||
| 151 | release_mem_region(nxp_pci_io_base, iolength); | ||
| 152 | iounmap(iobase); | ||
| 153 | return -ENOMEM; | ||
| 154 | } | ||
| 155 | |||
| 156 | if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) { | ||
| 157 | printk(KERN_ERR "host controller already in use\n"); | ||
| 158 | release_mem_region(nxp_pci_io_base, iolength); | ||
| 159 | iounmap(iobase); | ||
| 160 | return -EBUSY; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* bad pci latencies can contribute to overruns */ | ||
| 164 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); | ||
| 165 | if (latency) { | ||
| 166 | pci_read_config_byte(dev, PCI_MAX_LAT, &limit); | ||
| 167 | if (limit && limit < latency) | ||
| 168 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit); | ||
| 169 | } | ||
| 170 | |||
| 171 | /* Try to check whether we can access Scratch Register of | ||
| 172 | * Host Controller or not. The initial PCI access is retried until | ||
| 173 | * local init for the PCI bridge is completed | ||
| 174 | */ | ||
| 175 | retry_count = 20; | ||
| 176 | reg_data = 0; | ||
| 177 | while ((reg_data != 0xFACE) && retry_count) { | ||
| 178 | /*by default host is in 16bit mode, so | ||
| 179 | * io operations at this stage must be 16 bit | ||
| 180 | * */ | ||
| 181 | writel(0xface, chip_addr + HC_SCRATCH_REG); | ||
| 182 | udelay(100); | ||
| 183 | reg_data = readl(chip_addr + HC_SCRATCH_REG); | ||
| 184 | retry_count--; | ||
| 185 | } | ||
| 186 | |||
| 187 | /* Host Controller presence is detected by writing to scratch register | ||
| 188 | * and reading back and checking the contents are same or not | ||
| 189 | */ | ||
| 190 | if (reg_data != 0xFACE) { | ||
| 191 | err("scratch register mismatch %x", reg_data); | ||
| 192 | goto clean; | ||
| 193 | } | ||
| 194 | |||
| 195 | pci_set_master(dev); | ||
| 196 | |||
| 197 | status = readl(iobase + 0x68); | ||
| 198 | status |= 0x900; | ||
| 199 | writel(status, iobase + 0x68); | ||
| 200 | |||
| 201 | dev->dev.dma_mask = NULL; | ||
| 202 | hcd = isp1760_register(pci_mem_phy0, length, dev->irq, | ||
| 203 | IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); | ||
| 204 | pci_set_drvdata(dev, hcd); | ||
| 205 | if (!hcd) | ||
| 206 | return 0; | ||
| 207 | clean: | ||
| 208 | status = -ENODEV; | ||
| 209 | iounmap(iobase); | ||
| 210 | release_mem_region(pci_mem_phy0, length); | ||
| 211 | release_mem_region(nxp_pci_io_base, iolength); | ||
| 212 | return status; | ||
| 213 | } | ||
| 214 | static void isp1761_pci_remove(struct pci_dev *dev) | ||
| 215 | { | ||
| 216 | struct usb_hcd *hcd; | ||
| 217 | |||
| 218 | hcd = pci_get_drvdata(dev); | ||
| 219 | |||
| 220 | usb_remove_hcd(hcd); | ||
| 221 | iounmap(hcd->regs); | ||
| 222 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | ||
| 223 | usb_put_hcd(hcd); | ||
| 224 | |||
| 225 | pci_disable_device(dev); | ||
| 226 | |||
| 227 | iounmap(iobase); | ||
| 228 | iounmap(chip_addr); | ||
| 229 | |||
| 230 | release_mem_region(nxp_pci_io_base, iolength); | ||
| 231 | release_mem_region(pci_mem_phy0, length); | ||
| 232 | } | ||
| 233 | |||
| 234 | static void isp1761_pci_shutdown(struct pci_dev *dev) | ||
| 235 | { | ||
| 236 | printk(KERN_ERR "ips1761_pci_shutdown\n"); | ||
| 237 | } | ||
| 238 | |||
| 239 | static const struct pci_device_id isp1760_plx [] = { { | ||
| 240 | /* handle any USB 2.0 EHCI controller */ | ||
| 241 | PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0), | ||
| 242 | .driver_data = 0, | ||
| 243 | }, | ||
| 244 | { /* end: all zeroes */ } | ||
| 245 | }; | ||
| 246 | MODULE_DEVICE_TABLE(pci, isp1760_plx); | ||
| 247 | |||
| 248 | static struct pci_driver isp1761_pci_driver = { | ||
| 249 | .name = "isp1760", | ||
| 250 | .id_table = isp1760_plx, | ||
| 251 | .probe = isp1761_pci_probe, | ||
| 252 | .remove = isp1761_pci_remove, | ||
| 253 | .shutdown = isp1761_pci_shutdown, | ||
| 254 | }; | ||
| 255 | #endif | ||
| 256 | |||
| 257 | static int __init isp1760_init(void) | ||
| 258 | { | ||
| 259 | int ret; | ||
| 260 | |||
| 261 | init_kmem_once(); | ||
| 262 | |||
| 263 | #ifdef CONFIG_USB_ISP1760_OF | ||
| 264 | ret = of_register_platform_driver(&isp1760_of_driver); | ||
| 265 | if (ret) { | ||
| 266 | deinit_kmem_cache(); | ||
| 267 | return ret; | ||
| 268 | } | ||
| 269 | #endif | ||
| 270 | #ifdef CONFIG_USB_ISP1760_PCI | ||
| 271 | ret = pci_register_driver(&isp1761_pci_driver); | ||
| 272 | if (ret) | ||
| 273 | goto unreg_of; | ||
| 274 | #endif | ||
| 275 | return ret; | ||
| 276 | |||
| 277 | #ifdef CONFIG_USB_ISP1760_PCI | ||
| 278 | unreg_of: | ||
| 279 | #endif | ||
| 280 | #ifdef CONFIG_USB_ISP1760_OF | ||
| 281 | of_unregister_platform_driver(&isp1760_of_driver); | ||
| 282 | #endif | ||
| 283 | deinit_kmem_cache(); | ||
| 284 | return ret; | ||
| 285 | } | ||
| 286 | module_init(isp1760_init); | ||
| 287 | |||
| 288 | static void __exit isp1760_exit(void) | ||
| 289 | { | ||
| 290 | #ifdef CONFIG_USB_ISP1760_OF | ||
| 291 | of_unregister_platform_driver(&isp1760_of_driver); | ||
| 292 | #endif | ||
| 293 | #ifdef CONFIG_USB_ISP1760_PCI | ||
| 294 | pci_unregister_driver(&isp1761_pci_driver); | ||
| 295 | #endif | ||
| 296 | deinit_kmem_cache(); | ||
| 297 | } | ||
| 298 | module_exit(isp1760_exit); | ||
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 17dc2eccda83..79a78029f896 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
| @@ -613,7 +613,7 @@ static void start_hnp(struct ohci_hcd *ohci); | |||
| 613 | static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) | 613 | static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) |
| 614 | { | 614 | { |
| 615 | __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; | 615 | __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; |
| 616 | u32 temp; | 616 | u32 temp = 0; |
| 617 | u16 now = ohci_readl(ohci, &ohci->regs->fmnumber); | 617 | u16 now = ohci_readl(ohci, &ohci->regs->fmnumber); |
| 618 | u16 reset_done = now + PORT_RESET_MSEC; | 618 | u16 reset_done = now + PORT_RESET_MSEC; |
| 619 | int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC); | 619 | int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC); |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index d3e0d8aa3980..3a7bfe7a8874 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
| @@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) | |||
| 234 | return 0; | 234 | return 0; |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | static int remote_wakeup_is_broken(struct uhci_hcd *uhci) | 237 | static int global_suspend_mode_is_broken(struct uhci_hcd *uhci) |
| 238 | { | 238 | { |
| 239 | int port; | 239 | int port; |
| 240 | const char *sys_info; | 240 | const char *sys_info; |
| @@ -261,27 +261,60 @@ __releases(uhci->lock) | |||
| 261 | __acquires(uhci->lock) | 261 | __acquires(uhci->lock) |
| 262 | { | 262 | { |
| 263 | int auto_stop; | 263 | int auto_stop; |
| 264 | int int_enable, egsm_enable; | 264 | int int_enable, egsm_enable, wakeup_enable; |
| 265 | struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub; | 265 | struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub; |
| 266 | 266 | ||
| 267 | auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); | 267 | auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); |
| 268 | dev_dbg(&rhdev->dev, "%s%s\n", __func__, | 268 | dev_dbg(&rhdev->dev, "%s%s\n", __func__, |
| 269 | (auto_stop ? " (auto-stop)" : "")); | 269 | (auto_stop ? " (auto-stop)" : "")); |
| 270 | 270 | ||
| 271 | /* Enable resume-detect interrupts if they work. | 271 | /* Start off by assuming Resume-Detect interrupts and EGSM work |
| 272 | * Then enter Global Suspend mode if _it_ works, still configured. | 272 | * and that remote wakeups should be enabled. |
| 273 | */ | 273 | */ |
| 274 | egsm_enable = USBCMD_EGSM; | 274 | egsm_enable = USBCMD_EGSM; |
| 275 | uhci->working_RD = 1; | 275 | uhci->RD_enable = 1; |
| 276 | int_enable = USBINTR_RESUME; | 276 | int_enable = USBINTR_RESUME; |
| 277 | if (remote_wakeup_is_broken(uhci)) | 277 | wakeup_enable = 1; |
| 278 | egsm_enable = 0; | 278 | |
| 279 | if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable || | 279 | /* In auto-stop mode wakeups must always be detected, but |
| 280 | * Resume-Detect interrupts may be prohibited. (In the absence | ||
| 281 | * of CONFIG_PM, they are always disallowed.) | ||
| 282 | */ | ||
| 283 | if (auto_stop) { | ||
| 284 | if (!device_may_wakeup(&rhdev->dev)) | ||
| 285 | int_enable = 0; | ||
| 286 | |||
| 287 | /* In bus-suspend mode wakeups may be disabled, but if they are | ||
| 288 | * allowed then so are Resume-Detect interrupts. | ||
| 289 | */ | ||
| 290 | } else { | ||
| 280 | #ifdef CONFIG_PM | 291 | #ifdef CONFIG_PM |
| 281 | (!auto_stop && !rhdev->do_remote_wakeup) || | 292 | if (!rhdev->do_remote_wakeup) |
| 293 | wakeup_enable = 0; | ||
| 282 | #endif | 294 | #endif |
| 283 | (auto_stop && !device_may_wakeup(&rhdev->dev))) | 295 | } |
| 284 | uhci->working_RD = int_enable = 0; | 296 | |
| 297 | /* EGSM causes the root hub to echo a 'K' signal (resume) out any | ||
| 298 | * port which requests a remote wakeup. According to the USB spec, | ||
| 299 | * every hub is supposed to do this. But if we are ignoring | ||
| 300 | * remote-wakeup requests anyway then there's no point to it. | ||
| 301 | * We also shouldn't enable EGSM if it's broken. | ||
| 302 | */ | ||
| 303 | if (!wakeup_enable || global_suspend_mode_is_broken(uhci)) | ||
| 304 | egsm_enable = 0; | ||
| 305 | |||
| 306 | /* If we're ignoring wakeup events then there's no reason to | ||
| 307 | * enable Resume-Detect interrupts. We also shouldn't enable | ||
| 308 | * them if they are broken or disallowed. | ||
| 309 | * | ||
| 310 | * This logic may lead us to enabling RD but not EGSM. The UHCI | ||
| 311 | * spec foolishly says that RD works only when EGSM is on, but | ||
| 312 | * there's no harm in enabling it anyway -- perhaps some chips | ||
| 313 | * will implement it! | ||
| 314 | */ | ||
| 315 | if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) || | ||
| 316 | !int_enable) | ||
| 317 | uhci->RD_enable = int_enable = 0; | ||
| 285 | 318 | ||
| 286 | outw(int_enable, uhci->io_addr + USBINTR); | 319 | outw(int_enable, uhci->io_addr + USBINTR); |
| 287 | outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); | 320 | outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); |
| @@ -308,7 +341,11 @@ __acquires(uhci->lock) | |||
| 308 | 341 | ||
| 309 | uhci->rh_state = new_state; | 342 | uhci->rh_state = new_state; |
| 310 | uhci->is_stopped = UHCI_IS_STOPPED; | 343 | uhci->is_stopped = UHCI_IS_STOPPED; |
| 311 | uhci_to_hcd(uhci)->poll_rh = !int_enable; | 344 | |
| 345 | /* If interrupts don't work and remote wakeup is enabled then | ||
| 346 | * the suspended root hub needs to be polled. | ||
| 347 | */ | ||
| 348 | uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable); | ||
| 312 | 349 | ||
| 313 | uhci_scan_schedule(uhci); | 350 | uhci_scan_schedule(uhci); |
| 314 | uhci_fsbr_off(uhci); | 351 | uhci_fsbr_off(uhci); |
| @@ -344,9 +381,12 @@ __acquires(uhci->lock) | |||
| 344 | * for 20 ms. | 381 | * for 20 ms. |
| 345 | */ | 382 | */ |
| 346 | if (uhci->rh_state == UHCI_RH_SUSPENDED) { | 383 | if (uhci->rh_state == UHCI_RH_SUSPENDED) { |
| 384 | unsigned egsm; | ||
| 385 | |||
| 386 | /* Keep EGSM on if it was set before */ | ||
| 387 | egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM; | ||
| 347 | uhci->rh_state = UHCI_RH_RESUMING; | 388 | uhci->rh_state = UHCI_RH_RESUMING; |
| 348 | outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF, | 389 | outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD); |
| 349 | uhci->io_addr + USBCMD); | ||
| 350 | spin_unlock_irq(&uhci->lock); | 390 | spin_unlock_irq(&uhci->lock); |
| 351 | msleep(20); | 391 | msleep(20); |
| 352 | spin_lock_irq(&uhci->lock); | 392 | spin_lock_irq(&uhci->lock); |
| @@ -801,8 +841,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd) | |||
| 801 | 841 | ||
| 802 | spin_unlock_irq(&uhci->lock); | 842 | spin_unlock_irq(&uhci->lock); |
| 803 | 843 | ||
| 804 | if (!uhci->working_RD) { | 844 | /* If interrupts don't work and remote wakeup is enabled then |
| 805 | /* Suspended root hub needs to be polled */ | 845 | * the suspended root hub needs to be polled. |
| 846 | */ | ||
| 847 | if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) { | ||
| 806 | hcd->poll_rh = 1; | 848 | hcd->poll_rh = 1; |
| 807 | usb_hcd_poll_rh_status(hcd); | 849 | usb_hcd_poll_rh_status(hcd); |
| 808 | } | 850 | } |
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 340d6ed3e6e9..7d01c5677f92 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
| @@ -400,8 +400,9 @@ struct uhci_hcd { | |||
| 400 | unsigned int scan_in_progress:1; /* Schedule scan is running */ | 400 | unsigned int scan_in_progress:1; /* Schedule scan is running */ |
| 401 | unsigned int need_rescan:1; /* Redo the schedule scan */ | 401 | unsigned int need_rescan:1; /* Redo the schedule scan */ |
| 402 | unsigned int dead:1; /* Controller has died */ | 402 | unsigned int dead:1; /* Controller has died */ |
| 403 | unsigned int working_RD:1; /* Suspended root hub doesn't | 403 | unsigned int RD_enable:1; /* Suspended root hub with |
| 404 | need to be polled */ | 404 | Resume-Detect interrupts |
| 405 | enabled */ | ||
| 405 | unsigned int is_initialized:1; /* Data structure is usable */ | 406 | unsigned int is_initialized:1; /* Data structure is usable */ |
| 406 | unsigned int fsbr_is_on:1; /* FSBR is turned on */ | 407 | unsigned int fsbr_is_on:1; /* FSBR is turned on */ |
| 407 | unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */ | 408 | unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */ |
