summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/drivers/ata_mmc.c117
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 {
128static struct block_cache_entry block_cache[NUMCACHES]; 128static struct block_cache_entry block_cache[NUMCACHES];
129static int current_cache = 0; 129static int current_cache = 0;
130 130
131/* globals for background copy and swap */
132static const unsigned char *bcs_src = NULL;
133static unsigned char *bcs_dest = NULL;
134static unsigned long bcs_len = 0;
135
131static tCardInfo card_info[2]; 136static tCardInfo card_info[2];
132#ifndef HAVE_MULTIVOLUME 137#ifndef HAVE_MULTIVOLUME
133static int current_card = 0; 138static int current_card = 0;
@@ -152,12 +157,9 @@ static unsigned char poll_busy(long timeout);
152static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); 157static int send_cmd(int cmd, unsigned long parameter, unsigned char *response);
153static int receive_cxd(unsigned char *buf); 158static int receive_cxd(unsigned char *buf);
154static int initialize_card(int card_no); 159static int initialize_card(int card_no);
155static void swapcopy(void *dst, const void *src, unsigned long size); 160static void bg_copy_swap(void);
156static int receive_block(unsigned char *inbuf, unsigned char *swapbuf, 161static int receive_block(unsigned char *inbuf, int size, long timeout);
157 int size, long timeout); 162static int send_block(int size, unsigned char start_token, long timeout);
158static void swapcopy_block(const unsigned char *buf, int size);
159static int send_block(const unsigned char *nextbuf, int size,
160 unsigned char start_token, long timeout);
161static int cache_block(IF_MV2(int drive,) unsigned long blocknum, 163static int cache_block(IF_MV2(int drive,) unsigned long blocknum,
162 int size, long timeout); 164 int size, long timeout);
163static void mmc_tick(void); 165static 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
549static 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 */
553static 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 */
557static int receive_block(unsigned char *inbuf, unsigned char *swapbuf, 576static 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 */
599static 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. */
609static int send_block(const unsigned char *nextbuf, int size, 618static 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;