diff options
Diffstat (limited to 'drivers/block/mg_disk.c')
-rw-r--r-- | drivers/block/mg_disk.c | 101 |
1 files changed, 56 insertions, 45 deletions
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index f703f5478246..6d7fbaa92248 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c | |||
@@ -36,7 +36,6 @@ | |||
36 | 36 | ||
37 | /* Register offsets */ | 37 | /* Register offsets */ |
38 | #define MG_BUFF_OFFSET 0x8000 | 38 | #define MG_BUFF_OFFSET 0x8000 |
39 | #define MG_STORAGE_BUFFER_SIZE 0x200 | ||
40 | #define MG_REG_OFFSET 0xC000 | 39 | #define MG_REG_OFFSET 0xC000 |
41 | #define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */ | 40 | #define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */ |
42 | #define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */ | 41 | #define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */ |
@@ -219,6 +218,16 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) | |||
219 | host->error = MG_ERR_NONE; | 218 | host->error = MG_ERR_NONE; |
220 | expire = jiffies + msecs_to_jiffies(msec); | 219 | expire = jiffies + msecs_to_jiffies(msec); |
221 | 220 | ||
221 | /* These 2 times dummy status read prevents reading invalid | ||
222 | * status. A very little time (3 times of mflash operating clk) | ||
223 | * is required for busy bit is set. Use dummy read instead of | ||
224 | * busy wait, because mflash's PLL is machine dependent. | ||
225 | */ | ||
226 | if (prv_data->use_polling) { | ||
227 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); | ||
228 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); | ||
229 | } | ||
230 | |||
222 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); | 231 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); |
223 | 232 | ||
224 | do { | 233 | do { |
@@ -245,8 +254,6 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec) | |||
245 | mg_dump_status("not ready", status, host); | 254 | mg_dump_status("not ready", status, host); |
246 | return MG_ERR_INV_STAT; | 255 | return MG_ERR_INV_STAT; |
247 | } | 256 | } |
248 | if (prv_data->use_polling) | ||
249 | msleep(1); | ||
250 | 257 | ||
251 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); | 258 | status = inb((unsigned long)host->dev_base + MG_REG_STATUS); |
252 | } while (time_before(cur_jiffies, expire)); | 259 | } while (time_before(cur_jiffies, expire)); |
@@ -469,9 +476,18 @@ static unsigned int mg_out(struct mg_host *host, | |||
469 | return MG_ERR_NONE; | 476 | return MG_ERR_NONE; |
470 | } | 477 | } |
471 | 478 | ||
479 | static void mg_read_one(struct mg_host *host, struct request *req) | ||
480 | { | ||
481 | u16 *buff = (u16 *)req->buffer; | ||
482 | u32 i; | ||
483 | |||
484 | for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) | ||
485 | *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + | ||
486 | (i << 1)); | ||
487 | } | ||
488 | |||
472 | static void mg_read(struct request *req) | 489 | static void mg_read(struct request *req) |
473 | { | 490 | { |
474 | u32 j; | ||
475 | struct mg_host *host = req->rq_disk->private_data; | 491 | struct mg_host *host = req->rq_disk->private_data; |
476 | 492 | ||
477 | if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), | 493 | if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), |
@@ -482,49 +498,65 @@ static void mg_read(struct request *req) | |||
482 | blk_rq_sectors(req), blk_rq_pos(req), req->buffer); | 498 | blk_rq_sectors(req), blk_rq_pos(req), req->buffer); |
483 | 499 | ||
484 | do { | 500 | do { |
485 | u16 *buff = (u16 *)req->buffer; | ||
486 | |||
487 | if (mg_wait(host, ATA_DRQ, | 501 | if (mg_wait(host, ATA_DRQ, |
488 | MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { | 502 | MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) { |
489 | mg_bad_rw_intr(host); | 503 | mg_bad_rw_intr(host); |
490 | return; | 504 | return; |
491 | } | 505 | } |
492 | for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) | 506 | |
493 | *buff++ = inw((unsigned long)host->dev_base + | 507 | mg_read_one(host, req); |
494 | MG_BUFF_OFFSET + (j << 1)); | ||
495 | 508 | ||
496 | outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + | 509 | outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + |
497 | MG_REG_COMMAND); | 510 | MG_REG_COMMAND); |
498 | } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); | 511 | } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); |
499 | } | 512 | } |
500 | 513 | ||
514 | static void mg_write_one(struct mg_host *host, struct request *req) | ||
515 | { | ||
516 | u16 *buff = (u16 *)req->buffer; | ||
517 | u32 i; | ||
518 | |||
519 | for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) | ||
520 | outw(*buff++, (unsigned long)host->dev_base + MG_BUFF_OFFSET + | ||
521 | (i << 1)); | ||
522 | } | ||
523 | |||
501 | static void mg_write(struct request *req) | 524 | static void mg_write(struct request *req) |
502 | { | 525 | { |
503 | u32 j; | ||
504 | struct mg_host *host = req->rq_disk->private_data; | 526 | struct mg_host *host = req->rq_disk->private_data; |
527 | unsigned int rem = blk_rq_sectors(req); | ||
505 | 528 | ||
506 | if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req), | 529 | if (mg_out(host, blk_rq_pos(req), rem, |
507 | MG_CMD_WR, NULL) != MG_ERR_NONE) { | 530 | MG_CMD_WR, NULL) != MG_ERR_NONE) { |
508 | mg_bad_rw_intr(host); | 531 | mg_bad_rw_intr(host); |
509 | return; | 532 | return; |
510 | } | 533 | } |
511 | 534 | ||
512 | MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", | 535 | MG_DBG("requested %d sects (from %ld), buffer=0x%p\n", |
513 | blk_rq_sectors(req), blk_rq_pos(req), req->buffer); | 536 | rem, blk_rq_pos(req), req->buffer); |
537 | |||
538 | if (mg_wait(host, ATA_DRQ, | ||
539 | MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { | ||
540 | mg_bad_rw_intr(host); | ||
541 | return; | ||
542 | } | ||
514 | 543 | ||
515 | do { | 544 | do { |
516 | u16 *buff = (u16 *)req->buffer; | 545 | mg_write_one(host, req); |
517 | 546 | ||
518 | if (mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { | 547 | outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + |
548 | MG_REG_COMMAND); | ||
549 | |||
550 | rem--; | ||
551 | if (rem > 1 && mg_wait(host, ATA_DRQ, | ||
552 | MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { | ||
553 | mg_bad_rw_intr(host); | ||
554 | return; | ||
555 | } else if (mg_wait(host, MG_STAT_READY, | ||
556 | MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) { | ||
519 | mg_bad_rw_intr(host); | 557 | mg_bad_rw_intr(host); |
520 | return; | 558 | return; |
521 | } | 559 | } |
522 | for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) | ||
523 | outw(*buff++, (unsigned long)host->dev_base + | ||
524 | MG_BUFF_OFFSET + (j << 1)); | ||
525 | |||
526 | outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + | ||
527 | MG_REG_COMMAND); | ||
528 | } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); | 560 | } while (mg_end_request(host, 0, MG_SECTOR_SIZE)); |
529 | } | 561 | } |
530 | 562 | ||
@@ -532,7 +564,6 @@ static void mg_read_intr(struct mg_host *host) | |||
532 | { | 564 | { |
533 | struct request *req = host->req; | 565 | struct request *req = host->req; |
534 | u32 i; | 566 | u32 i; |
535 | u16 *buff; | ||
536 | 567 | ||
537 | /* check status */ | 568 | /* check status */ |
538 | do { | 569 | do { |
@@ -550,13 +581,7 @@ static void mg_read_intr(struct mg_host *host) | |||
550 | return; | 581 | return; |
551 | 582 | ||
552 | ok_to_read: | 583 | ok_to_read: |
553 | /* get current segment of request */ | 584 | mg_read_one(host, req); |
554 | buff = (u16 *)req->buffer; | ||
555 | |||
556 | /* read 1 sector */ | ||
557 | for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) | ||
558 | *buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET + | ||
559 | (i << 1)); | ||
560 | 585 | ||
561 | MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", | 586 | MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", |
562 | blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer); | 587 | blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer); |
@@ -575,8 +600,7 @@ ok_to_read: | |||
575 | static void mg_write_intr(struct mg_host *host) | 600 | static void mg_write_intr(struct mg_host *host) |
576 | { | 601 | { |
577 | struct request *req = host->req; | 602 | struct request *req = host->req; |
578 | u32 i, j; | 603 | u32 i; |
579 | u16 *buff; | ||
580 | bool rem; | 604 | bool rem; |
581 | 605 | ||
582 | /* check status */ | 606 | /* check status */ |
@@ -597,12 +621,7 @@ static void mg_write_intr(struct mg_host *host) | |||
597 | ok_to_write: | 621 | ok_to_write: |
598 | if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) { | 622 | if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) { |
599 | /* write 1 sector and set handler if remains */ | 623 | /* write 1 sector and set handler if remains */ |
600 | buff = (u16 *)req->buffer; | 624 | mg_write_one(host, req); |
601 | for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) { | ||
602 | outw(*buff, (unsigned long)host->dev_base + | ||
603 | MG_BUFF_OFFSET + (j << 1)); | ||
604 | buff++; | ||
605 | } | ||
606 | MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", | 625 | MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n", |
607 | blk_rq_pos(req), blk_rq_sectors(req), req->buffer); | 626 | blk_rq_pos(req), blk_rq_sectors(req), req->buffer); |
608 | host->mg_do_intr = mg_write_intr; | 627 | host->mg_do_intr = mg_write_intr; |
@@ -667,9 +686,6 @@ static unsigned int mg_issue_req(struct request *req, | |||
667 | unsigned int sect_num, | 686 | unsigned int sect_num, |
668 | unsigned int sect_cnt) | 687 | unsigned int sect_cnt) |
669 | { | 688 | { |
670 | u16 *buff; | ||
671 | u32 i; | ||
672 | |||
673 | switch (rq_data_dir(req)) { | 689 | switch (rq_data_dir(req)) { |
674 | case READ: | 690 | case READ: |
675 | if (mg_out(host, sect_num, sect_cnt, MG_CMD_RD, &mg_read_intr) | 691 | if (mg_out(host, sect_num, sect_cnt, MG_CMD_RD, &mg_read_intr) |
@@ -693,12 +709,7 @@ static unsigned int mg_issue_req(struct request *req, | |||
693 | mg_bad_rw_intr(host); | 709 | mg_bad_rw_intr(host); |
694 | return host->error; | 710 | return host->error; |
695 | } | 711 | } |
696 | buff = (u16 *)req->buffer; | 712 | mg_write_one(host, req); |
697 | for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) { | ||
698 | outw(*buff, (unsigned long)host->dev_base + | ||
699 | MG_BUFF_OFFSET + (i << 1)); | ||
700 | buff++; | ||
701 | } | ||
702 | mod_timer(&host->timer, jiffies + 3 * HZ); | 713 | mod_timer(&host->timer, jiffies + 3 * HZ); |
703 | outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + | 714 | outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + |
704 | MG_REG_COMMAND); | 715 | MG_REG_COMMAND); |