From 76df95bde1ec7d3f6371edcd128d4fca1cb7d2a9 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 20 Jun 2012 13:57:30 +0200 Subject: ARM mmu: don't use CONFIG_MMU to disable mmu code, there are static inline versions Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- arch/arm/cpu/mmu.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c index c19f9311cd..55b07a46d1 100644 --- a/arch/arm/cpu/mmu.c +++ b/arch/arm/cpu/mmu.c @@ -299,11 +299,9 @@ void *dma_alloc_coherent(size_t size) size = PAGE_ALIGN(size); ret = xmemalign(4096, size); -#ifdef CONFIG_MMU dma_inv_range((unsigned long)ret, (unsigned long)ret + size); remap_range(ret, size, PTE_FLAGS_UNCACHED); -#endif return ret; } @@ -320,9 +318,7 @@ void *phys_to_virt(unsigned long phys) void dma_free_coherent(void *mem, size_t size) { -#ifdef CONFIG_MMU remap_range(mem, size, PTE_FLAGS_CACHED); -#endif free(mem); } -- cgit v1.2.3 From ed2180d658b9dbc1e56ddb2e0119253a8b99b2f5 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 20 Jun 2012 13:57:31 +0200 Subject: blackfin, mips, openrisc, ppc, sandbox, x86: add generic dma_alloc, dma_free inlines Some drivers call dma_inv_range() on buffers, on arm these buffers must be cache line aligned. This patch introduces a generic dma_alloc, dma_free. Archs can implement in their own functions in "asm/dma.h" and add a: #define dma_alloc dma_alloc #define dma_free dma_free On all other archs the generic versions, which translate into xmalloc and free are used. Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- arch/blackfin/include/asm/dma.h | 13 +++++++++++++ arch/mips/include/asm/dma.h | 13 +++++++++++++ arch/openrisc/include/asm/dma.h | 13 +++++++++++++ arch/ppc/include/asm/dma.h | 13 +++++++++++++ arch/sandbox/include/asm/dma.h | 13 +++++++++++++ arch/x86/include/asm/dma.h | 13 +++++++++++++ include/dma.h | 30 ++++++++++++++++++++++++++++++ 7 files changed, 108 insertions(+) create mode 100644 arch/blackfin/include/asm/dma.h create mode 100644 arch/mips/include/asm/dma.h create mode 100644 arch/openrisc/include/asm/dma.h create mode 100644 arch/ppc/include/asm/dma.h create mode 100644 arch/sandbox/include/asm/dma.h create mode 100644 arch/x86/include/asm/dma.h create mode 100644 include/dma.h diff --git a/arch/blackfin/include/asm/dma.h b/arch/blackfin/include/asm/dma.h new file mode 100644 index 0000000000..27d269f491 --- /dev/null +++ b/arch/blackfin/include/asm/dma.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_DMA_H +#define __ASM_DMA_H + +/* empty */ + +#endif /* __ASM_DMA_H */ diff --git a/arch/mips/include/asm/dma.h b/arch/mips/include/asm/dma.h new file mode 100644 index 0000000000..27d269f491 --- /dev/null +++ b/arch/mips/include/asm/dma.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_DMA_H +#define __ASM_DMA_H + +/* empty */ + +#endif /* __ASM_DMA_H */ diff --git a/arch/openrisc/include/asm/dma.h b/arch/openrisc/include/asm/dma.h new file mode 100644 index 0000000000..27d269f491 --- /dev/null +++ b/arch/openrisc/include/asm/dma.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_DMA_H +#define __ASM_DMA_H + +/* empty */ + +#endif /* __ASM_DMA_H */ diff --git a/arch/ppc/include/asm/dma.h b/arch/ppc/include/asm/dma.h new file mode 100644 index 0000000000..27d269f491 --- /dev/null +++ b/arch/ppc/include/asm/dma.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_DMA_H +#define __ASM_DMA_H + +/* empty */ + +#endif /* __ASM_DMA_H */ diff --git a/arch/sandbox/include/asm/dma.h b/arch/sandbox/include/asm/dma.h new file mode 100644 index 0000000000..459536779e --- /dev/null +++ b/arch/sandbox/include/asm/dma.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_DMA_H +#define __ASM_DMA_H + +/* empty*/ + +#endif /* __ASM_DMA_H */ diff --git a/arch/x86/include/asm/dma.h b/arch/x86/include/asm/dma.h new file mode 100644 index 0000000000..27d269f491 --- /dev/null +++ b/arch/x86/include/asm/dma.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#ifndef __ASM_DMA_H +#define __ASM_DMA_H + +/* empty */ + +#endif /* __ASM_DMA_H */ diff --git a/include/dma.h b/include/dma.h new file mode 100644 index 0000000000..899f831faa --- /dev/null +++ b/include/dma.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#ifndef __DMA_H +#define __DMA_H + +#include +#include + +#include + +#ifndef dma_alloc +static inline void *dma_alloc(size_t size) +{ + return xmalloc(size); +} +#endif + +#ifndef dma_free +static inline void dma_free(void *mem) +{ + free(mem); +} +#endif + +#endif /* __DMA_H */ -- cgit v1.2.3 From 74b3f12a2501da52be663da71c1284672ba3f4e7 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 20 Jun 2012 13:57:32 +0200 Subject: nios: add dma_alloc, asm/dma.h This patch add dma_alloc to existing dma-mapping.h. On nios the mem is aligned to D_ACHE_LINE_SIZE. Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- arch/nios2/include/asm/dma-mapping.h | 10 ++++++++++ arch/nios2/include/asm/dma.h | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 arch/nios2/include/asm/dma.h diff --git a/arch/nios2/include/asm/dma-mapping.h b/arch/nios2/include/asm/dma-mapping.h index 5b70f4cead..9819a973e7 100644 --- a/arch/nios2/include/asm/dma-mapping.h +++ b/arch/nios2/include/asm/dma-mapping.h @@ -1,8 +1,12 @@ #ifndef __ASM_NIOS2_DMA_MAPPING_H #define __ASM_NIOS2_DMA_MAPPING_H +#include +#include + #include + /* dma_alloc_coherent() return cache-line aligned allocation which is mapped * to uncached io region. * @@ -22,4 +26,10 @@ static inline void *dma_alloc_coherent(size_t len, unsigned long *handle) return (void *)(*handle | IO_REGION_BASE); } +#define dma_alloc dma_alloc +static inline void *dma_alloc(size_t size) +{ + return xmemalign(DCACHE_LINE_SIZE, ALIGN(size, DCACHE_LINE_SIZE)); +} + #endif /* __ASM_NIOS2_DMA_MAPPING_H */ diff --git a/arch/nios2/include/asm/dma.h b/arch/nios2/include/asm/dma.h new file mode 100644 index 0000000000..8f709d2dbf --- /dev/null +++ b/arch/nios2/include/asm/dma.h @@ -0,0 +1,8 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#include -- cgit v1.2.3 From f98ebf91d624f0cb0f85105a0e67aee0078aa58b Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 20 Jun 2012 13:57:33 +0200 Subject: ARM mmu: add dma_alloc dma_alloc() allocates memory aligned to cache lines. We have to use cache line aligned buffers if a driver calls dma_inv_range on the buffer. Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- arch/arm/include/asm/dma.h | 8 ++++++++ arch/arm/include/asm/mmu.h | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 arch/arm/include/asm/dma.h diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h new file mode 100644 index 0000000000..cb9cd1b4ea --- /dev/null +++ b/arch/arm/include/asm/dma.h @@ -0,0 +1,8 @@ +/* + * Copyright (C) 2012 by Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + */ + +#include diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index f5ae7a823a..a66da8c0a8 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -1,9 +1,12 @@ #ifndef __ASM_MMU_H #define __ASM_MMU_H -#include -#include +#include #include +#include +#include + +#include #define PMD_SECT_DEF_UNCACHED (PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT) #define PMD_SECT_DEF_CACHED (PMD_SECT_WB | PMD_SECT_DEF_UNCACHED) @@ -23,6 +26,12 @@ static inline void setup_dma_coherent(unsigned long offset) { } +#define dma_alloc dma_alloc +static inline void *dma_alloc(size_t size) +{ + return xmemalign(64, ALIGN(size, 64)); +} + #ifdef CONFIG_MMU void *dma_alloc_coherent(size_t size); void dma_free_coherent(void *mem, size_t size); -- cgit v1.2.3 From 3f7987af96d2589d2d1f7a01ca11318909063ac1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 20 Jun 2012 13:57:34 +0200 Subject: USB gadget fsl: request cacheline aligned buffer The fsl udc driver allocates a buffer for small requests. The driver then calls dma_inv_range later on it. This buffer happens to be not cacheline aligned which means that a dma_inv_range can corrupt other memory around the buffer. Signed-off-by: Sascha Hauer [mkl: use dma_alloc] Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- drivers/usb/gadget/fsl_udc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c index 5b64ec2011..627e4177d6 100644 --- a/drivers/usb/gadget/fsl_udc.c +++ b/drivers/usb/gadget/fsl_udc.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,7 +9,6 @@ #include #include #include -#include /* ### define USB registers here */ @@ -2109,7 +2109,8 @@ static int struct_udc_setup(struct fsl_udc *udc, udc->status_req = container_of(fsl_alloc_request(NULL), struct fsl_req, req); /* allocate a small amount of memory to get valid address */ - udc->status_req->req.buf = xmalloc(8); + udc->status_req->req.buf = dma_alloc(8); + udc->status_req->req.length = 8; udc->resume_state = USB_STATE_NOTATTACHED; udc->usb_state = USB_STATE_POWERED; udc->ep0_dir = 0; -- cgit v1.2.3 From 887c7d5c38b7a0e1aa007c47221d48b12179239f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 20 Jun 2012 13:57:35 +0200 Subject: USB gadget: Fix dma memory allocations This is another variant of: USB gadget fsl: request cacheline aligned buffer The fsl udc driver allocates a buffer for small requests. The driver then calls dma_inv_range later on it. This buffer happens to be not cacheline aligned which means that a dma_inv_range can corrupt other memory around the buffer. Signed-off-by: Sascha Hauer [mkl: use dma_alloc] Signed-off-by: Marc Kleine-Budde Signed-off-by: Sascha Hauer --- drivers/usb/gadget/composite.c | 5 +++-- drivers/usb/gadget/dfu.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index fd70e623a6..44e58d7de0 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -867,7 +868,7 @@ composite_unbind(struct usb_gadget *gadget) composite->unbind(cdev); if (cdev->req) { - kfree(cdev->req->buf); + dma_free(cdev->req->buf); usb_ep_free_request(gadget->ep0, cdev->req); } kfree(cdev); @@ -911,7 +912,7 @@ static int __init composite_bind(struct usb_gadget *gadget) cdev->req = usb_ep_alloc_request(gadget->ep0); if (!cdev->req) goto fail; - cdev->req->buf = malloc(USB_BUFSIZ); + cdev->req->buf = dma_alloc(USB_BUFSIZ); if (!cdev->req->buf) goto fail; cdev->req->complete = composite_setup_complete; diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c index f26c1e43d0..e205c65f32 100644 --- a/drivers/usb/gadget/dfu.c +++ b/drivers/usb/gadget/dfu.c @@ -40,6 +40,7 @@ * - make 'dnstate' attached to 'struct usb_device_instance' */ +#include #include #include #include @@ -183,7 +184,7 @@ dfu_unbind(struct usb_configuration *c, struct usb_function *f) if (gadget_is_dualspeed(c->cdev->gadget)) free(f->hs_descriptors); - free(dfu->dnreq->buf); + dma_free(dfu->dnreq->buf); usb_ep_free_request(c->cdev->gadget->ep0, dfu->dnreq); free(dfu); } @@ -602,7 +603,7 @@ static int dfu_bind_config(struct usb_configuration *c) dfu->dnreq = usb_ep_alloc_request(c->cdev->gadget->ep0); if (!dfu->dnreq) printf("usb_ep_alloc_request failed\n"); - dfu->dnreq->buf = xmalloc(CONFIG_USBD_DFU_XFER_SIZE); + dfu->dnreq->buf = dma_alloc(CONFIG_USBD_DFU_XFER_SIZE); dfu->dnreq->complete = dn_complete; dfu->dnreq->zero = 0; -- cgit v1.2.3 From fc52e7e4806360afb1efcc7aa6b47f632cacefb4 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 20 Jun 2012 17:57:19 +0200 Subject: USB core: allocate setup_packet using dma_alloc The setup packet needs to be dma save. Signed-off-by: Sascha Hauer --- drivers/usb/core/usb.c | 18 +++++++++++------- include/usb/usb.h | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index bd2938d2b7..7333c0ee75 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -67,7 +68,6 @@ static int dev_index; static int asynch_allowed; -static struct devrequest setup_packet; static int usb_hub_probe(struct usb_device *dev, int ifnum); static int hub_port_reset(struct usb_device *dev, int port, @@ -454,6 +454,7 @@ static struct usb_device *usb_alloc_new_device(void) usbdev->devnum = dev_index + 1; usbdev->maxchild = 0; usbdev->dev.bus = &usb_bus_type; + usbdev->setup_packet = dma_alloc(sizeof(*usbdev->setup_packet)); dev_index++; @@ -471,6 +472,7 @@ void usb_rescan(void) unregister_device(&dev->dev); if (dev->hub) free(dev->hub); + dma_free(dev->setup_packet); free(dev); } @@ -532,6 +534,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, { struct usb_host *host = dev->host; int ret; + struct devrequest *setup_packet = dev->setup_packet; if ((timeout == 0) && (!asynch_allowed)) { /* request for a asynch control pipe is not allowed */ @@ -539,17 +542,18 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, } /* set setup command */ - setup_packet.requesttype = requesttype; - setup_packet.request = request; - setup_packet.value = cpu_to_le16(value); - setup_packet.index = cpu_to_le16(index); - setup_packet.length = cpu_to_le16(size); + setup_packet->requesttype = requesttype; + setup_packet->request = request; + setup_packet->value = cpu_to_le16(value); + setup_packet->index = cpu_to_le16(index); + setup_packet->length = cpu_to_le16(size); USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \ "value 0x%X index 0x%X length 0x%X\n", request, requesttype, value, index, size); dev->status = USB_ST_NOT_PROC; /*not yet processed */ - ret = host->submit_control_msg(dev, pipe, data, size, &setup_packet, timeout); + ret = host->submit_control_msg(dev, pipe, data, size, setup_packet, + timeout); if (ret) return ret; diff --git a/include/usb/usb.h b/include/usb/usb.h index 296e4e8ea8..f836593c20 100644 --- a/include/usb/usb.h +++ b/include/usb/usb.h @@ -161,6 +161,7 @@ struct usb_device { int configno; /* selected config number */ struct usb_device_descriptor descriptor; /* Device Descriptor */ struct usb_config_descriptor config; /* config descriptor */ + struct devrequest *setup_packet; int have_langid; /* whether string_langid is valid yet */ int string_langid; /* language ID for strings */ -- cgit v1.2.3 From 95aea88175ed2bcc0dc0367f95f757dd625ac68d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 20 Jun 2012 18:00:18 +0200 Subject: USB core: device descriptor using dma_alloc The device descriptor needs to be dma save. Signed-off-by: Sascha Hauer --- drivers/usb/core/usb.c | 53 ++++++++++++++++++++++++++------------------------ include/usb/usb.h | 2 +- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 7333c0ee75..264ca2d36e 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -80,8 +80,8 @@ static void print_usb_device(struct usb_device *dev) { printf("Bus %03d Device %03d: ID %04x:%04x %s\n", dev->host->busnum, dev->devnum, - dev->descriptor.idVendor, - dev->descriptor.idProduct, + dev->descriptor->idVendor, + dev->descriptor->idProduct, dev->prod); } @@ -323,7 +323,7 @@ static int usb_new_device(struct usb_device *dev) * some more, or keeps on retransmitting the 8 byte header. */ desc = (struct usb_device_descriptor *)tmpbuf; - dev->descriptor.bMaxPacketSize0 = 64; /* Start off at 64 bytes */ + dev->descriptor->bMaxPacketSize0 = 64; /* Start off at 64 bytes */ /* Default to 64 byte max packet size */ dev->maxpacketsize = PACKET_SIZE_64; dev->epmaxpacketin[0] = 64; @@ -335,7 +335,7 @@ static int usb_new_device(struct usb_device *dev) return 1; } - dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0; + dev->descriptor->bMaxPacketSize0 = desc->bMaxPacketSize0; /* find the port number we're at */ if (parent) { @@ -360,9 +360,9 @@ static int usb_new_device(struct usb_device *dev) } } - dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0; - dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; - switch (dev->descriptor.bMaxPacketSize0) { + dev->epmaxpacketin[0] = dev->descriptor->bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor->bMaxPacketSize0; + switch (dev->descriptor->bMaxPacketSize0) { case 8: dev->maxpacketsize = PACKET_SIZE_8; break; @@ -388,10 +388,10 @@ static int usb_new_device(struct usb_device *dev) wait_ms(10); /* Let the SET_ADDRESS settle */ - tmp = sizeof(dev->descriptor); + tmp = sizeof(*dev->descriptor); err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, - &dev->descriptor, sizeof(dev->descriptor)); + dev->descriptor, sizeof(*dev->descriptor)); if (err < tmp) { if (err < 0) printf("unable to get device descriptor (error=%d)\n", @@ -402,10 +402,10 @@ static int usb_new_device(struct usb_device *dev) return 1; } /* correct le values */ - le16_to_cpus(&dev->descriptor.bcdUSB); - le16_to_cpus(&dev->descriptor.idVendor); - le16_to_cpus(&dev->descriptor.idProduct); - le16_to_cpus(&dev->descriptor.bcdDevice); + le16_to_cpus(&dev->descriptor->bcdUSB); + le16_to_cpus(&dev->descriptor->idVendor); + le16_to_cpus(&dev->descriptor->idProduct); + le16_to_cpus(&dev->descriptor->bcdDevice); /* only support for one config for now */ usb_get_configuration_no(dev, &tmpbuf[0], 0); usb_parse_config(dev, &tmpbuf[0], 0); @@ -417,19 +417,19 @@ static int usb_new_device(struct usb_device *dev) return -1; } USB_PRINTF("new device: Mfr=%d, Product=%d, SerialNumber=%d\n", - dev->descriptor.iManufacturer, dev->descriptor.iProduct, - dev->descriptor.iSerialNumber); + dev->descriptor->iManufacturer, dev->descriptor->iProduct, + dev->descriptor->iSerialNumber); memset(dev->mf, 0, sizeof(dev->mf)); memset(dev->prod, 0, sizeof(dev->prod)); memset(dev->serial, 0, sizeof(dev->serial)); - if (dev->descriptor.iManufacturer) - usb_string(dev, dev->descriptor.iManufacturer, + if (dev->descriptor->iManufacturer) + usb_string(dev, dev->descriptor->iManufacturer, dev->mf, sizeof(dev->mf)); - if (dev->descriptor.iProduct) - usb_string(dev, dev->descriptor.iProduct, + if (dev->descriptor->iProduct) + usb_string(dev, dev->descriptor->iProduct, dev->prod, sizeof(dev->prod)); - if (dev->descriptor.iSerialNumber) - usb_string(dev, dev->descriptor.iSerialNumber, + if (dev->descriptor->iSerialNumber) + usb_string(dev, dev->descriptor->iSerialNumber, dev->serial, sizeof(dev->serial)); /* now prode if the device is a hub */ usb_hub_probe(dev, 0); @@ -455,6 +455,7 @@ static struct usb_device *usb_alloc_new_device(void) usbdev->maxchild = 0; usbdev->dev.bus = &usb_bus_type; usbdev->setup_packet = dma_alloc(sizeof(*usbdev->setup_packet)); + usbdev->descriptor = dma_alloc(sizeof(*usbdev->descriptor)); dev_index++; @@ -473,6 +474,7 @@ void usb_rescan(void) if (dev->hub) free(dev->hub); dma_free(dev->setup_packet); + dma_free(dev->descriptor); free(dev); } @@ -1288,11 +1290,11 @@ int usb_driver_register(struct usb_driver *drv) static int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) { if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && - id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) + id->idVendor != le16_to_cpu(dev->descriptor->idVendor)) return 0; if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && - id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) + id->idProduct != le16_to_cpu(dev->descriptor->idProduct)) return 0; return 1; @@ -1315,7 +1317,7 @@ static int usb_match_one_id(struct usb_device *usbdev, /* The interface class, subclass, and protocol should never be * checked for a match if the device class is Vendor Specific, * unless the match record specifies the Vendor ID. */ - if (usbdev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC && + if (usbdev->descriptor->bDeviceClass == USB_CLASS_VENDOR_SPEC && !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && (id->match_flags & USB_DEVICE_ID_MATCH_INT_INFO)) return 0; @@ -1375,7 +1377,8 @@ static int usb_match(struct device_d *dev, struct driver_d *drv) struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); const struct usb_device_id *id; - debug("matching: 0x%04x 0x%04x\n", usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); + debug("matching: 0x%04x 0x%04x\n", usbdev->descriptor->idVendor, + usbdev->descriptor->idProduct); id = usb_match_id(usbdev, usbdrv->id_table); if (id) { diff --git a/include/usb/usb.h b/include/usb/usb.h index f836593c20..f273983f5f 100644 --- a/include/usb/usb.h +++ b/include/usb/usb.h @@ -159,7 +159,7 @@ struct usb_device { int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ int configno; /* selected config number */ - struct usb_device_descriptor descriptor; /* Device Descriptor */ + struct usb_device_descriptor *descriptor; /* Device Descriptor */ struct usb_config_descriptor config; /* config descriptor */ struct devrequest *setup_packet; -- cgit v1.2.3 From 0c35d2210e2020cd8684b86fb4f2cfea663b223f Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 20 Jun 2012 18:23:19 +0200 Subject: USB core: Allocate tmpbuf using dma_alloc This needs to be dma save. Signed-off-by: Sascha Hauer --- drivers/usb/core/usb.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 264ca2d36e..a5075d5436 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -299,12 +299,14 @@ static int usb_new_device(struct usb_device *dev) { int addr, err; int tmp; - unsigned char tmpbuf[USB_BUFSIZ]; + void *buf; struct usb_device_descriptor *desc; int port = -1; struct usb_device *parent = dev->parent; unsigned short portstatus; + buf = dma_alloc(USB_BUFSIZ); + /* We still haven't set the Address yet */ addr = dev->devnum; dev->devnum = 0; @@ -322,7 +324,7 @@ static int usb_new_device(struct usb_device *dev) * the maxpacket size is 8 or 16 the device may be waiting to transmit * some more, or keeps on retransmitting the 8 byte header. */ - desc = (struct usb_device_descriptor *)tmpbuf; + desc = buf; dev->descriptor->bMaxPacketSize0 = 64; /* Start off at 64 bytes */ /* Default to 64 byte max packet size */ dev->maxpacketsize = PACKET_SIZE_64; @@ -332,7 +334,7 @@ static int usb_new_device(struct usb_device *dev) err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64); if (err < 0) { USB_PRINTF("%s: usb_get_descriptor() failed with %d\n", __func__, err); - return 1; + goto err_out; } dev->descriptor->bMaxPacketSize0 = desc->bMaxPacketSize0; @@ -349,14 +351,15 @@ static int usb_new_device(struct usb_device *dev) } if (port < 0) { printf("%s: cannot locate device's port.\n", __func__); - return 1; + err = -ENODEV; + goto err_out; } /* reset the port for the second time */ err = hub_port_reset(dev->parent, port, &portstatus); if (err < 0) { printf("\n Couldn't reset port %i\n", port); - return 1; + goto err_out; } } @@ -383,7 +386,7 @@ static int usb_new_device(struct usb_device *dev) if (err < 0) { printf("\n USB device not accepting new address " \ "(error=%lX)\n", dev->status); - return 1; + goto err_out; } wait_ms(10); /* Let the SET_ADDRESS settle */ @@ -399,7 +402,7 @@ static int usb_new_device(struct usb_device *dev) else printf("USB device descriptor short read " \ "(expected %i, got %i)\n", tmp, err); - return 1; + goto err_out; } /* correct le values */ le16_to_cpus(&dev->descriptor->bcdUSB); @@ -407,14 +410,14 @@ static int usb_new_device(struct usb_device *dev) le16_to_cpus(&dev->descriptor->idProduct); le16_to_cpus(&dev->descriptor->bcdDevice); /* only support for one config for now */ - usb_get_configuration_no(dev, &tmpbuf[0], 0); - usb_parse_config(dev, &tmpbuf[0], 0); + usb_get_configuration_no(dev, buf, 0); + usb_parse_config(dev, buf, 0); usb_set_maxpacket(dev); /* we set the default configuration here */ if (usb_set_configuration(dev, dev->config.bConfigurationValue)) { printf("failed to set default configuration " \ "len %d, status %lX\n", dev->act_len, dev->status); - return -1; + goto err_out; } USB_PRINTF("new device: Mfr=%d, Product=%d, SerialNumber=%d\n", dev->descriptor->iManufacturer, dev->descriptor->iProduct, @@ -441,7 +444,11 @@ static int usb_new_device(struct usb_device *dev) register_device(&dev->dev); list_add_tail(&dev->list, &usb_device_list); - return 0; + err = 0; + +err_out: + dma_free(buf); + return err; } static struct usb_device *usb_alloc_new_device(void) -- cgit v1.2.3 From 0128d993522ae67a84cb2760b5609eaab5e3224d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 20 Jun 2012 18:08:46 +0200 Subject: USB ehci: Use dma coherent buffers for qh/qtd There's no point in syncing them manually. Instead, use dma_alloc_coherent and skip the manual flushing/invalidating. Signed-off-by: Sascha Hauer --- drivers/usb/host/ehci-hcd.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a2473a9141..425406d443 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -148,9 +148,6 @@ static void cache_qh(struct ehci_priv *ehci, int flush) { int i; - flush_invalidate(ehci->qh_list, sizeof(struct QH) * NUM_QH, flush); - flush_invalidate(ehci->td, sizeof(struct qTD) * NUM_TD, flush); - for (i = 0; i < NUM_TD; i ++) cache_qtd(&ehci->td[i], flush); } @@ -878,8 +875,8 @@ static int ehci_probe(struct device_d *dev) ehci->hccr = dev_request_mem_region(dev, 0); ehci->hcor = dev_request_mem_region(dev, 1); - ehci->qh_list = xmemalign(32, sizeof(struct QH) * NUM_QH); - ehci->td = xmemalign(32, sizeof(struct qTD) * NUM_TD); + ehci->qh_list = dma_alloc_coherent(sizeof(struct QH) * NUM_TD); + ehci->td = dma_alloc_coherent(sizeof(struct qTD) * NUM_TD); host->init = ehci_init; host->submit_int_msg = submit_int_msg; -- cgit v1.2.3 From 787fa164dd3766f3822e9456a3cdd9d437b9bc5b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 21 Jun 2012 09:44:24 +0200 Subject: USB ehci: put fields of struct qTD directly into struct QH This allows us to extend struct qTD with non hardware specific fields. Signed-off-by: Sascha Hauer --- drivers/usb/host/ehci-hcd.c | 22 +++++++++++----------- drivers/usb/host/ehci.h | 6 +++++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 425406d443..929c8a6e93 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -293,11 +293,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, (dev->portnr << 23) | (dev->parent->devnum << 16) | (0 << 8) | (0 << 0); qh->qh_endpt2 = cpu_to_hc32(endpt); - qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + qh->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + qh->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); td = NULL; - tdp = &qh->qh_overlay.qt_next; + tdp = &qh->qt_next; toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); @@ -391,7 +391,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, ehci_writel(&ehci->hcor->or_usbcmd, cmd); ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, 0, 100 * 1000); - ehci_writel(&qh->qh_overlay.qt_token, 0); + ehci_writel(&qh->qt_token, 0); return -ETIMEDOUT; } } while (token & 0x80); @@ -410,7 +410,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, ehci->qh_list->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH); - token = hc32_to_cpu(qh->qh_overlay.qt_token); + token = hc32_to_cpu(qh->qt_token); if (!(token & 0x80)) { debug("TOKEN=0x%08x\n", token); switch (token & 0xfc) { @@ -448,10 +448,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, fail: printf("fail1\n"); - td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next); + td = (void *)hc32_to_cpu(qh->qt_next); while (td != (void *)QT_NEXT_TERMINATE) { - qh->qh_overlay.qt_next = td->qt_next; - td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next); + qh->qt_next = td->qt_next; + td = (void *)hc32_to_cpu(qh->qt_next); } return -1; } @@ -767,9 +767,9 @@ static int ehci_init(struct usb_host *host) ehci->qh_list->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH); ehci->qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12)); ehci->qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE); - ehci->qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - ehci->qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); - ehci->qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40); + ehci->qh_list->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + ehci->qh_list->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + ehci->qh_list->qt_token = cpu_to_hc32(0x40); /* Set async. queue head pointer. */ ehci_writel(&ehci->hcor->or_asynclistaddr, (uint32_t)ehci->qh_list); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index eac93db01c..76a3c85a90 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -179,7 +179,11 @@ struct QH { uint32_t qh_endpt1; uint32_t qh_endpt2; uint32_t qh_curtd; - struct qTD qh_overlay; + /* qtd overlay (hardware parts of a struct qTD) */ + uint32_t qt_next; + uint32_t qt_altnext; + uint32_t qt_token; + uint32_t qt_buffer[5]; /* * Add dummy fill value to make the size of this struct * aligned to 32 bytes -- cgit v1.2.3 From 9ca0e573af89a5d2ce0bc682633560891275bf71 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 21 Jun 2012 10:24:43 +0200 Subject: USB storage: use dma_alloc where appropriate Signed-off-by: Sascha Hauer --- drivers/usb/storage/transport.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index e7a5972750..68170b65c0 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -26,6 +26,7 @@ #include #include #include +#include #undef USB_STOR_DEBUG @@ -65,8 +66,8 @@ int usb_stor_Bulk_clear_endpt_stall(struct us_data *us, unsigned int pipe) /* Determine what the maximum LUN supported is */ int usb_stor_Bulk_max_lun(struct us_data *us) { - int len; - unsigned char iobuf[1]; + int len, ret = 0; + unsigned char *iobuf = dma_alloc(1); /* issue the command */ iobuf[0] = 0; @@ -81,7 +82,9 @@ int usb_stor_Bulk_max_lun(struct us_data *us) /* if we have a successful request, return the result */ if (len > 0) - return (int)iobuf[0]; + ret = iobuf[0]; + + dma_free(iobuf); /* * Some devices don't like GetMaxLUN. They may STALL the control @@ -90,7 +93,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) * ways. In these cases the best approach is to use the default * value: only one LUN. */ - return 0; + return ret; } int usb_stor_Bulk_transport(ccb *srb, struct us_data *us) -- cgit v1.2.3 From 9895357a71205ea7d92d7608bd5ea40cef38e4c1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 21 Jun 2012 10:25:29 +0200 Subject: block: use dma_alloc to allocate buffers Drivers may use dma to transfer blocks, so put them into dma save memory. Signed-off-by: Sascha Hauer --- common/block.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/common/block.c b/common/block.c index 71ecfd5ab7..f3bcdc8181 100644 --- a/common/block.c +++ b/common/block.c @@ -24,6 +24,7 @@ #include #include #include +#include #define BLOCKSIZE(blk) (1 << blk->blockbits) @@ -357,7 +358,7 @@ int blockdevice_register(struct block_device *blk) for (i = 0; i < 8; i++) { struct chunk *chunk = xzalloc(sizeof(*chunk)); - chunk->data = xmalloc(BUFSIZE); + chunk->data = dma_alloc(BUFSIZE); chunk->num = i; list_add_tail(&chunk->list, &blk->idle_blocks); } @@ -376,12 +377,12 @@ int blockdevice_unregister(struct block_device *blk) writebuffer_flush(blk); list_for_each_entry_safe(chunk, tmp, &blk->buffered_blocks, list) { - free(chunk->data); + dma_free(chunk->data); free(chunk); } list_for_each_entry_safe(chunk, tmp, &blk->idle_blocks, list) { - free(chunk->data); + dma_free(chunk->data); free(chunk); } -- cgit v1.2.3 From 527772ca0ea0447d8c5394e9d6bc1581bdf06835 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 21 Jun 2012 10:27:20 +0200 Subject: partition: Use dma_alloc for allocating buffers Drivers may use dma to transfer blocks, so put them into dma save memory. Signed-off-by: Sascha Hauer --- common/partitions.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/partitions.c b/common/partitions.c index 74b4f1201a..3d92838948 100644 --- a/common/partitions.c +++ b/common/partitions.c @@ -31,6 +31,7 @@ #include #include #include +#include struct partition { uint64_t first_sec; @@ -102,7 +103,7 @@ static void __maybe_unused try_dos_partition(struct block_device *blk, struct partition pentry; int i, rc; - buffer = xmalloc(SECTOR_SIZE); + buffer = dma_alloc(SECTOR_SIZE); /* read in the MBR to get the partition table */ rc = blk->ops->read(blk, buffer, 0, 1); @@ -142,7 +143,7 @@ static void __maybe_unused try_dos_partition(struct block_device *blk, } on_error: - free(buffer); + dma_free(buffer); } /** -- cgit v1.2.3 From 40faf584cd60c1e0e083ac75eb9ef5f9e7c071d0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 21 Jun 2012 11:14:25 +0200 Subject: USB ehci: rework cache handling We do not need to invalidate the cache in the poll loop anymore since the corresponding bit is now in a dma coherent area. Instead, flush cache before hardware operation and invalidate afterwards. Put the corresponding code inline since it's shorter. Signed-off-by: Sascha Hauer --- drivers/usb/host/ehci-hcd.c | 79 ++++++++++++--------------------------------- drivers/usb/host/ehci.h | 4 ++- 2 files changed, 24 insertions(+), 59 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 929c8a6e93..c2f48ce428 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -120,60 +120,6 @@ static struct descriptor { #define ehci_is_TDI() (ehci->flags & EHCI_HAS_TT) -#ifdef CONFIG_MMU -/* - * Routines to handle (flush/invalidate) the dcache for the QH and qTD - * structures and data buffers. This is needed on platforms using this - * EHCI support with dcache enabled. - */ -static void flush_invalidate(void *addr, int size, int flush) -{ - if (flush) { - dma_flush_range((unsigned long)addr, (unsigned long)(addr + size)); - } else { - dma_inv_range((unsigned long)addr, (unsigned long)(addr + size)); - } -} - -static void cache_qtd(struct qTD *qtd, int flush) -{ - u32 *ptr = (u32 *)qtd->qt_buffer[0]; - int len = (qtd->qt_token & 0x7fff0000) >> 16; - - if (ptr && len) - flush_invalidate(ptr, len, flush); -} - -static void cache_qh(struct ehci_priv *ehci, int flush) -{ - int i; - - for (i = 0; i < NUM_TD; i ++) - cache_qtd(&ehci->td[i], flush); -} - -static inline void ehci_flush_dcache(struct ehci_priv *ehci) -{ - cache_qh(ehci, 1); -} - -static inline void ehci_invalidate_dcache(struct ehci_priv *ehci) -{ - cache_qh(ehci, 0); -} -#else /* CONFIG_MMU */ -/* - * - */ -static inline void ehci_flush_dcache(struct ehci_priv *ehci) -{ -} - -static inline void ehci_invalidate_dcache(struct ehci_priv *ehci) -{ -} -#endif /* CONFIG_MMU */ - static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec) { uint32_t result; @@ -228,6 +174,9 @@ static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) int idx; addr = (uint32_t) buf; + td->qtd_dma = addr; + td->length = sz; + idx = 0; while (idx < 5) { td->qt_buffer[idx] = cpu_to_hc32(addr); @@ -261,7 +210,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, uint32_t endpt, token, usbsts; uint32_t c, toggle; uint32_t cmd; - int ret = 0; + int ret = 0, i; uint64_t start, timeout_val; debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe, @@ -360,7 +309,14 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, ehci->qh_list->qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH); /* Flush dcache */ - ehci_flush_dcache(ehci); + if (IS_ENABLED(CONFIG_MMU)) { + for (i = 0; i < NUM_TD; i ++) { + struct qTD *qtd = &ehci->td[i]; + if (!qtd->qtd_dma) + continue; + dma_flush_range(qtd->qtd_dma, qtd->qtd_dma + qtd->length); + } + } usbsts = ehci_readl(&ehci->hcor->or_usbsts); ehci_writel(&ehci->hcor->or_usbsts, (usbsts & 0x3f)); @@ -381,8 +337,6 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, start = get_time_ns(); vtd = td; do { - /* Invalidate dcache */ - ehci_invalidate_dcache(ehci); token = hc32_to_cpu(vtd->qt_token); if (is_timeout(start, timeout_val)) { /* Disable async schedule. */ @@ -396,6 +350,15 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, } } while (token & 0x80); + if (IS_ENABLED(CONFIG_MMU)) { + for (i = 0; i < NUM_TD; i ++) { + struct qTD *qtd = &ehci->td[i]; + if (!qtd->qtd_dma) + continue; + dma_inv_range(qtd->qtd_dma, qtd->qtd_dma + qtd->length); + } + } + /* Disable async schedule. */ cmd = ehci_readl(&ehci->hcor->or_usbcmd); cmd &= ~CMD_ASE; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 76a3c85a90..b127b95bbe 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -166,7 +166,9 @@ struct qTD { uint32_t qt_altnext; uint32_t qt_token; uint32_t qt_buffer[5]; -}; + unsigned long qtd_dma; + size_t length; +} __attribute__ ((aligned (32))); /* Queue Head (QH). */ struct QH { -- cgit v1.2.3