Index: firmware/usbstack/usb_storage.c =================================================================== --- firmware/usbstack/usb_storage.c (Revision 19224) +++ firmware/usbstack/usb_storage.c (Arbeitskopie) @@ -39,9 +39,11 @@ * by not overlapping storage_write_sector() with USB transfers. This does reduce * write performance, so we only do it for the affected DAPs */ +/* Disabled by FS#8663 patch as we want a solution which doesn't need this. #if (CONFIG_STORAGE & STORAGE_SD) #define SERIALIZE_WRITES #endif +*/ /* Enable the following define to export only the SD card slot. This * is useful for USBCV MSC tests, as those are destructive. * This won't work right if the device doesn't have a card slot. Index: firmware/target/arm/ata-sd-pp.c =================================================================== --- firmware/target/arm/ata-sd-pp.c (Revision 19224) +++ firmware/target/arm/ata-sd-pp.c (Arbeitskopie) @@ -54,6 +54,7 @@ #define DATA_REG (*(volatile unsigned int *)(0x70008280)) /* STATUS_REG bits */ +#define DATA_TRAN_DONE (1 << 11) #define DATA_DONE (1 << 12) #define CMD_DONE (1 << 13) #define ERROR_BITS (0x3f) @@ -423,15 +424,46 @@ /* Writes have to be kept slow for now */ static inline void copy_write_sectors(const unsigned char** buf) { - int cnt = FIFO_LEN; + int cnt = FIFO_LEN - 1; unsigned t; + long time; - do + time = USEC_TIMER + 3; + if (((intptr_t)*buf & 3) == 0) { + asm volatile ( + "ldmia %[buf]!, { r3, r5, r7, r9 } \r\n" + "mov r4, r3, lsr #16 \r\n" + "mov r6, r5, lsr #16 \r\n" + "mov r8, r7, lsr #16 \r\n" + "mov r10, r9, lsr #16 \r\n" + "stmia %[data], { r3-r10 } \r\n" + "ldmia %[buf]!, { r3, r5, r7, r9 } \r\n" + "mov r4, r3, lsr #16 \r\n" + "mov r6, r5, lsr #16 \r\n" + "mov r8, r7, lsr #16 \r\n" + "mov %[t], r9, lsr #16 \r\n" + "stmia %[data], { r3-r9 } \r\n" + : [buf]"+&r"(*buf), [t]"=&r"(t) + : [data]"r"(&DATA_REG) + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10" + ); + } + else + { + do + { + t = *(*buf)++; + t |= *(*buf)++ << 8; + DATA_REG = t; + } while (--cnt > 0); /* tail loop is faster */ t = *(*buf)++; t |= *(*buf)++ << 8; - DATA_REG = t; - } while (--cnt > 0); /* tail loop is faster */ + } + /* Don't write the last word before at least 3 usec have elapsed since FIFO_EMPTY */ + /* This prevents the 'two bytes inserted' bug. */ + while (!TIME_AFTER(USEC_TIMER, time)); + DATA_REG = t; } static int sd_select_bank(unsigned char bank) @@ -932,6 +964,13 @@ buf_end = outbuf + count * currcard->block_size - 2*FIFO_LEN; + /* Set SD_STATE_REG to SD_RCV because the card is in RCV state after WRITE_MULTIPLE_BLOCK. */ + /* This reliably prevents the 'two bytes inserted' bug in cases where the FIFO loop */ + /* was running too slow (USB). Though, the bug is still there if the loop runs too fast. */ + /* We have to take care that the last word isn't written too early in copy_write_sectors. */ + + SD_STATE_REG = SD_RCV; + for (buf = outbuf; buf <= buf_end;) { if (buf == buf_end) @@ -940,13 +979,12 @@ SD_STATE_REG = SD_PRG; } - udelay(2); /* needed here (loop is too fast :-) */ - /* Wait for the FIFO to empty */ if (sd_poll_status(FIFO_EMPTY, 0x80000)) { copy_write_sectors(&buf); /* Copy one chunk of 16 words */ /* TODO: Switch bank if necessary */ + continue; } @@ -956,6 +994,14 @@ last_disk_activity = current_tick; + /* When using SD_STATE_REG = SD_RCV we have to wait for DATA_TRAN_DONE here. */ + /* Without this, the last sector was not written sometimes. */ + if (!sd_poll_status(DATA_TRAN_DONE, 0x80000)) + { + ret = -EC_FIFO_WR_DONE; + goto sd_write_error; + } + if (!sd_poll_status(DATA_DONE, 0x80000)) { ret = -EC_FIFO_WR_DONE;