[RFC/PATCH] map drivers. DCACHE option for physmap and mphysmap drivers
Korolev, Alexey
alexey.korolev at intel.com
Thu Jan 26 12:24:29 EST 2006
Hi All,
Some mapping drivers of linux-mtd has feature of cached mapping. This
can improve read performance on FLASH significantly .
I think adding the option of data cache mapping would also be helpful
for physmap and mphysmap drivers.
Here is a perf. data I measured on Mainstone with enabled and disabled
DCACHE mapping option:
DCAHCE is off:
time dd if=/dev/mtd2 of=/dev/null bs=4k count=4k
4096+0 records in
4096+0 records out
real 0m 7.21s
user 0m 0.00s
sys 0m 7.21s
DCACHE is on:
time dd if=/dev/mtd2 of=/dev/null bs=4k count=4k
4096+0 records in
4096+0 records out
real 0m 0.69s
user 0m 0.01s
sys 0m 0.69s
Please find diff file below.
========================================================================
=====
diff -uNr a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
--- a/drivers/mtd/maps/Kconfig 2005-12-22 15:06:38.000000000 +0300
+++ b/drivers/mtd/maps/Kconfig 2005-12-22 15:05:24.000000000 +0300
@@ -60,6 +60,12 @@
Ignore this option if you use run-time physmap configuration
(i.e., run-time calling physmap_configure()).
+config MTD_PHYSMAP_DCACHE
+ bool "Enable dcache for flash mapping"
+ depends on MTD_PHYSMAP
+ help
+ This option enables CPU data cache for flash mapping
+ This improves flash read speed significantly.
config MTD_MULTI_PHYSMAP
tristate "multiple CFI Flash devices in physical memory map"
depends on MTD_CFI
@@ -86,6 +92,12 @@
depends on MTD_MULTI_PHYSMAP
default "2"
+config MTD_MULTI_PHYSMAP_1_DCACHE
+ bool "Enable dcache for 1st flash mapping"
+ depends on MTD_MULTI_PHYSMAP
+ help
+ This option enables CPU data cache for 1st flash mapping
+ This improves flash read speed significantly.
config MTD_MULTI_PHYSMAP_2_NAME
string "2nd mapping name"
depends on MTD_MULTI_PHYSMAP
@@ -106,6 +118,12 @@
depends on MTD_MULTI_PHYSMAP
default "2"
+config MTD_MULTI_PHYSMAP_2_DCACHE
+ bool "Enable dcache for 2nd flash mapping"
+ depends on MTD_MULTI_PHYSMAP
+ help
+ This option enables CPU data cache for 2nd flash mapping
+ This improves flash read speed significantly.
config MTD_MULTI_PHYSMAP_3_NAME
string "3rd mapping name"
depends on MTD_MULTI_PHYSMAP
@@ -126,6 +144,12 @@
depends on MTD_MULTI_PHYSMAP
default "2"
+config MTD_MULTI_PHYSMAP_3_DCACHE
+ bool "Enable dcache for 3rd flash mapping"
+ depends on MTD_MULTI_PHYSMAP
+ help
+ This option enables CPU data cache for 3rd flash mapping
+ This improves flash read speed significantly.
config MTD_MULTI_PHYSMAP_4_NAME
string "4th mapping name"
depends on MTD_MULTI_PHYSMAP
@@ -146,6 +170,12 @@
depends on MTD_MULTI_PHYSMAP
default "2"
+config MTD_MULTI_PHYSMAP_4_DCACHE
+ bool "Enable dcache for 4th flash mapping"
+ depends on MTD_MULTI_PHYSMAP
+ help
+ This option enables CPU data cache for 4th flash mapping
+ This improves flash read speed significantly.
config MTD_SUN_UFLASH
tristate "Sun Microsystems userflash support"
depends on (SPARC32 || SPARC64) && MTD_CFI
diff -uNr a/drivers/mtd/maps/mphysmap.c b/drivers/mtd/maps/mphysmap.c
--- a/drivers/mtd/maps/mphysmap.c 2005-12-22 15:06:38.000000000 +0300
+++ b/drivers/mtd/maps/mphysmap.c 2005-12-22 15:05:24.000000000 +0300
@@ -9,9 +9,40 @@
#include <linux/module.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
+#if defined(CONFIG_MTD_MULTI_PHYSMAP_1_DCACHE) || \
+ defined(CONFIG_MTD_MULTI_PHYSMAP_2_DCACHE) || \
+ defined(CONFIG_MTD_MULTI_PHYSMAP_3_DCACHE) || \
+ defined(CONFIG_MTD_MULTI_PHYSMAP_4_DCACHE)
+#define CONFIG_MTD_MULTI_PHYSMAP_DCACHE
+#endif
#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
#endif
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_DCACHE
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+#endif
+
+
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_DCACHE
+static void mphysmap_inval_cache(struct map_info *map, unsigned long
from, ssize_t len)
+{unsigned long end;
+ /* flush_cache_all() works, but seriously degrades performance */
+ /* flush_cache_all(); */
+ /**/
+ /* round to full pages */
+ end=(from+len);
+ end=(end / PAGE_SIZE + 1) * PAGE_SIZE;
+ from=(from / PAGE_SIZE) * PAGE_SIZE;
+ len=end-from;
+#ifdef CONFIG_ARM
+ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+#else
+ /* Non ARM architectures has not been tested */
+ dma_cache_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+#endif
+}
+#endif
static struct map_info mphysmap_static_maps[] = {
#if CONFIG_MTD_MULTI_PHYSMAP_1_WIDTH
@@ -20,6 +57,9 @@
.phys = CONFIG_MTD_MULTI_PHYSMAP_1_START,
.size = CONFIG_MTD_MULTI_PHYSMAP_1_LEN,
.bankwidth = CONFIG_MTD_MULTI_PHYSMAP_1_WIDTH,
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_1_DCACHE
+ .inval_cache = mphysmap_inval_cache,
+#endif
},
#endif
#if CONFIG_MTD_MULTI_PHYSMAP_2_WIDTH
@@ -28,6 +68,9 @@
.phys = CONFIG_MTD_MULTI_PHYSMAP_2_START,
.size = CONFIG_MTD_MULTI_PHYSMAP_2_LEN,
.bankwidth = CONFIG_MTD_MULTI_PHYSMAP_2_WIDTH,
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_2_DCACHE
+ .inval_cache = mphysmap_inval_cache,
+#endif
},
#endif
#if CONFIG_MTD_MULTI_PHYSMAP_3_WIDTH
@@ -36,6 +79,9 @@
.phys = CONFIG_MTD_MULTI_PHYSMAP_3_START,
.size = CONFIG_MTD_MULTI_PHYSMAP_3_LEN,
.bankwidth = CONFIG_MTD_MULTI_PHYSMAP_3_WIDTH,
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_3_DCACHE
+ .inval_cache = mphysmap_inval_cache,
+#endif
},
#endif
#if CONFIG_MTD_MULTI_PHYSMAP_4_WIDTH
@@ -44,6 +90,9 @@
.phys = CONFIG_MTD_MULTI_PHYSMAP_4_START,
.size = CONFIG_MTD_MULTI_PHYSMAP_4_LEN,
.bankwidth = CONFIG_MTD_MULTI_PHYSMAP_4_WIDTH,
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_4_DCACHE
+ .inval_cache = mphysmap_inval_cache,
+#endif
},
#endif
};
@@ -68,10 +117,20 @@
#endif
NULL};
#endif
- map->virt = ioremap(map->phys, map->size);
+ map->virt = ioremap_nocache(map->phys, map->size);
if (!map->virt)
return -EIO;
-
+ map->cached=NULL;
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_DCACHE
+ if (map->inval_cache)
+ {
+#ifdef CONFIG_ARM
+ map->cached = ioremap_cached(map->phys, map->size);
+#else
+ map->cached = __ioremap(map->phys, map->size,
L_PTE_CACHEABLE);
+#endif
+ };
+#endif
simple_map_init(map);
mtd = NULL;
type = rom_probe_types;
@@ -81,6 +140,10 @@
if (!mtd) {
iounmap(map->virt);
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_DCACHE
+ if (map->cached)
+ iounmap(map->cached);
+#endif
return -ENXIO;
}
@@ -134,6 +197,12 @@
map->map_priv_1 = 0;
map->map_priv_2 = 0;
map->virt = NULL;
+#ifdef CONFIG_MTD_MULTI_PHYSMAP_DCACHE
+ if (map->cached) {
+ iounmap(map->cached);
+ map->cached = NULL;
+ }
+#endif
}
diff -uNr a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
--- a/drivers/mtd/maps/physmap.c 2005-12-22 15:06:38.000000000 +0300
+++ b/drivers/mtd/maps/physmap.c 2005-12-22 15:05:24.000000000 +0300
@@ -19,15 +19,41 @@
#include <linux/mtd/map.h>
#include <linux/config.h>
#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
+#ifdef CONFIG_MTD_PHYSMAP_DCACHE
+#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
+#endif
static struct mtd_info *mymtd;
+#ifdef CONFIG_MTD_PHYSMAP_DCACHE
+static void physmap_inval_cache(struct map_info *map, unsigned long
from, ssize_t len)
+{unsigned long end;
+ /* flush_cache_all() works, but seriously degrades performance */
+ /* flush_cache_all(); */
+ /**/
+ /* round to full pages */
+ end=(from+len);
+ end=(end / PAGE_SIZE + 1) * PAGE_SIZE;
+ from=(from / PAGE_SIZE) * PAGE_SIZE;
+ len=end-from;
+#ifdef CONFIG_ARM
+ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+#else
+ /* Non ARM architectures are not tested */
+ dma_cache_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+#endif
+}
+#endif
+
struct map_info physmap_map = {
.name = "phys_mapped_flash",
.phys = CONFIG_MTD_PHYSMAP_START,
.size = CONFIG_MTD_PHYSMAP_LEN,
.bankwidth = CONFIG_MTD_PHYSMAP_BANKWIDTH,
+#ifdef CONFIG_MTD_PHYSMAP_DCACHE
+ .inval_cache = physmap_inval_cache,
+#endif
};
#ifdef CONFIG_MTD_PARTITIONS
@@ -52,13 +78,22 @@
const char **type;
printk(KERN_NOTICE "physmap flash device: %lx at %lx\n",
physmap_map.size, physmap_map.phys);
- physmap_map.virt = ioremap(physmap_map.phys, physmap_map.size);
+ physmap_map.virt = ioremap_nocache(physmap_map.phys,
physmap_map.size);
if (!physmap_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
-
+#ifdef CONFIG_MTD_PHYSMAP_DCACHE
+#ifdef CONFIG_ARM
+ physmap_map.cached = ioremap_cached(physmap_map.phys,
physmap_map.size);
+#else
+ physmap_map.cached = __ioremap(physmap_map.phys, physmap_map.size,
L_PTE_CACHEABLE);
+#endif
+ if (!physmap_map.cached) {
+ printk("Failed to ioremap cached\n");
+ }
+#endif
simple_map_init(&physmap_map);
mymtd = NULL;
@@ -94,6 +129,10 @@
}
iounmap(physmap_map.virt);
+#ifdef CONFIG_MTD_PHYSMAP_DCACHE
+ if (physmap_map.cached)
+ iounmap(physmap_map.cached);
+#endif
return -ENXIO;
}
@@ -115,6 +154,12 @@
iounmap(physmap_map.virt);
physmap_map.virt = NULL;
+#ifdef CONFIG_MTD_PHYSMAP_DCACHE
+ if (physmap_map.cached) {
+ iounmap(physmap_map.cached);
+ physmap_map.cached = NULL;
+ }
+#endif
}
module_init(init_physmap);
=========================================================
Thanks,
Alexey
More information about the linux-mtd
mailing list