ChangeSet 1.1504.2.12, 2003/12/08 17:44:31-08:00, [EMAIL PROTECTED] [PATCH] USB storage: Remove unneeded scatter-gather operations in sddr09
This patch removes some unnecessary scatter-gather code from the sddr09 driver. In its place a single smaller buffer is re-used each time through an I/O loop, as opposed to transferring all the data at once. Andries Brouwer kindly tested this and suggested some improvements to get it working right. drivers/usb/storage/sddr09.c | 112 ++++++++++++++++--------------------------- 1 files changed, 42 insertions(+), 70 deletions(-) diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c --- a/drivers/usb/storage/sddr09.c Mon Dec 29 14:25:42 2003 +++ b/drivers/usb/storage/sddr09.c Mon Dec 29 14:25:42 2003 @@ -1092,69 +1092,33 @@ static int sddr09_read_map(struct us_data *us) { - struct scatterlist *sg; struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; int numblocks, alloc_len, alloc_blocks; int i, j, result; - unsigned char *ptr; + unsigned char *buffer, *buffer_end, *ptr; unsigned int lba, lbact; if (!info->capacity) return -1; - // read 64 (1<<6) bytes for every block - // ( 1 << ( blockshift + pageshift ) bytes) - // of capacity: - // (1<<6)*capacity/(1<<(b+p)) = - // ((1<<6)*capacity)>>(b+p) = - // capacity>>(b+p-6) - - alloc_len = info->capacity >> - (info->blockshift + info->pageshift - CONTROL_SHIFT); - - // Allocate a number of scatterlist structures according to - // the number of 128k blocks in the alloc_len. Adding 128k-1 - // and then dividing by 128k gives the correct number of blocks. - // 128k = 1<<17 - - alloc_blocks = (alloc_len + (1<<17) - 1) >> 17; - sg = kmalloc(alloc_blocks*sizeof(struct scatterlist), - GFP_NOIO); - if (sg == NULL) - return 0; - - for (i=0; i<alloc_blocks; i++) { - int alloc_req = (i < alloc_blocks-1 ? 1 << 17 : alloc_len); - char *vaddr = kmalloc(alloc_req, GFP_NOIO); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3) - sg[i].page = virt_to_page(vaddr); - sg[i].offset = offset_in_page(vaddr); -#else - sg[i].address = vaddr; -#endif - sg[i].length = alloc_req; - alloc_len -= alloc_req; - } - - for (i=0; i<alloc_blocks; i++) - if (sg[i].page == NULL) { - for (i=0; i<alloc_blocks; i++) - if (sg[i].page != NULL) - kfree(sg_address(sg[i])); - kfree(sg); - return 0; - } + // size of a block is 1 << (blockshift + pageshift) bytes + // divide into the total capacity to get the number of blocks numblocks = info->capacity >> (info->blockshift + info->pageshift); - result = sddr09_read_control(us, 0, numblocks, - (unsigned char *)sg, alloc_blocks); - if (result != USB_STOR_TRANSPORT_GOOD) { - for (i=0; i<alloc_blocks; i++) - kfree(sg_address(sg[i])); - kfree(sg); - return -1; - } + // read 64 bytes for every block (actually 1 << CONTROL_SHIFT) + // but only use a 64 KB buffer + // buffer size used must be a multiple of (1 << CONTROL_SHIFT) +#define SDDR09_READ_MAP_BUFSZ 65536 + + alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT); + alloc_len = (alloc_blocks << CONTROL_SHIFT); + buffer = kmalloc(alloc_len, GFP_NOIO); + if (buffer == NULL) + return 0; + buffer_end = buffer + alloc_len; + +#undef SDDR09_READ_MAP_BUFSZ kfree(info->lba_to_pba); kfree(info->pba_to_lba); @@ -1162,29 +1126,31 @@ info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { - kfree(info->lba_to_pba); - kfree(info->pba_to_lba); - info->lba_to_pba = NULL; - info->pba_to_lba = NULL; - for (i=0; i<alloc_blocks; i++) - kfree(sg_address(sg[i])); - kfree(sg); - return 0; + result = -1; + goto done; } for (i = 0; i < numblocks; i++) info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF; - ptr = sg_address(sg[0]); - /* * Define lba-pba translation table */ - // Each block is 64 bytes of control data, so block i is located in - // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11) - for (i=0; i<numblocks; i++) { - ptr = sg_address(sg[i>>11]) + ((i&0x7ff)<<6); + ptr = buffer_end; + for (i = 0; i < numblocks; i++) { + ptr += (1 << CONTROL_SHIFT); + if (ptr >= buffer_end) { + ptr = buffer; + result = sddr09_read_control( + us, i << (info->blockshift + 8), + min(alloc_blocks, numblocks - i), + buffer, 0); + if (result != USB_STOR_TRANSPORT_GOOD) { + result = -1; + goto done; + } + } if (i == 0 || i == 1) { info->pba_to_lba[i] = UNUSABLE; @@ -1292,11 +1258,17 @@ } info->lbact = lbact; US_DEBUGP("Found %d LBA's\n", lbact); + result = 0; - for (i=0; i<alloc_blocks; i++) - kfree(sg_address(sg[i])); - kfree(sg); - return 0; + done: + if (result != 0) { + kfree(info->lba_to_pba); + kfree(info->pba_to_lba); + info->lba_to_pba = NULL; + info->pba_to_lba = NULL; + } + kfree(buffer); + return result; } static void ------------------------------------------------------- This SF.net email is sponsored by: IBM Linux Tutorials. Become an expert in LINUX or just sharpen your skills. Sign up for IBM's Free Linux Tutorials. Learn everything from the bash shell to sys admin. Click now! http://ads.osdn.com/?ad_id78&alloc_id371&op=click _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel