diff options
| author | Frank Gevaerts <frank@gevaerts.be> | 2009-03-29 19:56:21 +0000 |
|---|---|---|
| committer | Frank Gevaerts <frank@gevaerts.be> | 2009-03-29 19:56:21 +0000 |
| commit | 0ece30a72612bbb8267390bce93076a398c8095f (patch) | |
| tree | 2b64d817fed5f37ea4f8c53658d263e6a67bedd8 | |
| parent | d1af8f879a5ee354bd6360b2669674dfce7cdb37 (diff) | |
| download | rockbox-0ece30a72612bbb8267390bce93076a398c8095f.zip rockbox-0ece30a72612bbb8267390bce93076a398c8095f.tar.gz rockbox-0ece30a72612bbb8267390bce93076a398c8095f.tar.bz2 rockbox-0ece30a72612bbb8267390bce93076a398c8095f.tar.xz | |
Commit FS#10015 - Use chained transfer descriptor to speed up USB transfers on PP and iMX31
(not exactly the same. This one actually works)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20570 a1c6a512-1295-4272-9138-f99709370657
| -rw-r--r-- | firmware/target/arm/usb-drv-arc.c | 53 | ||||
| -rw-r--r-- | firmware/usbstack/usb_storage.c | 9 |
2 files changed, 36 insertions, 26 deletions
diff --git a/firmware/target/arm/usb-drv-arc.c b/firmware/target/arm/usb-drv-arc.c index 7fd00af..8e4eab6 100644 --- a/firmware/target/arm/usb-drv-arc.c +++ b/firmware/target/arm/usb-drv-arc.c @@ -308,6 +308,10 @@ #define DTD_RESERVED_PIPE_OFFSET 20 /*-------------------------------------------------------------------------*/ +/* 4 transfer descriptors per endpoint allow 64k transfers, which is the usual MSC + transfer size, so it seems like a good size */ +#define NUM_TDS_PER_EP 4 + /* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */ struct transfer_descriptor { unsigned int next_td_ptr; /* Next TD pointer(31-5), T(0) set @@ -322,7 +326,7 @@ struct transfer_descriptor { unsigned int reserved; } __attribute__ ((packed)); -static struct transfer_descriptor td_array[USB_NUM_ENDPOINTS*2] +static struct transfer_descriptor td_array[USB_NUM_ENDPOINTS*2*NUM_TDS_PER_EP] USB_DEVBSS_ATTR __attribute__((aligned(32))); /* manual: 32.13.1 Endpoint Queue Head (dQH) */ @@ -665,7 +669,7 @@ static int prime_transfer(int endpoint, void* ptr, int len, bool send, bool wait unsigned int mask = pipe2mask[pipe]; struct queue_head* qh = &qh_array[pipe]; static long last_tick; - struct transfer_descriptor* new_td; + struct transfer_descriptor* new_td,*cur_td,*prev_td; int oldlevel = disable_irq_save(); /* @@ -674,11 +678,23 @@ static int prime_transfer(int endpoint, void* ptr, int len, bool send, bool wait } */ qh->status = 0; - qh->length = 0; qh->wait = wait; - new_td=&td_array[pipe]; - prepare_td(new_td, 0, ptr, len,pipe); + new_td=&td_array[pipe*NUM_TDS_PER_EP]; + cur_td=new_td; + prev_td=0; + int tdlen; + + do + { + tdlen=MIN(len,16384); + prepare_td(cur_td, prev_td, ptr, tdlen,pipe); + ptr+=tdlen; + prev_td=cur_td; + cur_td++; + len-=tdlen; + } + while(len>0 ); //logf("starting ep %d %s",endpoint,send?"send":"receive"); qh->dtd.next_td_ptr = (unsigned int)new_td; @@ -807,6 +823,7 @@ static void prepare_td(struct transfer_descriptor* td, if (previous_td != 0) { previous_td->next_td_ptr=(unsigned int)td; + previous_td->size_ioc_sts&=~DTD_IOC; } } @@ -845,27 +862,19 @@ static void transfer_completed(void) int pipe = ep * 2 + dir; if (mask & pipe2mask[pipe]) { struct queue_head* qh = &qh_array[pipe]; - struct transfer_descriptor *td = &td_array[pipe]; - - if(td->size_ioc_sts & DTD_STATUS_ACTIVE) { - /* TODO this shouldn't happen, but...*/ - break; - } - if((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS != 0 && dir==0) { - /* We got less data than we asked for. */ - } - qh->length = (td->reserved & DTD_RESERVED_LENGTH_MASK) - - ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS); - if(td->size_ioc_sts & DTD_ERROR_MASK) { - logf("pipe %d err %x", pipe, td->size_ioc_sts & DTD_ERROR_MASK); - qh->status |= td->size_ioc_sts & DTD_ERROR_MASK; - /* TODO we need to handle this somehow. Flush the endpoint ? */ - } if(qh->wait) { qh->wait=0; wakeup_signal(&transfer_completion_signal[pipe]); } - usb_core_transfer_complete(ep, dir?USB_DIR_IN:USB_DIR_OUT, qh->status, qh->length); + int length=0; + struct transfer_descriptor* td=&td_array[pipe*NUM_TDS_PER_EP]; + while(td!=DTD_NEXT_TERMINATE && td!=0) + { + length += ((td->reserved & DTD_RESERVED_LENGTH_MASK) - + ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS)); + td=(struct transfer_descriptor*) td->next_td_ptr; + } + usb_core_transfer_complete(ep, dir?USB_DIR_IN:USB_DIR_OUT, qh->status, length); } } } diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index ca9f150..195a7c3 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c @@ -46,11 +46,12 @@ #define SECTOR_SIZE 512 -/* We can currently use up to 20k buffer size. More than that requires - * transfer chaining in the driver. Tests on sansa c200 show that the 16k - * limitation causes no more than 2% slowdown. +/* the ARC driver currently supports up to 64k USB transfers. This is + * enough for efficient mass storage support, as commonly host OSes + * don't do larger SCSI transfers anyway, so larger USB transfers + * wouldn't buy us anything. */ -#define BUFFER_SIZE 16384 +#define BUFFER_SIZE 65536 /* bulk-only class specific requests */ #define USB_BULK_RESET_REQUEST 0xff |