diff options
author | Jens Arnold <amiconn@rockbox.org> | 2008-09-14 23:38:31 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2008-09-14 23:38:31 +0000 |
commit | 36e311f68b3c332738187affad155a2851cf6934 (patch) | |
tree | 09c45718f7deeb709d83b063ef4aacd30a2b5a1d /firmware/drivers | |
parent | b1a584a1b6fbc3d16d7dbbd8f2fac857a1332f60 (diff) | |
download | rockbox-36e311f68b3c332738187affad155a2851cf6934.tar.gz rockbox-36e311f68b3c332738187affad155a2851cf6934.zip |
Implement chasing bitswap for reading. Speeds up reading single 512-byte blocks by 15..20%. * Restructure the write buffer handling a bit, making it more readable and a bit smaller. Also fixes an old corner case bug: writing data from address 0x0 (archos boot ROM dump) would have written wrong data.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18516 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/ata_mmc.c | 111 |
1 files changed, 54 insertions, 57 deletions
diff --git a/firmware/drivers/ata_mmc.c b/firmware/drivers/ata_mmc.c index da9f0d69fe..6c3f1f6775 100644 --- a/firmware/drivers/ata_mmc.c +++ b/firmware/drivers/ata_mmc.c | |||
@@ -120,13 +120,9 @@ static const unsigned char dummy[] = { | |||
120 | 120 | ||
121 | /* 2 buffers used alternatively for writing, including start token, | 121 | /* 2 buffers used alternatively for writing, including start token, |
122 | * dummy CRC and an extra byte to keep word alignment. */ | 122 | * dummy CRC and an extra byte to keep word alignment. */ |
123 | static unsigned char block_buffer[2][BLOCK_SIZE+4]; | 123 | static unsigned char write_buffer[2][BLOCK_SIZE+4]; |
124 | static int current_buffer = 0; | 124 | static int current_buffer = 0; |
125 | 125 | static const unsigned char *send_block_addr = NULL; | |
126 | /* globals for background copy and swap */ | ||
127 | static const unsigned char *bcs_src = NULL; | ||
128 | static unsigned char *bcs_dest = NULL; | ||
129 | static unsigned long bcs_len = 0; | ||
130 | 126 | ||
131 | static tCardInfo card_info[2]; | 127 | static tCardInfo card_info[2]; |
132 | #ifndef HAVE_MULTIVOLUME | 128 | #ifndef HAVE_MULTIVOLUME |
@@ -152,9 +148,10 @@ static unsigned char poll_busy(long timeout); | |||
152 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); | 148 | static int send_cmd(int cmd, unsigned long parameter, unsigned char *response); |
153 | static int receive_cxd(unsigned char *buf); | 149 | static int receive_cxd(unsigned char *buf); |
154 | static int initialize_card(int card_no); | 150 | static int initialize_card(int card_no); |
155 | static void bg_copy_swap(void); | ||
156 | static int receive_block(unsigned char *inbuf, long timeout); | 151 | static int receive_block(unsigned char *inbuf, long timeout); |
157 | static int send_block(unsigned char start_token, long timeout); | 152 | static void send_block_prepare(void); |
153 | static int send_block_send(unsigned char start_token, long timeout, | ||
154 | bool prepare_next); | ||
158 | static void mmc_tick(void); | 155 | static void mmc_tick(void); |
159 | 156 | ||
160 | /* implementation */ | 157 | /* implementation */ |
@@ -504,32 +501,11 @@ tCardInfo *mmc_card_info(int card_no) | |||
504 | return card; | 501 | return card; |
505 | } | 502 | } |
506 | 503 | ||
507 | /* Copy and swap in the background | 504 | /* Receive one block with DMA and bitswap it (chasing bitswap). */ |
508 | * If destination is NULL, use the next block buffer */ | ||
509 | static void bg_copy_swap(void) | ||
510 | { | ||
511 | if (!bcs_len) | ||
512 | return; | ||
513 | |||
514 | if (!bcs_dest) | ||
515 | { | ||
516 | current_buffer ^= 1; /* toggle buffer */ | ||
517 | bcs_dest = block_buffer[current_buffer] + 2; | ||
518 | } | ||
519 | if (bcs_src) | ||
520 | { | ||
521 | memcpy(bcs_dest, bcs_src, bcs_len); | ||
522 | bcs_src += bcs_len; | ||
523 | } | ||
524 | bitswap(bcs_dest, bcs_len); | ||
525 | bcs_dest += bcs_len; | ||
526 | bcs_len = 0; | ||
527 | } | ||
528 | |||
529 | /* Receive one block with dma, possibly swapping the previously received | ||
530 | * block in the background */ | ||
531 | static int receive_block(unsigned char *inbuf, long timeout) | 505 | static int receive_block(unsigned char *inbuf, long timeout) |
532 | { | 506 | { |
507 | unsigned long buf_end; | ||
508 | |||
533 | if (poll_byte(timeout) != DT_START_BLOCK) | 509 | if (poll_byte(timeout) != DT_START_BLOCK) |
534 | { | 510 | { |
535 | write_transfer(dummy, 1); | 511 | write_transfer(dummy, 1); |
@@ -549,14 +525,28 @@ static int receive_block(unsigned char *inbuf, long timeout) | |||
549 | CHCR0 = 0x4601; /* fixed source address, RXI1, enable */ | 525 | CHCR0 = 0x4601; /* fixed source address, RXI1, enable */ |
550 | DMAOR = 0x0001; | 526 | DMAOR = 0x0001; |
551 | SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ | 527 | SCR1 = (SCI_RE|SCI_RIE); /* kick off DMA */ |
552 | 528 | ||
553 | /* dma receives 2 bytes more than DTCR2, but the last 2 bytes are not | 529 | /* DMA receives 2 bytes more than DTCR2, but the last 2 bytes are not |
554 | * stored. The first extra byte is available from RDR1 after the DMA ends, | 530 | * stored. The first extra byte is available from RDR1 after the DMA ends, |
555 | * the second one is lost because of the SCI overrun. However, this | 531 | * the second one is lost because of the SCI overrun. However, this |
556 | * behaviour conveniently discards the crc. */ | 532 | * behaviour conveniently discards the crc. */ |
557 | 533 | ||
558 | bg_copy_swap(); | ||
559 | yield(); /* be nice */ | 534 | yield(); /* be nice */ |
535 | |||
536 | /* Bitswap received data, chasing the DMA pointer */ | ||
537 | buf_end = (unsigned long)inbuf + BLOCK_SIZE; | ||
538 | do | ||
539 | { | ||
540 | /* Call bitswap whenever (a multiple of) 8 bytes are | ||
541 | * available (value optimised by experimentation). */ | ||
542 | int swap_now = (DAR0 - (unsigned long)inbuf) & ~0x00000007; | ||
543 | if (swap_now) | ||
544 | { | ||
545 | bitswap(inbuf, swap_now); | ||
546 | inbuf += swap_now; | ||
547 | } | ||
548 | } | ||
549 | while ((unsigned long)inbuf < buf_end); | ||
560 | 550 | ||
561 | while (!(CHCR0 & 0x0002)); /* wait for end of DMA */ | 551 | while (!(CHCR0 & 0x0002)); /* wait for end of DMA */ |
562 | while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */ | 552 | while (!(SSR1 & SCI_ORER)); /* wait for the trailing bytes */ |
@@ -568,13 +558,29 @@ static int receive_block(unsigned char *inbuf, long timeout) | |||
568 | return 0; | 558 | return 0; |
569 | } | 559 | } |
570 | 560 | ||
571 | /* Send one block with dma from the current block buffer, possibly preparing | 561 | /* Prepare a block for sending by copying it to the next write buffer |
572 | * the next block within the next block buffer in the background. */ | 562 | * and bitswapping it. */ |
573 | static int send_block(unsigned char start_token, long timeout) | 563 | static void send_block_prepare(void) |
564 | { | ||
565 | unsigned char *dest; | ||
566 | |||
567 | current_buffer ^= 1; /* toggle buffer */ | ||
568 | dest = write_buffer[current_buffer] + 2; | ||
569 | |||
570 | memcpy(dest, send_block_addr, BLOCK_SIZE); | ||
571 | bitswap(dest, BLOCK_SIZE); | ||
572 | |||
573 | send_block_addr += BLOCK_SIZE; | ||
574 | } | ||
575 | |||
576 | /* Send one block with DMA from the current write buffer, possibly preparing | ||
577 | * the next block within the next write buffer in the background. */ | ||
578 | static int send_block_send(unsigned char start_token, long timeout, | ||
579 | bool prepare_next) | ||
574 | { | 580 | { |
575 | int rc = 0; | 581 | int rc = 0; |
576 | unsigned char *curbuf = block_buffer[current_buffer]; | 582 | unsigned char *curbuf = write_buffer[current_buffer]; |
577 | 583 | ||
578 | curbuf[1] = fliptable[(signed char)start_token]; | 584 | curbuf[1] = fliptable[(signed char)start_token]; |
579 | *(unsigned short *)(curbuf + BLOCK_SIZE + 2) = 0xFFFF; | 585 | *(unsigned short *)(curbuf + BLOCK_SIZE + 2) = 0xFFFF; |
580 | 586 | ||
@@ -592,7 +598,8 @@ static int send_block(unsigned char start_token, long timeout) | |||
592 | DMAOR = 0x0001; | 598 | DMAOR = 0x0001; |
593 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ | 599 | SCR1 = (SCI_TE|SCI_TIE); /* kick off DMA */ |
594 | 600 | ||
595 | bg_copy_swap(); | 601 | if (prepare_next) |
602 | send_block_prepare(); | ||
596 | yield(); /* be nice */ | 603 | yield(); /* be nice */ |
597 | 604 | ||
598 | while (!(CHCR0 & 0x0002)); /* wait for end of DMA */ | 605 | while (!(CHCR0 & 0x0002)); /* wait for end of DMA */ |
@@ -644,9 +651,6 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
644 | if (end_block == card->numblocks) | 651 | if (end_block == card->numblocks) |
645 | lastblock = 1; | 652 | lastblock = 1; |
646 | 653 | ||
647 | bcs_src = NULL; | ||
648 | bcs_dest = inbuf; | ||
649 | |||
650 | if (incount > 1) | 654 | if (incount > 1) |
651 | { | 655 | { |
652 | rc = send_cmd(CMD_READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, &response); | 656 | rc = send_cmd(CMD_READ_MULTIPLE_BLOCK, start * BLOCK_SIZE, &response); |
@@ -664,9 +668,8 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
664 | rc = rc * 10 - 4; | 668 | rc = rc * 10 - 4; |
665 | goto error; | 669 | goto error; |
666 | } | 670 | } |
667 | bcs_len = BLOCK_SIZE; | ||
668 | inbuf += BLOCK_SIZE; | 671 | inbuf += BLOCK_SIZE; |
669 | start++; | 672 | start++; |
670 | /* ^^ necessary for the abovementioned last block special case */ | 673 | /* ^^ necessary for the abovementioned last block special case */ |
671 | } | 674 | } |
672 | rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); | 675 | rc = send_cmd(CMD_STOP_TRANSMISSION, 0, &response); |
@@ -691,9 +694,7 @@ int ata_read_sectors(IF_MV2(int drive,) | |||
691 | rc = rc * 10 - 7; | 694 | rc = rc * 10 - 7; |
692 | goto error; | 695 | goto error; |
693 | } | 696 | } |
694 | bcs_len = BLOCK_SIZE; | ||
695 | } | 697 | } |
696 | bg_copy_swap(); | ||
697 | 698 | ||
698 | error: | 699 | error: |
699 | 700 | ||
@@ -727,10 +728,8 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
727 | if (start + count > card->numblocks) | 728 | if (start + count > card->numblocks) |
728 | panicf("Writing past end of card"); | 729 | panicf("Writing past end of card"); |
729 | 730 | ||
730 | bcs_src = buf; | 731 | send_block_addr = buf; |
731 | bcs_dest = NULL; /* next block buffer */ | 732 | send_block_prepare(); |
732 | bcs_len = BLOCK_SIZE; | ||
733 | bg_copy_swap(); | ||
734 | 733 | ||
735 | if (count > 1) | 734 | if (count > 1) |
736 | { | 735 | { |
@@ -752,16 +751,14 @@ int ata_write_sectors(IF_MV2(int drive,) | |||
752 | 751 | ||
753 | while (--count > 0) | 752 | while (--count > 0) |
754 | { | 753 | { |
755 | bcs_dest = NULL; /* next block cache */ | 754 | rc = send_block_send(start_token, card->write_timeout, true); |
756 | bcs_len = BLOCK_SIZE; | ||
757 | rc = send_block(start_token, card->write_timeout); | ||
758 | if (rc) | 755 | if (rc) |
759 | { | 756 | { |
760 | rc = rc * 10 - 3; | 757 | rc = rc * 10 - 3; |
761 | goto error; | 758 | goto error; |
762 | } | 759 | } |
763 | } | 760 | } |
764 | rc = send_block(start_token, card->write_timeout); | 761 | rc = send_block_send(start_token, card->write_timeout, false); |
765 | if (rc) | 762 | if (rc) |
766 | { | 763 | { |
767 | rc = rc * 10 - 4; | 764 | rc = rc * 10 - 4; |