diff options
author | Per Forlin <per.forlin@linaro.org> | 2011-08-19 15:21:27 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-09-09 06:06:04 -0400 |
commit | 6532c7fdb2c3a2ec1b949ecd2ff5375069c1639a (patch) | |
tree | 26afd8fdff7923f818f49aa405bb4208d1da914e /drivers/usb/gadget | |
parent | 04eee25b1d754a837360504b7af426d1f86ffeb7 (diff) |
usb: gadget: storage: make FSG_NUM_BUFFERS variable size
FSG_NUM_BUFFERS is set to 2 as default.
Usually 2 buffers are enough to establish a good buffering pipeline.
The number may be increased in order to compensate a for bursty VFS
behaviour.
Here follows a description of system that may require more than
2 buffers.
* CPU ondemand governor active
* latency cost for wake up and/or frequency change
* DMA for IO
Use case description.
* Data transfer from MMC via VFS to USB.
* DMA shuffles data from MMC and to USB.
* The CPU wakes up every now and then to pass data in and out from VFS,
which cause the bursty VFS behaviour.
Test set up
* Running dd on the host reading from the mass storage device
* cmdline: dd if=/dev/sdb of=/dev/null bs=4k count=$((256*100))
* Caches are dropped on the host and on the device before each run
Measurements on a Snowball board with ondemand_governor active.
FSG_NUM_BUFFERS 2
104857600 bytes (105 MB) copied, 5.62173 s, 18.7 MB/s
104857600 bytes (105 MB) copied, 5.61811 s, 18.7 MB/s
104857600 bytes (105 MB) copied, 5.57817 s, 18.8 MB/s
FSG_NUM_BUFFERS 4
104857600 bytes (105 MB) copied, 5.26839 s, 19.9 MB/s
104857600 bytes (105 MB) copied, 5.2691 s, 19.9 MB/s
104857600 bytes (105 MB) copied, 5.2711 s, 19.9 MB/s
There may not be one optimal number for all boards. This is why
the number is added to Kconfig. If selecting USB_GADGET_DEBUG_FILES
this value may be set by a module parameter as well.
Signed-off-by: Per Forlin <per.forlin@linaro.org>
Acked-by: Michal Nazarewicz <mina86@mina86.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 29 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 27 | ||||
-rw-r--r-- | drivers/usb/gadget/storage_common.c | 33 |
4 files changed, 85 insertions, 20 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index fe5637983892..a60b472a0b39 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -96,6 +96,22 @@ config USB_GADGET_VBUS_DRAW | |||
96 | This value will be used except for system-specific gadget | 96 | This value will be used except for system-specific gadget |
97 | drivers that have more specific information. | 97 | drivers that have more specific information. |
98 | 98 | ||
99 | config USB_GADGET_STORAGE_NUM_BUFFERS | ||
100 | int "Number of storage pipeline buffers" | ||
101 | range 2 4 | ||
102 | default 2 | ||
103 | help | ||
104 | Usually 2 buffers are enough to establish a good buffering | ||
105 | pipeline. The number may be increased in order to compensate | ||
106 | for a bursty VFS behaviour. For instance there may be CPU wake up | ||
107 | latencies that makes the VFS to appear bursty in a system with | ||
108 | an CPU on-demand governor. Especially if DMA is doing IO to | ||
109 | offload the CPU. In this case the CPU will go into power | ||
110 | save often and spin up occasionally to move data within VFS. | ||
111 | If selecting USB_GADGET_DEBUG_FILES this value may be set by | ||
112 | a module parameter as well. | ||
113 | If unsure, say 2. | ||
114 | |||
99 | # | 115 | # |
100 | # USB Peripheral Controller Support | 116 | # USB Peripheral Controller Support |
101 | # | 117 | # |
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 4306a8339487..756941473148 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c | |||
@@ -362,7 +362,7 @@ struct fsg_common { | |||
362 | 362 | ||
363 | struct fsg_buffhd *next_buffhd_to_fill; | 363 | struct fsg_buffhd *next_buffhd_to_fill; |
364 | struct fsg_buffhd *next_buffhd_to_drain; | 364 | struct fsg_buffhd *next_buffhd_to_drain; |
365 | struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; | 365 | struct fsg_buffhd *buffhds; |
366 | 366 | ||
367 | int cmnd_size; | 367 | int cmnd_size; |
368 | u8 cmnd[MAX_COMMAND_SIZE]; | 368 | u8 cmnd[MAX_COMMAND_SIZE]; |
@@ -2340,7 +2340,7 @@ reset: | |||
2340 | if (common->fsg) { | 2340 | if (common->fsg) { |
2341 | fsg = common->fsg; | 2341 | fsg = common->fsg; |
2342 | 2342 | ||
2343 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2343 | for (i = 0; i < fsg_num_buffers; ++i) { |
2344 | struct fsg_buffhd *bh = &common->buffhds[i]; | 2344 | struct fsg_buffhd *bh = &common->buffhds[i]; |
2345 | 2345 | ||
2346 | if (bh->inreq) { | 2346 | if (bh->inreq) { |
@@ -2397,7 +2397,7 @@ reset: | |||
2397 | clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); | 2397 | clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); |
2398 | 2398 | ||
2399 | /* Allocate the requests */ | 2399 | /* Allocate the requests */ |
2400 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2400 | for (i = 0; i < fsg_num_buffers; ++i) { |
2401 | struct fsg_buffhd *bh = &common->buffhds[i]; | 2401 | struct fsg_buffhd *bh = &common->buffhds[i]; |
2402 | 2402 | ||
2403 | rc = alloc_request(common, fsg->bulk_in, &bh->inreq); | 2403 | rc = alloc_request(common, fsg->bulk_in, &bh->inreq); |
@@ -2466,7 +2466,7 @@ static void handle_exception(struct fsg_common *common) | |||
2466 | 2466 | ||
2467 | /* Cancel all the pending transfers */ | 2467 | /* Cancel all the pending transfers */ |
2468 | if (likely(common->fsg)) { | 2468 | if (likely(common->fsg)) { |
2469 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2469 | for (i = 0; i < fsg_num_buffers; ++i) { |
2470 | bh = &common->buffhds[i]; | 2470 | bh = &common->buffhds[i]; |
2471 | if (bh->inreq_busy) | 2471 | if (bh->inreq_busy) |
2472 | usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); | 2472 | usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); |
@@ -2478,7 +2478,7 @@ static void handle_exception(struct fsg_common *common) | |||
2478 | /* Wait until everything is idle */ | 2478 | /* Wait until everything is idle */ |
2479 | for (;;) { | 2479 | for (;;) { |
2480 | int num_active = 0; | 2480 | int num_active = 0; |
2481 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2481 | for (i = 0; i < fsg_num_buffers; ++i) { |
2482 | bh = &common->buffhds[i]; | 2482 | bh = &common->buffhds[i]; |
2483 | num_active += bh->inreq_busy + bh->outreq_busy; | 2483 | num_active += bh->inreq_busy + bh->outreq_busy; |
2484 | } | 2484 | } |
@@ -2501,7 +2501,7 @@ static void handle_exception(struct fsg_common *common) | |||
2501 | */ | 2501 | */ |
2502 | spin_lock_irq(&common->lock); | 2502 | spin_lock_irq(&common->lock); |
2503 | 2503 | ||
2504 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2504 | for (i = 0; i < fsg_num_buffers; ++i) { |
2505 | bh = &common->buffhds[i]; | 2505 | bh = &common->buffhds[i]; |
2506 | bh->state = BUF_STATE_EMPTY; | 2506 | bh->state = BUF_STATE_EMPTY; |
2507 | } | 2507 | } |
@@ -2710,6 +2710,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, | |||
2710 | int nluns, i, rc; | 2710 | int nluns, i, rc; |
2711 | char *pathbuf; | 2711 | char *pathbuf; |
2712 | 2712 | ||
2713 | rc = fsg_num_buffers_validate(); | ||
2714 | if (rc != 0) | ||
2715 | return ERR_PTR(rc); | ||
2716 | |||
2713 | /* Find out how many LUNs there should be */ | 2717 | /* Find out how many LUNs there should be */ |
2714 | nluns = cfg->nluns; | 2718 | nluns = cfg->nluns; |
2715 | if (nluns < 1 || nluns > FSG_MAX_LUNS) { | 2719 | if (nluns < 1 || nluns > FSG_MAX_LUNS) { |
@@ -2728,6 +2732,14 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, | |||
2728 | common->free_storage_on_release = 0; | 2732 | common->free_storage_on_release = 0; |
2729 | } | 2733 | } |
2730 | 2734 | ||
2735 | common->buffhds = kcalloc(fsg_num_buffers, | ||
2736 | sizeof *(common->buffhds), GFP_KERNEL); | ||
2737 | if (!common->buffhds) { | ||
2738 | if (common->free_storage_on_release) | ||
2739 | kfree(common); | ||
2740 | return ERR_PTR(-ENOMEM); | ||
2741 | } | ||
2742 | |||
2731 | common->ops = cfg->ops; | 2743 | common->ops = cfg->ops; |
2732 | common->private_data = cfg->private_data; | 2744 | common->private_data = cfg->private_data; |
2733 | 2745 | ||
@@ -2805,7 +2817,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, | |||
2805 | 2817 | ||
2806 | /* Data buffers cyclic list */ | 2818 | /* Data buffers cyclic list */ |
2807 | bh = common->buffhds; | 2819 | bh = common->buffhds; |
2808 | i = FSG_NUM_BUFFERS; | 2820 | i = fsg_num_buffers; |
2809 | goto buffhds_first_it; | 2821 | goto buffhds_first_it; |
2810 | do { | 2822 | do { |
2811 | bh->next = bh + 1; | 2823 | bh->next = bh + 1; |
@@ -2931,12 +2943,13 @@ static void fsg_common_release(struct kref *ref) | |||
2931 | 2943 | ||
2932 | { | 2944 | { |
2933 | struct fsg_buffhd *bh = common->buffhds; | 2945 | struct fsg_buffhd *bh = common->buffhds; |
2934 | unsigned i = FSG_NUM_BUFFERS; | 2946 | unsigned i = fsg_num_buffers; |
2935 | do { | 2947 | do { |
2936 | kfree(bh->buf); | 2948 | kfree(bh->buf); |
2937 | } while (++bh, --i); | 2949 | } while (++bh, --i); |
2938 | } | 2950 | } |
2939 | 2951 | ||
2952 | kfree(common->buffhds); | ||
2940 | if (common->free_storage_on_release) | 2953 | if (common->free_storage_on_release) |
2941 | kfree(common); | 2954 | kfree(common); |
2942 | } | 2955 | } |
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index c6f96a2b3110..4b9797d07a67 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c | |||
@@ -460,7 +460,6 @@ struct fsg_dev { | |||
460 | 460 | ||
461 | struct fsg_buffhd *next_buffhd_to_fill; | 461 | struct fsg_buffhd *next_buffhd_to_fill; |
462 | struct fsg_buffhd *next_buffhd_to_drain; | 462 | struct fsg_buffhd *next_buffhd_to_drain; |
463 | struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; | ||
464 | 463 | ||
465 | int thread_wakeup_needed; | 464 | int thread_wakeup_needed; |
466 | struct completion thread_notifier; | 465 | struct completion thread_notifier; |
@@ -487,6 +486,8 @@ struct fsg_dev { | |||
487 | unsigned int nluns; | 486 | unsigned int nluns; |
488 | struct fsg_lun *luns; | 487 | struct fsg_lun *luns; |
489 | struct fsg_lun *curlun; | 488 | struct fsg_lun *curlun; |
489 | /* Must be the last entry */ | ||
490 | struct fsg_buffhd buffhds[]; | ||
490 | }; | 491 | }; |
491 | 492 | ||
492 | typedef void (*fsg_routine_t)(struct fsg_dev *); | 493 | typedef void (*fsg_routine_t)(struct fsg_dev *); |
@@ -2737,7 +2738,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting) | |||
2737 | 2738 | ||
2738 | reset: | 2739 | reset: |
2739 | /* Deallocate the requests */ | 2740 | /* Deallocate the requests */ |
2740 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2741 | for (i = 0; i < fsg_num_buffers; ++i) { |
2741 | struct fsg_buffhd *bh = &fsg->buffhds[i]; | 2742 | struct fsg_buffhd *bh = &fsg->buffhds[i]; |
2742 | 2743 | ||
2743 | if (bh->inreq) { | 2744 | if (bh->inreq) { |
@@ -2798,7 +2799,7 @@ reset: | |||
2798 | } | 2799 | } |
2799 | 2800 | ||
2800 | /* Allocate the requests */ | 2801 | /* Allocate the requests */ |
2801 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2802 | for (i = 0; i < fsg_num_buffers; ++i) { |
2802 | struct fsg_buffhd *bh = &fsg->buffhds[i]; | 2803 | struct fsg_buffhd *bh = &fsg->buffhds[i]; |
2803 | 2804 | ||
2804 | if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) | 2805 | if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) |
@@ -2894,7 +2895,7 @@ static void handle_exception(struct fsg_dev *fsg) | |||
2894 | /* Cancel all the pending transfers */ | 2895 | /* Cancel all the pending transfers */ |
2895 | if (fsg->intreq_busy) | 2896 | if (fsg->intreq_busy) |
2896 | usb_ep_dequeue(fsg->intr_in, fsg->intreq); | 2897 | usb_ep_dequeue(fsg->intr_in, fsg->intreq); |
2897 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2898 | for (i = 0; i < fsg_num_buffers; ++i) { |
2898 | bh = &fsg->buffhds[i]; | 2899 | bh = &fsg->buffhds[i]; |
2899 | if (bh->inreq_busy) | 2900 | if (bh->inreq_busy) |
2900 | usb_ep_dequeue(fsg->bulk_in, bh->inreq); | 2901 | usb_ep_dequeue(fsg->bulk_in, bh->inreq); |
@@ -2905,7 +2906,7 @@ static void handle_exception(struct fsg_dev *fsg) | |||
2905 | /* Wait until everything is idle */ | 2906 | /* Wait until everything is idle */ |
2906 | for (;;) { | 2907 | for (;;) { |
2907 | num_active = fsg->intreq_busy; | 2908 | num_active = fsg->intreq_busy; |
2908 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2909 | for (i = 0; i < fsg_num_buffers; ++i) { |
2909 | bh = &fsg->buffhds[i]; | 2910 | bh = &fsg->buffhds[i]; |
2910 | num_active += bh->inreq_busy + bh->outreq_busy; | 2911 | num_active += bh->inreq_busy + bh->outreq_busy; |
2911 | } | 2912 | } |
@@ -2927,7 +2928,7 @@ static void handle_exception(struct fsg_dev *fsg) | |||
2927 | * state, and the exception. Then invoke the handler. */ | 2928 | * state, and the exception. Then invoke the handler. */ |
2928 | spin_lock_irq(&fsg->lock); | 2929 | spin_lock_irq(&fsg->lock); |
2929 | 2930 | ||
2930 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 2931 | for (i = 0; i < fsg_num_buffers; ++i) { |
2931 | bh = &fsg->buffhds[i]; | 2932 | bh = &fsg->buffhds[i]; |
2932 | bh->state = BUF_STATE_EMPTY; | 2933 | bh->state = BUF_STATE_EMPTY; |
2933 | } | 2934 | } |
@@ -3157,7 +3158,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) | |||
3157 | } | 3158 | } |
3158 | 3159 | ||
3159 | /* Free the data buffers */ | 3160 | /* Free the data buffers */ |
3160 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) | 3161 | for (i = 0; i < fsg_num_buffers; ++i) |
3161 | kfree(fsg->buffhds[i].buf); | 3162 | kfree(fsg->buffhds[i].buf); |
3162 | 3163 | ||
3163 | /* Free the request and buffer for endpoint 0 */ | 3164 | /* Free the request and buffer for endpoint 0 */ |
@@ -3445,7 +3446,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) | |||
3445 | req->complete = ep0_complete; | 3446 | req->complete = ep0_complete; |
3446 | 3447 | ||
3447 | /* Allocate the data buffers */ | 3448 | /* Allocate the data buffers */ |
3448 | for (i = 0; i < FSG_NUM_BUFFERS; ++i) { | 3449 | for (i = 0; i < fsg_num_buffers; ++i) { |
3449 | struct fsg_buffhd *bh = &fsg->buffhds[i]; | 3450 | struct fsg_buffhd *bh = &fsg->buffhds[i]; |
3450 | 3451 | ||
3451 | /* Allocate for the bulk-in endpoint. We assume that | 3452 | /* Allocate for the bulk-in endpoint. We assume that |
@@ -3456,7 +3457,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) | |||
3456 | goto out; | 3457 | goto out; |
3457 | bh->next = bh + 1; | 3458 | bh->next = bh + 1; |
3458 | } | 3459 | } |
3459 | fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0]; | 3460 | fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0]; |
3460 | 3461 | ||
3461 | /* This should reflect the actual gadget power source */ | 3462 | /* This should reflect the actual gadget power source */ |
3462 | usb_gadget_set_selfpowered(gadget); | 3463 | usb_gadget_set_selfpowered(gadget); |
@@ -3572,7 +3573,9 @@ static int __init fsg_alloc(void) | |||
3572 | { | 3573 | { |
3573 | struct fsg_dev *fsg; | 3574 | struct fsg_dev *fsg; |
3574 | 3575 | ||
3575 | fsg = kzalloc(sizeof *fsg, GFP_KERNEL); | 3576 | fsg = kzalloc(sizeof *fsg + |
3577 | fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL); | ||
3578 | |||
3576 | if (!fsg) | 3579 | if (!fsg) |
3577 | return -ENOMEM; | 3580 | return -ENOMEM; |
3578 | spin_lock_init(&fsg->lock); | 3581 | spin_lock_init(&fsg->lock); |
@@ -3590,6 +3593,10 @@ static int __init fsg_init(void) | |||
3590 | int rc; | 3593 | int rc; |
3591 | struct fsg_dev *fsg; | 3594 | struct fsg_dev *fsg; |
3592 | 3595 | ||
3596 | rc = fsg_num_buffers_validate(); | ||
3597 | if (rc != 0) | ||
3598 | return rc; | ||
3599 | |||
3593 | if ((rc = fsg_alloc()) != 0) | 3600 | if ((rc = fsg_alloc()) != 0) |
3594 | return rc; | 3601 | return rc; |
3595 | fsg = the_fsg; | 3602 | fsg = the_fsg; |
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 3ea70d8549ef..9fd379998608 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c | |||
@@ -52,6 +52,12 @@ | |||
52 | * characters rather then a pointer to void. | 52 | * characters rather then a pointer to void. |
53 | */ | 53 | */ |
54 | 54 | ||
55 | /* | ||
56 | * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers | ||
57 | * sets the number of pipeline buffers (length of the fsg_buffhd array). | ||
58 | * The valid range of num_buffers is: num >= 2 && num <= 4. | ||
59 | */ | ||
60 | |||
55 | 61 | ||
56 | #include <linux/usb/storage.h> | 62 | #include <linux/usb/storage.h> |
57 | #include <scsi/scsi.h> | 63 | #include <scsi/scsi.h> |
@@ -264,8 +270,31 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev) | |||
264 | #define EP0_BUFSIZE 256 | 270 | #define EP0_BUFSIZE 256 |
265 | #define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ | 271 | #define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ |
266 | 272 | ||
267 | /* Number of buffers we will use. 2 is enough for double-buffering */ | 273 | #ifdef CONFIG_USB_GADGET_DEBUG_FILES |
268 | #define FSG_NUM_BUFFERS 2 | 274 | |
275 | static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; | ||
276 | module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO); | ||
277 | MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); | ||
278 | |||
279 | #else | ||
280 | |||
281 | /* | ||
282 | * Number of buffers we will use. | ||
283 | * 2 is usually enough for good buffering pipeline | ||
284 | */ | ||
285 | #define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS | ||
286 | |||
287 | #endif /* CONFIG_USB_DEBUG */ | ||
288 | |||
289 | /* check if fsg_num_buffers is within a valid range */ | ||
290 | static inline int fsg_num_buffers_validate(void) | ||
291 | { | ||
292 | if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) | ||
293 | return 0; | ||
294 | pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", | ||
295 | fsg_num_buffers, 2 ,4); | ||
296 | return -EINVAL; | ||
297 | } | ||
269 | 298 | ||
270 | /* Default size of buffer length. */ | 299 | /* Default size of buffer length. */ |
271 | #define FSG_BUFLEN ((u32)16384) | 300 | #define FSG_BUFLEN ((u32)16384) |