diff options
-rw-r--r-- | drivers/usb/misc/usbtest.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index b42ae6bfb12b..81ba14c73dc7 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c | |||
@@ -1337,7 +1337,9 @@ struct iso_context { | |||
1337 | unsigned pending; | 1337 | unsigned pending; |
1338 | spinlock_t lock; | 1338 | spinlock_t lock; |
1339 | struct completion done; | 1339 | struct completion done; |
1340 | int submit_error; | ||
1340 | unsigned long errors; | 1341 | unsigned long errors; |
1342 | unsigned long packet_count; | ||
1341 | struct usbtest_dev *dev; | 1343 | struct usbtest_dev *dev; |
1342 | }; | 1344 | }; |
1343 | 1345 | ||
@@ -1348,10 +1350,14 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs) | |||
1348 | spin_lock(&ctx->lock); | 1350 | spin_lock(&ctx->lock); |
1349 | ctx->count--; | 1351 | ctx->count--; |
1350 | 1352 | ||
1353 | ctx->packet_count += urb->number_of_packets; | ||
1351 | if (urb->error_count > 0) | 1354 | if (urb->error_count > 0) |
1352 | ctx->errors += urb->error_count; | 1355 | ctx->errors += urb->error_count; |
1356 | else if (urb->status != 0) | ||
1357 | ctx->errors += urb->number_of_packets; | ||
1353 | 1358 | ||
1354 | if (urb->status == 0 && ctx->count > (ctx->pending - 1)) { | 1359 | if (urb->status == 0 && ctx->count > (ctx->pending - 1) |
1360 | && !ctx->submit_error) { | ||
1355 | int status = usb_submit_urb (urb, GFP_ATOMIC); | 1361 | int status = usb_submit_urb (urb, GFP_ATOMIC); |
1356 | switch (status) { | 1362 | switch (status) { |
1357 | case 0: | 1363 | case 0: |
@@ -1362,6 +1368,8 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs) | |||
1362 | status); | 1368 | status); |
1363 | /* FALLTHROUGH */ | 1369 | /* FALLTHROUGH */ |
1364 | case -ENODEV: /* disconnected */ | 1370 | case -ENODEV: /* disconnected */ |
1371 | case -ESHUTDOWN: /* endpoint disabled */ | ||
1372 | ctx->submit_error = 1; | ||
1365 | break; | 1373 | break; |
1366 | } | 1374 | } |
1367 | } | 1375 | } |
@@ -1371,8 +1379,8 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs) | |||
1371 | if (ctx->pending == 0) { | 1379 | if (ctx->pending == 0) { |
1372 | if (ctx->errors) | 1380 | if (ctx->errors) |
1373 | dev_dbg (&ctx->dev->intf->dev, | 1381 | dev_dbg (&ctx->dev->intf->dev, |
1374 | "iso test, %lu errors\n", | 1382 | "iso test, %lu errors out of %lu\n", |
1375 | ctx->errors); | 1383 | ctx->errors, ctx->packet_count); |
1376 | complete (&ctx->done); | 1384 | complete (&ctx->done); |
1377 | } | 1385 | } |
1378 | done: | 1386 | done: |
@@ -1433,15 +1441,14 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, | |||
1433 | struct usb_device *udev; | 1441 | struct usb_device *udev; |
1434 | unsigned i; | 1442 | unsigned i; |
1435 | unsigned long packets = 0; | 1443 | unsigned long packets = 0; |
1436 | int status; | 1444 | int status = 0; |
1437 | struct urb *urbs[10]; /* FIXME no limit */ | 1445 | struct urb *urbs[10]; /* FIXME no limit */ |
1438 | 1446 | ||
1439 | if (param->sglen > 10) | 1447 | if (param->sglen > 10) |
1440 | return -EDOM; | 1448 | return -EDOM; |
1441 | 1449 | ||
1450 | memset(&context, 0, sizeof context); | ||
1442 | context.count = param->iterations * param->sglen; | 1451 | context.count = param->iterations * param->sglen; |
1443 | context.pending = param->sglen; | ||
1444 | context.errors = 0; | ||
1445 | context.dev = dev; | 1452 | context.dev = dev; |
1446 | init_completion (&context.done); | 1453 | init_completion (&context.done); |
1447 | spin_lock_init (&context.lock); | 1454 | spin_lock_init (&context.lock); |
@@ -1473,6 +1480,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, | |||
1473 | 1480 | ||
1474 | spin_lock_irq (&context.lock); | 1481 | spin_lock_irq (&context.lock); |
1475 | for (i = 0; i < param->sglen; i++) { | 1482 | for (i = 0; i < param->sglen; i++) { |
1483 | ++context.pending; | ||
1476 | status = usb_submit_urb (urbs [i], SLAB_ATOMIC); | 1484 | status = usb_submit_urb (urbs [i], SLAB_ATOMIC); |
1477 | if (status < 0) { | 1485 | if (status < 0) { |
1478 | ERROR (dev, "submit iso[%d], error %d\n", i, status); | 1486 | ERROR (dev, "submit iso[%d], error %d\n", i, status); |
@@ -1483,12 +1491,26 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, | |||
1483 | 1491 | ||
1484 | simple_free_urb (urbs [i]); | 1492 | simple_free_urb (urbs [i]); |
1485 | context.pending--; | 1493 | context.pending--; |
1494 | context.submit_error = 1; | ||
1495 | break; | ||
1486 | } | 1496 | } |
1487 | } | 1497 | } |
1488 | spin_unlock_irq (&context.lock); | 1498 | spin_unlock_irq (&context.lock); |
1489 | 1499 | ||
1490 | wait_for_completion (&context.done); | 1500 | wait_for_completion (&context.done); |
1491 | return 0; | 1501 | |
1502 | /* | ||
1503 | * Isochronous transfers are expected to fail sometimes. As an | ||
1504 | * arbitrary limit, we will report an error if any submissions | ||
1505 | * fail or if the transfer failure rate is > 10%. | ||
1506 | */ | ||
1507 | if (status != 0) | ||
1508 | ; | ||
1509 | else if (context.submit_error) | ||
1510 | status = -EACCES; | ||
1511 | else if (context.errors > context.packet_count / 10) | ||
1512 | status = -EIO; | ||
1513 | return status; | ||
1492 | 1514 | ||
1493 | fail: | 1515 | fail: |
1494 | for (i = 0; i < param->sglen; i++) { | 1516 | for (i = 0; i < param->sglen; i++) { |