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/f_mass_storage.c | |
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/f_mass_storage.c')
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 29 |
1 files changed, 21 insertions, 8 deletions
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 | } |