From c620b321b1d0270539dd751f5a3a53fe8d6c4c8e Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 22 Feb 2016 18:25:58 -0600 Subject: [PATCH] FAT: Add a new configuration option to decouple the logic that retries the direct transfer from the logic that enables DMA memory allocators. --- arch | 2 +- fs/fat/Kconfig | 45 ++++++++++++++++++++++++++++++++++++++++++--- fs/fat/fs_fat32.c | 45 +++++++++++++++++++++++---------------------- 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/arch b/arch index 7ed1d2eb50..50415398b1 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 7ed1d2eb50bcfc637e21fcf41521e562d4a521a1 +Subproject commit 50415398b1ae76ffb66df9813f4647dcbfcee234 diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig index d0ec9a950a..9176484f91 100644 --- a/fs/fat/Kconfig +++ b/fs/fat/Kconfig @@ -51,9 +51,9 @@ config FS_FATTIME hardware RTC or other way to get the time and date. config FAT_FORCE_INDIRECT -bool "Force all in-direct transfers" -default n ----help--- + bool "Force direct transfers" + default n + ---help--- Normally, the default behavior for the FAT file system is to perform data transfers indirectly though specially allocated sector buffers or, under certain circumstances, directly through user provided @@ -73,9 +73,20 @@ default n systems internal sector buffers, and (2) A loss of performance because I/O will be limited to one sector at a time. + This would typically be used with CONFIG_FAT_DMAMEMORY so that + special memory allocators are also used and transfers are also + performed using only that specially allocated memory. + CONFIG_FAT_DMAMEMORY, on the other hand, is often used without + CONFIG_FAT_FORCE_INDIRECT when the user memory buffers may come + from mixed locations, some of which are DMA-able and some of + which are not. But CONFIG_FAT_FORCE_INDIRECT could be used + without CONFIG_FAT_DMAMEMORY if there is, for example, only a + memory aligment constraints. + config FAT_DMAMEMORY bool "DMA memory allocator" default n + select FAT_DIRECT_RETRY if !FAT_FORCE_INDIRECT ---help--- The FAT file system allocates two I/O buffers for data transfer, each are the size of one device sector. One of the buffers is allocated @@ -90,4 +101,32 @@ config FAT_DMAMEMORY corresponding function that will be called to free the DMA-capable memory. +config FAT_DIRECT_RETRY + bool "Direct transfer retry" + default y if FAT_DMAMEMORY + default n if !FAT_DMAMEMORY + depends on !FAT_FORCE_INDIRECT + ---help--- + The FAT file system contains internal, well aligned sector buffers + for indirect data transfer. These transfers are indirect in the + sense that that the actual transfer occurs into/out of the sector + buffers and an additional copy is necessary to/from the user- + provided I/O buffers. But under certain conditions, the FAT file + system will use the caller-provided I/O buffers directly to improve + efficiency. Those conditions are (1) CONFIG_FAT_FORCE_INDIRECT is + not defined, (2) The access is to/from the beginning of a sector, + and (3) the user provided buffer is large enough to hold an entire + sector. + + The lower level SDIO driver may have, certain requirements on the + memory buffer in order to perform the transfer. Perhaps special + DMA memory should be used (with CONFIG_FAT_DMAMEMORY) or perhaps + some special memory alignment is required to interace with the + hardware. + + If this option is selected, then the FAT file system will first + try the user provided I/O buffer under above conditions. If the + transfer fails with -EFAULT. then the FAT file system will try one + more time using the internal sector buffers. + endif # FAT diff --git a/fs/fat/fs_fat32.c b/fs/fat/fs_fat32.c index ac492809f0..7fddec4d03 100644 --- a/fs/fat/fs_fat32.c +++ b/fs/fat/fs_fat32.c @@ -409,17 +409,16 @@ static int fat_close(FAR struct file *filep) /* Recover our private data from the struct file instance */ - ff = filep->f_priv; + ff = filep->f_priv; + inode = filep->f_inode; + fs = inode->i_private; + + DEBUGASSERT(fs != NULL); /* Check for the forced mount condition */ if ((ff->ff_bflags & UMOUNT_FORCED) == 0) { - inode = filep->f_inode; - fs = inode->i_private; - - DEBUGASSERT(fs != NULL); - /* Do not check if the mount is healthy. We must support closing of * the file even when there is healthy mount. */ @@ -589,7 +588,7 @@ static ssize_t fat_read(FAR struct file *filep, FAR char *buffer, ff->ff_sectorsincluster = fs->fs_fatsecperclus; } -#ifdef CONFIG_FAT_DMAMEMORY /* Warning avoidance */ +#ifdef CONFIG_FAT_DIRECT_RETRY /* Warning avoidance */ fat_read_restart: #endif @@ -626,21 +625,22 @@ fat_read_restart: ret = fat_hwread(fs, userbuffer, ff->ff_currentsector, nsectors); if (ret < 0) { -#ifdef CONFIG_FAT_DMAMEMORY +#ifdef CONFIG_FAT_DIRECT_RETRY /* The low-level driver may return -EFAULT in the case where - * the transfer cannot be performed due to DMA constraints. - * It is probable that the buffer is completely un-DMA-able, - * so force indirect transfers via the sector buffer and - * restart the operation. + * the transfer cannot be performed due to buffer memory + * constraints. It is probable that the buffer is completely + * un-DMA-able or improperly aligned. In this case, force + * indirect transfers via the sector buffer and restart the + * operation (unless we have already tried that). */ - if (ret == -EFAULT) + if (ret == -EFAULT && !force_indirect) { fdbg("DMA: read alignment error, restarting indirect\n"); force_indirect = true; goto fat_read_restart; } -#endif /* CONFIG_FAT_DMAMEMORY */ +#endif /* CONFIG_FAT_DIRECT_RETRY */ goto errout_with_semaphore; } @@ -848,7 +848,7 @@ static ssize_t fat_write(FAR struct file *filep, FAR const char *buffer, ff->ff_currentsector = fat_cluster2sector(fs, cluster); } -#ifdef CONFIG_FAT_DMAMEMORY /* Warning avoidance */ +#ifdef CONFIG_FAT_DIRECT_RETRY /* Warning avoidance */ fat_write_restart: #endif @@ -885,21 +885,22 @@ fat_write_restart: ret = fat_hwwrite(fs, userbuffer, ff->ff_currentsector, nsectors); if (ret < 0) { -#ifdef CONFIG_FAT_DMAMEMORY +#ifdef CONFIG_FAT_DIRECT_RETRY /* The low-level driver may return -EFAULT in the case where - * the transfer cannot be performed due to DMA constraints. - * It is probable that the buffer is completely un-DMA-able, - * so force indirect transfers via the sector buffer and - * restart the operation. + * the transfer cannot be performed due to buffer memory + * constraints. It is probable that the buffer is completely + * un-DMA-able or improperly aligned. In this case, force + * indirect transfers via the sector buffer and restart the + * operation (unless we have already tried that). */ - if (ret == -EFAULT) + if (ret == -EFAULT && !force_indirect) { fdbg("DMA: write alignment error, restarting indirect\n"); force_indirect = true; goto fat_write_restart; } -#endif /* CONFIG_FAT_DMAMEMORY */ +#endif /* CONFIG_FAT_DIRECT_RETRY */ goto errout_with_semaphore; }