* [PATCH v7 8/9] nvmem: sunxi: Move the SID driver to the nvmem framework
From: Srinivas Kandagatla @ 2015-07-10 9:45 UTC (permalink / raw)
To: linux-arm-kernel, Greg Kroah-Hartman
Cc: Rob Herring, Kumar Gala, Mark Brown, s.hauer, linux-api,
linux-kernel, devicetree, linux-arm-msm, arnd, sboyd,
pantelis.antoniou, mporter, stefan.wahren, wxt,
Srinivas Kandagatla, Maxime Ripard
In-Reply-To: <1436521427-10568-1-git-send-email-srinivas.kandagatla@linaro.org>
From: Maxime Ripard <maxime.ripard@free-electrons.com>
Now that we have the nvmem framework, we can consolidate the common
driver code. Move the driver to the framework, and hopefully, it will
fix the sysfs file creation race.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
Documentation/ABI/testing/sysfs-driver-sunxi-sid | 22 ---
.../bindings/misc/allwinner,sunxi-sid.txt | 17 ---
.../bindings/nvmem/allwinner,sunxi-sid.txt | 21 +++
drivers/misc/eeprom/Kconfig | 13 --
drivers/misc/eeprom/Makefile | 1 -
drivers/misc/eeprom/sunxi_sid.c | 156 --------------------
drivers/nvmem/Kconfig | 11 ++
drivers/nvmem/Makefile | 2 +
drivers/nvmem/sunxi_sid.c | 160 +++++++++++++++++++++
9 files changed, 194 insertions(+), 209 deletions(-)
delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
create mode 100644 Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
create mode 100644 drivers/nvmem/sunxi_sid.c
diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What: /sys/devices/*/<our-device>/eeprom
-Date: August 2013
-Contact: Oliver Schinagl <oliver@schinagl.nl>
-Description: read-only access to the SID (Security-ID) on current
- A-series SoC's from Allwinner. Currently supports A10, A10s, A13
- and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
- whereas the newer A20 SoC exposes 512 bytes split into sections.
- Besides the 16 bytes of SID, there's also an SJTAG area,
- HDMI-HDCP key and some custom keys. Below a quick overview, for
- details see the user manual:
- 0x000 128 bit root-key (sun[457]i)
- 0x010 128 bit boot-key (sun7i)
- 0x020 64 bit security-jtag-key (sun7i)
- 0x028 16 bit key configuration (sun7i)
- 0x02b 16 bit custom-vendor-key (sun7i)
- 0x02c 320 bit low general key (sun7i)
- 0x040 32 bit read-control access (sun7i)
- 0x064 224 bit low general key (sun7i)
- 0x080 2304 bit HDCP-key (sun7i)
- 0x1a0 768 bit high general key (sun7i)
-Users: any user space application which wants to read the SID on
- Allwinner's A-series of CPU's.
diff --git a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
deleted file mode 100644
index fabdf64..0000000
--- a/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Allwinner sunxi-sid
-
-Required properties:
-- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
-- reg: Should contain registers location and length
-
-Example for sun4i:
- sid@01c23800 {
- compatible = "allwinner,sun4i-a10-sid";
- reg = <0x01c23800 0x10>
- };
-
-Example for sun7i:
- sid@01c23800 {
- compatible = "allwinner,sun7i-a20-sid";
- reg = <0x01c23800 0x200>
- };
diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
new file mode 100644
index 0000000..d543ed3
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
@@ -0,0 +1,21 @@
+Allwinner sunxi-sid
+
+Required properties:
+- compatible: "allwinner,sun4i-a10-sid" or "allwinner,sun7i-a20-sid"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/nvmem/nvmem.txt
+
+Example for sun4i:
+ sid@01c23800 {
+ compatible = "allwinner,sun4i-a10-sid";
+ reg = <0x01c23800 0x10>
+ };
+
+Example for sun7i:
+ sid@01c23800 {
+ compatible = "allwinner,sun7i-a20-sid";
+ reg = <0x01c23800 0x200>
+ };
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
If unsure, say N.
-config EEPROM_SUNXI_SID
- tristate "Allwinner sunxi security ID support"
- depends on ARCH_SUNXI && SYSFS
- help
- This is a driver for the 'security ID' available on various Allwinner
- devices.
-
- Due to the potential risks involved with changing e-fuses,
- this driver is read-only.
-
- This driver can also be built as a module. If so, the module
- will be called sunxi_sid.
-
endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o
obj-$(CONFIG_EEPROM_MAX6875) += max6875.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID) += sunxi_sid.o
obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
- void __iomem *reg_base;
- unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
- const unsigned int offset)
-{
- u32 sid_key;
-
- if (offset >= sid_data->keysize)
- return 0;
-
- sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
- sid_key >>= (offset % 4) * 8;
-
- return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t pos, size_t size)
-{
- struct platform_device *pdev;
- struct sunxi_sid_data *sid_data;
- int i;
-
- pdev = to_platform_device(kobj_to_dev(kobj));
- sid_data = platform_get_drvdata(pdev);
-
- if (pos < 0 || pos >= sid_data->keysize)
- return 0;
- if (size > sid_data->keysize - pos)
- size = sid_data->keysize - pos;
-
- for (i = 0; i < size; i++)
- buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
- return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
- .attr = { .name = "eeprom", .mode = S_IRUGO, },
- .read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
- device_remove_bin_file(&pdev->dev, &sid_bin_attr);
- dev_dbg(&pdev->dev, "driver unloaded\n");
-
- return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
- { .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
- { .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
- {/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
- struct sunxi_sid_data *sid_data;
- struct resource *res;
- const struct of_device_id *of_dev_id;
- u8 *entropy;
- unsigned int i;
-
- sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
- GFP_KERNEL);
- if (!sid_data)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(sid_data->reg_base))
- return PTR_ERR(sid_data->reg_base);
-
- of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
- if (!of_dev_id)
- return -ENODEV;
- sid_data->keysize = (int)of_dev_id->data;
-
- platform_set_drvdata(pdev, sid_data);
-
- sid_bin_attr.size = sid_data->keysize;
- if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
- return -ENODEV;
-
- entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
- for (i = 0; i < sid_data->keysize; i++)
- entropy[i] = sunxi_sid_read_byte(sid_data, i);
- add_device_randomness(entropy, sid_data->keysize);
- kfree(entropy);
-
- dev_dbg(&pdev->dev, "loaded\n");
-
- return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
- .probe = sunxi_sid_probe,
- .remove = sunxi_sid_remove,
- .driver = {
- .name = DRV_NAME,
- .of_match_table = sunxi_sid_of_match,
- },
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index fa85805..8db2978 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -25,4 +25,15 @@ config QCOM_QFPROM
This driver can also be built as a module. If so, the module
will be called nvmem_qfprom.
+config NVMEM_SUNXI_SID
+ tristate "Allwinner SoCs SID support"
+ depends on ARCH_SUNXI
+ select REGMAP_MMIO
+ help
+ This is a driver for the 'security ID' available on various Allwinner
+ devices.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem_sunxi_sid.
+
endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index ff44fe9..4328b93 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -8,3 +8,5 @@ nvmem_core-y := core.o
# Devices
obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
nvmem_qfprom-y := qfprom.o
+obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
+nvmem_sunxi_sid-y := sunxi_sid.o
diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
new file mode 100644
index 0000000..1c3ff2e6
--- /dev/null
+++ b/drivers/nvmem/sunxi_sid.c
@@ -0,0 +1,160 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#include <linux/platform_device.h>
+#include <linux/nvmem-provider.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+
+
+static struct nvmem_config econfig = {
+ .name = "sunxi-sid",
+ .read_only = true,
+ .owner = THIS_MODULE,
+};
+
+struct sunxi_sid {
+ void __iomem *base;
+};
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this results in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarely probed, this is not really an issue.
+ */
+static u8 sunxi_sid_read_byte(const struct sunxi_sid *sid,
+ const unsigned int offset)
+{
+ u32 sid_key;
+
+ sid_key = ioread32be(sid->base + round_down(offset, 4));
+ sid_key >>= (offset % 4) * 8;
+
+ return sid_key; /* Only return the last byte */
+}
+
+static int sunxi_sid_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct sunxi_sid *sid = context;
+ unsigned int offset = *(u32 *)reg;
+ u8 *buf = val;
+
+ while (val_size) {
+ *buf++ = sunxi_sid_read_byte(sid, offset);
+ val_size--;
+ offset++;
+ }
+
+ return 0;
+}
+
+static int sunxi_sid_write(void *context, const void *data, size_t count)
+{
+ /* Unimplemented, dummy to keep regmap core happy */
+ return 0;
+}
+
+static struct regmap_bus sunxi_sid_bus = {
+ .read = sunxi_sid_read,
+ .write = sunxi_sid_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return false;
+}
+
+static struct regmap_config sunxi_sid_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .reg_stride = 1,
+ .writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static int sunxi_sid_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct nvmem_device *nvmem;
+ struct regmap *regmap;
+ struct sunxi_sid *sid;
+
+ sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
+ if (!sid)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sid->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(sid->base))
+ return PTR_ERR(sid->base);
+
+ sunxi_sid_regmap_config.max_register = resource_size(res) - 1;
+
+ regmap = devm_regmap_init(dev, &sunxi_sid_bus, sid,
+ &sunxi_sid_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "regmap init failed\n");
+ return PTR_ERR(regmap);
+ }
+ econfig.dev = dev;
+ nvmem = nvmem_register(&econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ platform_set_drvdata(pdev, nvmem);
+
+ return 0;
+}
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+ struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+ return nvmem_unregister(nvmem);
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-sid" },
+ { .compatible = "allwinner,sun7i-a20-sid" },
+ {/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct platform_driver sunxi_sid_driver = {
+ .probe = sunxi_sid_probe,
+ .remove = sunxi_sid_remove,
+ .driver = {
+ .name = "eeprom-sunxi-sid",
+ .of_match_table = sunxi_sid_of_match,
+ },
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
--
1.9.1
^ permalink raw reply related
* [PATCH v7 7/9] nvmem: qfprom: Add bindings for qfprom
From: Srinivas Kandagatla @ 2015-07-10 9:45 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Greg Kroah-Hartman
Cc: Rob Herring, Kumar Gala, Mark Brown,
s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w,
mporter-OWPKS81ov/FWk0Htik3J/w, stefan.wahren-eS4NqCHxEME,
wxt-TNX95d0MmH7DzftRWevZcw, Srinivas Kandagatla
In-Reply-To: <1436521427-10568-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
This patch adds bindings for qfprom found in QCOM SOCs. QFPROM driver
is based on simple nvmem framework.
Reviewed-by: Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
Documentation/devicetree/bindings/nvmem/qfprom.txt | 35 ++++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 Documentation/devicetree/bindings/nvmem/qfprom.txt
diff --git a/Documentation/devicetree/bindings/nvmem/qfprom.txt b/Documentation/devicetree/bindings/nvmem/qfprom.txt
new file mode 100644
index 0000000..4ad68b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/qfprom.txt
@@ -0,0 +1,35 @@
+= Qualcomm QFPROM device tree bindings =
+
+This binding is intended to represent QFPROM which is found in most QCOM SOCs.
+
+Required properties:
+- compatible: should be "qcom,qfprom"
+- reg: Should contain registers location and length
+
+= Data cells =
+Are child nodes of qfprom, bindings of which as described in
+bindings/nvmem/nvmem.txt
+
+Example:
+
+ qfprom: qfprom@00700000 {
+ compatible = "qcom,qfprom";
+ reg = <0x00700000 0x8000>;
+ ...
+ /* Data cells */
+ tsens_calibration: calib@404 {
+ reg = <0x4404 0x10>;
+ };
+ };
+
+
+= Data consumers =
+Are device nodes which consume nvmem data cells.
+
+For example:
+
+ tsens {
+ ...
+ nvmem-cells = <&tsens_calibration>;
+ nvmem-cell-names = "calibration";
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v7 6/9] nvmem: qfprom: Add Qualcomm QFPROM support.
From: Srinivas Kandagatla @ 2015-07-10 9:45 UTC (permalink / raw)
To: linux-arm-kernel, Greg Kroah-Hartman
Cc: Rob Herring, Kumar Gala, Mark Brown, s.hauer, linux-api,
linux-kernel, devicetree, linux-arm-msm, arnd, sboyd,
pantelis.antoniou, mporter, stefan.wahren, wxt,
Srinivas Kandagatla
In-Reply-To: <1436521427-10568-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.
On MSM parts there are some efuses (called qfprom) these fuses store
things like calibration data, speed bins.. etc. Drivers like cpufreq,
thermal sensors would read out this data for configuring the driver.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
drivers/nvmem/Kconfig | 15 +++++++++
drivers/nvmem/Makefile | 4 +++
drivers/nvmem/qfprom.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 106 insertions(+)
create mode 100644 drivers/nvmem/qfprom.c
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index de90c82..fa85805 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -11,3 +11,18 @@ menuconfig NVMEM
will be called nvmem_core.
If unsure, say no.
+
+if NVMEM
+
+config QCOM_QFPROM
+ tristate "QCOM QFPROM Support"
+ depends on ARCH_QCOM || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ Say y here to enable QFPROM support. The QFPROM provides access
+ functions for QFPROM data to rest of the drivers via nvmem interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem_qfprom.
+
+endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 6df2c69..ff44fe9 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -4,3 +4,7 @@
obj-$(CONFIG_NVMEM) += nvmem_core.o
nvmem_core-y := core.o
+
+# Devices
+obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
+nvmem_qfprom-y := qfprom.o
diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c
new file mode 100644
index 0000000..0e22a03
--- /dev/null
+++ b/drivers/nvmem/qfprom.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+static struct regmap_config qfprom_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .reg_stride = 1,
+};
+
+static struct nvmem_config econfig = {
+ .name = "qfprom",
+ .owner = THIS_MODULE,
+};
+
+static int qfprom_remove(struct platform_device *pdev)
+{
+ struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+ return nvmem_unregister(nvmem);
+}
+
+static int qfprom_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct nvmem_device *nvmem;
+ struct regmap *regmap;
+ void __iomem *base;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ qfprom_regmap_config.max_register = resource_size(res) - 1;
+
+ regmap = devm_regmap_init_mmio(dev, base, &qfprom_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "regmap init failed\n");
+ return PTR_ERR(regmap);
+ }
+ econfig.dev = dev;
+ nvmem = nvmem_register(&econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ platform_set_drvdata(pdev, nvmem);
+
+ return 0;
+}
+
+static const struct of_device_id qfprom_of_match[] = {
+ { .compatible = "qcom,qfprom",},
+ {/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+ .probe = qfprom_probe,
+ .remove = qfprom_remove,
+ .driver = {
+ .name = "qcom,qfprom",
+ .of_match_table = qfprom_of_match,
+ },
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v7 5/9] Documentation: nvmem: add nvmem api level and how-to doc
From: Srinivas Kandagatla @ 2015-07-10 9:45 UTC (permalink / raw)
To: linux-arm-kernel, Greg Kroah-Hartman
Cc: Rob Herring, Kumar Gala, Mark Brown, s.hauer, linux-api,
linux-kernel, devicetree, linux-arm-msm, arnd, sboyd,
pantelis.antoniou, mporter, stefan.wahren, wxt,
Srinivas Kandagatla
In-Reply-To: <1436521427-10568-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch add basic how-to and api summary documentation for simple
NVMEM framework.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
Documentation/nvmem/nvmem.txt | 152 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 152 insertions(+)
create mode 100644 Documentation/nvmem/nvmem.txt
diff --git a/Documentation/nvmem/nvmem.txt b/Documentation/nvmem/nvmem.txt
new file mode 100644
index 0000000..b074b71
--- /dev/null
+++ b/Documentation/nvmem/nvmem.txt
@@ -0,0 +1,152 @@
+ NVMEM SUBSYSTEM
+ Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+
+This document explains the Simple NVMEM Framework along with the APIs provided,
+and how-to-use.
+
+1. Introduction
+===============
+*NVMEM* is the abbreviation for Non Volatile Memory layer. It is used to
+retrieve configuration or SOC or Device specific data from a non volatile memories
+like eeprom, efuses and so on.
+
+Up until now, NVMEM drivers like eeprom were stored in drivers/misc, where they
+all had to duplicate pretty much the same code to register a sysfs file, allow
+in-kernel users to access the content of the devices they were driving, etc.
+
+This was also a problem as far as other in-kernel users were involved, since
+the solutions used were pretty much different from on driver to another, there
+was a rather big abstraction leak.
+
+Introduction of this framework aims at solving this. It also introduces DT
+representation for consumer devices to go get the data they require (MAC
+Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
+This framework is based on regmap, so that most of the abstraction
+available in regmap can be reused, across multiple types of buses.
+
+NVMEM Providers
++++++++++++++++
+
+NVMEM provider refers to an entity that implements methods to initialize, read
+and write the non-volatile memory.
+
+2. Registering/Unregistering the NVMEM provider
+===============================================
+
+A NVMEM provider can register with NVMEM core by suppling relevant
+nvmem configuration to nvmem_register(), on success core would return a valid
+nvmem_device pointer.
+
+nvmem_unregister(nvmem) is used to unregister the already registered provider.
+
+For example for simple qfprom case:
+
+static struct nvmem_config econfig = {
+ .name = "qfprom",
+ .owner = THIS_MODULE,
+};
+
+static int qfprom_probe(struct platform_device *pdev)
+{
+ ...
+ econfig.dev = &pdev->dev;
+ nvmem = nvmem_register(&econfig);
+ ...
+}
+
+It is mandatory that the NVMEM provider has a regmap associated with its
+struct device.
+
+NVMEM Consumers
++++++++++++++++
+
+NVMEM consumers are the entities which make use of the NVMEM provider to
+read/write into NVMEM.
+
+3. NVMEM cell based consumer APIs.
+=================================
+
+NVMEM cells are the data entries/fields in the NVMEM.
+The NVMEM framework provides 3 APIs to read/write NVMEM cells.
+
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
+struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name);
+
+void nvmem_cell_put(struct nvmem_cell *cell);
+void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
+
+void *nvmem_cell_read(struct nvmem_cell *cell, ssize_t *len);
+int nvmem_cell_write(struct nvmem_cell *cell, void *buf, ssize_t len);
+
+*nvmem_cell_get() apis will get a reference to nvmem cell for a given id,
+and nvmem_cell_read/write() can then directly read or write to the cell.
+Once the usage of the cell is finished the consumer should call *nvmem_cell_put()
+to free all the allocation memory for the cell.
+
+4. Direct NVMEM device based consumer APIs.
+==========================================
+
+In some instances it is necessary to directly read/write the NVMEM.
+To facilitate such consumers NVMEM framework provides below apis.
+
+struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
+struct nvmem_device *devm_nvmem_device_get(struct device *dev,
+ const char *name);
+void nvmem_device_put(struct nvmem_device *nvmem);
+int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
+ size_t bytes, void *buf);
+int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
+ size_t bytes, void *buf);
+int nvmem_device_cell_read(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info, void *buf);
+int nvmem_device_cell_write(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info, void *buf);
+
+Before the consumers can read/write NVMEM directly, it should get hold
+of nvmem_controller from one of the *nvmem_device_get() api.
+
+Difference between these apis and cell based apis is that these apis
+always take nvmem_device as parameter.
+
+5. Releasing a reference to the NVMEM
+=====================================
+
+When the consumers no longer needs the NVMEM, it has to release the reference
+to the NVMEM it has obtained using the APIs mentioned in the above section.
+NVMEM framework provides 2 APIs to release a reference to the NVMEM.
+
+void nvmem_cell_put(struct nvmem_cell *cell);
+void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
+void nvmem_device_put(struct nvmem_device *nvmem);
+void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem);
+
+Both these APIs are used to release a reference to the NVMEM and
+devm_nvmem_cell_put and devm_nvmem_device_put destroys the devres associated
+with this NVMEM.
+
+Userspace
++++++++++
+
+6. Userspace binary interface.
+==============================
+
+Userspace can read/write the raw NVMEM file located at
+/sys/bus/nvmem/devices/*/nvmem
+
+ex:
+
+hexdump /sys/bus/nvmem/devices/qfprom0/nvmem
+
+0000000 0000 0000 0000 0000 0000 0000 0000 0000
+*
+00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
+0000000 0000 0000 0000 0000 0000 0000 0000 0000
+...
+*
+0001000
+
+7. DeviceTree Binding
+=====================
+
+The documentation for NVMEM dt binding can be found @
+Documentation/devicetree/bindings/nvmem/nvmem.txt
--
1.9.1
^ permalink raw reply related
* [PATCH v7 4/9] nvmem: Add bindings for simple nvmem framework
From: Srinivas Kandagatla @ 2015-07-10 9:45 UTC (permalink / raw)
To: linux-arm-kernel, Greg Kroah-Hartman
Cc: Rob Herring, Kumar Gala, Mark Brown, s.hauer, linux-api,
linux-kernel, devicetree, linux-arm-msm, arnd, sboyd,
pantelis.antoniou, mporter, stefan.wahren, wxt,
Srinivas Kandagatla, Maxime Ripard
In-Reply-To: <1436521427-10568-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds bindings for simple nvmem framework which allows nvmem
consumers to talk to nvmem providers to get access to nvmem cell data.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
Documentation/devicetree/bindings/nvmem/nvmem.txt | 85 +++++++++++++++++++++++
1 file changed, 85 insertions(+)
create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.txt
diff --git a/Documentation/devicetree/bindings/nvmem/nvmem.txt b/Documentation/devicetree/bindings/nvmem/nvmem.txt
new file mode 100644
index 0000000..849f1e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/nvmem.txt
@@ -0,0 +1,85 @@
+= NVMEM(Non Volatile Memory) Data Device Tree Bindings =
+
+This binding is intended to represent the location of hardware
+configuration data stored in NVMEMs like eeprom, efuses and so on.
+
+On a significant proportion of boards, the manufacturer has stored
+some data on NVMEM, for the OS to be able to retrieve these information
+and act upon it. Obviously, the OS has to know about where to retrieve
+these data from, and where they are stored on the storage device.
+
+This document is here to document this.
+
+= Data providers =
+Contains bindings specific to provider drivers and data cells as children
+of this node.
+
+Optional properties:
+ read-only: Mark the provider as read only.
+
+= Data cells =
+These are the child nodes of the provider which contain data cell
+information like offset and size in nvmem provider.
+
+Required properties:
+reg: specifies the offset in byte within that storage device, start bit
+ in the byte and the length in bytes of the data we care about.
+ There could be more than one offset-length pairs in this property.
+
+Optional properties:
+
+bit-offset: specifies the offset in bit within the address range specified
+ by reg property. Can take values from 0-7.
+nbits: specifies number of bits this cell occupies starting from bit-offset.
+
+For example:
+
+ /* Provider */
+ qfprom: qfprom@00700000 {
+ ...
+
+ /* Data cells */
+ tsens_calibration: calib@404 {
+ reg = <0x404 0x10>;
+ };
+
+ tsens_calibration_bckp: calib_bckp@504 {
+ reg = <0x504 0x11>;
+ bit-offset = 6;
+ nbits = 128;
+ };
+
+ pvs_version: pvs-version@6 {
+ reg = <0x6 0x2>
+ bit-offset = 7;
+ nbits = 2;
+ };
+
+ speed_bin: speed-bin@c{
+ reg = <0xc 0x1>;
+ bit-offset = 2;
+ nbits = 3;
+
+ };
+ ...
+ };
+
+= Data consumers =
+Are device nodes which consume nvmem data cells/providers.
+
+Required-properties:
+nvmem-cells: list of phandle to the nvmem data cells.
+nvmem-cell-names: names for the each nvmem-cells specified. Required if
+ nvmem-cells is used.
+
+Optional-properties:
+nvmem : list of phandles to nvmem providers.
+nvmem-names: names for the each nvmem provider. required if nvmem is used.
+
+For example:
+
+ tsens {
+ ...
+ nvmem-cells = <&tsens_calibration>;
+ nvmem-cell-names = "calibration";
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v7 3/9] nvmem: Add nvmem_device based consumer apis.
From: Srinivas Kandagatla @ 2015-07-10 9:45 UTC (permalink / raw)
To: linux-arm-kernel, Greg Kroah-Hartman
Cc: stefan.wahren, devicetree, arnd, linux-api, s.hauer, sboyd,
linux-kernel, Rob Herring, pantelis.antoniou, Mark Brown,
Srinivas Kandagatla, Kumar Gala, mporter, linux-arm-msm, wxt
In-Reply-To: <1436521427-10568-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds read/write apis which are based on nvmem_device. It is
common that the drivers like omap cape manager or qcom cpr driver to
access bytes directly at particular offset in the eeprom and not from
nvmem cell info in DT. These driver would need to get access to the nvmem
directly, which is what these new APIS provide.
These wrapper apis would help such users to avoid code duplication in
there drivers and also avoid them reading a big eeprom blob and parsing
it internally in there driver.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
drivers/nvmem/core.c | 259 +++++++++++++++++++++++++++++++++++++++++
include/linux/nvmem-consumer.h | 79 +++++++++++++
include/linux/nvmem-provider.h | 10 +-
3 files changed, 340 insertions(+), 8 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index f429ad4..92df617 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -417,6 +417,149 @@ static void __nvmem_device_put(struct nvmem_device *nvmem)
mutex_unlock(&nvmem_mutex);
}
+static int nvmem_match(struct device *dev, void *data)
+{
+ return !strcmp(dev_name(dev), data);
+}
+
+static struct nvmem_device *nvmem_find(const char *name)
+{
+ struct device *d;
+
+ d = bus_find_device(&nvmem_bus_type, NULL, (void *)name, nvmem_match);
+
+ return d ? to_nvmem_device(d) : NULL;
+}
+
+#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
+/**
+ * of_nvmem_device_get() - Get nvmem device from a given id
+ *
+ * @dev node: Device tree node that uses the nvmem device
+ * @id: nvmem name from nvmem-names property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct nvmem_device.
+ */
+struct nvmem_device *of_nvmem_device_get(struct device_node *np, const char *id)
+{
+
+ struct device_node *nvmem_np;
+ int index;
+
+ index = of_property_match_string(np, "nvmem-names", id);
+
+ nvmem_np = of_parse_phandle(np, "nvmem", index);
+ if (!nvmem_np)
+ return ERR_PTR(-EINVAL);
+
+ return __nvmem_device_get(nvmem_np, NULL, NULL);
+
+}
+EXPORT_SYMBOL_GPL(of_nvmem_device_get);
+#endif
+
+/**
+ * nvmem_device_get() - Get nvmem device from a given id
+ *
+ * @dev : Device that uses the nvmem device
+ * @id: nvmem name from nvmem-names property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct nvmem_device.
+ */
+struct nvmem_device *nvmem_device_get(struct device *dev, const char *dev_name)
+{
+ if (dev->of_node) { /* try dt first */
+ struct nvmem_device *nvmem;
+
+ nvmem = of_nvmem_device_get(dev->of_node, dev_name);
+
+ if (!IS_ERR(nvmem) || PTR_ERR(nvmem) == -EPROBE_DEFER)
+ return nvmem;
+
+ }
+
+ return nvmem_find(dev_name);
+
+}
+EXPORT_SYMBOL_GPL(nvmem_device_get);
+
+static int devm_nvmem_device_match(struct device *dev, void *res, void *data)
+{
+ struct nvmem_device **nvmem = res;
+
+ if (!nvmem || !*nvmem) {
+ WARN_ON(!nvmem || !*nvmem);
+ return 0;
+ }
+ return *nvmem == data;
+}
+
+static void devm_nvmem_device_release(struct device *dev, void *res)
+{
+ nvmem_device_put(*(struct nvmem_device **)res);
+}
+
+/**
+ * devm_nvmem_device_put() - put alredy got nvmem device
+ *
+ * @nvmem: pointer to nvmem device allocated by devm_nvmem_cell_get(),
+ * that needs to be released.
+ */
+void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem)
+{
+ int ret;
+
+ ret = devres_release(dev, devm_nvmem_device_release,
+ devm_nvmem_device_match, nvmem);
+
+ WARN_ON(ret);
+
+}
+EXPORT_SYMBOL_GPL(devm_nvmem_device_put);
+
+/**
+ * nvmem_device_put() - put alredy got nvmem device
+ *
+ * @nvmem: pointer to nvmem device that needs to be released.
+ */
+void nvmem_device_put(struct nvmem_device *nvmem)
+{
+ __nvmem_device_put(nvmem);
+}
+EXPORT_SYMBOL_GPL(nvmem_device_put);
+
+/**
+ * devm_nvmem_device_get() - Get nvmem cell of device form a given id
+ *
+ * @dev node: Device tree node that uses the nvmem cell
+ * @id: nvmem name in nvmems property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct nvmem_cell. The nvmem_cell will be freed by the
+ * automatically once the device is freed.
+ */
+struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
+{
+ struct nvmem_device **ptr, *nvmem;
+
+ ptr = devres_alloc(devm_nvmem_device_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ nvmem = nvmem_device_get(dev, id);
+ if (!IS_ERR(nvmem)) {
+ *ptr = nvmem;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return nvmem;
+}
+EXPORT_SYMBOL_GPL(devm_nvmem_device_get);
+
static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
{
struct nvmem_cell *cell = NULL;
@@ -781,6 +924,122 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
}
EXPORT_SYMBOL_GPL(nvmem_cell_write);
+/**
+ * nvmem_device_cell_read() - Read a given nvmem device and cell
+ *
+ * @nvmem: nvmem device to read from.
+ * @info: nvmem cell info to be read.
+ * @buf: buffer pointer which will be populated on successful read.
+ *
+ * The return value would be length of successful bytes read on success
+ * and error code in error cases.
+ */
+ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info, void *buf)
+{
+ struct nvmem_cell cell;
+ int rc;
+ ssize_t len;
+
+ if (!nvmem || !nvmem->regmap)
+ return -EINVAL;
+
+ rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ rc = __nvmem_cell_read(nvmem, &cell, buf, &len);
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(nvmem_device_cell_read);
+
+/**
+ * nvmem_device_cell_write() - Write cell to a given nvmem device
+ *
+ * @nvmem: nvmem device to be written to.
+ * @info: nvmem cell info to be written
+ * @buf: buffer to be written to cell.
+ *
+ * The return value will be an length of bytes written or non zero on failure.
+ * */
+int nvmem_device_cell_write(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info, void *buf)
+{
+ struct nvmem_cell cell;
+ int rc;
+
+ if (!nvmem || !nvmem->regmap)
+ return -EINVAL;
+
+ rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell);
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ return nvmem_cell_write(&cell, buf, cell.bytes);
+}
+EXPORT_SYMBOL_GPL(nvmem_device_cell_write);
+
+/**
+ * nvmem_device_read() - Read from a given nvmem device
+ *
+ * @nvmem: nvmem device to read from.
+ * @offset: offset in nvmem device.
+ * @bytes: number of bytes to read.
+ * @buf: buffer pointer which will be populated on successful read.
+ *
+ * The return value would be length of successful bytes read on success
+ * and error code in error cases.
+ */
+int nvmem_device_read(struct nvmem_device *nvmem,
+ unsigned int offset,
+ size_t bytes, void *buf)
+{
+ int rc;
+
+ if (!nvmem || !nvmem->regmap)
+ return -EINVAL;
+
+ rc = regmap_raw_read(nvmem->regmap, offset, buf, bytes);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ return bytes;
+}
+EXPORT_SYMBOL_GPL(nvmem_device_read);
+
+/**
+ * nvmem_device_write() - Write cell to a given nvmem device
+ *
+ * @nvmem: nvmem device to be written to.
+ * @offset: offset in nvmem device.
+ * @bytes: number of bytes to write.
+ * @buf: buffer to be written.
+ *
+ * The return value will be an length of bytes written or non zero on failure.
+ * */
+int nvmem_device_write(struct nvmem_device *nvmem,
+ unsigned int offset,
+ size_t bytes, void *buf)
+{
+ int rc;
+
+ if (!nvmem || !nvmem->regmap)
+ return -EINVAL;
+
+ rc = regmap_raw_write(nvmem->regmap, offset, buf, bytes);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+
+ return bytes;
+}
+EXPORT_SYMBOL_GPL(nvmem_device_write);
+
static int __init nvmem_init(void)
{
return bus_register(&nvmem_bus_type);
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index 90bf4c3..8aaaedf 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -16,6 +16,15 @@ struct device;
struct device_node;
/* consumer cookie */
struct nvmem_cell;
+struct nvmem_device;
+
+struct nvmem_cell_info {
+ const char *name;
+ unsigned int offset;
+ unsigned int bytes;
+ unsigned int bit_offset;
+ unsigned int nbits;
+};
#if IS_ENABLED(CONFIG_NVMEM)
@@ -27,6 +36,21 @@ void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len);
+/* direct nvmem device read/write interface */
+struct nvmem_device *nvmem_device_get(struct device *dev, const char *name);
+struct nvmem_device *devm_nvmem_device_get(struct device *dev,
+ const char *name);
+void nvmem_device_put(struct nvmem_device *nvmem);
+void devm_nvmem_device_put(struct device *dev, struct nvmem_device *nvmem);
+int nvmem_device_read(struct nvmem_device *nvmem, unsigned int offset,
+ size_t bytes, void *buf);
+int nvmem_device_write(struct nvmem_device *nvmem, unsigned int offset,
+ size_t bytes, void *buf);
+ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info, void *buf);
+int nvmem_device_cell_write(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info, void *buf);
+
#else
static inline struct nvmem_cell *nvmem_cell_get(struct device *dev,
@@ -60,17 +84,72 @@ static inline int nvmem_cell_write(struct nvmem_cell *cell,
{
return -ENOSYS;
}
+
+static inline struct nvmem_device *nvmem_device_get(struct device *dev,
+ const char *name)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct nvmem_device *devm_nvmem_device_get(struct device *dev,
+ const char *name)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline void nvmem_device_put(struct nvmem_device *nvmem)
+{
+}
+
+static inline void devm_nvmem_device_put(struct device *dev,
+ struct nvmem_device *nvmem)
+{
+}
+
+static inline ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info,
+ void *buf)
+{
+ return -ENOSYS;
+}
+
+static inline int nvmem_device_cell_write(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info,
+ void *buf)
+{
+ return -ENOSYS;
+}
+
+static inline int nvmem_device_read(struct nvmem_device *nvmem,
+ unsigned int offset, size_t bytes, void *buf)
+{
+ return -ENOSYS;
+}
+
+static inline int nvmem_device_write(struct nvmem_device *nvmem,
+ unsigned int offset, size_t bytes, void *buf)
+{
+ return -ENOSYS;
+}
#endif /* CONFIG_NVMEM */
#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
const char *name);
+struct nvmem_device *of_nvmem_device_get(struct device_node *np,
+ const char *name);
#else
static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
const char *name)
{
return ERR_PTR(-ENOSYS);
}
+
+static inline struct nvmem_device *of_nvmem_device_get(struct device_node *np,
+ const char *name)
+{
+ return ERR_PTR(-ENOSYS);
+}
#endif /* CONFIG_NVMEM && CONFIG_OF */
#endif /* ifndef _LINUX_NVMEM_CONSUMER_H */
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index f589d3b..74eed42 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -12,15 +12,9 @@
#ifndef _LINUX_NVMEM_PROVIDER_H
#define _LINUX_NVMEM_PROVIDER_H
-struct nvmem_device;
+#include <linux/nvmem-consumer.h>
-struct nvmem_cell_info {
- const char *name;
- int offset;
- int bytes;
- int bit_offset;
- int nbits;
-};
+struct nvmem_device;
struct nvmem_config {
struct device *dev;
--
1.9.1
^ permalink raw reply related
* [PATCH v7 2/9] nvmem: Add a simple NVMEM framework for consumers
From: Srinivas Kandagatla @ 2015-07-10 9:44 UTC (permalink / raw)
To: linux-arm-kernel, Greg Kroah-Hartman
Cc: Rob Herring, Kumar Gala, Mark Brown, s.hauer, linux-api,
linux-kernel, devicetree, linux-arm-msm, arnd, sboyd,
pantelis.antoniou, mporter, stefan.wahren, wxt,
Srinivas Kandagatla, Maxime Ripard
In-Reply-To: <1436521427-10568-1-git-send-email-srinivas.kandagatla@linaro.org>
This patch adds just consumers part of the framework just to enable easy
review.
Up until now, nvmem drivers were stored in drivers/misc, where they all
had to duplicate pretty much the same code to register a sysfs file,
allow in-kernel users to access the content of the devices they were
driving, etc.
This was also a problem as far as other in-kernel users were involved,
since the solutions used were pretty much different from on driver to
another, there was a rather big abstraction leak.
This introduction of this framework aims at solving this. It also
introduces DT representation for consumer devices to go get the data they
require (MAC Addresses, SoC/Revision ID, part numbers, and so on) from
the nvmems.
Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[Maxime Ripard: intial version of the framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
drivers/nvmem/core.c | 424 ++++++++++++++++++++++++++++++++++++++++-
include/linux/nvmem-consumer.h | 76 ++++++++
2 files changed, 498 insertions(+), 2 deletions(-)
create mode 100644 include/linux/nvmem-consumer.h
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index a779ad1..f429ad4 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -15,14 +15,15 @@
*/
#include <linux/device.h>
-#include <linux/nvmem-provider.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/init.h>
-#include <linux/regmap.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/nvmem-provider.h>
#include <linux/of.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
struct nvmem_device {
@@ -334,6 +335,7 @@ struct nvmem_device *nvmem_register(struct nvmem_config *config)
if (config->cells)
nvmem_add_cells(nvmem, config);
+
return nvmem;
}
EXPORT_SYMBOL_GPL(nvmem_register);
@@ -361,6 +363,424 @@ int nvmem_unregister(struct nvmem_device *nvmem)
}
EXPORT_SYMBOL_GPL(nvmem_unregister);
+static struct nvmem_device *__nvmem_device_get(struct device_node *np,
+ struct nvmem_cell **cellp,
+ const char *cell_id)
+{
+ struct nvmem_device *nvmem = NULL;
+
+ mutex_lock(&nvmem_mutex);
+
+ if (np) {
+ nvmem = of_nvmem_find(np);
+ if (!nvmem) {
+ mutex_unlock(&nvmem_mutex);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+ } else {
+ struct nvmem_cell *cell = nvmem_find_cell(cell_id);
+
+ if (cell) {
+ nvmem = cell->nvmem;
+ *cellp = cell;
+ }
+
+ if (!nvmem) {
+ mutex_unlock(&nvmem_mutex);
+ return ERR_PTR(-ENOENT);
+ }
+ }
+
+ nvmem->users++;
+ mutex_unlock(&nvmem_mutex);
+
+ if (!try_module_get(nvmem->owner)) {
+ dev_err(&nvmem->dev,
+ "could not increase module refcount for cell %s\n",
+ nvmem->name);
+
+ mutex_lock(&nvmem_mutex);
+ nvmem->users--;
+ mutex_unlock(&nvmem_mutex);
+
+ return ERR_PTR(-EINVAL);
+ }
+
+ return nvmem;
+}
+
+static void __nvmem_device_put(struct nvmem_device *nvmem)
+{
+ module_put(nvmem->owner);
+ mutex_lock(&nvmem_mutex);
+ nvmem->users--;
+ mutex_unlock(&nvmem_mutex);
+}
+
+static struct nvmem_cell *nvmem_cell_get_from_list(const char *cell_id)
+{
+ struct nvmem_cell *cell = NULL;
+ struct nvmem_device *nvmem;
+
+ nvmem = __nvmem_device_get(NULL, &cell, cell_id);
+ if (IS_ERR(nvmem))
+ return ERR_CAST(nvmem);
+
+
+ return cell;
+
+}
+
+#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
+/**
+ * of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
+ *
+ * @dev node: Device tree node that uses the nvmem cell
+ * @id: nvmem cell name from nvmem-cell-names property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct nvmem_cell. The nvmem_cell will be freed by the
+ * nvmem_cell_put().
+ */
+struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
+ const char *name)
+{
+ struct device_node *cell_np, *nvmem_np;
+ struct nvmem_cell *cell;
+ struct nvmem_device *nvmem;
+ const __be32 *addr;
+ int rval, len, index;
+
+ index = of_property_match_string(np, "nvmem-cell-names", name);
+
+ cell_np = of_parse_phandle(np, "nvmem-cells", index);
+ if (!cell_np)
+ return ERR_PTR(-EINVAL);
+
+ nvmem_np = of_get_next_parent(cell_np);
+ if (!nvmem_np)
+ return ERR_PTR(-EINVAL);
+
+ nvmem = __nvmem_device_get(nvmem_np, NULL, NULL);
+ if (IS_ERR(nvmem))
+ return ERR_CAST(nvmem);
+
+ addr = of_get_property(cell_np, "reg", &len);
+ if (!addr || (len < 2 * sizeof(int))) {
+ dev_err(&nvmem->dev, "nvmem: invalid reg on %s\n",
+ cell_np->full_name);
+ rval = -EINVAL;
+ goto err_mem;
+ }
+
+ cell = kzalloc(sizeof(*cell), GFP_KERNEL);
+ if (!cell) {
+ rval = -ENOMEM;
+ goto err_mem;
+ }
+
+ cell->nvmem = nvmem;
+ cell->offset = be32_to_cpup(addr++);
+ cell->bytes = be32_to_cpup(addr);
+ cell->name = cell_np->name;
+
+ of_property_read_u32(cell_np, "bit-offset", &cell->bit_offset);
+ of_property_read_u32(cell_np, "nbits", &cell->nbits);
+
+ if (cell->nbits)
+ cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
+ BITS_PER_BYTE);
+
+ if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
+ dev_err(&nvmem->dev,
+ "cell %s unaligned to nvmem stride %d\n",
+ cell->name, nvmem->stride);
+ rval = -EINVAL;
+ goto err_sanity;
+ }
+
+ nvmem_cell_add(cell);
+
+ return cell;
+
+err_sanity:
+ kfree(cell);
+
+err_mem:
+ __nvmem_device_put(nvmem);
+
+ return ERR_PTR(rval);
+
+}
+EXPORT_SYMBOL_GPL(of_nvmem_cell_get);
+#endif
+
+/**
+ * nvmem_cell_get() - Get nvmem cell of device form a given cell name
+ *
+ * @dev node: Device tree node that uses the nvmem cell
+ * @id: nvmem cell name to get.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct nvmem_cell. The nvmem_cell will be freed by the
+ * nvmem_cell_put().
+ */
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id)
+{
+ struct nvmem_cell *cell;
+
+ if (dev->of_node) { /* try dt first */
+ cell = of_nvmem_cell_get(dev->of_node, cell_id);
+ if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER)
+ return cell;
+ }
+
+ return nvmem_cell_get_from_list(cell_id);
+
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_get);
+
+static void devm_nvmem_cell_release(struct device *dev, void *res)
+{
+ nvmem_cell_put(*(struct nvmem_cell **)res);
+}
+
+/**
+ * devm_nvmem_cell_get() - Get nvmem cell of device form a given id
+ *
+ * @dev node: Device tree node that uses the nvmem cell
+ * @id: nvmem id in nvmem-names property.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct nvmem_cell. The nvmem_cell will be freed by the
+ * automatically once the device is freed.
+ */
+struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *id)
+{
+ struct nvmem_cell **ptr, *cell;
+
+ ptr = devres_alloc(devm_nvmem_cell_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ cell = nvmem_cell_get(dev, id);
+ if (!IS_ERR(cell)) {
+ *ptr = cell;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return cell;
+}
+EXPORT_SYMBOL_GPL(devm_nvmem_cell_get);
+
+static int devm_nvmem_cell_match(struct device *dev, void *res, void *data)
+{
+ struct nvmem_cell **c = res;
+
+ if (!c || !*c) {
+ WARN_ON(!c || !*c);
+ return 0;
+ }
+ return *c == data;
+}
+
+/**
+ * devm_nvmem_cell_put() - Release previously allocated nvmem cell
+ * from devm_nvmem_cell_get.
+ *
+ * @cell: Previously allocated nvmem cell by devm_nvmem_cell_get()
+ */
+void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell)
+{
+ int ret;
+
+ ret = devres_release(dev, devm_nvmem_cell_release,
+ devm_nvmem_cell_match, cell);
+
+ WARN_ON(ret);
+}
+EXPORT_SYMBOL(devm_nvmem_cell_put);
+
+/**
+ * nvmem_cell_put() - Release previously allocated nvmem cell.
+ *
+ * @cell: Previously allocated nvmem cell by nvmem_cell_get()
+ */
+void nvmem_cell_put(struct nvmem_cell *cell)
+{
+ struct nvmem_device *nvmem = cell->nvmem;
+
+ __nvmem_device_put(nvmem);
+ nvmem_cell_drop(cell);
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_put);
+
+static inline void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell,
+ void *buf)
+{
+ u8 *p, *b;
+ int i, bit_offset = cell->bit_offset;
+
+ p = b = buf;
+ if (bit_offset) {
+ /* First shift */
+ *b++ >>= bit_offset;
+
+ /* setup rest of the bytes if any */
+ for (i = 1; i < cell->bytes; i++) {
+ /* Get bits from next byte and shift them towards msb */
+ *p |= *b << (BITS_PER_BYTE - bit_offset);
+
+ p = b;
+ *b++ >>= bit_offset;
+ }
+
+ /* result fits in less bytes */
+ if (cell->bytes != DIV_ROUND_UP(cell->nbits, BITS_PER_BYTE))
+ *p-- = 0;
+ }
+ /* clear msb bits if any leftover in the last byte */
+ *p &= GENMASK((cell->nbits%BITS_PER_BYTE) - 1, 0);
+}
+
+static int __nvmem_cell_read(struct nvmem_device *nvmem,
+ struct nvmem_cell *cell,
+ void *buf, size_t *len)
+{
+ int rc;
+
+ rc = regmap_raw_read(nvmem->regmap, cell->offset, buf, cell->bytes);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ /* shift bits in-place */
+ if (cell->bit_offset || cell->bit_offset)
+ nvmem_shift_read_buffer_in_place(cell, buf);
+
+ *len = cell->bytes;
+
+ return 0;
+}
+/**
+ * nvmem_cell_read() - Read a given nvmem cell
+ *
+ * @cell: nvmem cell to be read.
+ * @len: pointer to length of cell which will be populated on successful read.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a char * bufffer. The buffer should be freed by the consumer with a
+ * kfree().
+ */
+void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
+{
+ struct nvmem_device *nvmem = cell->nvmem;
+ u8 *buf;
+ int rc;
+
+ if (!nvmem || !nvmem->regmap)
+ return ERR_PTR(-EINVAL);
+
+ buf = kzalloc(cell->bytes, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ rc = __nvmem_cell_read(nvmem, cell, buf, len);
+ if (IS_ERR_VALUE(rc)) {
+ kfree(buf);
+ return ERR_PTR(rc);
+ }
+
+ return buf;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_read);
+
+static inline void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell,
+ u8 *_buf, int len)
+{
+ struct nvmem_device *nvmem = cell->nvmem;
+ int i, rc, nbits, bit_offset = cell->bit_offset;
+ u8 v, *p, *buf, *b, pbyte, pbits;
+
+ nbits = cell->nbits;
+ buf = kzalloc(cell->bytes, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(buf, _buf, len);
+ p = b = buf;
+
+ if (bit_offset) {
+ pbyte = *b;
+ *b <<= bit_offset;
+
+ /* setup the first byte with lsb bits from nvmem */
+ rc = regmap_raw_read(nvmem->regmap, cell->offset, &v, 1);
+ *b++ |= GENMASK(bit_offset - 1, 0) & v;
+
+ /* setup rest of the byte if any */
+ for (i = 1; i < cell->bytes; i++) {
+ /* Get last byte bits and shift them towards lsb */
+ pbits = pbyte >> (BITS_PER_BYTE - 1 - bit_offset);
+ pbyte = *b;
+ p = b;
+ *b <<= bit_offset;
+ *b++ |= pbits;
+ }
+ }
+
+ /* if it's not end on byte boundary */
+ if ((nbits + bit_offset) % BITS_PER_BYTE) {
+ /* setup the last byte with msb bits from nvmem */
+ rc = regmap_raw_read(nvmem->regmap,
+ cell->offset + cell->bytes - 1, &v, 1);
+ *p |= GENMASK(7, (nbits + bit_offset) % BITS_PER_BYTE) & v;
+
+ }
+
+ return buf;
+}
+
+/**
+ * nvmem_cell_write() - Write to a given nvmem cell
+ *
+ * @cell: nvmem cell to be written.
+ * @buf: Buffer to be written.
+ * @len: length of buffer to be written to nvmem cell.
+ *
+ * The return value will be an length of bytes written or non zero on failure.
+ */
+int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len)
+{
+ struct nvmem_device *nvmem = cell->nvmem;
+ int rc;
+ void *wbuf = buf;
+
+ if (!nvmem || !nvmem->regmap || nvmem->read_only ||
+ (cell->bit_offset == 0 && len != cell->bytes))
+ return -EINVAL;
+
+ if (cell->bit_offset || cell->nbits) {
+ wbuf = nvmem_cell_prepare_write_buffer(cell, buf, len);
+ if (IS_ERR(wbuf))
+ return PTR_ERR(wbuf);
+ }
+
+ rc = regmap_raw_write(nvmem->regmap, cell->offset, wbuf, cell->bytes);
+
+ /* free the tmp buffer */
+ if (cell->bit_offset)
+ kfree(wbuf);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_write);
+
static int __init nvmem_init(void)
{
return bus_register(&nvmem_bus_type);
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
new file mode 100644
index 0000000..90bf4c3
--- /dev/null
+++ b/include/linux/nvmem-consumer.h
@@ -0,0 +1,76 @@
+/*
+ * nvmem framework consumer.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_NVMEM_CONSUMER_H
+#define _LINUX_NVMEM_CONSUMER_H
+
+struct device;
+struct device_node;
+/* consumer cookie */
+struct nvmem_cell;
+
+#if IS_ENABLED(CONFIG_NVMEM)
+
+/* Cell based interface */
+struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
+struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name);
+void nvmem_cell_put(struct nvmem_cell *cell);
+void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
+void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
+int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len);
+
+#else
+
+static inline struct nvmem_cell *nvmem_cell_get(struct device *dev,
+ const char *name)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct nvmem_cell *devm_nvmem_cell_get(struct device *dev,
+ const char *name)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline void devm_nvmem_cell_put(struct device *dev,
+ struct nvmem_cell *cell)
+{
+
+}
+static inline void nvmem_cell_put(struct nvmem_cell *cell)
+{
+}
+
+static inline char *nvmem_cell_read(struct nvmem_cell *cell, size_t *len)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline int nvmem_cell_write(struct nvmem_cell *cell,
+ const char *buf, size_t len)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_NVMEM */
+
+#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
+struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
+ const char *name);
+#else
+static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
+ const char *name)
+{
+ return ERR_PTR(-ENOSYS);
+}
+#endif /* CONFIG_NVMEM && CONFIG_OF */
+
+#endif /* ifndef _LINUX_NVMEM_CONSUMER_H */
--
1.9.1
^ permalink raw reply related
* [PATCH v7 1/9] nvmem: Add a simple NVMEM framework for nvmem providers
From: Srinivas Kandagatla @ 2015-07-10 9:44 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Greg Kroah-Hartman
Cc: Rob Herring, Kumar Gala, Mark Brown,
s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w,
mporter-OWPKS81ov/FWk0Htik3J/w, stefan.wahren-eS4NqCHxEME,
wxt-TNX95d0MmH7DzftRWevZcw, Srinivas Kandagatla, Maxime Ripard
In-Reply-To: <1436521427-10568-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
This patch adds just providers part of the framework just to enable easy
review.
Up until now, NVMEM drivers like eeprom were stored in drivers/misc,
where they all had to duplicate pretty much the same code to register
a sysfs file, allow in-kernel users to access the content of the devices
they were driving, etc.
This was also a problem as far as other in-kernel users were involved,
since the solutions used were pretty much different from on driver to
another, there was a rather big abstraction leak.
This introduction of this framework aims at solving this. It also
introduces DT representation for consumer devices to go get the data
they require (MAC Addresses, SoC/Revision ID, part numbers, and so on)
from the nvmems.
Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.
Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
[Maxime Ripard: intial version of eeprom framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/nvmem/Kconfig | 13 ++
drivers/nvmem/Makefile | 6 +
drivers/nvmem/core.c | 380 +++++++++++++++++++++++++++++++++++++++++
include/linux/nvmem-provider.h | 54 ++++++
6 files changed, 456 insertions(+)
create mode 100644 drivers/nvmem/Kconfig
create mode 100644 drivers/nvmem/Makefile
create mode 100644 drivers/nvmem/core.c
create mode 100644 include/linux/nvmem-provider.h
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 6e973b8..4e2e6aa 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -184,4 +184,6 @@ source "drivers/android/Kconfig"
source "drivers/nvdimm/Kconfig"
+source "drivers/nvmem/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index b64b49f..4c270f5 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -165,3 +165,4 @@ obj-$(CONFIG_RAS) += ras/
obj-$(CONFIG_THUNDERBOLT) += thunderbolt/
obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/
obj-$(CONFIG_ANDROID) += android/
+obj-$(CONFIG_NVMEM) += nvmem/
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
new file mode 100644
index 0000000..de90c82
--- /dev/null
+++ b/drivers/nvmem/Kconfig
@@ -0,0 +1,13 @@
+menuconfig NVMEM
+ tristate "NVMEM Support"
+ select REGMAP
+ help
+ Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES...
+
+ This framework is designed to provide a generic interface to NVMEM
+ from both the Linux Kernel and the userspace.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem_core.
+
+ If unsure, say no.
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
new file mode 100644
index 0000000..6df2c69
--- /dev/null
+++ b/drivers/nvmem/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for nvmem drivers.
+#
+
+obj-$(CONFIG_NVMEM) += nvmem_core.o
+nvmem_core-y := core.o
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
new file mode 100644
index 0000000..a779ad1
--- /dev/null
+++ b/drivers/nvmem/core.c
@@ -0,0 +1,380 @@
+/*
+ * nvmem framework core.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/nvmem-provider.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+struct nvmem_device {
+ const char *name;
+ struct regmap *regmap;
+ struct module *owner;
+ struct device dev;
+ int stride;
+ int word_size;
+ int ncells;
+ int id;
+ int users;
+ size_t size;
+ bool read_only;
+};
+
+struct nvmem_cell {
+ const char *name;
+ int offset;
+ int bytes;
+ int bit_offset;
+ int nbits;
+ struct nvmem_device *nvmem;
+ struct list_head node;
+};
+
+static DEFINE_MUTEX(nvmem_mutex);
+static DEFINE_IDA(nvmem_ida);
+
+static LIST_HEAD(nvmem_cells);
+static DEFINE_MUTEX(nvmem_cells_mutex);
+
+#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
+
+static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t pos, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nvmem_device *nvmem = to_nvmem_device(dev);
+ int rc;
+
+ /* Stop the user from reading */
+ if (pos > nvmem->size)
+ return 0;
+
+ if (pos + count > nvmem->size)
+ count = nvmem->size - pos;
+
+ count = count/nvmem->word_size * nvmem->word_size;
+
+ rc = regmap_raw_read(nvmem->regmap, pos, buf, count);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ return count;
+}
+
+static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t pos, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nvmem_device *nvmem = to_nvmem_device(dev);
+ int rc;
+
+ /* Stop the user from writing */
+ if (pos > nvmem->size)
+ return 0;
+
+ if (pos + count > nvmem->size)
+ count = nvmem->size - pos;
+
+ count = count/nvmem->word_size * nvmem->word_size;
+
+ rc = regmap_raw_write(nvmem->regmap, pos, buf, count);
+
+ if (IS_ERR_VALUE(rc))
+ return rc;
+
+ return count;
+}
+
+/* default read/write permissions */
+static struct bin_attribute bin_attr_rw_nvmem = {
+ .attr = {
+ .name = "nvmem",
+ .mode = S_IWUSR | S_IRUGO,
+ },
+ .read = bin_attr_nvmem_read,
+ .write = bin_attr_nvmem_write,
+};
+
+/* read only permission */
+static struct bin_attribute bin_attr_ro_nvmem = {
+ .attr = {
+ .name = "nvmem",
+ .mode = S_IRUGO,
+ },
+ .read = bin_attr_nvmem_read,
+};
+
+static void nvmem_release(struct device *dev)
+{
+ struct nvmem_device *nvmem = to_nvmem_device(dev);
+
+ ida_simple_remove(&nvmem_ida, nvmem->id);
+ kfree(nvmem);
+}
+
+static const struct device_type nvmem_provider_type = {
+ .release = nvmem_release,
+};
+
+static struct bus_type nvmem_bus_type = {
+ .name = "nvmem",
+};
+
+static int of_nvmem_match(struct device *dev, void *nvmem_np)
+{
+ return dev->of_node == nvmem_np;
+}
+
+static struct nvmem_device *of_nvmem_find(struct device_node *nvmem_np)
+{
+ struct device *d;
+
+ if (!nvmem_np)
+ return NULL;
+
+ d = bus_find_device(&nvmem_bus_type, NULL, nvmem_np, of_nvmem_match);
+
+ return d ? to_nvmem_device(d) : NULL;
+}
+
+static struct nvmem_cell *nvmem_find_cell(const char *cell_id)
+{
+ struct nvmem_cell *p;
+
+ list_for_each_entry(p, &nvmem_cells, node)
+ if (p && !strcmp(p->name, cell_id))
+ return p;
+
+ return NULL;
+}
+
+static void nvmem_cell_drop(struct nvmem_cell *cell)
+{
+ mutex_lock(&nvmem_cells_mutex);
+ list_del(&cell->node);
+ mutex_unlock(&nvmem_cells_mutex);
+ kfree(cell);
+}
+
+static void nvmem_device_remove_all_cells(struct nvmem_device *nvmem)
+{
+ struct nvmem_cell *cell;
+ struct list_head *p, *n;
+
+ list_for_each_safe(p, n, &nvmem_cells) {
+ cell = list_entry(p, struct nvmem_cell, node);
+ if (cell->nvmem == nvmem)
+ nvmem_cell_drop(cell);
+ }
+}
+
+static void nvmem_cell_add(struct nvmem_cell *cell)
+{
+ mutex_lock(&nvmem_cells_mutex);
+ list_add_tail(&cell->node, &nvmem_cells);
+ mutex_unlock(&nvmem_cells_mutex);
+}
+
+static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *info,
+ struct nvmem_cell *cell)
+{
+ cell->nvmem = nvmem;
+ cell->offset = info->offset;
+ cell->bytes = info->bytes;
+ cell->name = info->name;
+
+ cell->bit_offset = info->bit_offset;
+ cell->nbits = info->nbits;
+
+ if (cell->nbits)
+ cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset,
+ BITS_PER_BYTE);
+
+ if (!IS_ALIGNED(cell->offset, nvmem->stride)) {
+ dev_err(&nvmem->dev,
+ "cell %s unaligned to nvmem stride %d\n",
+ cell->name, nvmem->stride);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nvmem_add_cells(struct nvmem_device *nvmem,
+ struct nvmem_config *cfg)
+{
+ struct nvmem_cell **cells;
+ struct nvmem_cell_info *info = cfg->cells;
+ int i, rval;
+
+ cells = kzalloc(sizeof(*cells) * cfg->ncells, GFP_KERNEL);
+ if (!cells)
+ return -ENOMEM;
+
+ for (i = 0; i < cfg->ncells; i++) {
+ cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL);
+ if (!cells[i]) {
+ rval = -ENOMEM;
+ goto err;
+ }
+
+ rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]);
+ if (IS_ERR_VALUE(rval)) {
+ kfree(cells[i]);
+ goto err;
+ }
+
+ nvmem_cell_add(cells[i]);
+ }
+
+ nvmem->ncells = cfg->ncells;
+ /* remove tmp array */
+ kfree(cells);
+
+ return 0;
+err:
+ while (--i)
+ nvmem_cell_drop(cells[i]);
+
+ return rval;
+}
+
+/**
+ * nvmem_register() - Register a nvmem device for given nvmem_config.
+ * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem
+ *
+ * @config: nvmem device configuration with which nvmem device is created.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to nvmem_device.
+ */
+
+struct nvmem_device *nvmem_register(struct nvmem_config *config)
+{
+ struct nvmem_device *nvmem;
+ struct regmap *rm;
+ int rval;
+
+ if (!config->dev)
+ return ERR_PTR(-EINVAL);
+
+ rm = dev_get_regmap(config->dev, NULL);
+ if (!rm) {
+ dev_err(config->dev, "Regmap not found\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ nvmem = kzalloc(sizeof(*nvmem), GFP_KERNEL);
+ if (!nvmem)
+ return ERR_PTR(-ENOMEM);
+
+ nvmem->id = ida_simple_get(&nvmem_ida, 0, 0, GFP_KERNEL);
+ if (nvmem->id < 0) {
+ kfree(nvmem);
+ return ERR_PTR(nvmem->id);
+ }
+
+ nvmem->regmap = rm;
+ nvmem->owner = config->owner;
+ nvmem->stride = regmap_get_reg_stride(rm);
+ nvmem->word_size = regmap_get_val_bytes(rm);
+ nvmem->size = regmap_get_max_register(rm) + nvmem->stride;
+ nvmem->dev.type = &nvmem_provider_type;
+ nvmem->dev.bus = &nvmem_bus_type;
+ nvmem->dev.parent = config->dev;
+ nvmem->dev.of_node = config->dev->of_node;
+ dev_set_name(&nvmem->dev, "%s%d",
+ config->name ? : "nvmem", config->id);
+
+ nvmem->read_only = nvmem->dev.of_node ?
+ of_property_read_bool(nvmem->dev.of_node,
+ "read-only") :
+ config->read_only;
+
+ device_initialize(&nvmem->dev);
+
+ dev_dbg(&nvmem->dev, "Registering nvmem device %s\n",
+ dev_name(&nvmem->dev));
+
+ rval = device_add(&nvmem->dev);
+ if (rval) {
+ ida_simple_remove(&nvmem_ida, nvmem->id);
+ kfree(nvmem);
+ return ERR_PTR(rval);
+ }
+
+ if (device_create_bin_file(&nvmem->dev,
+ nvmem->read_only ? &bin_attr_ro_nvmem :
+ &bin_attr_rw_nvmem))
+ dev_info(&nvmem->dev, "Failed to create sysfs binary file\n");
+
+ if (config->cells)
+ nvmem_add_cells(nvmem, config);
+
+ return nvmem;
+}
+EXPORT_SYMBOL_GPL(nvmem_register);
+
+/**
+ * nvmem_unregister() - Unregister previously registered nvmem device
+ *
+ * @nvmem: Pointer to previously registered nvmem device.
+ *
+ * The return value will be an non zero on error or a zero on success.
+ */
+int nvmem_unregister(struct nvmem_device *nvmem)
+{
+ mutex_lock(&nvmem_mutex);
+ if (nvmem->users) {
+ mutex_unlock(&nvmem_mutex);
+ return -EBUSY;
+ }
+ mutex_unlock(&nvmem_mutex);
+
+ nvmem_device_remove_all_cells(nvmem);
+ device_del(&nvmem->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_unregister);
+
+static int __init nvmem_init(void)
+{
+ return bus_register(&nvmem_bus_type);
+}
+
+static void __exit nvmem_exit(void)
+{
+ bus_unregister(&nvmem_bus_type);
+}
+
+subsys_initcall(nvmem_init);
+module_exit(nvmem_exit);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org");
+MODULE_DESCRIPTION("nvmem Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
new file mode 100644
index 0000000..f589d3b
--- /dev/null
+++ b/include/linux/nvmem-provider.h
@@ -0,0 +1,54 @@
+/*
+ * nvmem framework provider.
+ *
+ * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
+ * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _LINUX_NVMEM_PROVIDER_H
+#define _LINUX_NVMEM_PROVIDER_H
+
+struct nvmem_device;
+
+struct nvmem_cell_info {
+ const char *name;
+ int offset;
+ int bytes;
+ int bit_offset;
+ int nbits;
+};
+
+struct nvmem_config {
+ struct device *dev;
+ const char *name;
+ int id;
+ struct module *owner;
+ struct nvmem_cell_info *cells;
+ int ncells;
+ bool read_only;
+};
+
+#if IS_ENABLED(CONFIG_NVMEM)
+
+struct nvmem_device *nvmem_register(struct nvmem_config *cfg);
+int nvmem_unregister(struct nvmem_device *nvmem);
+
+#else
+
+static inline struct nvmem_device *nvmem_register(struct nvmem_config *cfg)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline int nvmem_unregister(struct nvmem_device *nvmem)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_NVMEM */
+
+#endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
--
1.9.1
^ permalink raw reply related
* [PATCH v7 0/9] Add simple NVMEM Framework via regmap.
From: Srinivas Kandagatla @ 2015-07-10 9:43 UTC (permalink / raw)
To: linux-arm-kernel, Greg Kroah-Hartman
Cc: Rob Herring, Kumar Gala, Mark Brown, s.hauer, linux-api,
linux-kernel, devicetree, linux-arm-msm, arnd, sboyd,
pantelis.antoniou, mporter, stefan.wahren, wxt,
Srinivas Kandagatla
Hi Greg,
This patchset adds a new simple NVMEM framework to kernel, and it is tested
with various drivers like "QCOM thermal sensors", "QCOM cpr driver",
"begal bone cape manager" and few more on the way.
Thankyou all for providing inputs and comments on previous versions of this
patchset. Here is the v7 of the patchset addressing all the issues raised as
part of previous versions review.
Up until now, NVMEM drivers like eeprom were stored in drivers/misc, where they
all had to duplicate pretty much the same code to register a sysfs file, allow
in-kernel users to access the content of the devices they were driving, etc.
This was also a problem as far as other in-kernel users were involved, since
the solutions used were pretty much different from on driver to another, there
was a rather big abstraction leak.
Introduction of this framework aims at solving this. It also introduces DT
representation for consumer devices to go get the data they require (MAC
Addresses, SoC/Revision ID, part numbers, and so on) from the NVMEMs.
After learning few things about QCOM qfprom and other eeprom/efuses, which
has packed fields at bit level. Which makes it important to add support to
such memories. This version adds support to this type of non volatile
memories by adding support to bit level nvmem-cells.
Having regmap interface to this framework would give much better
abstraction for nvmems on different buses.
patch 1-4 Introduces the NVMEM framework.
Patch 5-6 Adds Qualcomm specific qfprom driver.
Patch 7 migrates an existing driver to nvmem framework.
Patch 8 adds entry in MAINTAINERS.
Its also possible to migrate other nvmem drivers to this framework, and I think
some of them already posted patches based on this framework.
Providers APIs:
nvmem_register/unregister();
Consumers APIs:
Cell based apis for both DT/Non-DT:
nvmem_cell_get()/nvmem_cell_put();
devm_nvmem_cell_get()/devm_nvmem_cell_put();
of_nvmem_cell_get()
nvmem_cell_read()/nvmem_cell_write();
Raw byte access apis for both DT/non-DT.
nvmem_device_get()/nvmem_device_put()
devm_nvmem_device_get()/nvmem_device_put()
of_nvmem_device_get()
nvmem_device_read()/nvmem_device_write();
nvmem_device_cell_read()/nvmem_device_cell_write();
Device Tree:
/* Provider */
qfprom: qfprom@00700000 {
...
/* Data cells */
tsens_calibration: calib@404 {
reg = <0x404 0x10>;
};
tsens_calibration_bckp: calib_bckp@504 {
reg = <0x504 0x11>;
bit-offset = 6;
nbits = 128;
};
pvs_version: pvs-version@6 {
reg = <0x6 0x2>
bit-offset = 7;
nbits = 2;
};
speed_bin: speed-bin@c{
reg = <0xc 0x1>;
bit-offset = 2;
nbits = 3;
};
...
};
/* Consumer */
tsens {
...
nvmem-cells = <&tsens_calibration>;
nvmem-cell-names = "calibration";
};
userspace interface: binary file in /sys/bus/nvmem/devices/*/nvmem
ex:
hexdump /sys/bus/nvmem/devices/qfprom0/nvmem
0000000 0000 0000 0000 0000 0000 0000 0000 0000
*
00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00
0000000 0000 0000 0000 0000 0000 0000 0000 0000
...
*
0001000
Changes since v6 (https://lkml.org/lkml/2015/6/24/325)
* Replaced class usage with bus, suggested by Stephen Boyd.
* various cosmetic and header cleanups suggested by Stefan Wahren
* changed nvmem-cell property to nvmem-cells spotted by Rajendra Nayak
Changes since v5(https://lkml.org/lkml/2015/5/21/643)
* skipped regmap patches which are already merged by Mark.
* Fixed lot of style related comments by Stephen.
* Fixed sunxi driver.
* added devm_* variants requested by Stephen.
* added of_* variants requested by Pantelis Antoniou
* added read_only options for non-dt drivers.
* added basic how-to doc.
Changes since v4(https://lkml.org/lkml/2015/3/30/725)
* rename eeprom to nvmem suggested by Matt Porter
* added bit level support to nvmem cells, if not framework is
not usable for qcom platforms.
* removed ternary operator shortcut suggested by Mark B.
* unified consumer/provider apis for both DT and non-DT.
* added name support for cell.
* added bit level bindings.
* added read-only support suggested by Matt Porter and others.
* added new nvmem_device based consumer apis.
Changes since v3(https://lkml.org/lkml/2015/3/24/1066)
* simplified logic in bin_attr_eeprom_read/write spotted by Mark Brown.
* moved from using regmap_bulk_read/write to regmap_raw_read/write
spotted by Mark Brown
* Fixed return error codes for the dummy wrappers spotted by Sascha Hauer
* Fixed various error code checks in core spotted by Sascha Hauer.
* Simplified consumer bindings suggested by Sascha Hauer.
* Added eeprom-mmio helper functions.
Changes since v2(https://lkml.org/lkml/2015/3/13/168)
* Fixed error handling in eeprom_register spotted by Mark Brown
* Added new regmap_get_max_register() and regmap_get_reg_stride().
* Fixed module build errors reported by kbuild robot.
* recycle the ids when eeprom provider is released.
Changes since v1(https://lkml.org/lkml/2015/3/5/153)
* Fix various Licencing issues spotted by Paul Bolle and Mark Brown
* Allow eeprom core to build as module spotted by Paul Bolle.
* Fix various kconfig issues spotted by Paul Bolle.
* remove unessary atomic varible spotted by Mark Brown.
* Few cleanups and common up some of the code in core.
* Add qfprom bindings.
Changes since RFC(https://lkml.org/lkml/2015/2/19/307)
* Fix documentation and error checks in read/write spotted by Andrew Lunn
* Kconfig fix suggested by Stephen Boyd.
* Add module owner suggested by Stephen Boyd and others.
* Fix unsafe handling of eeprom in unregister spotted by Russell and Mark Brown.
* seperate bindings patch as suggested by Rob.
* Add MAINTAINERS as suggested by Rob.
* Added support to allow reading eeprom for things like serial number which
* canbe scatters across.
* Added eeprom data using reg property suggested by Sascha and Stephen.
* Added non-DT support.
* Move kerneldoc to the src files spotted by Mark Brown.
* Remove local list and do eeprom lookup by using class_find_device()
Thanks,
srini
Maxime Ripard (1):
nvmem: sunxi: Move the SID driver to the nvmem framework
Srinivas Kandagatla (8):
nvmem: Add a simple NVMEM framework for nvmem providers
nvmem: Add a simple NVMEM framework for consumers
nvmem: Add nvmem_device based consumer apis.
nvmem: Add bindings for simple nvmem framework
Documentation: nvmem: add nvmem api level and how-to doc
nvmem: qfprom: Add Qualcomm QFPROM support.
nvmem: qfprom: Add bindings for qfprom
nvmem: Add to MAINTAINERS for nvmem framework
Documentation/ABI/testing/sysfs-driver-sunxi-sid | 22 -
.../bindings/misc/allwinner,sunxi-sid.txt | 17 -
.../bindings/nvmem/allwinner,sunxi-sid.txt | 21 +
Documentation/devicetree/bindings/nvmem/nvmem.txt | 85 ++
Documentation/devicetree/bindings/nvmem/qfprom.txt | 35 +
Documentation/nvmem/nvmem.txt | 152 +++
MAINTAINERS | 9 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/misc/eeprom/Kconfig | 13 -
drivers/misc/eeprom/Makefile | 1 -
drivers/misc/eeprom/sunxi_sid.c | 156 ---
drivers/nvmem/Kconfig | 39 +
drivers/nvmem/Makefile | 12 +
drivers/nvmem/core.c | 1059 ++++++++++++++++++++
drivers/nvmem/qfprom.c | 87 ++
drivers/nvmem/sunxi_sid.c | 160 +++
include/linux/nvmem-consumer.h | 155 +++
include/linux/nvmem-provider.h | 48 +
19 files changed, 1865 insertions(+), 209 deletions(-)
delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
delete mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
create mode 100644 Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
create mode 100644 Documentation/devicetree/bindings/nvmem/nvmem.txt
create mode 100644 Documentation/devicetree/bindings/nvmem/qfprom.txt
create mode 100644 Documentation/nvmem/nvmem.txt
delete mode 100644 drivers/misc/eeprom/sunxi_sid.c
create mode 100644 drivers/nvmem/Kconfig
create mode 100644 drivers/nvmem/Makefile
create mode 100644 drivers/nvmem/core.c
create mode 100644 drivers/nvmem/qfprom.c
create mode 100644 drivers/nvmem/sunxi_sid.c
create mode 100644 include/linux/nvmem-consumer.h
create mode 100644 include/linux/nvmem-provider.h
--
1.9.1
^ permalink raw reply
* Re: [RFCv3 3/5] mm/balloon: apply mobile page migratable into balloon
From: Gioh Kim @ 2015-07-10 0:21 UTC (permalink / raw)
To: Michael S. Tsirkin, koct9i, aquini
Cc: akpm, linux-mm, linux-api, linux-kernel, virtualization, bfields,
minchan, Gioh Kim, viro, gunho.lee, linux-fsdevel, jlayton,
iamjoonsoo.kim, vbabka
In-Reply-To: <20150709105119-mutt-send-email-mst@redhat.com>
>> @@ -124,6 +130,7 @@ static inline void balloon_page_insert(struct balloon_dev_info *balloon,
>> struct page *page)
>> {
>> __SetPageBalloon(page);
>> + page->mapping = balloon->inode->i_mapping;
>> SetPagePrivate(page);
>> set_page_private(page, (unsigned long)balloon);
>> list_add(&page->lru, &balloon->pages);
>> @@ -140,6 +147,7 @@ static inline void balloon_page_insert(struct balloon_dev_info *balloon,
>> static inline void balloon_page_delete(struct page *page)
>> {
>> __ClearPageBalloon(page);
>> + page->mapping = NULL;
>> set_page_private(page, 0);
>> if (PagePrivate(page)) {
>> ClearPagePrivate(page);
>
> Order of cleanup here is not the reverse of the order of initialization.
> Better make it exactly the reverse.
>
>
> Also, I have a question: is it enough to lock the page to make changing
> the mapping safe? Do all users lock the page too?
>
>
>
>
I think balloon developers can answer that precisely.
I've just follow this comment:
http://lxr.free-electrons.com/source/include/linux/balloon_compaction.h#L16
^ permalink raw reply
* Re: [RFCv3 0/5] enable migration of driver pages
From: Gioh Kim @ 2015-07-10 0:02 UTC (permalink / raw)
To: Dave Airlie, dri-devel, Andrew Morton, jlayton, bfields, vbabka,
iamjoonsoo.kim, Al Viro, Michael S. Tsirkin, koct9i, minchan,
aquini, linux-fsdevel, open list:VIRTIO CORE, NET..., LKML, open,
list@kvack.org: ABI/API, Linux Memory Management List, gunho.lee,
Gioh Kim
In-Reply-To: <20150709130848.GD21858@phenom.ffwll.local>
2015-07-09 오후 10:08에 Daniel Vetter 이(가) 쓴 글:
> Also there's a bit a lack of gpu drivers from the arm world in upstream,
> which is probabyl why this patch series doesn't come with a user. Might be
> better to first upstream the driver before talking about additional
> infrastructure that it needs.
> -Daniel
I'm not from ARM but I just got the idea of driver page migration
during I worked with ARM gpu driver.
I'm sure this patch is good for zram and balloon
and hope it can be applied to drivers consuming many pages and generating fragmentation,
such as GPU or gfx driver.
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3] ipc: Modify message queue accounting to not take kernel data structures into account
From: Davidlohr Bueso @ 2015-07-10 0:00 UTC (permalink / raw)
To: Doug Ledford
Cc: mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w, Marcus Gelderie, lkml,
David Howells, Alexander Viro, John Duffy, Arto Bendiken,
Linux API, Andrew Morton
In-Reply-To: <559D7760.1020909-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
While on the subject, after taking another look at where and how we
calculate the treesize, I think we can remove this check when checking
attributes (mqueue_attr_ok -- which itself could use some simplifying):
mq_treesize = attr->mq_maxmsg * sizeof(struct msg_msg) +
min_t(unsigned int, attr->mq_maxmsg, MQ_PRIO_MAX) *
sizeof(struct posix_msg_tree_node);
total_size = attr->mq_maxmsg * attr->mq_msgsize;
if (total_size + mq_treesize < total_size)
return -EOVERFLOW;
^^^ this condition is never true, so we never return EOVERFLOW.
return 0;
The below gets rid of this bogus check and refactors similar code,
introducing a mqueue_sizeof() helper to do the job of calculating total
mqueue overhead.
Thoughts?
Thanks,
Davidlohr
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 161a180..a5d0c9e 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -209,6 +209,31 @@ try_again:
return msg;
}
+/*
+ * We used to allocate a static array of pointers and account
+ * the size of that array as well as one msg_msg struct per
+ * possible message into the queue size. That's no longer
+ * accurate as the queue is now an rbtree and will grow and
+ * shrink depending on usage patterns. We can, however, still
+ * account one msg_msg struct per message, but the nodes are
+ * allocated depending on priority usage, and most programs
+ * only use one, or a handful, of priorities. However, since
+ * this is pinned memory, we need to assume worst case, so
+ * that means the min(mq_maxmsg, max_priorities) * struct
+ * posix_msg_tree_node.
+ */
+static inline unsigned long mqueue_sizeof(struct mqueue_inode_info *info)
+{
+ unsigned long mq_treesize, mq_max_msgsize;
+
+ mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
+ min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
+ sizeof(struct posix_msg_tree_node);
+
+ mq_max_msgsize = info->attr.mq_maxmsg * info->attr.mq_msgsize;
+ return mq_treesize + mq_max_msgsize; /* bytes */
+}
+
static struct inode *mqueue_get_inode(struct super_block *sb,
struct ipc_namespace *ipc_ns, umode_t mode,
struct mq_attr *attr)
@@ -229,7 +254,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
if (S_ISREG(mode)) {
struct mqueue_inode_info *info;
- unsigned long mq_bytes, mq_treesize;
+ unsigned long mq_bytes;
inode->i_fop = &mqueue_file_operations;
inode->i_size = FILENT_SIZE;
@@ -254,25 +279,8 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
info->attr.mq_maxmsg = attr->mq_maxmsg;
info->attr.mq_msgsize = attr->mq_msgsize;
}
- /*
- * We used to allocate a static array of pointers and account
- * the size of that array as well as one msg_msg struct per
- * possible message into the queue size. That's no longer
- * accurate as the queue is now an rbtree and will grow and
- * shrink depending on usage patterns. We can, however, still
- * account one msg_msg struct per message, but the nodes are
- * allocated depending on priority usage, and most programs
- * only use one, or a handful, of priorities. However, since
- * this is pinned memory, we need to assume worst case, so
- * that means the min(mq_maxmsg, max_priorities) * struct
- * posix_msg_tree_node.
- */
- mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
- min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
- sizeof(struct posix_msg_tree_node);
- mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
- info->attr.mq_msgsize);
+ mq_bytes = mqueue_sizeof(info);
spin_lock(&mq_lock);
if (u->mq_bytes + mq_bytes < u->mq_bytes ||
@@ -371,7 +379,7 @@ static void mqueue_evict_inode(struct inode *inode)
{
struct mqueue_inode_info *info;
struct user_struct *user;
- unsigned long mq_bytes, mq_treesize;
+ unsigned long mq_bytes;
struct ipc_namespace *ipc_ns;
struct msg_msg *msg;
@@ -388,13 +396,7 @@ static void mqueue_evict_inode(struct inode *inode)
kfree(info->node_cache);
spin_unlock(&info->lock);
- /* Total amount of bytes accounted for the mqueue */
- mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
- min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
- sizeof(struct posix_msg_tree_node);
-
- mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
- info->attr.mq_msgsize);
+ mq_bytes = mqueue_sizeof(info);
user = info->user;
if (user) {
@@ -692,9 +694,6 @@ static void remove_notification(struct mqueue_inode_info *info)
static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
{
- int mq_treesize;
- unsigned long total_size;
-
if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
return -EINVAL;
if (capable(CAP_SYS_RESOURCE)) {
@@ -709,12 +708,6 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
/* check for overflow */
if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
return -EOVERFLOW;
- mq_treesize = attr->mq_maxmsg * sizeof(struct msg_msg) +
- min_t(unsigned int, attr->mq_maxmsg, MQ_PRIO_MAX) *
- sizeof(struct posix_msg_tree_node);
- total_size = attr->mq_maxmsg * attr->mq_msgsize;
- if (total_size + mq_treesize < total_size)
- return -EOVERFLOW;
return 0;
}
^ permalink raw reply related
* Good Day
From: abdullahmohad02 @ 2015-07-09 19:37 UTC (permalink / raw)
Good Day
I know that this mail will come to you as a surprise as we have never
met before, but need not to worry as I am contacting you independently
of my Investigation and no one is informed of this communication. I
need your Urgent assistance in transferring the sum of $7.5 million
immediately to your Private account. The money has been here in our
Bank lying dormant for years now without anybody coming for the claim
of it.
I want to release the money to you as the relative to our deceased
customer (The account owner) MR. ANDREAS SCHRANNER who died a long
with his supposed NEXT OF KIN since 2003. The Banking law here does
not allow such money to stay more than 13 Years, because the money
will be recalled to the Bank treasury account as unclaimed fund.
By indicating your interest contact me through my private email
address ( abdullahmohad02-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org ) I will send you the full
details on how the Business will be executed. Please respond urgently
and delete if you are not interested
Regards,
Mr. Abdullah Mohad
^ permalink raw reply
* Re: [PATCH V3 3/5] mm: mlock: Introduce VM_LOCKONFAULT and add mlock flags to enable it
From: Eric B Munson @ 2015-07-09 18:46 UTC (permalink / raw)
To: Jonathan Corbet
Cc: Andrew Morton, Michal Hocko, Vlastimil Babka, linux-alpha,
linux-kernel, linux-mips, linux-parisc, linuxppc-dev, sparclinux,
linux-xtensa, linux-mm, linux-arch, linux-api
In-Reply-To: <20150708151750.75e65859@lwn.net>
[-- Attachment #1: Type: text/plain, Size: 1548 bytes --]
On Wed, 08 Jul 2015, Jonathan Corbet wrote:
> On Wed, 8 Jul 2015 16:34:56 -0400
> Eric B Munson <emunson@akamai.com> wrote:
>
> > > Quick, possibly dumb question: I've been beating my head against these for
> > > a little bit, and I can't figure out what's supposed to happen in this
> > > case:
> > >
> > > mlock2(addr, len, MLOCK_ONFAULT);
> > > munlock2(addr, len, MLOCK_LOCKED);
> > >
> > > It looks to me like it will clear VM_LOCKED without actually unlocking any
> > > pages. Is that the intended result?
> >
> > This is not quite right, what happens when you call munlock2(addr, len,
> > MLOCK_LOCKED); is we call apply_vma_flags(addr, len, VM_LOCKED, false).
>
> From your explanation, it looks like what I said *was* right...what I was
> missing was the fact that VM_LOCKED isn't set in the first place. So that
> call would be a no-op, clearing a flag that's already cleared.
Sorry, I misread the original. You are correct with the addition that
the call to munlock2(MLOCK_LOCKED) is a noop in this case.
>
> One other question...if I call mlock2(MLOCK_ONFAULT) on a range that
> already has resident pages, I believe that those pages will not be locked
> until they are reclaimed and faulted back in again, right? I suspect that
> could be surprising to users.
That is the case. I am looking into what it would take to find only the
present pages in a range and lock them, if that is the behavior that is
preferred I can include it in the updated series.
>
> Thanks,
>
> jon
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [RFC 4/8] lsm: smack: smack callbacks for kdbus security hooks
From: Casey Schaufler @ 2015-07-09 15:24 UTC (permalink / raw)
To: Sergei Zviagintsev, Paul Osmialowski
Cc: Paul Moore, James Morris, Serge E. Hallyn, Kees Cook,
Tetsuo Handa, Stephen Smalley, Neil Brown, Mark Rustad,
Greg Kroah-Hartman, Daniel Mack, David Herrmann, Djalal Harouni,
Shuah Khan, Al Viro, linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Karol Lewandowski,
Lukasz Skalski
In-Reply-To: <20150709100808.GH25971-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
On 7/9/2015 3:08 AM, Sergei Zviagintsev wrote:
> Hi,
>
> On Wed, Jul 08, 2015 at 12:25:06PM +0200, Paul Osmialowski wrote:
>> This adds implementation of three smack callbacks sitting behind kdbus
>> security hooks as proposed by Karol Lewandowski.
>>
>> Originates from:
>>
>> git://git.infradead.org/users/pcmoore/selinux (branch: working-kdbus)
>> commit: fc3505d058c001fe72a6f66b833e0be5b2d118f3
>>
>> https://github.com/lmctl/linux.git (branch: kdbus-lsm-v4.for-systemd-v212)
>> commit: 103c26fd27d1ec8c32d85dd3d85681f936ac66fb
>>
>> Signed-off-by: Karol Lewandowski <k.lewandowsk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Paul Osmialowski <p.osmialowsk-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>> security/smack/smack_lsm.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 68 insertions(+)
>>
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index a143328..033b756 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -41,6 +41,7 @@
>> #include <linux/msg.h>
>> #include <linux/shm.h>
>> #include <linux/binfmts.h>
>> +#include <kdbus/connection.h>
>> #include "smack.h"
>>
>> #define TRANS_TRUE "TRUE"
>> @@ -3336,6 +3337,69 @@ static int smack_setprocattr(struct task_struct *p, char *name,
>> }
>>
>> /**
>> + * smack_kdbus_connect - Set the security blob for a KDBus connection
>> + * @conn: the connection
>> + * @secctx: smack label
>> + * @seclen: smack label length
>> + *
>> + * Returns 0
>> + */
>> +static int smack_kdbus_connect(struct kdbus_conn *conn,
>> + const char *secctx, u32 seclen)
>> +{
>> + struct smack_known *skp;
>> +
>> + if (secctx && seclen > 0)
>> + skp = smk_import_entry(secctx, seclen);
>> + else
>> + skp = smk_of_current();
>> + conn->security = skp;
>> +
>> + return 0;
>> +}
>> +
>> +/**
>> + * smack_kdbus_conn_free - Clear the security blob for a KDBus connection
>> + * @conn: the connection
>> + *
>> + * Clears the blob pointer
>> + */
>> +static void smack_kdbus_conn_free(struct kdbus_conn *conn)
>> +{
>> + conn->security = NULL;
>> +}
>> +
>> +/**
>> + * smack_kdbus_talk - Smack access on KDBus
>> + * @src: source kdbus connection
>> + * @dst: destination kdbus connection
>> + *
>> + * Return 0 if a subject with the smack of sock could access
>> + * an object with the smack of other, otherwise an error code
>> + */
>> +static int smack_kdbus_talk(const struct kdbus_conn *src,
>> + const struct kdbus_conn *dst)
>> +{
>> + struct smk_audit_info ad;
>> + struct smack_known *sskp = src->security;
>> + struct smack_known *dskp = dst->security;
>> + int ret;
>> +
>> + BUG_ON(sskp == NULL);
>> + BUG_ON(dskp == NULL);
> I am not familiar with the smack code so far, but I see that current
> security/smack/smack_lsm.c contains only one BUG_ON and this patch adds
> another two.
Smack does not use BUG_ON for routine error checking. If there
is reason to expect that these values will not be set the case
should be checked for and handled. Otherwise, I don't believe
in cluttering the code with assertions.
>
>> +
>> + if (smack_privileged(CAP_MAC_OVERRIDE))
>> + return 0;
>> +
>> + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NONE);
>> +
>> + ret = smk_access(sskp, dskp, MAY_WRITE, &ad);
>> + if (ret)
>> + return ret;
>> + return 0;
> Three redundant lines here.
>
>> +}
>> +
>> +/**
>> * smack_unix_stream_connect - Smack access on UDS
>> * @sock: one sock
>> * @other: the other sock
>> @@ -4393,6 +4457,10 @@ struct security_hook_list smack_hooks[] = {
>> LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
>> LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
>> LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),
>> +
>> + LSM_HOOK_INIT(kdbus_connect, smack_kdbus_connect),
>> + LSM_HOOK_INIT(kdbus_conn_free, smack_kdbus_conn_free),
>> + LSM_HOOK_INIT(kdbus_talk, smack_kdbus_talk),
>> };
>>
>>
>> --
>> 1.9.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [RFCv3 0/5] enable migration of driver pages
From: Kirill A. Shutemov @ 2015-07-09 14:02 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Gioh Kim, Dave Airlie, dri-devel, Andrew Morton, jlayton, bfields,
vbabka, iamjoonsoo.kim, Al Viro, Michael S. Tsirkin, koct9i,
minchan, aquini, linux-fsdevel, open list:VIRTIO CORE, NET...,
LKML, open, list, ABI/API, Linux Memory Management List,
gunho.lee, Gioh Kim, Kirill A. Shutemov, Hugh Dickins
In-Reply-To: <20150709133301.GG5176@intel.com>
On Thu, Jul 09, 2015 at 04:33:01PM +0300, Ville Syrjälä wrote:
> On Thu, Jul 09, 2015 at 03:08:48PM +0200, Daniel Vetter wrote:
> > On Thu, Jul 09, 2015 at 08:55:25AM +0900, Gioh Kim wrote:
> > >
> > >
> > > 2015-07-09 오전 7:47에 Dave Airlie 이(가) 쓴 글:
> > > >>>
> > > >>>
> > > >>>Can the various in-kernel GPU drivers benefit from this? If so, wiring
> > > >>>up one or more of those would be helpful?
> > > >>
> > > >>
> > > >>I'm sure that other in-kernel GPU drivers can have benefit.
> > > >>It must be helpful.
> > > >>
> > > >>If I was familiar with other in-kernel GPU drivers code, I tried to patch
> > > >>them.
> > > >>It's too bad.
> > > >
> > > >I'll bring dri-devel into the loop here.
> > > >
> > > >ARM GPU developers please take a look at this stuff, Laurent, Rob,
> > > >Eric I suppose.
> > >
> > > I sent a patch, https://lkml.org/lkml/2015/3/24/1182, and my opinion about compaction
> > > to ARM GPU developers via Korea ARM branch.
> > > I got a reply that they had no time to review it.
> > >
> > > I hope they're interested to this patch.
> >
> > i915 gpus would support 64kb and 2mb pages, but we never implemented this.
> > I don't think this would fit for gem based drivers since our backing
> > storage is shmemfs. So if we want to implement page migration (which we'd
> > probably want to make large pages work well) we'd need to pimp shmem to a)
> > hand large pages to us b) forward the migrate calls. Probably that means
> > we need to build our own gemfs reusing shmemfs code.
>
> AFAIK there are efforts ongoing to make large pages work with shmem.
>
> Kirill, IIRC you mentioned that you're were looking into this a while
> back?
I work in this direction, but don't have anything to show at the moment.
Hugh has published his implementation of huge tmpfs back in February:
http://lkml.kernel.org/g/alpine.LSU.2.11.1502201941340.14414@eggly.anvils
--
Kirill A. Shutemov
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [RFCv3 0/5] enable migration of driver pages
From: Ville Syrjälä @ 2015-07-09 13:33 UTC (permalink / raw)
To: Gioh Kim, Dave Airlie, dri-devel, Andrew Morton, jlayton, bfields,
vbabka, iamjoonsoo.kim, Al Viro, Michael S. Tsirkin, koct9i,
minchan, aquini, linux-fsdevel, open list:VIRTIO CORE, NET...,
LKML, open, list, ABI/API, Linux Memory Management List,
gunho.lee, Gioh Kim
Cc: Kirill A. Shutemov
In-Reply-To: <20150709130848.GD21858@phenom.ffwll.local>
On Thu, Jul 09, 2015 at 03:08:48PM +0200, Daniel Vetter wrote:
> On Thu, Jul 09, 2015 at 08:55:25AM +0900, Gioh Kim wrote:
> >
> >
> > 2015-07-09 오전 7:47에 Dave Airlie 이(가) 쓴 글:
> > >>>
> > >>>
> > >>>Can the various in-kernel GPU drivers benefit from this? If so, wiring
> > >>>up one or more of those would be helpful?
> > >>
> > >>
> > >>I'm sure that other in-kernel GPU drivers can have benefit.
> > >>It must be helpful.
> > >>
> > >>If I was familiar with other in-kernel GPU drivers code, I tried to patch
> > >>them.
> > >>It's too bad.
> > >
> > >I'll bring dri-devel into the loop here.
> > >
> > >ARM GPU developers please take a look at this stuff, Laurent, Rob,
> > >Eric I suppose.
> >
> > I sent a patch, https://lkml.org/lkml/2015/3/24/1182, and my opinion about compaction
> > to ARM GPU developers via Korea ARM branch.
> > I got a reply that they had no time to review it.
> >
> > I hope they're interested to this patch.
>
> i915 gpus would support 64kb and 2mb pages, but we never implemented this.
> I don't think this would fit for gem based drivers since our backing
> storage is shmemfs. So if we want to implement page migration (which we'd
> probably want to make large pages work well) we'd need to pimp shmem to a)
> hand large pages to us b) forward the migrate calls. Probably that means
> we need to build our own gemfs reusing shmemfs code.
AFAIK there are efforts ongoing to make large pages work with shmem.
Kirill, IIRC you mentioned that you're were looking into this a while
back?
--
Ville Syrjälä
Intel OTC
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH -mm v6 5/6] proc: add kpageidle file
From: Vladimir Davydov @ 2015-07-09 13:19 UTC (permalink / raw)
To: Andres Lagar-Cavilla
Cc: Andrew Morton, Minchan Kim, Raghavendra K T, Johannes Weiner,
Michal Hocko, Greg Thelen, Michel Lespinasse, David Rientjes,
Pavel Emelyanov, Cyrill Gorcunov, Jonathan Corbet,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, linux-mm-Bw31MaZKKs3YtjvyW6yDsg,
cgroups-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAJu=L5-fwHMEKmL1Sp7owXyBa0GCrGR=TdKZbh15CJA3WrcwqA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi Andres,
On Wed, Jul 08, 2015 at 04:01:13PM -0700, Andres Lagar-Cavilla wrote:
> On Fri, Jun 12, 2015 at 2:52 AM, Vladimir Davydov
[...]
> > @@ -275,6 +276,179 @@ static const struct file_operations proc_kpagecgroup_operations = {
> > };
> > #endif /* CONFIG_MEMCG */
> >
> > +#ifdef CONFIG_IDLE_PAGE_TRACKING
> > +/*
> > + * Idle page tracking only considers user memory pages, for other types of
> > + * pages the idle flag is always unset and an attempt to set it is silently
> > + * ignored.
> > + *
> > + * We treat a page as a user memory page if it is on an LRU list, because it is
> > + * always safe to pass such a page to page_referenced(), which is essential for
> > + * idle page tracking. With such an indicator of user pages we can skip
> > + * isolated pages, but since there are not usually many of them, it will hardly
> > + * affect the overall result.
> > + *
> > + * This function tries to get a user memory page by pfn as described above.
> > + */
> > +static struct page *kpageidle_get_page(unsigned long pfn)
> > +{
> > + struct page *page;
> > + struct zone *zone;
> > +
> > + if (!pfn_valid(pfn))
> > + return NULL;
> > +
> > + page = pfn_to_page(pfn);
> > + if (!page || !PageLRU(page))
>
> Isolation can race in while you're processing the page, after these
> checks. This is ok, but worth a small comment.
Agree, will add one.
>
> > + return NULL;
> > + if (!get_page_unless_zero(page))
> > + return NULL;
> > +
> > + zone = page_zone(page);
> > + spin_lock_irq(&zone->lru_lock);
> > + if (unlikely(!PageLRU(page))) {
> > + put_page(page);
> > + page = NULL;
> > + }
> > + spin_unlock_irq(&zone->lru_lock);
> > + return page;
> > +}
> > +
> > +/*
> > + * This function calls page_referenced() to clear the referenced bit for all
> > + * mappings to a page. Since the latter also clears the page idle flag if the
> > + * page was referenced, it can be used to update the idle flag of a page.
> > + */
> > +static void kpageidle_clear_pte_refs(struct page *page)
> > +{
> > + unsigned long dummy;
> > +
> > + if (page_referenced(page, 0, NULL, &dummy, NULL))
>
> Because of pte/pmd_clear_flush_young* called in the guts of
> page_referenced_one, an N byte write or read to /proc/kpageidle will
> cause N * 64 TLB flushes.
>
> Additionally, because of the _notify connection to mmu notifiers, this
> will also cause N * 64 EPT TLB flushes (in the KVM Intel case, similar
> for other notifier flavors, you get the point).
>
> The solution is relatively straightforward: augment
> page_referenced_one with a mode marker or boolean that determines
> whether tlb flushing is required.
Frankly, I don't think that tlb flushes are such a big deal in the scope
of this feature, because one is not supposed to write to kpageidle that
often. However, I agree we'd better avoid overhead we can easily avoid,
so I'll add a new flag to differentiate between kpageidle and reclaim
path in page_referenced, as you suggested.
>
> For an access pattern tracker such as the one you propose, flushing is
> not strictly necessary: the next context switch will take care. Too
> bad if you missed a few accesses because the pte/pmd was loaded in the
> TLB. Not so easy for MMU notifiers, because each secondary MMU has its
> own semantics. You could arguably throw the towel in there, or try to
> provide a framework (i.e. propagate the flushing flag) and let each
> implementation fill the gaps.
>
> > + /*
> > + * We cleared the referenced bit in a mapping to this page. To
> > + * avoid interference with the reclaimer, mark it young so that
> > + * the next call to page_referenced() will also return > 0 (see
> > + * page_referenced_one())
> > + */
> > + set_page_young(page);
> > +}
> > +
> > +static ssize_t kpageidle_read(struct file *file, char __user *buf,
> > + size_t count, loff_t *ppos)
> > +{
> > + u64 __user *out = (u64 __user *)buf;
> > + struct page *page;
> > + unsigned long pfn, end_pfn;
> > + ssize_t ret = 0;
> > + u64 idle_bitmap = 0;
> > + int bit;
> > +
> > + if (*ppos & KPMMASK || count & KPMMASK)
> > + return -EINVAL;
> > +
> > + pfn = *ppos * BITS_PER_BYTE;
> > + if (pfn >= max_pfn)
> > + return 0;
> > +
> > + end_pfn = pfn + count * BITS_PER_BYTE;
> > + if (end_pfn > max_pfn)
> > + end_pfn = ALIGN(max_pfn, KPMBITS);
> > +
> > + for (; pfn < end_pfn; pfn++) {
> > + bit = pfn % KPMBITS;
> > + page = kpageidle_get_page(pfn);
> > + if (page) {
> > + if (page_is_idle(page)) {
> > + /*
> > + * The page might have been referenced via a
> > + * pte, in which case it is not idle. Clear
> > + * refs and recheck.
> > + */
> > + kpageidle_clear_pte_refs(page);
> > + if (page_is_idle(page))
> > + idle_bitmap |= 1ULL << bit;
> > + }
> > + put_page(page);
> > + }
> > + if (bit == KPMBITS - 1) {
> > + if (put_user(idle_bitmap, out)) {
> > + ret = -EFAULT;
> > + break;
> > + }
> > + idle_bitmap = 0;
> > + out++;
> > + }
> > + }
> > +
> > + *ppos += (char __user *)out - buf;
> > + if (!ret)
> > + ret = (char __user *)out - buf;
> > + return ret;
> > +}
> > +
> > +static ssize_t kpageidle_write(struct file *file, const char __user *buf,
>
> Your reasoning for a host wide /proc/kpageidle is well argued, but I'm
> still hesitant.
>
> mincore() shows how to (relatively simply) resolve unmapped file pages
> to their backing page cache destination. You could recycle that code
> and then you'd have per process idle/idling interfaces. With the
> advantage of a clear TLB flush demarcation.
Hmm, I still don't see how we could handle page cache that does not
belong to any process in the scope of sys_mincore.
Besides, it'd be awkward to reuse sys_mincore for idle page tracking,
because we need two operations, set idle and check idle, while the
sys_mincore semantic implies only getting information from the kernel,
not vice versa.
Of course, we could introduce a separate syscall, say sys_idlecore, but
IMO it is not a good idea to add a syscall for such a specific feature,
which can be compiled out. I think a proc file suits better for the
purpose, especially counting that we have a bunch of similar files
(pagemap, kpageflags, kpagecount).
Anyway, I'm open for suggestions. If you have a different user API
design in mind, which in your opinion would fit better, please share.
>
> > + size_t count, loff_t *ppos)
> > +{
> > + const u64 __user *in = (const u64 __user *)buf;
> > + struct page *page;
> > + unsigned long pfn, end_pfn;
> > + ssize_t ret = 0;
> > + u64 idle_bitmap = 0;
> > + int bit;
> > +
> > + if (*ppos & KPMMASK || count & KPMMASK)
> > + return -EINVAL;
> > +
> > + pfn = *ppos * BITS_PER_BYTE;
> > + if (pfn >= max_pfn)
> > + return -ENXIO;
> > +
> > + end_pfn = pfn + count * BITS_PER_BYTE;
> > + if (end_pfn > max_pfn)
> > + end_pfn = ALIGN(max_pfn, KPMBITS);
> > +
> > + for (; pfn < end_pfn; pfn++) {
>
> Relatively straight forward to teleport forward 512 (or more
> correctly: 1 << compound_order(page)) pages for THP pages, once done
> with a THP head, and avoid 511 fruitless trips down rmap.c for each
> tail.
Right, will fix.
>
> > + bit = pfn % KPMBITS;
> > + if (bit == 0) {
> > + if (get_user(idle_bitmap, in)) {
> > + ret = -EFAULT;
> > + break;
> > + }
> > + in++;
> > + }
> > + if (idle_bitmap >> bit & 1) {
> > + page = kpageidle_get_page(pfn);
> > + if (page) {
> > + kpageidle_clear_pte_refs(page);
> > + set_page_idle(page);
>
> In the common case this will make a page both young and idle. This is
> fine. We will come back to it below.
>
> > + put_page(page);
> > + }
> > + }
> > + }
> > +
> > + *ppos += (const char __user *)in - buf;
> > + if (!ret)
> > + ret = (const char __user *)in - buf;
> > + return ret;
> > +}
> > +
> > +static const struct file_operations proc_kpageidle_operations = {
> > + .llseek = mem_lseek,
> > + .read = kpageidle_read,
> > + .write = kpageidle_write,
> > +};
> > +
> > +#ifndef CONFIG_64BIT
> > +static bool need_page_idle(void)
> > +{
> > + return true;
> > +}
> > +struct page_ext_operations page_idle_ops = {
> > + .need = need_page_idle,
> > +};
> > +#endif
> > +#endif /* CONFIG_IDLE_PAGE_TRACKING */
> > +
> > static int __init proc_page_init(void)
> > {
> > proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations);
[...]
> > @@ -798,6 +798,14 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,
> > pte_unmap_unlock(pte, ptl);
>
> This is not in your patch, but further up in page_referenced_one there
> is the pmd case.
>
> So what happens on THP split? That was a leading question: you should
> propagate the young and idle flags to the split-up tail pages.
Good catch! I completely forgot about THP slit. Will fix in the next
iteration.
>
> > }
> >
> > + if (referenced && page_is_idle(page))
> > + clear_page_idle(page);
>
> Is it so expensive to just call clear without the test .. ?
This function is normally called from a relatively cold path - memory
reclaim, where we modify page->flags anyway, so I think it won't make
any difference if we drop this check.
>
> > +
> > + if (page_is_young(page)) {
> > + clear_page_young(page);
>
> referenced += test_and_clear_page_young(page) .. ?
Yeah, that does look better.
>
> > + referenced++;
> > + }
> > +
>
> Invert the order. A page can be both young and idle -- we noted that
> closer to the top of the patch.
>
> So young bumps referenced up, and then the final referenced value is
> used to clear idle.
I don't think it'd work. Look, kpageidle_write clears pte references and
sets the idle flag. If the page was referenced it also sets the young
flag in order not to interfere with the reclaimer. When kpageidle_read
is called afterwards, it must see the idle flag set iff the page has not
been referenced since kpageidle_write set it. However, if
page_referenced was not called on the page from the reclaim path, it
will still be young no matter if it has been referenced or not and
therefore will always be identified as not idle, which is incorrect.
>
> > if (referenced) {
>
> At this point, if you follow my suggestion of augmenting
> page_referenced_one with a mode indicator (for TLB flushing), you can
> set page young here. There is the added benefit of holding the
> mmap_mutex lock or vma_lock, which prevents reclaim, try_to_unmap,
> migration, from exploiting a small window where page young is not set
> but should.
Yeah, if we go with the page_referenced mode switcher you suggested
above, it's definitely worth moving set_page_young here.
Thank you for the review!
Vladimir
>
> > pra->referenced++;
> > pra->vm_flags |= vma->vm_flags;
> > diff --git a/mm/swap.c b/mm/swap.c
> > index ab7c338eda87..db43c9b4891d 100644
> > --- a/mm/swap.c
> > +++ b/mm/swap.c
> > @@ -623,6 +623,8 @@ void mark_page_accessed(struct page *page)
> > } else if (!PageReferenced(page)) {
> > SetPageReferenced(page);
> > }
> > + if (page_is_idle(page))
> > + clear_page_idle(page);
> > }
> > EXPORT_SYMBOL(mark_page_accessed);
> >
^ permalink raw reply
* Re: [RFCv3 0/5] enable migration of driver pages
From: Daniel Vetter @ 2015-07-09 13:08 UTC (permalink / raw)
To: Gioh Kim
Cc: Dave Airlie, dri-devel, Andrew Morton, jlayton, bfields, vbabka,
iamjoonsoo.kim, Al Viro, Michael S. Tsirkin, koct9i, minchan,
aquini, linux-fsdevel, open list:VIRTIO CORE, NET..., LKML, open,
list, ABI/API, Linux Memory Management List, gunho.lee, Gioh Kim
In-Reply-To: <559DB86D.40000@lge.com>
On Thu, Jul 09, 2015 at 08:55:25AM +0900, Gioh Kim wrote:
>
>
> 2015-07-09 오전 7:47에 Dave Airlie 이(가) 쓴 글:
> >>>
> >>>
> >>>Can the various in-kernel GPU drivers benefit from this? If so, wiring
> >>>up one or more of those would be helpful?
> >>
> >>
> >>I'm sure that other in-kernel GPU drivers can have benefit.
> >>It must be helpful.
> >>
> >>If I was familiar with other in-kernel GPU drivers code, I tried to patch
> >>them.
> >>It's too bad.
> >
> >I'll bring dri-devel into the loop here.
> >
> >ARM GPU developers please take a look at this stuff, Laurent, Rob,
> >Eric I suppose.
>
> I sent a patch, https://lkml.org/lkml/2015/3/24/1182, and my opinion about compaction
> to ARM GPU developers via Korea ARM branch.
> I got a reply that they had no time to review it.
>
> I hope they're interested to this patch.
i915 gpus would support 64kb and 2mb pages, but we never implemented this.
I don't think this would fit for gem based drivers since our backing
storage is shmemfs. So if we want to implement page migration (which we'd
probably want to make large pages work well) we'd need to pimp shmem to a)
hand large pages to us b) forward the migrate calls. Probably that means
we need to build our own gemfs reusing shmemfs code.
I guess something similar would apply for ttm-based drivers (which use
shmemfs just for swap-in/out but otherwise have their own page allocator,
at least sometimes).
Given all that I'd expect anything implementing migrate to just create a
gpufs thing for the backing storage, no need for more hooks. There's also
other areas for better code sharing among gpu drivers (e.g. mmu notifiers
to get off userspace pages slurped in&pinned with gup or shrinker
callbacks to get the gpu off it's memory binge). But that would all be
helper libraries in drm, not sure we need anything new from the core vm.
Also there's a bit a lack of gpu drivers from the arm world in upstream,
which is probabyl why this patch series doesn't come with a user. Might be
better to first upstream the driver before talking about additional
infrastructure that it needs.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH tip/master ] ftracetest: Update kprobe-tracer testcases because of renaming do_fork
From: Steven Rostedt @ 2015-07-09 12:03 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Vince Weaver, linux-api-u79uwXL29TY76Z2rM5mHXA, Heiko Carstens,
Shuah Khan, Linux Kernel Mailing List, Ingo Molnar, Namhyung Kim,
Ingo Molnar
In-Reply-To: <20150709101012.21228.45338.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
On Thu, 09 Jul 2015 19:10:12 +0900
Masami Hiramatsu <masami.hiramatsu.pt-FCd8Q96Dh0JBDgjK7y7TUQ@public.gmane.org> wrote:
> echo 0 > events/enable
> echo > kprobe_events
> -echo p:myevent do_fork > kprobe_events
> +echo p:myevent _do_fork > kprobe_events
> grep myevent kprobe_events
> test -d events/kprobes/myevent
> echo > kprobe_events
> diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
> index d8c7bb6..74507db 100644
> --- a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
> +++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
> @@ -5,7 +5,7 @@
>
> echo 0 > events/enable
> echo > kprobe_events
> -echo p:myevent do_fork > kprobe_events
> +echo p:myevent _do_fork > kprobe_events
> test -d events/kprobes/myevent
> echo 1 > events/kprobes/myevent/enable
> echo > kprobe_events && exit 1 # this must fail
> diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
> index c45ee27..64949d4 100644
> --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
> +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
> @@ -5,7 +5,7 @@
>
> echo 0 > events/enable
> echo > kprobe_events
> -echo 'p:testprobe do_fork $stack $stack0 +0($stack)' > kprobe_events
> +echo 'p:testprobe _do_fork $stack $stack0 +0($stack)' > kprobe_events
> grep testprobe kprobe_events
> test -d events/kprobes/testprobe
> echo 1 > events/kprobes/testprobe/enable
> diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
> index ab41d2b..d6f2f49 100644
> --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
> +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
> @@ -6,31 +6,31 @@ grep function available_tracers || exit_unsupported # this is configurable
>
> # prepare
> echo nop > current_tracer
> -echo do_fork > set_ftrace_filter
> +echo _do_fork > set_ftrace_filter
> echo 0 > events/enable
> echo > kprobe_events
> -echo 'p:testprobe do_fork' > kprobe_events
> +echo 'p:testprobe _do_fork' > kprobe_events
>
> # kprobe on / ftrace off
> echo 1 > events/kprobes/testprobe/enable
> echo > trace
> ( echo "forked")
> grep testprobe trace
> -! grep 'do_fork <-' trace
> +! grep '_do_fork <-' trace
>
> # kprobe on / ftrace on
> echo function > current_tracer
> echo > trace
> ( echo "forked")
> grep testprobe trace
> -grep 'do_fork <-' trace
> +grep '_do_fork <-' trace
>
> # kprobe off / ftrace on
> echo 0 > events/kprobes/testprobe/enable
> echo > trace
> ( echo "forked")
> ! grep testprobe trace
> -grep 'do_fork <-' trace
> +grep '_do_fork <-' trace
>
> # kprobe on / ftrace on
> echo 1 > events/kprobes/testprobe/enable
> @@ -38,14 +38,14 @@ echo function > current_tracer
> echo > trace
> ( echo "forked")
> grep testprobe trace
> -grep 'do_fork <-' trace
> +grep '_do_fork <-' trace
>
> # kprobe on / ftrace off
> echo nop > current_tracer
> echo > trace
> ( echo "forked")
> grep testprobe trace
> -! grep 'do_fork <-' trace
> +! grep '_do_fork <-' trace
>
> # cleanup
> echo nop > current_tracer
> diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
> index 3171798..0d09546 100644
> --- a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
> +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
> @@ -5,7 +5,7 @@
>
> echo 0 > events/enable
> echo > kprobe_events
> -echo 'r:testprobe2 do_fork $retval' > kprobe_events
> +echo 'r:testprobe2 _do_fork $retval' > kprobe_events
> grep testprobe2 kprobe_events
> test -d events/kprobes/testprobe2
> echo 1 > events/kprobes/testprobe2/enable
Instead of hard coding the name, what about adding a global variable
for the function, in case we need to change it again, it would only
need to be changed in one place?
-- Steve
^ permalink raw reply
* Re: [RFC 5/8] kdbus: use LSM hooks in kdbus code
From: Paul Osmialowski @ 2015-07-09 11:28 UTC (permalink / raw)
To: Sergei Zviagintsev
Cc: Lukasz Pawelczyk, Paul Moore, James Morris, Casey Schaufler,
Serge E. Hallyn, Kees Cook, Tetsuo Handa, Stephen Smalley,
Neil Brown, Mark Rustad, Greg Kroah-Hartman, Daniel Mack,
David Herrmann, Djalal Harouni, Shuah Khan, Al Viro,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Karol Lewandowski,
Lukasz Skalski, Paul Osmialowski
In-Reply-To: <20150709105510.GI25971-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
On Thu, 9 Jul 2015, Sergei Zviagintsev wrote:
> Hi,
>
> On Wed, Jul 08, 2015 at 02:12:03PM +0200, Paul Osmialowski wrote:
> [...]
>>
>> + ret = security_kdbus_bus_alloc(b);
>> + if (ret) {
>> + goto exit_unref;
>> + }
>
> checkpatch.pl will complain about this
>
>
It should but it didn't:
$ scripts/checkpatch.pl 0005-kdbus-use-LSM-hooks-in-kdbus-code.patch
total: 0 errors, 0 warnings, 365 lines checked
0005-kdbus-use-LSM-hooks-in-kdbus-code.patch has no obvious style problems
and is ready for submission.
^ permalink raw reply
* Re: [RFC 5/8] kdbus: use LSM hooks in kdbus code
From: Sergei Zviagintsev @ 2015-07-09 10:55 UTC (permalink / raw)
To: Paul Osmialowski
Cc: Lukasz Pawelczyk, Paul Moore, James Morris, Casey Schaufler,
Serge E. Hallyn, Kees Cook, Tetsuo Handa, Stephen Smalley,
Neil Brown, Mark Rustad, Greg Kroah-Hartman, Daniel Mack,
David Herrmann, Djalal Harouni, Shuah Khan, Al Viro,
linux-security-module, linux-kernel, linux-api, Karol Lewandowski,
Lukasz Skalski
In-Reply-To: <alpine.DEB.2.10.1507081411410.12441@AMDC1262.digital.local>
Hi,
On Wed, Jul 08, 2015 at 02:12:03PM +0200, Paul Osmialowski wrote:
[...]
>
> + ret = security_kdbus_bus_alloc(b);
> + if (ret) {
> + goto exit_unref;
> + }
checkpatch.pl will complain about this
^ permalink raw reply
* [PATCH tip/master ] ftracetest: Update kprobe-tracer testcases because of renaming do_fork
From: Masami Hiramatsu @ 2015-07-09 10:10 UTC (permalink / raw)
To: Steven Rostedt
Cc: Vince Weaver, linux-api, Heiko Carstens, Shuah Khan,
Linux Kernel Mailing List, Ingo Molnar, Namhyung Kim, Ingo Molnar
Since the commit 3033f14ab78c ("clone: support passing tls argument via
C rather than pt_regs magic") renames do_fork to _do_fork, the testcases
for kprobe-tracer doesn't work correctly on the latest kernel.
This fixes it by changing do_fork to _do_fork.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Reported-by: Vince Weaver <vincent.weaver@maine.edu>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
.../ftrace/test.d/kprobe/add_and_remove.tc | 2 +-
.../selftests/ftrace/test.d/kprobe/busy_check.tc | 2 +-
.../selftests/ftrace/test.d/kprobe/kprobe_args.tc | 2 +-
.../ftrace/test.d/kprobe/kprobe_ftrace.tc | 14 +++++++-------
.../ftrace/test.d/kprobe/kretprobe_args.tc | 2 +-
5 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
index a5a4262..c3843ed 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
@@ -5,7 +5,7 @@
echo 0 > events/enable
echo > kprobe_events
-echo p:myevent do_fork > kprobe_events
+echo p:myevent _do_fork > kprobe_events
grep myevent kprobe_events
test -d events/kprobes/myevent
echo > kprobe_events
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
index d8c7bb6..74507db 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
@@ -5,7 +5,7 @@
echo 0 > events/enable
echo > kprobe_events
-echo p:myevent do_fork > kprobe_events
+echo p:myevent _do_fork > kprobe_events
test -d events/kprobes/myevent
echo 1 > events/kprobes/myevent/enable
echo > kprobe_events && exit 1 # this must fail
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
index c45ee27..64949d4 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
@@ -5,7 +5,7 @@
echo 0 > events/enable
echo > kprobe_events
-echo 'p:testprobe do_fork $stack $stack0 +0($stack)' > kprobe_events
+echo 'p:testprobe _do_fork $stack $stack0 +0($stack)' > kprobe_events
grep testprobe kprobe_events
test -d events/kprobes/testprobe
echo 1 > events/kprobes/testprobe/enable
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
index ab41d2b..d6f2f49 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
@@ -6,31 +6,31 @@ grep function available_tracers || exit_unsupported # this is configurable
# prepare
echo nop > current_tracer
-echo do_fork > set_ftrace_filter
+echo _do_fork > set_ftrace_filter
echo 0 > events/enable
echo > kprobe_events
-echo 'p:testprobe do_fork' > kprobe_events
+echo 'p:testprobe _do_fork' > kprobe_events
# kprobe on / ftrace off
echo 1 > events/kprobes/testprobe/enable
echo > trace
( echo "forked")
grep testprobe trace
-! grep 'do_fork <-' trace
+! grep '_do_fork <-' trace
# kprobe on / ftrace on
echo function > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
-grep 'do_fork <-' trace
+grep '_do_fork <-' trace
# kprobe off / ftrace on
echo 0 > events/kprobes/testprobe/enable
echo > trace
( echo "forked")
! grep testprobe trace
-grep 'do_fork <-' trace
+grep '_do_fork <-' trace
# kprobe on / ftrace on
echo 1 > events/kprobes/testprobe/enable
@@ -38,14 +38,14 @@ echo function > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
-grep 'do_fork <-' trace
+grep '_do_fork <-' trace
# kprobe on / ftrace off
echo nop > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
-! grep 'do_fork <-' trace
+! grep '_do_fork <-' trace
# cleanup
echo nop > current_tracer
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
index 3171798..0d09546 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
@@ -5,7 +5,7 @@
echo 0 > events/enable
echo > kprobe_events
-echo 'r:testprobe2 do_fork $retval' > kprobe_events
+echo 'r:testprobe2 _do_fork $retval' > kprobe_events
grep testprobe2 kprobe_events
test -d events/kprobes/testprobe2
echo 1 > events/kprobes/testprobe2/enable
^ permalink raw reply related
* Re: [RFC 4/8] lsm: smack: smack callbacks for kdbus security hooks
From: Sergei Zviagintsev @ 2015-07-09 10:08 UTC (permalink / raw)
To: Paul Osmialowski
Cc: Paul Moore, James Morris, Casey Schaufler, Serge E. Hallyn,
Kees Cook, Tetsuo Handa, Stephen Smalley, Neil Brown, Mark Rustad,
Greg Kroah-Hartman, Daniel Mack, David Herrmann, Djalal Harouni,
Shuah Khan, Al Viro, linux-security-module, linux-kernel,
linux-api, Karol Lewandowski, Lukasz Skalski
In-Reply-To: <1436351110-5902-5-git-send-email-p.osmialowsk@samsung.com>
Hi,
On Wed, Jul 08, 2015 at 12:25:06PM +0200, Paul Osmialowski wrote:
> This adds implementation of three smack callbacks sitting behind kdbus
> security hooks as proposed by Karol Lewandowski.
>
> Originates from:
>
> git://git.infradead.org/users/pcmoore/selinux (branch: working-kdbus)
> commit: fc3505d058c001fe72a6f66b833e0be5b2d118f3
>
> https://github.com/lmctl/linux.git (branch: kdbus-lsm-v4.for-systemd-v212)
> commit: 103c26fd27d1ec8c32d85dd3d85681f936ac66fb
>
> Signed-off-by: Karol Lewandowski <k.lewandowsk@samsung.com>
> Signed-off-by: Paul Osmialowski <p.osmialowsk@samsung.com>
> ---
> security/smack/smack_lsm.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 68 insertions(+)
>
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index a143328..033b756 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -41,6 +41,7 @@
> #include <linux/msg.h>
> #include <linux/shm.h>
> #include <linux/binfmts.h>
> +#include <kdbus/connection.h>
> #include "smack.h"
>
> #define TRANS_TRUE "TRUE"
> @@ -3336,6 +3337,69 @@ static int smack_setprocattr(struct task_struct *p, char *name,
> }
>
> /**
> + * smack_kdbus_connect - Set the security blob for a KDBus connection
> + * @conn: the connection
> + * @secctx: smack label
> + * @seclen: smack label length
> + *
> + * Returns 0
> + */
> +static int smack_kdbus_connect(struct kdbus_conn *conn,
> + const char *secctx, u32 seclen)
> +{
> + struct smack_known *skp;
> +
> + if (secctx && seclen > 0)
> + skp = smk_import_entry(secctx, seclen);
> + else
> + skp = smk_of_current();
> + conn->security = skp;
> +
> + return 0;
> +}
> +
> +/**
> + * smack_kdbus_conn_free - Clear the security blob for a KDBus connection
> + * @conn: the connection
> + *
> + * Clears the blob pointer
> + */
> +static void smack_kdbus_conn_free(struct kdbus_conn *conn)
> +{
> + conn->security = NULL;
> +}
> +
> +/**
> + * smack_kdbus_talk - Smack access on KDBus
> + * @src: source kdbus connection
> + * @dst: destination kdbus connection
> + *
> + * Return 0 if a subject with the smack of sock could access
> + * an object with the smack of other, otherwise an error code
> + */
> +static int smack_kdbus_talk(const struct kdbus_conn *src,
> + const struct kdbus_conn *dst)
> +{
> + struct smk_audit_info ad;
> + struct smack_known *sskp = src->security;
> + struct smack_known *dskp = dst->security;
> + int ret;
> +
> + BUG_ON(sskp == NULL);
> + BUG_ON(dskp == NULL);
I am not familiar with the smack code so far, but I see that current
security/smack/smack_lsm.c contains only one BUG_ON and this patch adds
another two.
> +
> + if (smack_privileged(CAP_MAC_OVERRIDE))
> + return 0;
> +
> + smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NONE);
> +
> + ret = smk_access(sskp, dskp, MAY_WRITE, &ad);
> + if (ret)
> + return ret;
> + return 0;
Three redundant lines here.
> +}
> +
> +/**
> * smack_unix_stream_connect - Smack access on UDS
> * @sock: one sock
> * @other: the other sock
> @@ -4393,6 +4457,10 @@ struct security_hook_list smack_hooks[] = {
> LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
> LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
> LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),
> +
> + LSM_HOOK_INIT(kdbus_connect, smack_kdbus_connect),
> + LSM_HOOK_INIT(kdbus_conn_free, smack_kdbus_conn_free),
> + LSM_HOOK_INIT(kdbus_talk, smack_kdbus_talk),
> };
>
>
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH] fs, proc: add help for CONFIG_PROC_CHILDREN
From: Jean Delvare @ 2015-07-09 9:04 UTC (permalink / raw)
To: Iago López Galeiras
Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Cyrill Gorcunov, Andrew Morton,
Djalal Harouni, Alban Crequy
In-Reply-To: <1436387284-3998-1-git-send-email-iago-973cpzSjLbNWk0Htik3J/w@public.gmane.org>
Le Wednesday 08 July 2015 à 22:28 +0200, Iago López Galeiras a écrit :
> The purpose of the option was documented in
> Documentation/filesystems/proc.txt but the help text was missing.
>
> Add small help text that also points to the documentation.
>
> Signed-off-by: Iago López Galeiras <iago-973cpzSjLbNWk0Htik3J/w@public.gmane.org>
> ---
> fs/proc/Kconfig | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
> index d751fcb..1ade120 100644
> --- a/fs/proc/Kconfig
> +++ b/fs/proc/Kconfig
> @@ -75,3 +75,9 @@ config PROC_PAGE_MONITOR
> config PROC_CHILDREN
> bool "Include /proc/<pid>/task/<tid>/children file"
> default n
> + help
> + Provides a fast way to retrieve first level children pids of a task. See
> + <file:Documentation/filesystems/proc.txt> for more information.
> +
> + Say Y if you are running any user-space software which takes benefit from
> + this interface. For example, rkt is such a piece of software.
Thanks for doing that.
Reviewed-by: Jean Delvare <jdelvare-l3A5Bk7waGM@public.gmane.org>
--
Jean Delvare
SUSE L3 Support
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox