Skip to content

Commit 9401911

Browse files
vwaxmiquelraynal
authored andcommitted
mtd: phram: Allow cached mappings
Currently phram always uses ioremap(), but this is unnecessary when normal memory is used. If the reserved-memory node does not specify the no-map property, indicating it should be mapped as system RAM and ioremap() cannot be used on it, use a cached mapping using memremap(MEMREMAP_WB) instead. On one of my systems this improves read performance by ~70%. (Note that this driver has always used normal memcpy/memset functions on memory obtained from ioremap(), which sparse doesn't like. There is no memremap() variant which maps exactly to ioremap() on all architectures, so that behaviour of the driver is not changed to avoid affecting existing users, but the sparse warnings are suppressed in the moved code with __force.) Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/linux-mtd/20220510151822.1809278-1-vincent.whitchurch@axis.com
1 parent bcdf031 commit 9401911

1 file changed

Lines changed: 37 additions & 6 deletions

File tree

drivers/mtd/devices/phram.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
struct phram_mtd_list {
3535
struct mtd_info mtd;
3636
struct list_head list;
37+
bool cached;
3738
};
3839

3940
static LIST_HEAD(phram_list);
@@ -80,13 +81,41 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
8081
return 0;
8182
}
8283

84+
static int phram_map(struct phram_mtd_list *phram, phys_addr_t start, size_t len)
85+
{
86+
void *addr = NULL;
87+
88+
if (phram->cached)
89+
addr = memremap(start, len, MEMREMAP_WB);
90+
else
91+
addr = (void __force *)ioremap(start, len);
92+
if (!addr)
93+
return -EIO;
94+
95+
phram->mtd.priv = addr;
96+
97+
return 0;
98+
}
99+
100+
static void phram_unmap(struct phram_mtd_list *phram)
101+
{
102+
void *addr = phram->mtd.priv;
103+
104+
if (phram->cached) {
105+
memunmap(addr);
106+
return;
107+
}
108+
109+
iounmap((void __iomem *)addr);
110+
}
111+
83112
static void unregister_devices(void)
84113
{
85114
struct phram_mtd_list *this, *safe;
86115

87116
list_for_each_entry_safe(this, safe, &phram_list, list) {
88117
mtd_device_unregister(&this->mtd);
89-
iounmap(this->mtd.priv);
118+
phram_unmap(this);
90119
kfree(this->mtd.name);
91120
kfree(this);
92121
}
@@ -96,16 +125,18 @@ static int register_device(struct platform_device *pdev, const char *name,
96125
phys_addr_t start, size_t len, uint32_t erasesize)
97126
{
98127
struct device_node *np = pdev ? pdev->dev.of_node : NULL;
128+
bool cached = np ? !of_property_read_bool(np, "no-map") : false;
99129
struct phram_mtd_list *new;
100130
int ret = -ENOMEM;
101131

102132
new = kzalloc(sizeof(*new), GFP_KERNEL);
103133
if (!new)
104134
goto out0;
105135

106-
ret = -EIO;
107-
new->mtd.priv = ioremap(start, len);
108-
if (!new->mtd.priv) {
136+
new->cached = cached;
137+
138+
ret = phram_map(new, start, len);
139+
if (ret) {
109140
pr_err("ioremap failed\n");
110141
goto out1;
111142
}
@@ -140,7 +171,7 @@ static int register_device(struct platform_device *pdev, const char *name,
140171
return 0;
141172

142173
out2:
143-
iounmap(new->mtd.priv);
174+
phram_unmap(new);
144175
out1:
145176
kfree(new);
146177
out0:
@@ -362,7 +393,7 @@ static int phram_remove(struct platform_device *pdev)
362393
struct phram_mtd_list *phram = platform_get_drvdata(pdev);
363394

364395
mtd_device_unregister(&phram->mtd);
365-
iounmap(phram->mtd.priv);
396+
phram_unmap(phram);
366397
kfree(phram);
367398

368399
return 0;

0 commit comments

Comments
 (0)