diff options
-rw-r--r-- | firmware/drivers/ata_mmc.c | 117 |
1 files changed, 63 insertions, 54 deletions
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c index 606bb0c822..9e854ce977 100644 --- a/firmware/drivers/ata_mmc.c +++ b/firmware/drivers/ata_mmc.c | |||
@@ -128,6 +128,11 @@ struct block_cache_entry { | |||
128 | static struct block_cache_entry block_cache[NUMCACHES]; | 128 | static struct block_cache_entry block_cache[NUMCACHES]; |
129 | static int current_cache = 0; | 129 | static int current_cache = 0; |
130 | 130 | ||
131 | /* globals for background copy and swap */ | ||
132 | static const unsigned char *bcs_src = NULL; | ||
133 | static unsigned char *bcs_dest = NULL; | ||
134 | static unsigned long bcs_len = 0; | ||
135 | |||
131 | static tCardInfo card_info[2]; | 136 | static tCardInfo card_info[2]; |
132 | #ifndef HAVE_MULTIVOLUME | 137 | #ifndef HAVE_MULTIVOLUME |
133 | static int current_card = 0; | 138 | static int current_card = 0; |
@@ -152,12 +157,9 @@ static unsigned char poll_busy(long timeout); | |||
152 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); | 157 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); |
153 | static int receive_cxd(unsigned char *buf); | 158 | static int receive_cxd(unsigned char *buf); |
154 | static int initialize_card(int card_no); | 159 | static int initialize_card(int card_no); |
155 | static void swapcopy(void *dst, const void *src, unsigned long size); | 160 | static void bg_copy_swap(void); |
156 | static int receive_block(unsigned char *inbuf, unsigned char *swapbuf, | 161 | static int receive_block(unsigned char *inbuf, int size, long timeout); |
157 | int size, long timeout); | 162 | static int send_block(int size, unsigned char start_token, long timeout); |
158 | static void swapcopy_block(const unsigned char *buf, int size); | ||
159 | static int send_block(const unsigned char *nextbuf, int size, | ||
160 | unsigned char start_token, long timeout); | ||
161 | static int cache_block(IF_MV2(int drive,) unsigned long blocknum, | 163 | static int cache_block(IF_MV2(int drive,) unsigned long blocknum, |
162 | int size, long timeout); | 164 | int size, long timeout); |
163 | static void mmc_tick(void); | 165 | static void mmc_tick(void); |
@@ -546,16 +548,32 @@ tCardInfo *mmc_card_info(int card_no) | |||
546 | return card; | 548 | return card; |
547 | } | 549 | } |
548 | 550 | ||
549 | static void swapcopy(void *dst, const void *src, unsigned long size) | 551 | /* copy and swap in the background. If destination is NULL, use the next |
552 | * block cache entry */ | ||
553 | static void bg_copy_swap(void) | ||
550 | { | 554 | { |
551 | memcpy(dst, src, size); | 555 | if (!bcs_len) |
552 | bitswap(dst, size); | 556 | return; |
557 | |||
558 | if (!bcs_dest) | ||
559 | { | ||
560 | current_cache = (current_cache + 1) % NUMCACHES; /* next cache */ | ||
561 | block_cache[current_cache].inuse = false; | ||
562 | bcs_dest = block_cache[current_cache].data + 2; | ||
563 | } | ||
564 | if (bcs_src) | ||
565 | { | ||
566 | memcpy(bcs_dest, bcs_src, bcs_len); | ||
567 | bcs_src += bcs_len; | ||
568 | } | ||
569 | bitswap(bcs_dest, bcs_len); | ||
570 | bcs_dest += bcs_len; | ||
571 | bcs_len = 0; | ||
553 | } | 572 | } |
554 | 573 | ||
555 | /* Receive one block with dma, possibly swapping the previously received | 574 | /* Receive one block with dma, possibly swapping the previously received |
556 | * block in the background */ | 575 | * block in the background */ |
557 | static int receive_block(unsigned char *inbuf, unsigned char *swapbuf, | 576 | static int receive_block(unsigned char *inbuf, int size, long timeout) |
558 | int size, long timeout) | ||
559 | { | 577 | { |
560 | if (poll_byte(timeout) != DT_START_BLOCK) | 578 | if (poll_byte(timeout) != DT_START_BLOCK) |
561 | { | 579 | { |
@@ -582,8 +600,7 @@ static int receive_block(unsigned char *inbuf, unsigned char *swapbuf, | |||
582 | * the second one is lost because of the SCI overrun. However, this | 600 | * the second one is lost because of the SCI overrun. However, this |
583 | * behaviour conveniently discards the crc. */ | 601 | * behaviour conveniently discards the crc. */ |
584 | 602 | ||
585 | if (swapbuf != NULL) /* bitswap previous block */ | 603 | bg_copy_swap(); |
586 | bitswap(swapbuf, size); | ||
587 | yield(); /* be nice */ | 604 | yield(); /* be nice */ |
588 | 605 | ||
589 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ | 606 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ |
@@ -592,22 +609,13 @@ static int receive_block(unsigned char *inbuf, unsigned char *swapbuf, | |||
592 | serial_mode = SER_DISABLED; | 609 | serial_mode = SER_DISABLED; |
593 | 610 | ||
594 | write_transfer(dummy, 1); /* send trailer */ | 611 | write_transfer(dummy, 1); /* send trailer */ |
612 | last_disk_activity = current_tick; | ||
595 | return 0; | 613 | return 0; |
596 | } | 614 | } |
597 | 615 | ||
598 | /* copies one block into the next-current block cache, then bitswaps */ | ||
599 | static void swapcopy_block(const unsigned char *buf, int size) | ||
600 | { | ||
601 | current_cache = (current_cache + 1) % NUMCACHES; /* next cache */ | ||
602 | |||
603 | block_cache[current_cache].inuse = false; | ||
604 | swapcopy(block_cache[current_cache].data + 2, buf, size); | ||
605 | } | ||
606 | |||
607 | /* Send one block with dma from the current block cache, possibly preparing | 616 | /* Send one block with dma from the current block cache, possibly preparing |
608 | * the next block within the next block cache in the background. */ | 617 | * the next block within the next block cache in the background. */ |
609 | static int send_block(const unsigned char *nextbuf, int size, | 618 | static int send_block(int size, unsigned char start_token, long timeout) |
610 | unsigned char start_token, long timeout) | ||
611 | { | 619 | { |
612 | int rc = 0; | 620 | int rc = 0; |
613 | unsigned char *curbuf = block_cache[current_cache].data; | 621 | unsigned char *curbuf = block_cache[current_cache].data; |
@@ -629,8 +637,7 @@ static int send_block(const unsigned char *nextbuf, int size, | |||
629 | DMAOR = 0x0001; | 637 | DMAOR = 0x0001; |
630 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ | 638 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ |
631 | 639 | ||
632 | if (nextbuf != NULL) /* prepare next sector */ | 640 | bg_copy_swap(); |
633 | swapcopy_block(nextbuf, size); | ||
634 | yield(); /* be nice */ | 641 | yield(); /* be nice */ |
635 | 642 | ||
636 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ | 643 | while (!(CHCR2 & 0x0002)); /* wait for end of DMA */ |
@@ -642,6 +649,7 @@ static int send_block(const unsigned char *nextbuf, int size, | |||
642 | rc = -1; | 649 | rc = -1; |
643 | 650 | ||
644 | write_transfer(dummy, 1); | 651 | write_transfer(dummy, 1); |
652 | last_disk_activity = current_tick; | ||
645 | 653 | ||
646 | return rc; | 654 | return rc; |
647 | } | 655 | } |
@@ -662,6 +670,7 @@ static int cache_block(IF_MV2(int drive,) unsigned long blocknum, | |||
662 | ) | 670 | ) |
663 | { | 671 | { |
664 | current_cache = i; | 672 | current_cache = i; |
673 | bg_copy_swap(); | ||
665 | return 0; | 674 | return 0; |
666 | } | 675 | } |
667 | } | 676 | } |
@@ -672,8 +681,7 @@ static int cache_block(IF_MV2(int drive,) unsigned long blocknum, | |||
672 | return rc * 10 - 1; | 681 | return rc * 10 - 1; |
673 | 682 | ||
674 | block_cache[current_cache].inuse = false; | 683 | block_cache[current_cache].inuse = false; |
675 | rc = receive_block(block_cache[current_cache].data + 2, NULL, | 684 | rc = receive_block(block_cache[current_cache].data + 2, size, timeout); |
676 | size, timeout); | ||
677 | if (rc) | 685 | if (rc) |
678 | return rc * 10 - 2; | 686 | return rc * 10 - 2; |
679 | 687 | ||
@@ -682,7 +690,6 @@ static int cache_block(IF_MV2(int drive,) unsigned long blocknum, | |||
682 | #endif | 690 | #endif |
683 | block_cache[current_cache].blocknum = blocknum; | 691 | block_cache[current_cache].blocknum = blocknum; |
684 | block_cache[current_cache].inuse = true; | 692 | block_cache[current_cache].inuse = true; |
685 | last_disk_activity = current_tick; | ||
686 | 693 | ||
687 | return 0; | 694 | return 0; |
688 | } | 695 | } |
@@ -697,7 +704,6 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
697 | unsigned long c_addr, c_end_addr; | 704 | unsigned long c_addr, c_end_addr; |
698 | unsigned long c_block, c_end_block; | 705 | unsigned long c_block, c_end_block; |
699 | unsigned char response; | 706 | unsigned char response; |
700 | void *inbuf_prev = NULL; | ||
701 | tCardInfo *card; | 707 | tCardInfo *card; |
702 | 708 | ||
703 | c_addr = start * SECTOR_SIZE; | 709 | c_addr = start * SECTOR_SIZE; |
@@ -727,6 +733,7 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
727 | offset = c_addr & (blocksize - 1); | 733 | offset = c_addr & (blocksize - 1); |
728 | c_block = c_addr >> card->block_exp; | 734 | c_block = c_addr >> card->block_exp; |
729 | c_end_block = c_end_addr >> card->block_exp; | 735 | c_end_block = c_end_addr >> card->block_exp; |
736 | bcs_dest = inbuf; | ||
730 | 737 | ||
731 | if (offset) /* first partial block */ | 738 | if (offset) /* first partial block */ |
732 | { | 739 | { |
@@ -738,8 +745,9 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
738 | { | 745 | { |
739 | rc = rc * 10 - 3; | 746 | rc = rc * 10 - 3; |
740 | goto error; | 747 | goto error; |
741 | } | 748 | } |
742 | swapcopy(inbuf, block_cache[current_cache].data + 2 + offset, len); | 749 | bcs_src = block_cache[current_cache].data + 2 + offset; |
750 | bcs_len = len; | ||
743 | inbuf += len; | 751 | inbuf += len; |
744 | c_addr += len; | 752 | c_addr += len; |
745 | c_block++; | 753 | c_block++; |
@@ -764,15 +772,14 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
764 | } | 772 | } |
765 | while (c_block < c_end_block) | 773 | while (c_block < c_end_block) |
766 | { | 774 | { |
767 | rc = receive_block(inbuf, inbuf_prev, blocksize, | 775 | rc = receive_block(inbuf, blocksize, card->read_timeout); |
768 | card->read_timeout); | ||
769 | if (rc) | 776 | if (rc) |
770 | { | 777 | { |
771 | rc = rc * 10 - 5; | 778 | rc = rc * 10 - 5; |
772 | goto error; | 779 | goto error; |
773 | } | 780 | } |
774 | last_disk_activity = current_tick; | 781 | bcs_src = NULL; |
775 | inbuf_prev = inbuf; | 782 | bcs_len = blocksize; |
776 | inbuf += blocksize; | 783 | inbuf += blocksize; |
777 | c_addr += blocksize; | 784 | c_addr += blocksize; |
778 | c_block++; | 785 | c_block++; |
@@ -786,7 +793,6 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
786 | goto error; | 793 | goto error; |
787 | } | 794 | } |
788 | } | 795 | } |
789 | bitswap(inbuf_prev, blocksize); | ||
790 | } | 796 | } |
791 | if (c_addr < c_end_addr) /* last partial block */ | 797 | if (c_addr < c_end_addr) /* last partial block */ |
792 | { | 798 | { |
@@ -796,10 +802,11 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
796 | { | 802 | { |
797 | rc = rc * 10 - 7; | 803 | rc = rc * 10 - 7; |
798 | goto error; | 804 | goto error; |
799 | } | 805 | } |
800 | swapcopy(inbuf, block_cache[current_cache].data + 2, | 806 | bcs_src = block_cache[current_cache].data + 2; |
801 | c_end_addr - c_addr); | 807 | bcs_len = c_end_addr - c_addr; |
802 | } | 808 | } |
809 | bg_copy_swap(); | ||
803 | 810 | ||
804 | error: | 811 | error: |
805 | 812 | ||
@@ -854,6 +861,7 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
854 | offset = c_addr & (blocksize - 1); | 861 | offset = c_addr & (blocksize - 1); |
855 | c_block = c_addr >> card->block_exp; | 862 | c_block = c_addr >> card->block_exp; |
856 | c_end_block = c_end_addr >> card->block_exp; | 863 | c_end_block = c_end_addr >> card->block_exp; |
864 | bcs_src = buf; | ||
857 | 865 | ||
858 | /* Special case: first block is trimmed at both ends. May only happen | 866 | /* Special case: first block is trimmed at both ends. May only happen |
859 | * if (blocksize > 2 * sectorsize), i.e. blocksize == 2048 */ | 867 | * if (blocksize > 2 * sectorsize), i.e. blocksize == 2048 */ |
@@ -875,27 +883,28 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
875 | write_cmd = CMD_WRITE_BLOCK; | 883 | write_cmd = CMD_WRITE_BLOCK; |
876 | start_token = DT_START_BLOCK; | 884 | start_token = DT_START_BLOCK; |
877 | } | 885 | } |
878 | 886 | ||
879 | if (offset) | 887 | if (offset) |
880 | { | 888 | { |
881 | unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset); | 889 | unsigned long len = MIN(c_end_addr - c_addr, blocksize - offset); |
882 | 890 | ||
883 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, | 891 | rc = cache_block(IF_MV2(drive,) c_block, blocksize, |
884 | card->read_timeout); | 892 | card->read_timeout); |
885 | if (rc) | 893 | if (rc) |
886 | { | 894 | { |
887 | rc = rc * 10 - 2; | 895 | rc = rc * 10 - 2; |
888 | goto error; | 896 | goto error; |
889 | } | 897 | } |
890 | swapcopy(block_cache[current_cache].data + 2 + offset, buf, len); | 898 | bcs_dest = block_cache[current_cache].data + 2 + offset; |
891 | buf += len; | 899 | bcs_len = len; |
892 | c_addr -= offset; | 900 | c_addr -= offset; |
893 | } | 901 | } |
894 | else | 902 | else |
895 | { | 903 | { |
896 | swapcopy_block(buf, blocksize); | 904 | bcs_dest = NULL; /* next block cache */ |
897 | buf += blocksize; | 905 | bcs_len = blocksize; |
898 | } | 906 | } |
907 | bg_copy_swap(); | ||
899 | rc = send_cmd(write_cmd, c_addr, &response); | 908 | rc = send_cmd(write_cmd, c_addr, &response); |
900 | if (rc) | 909 | if (rc) |
901 | { | 910 | { |
@@ -906,24 +915,23 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
906 | 915 | ||
907 | while (c_block < c_end_block) | 916 | while (c_block < c_end_block) |
908 | { | 917 | { |
909 | rc = send_block(buf, blocksize, start_token, card->write_timeout); | 918 | bcs_dest = NULL; /* next block cache */ |
919 | bcs_len = blocksize; | ||
920 | rc = send_block(blocksize, start_token, card->write_timeout); | ||
910 | if (rc) | 921 | if (rc) |
911 | { | 922 | { |
912 | rc = rc * 10 - 4; | 923 | rc = rc * 10 - 4; |
913 | goto error; | 924 | goto error; |
914 | } | 925 | } |
915 | last_disk_activity = current_tick; | ||
916 | buf += blocksize; | ||
917 | c_addr += blocksize; | 926 | c_addr += blocksize; |
918 | c_block++; | 927 | c_block++; |
919 | } | 928 | } |
920 | rc = send_block(NULL, blocksize, start_token, card->write_timeout); | 929 | rc = send_block(blocksize, start_token, card->write_timeout); |
921 | if (rc) | 930 | if (rc) |
922 | { | 931 | { |
923 | rc = rc * 10 - 5; | 932 | rc = rc * 10 - 5; |
924 | goto error; | 933 | goto error; |
925 | } | 934 | } |
926 | last_disk_activity = current_tick; | ||
927 | c_addr += blocksize; | 935 | c_addr += blocksize; |
928 | /* c_block++ was done early */ | 936 | /* c_block++ was done early */ |
929 | 937 | ||
@@ -944,15 +952,16 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
944 | rc = rc * 10 - 6; | 952 | rc = rc * 10 - 6; |
945 | goto error; | 953 | goto error; |
946 | } | 954 | } |
947 | swapcopy(block_cache[current_cache].data + 2, buf, | 955 | bcs_dest = block_cache[current_cache].data + 2; |
948 | c_end_addr - c_addr); | 956 | bcs_len = c_end_addr - c_addr; |
957 | bg_copy_swap(); | ||
949 | rc = send_cmd(CMD_WRITE_BLOCK, c_addr, &response); | 958 | rc = send_cmd(CMD_WRITE_BLOCK, c_addr, &response); |
950 | if (rc) | 959 | if (rc) |
951 | { | 960 | { |
952 | rc = rc * 10 - 7; | 961 | rc = rc * 10 - 7; |
953 | goto error; | 962 | goto error; |
954 | } | 963 | } |
955 | rc = send_block(NULL, blocksize, DT_START_BLOCK, card->write_timeout); | 964 | rc = send_block(blocksize, DT_START_BLOCK, card->write_timeout); |
956 | if (rc) | 965 | if (rc) |
957 | { | 966 | { |
958 | rc = rc * 10 - 8; | 967 | rc = rc * 10 - 8; |