Skip to content

Commit ff9c895

Browse files
AlanSterngregkh
authored andcommitted
USB: fix usbmon and DMA mapping for scatter-gather URBs
This patch (as1368) fixes a rather obscure bug in usbmon: When tracing URBs sent by the scatter-gather library, it accesses the data buffers while they are still mapped for DMA. The solution is to move the mapping and unmapping out of the s-g library and into the usual place in hcd.c. This requires the addition of new URB flag bits to describe the kind of mapping needed, since we have to call dma_map_sg() if the HCD supports native scatter-gather operation and dma_map_page() if it doesn't. The nice thing about having the new flags is that they simplify the testing for unmapping. The patch removes the only caller of usb_buffer_[un]map_sg(), so those functions are #if'ed out. A later patch will remove them entirely. As a result of this change, urb->sg will be set in situations where it wasn't set previously. Hence the xhci and whci drivers are adjusted to test urb->num_sgs instead, which retains its original meaning and is nonzero only when the HCD has to handle a scatterlist. Finally, even when a submission error occurs we don't want to hand URBs to usbmon before they are unmapped. The submission path is rearranged so that map_urb_for_dma() is called only for non-root-hub URBs and unmap_urb_for_dma() is called immediately after a submission error. This simplifies the error handling. Signed-off-by: Alan Stern <[email protected]> CC: <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0ff8d1b commit ff9c895

File tree

9 files changed

+138
-108
lines changed

9 files changed

+138
-108
lines changed

drivers/usb/core/hcd.c

Lines changed: 105 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,51 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
12591259
*dma_handle = 0;
12601260
}
12611261

1262+
static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
1263+
{
1264+
enum dma_data_direction dir;
1265+
1266+
if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
1267+
dma_unmap_single(hcd->self.controller,
1268+
urb->setup_dma,
1269+
sizeof(struct usb_ctrlrequest),
1270+
DMA_TO_DEVICE);
1271+
else if (urb->transfer_flags & URB_SETUP_MAP_LOCAL)
1272+
hcd_free_coherent(urb->dev->bus,
1273+
&urb->setup_dma,
1274+
(void **) &urb->setup_packet,
1275+
sizeof(struct usb_ctrlrequest),
1276+
DMA_TO_DEVICE);
1277+
1278+
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1279+
if (urb->transfer_flags & URB_DMA_MAP_SG)
1280+
dma_unmap_sg(hcd->self.controller,
1281+
urb->sg->sg,
1282+
urb->num_sgs,
1283+
dir);
1284+
else if (urb->transfer_flags & URB_DMA_MAP_PAGE)
1285+
dma_unmap_page(hcd->self.controller,
1286+
urb->transfer_dma,
1287+
urb->transfer_buffer_length,
1288+
dir);
1289+
else if (urb->transfer_flags & URB_DMA_MAP_SINGLE)
1290+
dma_unmap_single(hcd->self.controller,
1291+
urb->transfer_dma,
1292+
urb->transfer_buffer_length,
1293+
dir);
1294+
else if (urb->transfer_flags & URB_MAP_LOCAL)
1295+
hcd_free_coherent(urb->dev->bus,
1296+
&urb->transfer_dma,
1297+
&urb->transfer_buffer,
1298+
urb->transfer_buffer_length,
1299+
dir);
1300+
1301+
/* Make it safe to call this routine more than once */
1302+
urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
1303+
URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |
1304+
URB_DMA_MAP_SINGLE | URB_MAP_LOCAL);
1305+
}
1306+
12621307
static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
12631308
gfp_t mem_flags)
12641309
{
@@ -1270,8 +1315,6 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
12701315
* unless it uses pio or talks to another transport,
12711316
* or uses the provided scatter gather list for bulk.
12721317
*/
1273-
if (is_root_hub(urb->dev))
1274-
return 0;
12751318

12761319
if (usb_endpoint_xfer_control(&urb->ep->desc)
12771320
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
@@ -1284,83 +1327,82 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
12841327
if (dma_mapping_error(hcd->self.controller,
12851328
urb->setup_dma))
12861329
return -EAGAIN;
1330+
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
12871331
} else if (hcd->driver->flags & HCD_LOCAL_MEM)
12881332
ret = hcd_alloc_coherent(
12891333
urb->dev->bus, mem_flags,
12901334
&urb->setup_dma,
12911335
(void **)&urb->setup_packet,
12921336
sizeof(struct usb_ctrlrequest),
12931337
DMA_TO_DEVICE);
1338+
if (ret)
1339+
return ret;
1340+
urb->transfer_flags |= URB_SETUP_MAP_LOCAL;
12941341
}
12951342

12961343
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1297-
if (ret == 0 && urb->transfer_buffer_length != 0
1344+
if (urb->transfer_buffer_length != 0
12981345
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
12991346
if (hcd->self.uses_dma) {
1300-
urb->transfer_dma = dma_map_single (
1301-
hcd->self.controller,
1302-
urb->transfer_buffer,
1303-
urb->transfer_buffer_length,
1304-
dir);
1305-
if (dma_mapping_error(hcd->self.controller,
1347+
if (urb->num_sgs) {
1348+
int n = dma_map_sg(
1349+
hcd->self.controller,
1350+
urb->sg->sg,
1351+
urb->num_sgs,
1352+
dir);
1353+
if (n <= 0)
1354+
ret = -EAGAIN;
1355+
else
1356+
urb->transfer_flags |= URB_DMA_MAP_SG;
1357+
if (n != urb->num_sgs) {
1358+
urb->num_sgs = n;
1359+
urb->transfer_flags |=
1360+
URB_DMA_SG_COMBINED;
1361+
}
1362+
} else if (urb->sg) {
1363+
struct scatterlist *sg;
1364+
1365+
sg = (struct scatterlist *) urb->sg;
1366+
urb->transfer_dma = dma_map_page(
1367+
hcd->self.controller,
1368+
sg_page(sg),
1369+
sg->offset,
1370+
urb->transfer_buffer_length,
1371+
dir);
1372+
if (dma_mapping_error(hcd->self.controller,
13061373
urb->transfer_dma))
1307-
return -EAGAIN;
1374+
ret = -EAGAIN;
1375+
else
1376+
urb->transfer_flags |= URB_DMA_MAP_PAGE;
1377+
} else {
1378+
urb->transfer_dma = dma_map_single(
1379+
hcd->self.controller,
1380+
urb->transfer_buffer,
1381+
urb->transfer_buffer_length,
1382+
dir);
1383+
if (dma_mapping_error(hcd->self.controller,
1384+
urb->transfer_dma))
1385+
ret = -EAGAIN;
1386+
else
1387+
urb->transfer_flags |= URB_DMA_MAP_SINGLE;
1388+
}
13081389
} else if (hcd->driver->flags & HCD_LOCAL_MEM) {
13091390
ret = hcd_alloc_coherent(
13101391
urb->dev->bus, mem_flags,
13111392
&urb->transfer_dma,
13121393
&urb->transfer_buffer,
13131394
urb->transfer_buffer_length,
13141395
dir);
1315-
1316-
if (ret && usb_endpoint_xfer_control(&urb->ep->desc)
1317-
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
1318-
hcd_free_coherent(urb->dev->bus,
1319-
&urb->setup_dma,
1320-
(void **)&urb->setup_packet,
1321-
sizeof(struct usb_ctrlrequest),
1322-
DMA_TO_DEVICE);
1396+
if (ret == 0)
1397+
urb->transfer_flags |= URB_MAP_LOCAL;
13231398
}
1399+
if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE |
1400+
URB_SETUP_MAP_LOCAL)))
1401+
unmap_urb_for_dma(hcd, urb);
13241402
}
13251403
return ret;
13261404
}
13271405

1328-
static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
1329-
{
1330-
enum dma_data_direction dir;
1331-
1332-
if (is_root_hub(urb->dev))
1333-
return;
1334-
1335-
if (usb_endpoint_xfer_control(&urb->ep->desc)
1336-
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
1337-
if (hcd->self.uses_dma)
1338-
dma_unmap_single(hcd->self.controller, urb->setup_dma,
1339-
sizeof(struct usb_ctrlrequest),
1340-
DMA_TO_DEVICE);
1341-
else if (hcd->driver->flags & HCD_LOCAL_MEM)
1342-
hcd_free_coherent(urb->dev->bus, &urb->setup_dma,
1343-
(void **)&urb->setup_packet,
1344-
sizeof(struct usb_ctrlrequest),
1345-
DMA_TO_DEVICE);
1346-
}
1347-
1348-
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
1349-
if (urb->transfer_buffer_length != 0
1350-
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
1351-
if (hcd->self.uses_dma)
1352-
dma_unmap_single(hcd->self.controller,
1353-
urb->transfer_dma,
1354-
urb->transfer_buffer_length,
1355-
dir);
1356-
else if (hcd->driver->flags & HCD_LOCAL_MEM)
1357-
hcd_free_coherent(urb->dev->bus, &urb->transfer_dma,
1358-
&urb->transfer_buffer,
1359-
urb->transfer_buffer_length,
1360-
dir);
1361-
}
1362-
}
1363-
13641406
/*-------------------------------------------------------------------------*/
13651407

13661408
/* may be called in any context with a valid urb->dev usecount
@@ -1389,21 +1431,20 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
13891431
* URBs must be submitted in process context with interrupts
13901432
* enabled.
13911433
*/
1392-
status = map_urb_for_dma(hcd, urb, mem_flags);
1393-
if (unlikely(status)) {
1394-
usbmon_urb_submit_error(&hcd->self, urb, status);
1395-
goto error;
1396-
}
13971434

1398-
if (is_root_hub(urb->dev))
1435+
if (is_root_hub(urb->dev)) {
13991436
status = rh_urb_enqueue(hcd, urb);
1400-
else
1401-
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
1437+
} else {
1438+
status = map_urb_for_dma(hcd, urb, mem_flags);
1439+
if (likely(status == 0)) {
1440+
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
1441+
if (unlikely(status))
1442+
unmap_urb_for_dma(hcd, urb);
1443+
}
1444+
}
14021445

14031446
if (unlikely(status)) {
14041447
usbmon_urb_submit_error(&hcd->self, urb, status);
1405-
unmap_urb_for_dma(hcd, urb);
1406-
error:
14071448
urb->hcpriv = NULL;
14081449
INIT_LIST_HEAD(&urb->urb_list);
14091450
atomic_dec(&urb->use_count);

drivers/usb/core/message.c

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,6 @@ static void sg_clean(struct usb_sg_request *io)
259259
kfree(io->urbs);
260260
io->urbs = NULL;
261261
}
262-
if (io->dev->dev.dma_mask != NULL)
263-
usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
264-
io->sg, io->nents);
265262
io->dev = NULL;
266263
}
267264

@@ -364,7 +361,6 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
364361
{
365362
int i;
366363
int urb_flags;
367-
int dma;
368364
int use_sg;
369365

370366
if (!io || !dev || !sg
@@ -378,21 +374,9 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
378374
io->pipe = pipe;
379375
io->sg = sg;
380376
io->nents = nents;
381-
382-
/* not all host controllers use DMA (like the mainstream pci ones);
383-
* they can use PIO (sl811) or be software over another transport.
384-
*/
385-
dma = (dev->dev.dma_mask != NULL);
386-
if (dma)
387-
io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
388-
sg, nents);
389-
else
390-
io->entries = nents;
377+
io->entries = nents;
391378

392379
/* initialize all the urbs we'll use */
393-
if (io->entries <= 0)
394-
return io->entries;
395-
396380
if (dev->bus->sg_tablesize > 0) {
397381
io->urbs = kmalloc(sizeof *io->urbs, mem_flags);
398382
use_sg = true;
@@ -404,8 +388,6 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
404388
goto nomem;
405389

406390
urb_flags = 0;
407-
if (dma)
408-
urb_flags |= URB_NO_TRANSFER_DMA_MAP;
409391
if (usb_pipein(pipe))
410392
urb_flags |= URB_SHORT_NOT_OK;
411393

@@ -423,12 +405,13 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
423405

424406
io->urbs[0]->complete = sg_complete;
425407
io->urbs[0]->context = io;
408+
426409
/* A length of zero means transfer the whole sg list */
427410
io->urbs[0]->transfer_buffer_length = length;
428411
if (length == 0) {
429412
for_each_sg(sg, sg, io->entries, i) {
430413
io->urbs[0]->transfer_buffer_length +=
431-
sg_dma_len(sg);
414+
sg->length;
432415
}
433416
}
434417
io->urbs[0]->sg = io;
@@ -454,33 +437,25 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
454437
io->urbs[i]->context = io;
455438

456439
/*
457-
* Some systems need to revert to PIO when DMA is temporarily
458-
* unavailable. For their sakes, both transfer_buffer and
459-
* transfer_dma are set when possible.
460-
*
461-
* Note that if IOMMU coalescing occurred, we cannot
462-
* trust sg_page anymore, so check if S/G list shrunk.
440+
* Some systems can't use DMA; they use PIO instead.
441+
* For their sakes, transfer_buffer is set whenever
442+
* possible.
463443
*/
464-
if (io->nents == io->entries && !PageHighMem(sg_page(sg)))
444+
if (!PageHighMem(sg_page(sg)))
465445
io->urbs[i]->transfer_buffer = sg_virt(sg);
466446
else
467447
io->urbs[i]->transfer_buffer = NULL;
468448

469-
if (dma) {
470-
io->urbs[i]->transfer_dma = sg_dma_address(sg);
471-
len = sg_dma_len(sg);
472-
} else {
473-
/* hc may use _only_ transfer_buffer */
474-
len = sg->length;
475-
}
476-
449+
len = sg->length;
477450
if (length) {
478451
len = min_t(unsigned, len, length);
479452
length -= len;
480453
if (length == 0)
481454
io->entries = i + 1;
482455
}
483456
io->urbs[i]->transfer_buffer_length = len;
457+
458+
io->urbs[i]->sg = (struct usb_sg_request *) sg;
484459
}
485460
io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
486461
}

drivers/usb/core/urb.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,9 +333,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
333333
is_out = usb_endpoint_dir_out(&ep->desc);
334334
}
335335

336-
/* Cache the direction for later use */
337-
urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
338-
(is_out ? URB_DIR_OUT : URB_DIR_IN);
336+
/* Clear the internal flags and cache the direction for later use */
337+
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |
338+
URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
339+
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
340+
URB_DMA_SG_COMBINED);
341+
urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN);
339342

340343
if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
341344
dev->state < USB_STATE_CONFIGURED)

drivers/usb/core/usb.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,7 @@ void usb_buffer_unmap(struct urb *urb)
881881
EXPORT_SYMBOL_GPL(usb_buffer_unmap);
882882
#endif /* 0 */
883883

884+
#if 0
884885
/**
885886
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
886887
* @dev: device to which the scatterlist will be mapped
@@ -924,6 +925,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
924925
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE) ? : -ENOMEM;
925926
}
926927
EXPORT_SYMBOL_GPL(usb_buffer_map_sg);
928+
#endif
927929

928930
/* XXX DISABLED, no users currently. If you wish to re-enable this
929931
* XXX please determine whether the sync is to transfer ownership of
@@ -960,6 +962,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
960962
EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
961963
#endif
962964

965+
#if 0
963966
/**
964967
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
965968
* @dev: device to which the scatterlist will be mapped
@@ -985,6 +988,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
985988
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
986989
}
987990
EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg);
991+
#endif
988992

989993
/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */
990994
#ifdef MODULE

drivers/usb/host/whci/qset.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
646646
wurb->urb = urb;
647647
INIT_WORK(&wurb->dequeue_work, urb_dequeue_work);
648648

649-
if (urb->sg) {
649+
if (urb->num_sgs) {
650650
ret = qset_add_urb_sg(whc, qset, urb, mem_flags);
651651
if (ret == -EINVAL) {
652652
qset_free_stds(qset, urb);

drivers/usb/host/xhci-ring.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1962,7 +1962,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
19621962
int running_total, trb_buff_len, ret;
19631963
u64 addr;
19641964

1965-
if (urb->sg)
1965+
if (urb->num_sgs)
19661966
return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
19671967

19681968
ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;

0 commit comments

Comments
 (0)