2022-04-06 11:50:48

by Vincent Whitchurch

[permalink] [raw]
Subject: [PATCH v2 0/4] mtd: phram improvements

v2:
- Add note on what "phram" means in binding.
- Use /schemas/mtd/mtd.yaml instead of relative pathUse /schemas/mtd/mtd.yaml
instead of relative path in binding.

The phram driver in the MTD subsystem can be used to allow the kernel to use an
MTD or (via mtdblock) a block device in RAM (with the contents loaded by a
bootloader for example). This series has some improvements to make it more
usable by adding device tree support and to significantly improve its
performance by using cached mappings when possible.

I use this feature to pass the rootfs to the kernel when booting from RAM. The
boot is much faster and requires less memory than initrd (which is on top of
that being deprecated), and it allows the same disk images to be used when
booting from RAM, unlike initramfs.

Cc: [email protected]

Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]

Cc: [email protected]

Vincent Whitchurch (4):
mtd: core: Check devicetree alias for index
dt-bindings: reserved-memory: Add phram
mtd: phram: Allow probing via reserved-memory
mtd: phram: Allow cached mappings

.../bindings/reserved-memory/phram.yaml | 47 +++++++++++
drivers/mtd/devices/phram.c | 78 +++++++++++++++++--
drivers/mtd/mtdcore.c | 11 ++-
drivers/of/platform.c | 1 +
4 files changed, 129 insertions(+), 8 deletions(-)
create mode 100644 Documentation/devicetree/bindings/reserved-memory/phram.yaml

--
2.34.1


2022-04-06 11:59:04

by Vincent Whitchurch

[permalink] [raw]
Subject: [PATCH v2 1/4] mtd: core: Check devicetree alias for index

Allow the MTD index to be specified via a devicetree alias, so that the
number does not just depend on probe order. This is useful to allow
pseudo-devices like phram to be optionally used on systems, without
having this affect the numbering of the real hardware MTD devices.

Signed-off-by: Vincent Whitchurch <[email protected]>
---
drivers/mtd/mtdcore.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 7731796024e0..9eb0680db312 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -557,9 +557,10 @@ static int mtd_nvmem_add(struct mtd_info *mtd)

int add_mtd_device(struct mtd_info *mtd)
{
+ struct device_node *np = mtd_get_of_node(mtd);
struct mtd_info *master = mtd_get_master(mtd);
struct mtd_notifier *not;
- int i, error;
+ int i, error, ofidx;

/*
* May occur, for instance, on buggy drivers which call
@@ -598,7 +599,13 @@ int add_mtd_device(struct mtd_info *mtd)

mutex_lock(&mtd_table_mutex);

- i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
+ ofidx = -1;
+ if (np)
+ ofidx = of_alias_get_id(np, "mtd");
+ if (ofidx >= 0)
+ i = idr_alloc(&mtd_idr, mtd, ofidx, ofidx + 1, GFP_KERNEL);
+ else
+ i = idr_alloc(&mtd_idr, mtd, 0, 0, GFP_KERNEL);
if (i < 0) {
error = i;
goto fail_locked;
--
2.34.1

2022-04-06 12:10:43

by Vincent Whitchurch

[permalink] [raw]
Subject: [PATCH v2 3/4] mtd: phram: Allow probing via reserved-memory

Allow phram to be probed from the devicetree. It expects to be in a
reserved-memory node as documented by the bindings. This allows things
like partitioning to be specified via the devicetree.

Signed-off-by: Vincent Whitchurch <[email protected]>
---
drivers/mtd/devices/phram.c | 67 ++++++++++++++++++++++++++++++++++---
drivers/of/platform.c | 1 +
2 files changed, 64 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index d503821a3e60..6dfe9401a3c5 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -27,6 +27,9 @@
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <asm/div64.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of.h>

struct phram_mtd_list {
struct mtd_info mtd;
@@ -89,8 +92,10 @@ static void unregister_devices(void)
}
}

-static int register_device(char *name, phys_addr_t start, size_t len, uint32_t erasesize)
+static int register_device(struct platform_device *pdev, const char *name,
+ phys_addr_t start, size_t len, uint32_t erasesize)
{
+ struct device_node *np = pdev ? pdev->dev.of_node : NULL;
struct phram_mtd_list *new;
int ret = -ENOMEM;

@@ -119,13 +124,19 @@ static int register_device(char *name, phys_addr_t start, size_t len, uint32_t e
new->mtd.erasesize = erasesize;
new->mtd.writesize = 1;

+ mtd_set_of_node(&new->mtd, np);
+
ret = -EAGAIN;
if (mtd_device_register(&new->mtd, NULL, 0)) {
pr_err("Failed to register new device\n");
goto out2;
}

- list_add_tail(&new->list, &phram_list);
+ if (pdev)
+ platform_set_drvdata(pdev, new);
+ else
+ list_add_tail(&new->list, &phram_list);
+
return 0;

out2:
@@ -278,7 +289,7 @@ static int phram_setup(const char *val)
goto error;
}

- ret = register_device(name, start, len, (uint32_t)erasesize);
+ ret = register_device(NULL, name, start, len, (uint32_t)erasesize);
if (ret)
goto error;

@@ -325,10 +336,54 @@ static int phram_param_call(const char *val, const struct kernel_param *kp)
module_param_call(phram, phram_param_call, NULL, NULL, 0200);
MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>[,<erasesize>]\"");

+#ifdef CONFIG_OF
+static const struct of_device_id phram_of_match[] = {
+ { .compatible = "phram" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, phram_of_match)
+#endif
+
+static int phram_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOMEM;
+
+ /* mtd_set_of_node() reads name from "label" */
+ return register_device(pdev, NULL, res->start, resource_size(res),
+ PAGE_SIZE);
+}
+
+static int phram_remove(struct platform_device *pdev)
+{
+ struct phram_mtd_list *phram = platform_get_drvdata(pdev);
+
+ mtd_device_unregister(&phram->mtd);
+ iounmap(phram->mtd.priv);
+ kfree(phram);
+
+ return 0;
+}
+
+static struct platform_driver phram_driver = {
+ .probe = phram_probe,
+ .remove = phram_remove,
+ .driver = {
+ .name = "phram",
+ .of_match_table = of_match_ptr(phram_of_match),
+ },
+};

static int __init init_phram(void)
{
- int ret = 0;
+ int ret;
+
+ ret = platform_driver_register(&phram_driver);
+ if (ret)
+ return ret;

#ifndef MODULE
if (phram_paramline[0])
@@ -336,12 +391,16 @@ static int __init init_phram(void)
phram_init_called = 1;
#endif

+ if (ret)
+ platform_driver_unregister(&phram_driver);
+
return ret;
}

static void __exit cleanup_phram(void)
{
unregister_devices();
+ platform_driver_unregister(&phram_driver);
}

module_init(init_phram);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index a16b74f32aa9..55d62b82c650 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -509,6 +509,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate);

#ifndef CONFIG_PPC
static const struct of_device_id reserved_mem_matches[] = {
+ { .compatible = "phram" },
{ .compatible = "qcom,rmtfs-mem" },
{ .compatible = "qcom,cmd-db" },
{ .compatible = "qcom,smem" },
--
2.34.1

2022-04-06 13:03:04

by Vincent Whitchurch

[permalink] [raw]
Subject: [PATCH v2 4/4] 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%.

Signed-off-by: Vincent Whitchurch <[email protected]>
---
drivers/mtd/devices/phram.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 6dfe9401a3c5..ac2679f9031a 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -34,6 +34,7 @@
struct phram_mtd_list {
struct mtd_info mtd;
struct list_head list;
+ bool cached;
};

static LIST_HEAD(phram_list);
@@ -96,6 +97,7 @@ static int register_device(struct platform_device *pdev, const char *name,
phys_addr_t start, size_t len, uint32_t erasesize)
{
struct device_node *np = pdev ? pdev->dev.of_node : NULL;
+ bool cached = np ? !of_property_read_bool(np, "no-map") : false;
struct phram_mtd_list *new;
int ret = -ENOMEM;

@@ -103,8 +105,13 @@ static int register_device(struct platform_device *pdev, const char *name,
if (!new)
goto out0;

+ new->cached = cached;
+
ret = -EIO;
- new->mtd.priv = ioremap(start, len);
+ if (cached)
+ new->mtd.priv = memremap(start, len, MEMREMAP_WB);
+ else
+ new->mtd.priv = ioremap(start, len);
if (!new->mtd.priv) {
pr_err("ioremap failed\n");
goto out1;
@@ -140,7 +147,7 @@ static int register_device(struct platform_device *pdev, const char *name,
return 0;

out2:
- iounmap(new->mtd.priv);
+ cached ? memunmap(new->mtd.priv) : iounmap(new->mtd.priv);
out1:
kfree(new);
out0:
@@ -362,7 +369,7 @@ static int phram_remove(struct platform_device *pdev)
struct phram_mtd_list *phram = platform_get_drvdata(pdev);

mtd_device_unregister(&phram->mtd);
- iounmap(phram->mtd.priv);
+ phram->cached ? memunmap(phram->mtd.priv) : iounmap(phram->mtd.priv);
kfree(phram);

return 0;
--
2.34.1

2022-04-06 13:15:39

by Vincent Whitchurch

[permalink] [raw]
Subject: [PATCH v2 2/4] dt-bindings: reserved-memory: Add phram

Add bindings to allow MTD/block devices to be created in reserved-memory
regions using the "phram" driver.

This allows things like partitioning to be specified via the existing
devicetree bindings.

Signed-off-by: Vincent Whitchurch <[email protected]>
---

Notes:
v2:
- Add note on what "phram" means.
- Use /schemas/mtd/mtd.yaml instead of relative pathUse /schemas/mtd/mtd.yaml instead of relative path.

.../bindings/reserved-memory/phram.yaml | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 Documentation/devicetree/bindings/reserved-memory/phram.yaml

diff --git a/Documentation/devicetree/bindings/reserved-memory/phram.yaml b/Documentation/devicetree/bindings/reserved-memory/phram.yaml
new file mode 100644
index 000000000000..318415b56afe
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/phram.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reserved-memory/phram.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MTD/block device in RAM
+
+description: |
+ Use the reserved memory region as an MTD or block device. The "phram" node
+ is named after the "MTD in PHysical RAM" driver which provides an
+ implementation of this functionality in Linux.
+
+ If no-map is not set, cached mappings will be used for the memory region.
+
+maintainers:
+ - Vincent Whitchurch <[email protected]>
+
+allOf:
+ - $ref: "reserved-memory.yaml"
+ - $ref: "/schemas/mtd/mtd.yaml"
+
+properties:
+ compatible:
+ const: phram
+
+ reg:
+ description: region of memory that contains the MTD/block device
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ phram: flash@12340000 {
+ compatible = "phram";
+ label = "rootfs";
+ reg = <0x12340000 0x00800000>;
+ };
+ };
--
2.34.1

2022-04-06 14:53:07

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] mtd: phram: Allow probing via reserved-memory

Hi Vincent,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on mtd/mtd/next]
[also build test ERROR on mtd/mtd/fixes robh/for-next v5.18-rc1 next-20220405]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/intel-lab-lkp/linux/commits/Vincent-Whitchurch/mtd-phram-improvements/20220406-070357
base: https://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git mtd/next
config: i386-randconfig-a005 (https://download.01.org/0day-ci/archive/20220406/[email protected]/config)
compiler: gcc-11 (Debian 11.2.0-19) 11.2.0
reproduce (this is a W=1 build):
# https://github.com/intel-lab-lkp/linux/commit/5f942c36259bf6194f9cc8ed7cbacdca28200e20
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Vincent-Whitchurch/mtd-phram-improvements/20220406-070357
git checkout 5f942c36259bf6194f9cc8ed7cbacdca28200e20
# save the config file to linux build tree
mkdir build_dir
make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/mtd/devices/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

>> drivers/mtd/devices/phram.c:347:1: error: expected ',' or ';' before 'static'
347 | static int phram_probe(struct platform_device *pdev)
| ^~~~~~
>> drivers/mtd/devices/phram.c:372:27: error: 'phram_probe' undeclared here (not in a function); did you mean 'phram_write'?
372 | .probe = phram_probe,
| ^~~~~~~~~~~
| phram_write


vim +347 drivers/mtd/devices/phram.c

346
> 347 static int phram_probe(struct platform_device *pdev)
348 {
349 struct resource *res;
350
351 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
352 if (!res)
353 return -ENOMEM;
354
355 /* mtd_set_of_node() reads name from "label" */
356 return register_device(pdev, NULL, res->start, resource_size(res),
357 PAGE_SIZE);
358 }
359
360 static int phram_remove(struct platform_device *pdev)
361 {
362 struct phram_mtd_list *phram = platform_get_drvdata(pdev);
363
364 mtd_device_unregister(&phram->mtd);
365 iounmap(phram->mtd.priv);
366 kfree(phram);
367
368 return 0;
369 }
370
371 static struct platform_driver phram_driver = {
> 372 .probe = phram_probe,
373 .remove = phram_remove,
374 .driver = {
375 .name = "phram",
376 .of_match_table = of_match_ptr(phram_of_match),
377 },
378 };
379

--
0-DAY CI Kernel Test Service
https://01.org/lkp