aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMagnus Damm <magnus.damm@gmail.com>2008-01-23 01:58:35 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 17:35:05 -0500
commitb3476675320eda83cf061a686cdc80b76f2bfdc4 (patch)
tree11d31a0ade5c961fd5738a67b99ccb411325607d /drivers
parent0915f490d81c1a5098b399ec6c0be45bd421ee1d (diff)
usb: dma bounce buffer support
usb: dma bounce buffer support V4 This patch adds dma bounce buffer support to the usb core. These buffers can be enabled with the HCD_LOCAL_MEM flag, and they make sure that all data passed to the host controller is allocated using dma_alloc_coherent(). Signed-off-by: Magnus Damm <damm@igel.co.jp> Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/buffer.c9
-rw-r--r--drivers/usb/core/hcd.c176
-rw-r--r--drivers/usb/core/hcd.h1
3 files changed, 163 insertions, 23 deletions
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 28d4972f7ad5..acd9f00a0b76 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -53,7 +53,8 @@ int hcd_buffer_create(struct usb_hcd *hcd)
53 char name[16]; 53 char name[16];
54 int i, size; 54 int i, size;
55 55
56 if (!hcd->self.controller->dma_mask) 56 if (!hcd->self.controller->dma_mask &&
57 !(hcd->driver->flags & HCD_LOCAL_MEM))
57 return 0; 58 return 0;
58 59
59 for (i = 0; i < HCD_BUFFER_POOLS; i++) { 60 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
@@ -107,7 +108,8 @@ void *hcd_buffer_alloc(
107 int i; 108 int i;
108 109
109 /* some USB hosts just use PIO */ 110 /* some USB hosts just use PIO */
110 if (!bus->controller->dma_mask) { 111 if (!bus->controller->dma_mask &&
112 !(hcd->driver->flags & HCD_LOCAL_MEM)) {
111 *dma = ~(dma_addr_t) 0; 113 *dma = ~(dma_addr_t) 0;
112 return kmalloc(size, mem_flags); 114 return kmalloc(size, mem_flags);
113 } 115 }
@@ -132,7 +134,8 @@ void hcd_buffer_free(
132 if (!addr) 134 if (!addr)
133 return; 135 return;
134 136
135 if (!bus->controller->dma_mask) { 137 if (!bus->controller->dma_mask &&
138 !(hcd->driver->flags & HCD_LOCAL_MEM)) {
136 kfree(addr); 139 kfree(addr);
137 return; 140 return;
138 } 141 }
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 372372116bb0..febd6b40da3b 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -35,6 +35,7 @@
35#include <linux/mutex.h> 35#include <linux/mutex.h>
36#include <asm/irq.h> 36#include <asm/irq.h>
37#include <asm/byteorder.h> 37#include <asm/byteorder.h>
38#include <asm/unaligned.h>
38#include <linux/platform_device.h> 39#include <linux/platform_device.h>
39#include <linux/workqueue.h> 40#include <linux/workqueue.h>
40 41
@@ -1112,48 +1113,177 @@ void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
1112} 1113}
1113EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); 1114EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
1114 1115
1115static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) 1116/*
1117 * Some usb host controllers can only perform dma using a small SRAM area.
1118 * The usb core itself is however optimized for host controllers that can dma
1119 * using regular system memory - like pci devices doing bus mastering.
1120 *
1121 * To support host controllers with limited dma capabilites we provide dma
1122 * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag.
1123 * For this to work properly the host controller code must first use the
1124 * function dma_declare_coherent_memory() to point out which memory area
1125 * that should be used for dma allocations.
1126 *
1127 * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for
1128 * dma using dma_alloc_coherent() which in turn allocates from the memory
1129 * area pointed out with dma_declare_coherent_memory().
1130 *
1131 * So, to summarize...
1132 *
1133 * - We need "local" memory, canonical example being
1134 * a small SRAM on a discrete controller being the
1135 * only memory that the controller can read ...
1136 * (a) "normal" kernel memory is no good, and
1137 * (b) there's not enough to share
1138 *
1139 * - The only *portable* hook for such stuff in the
1140 * DMA framework is dma_declare_coherent_memory()
1141 *
1142 * - So we use that, even though the primary requirement
1143 * is that the memory be "local" (hence addressible
1144 * by that device), not "coherent".
1145 *
1146 */
1147
1148static int hcd_alloc_coherent(struct usb_bus *bus,
1149 gfp_t mem_flags, dma_addr_t *dma_handle,
1150 void **vaddr_handle, size_t size,
1151 enum dma_data_direction dir)
1152{
1153 unsigned char *vaddr;
1154
1155 vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr),
1156 mem_flags, dma_handle);
1157 if (!vaddr)
1158 return -ENOMEM;
1159
1160 /*
1161 * Store the virtual address of the buffer at the end
1162 * of the allocated dma buffer. The size of the buffer
1163 * may be uneven so use unaligned functions instead
1164 * of just rounding up. It makes sense to optimize for
1165 * memory footprint over access speed since the amount
1166 * of memory available for dma may be limited.
1167 */
1168 put_unaligned((unsigned long)*vaddr_handle,
1169 (unsigned long *)(vaddr + size));
1170
1171 if (dir == DMA_TO_DEVICE)
1172 memcpy(vaddr, *vaddr_handle, size);
1173
1174 *vaddr_handle = vaddr;
1175 return 0;
1176}
1177
1178static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
1179 void **vaddr_handle, size_t size,
1180 enum dma_data_direction dir)
1181{
1182 unsigned char *vaddr = *vaddr_handle;
1183
1184 vaddr = (void *)get_unaligned((unsigned long *)(vaddr + size));
1185
1186 if (dir == DMA_FROM_DEVICE)
1187 memcpy(vaddr, *vaddr_handle, size);
1188
1189 hcd_buffer_free(bus, size + sizeof(vaddr), *vaddr_handle, *dma_handle);
1190
1191 *vaddr_handle = vaddr;
1192 *dma_handle = 0;
1193}
1194
1195static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
1196 gfp_t mem_flags)
1116{ 1197{
1198 enum dma_data_direction dir;
1199 int ret = 0;
1200
1117 /* Map the URB's buffers for DMA access. 1201 /* Map the URB's buffers for DMA access.
1118 * Lower level HCD code should use *_dma exclusively, 1202 * Lower level HCD code should use *_dma exclusively,
1119 * unless it uses pio or talks to another transport. 1203 * unless it uses pio or talks to another transport.
1120 */ 1204 */
1121 if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { 1205 if (is_root_hub(urb->dev))
1122 if (usb_endpoint_xfer_control(&urb->ep->desc) 1206 return 0;
1123 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) 1207
1124 urb->setup_dma = dma_map_single ( 1208 if (usb_endpoint_xfer_control(&urb->ep->desc)
1209 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
1210 if (hcd->self.uses_dma)
1211 urb->setup_dma = dma_map_single(
1125 hcd->self.controller, 1212 hcd->self.controller,
1126 urb->setup_packet, 1213 urb->setup_packet,
1127 sizeof (struct usb_ctrlrequest), 1214 sizeof(struct usb_ctrlrequest),
1128 DMA_TO_DEVICE); 1215 DMA_TO_DEVICE);
1129 if (urb->transfer_buffer_length != 0 1216 else if (hcd->driver->flags & HCD_LOCAL_MEM)
1130 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) 1217 ret = hcd_alloc_coherent(
1218 urb->dev->bus, mem_flags,
1219 &urb->setup_dma,
1220 (void **)&urb->setup_packet,
1221 sizeof(struct usb_ctrlrequest),
1222 DMA_TO_DEVICE);
1223 }
1224
1225 dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1226 if (ret == 0 && urb->transfer_buffer_length != 0
1227 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
1228 if (hcd->self.uses_dma)
1131 urb->transfer_dma = dma_map_single ( 1229 urb->transfer_dma = dma_map_single (
1132 hcd->self.controller, 1230 hcd->self.controller,
1133 urb->transfer_buffer, 1231 urb->transfer_buffer,
1134 urb->transfer_buffer_length, 1232 urb->transfer_buffer_length,
1135 usb_urb_dir_in(urb) 1233 dir);
1136 ? DMA_FROM_DEVICE 1234 else if (hcd->driver->flags & HCD_LOCAL_MEM) {
1137 : DMA_TO_DEVICE); 1235 ret = hcd_alloc_coherent(
1236 urb->dev->bus, mem_flags,
1237 &urb->transfer_dma,
1238 &urb->transfer_buffer,
1239 urb->transfer_buffer_length,
1240 dir);
1241
1242 if (ret && usb_endpoint_xfer_control(&urb->ep->desc)
1243 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
1244 hcd_free_coherent(urb->dev->bus,
1245 &urb->setup_dma,
1246 (void **)&urb->setup_packet,
1247 sizeof(struct usb_ctrlrequest),
1248 DMA_TO_DEVICE);
1249 }
1138 } 1250 }
1251 return ret;
1139} 1252}
1140 1253
1141static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) 1254static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
1142{ 1255{
1143 if (hcd->self.uses_dma && !is_root_hub(urb->dev)) { 1256 enum dma_data_direction dir;
1144 if (usb_endpoint_xfer_control(&urb->ep->desc) 1257
1145 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) 1258 if (is_root_hub(urb->dev))
1259 return;
1260
1261 if (usb_endpoint_xfer_control(&urb->ep->desc)
1262 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
1263 if (hcd->self.uses_dma)
1146 dma_unmap_single(hcd->self.controller, urb->setup_dma, 1264 dma_unmap_single(hcd->self.controller, urb->setup_dma,
1147 sizeof(struct usb_ctrlrequest), 1265 sizeof(struct usb_ctrlrequest),
1148 DMA_TO_DEVICE); 1266 DMA_TO_DEVICE);
1149 if (urb->transfer_buffer_length != 0 1267 else if (hcd->driver->flags & HCD_LOCAL_MEM)
1150 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) 1268 hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
1269 (void **)&urb->setup_packet,
1270 sizeof(struct usb_ctrlrequest),
1271 DMA_TO_DEVICE);
1272 }
1273
1274 dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1275 if (urb->transfer_buffer_length != 0
1276 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
1277 if (hcd->self.uses_dma)
1151 dma_unmap_single(hcd->self.controller, 1278 dma_unmap_single(hcd->self.controller,
1152 urb->transfer_dma, 1279 urb->transfer_dma,
1153 urb->transfer_buffer_length, 1280 urb->transfer_buffer_length,
1154 usb_urb_dir_in(urb) 1281 dir);
1155 ? DMA_FROM_DEVICE 1282 else if (hcd->driver->flags & HCD_LOCAL_MEM)
1156 : DMA_TO_DEVICE); 1283 hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
1284 &urb->transfer_buffer,
1285 urb->transfer_buffer_length,
1286 dir);
1157 } 1287 }
1158} 1288}
1159 1289
@@ -1185,7 +1315,12 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
1185 * URBs must be submitted in process context with interrupts 1315 * URBs must be submitted in process context with interrupts
1186 * enabled. 1316 * enabled.
1187 */ 1317 */
1188 map_urb_for_dma(hcd, urb); 1318 status = map_urb_for_dma(hcd, urb, mem_flags);
1319 if (unlikely(status)) {
1320 usbmon_urb_submit_error(&hcd->self, urb, status);
1321 goto error;
1322 }
1323
1189 if (is_root_hub(urb->dev)) 1324 if (is_root_hub(urb->dev))
1190 status = rh_urb_enqueue(hcd, urb); 1325 status = rh_urb_enqueue(hcd, urb);
1191 else 1326 else
@@ -1194,6 +1329,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
1194 if (unlikely(status)) { 1329 if (unlikely(status)) {
1195 usbmon_urb_submit_error(&hcd->self, urb, status); 1330 usbmon_urb_submit_error(&hcd->self, urb, status);
1196 unmap_urb_for_dma(hcd, urb); 1331 unmap_urb_for_dma(hcd, urb);
1332 error:
1197 urb->hcpriv = NULL; 1333 urb->hcpriv = NULL;
1198 INIT_LIST_HEAD(&urb->urb_list); 1334 INIT_LIST_HEAD(&urb->urb_list);
1199 atomic_dec(&urb->use_count); 1335 atomic_dec(&urb->use_count);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 080298ad5990..0095641c51fa 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -165,6 +165,7 @@ struct hc_driver {
165 165
166 int flags; 166 int flags;
167#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ 167#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
168#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
168#define HCD_USB11 0x0010 /* USB 1.1 */ 169#define HCD_USB11 0x0010 /* USB 1.1 */
169#define HCD_USB2 0x0020 /* USB 2.0 */ 170#define HCD_USB2 0x0020 /* USB 2.0 */
170 171