aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/lpddr
diff options
context:
space:
mode:
authorStefani Seibold <stefani@seibold.net>2010-04-18 16:46:44 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-05-10 09:22:30 -0400
commitc4e773764cead9358fd4b036d1b883fff3968513 (patch)
treeceb30e53d7ba33a071653c2bc05c06293d84575f /drivers/mtd/lpddr
parent67026418f534045525a7c39f506006cd7fbd197f (diff)
mtd: fix a huge latency problem in the MTD CFI and LPDDR flash drivers.
The use of a memcpy() during a spinlock operation will cause very long thread context switch delays if the flash chip bandwidth is low and the data to be copied large, because a spinlock will disable preemption. For example: A flash with 6,5 MB/s bandwidth will cause under ubifs, which request sometimes 128 KiB (the flash erase size), a preemption delay of 20 milliseconds. High priority threads will not be served during this time, regardless whether this threads access the flash or not. This behavior breaks real time. The patch changes all the use of spin_lock operations for xxxx->mutex into mutex operations, which is exact what the name says and means. I have checked the code of the drivers and there is no use of atomic pathes like interrupt or timers. The mtdoops facility will also not be used by this drivers. So it is dave to replace the spin_lock against mutex. There is no performance regression since the mutex is normally not acquired. Changelog: 06.03.2010 First release 26.03.2010 Fix mutex[1] issue and tested it for compile failure Signed-off-by: Stefani Seibold <stefani@seibold.net> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/lpddr')
-rw-r--r--drivers/mtd/lpddr/lpddr_cmds.c79
1 files changed, 39 insertions, 40 deletions
diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c
index e22ca49583e7..eb6f437ca9ec 100644
--- a/drivers/mtd/lpddr/lpddr_cmds.c
+++ b/drivers/mtd/lpddr/lpddr_cmds.c
@@ -106,8 +106,7 @@ struct mtd_info *lpddr_cmdset(struct map_info *map)
106 /* those should be reset too since 106 /* those should be reset too since
107 they create memory references. */ 107 they create memory references. */
108 init_waitqueue_head(&chip->wq); 108 init_waitqueue_head(&chip->wq);
109 spin_lock_init(&chip->_spinlock); 109 mutex_init(&chip->mutex);
110 chip->mutex = &chip->_spinlock;
111 chip++; 110 chip++;
112 } 111 }
113 } 112 }
@@ -143,7 +142,7 @@ static int wait_for_ready(struct map_info *map, struct flchip *chip,
143 } 142 }
144 143
145 /* OK Still waiting. Drop the lock, wait a while and retry. */ 144 /* OK Still waiting. Drop the lock, wait a while and retry. */
146 spin_unlock(chip->mutex); 145 mutex_unlock(&chip->mutex);
147 if (sleep_time >= 1000000/HZ) { 146 if (sleep_time >= 1000000/HZ) {
148 /* 147 /*
149 * Half of the normal delay still remaining 148 * Half of the normal delay still remaining
@@ -158,17 +157,17 @@ static int wait_for_ready(struct map_info *map, struct flchip *chip,
158 cond_resched(); 157 cond_resched();
159 timeo--; 158 timeo--;
160 } 159 }
161 spin_lock(chip->mutex); 160 mutex_lock(&chip->mutex);
162 161
163 while (chip->state != chip_state) { 162 while (chip->state != chip_state) {
164 /* Someone's suspended the operation: sleep */ 163 /* Someone's suspended the operation: sleep */
165 DECLARE_WAITQUEUE(wait, current); 164 DECLARE_WAITQUEUE(wait, current);
166 set_current_state(TASK_UNINTERRUPTIBLE); 165 set_current_state(TASK_UNINTERRUPTIBLE);
167 add_wait_queue(&chip->wq, &wait); 166 add_wait_queue(&chip->wq, &wait);
168 spin_unlock(chip->mutex); 167 mutex_unlock(&chip->mutex);
169 schedule(); 168 schedule();
170 remove_wait_queue(&chip->wq, &wait); 169 remove_wait_queue(&chip->wq, &wait);
171 spin_lock(chip->mutex); 170 mutex_lock(&chip->mutex);
172 } 171 }
173 if (chip->erase_suspended || chip->write_suspended) { 172 if (chip->erase_suspended || chip->write_suspended) {
174 /* Suspend has occured while sleep: reset timeout */ 173 /* Suspend has occured while sleep: reset timeout */
@@ -229,20 +228,20 @@ static int get_chip(struct map_info *map, struct flchip *chip, int mode)
229 * it'll happily send us to sleep. In any case, when 228 * it'll happily send us to sleep. In any case, when
230 * get_chip returns success we're clear to go ahead. 229 * get_chip returns success we're clear to go ahead.
231 */ 230 */
232 ret = spin_trylock(contender->mutex); 231 ret = mutex_trylock(&contender->mutex);
233 spin_unlock(&shared->lock); 232 spin_unlock(&shared->lock);
234 if (!ret) 233 if (!ret)
235 goto retry; 234 goto retry;
236 spin_unlock(chip->mutex); 235 mutex_unlock(&chip->mutex);
237 ret = chip_ready(map, contender, mode); 236 ret = chip_ready(map, contender, mode);
238 spin_lock(chip->mutex); 237 mutex_lock(&chip->mutex);
239 238
240 if (ret == -EAGAIN) { 239 if (ret == -EAGAIN) {
241 spin_unlock(contender->mutex); 240 mutex_unlock(&contender->mutex);
242 goto retry; 241 goto retry;
243 } 242 }
244 if (ret) { 243 if (ret) {
245 spin_unlock(contender->mutex); 244 mutex_unlock(&contender->mutex);
246 return ret; 245 return ret;
247 } 246 }
248 spin_lock(&shared->lock); 247 spin_lock(&shared->lock);
@@ -251,10 +250,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, int mode)
251 * state. Put contender and retry. */ 250 * state. Put contender and retry. */
252 if (chip->state == FL_SYNCING) { 251 if (chip->state == FL_SYNCING) {
253 put_chip(map, contender); 252 put_chip(map, contender);
254 spin_unlock(contender->mutex); 253 mutex_unlock(&contender->mutex);
255 goto retry; 254 goto retry;
256 } 255 }
257 spin_unlock(contender->mutex); 256 mutex_unlock(&contender->mutex);
258 } 257 }
259 258
260 /* Check if we have suspended erase on this chip. 259 /* Check if we have suspended erase on this chip.
@@ -264,10 +263,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, int mode)
264 spin_unlock(&shared->lock); 263 spin_unlock(&shared->lock);
265 set_current_state(TASK_UNINTERRUPTIBLE); 264 set_current_state(TASK_UNINTERRUPTIBLE);
266 add_wait_queue(&chip->wq, &wait); 265 add_wait_queue(&chip->wq, &wait);
267 spin_unlock(chip->mutex); 266 mutex_unlock(&chip->mutex);
268 schedule(); 267 schedule();
269 remove_wait_queue(&chip->wq, &wait); 268 remove_wait_queue(&chip->wq, &wait);
270 spin_lock(chip->mutex); 269 mutex_lock(&chip->mutex);
271 goto retry; 270 goto retry;
272 } 271 }
273 272
@@ -336,10 +335,10 @@ static int chip_ready(struct map_info *map, struct flchip *chip, int mode)
336sleep: 335sleep:
337 set_current_state(TASK_UNINTERRUPTIBLE); 336 set_current_state(TASK_UNINTERRUPTIBLE);
338 add_wait_queue(&chip->wq, &wait); 337 add_wait_queue(&chip->wq, &wait);
339 spin_unlock(chip->mutex); 338 mutex_unlock(&chip->mutex);
340 schedule(); 339 schedule();
341 remove_wait_queue(&chip->wq, &wait); 340 remove_wait_queue(&chip->wq, &wait);
342 spin_lock(chip->mutex); 341 mutex_lock(&chip->mutex);
343 return -EAGAIN; 342 return -EAGAIN;
344 } 343 }
345} 344}
@@ -355,12 +354,12 @@ static void put_chip(struct map_info *map, struct flchip *chip)
355 if (shared->writing && shared->writing != chip) { 354 if (shared->writing && shared->writing != chip) {
356 /* give back the ownership */ 355 /* give back the ownership */
357 struct flchip *loaner = shared->writing; 356 struct flchip *loaner = shared->writing;
358 spin_lock(loaner->mutex); 357 mutex_lock(&loaner->mutex);
359 spin_unlock(&shared->lock); 358 spin_unlock(&shared->lock);
360 spin_unlock(chip->mutex); 359 mutex_unlock(&chip->mutex);
361 put_chip(map, loaner); 360 put_chip(map, loaner);
362 spin_lock(chip->mutex); 361 mutex_lock(&chip->mutex);
363 spin_unlock(loaner->mutex); 362 mutex_unlock(&loaner->mutex);
364 wake_up(&chip->wq); 363 wake_up(&chip->wq);
365 return; 364 return;
366 } 365 }
@@ -413,10 +412,10 @@ int do_write_buffer(struct map_info *map, struct flchip *chip,
413 412
414 wbufsize = 1 << lpddr->qinfo->BufSizeShift; 413 wbufsize = 1 << lpddr->qinfo->BufSizeShift;
415 414
416 spin_lock(chip->mutex); 415 mutex_lock(&chip->mutex);
417 ret = get_chip(map, chip, FL_WRITING); 416 ret = get_chip(map, chip, FL_WRITING);
418 if (ret) { 417 if (ret) {
419 spin_unlock(chip->mutex); 418 mutex_unlock(&chip->mutex);
420 return ret; 419 return ret;
421 } 420 }
422 /* Figure out the number of words to write */ 421 /* Figure out the number of words to write */
@@ -477,7 +476,7 @@ int do_write_buffer(struct map_info *map, struct flchip *chip,
477 } 476 }
478 477
479 out: put_chip(map, chip); 478 out: put_chip(map, chip);
480 spin_unlock(chip->mutex); 479 mutex_unlock(&chip->mutex);
481 return ret; 480 return ret;
482} 481}
483 482
@@ -489,10 +488,10 @@ int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
489 struct flchip *chip = &lpddr->chips[chipnum]; 488 struct flchip *chip = &lpddr->chips[chipnum];
490 int ret; 489 int ret;
491 490
492 spin_lock(chip->mutex); 491 mutex_lock(&chip->mutex);
493 ret = get_chip(map, chip, FL_ERASING); 492 ret = get_chip(map, chip, FL_ERASING);
494 if (ret) { 493 if (ret) {
495 spin_unlock(chip->mutex); 494 mutex_unlock(&chip->mutex);
496 return ret; 495 return ret;
497 } 496 }
498 send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL); 497 send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL);
@@ -504,7 +503,7 @@ int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
504 goto out; 503 goto out;
505 } 504 }
506 out: put_chip(map, chip); 505 out: put_chip(map, chip);
507 spin_unlock(chip->mutex); 506 mutex_unlock(&chip->mutex);
508 return ret; 507 return ret;
509} 508}
510 509
@@ -517,10 +516,10 @@ static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
517 struct flchip *chip = &lpddr->chips[chipnum]; 516 struct flchip *chip = &lpddr->chips[chipnum];
518 int ret = 0; 517 int ret = 0;
519 518
520 spin_lock(chip->mutex); 519 mutex_lock(&chip->mutex);
521 ret = get_chip(map, chip, FL_READY); 520 ret = get_chip(map, chip, FL_READY);
522 if (ret) { 521 if (ret) {
523 spin_unlock(chip->mutex); 522 mutex_unlock(&chip->mutex);
524 return ret; 523 return ret;
525 } 524 }
526 525
@@ -528,7 +527,7 @@ static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
528 *retlen = len; 527 *retlen = len;
529 528
530 put_chip(map, chip); 529 put_chip(map, chip);
531 spin_unlock(chip->mutex); 530 mutex_unlock(&chip->mutex);
532 return ret; 531 return ret;
533} 532}
534 533
@@ -568,9 +567,9 @@ static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
568 else 567 else
569 thislen = len; 568 thislen = len;
570 /* get the chip */ 569 /* get the chip */
571 spin_lock(chip->mutex); 570 mutex_lock(&chip->mutex);
572 ret = get_chip(map, chip, FL_POINT); 571 ret = get_chip(map, chip, FL_POINT);
573 spin_unlock(chip->mutex); 572 mutex_unlock(&chip->mutex);
574 if (ret) 573 if (ret)
575 break; 574 break;
576 575
@@ -610,7 +609,7 @@ static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
610 else 609 else
611 thislen = len; 610 thislen = len;
612 611
613 spin_lock(chip->mutex); 612 mutex_lock(&chip->mutex);
614 if (chip->state == FL_POINT) { 613 if (chip->state == FL_POINT) {
615 chip->ref_point_counter--; 614 chip->ref_point_counter--;
616 if (chip->ref_point_counter == 0) 615 if (chip->ref_point_counter == 0)
@@ -620,7 +619,7 @@ static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
620 "pointed region\n", map->name); 619 "pointed region\n", map->name);
621 620
622 put_chip(map, chip); 621 put_chip(map, chip);
623 spin_unlock(chip->mutex); 622 mutex_unlock(&chip->mutex);
624 623
625 len -= thislen; 624 len -= thislen;
626 ofs = 0; 625 ofs = 0;
@@ -726,10 +725,10 @@ int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk)
726 int chipnum = adr >> lpddr->chipshift; 725 int chipnum = adr >> lpddr->chipshift;
727 struct flchip *chip = &lpddr->chips[chipnum]; 726 struct flchip *chip = &lpddr->chips[chipnum];
728 727
729 spin_lock(chip->mutex); 728 mutex_lock(&chip->mutex);
730 ret = get_chip(map, chip, FL_LOCKING); 729 ret = get_chip(map, chip, FL_LOCKING);
731 if (ret) { 730 if (ret) {
732 spin_unlock(chip->mutex); 731 mutex_unlock(&chip->mutex);
733 return ret; 732 return ret;
734 } 733 }
735 734
@@ -749,7 +748,7 @@ int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk)
749 goto out; 748 goto out;
750 } 749 }
751out: put_chip(map, chip); 750out: put_chip(map, chip);
752 spin_unlock(chip->mutex); 751 mutex_unlock(&chip->mutex);
753 return ret; 752 return ret;
754} 753}
755 754
@@ -770,10 +769,10 @@ int word_program(struct map_info *map, loff_t adr, uint32_t curval)
770 int chipnum = adr >> lpddr->chipshift; 769 int chipnum = adr >> lpddr->chipshift;
771 struct flchip *chip = &lpddr->chips[chipnum]; 770 struct flchip *chip = &lpddr->chips[chipnum];
772 771
773 spin_lock(chip->mutex); 772 mutex_lock(&chip->mutex);
774 ret = get_chip(map, chip, FL_WRITING); 773 ret = get_chip(map, chip, FL_WRITING);
775 if (ret) { 774 if (ret) {
776 spin_unlock(chip->mutex); 775 mutex_unlock(&chip->mutex);
777 return ret; 776 return ret;
778 } 777 }
779 778
@@ -787,7 +786,7 @@ int word_program(struct map_info *map, loff_t adr, uint32_t curval)
787 } 786 }
788 787
789out: put_chip(map, chip); 788out: put_chip(map, chip);
790 spin_unlock(chip->mutex); 789 mutex_unlock(&chip->mutex);
791 return ret; 790 return ret;
792} 791}
793 792