[U-Boot] [PATCH 0/3] USB subsystem changes for 64 bit

This patch series contains USB fixes and enhancements for more complete support of 64-bit architectures

This patch converts USB protocol headers to use explicitly sized fields like the rest of the code
Signed-off-by: Radha Mohan Chintakuntla rchintakuntla@cavium.com Signed-off-by: Sergey Temerkhanov s.temerkhanov@gmail.com --- include/usb.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/include/usb.h b/include/usb.h index a8fee0b..2c3d506 100644 --- a/include/usb.h +++ b/include/usb.h @@ -45,20 +45,20 @@
/* device request (setup) */ struct devrequest { - unsigned char requesttype; - unsigned char request; - unsigned short value; - unsigned short index; - unsigned short length; + __u8 requesttype; + __u8 request; + __le16 value; + __le16 index; + __le16 length; } __attribute__ ((packed));
/* Interface */ struct usb_interface { struct usb_interface_descriptor desc;
- unsigned char no_of_ep; - unsigned char num_altsetting; - unsigned char act_altsetting; + __u8 no_of_ep; + __u8 num_altsetting; + __u8 act_altsetting;
struct usb_endpoint_descriptor ep_desc[USB_MAXENDPOINTS]; /* @@ -73,7 +73,7 @@ struct usb_interface { struct usb_config { struct usb_config_descriptor desc;
- unsigned char no_of_if; /* number of interfaces */ + __u8 no_of_if; /* number of interfaces */ struct usb_interface if_desc[USB_MAXINTERFACES]; } __attribute__ ((packed));

This commit allows xHCI to use both 64 and 32 bit memory physical addresses depending on architecture it's being built for. Also it makes use of readq()/writeq() on 64-bit systems
Signed-off-by: Sergey Temerkhanov s.temerkhanov@gmail.com Signed-off-by: Radha Mohan Chintakuntla rchintakuntla@cavium.com --- drivers/usb/host/xhci-mem.c | 20 ++++++++++---------- drivers/usb/host/xhci-ring.c | 30 +++++++++++++++--------------- drivers/usb/host/xhci.c | 10 +++++----- drivers/usb/host/xhci.h | 13 +++++++++++-- 4 files changed, 41 insertions(+), 32 deletions(-)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 89908e8..10f11cd 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -31,7 +31,7 @@ * @param len the length of the cache line to be flushed * @return none */ -void xhci_flush_cache(uint32_t addr, u32 len) +void xhci_flush_cache(uintptr_t addr, u32 len) { BUG_ON((void *)addr == NULL || len == 0);
@@ -46,7 +46,7 @@ void xhci_flush_cache(uint32_t addr, u32 len) * @param len the length of the cache line to be invalidated * @return none */ -void xhci_inval_cache(uint32_t addr, u32 len) +void xhci_inval_cache(uintptr_t addr, u32 len) { BUG_ON((void *)addr == NULL || len == 0);
@@ -175,7 +175,7 @@ static void *xhci_malloc(unsigned int size) BUG_ON(!ptr); memset(ptr, '\0', size);
- xhci_flush_cache((uint32_t)ptr, size); + xhci_flush_cache((uintptr_t)ptr, size);
return ptr; } @@ -400,8 +400,8 @@ int xhci_alloc_virt_device(struct usb_device *udev) /* Point to output device context in dcbaa. */ ctrl->dcbaa->dev_context_ptrs[slot_id] = byte_64;
- xhci_flush_cache((uint32_t)&ctrl->dcbaa->dev_context_ptrs[slot_id], - sizeof(__le64)); + xhci_flush_cache((uintptr_t)&ctrl->dcbaa->dev_context_ptrs[slot_id], + sizeof(__le64)); return 0; }
@@ -478,8 +478,8 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr, entry->rsvd = 0; seg = seg->next; } - xhci_flush_cache((uint32_t)ctrl->erst.entries, - ERST_NUM_SEGS * sizeof(struct xhci_erst_entry)); + xhci_flush_cache((uintptr_t)ctrl->erst.entries, + ERST_NUM_SEGS * sizeof(struct xhci_erst_entry));
deq = (unsigned long)ctrl->event_ring->dequeue;
@@ -496,7 +496,7 @@ int xhci_mem_init(struct xhci_ctrl *ctrl, struct xhci_hccr *hccr, /* this is the event ring segment table pointer */ val_64 = xhci_readq(&ctrl->ir_set->erst_base); val_64 &= ERST_PTR_MASK; - val_64 |= ((u32)(ctrl->erst.entries) & ~ERST_PTR_MASK); + val_64 |= ((uintptr_t)(ctrl->erst.entries) & ~ERST_PTR_MASK);
xhci_writeq(&ctrl->ir_set->erst_base, val_64);
@@ -715,6 +715,6 @@ void xhci_setup_addressable_virt_dev(struct usb_device *udev)
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
- xhci_flush_cache((uint32_t)ep0_ctx, sizeof(struct xhci_ep_ctx)); - xhci_flush_cache((uint32_t)slot_ctx, sizeof(struct xhci_slot_ctx)); + xhci_flush_cache((uintptr_t)ep0_ctx, sizeof(struct xhci_ep_ctx)); + xhci_flush_cache((uintptr_t)slot_ctx, sizeof(struct xhci_slot_ctx)); } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b5aade9..f3759d4 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -122,8 +122,8 @@ static void inc_enq(struct xhci_ctrl *ctrl, struct xhci_ring *ring, next->link.control |= cpu_to_le32(chain);
next->link.control ^= cpu_to_le32(TRB_CYCLE); - xhci_flush_cache((uint32_t)next, - sizeof(union xhci_trb)); + xhci_flush_cache((uintptr_t)next, + sizeof(union xhci_trb)); } /* Toggle the cycle bit after the last ring segment. */ if (last_trb_on_last_seg(ctrl, ring, @@ -191,7 +191,7 @@ static struct xhci_generic_trb *queue_trb(struct xhci_ctrl *ctrl, for (i = 0; i < 4; i++) trb->field[i] = cpu_to_le32(trb_fields[i]);
- xhci_flush_cache((uint32_t)trb, sizeof(struct xhci_generic_trb)); + xhci_flush_cache((uintptr_t)trb, sizeof(struct xhci_generic_trb));
inc_enq(ctrl, ring, more_trbs_coming);
@@ -244,7 +244,7 @@ static int prepare_ring(struct xhci_ctrl *ctrl, struct xhci_ring *ep_ring,
next->link.control ^= cpu_to_le32(TRB_CYCLE);
- xhci_flush_cache((uint32_t)next, sizeof(union xhci_trb)); + xhci_flush_cache((uintptr_t)next, sizeof(union xhci_trb));
/* Toggle the cycle bit after the last ring segment. */ if (last_trb_on_last_seg(ctrl, ep_ring, @@ -364,7 +364,7 @@ static void giveback_first_trb(struct usb_device *udev, int ep_index, else start_trb->field[3] &= cpu_to_le32(~TRB_CYCLE);
- xhci_flush_cache((uint32_t)start_trb, sizeof(struct xhci_generic_trb)); + xhci_flush_cache((uintptr_t)start_trb, sizeof(struct xhci_generic_trb));
/* Ringing EP doorbell here */ xhci_writel(&ctrl->dba->doorbell[udev->slot_id], @@ -403,8 +403,8 @@ static int event_ready(struct xhci_ctrl *ctrl) { union xhci_trb *event;
- xhci_inval_cache((uint32_t)ctrl->event_ring->dequeue, - sizeof(union xhci_trb)); + xhci_inval_cache((uintptr_t)ctrl->event_ring->dequeue, + sizeof(union xhci_trb));
event = ctrl->event_ring->dequeue;
@@ -576,8 +576,8 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, ep_index = usb_pipe_ep_index(pipe); virt_dev = ctrl->devs[slot_id];
- xhci_inval_cache((uint32_t)virt_dev->out_ctx->bytes, - virt_dev->out_ctx->size); + xhci_inval_cache((uintptr_t)virt_dev->out_ctx->bytes, + virt_dev->out_ctx->size);
ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index);
@@ -644,7 +644,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, first_trb = true;
/* flush the buffer before use */ - xhci_flush_cache((uint32_t)buffer, length); + xhci_flush_cache((uintptr_t)buffer, length);
/* Queue the first TRB, even if it's zero-length */ do { @@ -722,7 +722,7 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe,
record_transfer_result(udev, event, length); xhci_acknowledge_event(ctrl); - xhci_inval_cache((uint32_t)buffer, length); + xhci_inval_cache((uintptr_t)buffer, length);
return (udev->status != USB_ST_NOT_PROC) ? 0 : -1; } @@ -776,8 +776,8 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, return ret; }
- xhci_inval_cache((uint32_t)virt_dev->out_ctx->bytes, - virt_dev->out_ctx->size); + xhci_inval_cache((uintptr_t)virt_dev->out_ctx->bytes, + virt_dev->out_ctx->size);
struct xhci_ep_ctx *ep_ctx = NULL; ep_ctx = xhci_get_ep_ctx(ctrl, virt_dev->out_ctx, ep_index); @@ -874,7 +874,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, trb_fields[2] = length_field; trb_fields[3] = field | ep_ring->cycle_state;
- xhci_flush_cache((uint32_t)buffer, length); + xhci_flush_cache((uintptr_t)buffer, length); queue_trb(ctrl, ep_ring, true, trb_fields); }
@@ -915,7 +915,7 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
/* Invalidate buffer to make it available to usb-core */ if (length > 0) - xhci_inval_cache((uint32_t)buffer, length); + xhci_inval_cache((uintptr_t)buffer, length);
if (GET_COMP_CODE(le32_to_cpu(event->trans_event.transfer_len)) == COMP_SHORT_TX) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 87f2972..f8b5ce4 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -256,7 +256,7 @@ static int xhci_configure_endpoints(struct usb_device *udev, bool ctx_change) virt_dev = ctrl->devs[udev->slot_id]; in_ctx = virt_dev->in_ctx;
- xhci_flush_cache((uint32_t)in_ctx->bytes, in_ctx->size); + xhci_flush_cache((uintptr_t)in_ctx->bytes, in_ctx->size); xhci_queue_command(ctrl, in_ctx->bytes, udev->slot_id, 0, ctx_change ? TRB_EVAL_CONTEXT : TRB_CONFIG_EP); event = xhci_wait_for_event(ctrl, TRB_COMPLETION); @@ -325,7 +325,7 @@ static int xhci_set_configuration(struct usb_device *udev) max_ep_flag = ep_flag; }
- xhci_inval_cache((uint32_t)out_ctx->bytes, out_ctx->size); + xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size);
/* slot context */ xhci_slot_copy(ctrl, in_ctx, out_ctx); @@ -442,8 +442,8 @@ static int xhci_address_device(struct usb_device *udev) */ return ret;
- xhci_inval_cache((uint32_t)virt_dev->out_ctx->bytes, - virt_dev->out_ctx->size); + xhci_inval_cache((uintptr_t)virt_dev->out_ctx->bytes, + virt_dev->out_ctx->size); slot_ctx = xhci_get_slot_ctx(ctrl, virt_dev->out_ctx);
debug("xHC internal address is: %d\n", @@ -525,7 +525,7 @@ int xhci_check_maxpacket(struct usb_device *udev) ifdesc = &udev->config.if_desc[0];
out_ctx = ctrl->devs[slot_id]->out_ctx; - xhci_inval_cache((uint32_t)out_ctx->bytes, out_ctx->size); + xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size);
ep_ctx = xhci_get_ep_ctx(ctrl, out_ctx, ep_index); hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 6685ed2..0951e87 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -17,6 +17,7 @@ #ifndef HOST_XHCI_H_ #define HOST_XHCI_H_
+#include <asm/types.h> #include <asm/cache.h> #include <asm/io.h> #include <linux/list.h> @@ -1108,20 +1109,28 @@ static inline void xhci_writel(uint32_t volatile *regs, const unsigned int val) */ static inline u64 xhci_readq(__le64 volatile *regs) { +#if BITS_PER_LONG == 64 + return readq(regs); +#else __u32 *ptr = (__u32 *)regs; u64 val_lo = readl(ptr); u64 val_hi = readl(ptr + 1); return val_lo + (val_hi << 32); +#endif }
static inline void xhci_writeq(__le64 volatile *regs, const u64 val) { +#if BITS_PER_LONG == 64 + writeq(val, regs); +#else __u32 *ptr = (__u32 *)regs; u32 val_lo = lower_32_bits(val); /* FIXME */ u32 val_hi = upper_32_bits(val); writel(val_lo, ptr); writel(val_hi, ptr + 1); +#endif }
int xhci_hcd_init(int index, struct xhci_hccr **ret_hccr, @@ -1242,8 +1251,8 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long pipe, int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe, struct devrequest *req, int length, void *buffer); int xhci_check_maxpacket(struct usb_device *udev); -void xhci_flush_cache(uint32_t addr, u32 type_len); -void xhci_inval_cache(uint32_t addr, u32 type_len); +void xhci_flush_cache(uintptr_t addr, u32 type_len); +void xhci_inval_cache(uintptr_t addr, u32 type_len); void xhci_cleanup(struct xhci_ctrl *ctrl); struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs); int xhci_alloc_virt_device(struct usb_device *udev);

This patch fixes USB storage capacity detection breakage on 64-bit systems which arises due to 'unsigned long' length difference. Old code assumes that to be 32 bit and breaks because of inappropriate response buffer layout. Also this fixes a number of build warnings and changes big-endian values treatment style to be architecture-independent
Signed-off-by: Sergey Temerkhanov s.temerkhanov@gmail.com Signed-off-by: Radha Mohan Chintakuntla rchintakuntla@cavium.com --- common/usb_storage.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-)
diff --git a/common/usb_storage.c b/common/usb_storage.c index 1411737..a1dfc58 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -336,8 +336,8 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length) /* set up the transfer loop */ do { /* transfer the data */ - debug("Bulk xfer 0x%x(%d) try #%d\n", - (unsigned int)buf, this_xfer, 11 - maxtry); + debug("Bulk xfer %p(%d) try #%d\n", + buf, this_xfer, 11 - maxtry); result = usb_bulk_msg(us->pusb_dev, pipe, buf, this_xfer, &partial, USB_CNTL_TIMEOUT * 5); @@ -514,6 +514,7 @@ static int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) cbw->bCDBLength = srb->cmdlen; /* copy the command data into the CBW command data buffer */ /* DST SRC LEN!!! */ + memcpy(cbw->CBWCDB, srb->cmd, srb->cmdlen); result = usb_bulk_msg(us->pusb_dev, pipe, cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT * 5); @@ -603,7 +604,7 @@ static int usb_stor_CBI_get_status(ccb *srb, struct us_data *us) (void *) &us->ip_data, us->irqmaxp, us->irqinterval); timeout = 1000; while (timeout--) { - if ((volatile int *) us->ip_wanted == NULL) + if (us->ip_wanted == 0) break; mdelay(10); } @@ -689,6 +690,7 @@ static int usb_stor_BBB_transport(ccb *srb, struct us_data *us) pipe = pipein; else pipe = pipeout; + result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT * 5); /* special handling of STALL in DATA phase */ @@ -1067,7 +1069,7 @@ unsigned long usb_stor_read(int device, lbaint_t blknr,
usb_disable_asynch(1); /* asynch transfer not allowed */ srb->lun = usb_dev_desc[device].lun; - buf_addr = (unsigned long)buffer; + buf_addr = (uintptr_t)buffer; start = blknr; blks = blkcnt;
@@ -1141,7 +1143,7 @@ unsigned long usb_stor_write(int device, lbaint_t blknr, usb_disable_asynch(1); /* asynch transfer not allowed */
srb->lun = usb_dev_desc[device].lun; - buf_addr = (unsigned long)buffer; + buf_addr = (uintptr_t)buffer; start = blknr; blks = blkcnt;
@@ -1334,9 +1336,9 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss, block_dev_desc_t *dev_desc) { unsigned char perq, modi; - ALLOC_CACHE_ALIGN_BUFFER(unsigned long, cap, 2); - ALLOC_CACHE_ALIGN_BUFFER(unsigned char, usb_stor_buf, 36); - unsigned long *capacity, *blksz; + ALLOC_CACHE_ALIGN_BUFFER(u32, cap, 2); + ALLOC_CACHE_ALIGN_BUFFER(u8, usb_stor_buf, 36); + u32 capacity, blksz; ccb *pccb = &usb_ccb;
pccb->pdata = usb_stor_buf; @@ -1362,9 +1364,9 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss, /* drive is removable */ dev_desc->removable = 1; } - memcpy(&dev_desc->vendor[0], (const void *) &usb_stor_buf[8], 8); - memcpy(&dev_desc->product[0], (const void *) &usb_stor_buf[16], 16); - memcpy(&dev_desc->revision[0], (const void *) &usb_stor_buf[32], 4); + memcpy(dev_desc->vendor, (const void *)&usb_stor_buf[8], 8); + memcpy(dev_desc->product, (const void *)&usb_stor_buf[16], 16); + memcpy(dev_desc->revision, (const void *)&usb_stor_buf[32], 4); dev_desc->vendor[8] = 0; dev_desc->product[16] = 0; dev_desc->revision[4] = 0; @@ -1385,7 +1387,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss, } return 0; } - pccb->pdata = (unsigned char *)&cap[0]; + pccb->pdata = (unsigned char *)cap; memset(pccb->pdata, 0, 8); if (usb_read_capacity(pccb, ss) != 0) { printf("READ_CAP ERROR\n"); @@ -1393,21 +1395,21 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss, cap[1] = 0x200; } ss->flags &= ~USB_READY; - debug("Read Capacity returns: 0x%lx, 0x%lx\n", cap[0], cap[1]); + debug("Read Capacity returns: 0x%08x, 0x%08x\n", cap[0], cap[1]); #if 0 if (cap[0] > (0x200000 * 10)) /* greater than 10 GByte */ cap[0] >>= 16; -#endif + cap[0] = cpu_to_be32(cap[0]); cap[1] = cpu_to_be32(cap[1]); +#endif + + capacity = be32_to_cpu(cap[0]) + 1; + blksz = be32_to_cpu(cap[1]);
- /* this assumes bigendian! */ - cap[0] += 1; - capacity = &cap[0]; - blksz = &cap[1]; - debug("Capacity = 0x%lx, blocksz = 0x%lx\n", *capacity, *blksz); - dev_desc->lba = *capacity; - dev_desc->blksz = *blksz; + debug("Capacity = 0x%08x, blocksz = 0x%08x\n", capacity, blksz); + dev_desc->lba = capacity; + dev_desc->blksz = blksz; dev_desc->log2blksz = LOG2(dev_desc->blksz); dev_desc->type = perq; debug(" address %d\n", dev_desc->target);
participants (2)
-
Marek Vasut
-
Sergey Temerkhanov