2015-12-08 14:06:04

by Andrew Lunn

[permalink] [raw]
Subject: [PATCH 0/6] Convert existing EEPROM drivers to NVMEM

This patches converts the old EEPROM drivers in driver/misc/eeprom to
use the NVMEM framework. These drivers export there content in /sys as
read only to root, since the EEPROM may contain sensitive information.
So the first patch adds a flag so the NVMEM framework will create its
file in /sys as root read only.

To keep backwards compatibility with these older drivers, the contents
of the EEPROM must be exports in sysfs in a file called eeprom in the
devices node in sys, where as the NVMEM places them under class/nvmem.
So add this optional backwards compatible to the framework.

Then convert the at24, at25 and 93xx46 by adding regmap support,
removing each drivers own /sys code and registering with the NVMEM
framework.

AT24 and 93xx46 has been boot tested, at25 compile tested only.

Andrew Lunn (6):
nvmem: Add flag to export NVMEM to root only
nvmem: Add backwards compatibility support for older EEPROM drivers.
eeprom: at24: extend driver to plug into the NVMEM framework
eeprom: at25: Remove in kernel API for accessing the EEPROM
eeprom: at25: extend driver to plug into the NVMEM framework
eeprom: 93xx46: extend driver to plug into the NVMEM framework

drivers/misc/eeprom/Kconfig | 9 +++
drivers/misc/eeprom/at24.c | 119 +++++++++++++++++++----------
drivers/misc/eeprom/at25.c | 147 ++++++++++++++++--------------------
drivers/misc/eeprom/eeprom_93xx46.c | 121 ++++++++++++++++++++++-------
drivers/nvmem/Kconfig | 7 ++
drivers/nvmem/core.c | 132 ++++++++++++++++++++++++++++++--
include/linux/nvmem-provider.h | 11 +++
include/linux/spi/eeprom.h | 2 -
8 files changed, 393 insertions(+), 155 deletions(-)

--
2.6.2


2015-12-08 14:05:56

by Andrew Lunn

[permalink] [raw]
Subject: [PATCH 1/6] nvmem: Add flag to export NVMEM to root only

Legacy AT24, AT25 EEPROMs are exported in sys so that only root can
read the contents. The EEPROMs may contain sensitive information. Add
a flag so the provide can indicate that NVMEM should also restrict
access to root only.

Signed-off-by: Andrew Lunn <[email protected]>
---
drivers/nvmem/core.c | 57 ++++++++++++++++++++++++++++++++++++++++--
include/linux/nvmem-provider.h | 1 +
2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 6fd4e5a5ef4a..4ccf03da6467 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -155,6 +155,53 @@ static const struct attribute_group *nvmem_ro_dev_groups[] = {
NULL,
};

+/* default read/write permissions, root only */
+static struct bin_attribute bin_attr_rw_root_nvmem = {
+ .attr = {
+ .name = "nvmem",
+ .mode = S_IWUSR | S_IRUSR,
+ },
+ .read = bin_attr_nvmem_read,
+ .write = bin_attr_nvmem_write,
+};
+
+static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
+ &bin_attr_rw_root_nvmem,
+ NULL,
+};
+
+static const struct attribute_group nvmem_bin_rw_root_group = {
+ .bin_attrs = nvmem_bin_rw_root_attributes,
+};
+
+static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
+ &nvmem_bin_rw_root_group,
+ NULL,
+};
+
+/* read only permission, root only */
+static struct bin_attribute bin_attr_ro_root_nvmem = {
+ .attr = {
+ .name = "nvmem",
+ .mode = S_IRUSR,
+ },
+ .read = bin_attr_nvmem_read,
+};
+
+static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
+ &bin_attr_ro_root_nvmem,
+ NULL,
+};
+
+static const struct attribute_group nvmem_bin_ro_root_group = {
+ .bin_attrs = nvmem_bin_ro_root_attributes,
+};
+
+static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
+ &nvmem_bin_ro_root_group,
+ NULL,
+};
+
static void nvmem_release(struct device *dev)
{
struct nvmem_device *nvmem = to_nvmem_device(dev);
@@ -347,8 +394,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
nvmem->read_only = of_property_read_bool(np, "read-only") |
config->read_only;

- nvmem->dev.groups = nvmem->read_only ? nvmem_ro_dev_groups :
- nvmem_rw_dev_groups;
+ if (config->root_only)
+ nvmem->dev.groups = nvmem->read_only ?
+ nvmem_ro_root_dev_groups :
+ nvmem_rw_root_dev_groups;
+ else
+ nvmem->dev.groups = nvmem->read_only ?
+ nvmem_ro_dev_groups :
+ nvmem_rw_dev_groups;

device_initialize(&nvmem->dev);

diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 0b68caff1b3c..d24fefa0c11d 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -23,6 +23,7 @@ struct nvmem_config {
const struct nvmem_cell_info *cells;
int ncells;
bool read_only;
+ bool root_only;
};

#if IS_ENABLED(CONFIG_NVMEM)
--
2.6.2

2015-12-08 14:05:48

by Andrew Lunn

[permalink] [raw]
Subject: [PATCH 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers.

Older drivers made an 'eeprom' file available in the /sys device
directory. Have the NVMEM core provide this to retain backwards
compatibility.

Signed-off-by: Andrew Lunn <[email protected]>
---
drivers/nvmem/Kconfig | 7 ++++
drivers/nvmem/core.c | 75 +++++++++++++++++++++++++++++++++++++++---
include/linux/nvmem-provider.h | 10 ++++++
3 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index bc4ea585b42e..b4e79ba7d502 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -13,6 +13,13 @@ menuconfig NVMEM
If unsure, say no.

if NVMEM
+config NVMEM_COMPAT
+ bool "Enable /sys compatibility with old eeprom drivers"
+ help
+ Older EEPROM drivers, such as AT24, AT25, provide access to
+ the eeprom via a file called "eeprom" in /sys under the
+ device node. Enabling this option makes the NVMEM core
+ provide this file to retain backwards compatibility

config NVMEM_IMX_OCOTP
tristate "i.MX6 On-Chip OTP Controller support"
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 4ccf03da6467..75a498f5e139 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -38,8 +38,13 @@ struct nvmem_device {
int users;
size_t size;
bool read_only;
+ int flags;
+ struct bin_attribute eeprom;
+ struct device *base_dev;
};

+#define FLAG_COMPAT BIT(0)
+
struct nvmem_cell {
const char *name;
int offset;
@@ -62,10 +67,16 @@ 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);
+ struct device *dev;
+ struct nvmem_device *nvmem;
int rc;

+ if (attr->private)
+ dev = attr->private;
+ else
+ dev = container_of(kobj, struct device, kobj);
+ nvmem = to_nvmem_device(dev);
+
/* Stop the user from reading */
if (pos >= nvmem->size)
return 0;
@@ -87,10 +98,16 @@ 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);
+ struct device *dev;
+ struct nvmem_device *nvmem;
int rc;

+ if (attr->private)
+ dev = attr->private;
+ else
+ dev = container_of(kobj, struct device, kobj);
+ nvmem = to_nvmem_device(dev);
+
/* Stop the user from writing */
if (pos >= nvmem->size)
return 0;
@@ -421,6 +438,53 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
}
EXPORT_SYMBOL_GPL(nvmem_register);

+#if IS_ENABLED(CONFIG_NVMEM_COMPAT)
+/**
+ * nvmem_register_compat() - Register a nvmem device for given nvmem_config.
+ * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem and
+ * an eeprom file in the drivers sys directory.
+ *
+ * @config: nvmem device configuration with which nvmem device is created.
+ * @dev: device structure of underlying device
+ *
+ * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
+ * on success.
+ */
+
+struct nvmem_device *nvmem_register_compat(const struct nvmem_config *config,
+ struct device *base_dev)
+{
+ struct nvmem_device *nvmem;
+ int rval;
+
+ nvmem = nvmem_register(config);
+ if (IS_ERR(nvmem))
+ return nvmem;
+
+ if (nvmem->read_only)
+ nvmem->eeprom = bin_attr_ro_root_nvmem;
+ else
+ nvmem->eeprom = bin_attr_rw_root_nvmem;
+ nvmem->eeprom.attr.name = "eeprom";
+ nvmem->eeprom.size = nvmem->size;
+ nvmem->eeprom.private = &nvmem->dev;
+ nvmem->base_dev = base_dev;
+
+ rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
+ if (rval) {
+ dev_err(&nvmem->dev,
+ "Failed to create eeprom binary file %d\n", rval);
+ nvmem_unregister(nvmem);
+ return ERR_PTR(rval);
+ }
+
+ nvmem->flags |= FLAG_COMPAT;
+
+ return nvmem;
+}
+EXPORT_SYMBOL_GPL(nvmem_register_compat);
+#endif /* CONFIG_NVMEM_COMPAT */
+
/**
* nvmem_unregister() - Unregister previously registered nvmem device
*
@@ -437,6 +501,9 @@ int nvmem_unregister(struct nvmem_device *nvmem)
}
mutex_unlock(&nvmem_mutex);

+ if (nvmem->flags & FLAG_COMPAT)
+ device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
+
nvmem_device_remove_all_cells(nvmem);
device_del(&nvmem->dev);

diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index d24fefa0c11d..012030bd4495 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -45,4 +45,14 @@ static inline int nvmem_unregister(struct nvmem_device *nvmem)

#endif /* CONFIG_NVMEM */

+#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_NVMEM_COMPAT)
+struct nvmem_device *nvmem_register_compat(const struct nvmem_config *config,
+ struct device *base_dev);
+#else
+static inline struct nvmem_device *
+nvmem_register_compat(const struct nvmem_config *c, struct device *base_dev)
+{
+ return ERR_PTR(-ENOSYS);
+}
+#endif /* CONFIG_NVMEM && CONFIG_NVMEM_COMPAT */
#endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
--
2.6.2

2015-12-08 14:05:25

by Andrew Lunn

[permalink] [raw]
Subject: [PATCH 3/6] eeprom: at24: extend driver to plug into the NVMEM framework

Add a regmap for accessing the EEPROM, and then use that with the
NVMEM framework. Use it backward compatibility register function, so
that the 'eeprom' file in sys is provided by the framework.

Signed-off-by: Andrew Lunn <[email protected]>
---
drivers/misc/eeprom/Kconfig | 3 ++
drivers/misc/eeprom/at24.c | 119 +++++++++++++++++++++++++++++---------------
2 files changed, 81 insertions(+), 41 deletions(-)

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1fa9dd1..21d409730221 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -3,6 +3,9 @@ menu "EEPROM support"
config EEPROM_AT24
tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
depends on I2C && SYSFS
+ select REGMAP
+ select NVMEM
+ select NVMEM_COMPAT
help
Enable this driver to get read/write support to most I2C EEPROMs
and compatible devices like FRAMs, SRAMs, ROMs etc. After you
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 5d7c0900fa1b..84e348c1620c 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -15,7 +15,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
-#include <linux/sysfs.h>
#include <linux/mod_devicetable.h>
#include <linux/log2.h>
#include <linux/bitops.h>
@@ -23,6 +22,8 @@
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
#include <linux/platform_data/at24.h>

/*
@@ -64,12 +65,15 @@ struct at24_data {
* but not from changes by other I2C masters.
*/
struct mutex lock;
- struct bin_attribute bin;

u8 *writebuf;
unsigned write_max;
unsigned num_addresses;

+ struct regmap_config regmap_config;
+ struct nvmem_config nvmem_config;
+ struct nvmem_device *nvmem;
+
/*
* Some chips tie up multiple I2C addresses; dummy devices reserve
* them for us, and we'll use them with SMBus calls.
@@ -283,17 +287,6 @@ static ssize_t at24_read(struct at24_data *at24,
return retval;
}

-static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t off, size_t count)
-{
- struct at24_data *at24;
-
- at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
- return at24_read(at24, buf, off, count);
-}
-
-
/*
* Note that if the hardware write-protect pin is pulled high, the whole
* chip is normally write protected. But there are plenty of product
@@ -414,16 +407,6 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
return retval;
}

-static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t off, size_t count)
-{
- struct at24_data *at24;
-
- at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
- return at24_write(at24, buf, off, count);
-}
-
/*-------------------------------------------------------------------------*/

/*
@@ -450,6 +433,49 @@ static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf,

/*-------------------------------------------------------------------------*/

+/*
+ * Provide a regmap interface, which is registered with the NVMEM
+ * framework
+*/
+static int at24_regmap_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct at24_data *at24 = context;
+ off_t offset = *(u32 *)reg;
+ int err;
+
+ err = at24_read(at24, val, offset, val_size);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int at24_regmap_write(void *context, const void *data, size_t count)
+{
+ struct at24_data *at24 = context;
+ const char *buf;
+ u32 offset;
+ size_t len;
+ int err;
+
+ memcpy(&offset, data, sizeof(offset));
+ buf = (const char *)data + sizeof(offset);
+ len = count - sizeof(offset);
+
+ err = at24_write(at24, buf, offset, len);
+ if (err)
+ return err;
+ return 0;
+}
+
+static const struct regmap_bus at24_regmap_bus = {
+ .read = at24_regmap_read,
+ .write = at24_regmap_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+/*-------------------------------------------------------------------------*/
+
#ifdef CONFIG_OF
static void at24_get_ofdata(struct i2c_client *client,
struct at24_platform_data *chip)
@@ -481,6 +507,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct at24_data *at24;
int err;
unsigned i, num_addresses;
+ struct regmap *regmap;

if (client->dev.platform_data) {
chip = *(struct at24_platform_data *)client->dev.platform_data;
@@ -573,16 +600,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
at24->chip = chip;
at24->num_addresses = num_addresses;

- /*
- * Export the EEPROM bytes through sysfs, since that's convenient.
- * By default, only root should see the data (maybe passwords etc)
- */
- sysfs_bin_attr_init(&at24->bin);
- at24->bin.attr.name = "eeprom";
- at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
- at24->bin.read = at24_bin_read;
- at24->bin.size = chip.byte_len;
-
at24->macc.read = at24_macc_read;

writable = !(chip.flags & AT24_FLAG_READONLY);
@@ -593,9 +610,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)

at24->macc.write = at24_macc_write;

- at24->bin.write = at24_bin_write;
- at24->bin.attr.mode |= S_IWUSR;
-
if (write_max > io_limit)
write_max = io_limit;
if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
@@ -627,14 +641,36 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
}

- err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
- if (err)
+ at24->regmap_config.reg_bits = 32;
+ at24->regmap_config.val_bits = 8;
+ at24->regmap_config.reg_stride = 1;
+ at24->regmap_config.max_register = chip.byte_len - 1;
+
+ regmap = devm_regmap_init(&client->dev, &at24_regmap_bus, at24,
+ &at24->regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "regmap init failed\n");
+ err = PTR_ERR(regmap);
goto err_clients;
+ }
+
+ at24->nvmem_config.name = dev_name(&client->dev);
+ at24->nvmem_config.dev = &client->dev;
+ at24->nvmem_config.read_only = !writable;
+ at24->nvmem_config.root_only = true;
+ at24->nvmem_config.owner = THIS_MODULE;
+
+ at24->nvmem = nvmem_register_compat(&at24->nvmem_config,
+ &client->dev);
+ if (IS_ERR(at24->nvmem)) {
+ err = PTR_ERR(at24->nvmem);
+ goto err_clients;
+ }

i2c_set_clientdata(client, at24);

- dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",
- at24->bin.size, client->name,
+ dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
+ chip.byte_len, client->name,
writable ? "writable" : "read-only", at24->write_max);
if (use_smbus == I2C_SMBUS_WORD_DATA ||
use_smbus == I2C_SMBUS_BYTE_DATA) {
@@ -663,7 +699,8 @@ static int at24_remove(struct i2c_client *client)
int i;

at24 = i2c_get_clientdata(client);
- sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
+
+ nvmem_unregister(at24->nvmem);

for (i = 1; i < at24->num_addresses; i++)
i2c_unregister_device(at24->client[i]);
--
2.6.2

2015-12-08 14:06:13

by Andrew Lunn

[permalink] [raw]
Subject: [PATCH 4/6] eeprom: at25: Remove in kernel API for accessing the EEPROM

The setup() callback is not used by any in kernel code. Remove it.
Any new code which requires access to the eeprom can use the NVMEM
API.

Signed-off-by: Andrew Lunn <[email protected]>
---
drivers/misc/eeprom/at25.c | 26 --------------------------
include/linux/spi/eeprom.h | 2 --
2 files changed, 28 deletions(-)

diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index f850ef556bcc..4732f6997289 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -29,7 +29,6 @@

struct at25_data {
struct spi_device *spi;
- struct memory_accessor mem;
struct mutex lock;
struct spi_eeprom chip;
struct bin_attribute bin;
@@ -281,26 +280,6 @@ at25_bin_write(struct file *filp, struct kobject *kobj,

/*-------------------------------------------------------------------------*/

-/* Let in-kernel code access the eeprom data. */
-
-static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf,
- off_t offset, size_t count)
-{
- struct at25_data *at25 = container_of(mem, struct at25_data, mem);
-
- return at25_ee_read(at25, buf, offset, count);
-}
-
-static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
- off_t offset, size_t count)
-{
- struct at25_data *at25 = container_of(mem, struct at25_data, mem);
-
- return at25_ee_write(at25, buf, offset, count);
-}
-
-/*-------------------------------------------------------------------------*/
-
static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
u32 val;
@@ -415,22 +394,17 @@ static int at25_probe(struct spi_device *spi)
at25->bin.attr.name = "eeprom";
at25->bin.attr.mode = S_IRUSR;
at25->bin.read = at25_bin_read;
- at25->mem.read = at25_mem_read;

at25->bin.size = at25->chip.byte_len;
if (!(chip.flags & EE_READONLY)) {
at25->bin.write = at25_bin_write;
at25->bin.attr.mode |= S_IWUSR;
- at25->mem.write = at25_mem_write;
}

err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
if (err)
return err;

- if (chip.setup)
- chip.setup(&at25->mem, chip.context);
-
dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
(at25->bin.size < 1024)
? at25->bin.size
diff --git a/include/linux/spi/eeprom.h b/include/linux/spi/eeprom.h
index 403e007aef68..e34e169f9dcb 100644
--- a/include/linux/spi/eeprom.h
+++ b/include/linux/spi/eeprom.h
@@ -30,8 +30,6 @@ struct spi_eeprom {
*/
#define EE_INSTR_BIT3_IS_ADDR 0x0010

- /* for exporting this chip's data to other kernel code */
- void (*setup)(struct memory_accessor *mem, void *context);
void *context;
};

--
2.6.2

2015-12-08 14:05:40

by Andrew Lunn

[permalink] [raw]
Subject: [PATCH 5/6] eeprom: at25: extend driver to plug into the NVMEM framework

Add a regmap for accessing the EEPROM, and then use that with the
NVMEM framework. Use it backward compatibility register function, so
that the 'eeprom' file in sys is provided by the framework.

Signed-off-by: Andrew Lunn <[email protected]>
---
drivers/misc/eeprom/Kconfig | 3 ++
drivers/misc/eeprom/at25.c | 123 ++++++++++++++++++++++++--------------------
2 files changed, 71 insertions(+), 55 deletions(-)

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 21d409730221..ff3e1dd751ec 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -33,6 +33,9 @@ config EEPROM_AT24
config EEPROM_AT25
tristate "SPI EEPROMs from most vendors"
depends on SPI && SYSFS
+ select REGMAP
+ select NVMEM
+ select NVMEM_COMPAT
help
Enable this driver to get read/write support to most SPI EEPROMs,
after you configure the board init code to know about each eeprom
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 4732f6997289..327db31153ec 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -16,6 +16,8 @@
#include <linux/device.h>
#include <linux/sched.h>

+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
#include <linux/property.h>
@@ -31,8 +33,10 @@ struct at25_data {
struct spi_device *spi;
struct mutex lock;
struct spi_eeprom chip;
- struct bin_attribute bin;
unsigned addrlen;
+ struct regmap_config regmap_config;
+ struct nvmem_config nvmem_config;
+ struct nvmem_device *nvmem;
};

#define AT25_WREN 0x06 /* latch the write enable */
@@ -76,10 +80,10 @@ at25_ee_read(
struct spi_message m;
u8 instr;

- if (unlikely(offset >= at25->bin.size))
+ if (unlikely(offset >= at25->chip.byte_len))
return 0;
- if ((offset + count) > at25->bin.size)
- count = at25->bin.size - offset;
+ if ((offset + count) > at25->chip.byte_len)
+ count = at25->chip.byte_len - offset;
if (unlikely(!count))
return count;

@@ -130,21 +134,19 @@ at25_ee_read(
return status ? status : count;
}

-static ssize_t
-at25_bin_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static int at25_regmap_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
{
- struct device *dev;
- struct at25_data *at25;
-
- dev = container_of(kobj, struct device, kobj);
- at25 = dev_get_drvdata(dev);
+ struct at25_data *at25 = context;
+ off_t offset = *(u32 *)reg;
+ int err;

- return at25_ee_read(at25, buf, off, count);
+ err = at25_ee_read(at25, val, offset, val_size);
+ if (err)
+ return err;
+ return 0;
}

-
static ssize_t
at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
size_t count)
@@ -154,10 +156,10 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
unsigned buf_size;
u8 *bounce;

- if (unlikely(off >= at25->bin.size))
+ if (unlikely(off >= at25->chip.byte_len))
return -EFBIG;
- if ((off + count) > at25->bin.size)
- count = at25->bin.size - off;
+ if ((off + count) > at25->chip.byte_len)
+ count = at25->chip.byte_len - off;
if (unlikely(!count))
return count;

@@ -264,20 +266,30 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
return written ? written : status;
}

-static ssize_t
-at25_bin_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static int at25_regmap_write(void *context, const void *data, size_t count)
{
- struct device *dev;
- struct at25_data *at25;
+ struct at25_data *at25 = context;
+ const char *buf;
+ u32 offset;
+ size_t len;
+ int err;

- dev = container_of(kobj, struct device, kobj);
- at25 = dev_get_drvdata(dev);
+ memcpy(&offset, data, sizeof(offset));
+ buf = (const char *)data + sizeof(offset);
+ len = count - sizeof(offset);

- return at25_ee_write(at25, buf, off, count);
+ err = at25_ee_write(at25, buf, offset, len);
+ if (err)
+ return err;
+ return 0;
}

+static const struct regmap_bus at25_regmap_bus = {
+ .read = at25_regmap_read,
+ .write = at25_regmap_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
/*-------------------------------------------------------------------------*/

static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
@@ -337,6 +349,7 @@ static int at25_probe(struct spi_device *spi)
{
struct at25_data *at25 = NULL;
struct spi_eeprom chip;
+ struct regmap *regmap;
int err;
int sr;
int addrlen;
@@ -381,35 +394,34 @@ static int at25_probe(struct spi_device *spi)
spi_set_drvdata(spi, at25);
at25->addrlen = addrlen;

- /* Export the EEPROM bytes through sysfs, since that's convenient.
- * And maybe to other kernel code; it might hold a board's Ethernet
- * address, or board-specific calibration data generated on the
- * manufacturing floor.
- *
- * Default to root-only access to the data; EEPROMs often hold data
- * that's sensitive for read and/or write, like ethernet addresses,
- * security codes, board-specific manufacturing calibrations, etc.
- */
- sysfs_bin_attr_init(&at25->bin);
- at25->bin.attr.name = "eeprom";
- at25->bin.attr.mode = S_IRUSR;
- at25->bin.read = at25_bin_read;
-
- at25->bin.size = at25->chip.byte_len;
- if (!(chip.flags & EE_READONLY)) {
- at25->bin.write = at25_bin_write;
- at25->bin.attr.mode |= S_IWUSR;
- }
+ at25->regmap_config.reg_bits = 32;
+ at25->regmap_config.val_bits = 8;
+ at25->regmap_config.reg_stride = 1;
+ at25->regmap_config.max_register = chip.byte_len - 1;

- err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
- if (err)
- return err;
+ regmap = devm_regmap_init(&spi->dev, &at25_regmap_bus, at25,
+ &at25->regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "regmap init failed\n");
+ return PTR_ERR(regmap);
+ }

- dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
- (at25->bin.size < 1024)
- ? at25->bin.size
- : (at25->bin.size / 1024),
- (at25->bin.size < 1024) ? "Byte" : "KByte",
+ at25->nvmem_config.name = dev_name(&spi->dev);
+ at25->nvmem_config.dev = &spi->dev;
+ at25->nvmem_config.read_only = chip.flags & EE_READONLY;
+ at25->nvmem_config.root_only = true;
+ at25->nvmem_config.owner = THIS_MODULE;
+
+ at25->nvmem = nvmem_register_compat(&at25->nvmem_config,
+ &spi->dev);
+ if (IS_ERR(at25->nvmem))
+ return PTR_ERR(at25->nvmem);
+
+ dev_info(&spi->dev, "%d %s %s eeprom%s, pagesize %u\n",
+ (chip.byte_len < 1024)
+ ? chip.byte_len
+ : (chip.byte_len / 1024),
+ (chip.byte_len < 1024) ? "Byte" : "KByte",
at25->chip.name,
(chip.flags & EE_READONLY) ? " (readonly)" : "",
at25->chip.page_size);
@@ -421,7 +433,8 @@ static int at25_remove(struct spi_device *spi)
struct at25_data *at25;

at25 = spi_get_drvdata(spi);
- sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);
+ nvmem_unregister(at25->nvmem);
+
return 0;
}

--
2.6.2

2015-12-08 14:05:32

by Andrew Lunn

[permalink] [raw]
Subject: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework

Add a regmap for accessing the EEPROM, and then use that with the
NVMEM framework. Use it backward compatibility register function, so
that the 'eeprom' file in sys is provided by the framework.

Signed-off-by: Andrew Lunn <[email protected]>
---
drivers/misc/eeprom/Kconfig | 3 +
drivers/misc/eeprom/eeprom_93xx46.c | 121 ++++++++++++++++++++++++++++--------
2 files changed, 98 insertions(+), 26 deletions(-)

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index ff3e1dd751ec..5dfa2c2c2277 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -80,6 +80,9 @@ config EEPROM_93CX6
config EEPROM_93XX46
tristate "Microwire EEPROM 93XX46 support"
depends on SPI && SYSFS
+ select REGMAP
+ select NVMEM
+ select NVMEM_COMPAT
help
Driver for the microwire EEPROM chipsets 93xx46x. The driver
supports both read and write commands and also the command to
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index ff63f05edc76..aa75f59abfba 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -15,7 +15,8 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/sysfs.h>
+#include <linux/nvmem-provider.h>
+#include <linux/regmap.h>
#include <linux/eeprom_93xx46.h>

#define OP_START 0x4
@@ -28,25 +29,29 @@
struct eeprom_93xx46_dev {
struct spi_device *spi;
struct eeprom_93xx46_platform_data *pdata;
- struct bin_attribute bin;
struct mutex lock;
+ struct regmap_config regmap_config;
+ struct nvmem_config nvmem_config;
+ struct nvmem_device *nvmem;
int addrlen;
+ int size;
};

static ssize_t
-eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+eeprom_93xx46_read(struct eeprom_93xx46_dev *edev, char *buf,
+ unsigned off, size_t count)
{
- struct eeprom_93xx46_dev *edev;
- struct device *dev;
struct spi_message m;
struct spi_transfer t[2];
int bits, ret;
u16 cmd_addr;

- dev = container_of(kobj, struct device, kobj);
- edev = dev_get_drvdata(dev);
+ if (unlikely(off >= edev->size))
+ return 0;
+ if ((off + count) > edev->size)
+ count = edev->size - off;
+ if (unlikely(!count))
+ return count;

cmd_addr = OP_READ << edev->addrlen;

@@ -94,6 +99,7 @@ eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj,
return ret ? : count;
}

+
static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
{
struct spi_message m;
@@ -182,16 +188,17 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
}

static ssize_t
-eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+eeprom_93xx46_write(struct eeprom_93xx46_dev *edev, const char *buf,
+ loff_t off, size_t count)
{
- struct eeprom_93xx46_dev *edev;
- struct device *dev;
int i, ret, step = 1;

- dev = container_of(kobj, struct device, kobj);
- edev = dev_get_drvdata(dev);
+ if (unlikely(off >= edev->size))
+ return -EFBIG;
+ if ((off + count) > edev->size)
+ count = edev->size - off;
+ if (unlikely(!count))
+ return count;

/* only write even number of bytes on 16-bit devices */
if (edev->addrlen == 6) {
@@ -228,6 +235,49 @@ eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
return ret ? : count;
}

+/*
+ * Provide a regmap interface, which is registered with the NVMEM
+ * framework
+*/
+static int eeprom_93xx46_regmap_read(void *context, const void *reg,
+ size_t reg_size, void *val,
+ size_t val_size)
+{
+ struct eeprom_93xx46_dev *eeprom_93xx46 = context;
+ off_t offset = *(u32 *)reg;
+ int err;
+
+ err = eeprom_93xx46_read(eeprom_93xx46, val, offset, val_size);
+ if (err)
+ return err;
+ return 0;
+}
+
+static int eeprom_93xx46_regmap_write(void *context, const void *data,
+ size_t count)
+{
+ struct eeprom_93xx46_dev *eeprom_93xx46 = context;
+ const char *buf;
+ u32 offset;
+ size_t len;
+ int err;
+
+ memcpy(&offset, data, sizeof(offset));
+ buf = (const char *)data + sizeof(offset);
+ len = count - sizeof(offset);
+
+ err = eeprom_93xx46_write(eeprom_93xx46, buf, offset, len);
+ if (err)
+ return err;
+ return 0;
+}
+
+static const struct regmap_bus eeprom_93xx46_regmap_bus = {
+ .read = eeprom_93xx46_regmap_read,
+ .write = eeprom_93xx46_regmap_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
{
struct eeprom_93xx46_platform_data *pd = edev->pdata;
@@ -298,6 +348,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
{
struct eeprom_93xx46_platform_data *pd;
struct eeprom_93xx46_dev *edev;
+ struct regmap *regmap;
int err;

pd = spi->dev.platform_data;
@@ -325,19 +376,36 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
edev->spi = spi_dev_get(spi);
edev->pdata = pd;

- sysfs_bin_attr_init(&edev->bin);
- edev->bin.attr.name = "eeprom";
- edev->bin.attr.mode = S_IRUSR;
- edev->bin.read = eeprom_93xx46_bin_read;
- edev->bin.size = 128;
+ edev->size = 128;
+
if (!(pd->flags & EE_READONLY)) {
- edev->bin.write = eeprom_93xx46_bin_write;
- edev->bin.attr.mode |= S_IWUSR;
}

- err = sysfs_create_bin_file(&spi->dev.kobj, &edev->bin);
- if (err)
+ edev->regmap_config.reg_bits = 32;
+ edev->regmap_config.val_bits = 8;
+ edev->regmap_config.reg_stride = 1;
+ edev->regmap_config.max_register = edev->size - 1;
+
+ regmap = devm_regmap_init(&spi->dev, &eeprom_93xx46_regmap_bus, edev,
+ &edev->regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "regmap init failed\n");
+ err = PTR_ERR(regmap);
goto fail;
+ }
+
+ edev->nvmem_config.name = dev_name(&spi->dev);
+ edev->nvmem_config.dev = &spi->dev;
+ edev->nvmem_config.read_only = pd->flags & EE_READONLY;
+ edev->nvmem_config.root_only = true;
+ edev->nvmem_config.owner = THIS_MODULE;
+
+ edev->nvmem = nvmem_register_compat(&edev->nvmem_config,
+ &spi->dev);
+ if (IS_ERR(edev->nvmem)) {
+ err = PTR_ERR(edev->nvmem);
+ goto fail;
+ }

dev_info(&spi->dev, "%d-bit eeprom %s\n",
(pd->flags & EE_ADDR8) ? 8 : 16,
@@ -359,10 +427,11 @@ static int eeprom_93xx46_remove(struct spi_device *spi)
{
struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);

+ nvmem_unregister(edev->nvmem);
+
if (!(edev->pdata->flags & EE_READONLY))
device_remove_file(&spi->dev, &dev_attr_erase);

- sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
kfree(edev);
return 0;
}
--
2.6.2

2015-12-11 13:03:42

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers.

On Tue, Dec 08, 2015 at 03:05:07PM +0100, Andrew Lunn wrote:
> Older drivers made an 'eeprom' file available in the /sys device
> directory. Have the NVMEM core provide this to retain backwards
> compatibility.
>
> Signed-off-by: Andrew Lunn <[email protected]>
> ---
> drivers/nvmem/Kconfig | 7 ++++
> drivers/nvmem/core.c | 75 +++++++++++++++++++++++++++++++++++++++---
> include/linux/nvmem-provider.h | 10 ++++++
> 3 files changed, 88 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> index bc4ea585b42e..b4e79ba7d502 100644
> --- a/drivers/nvmem/Kconfig
> +++ b/drivers/nvmem/Kconfig
> @@ -13,6 +13,13 @@ menuconfig NVMEM
> If unsure, say no.
>
> if NVMEM
> +config NVMEM_COMPAT
> + bool "Enable /sys compatibility with old eeprom drivers"
> + help
> + Older EEPROM drivers, such as AT24, AT25, provide access to
> + the eeprom via a file called "eeprom" in /sys under the
> + device node. Enabling this option makes the NVMEM core
> + provide this file to retain backwards compatibility

I don't like this being a Kconfig option TBH. In most cases, when I read
"retain backwards compatibility" in Kconfig help texts, I keep the
option activated because I don't know the details when exactly it is
safe to disable it. Plus, we have too many Kconfig symbols already.

I suggest to add this flag to nvmem_config and let the old eeprom
drivers always set this flag because they need to provide this file for
some more time, if not forever. New drivers using the nvmem_layer will
probably not want to set this.

BTW how does this NVMEM framework relate to the memory_accessor
framework. Can it be used to replace it? I think we should keep the
number of eeprom interfaces at a sane level, preferably 1 ;)

Also adding Pantelis to CC who also submitted at24 NVMEM support a while
ago.


Attachments:
(No filename) (1.83 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2015-12-11 13:43:42

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers.

On Fri, Dec 11, 2015 at 02:03:25PM +0100, Wolfram Sang wrote:
> On Tue, Dec 08, 2015 at 03:05:07PM +0100, Andrew Lunn wrote:
> > Older drivers made an 'eeprom' file available in the /sys device
> > directory. Have the NVMEM core provide this to retain backwards
> > compatibility.
> >
> > Signed-off-by: Andrew Lunn <[email protected]>
> > ---
> > drivers/nvmem/Kconfig | 7 ++++
> > drivers/nvmem/core.c | 75 +++++++++++++++++++++++++++++++++++++++---
> > include/linux/nvmem-provider.h | 10 ++++++
> > 3 files changed, 88 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> > index bc4ea585b42e..b4e79ba7d502 100644
> > --- a/drivers/nvmem/Kconfig
> > +++ b/drivers/nvmem/Kconfig
> > @@ -13,6 +13,13 @@ menuconfig NVMEM
> > If unsure, say no.
> >
> > if NVMEM
> > +config NVMEM_COMPAT
> > + bool "Enable /sys compatibility with old eeprom drivers"
> > + help
> > + Older EEPROM drivers, such as AT24, AT25, provide access to
> > + the eeprom via a file called "eeprom" in /sys under the
> > + device node. Enabling this option makes the NVMEM core
> > + provide this file to retain backwards compatibility
>
> I don't like this being a Kconfig option TBH. In most cases, when I read
> "retain backwards compatibility" in Kconfig help texts, I keep the
> option activated because I don't know the details when exactly it is
> safe to disable it. Plus, we have too many Kconfig symbols already.
>
> I suggest to add this flag to nvmem_config and let the old eeprom
> drivers always set this flag because they need to provide this file for
> some more time, if not forever. New drivers using the nvmem_layer will
> probably not want to set this.

I'm happy to do this, if the NVMEM core maintainers agree.

> BTW how does this NVMEM framework relate to the memory_accessor
> framework. Can it be used to replace it? I think we should keep the
> number of eeprom interfaces at a sane level, preferably 1 ;)

The memory_accessor framework only seems to work with old style
platform data devices, where you can register the callback function to
be used during probe. Because it cannot be used in a DT system, there
are very few users of it, only boards in arch/arm/mach-davinci. They
use it to get their MAC address out of the EEPROM. There are no users
of the AT25 equivalent, which is why i removed it. So this API is
dying on its own.

The NVMEM framework has a similar API for accessing the whole EEPROM,
and a much finer grained API for accessing cells within the EEPROM,
for example saying bytes 16-22 is the MAC address cell.

However, the NVMEM APIs are DT only, so are not a replacement for
memory_accessor. We need to keep memory_accessor until Davinci gets
converted to DT.

> Also adding Pantelis to CC who also submitted at24 NVMEM support a while
> ago.

Thanks for pointing this out, i was not aware of that patch.

Thanks
Andrew

2015-12-12 11:04:15

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers.


> of the AT25 equivalent, which is why i removed it. So this API is
> dying on its own.

Yes, it is dying; but it is lying around, rotting, and smelling. I'd
like to bury it away.

> However, the NVMEM APIs are DT only, so are not a replacement for
> memory_accessor. We need to keep memory_accessor until Davinci gets
> converted to DT.

I don't expect these boards to be converted to DT. We'll have to figure
something else somewhen.

Thanks,

Wolfram


Attachments:
(No filename) (459.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2015-12-15 10:02:35

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 1/6] nvmem: Add flag to export NVMEM to root only


Hi Andrew,

Thanks for this patch.

On 08/12/15 14:05, Andrew Lunn wrote:
> Legacy AT24, AT25 EEPROMs are exported in sys so that only root can
> read the contents. The EEPROMs may contain sensitive information. Add
> a flag so the provide can indicate that NVMEM should also restrict
> access to root only.
>
> Signed-off-by: Andrew Lunn <[email protected]>
> ---
> drivers/nvmem/core.c | 57 ++++++++++++++++++++++++++++++++++++++++--
> include/linux/nvmem-provider.h | 1 +
> 2 files changed, 56 insertions(+), 2 deletions(-)
>

This patch as it is look Ok to me.

thanks,
srini

> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> index 6fd4e5a5ef4a..4ccf03da6467 100644
> --- a/drivers/nvmem/core.c
> +++ b/drivers/nvmem/core.c
> @@ -155,6 +155,53 @@ static const struct attribute_group *nvmem_ro_dev_groups[] = {
> NULL,
> };
>
> +/* default read/write permissions, root only */
> +static struct bin_attribute bin_attr_rw_root_nvmem = {
> + .attr = {
> + .name = "nvmem",
> + .mode = S_IWUSR | S_IRUSR,
> + },
> + .read = bin_attr_nvmem_read,
> + .write = bin_attr_nvmem_write,
> +};
> +
> +static struct bin_attribute *nvmem_bin_rw_root_attributes[] = {
> + &bin_attr_rw_root_nvmem,
> + NULL,
> +};
> +
> +static const struct attribute_group nvmem_bin_rw_root_group = {
> + .bin_attrs = nvmem_bin_rw_root_attributes,
> +};
> +
> +static const struct attribute_group *nvmem_rw_root_dev_groups[] = {
> + &nvmem_bin_rw_root_group,
> + NULL,
> +};
> +
> +/* read only permission, root only */
> +static struct bin_attribute bin_attr_ro_root_nvmem = {
> + .attr = {
> + .name = "nvmem",
> + .mode = S_IRUSR,
> + },
> + .read = bin_attr_nvmem_read,
> +};
> +
> +static struct bin_attribute *nvmem_bin_ro_root_attributes[] = {
> + &bin_attr_ro_root_nvmem,
> + NULL,
> +};
> +
> +static const struct attribute_group nvmem_bin_ro_root_group = {
> + .bin_attrs = nvmem_bin_ro_root_attributes,
> +};
> +
> +static const struct attribute_group *nvmem_ro_root_dev_groups[] = {
> + &nvmem_bin_ro_root_group,
> + NULL,
> +};
> +
> static void nvmem_release(struct device *dev)
> {
> struct nvmem_device *nvmem = to_nvmem_device(dev);
> @@ -347,8 +394,14 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
> nvmem->read_only = of_property_read_bool(np, "read-only") |
> config->read_only;
>
> - nvmem->dev.groups = nvmem->read_only ? nvmem_ro_dev_groups :
> - nvmem_rw_dev_groups;
> + if (config->root_only)
> + nvmem->dev.groups = nvmem->read_only ?
> + nvmem_ro_root_dev_groups :
> + nvmem_rw_root_dev_groups;
> + else
> + nvmem->dev.groups = nvmem->read_only ?
> + nvmem_ro_dev_groups :
> + nvmem_rw_dev_groups;
>
> device_initialize(&nvmem->dev);
>
> diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
> index 0b68caff1b3c..d24fefa0c11d 100644
> --- a/include/linux/nvmem-provider.h
> +++ b/include/linux/nvmem-provider.h
> @@ -23,6 +23,7 @@ struct nvmem_config {
> const struct nvmem_cell_info *cells;
> int ncells;
> bool read_only;
> + bool root_only;
> };
>
> #if IS_ENABLED(CONFIG_NVMEM)
>

2015-12-15 10:08:58

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 4/6] eeprom: at25: Remove in kernel API for accessing the EEPROM



On 08/12/15 14:05, Andrew Lunn wrote:
> The setup() callback is not used by any in kernel code. Remove it.
> Any new code which requires access to the eeprom can use the NVMEM
> API.
>
> Signed-off-by: Andrew Lunn <[email protected]>
> ---
> drivers/misc/eeprom/at25.c | 26 --------------------------
> include/linux/spi/eeprom.h | 2 --
> 2 files changed, 28 deletions(-)
>

This is nice, The memory_accessor users can still use the
nvmem_device_get() by passing the nvmem provider device_name which would
give a handle to nvmem_device.


--srini
> diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
> index f850ef556bcc..4732f6997289 100644
> --- a/drivers/misc/eeprom/at25.c
> +++ b/drivers/misc/eeprom/at25.c
> @@ -29,7 +29,6 @@
>
> struct at25_data {
> struct spi_device *spi;
> - struct memory_accessor mem;
> struct mutex lock;
> struct spi_eeprom chip;
> struct bin_attribute bin;
> @@ -281,26 +280,6 @@ at25_bin_write(struct file *filp, struct kobject *kobj,
>
> /*-------------------------------------------------------------------------*/
>
> -/* Let in-kernel code access the eeprom data. */
> -
> -static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf,
> - off_t offset, size_t count)
> -{
> - struct at25_data *at25 = container_of(mem, struct at25_data, mem);
> -
> - return at25_ee_read(at25, buf, offset, count);
> -}
> -
> -static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
> - off_t offset, size_t count)
> -{
> - struct at25_data *at25 = container_of(mem, struct at25_data, mem);
> -
> - return at25_ee_write(at25, buf, offset, count);
> -}
> -
> -/*-------------------------------------------------------------------------*/
> -
> static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
> {
> u32 val;
> @@ -415,22 +394,17 @@ static int at25_probe(struct spi_device *spi)
> at25->bin.attr.name = "eeprom";
> at25->bin.attr.mode = S_IRUSR;
> at25->bin.read = at25_bin_read;
> - at25->mem.read = at25_mem_read;
>
> at25->bin.size = at25->chip.byte_len;
> if (!(chip.flags & EE_READONLY)) {
> at25->bin.write = at25_bin_write;
> at25->bin.attr.mode |= S_IWUSR;
> - at25->mem.write = at25_mem_write;
> }
>
> err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
> if (err)
> return err;
>
> - if (chip.setup)
> - chip.setup(&at25->mem, chip.context);
> -
> dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
> (at25->bin.size < 1024)
> ? at25->bin.size
> diff --git a/include/linux/spi/eeprom.h b/include/linux/spi/eeprom.h
> index 403e007aef68..e34e169f9dcb 100644
> --- a/include/linux/spi/eeprom.h
> +++ b/include/linux/spi/eeprom.h
> @@ -30,8 +30,6 @@ struct spi_eeprom {
> */
> #define EE_INSTR_BIT3_IS_ADDR 0x0010
>
> - /* for exporting this chip's data to other kernel code */
> - void (*setup)(struct memory_accessor *mem, void *context);
> void *context;
> };
>
>

2015-12-15 10:04:51

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers.



On 11/12/15 13:03, Wolfram Sang wrote:
> On Tue, Dec 08, 2015 at 03:05:07PM +0100, Andrew Lunn wrote:
>> Older drivers made an 'eeprom' file available in the /sys device
>> directory. Have the NVMEM core provide this to retain backwards
>> compatibility.
>>
>> Signed-off-by: Andrew Lunn <[email protected]>
>> ---
>> drivers/nvmem/Kconfig | 7 ++++
>> drivers/nvmem/core.c | 75 +++++++++++++++++++++++++++++++++++++++---
>> include/linux/nvmem-provider.h | 10 ++++++
>> 3 files changed, 88 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
>> index bc4ea585b42e..b4e79ba7d502 100644
>> --- a/drivers/nvmem/Kconfig
>> +++ b/drivers/nvmem/Kconfig
>> @@ -13,6 +13,13 @@ menuconfig NVMEM
>> If unsure, say no.
>>
>> if NVMEM
>> +config NVMEM_COMPAT
>> + bool "Enable /sys compatibility with old eeprom drivers"
>> + help
>> + Older EEPROM drivers, such as AT24, AT25, provide access to
>> + the eeprom via a file called "eeprom" in /sys under the
>> + device node. Enabling this option makes the NVMEM core
>> + provide this file to retain backwards compatibility
>
> I don't like this being a Kconfig option TBH. In most cases, when I read
> "retain backwards compatibility" in Kconfig help texts, I keep the
> option activated because I don't know the details when exactly it is
> safe to disable it. Plus, we have too many Kconfig symbols already.
>
+1 for not adding new Kconfig here.


> I suggest to add this flag to nvmem_config and let the old eeprom
> drivers always set this flag because they need to provide this file for
> some more time, if not forever. New drivers using the nvmem_layer will
> probably not want to set this.

yes, thats my view to, we should move the flag to nvmem_config and let
nvmem_register() do what it wants with it, this would avoid adding new
api too.
>
> BTW how does this NVMEM framework relate to the memory_accessor
> framework. Can it be used to replace it? I think we should keep the
> number of eeprom interfaces at a sane level, preferably 1 ;)

Non DT users can still get access to nvmem by passing nvmem provider
name to nvmem_device_get(), this should be able to replace the need of
memory_accessor.

--srini


>
> Also adding Pantelis to CC who also submitted at24 NVMEM support a while
> ago.
>

2015-12-15 10:05:13

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 2/6] nvmem: Add backwards compatibility support for older EEPROM drivers.


Below are few comments.

On 08/12/15 14:05, Andrew Lunn wrote:
> Older drivers made an 'eeprom' file available in the /sys device
> directory. Have the NVMEM core provide this to retain backwards
> compatibility.
>
> Signed-off-by: Andrew Lunn <[email protected]>
> ---
> drivers/nvmem/Kconfig | 7 ++++
> drivers/nvmem/core.c | 75 +++++++++++++++++++++++++++++++++++++++---
> include/linux/nvmem-provider.h | 10 ++++++
> 3 files changed, 88 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> index bc4ea585b42e..b4e79ba7d502 100644
> --- a/drivers/nvmem/Kconfig
> +++ b/drivers/nvmem/Kconfig
> @@ -13,6 +13,13 @@ menuconfig NVMEM
> If unsure, say no.
>
> if NVMEM
> +config NVMEM_COMPAT
> + bool "Enable /sys compatibility with old eeprom drivers"
> + help
> + Older EEPROM drivers, such as AT24, AT25, provide access to
> + the eeprom via a file called "eeprom" in /sys under the
> + device node. Enabling this option makes the NVMEM core
> + provide this file to retain backwards compatibility
>
Lets get rid of this Kconfig as Wolfram suggested.
We are already adding NVMEM_COMPAT in the nvmem_device structrure lets
move the flags into the struct nvmem_config and use the nvmem_register
api as it is.

nvmem_register() can decide what do do with that from there.
I would also prefer a warning if this flag is set, this is to deter any
new users.

Let me know your thoughts?

> config NVMEM_IMX_OCOTP
> tristate "i.MX6 On-Chip OTP Controller support"
> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> index 4ccf03da6467..75a498f5e139 100644
> --- a/drivers/nvmem/core.c
> +++ b/drivers/nvmem/core.c
> @@ -38,8 +38,13 @@ struct nvmem_device {
> int users;
> size_t size;
> bool read_only;
> + int flags;
> + struct bin_attribute eeprom;
> + struct device *base_dev;
> };
>
> +#define FLAG_COMPAT BIT(0)
> +
> struct nvmem_cell {
> const char *name;
> int offset;
> @@ -62,10 +67,16 @@ 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);
> + struct device *dev;
> + struct nvmem_device *nvmem;
> int rc;
>
> + if (attr->private)
> + dev = attr->private;
> + else
> + dev = container_of(kobj, struct device, kobj);
> + nvmem = to_nvmem_device(dev);
> +
> /* Stop the user from reading */
> if (pos >= nvmem->size)
> return 0;
> @@ -87,10 +98,16 @@ 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);
> + struct device *dev;
> + struct nvmem_device *nvmem;
> int rc;
>
> + if (attr->private)
> + dev = attr->private;
> + else
> + dev = container_of(kobj, struct device, kobj);
> + nvmem = to_nvmem_device(dev);
> +
> /* Stop the user from writing */
> if (pos >= nvmem->size)
> return 0;
> @@ -421,6 +438,53 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
> }
> EXPORT_SYMBOL_GPL(nvmem_register);
>
> +#if IS_ENABLED(CONFIG_NVMEM_COMPAT)
> +/**
> + * nvmem_register_compat() - Register a nvmem device for given nvmem_config.
> + * Also creates an binary entry in /sys/bus/nvmem/devices/dev-name/nvmem and
> + * an eeprom file in the drivers sys directory.
> + *
> + * @config: nvmem device configuration with which nvmem device is created.
> + * @dev: device structure of underlying device
> + *
> + * Return: Will be an ERR_PTR() on error or a valid pointer to nvmem_device
> + * on success.
> + */
> +
> +struct nvmem_device *nvmem_register_compat(const struct nvmem_config *config,
> + struct device *base_dev)
> +{
Possibly move most of it or some of it a local static function which
will be called from nvmem_register depending on the NVMEM_FLAG_COMPAT.

> + struct nvmem_device *nvmem;
> + int rval;
> +
> + nvmem = nvmem_register(config);
> + if (IS_ERR(nvmem))
> + return nvmem;
> +
> + if (nvmem->read_only)
> + nvmem->eeprom = bin_attr_ro_root_nvmem;
> + else
> + nvmem->eeprom = bin_attr_rw_root_nvmem;
> + nvmem->eeprom.attr.name = "eeprom";
> + nvmem->eeprom.size = nvmem->size;
> + nvmem->eeprom.private = &nvmem->dev;
> + nvmem->base_dev = base_dev;
> +
> + rval = device_create_bin_file(nvmem->base_dev, &nvmem->eeprom);
> + if (rval) {
> + dev_err(&nvmem->dev,
> + "Failed to create eeprom binary file %d\n", rval);
> + nvmem_unregister(nvmem);
> + return ERR_PTR(rval);
> + }
> +
> + nvmem->flags |= FLAG_COMPAT;
> +
> + return nvmem;
> +}
> +EXPORT_SYMBOL_GPL(nvmem_register_compat);
> +#endif /* CONFIG_NVMEM_COMPAT */
> +
> /**
> * nvmem_unregister() - Unregister previously registered nvmem device
> *
> @@ -437,6 +501,9 @@ int nvmem_unregister(struct nvmem_device *nvmem)
> }
> mutex_unlock(&nvmem_mutex);
>
> + if (nvmem->flags & FLAG_COMPAT)
> + device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
> +
> nvmem_device_remove_all_cells(nvmem);
> device_del(&nvmem->dev);
>
> diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
> index d24fefa0c11d..012030bd4495 100644
> --- a/include/linux/nvmem-provider.h
> +++ b/include/linux/nvmem-provider.h
> @@ -45,4 +45,14 @@ static inline int nvmem_unregister(struct nvmem_device *nvmem)
>
> #endif /* CONFIG_NVMEM */
>
> +#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_NVMEM_COMPAT)
> +struct nvmem_device *nvmem_register_compat(const struct nvmem_config *config,
> + struct device *base_dev);
> +#else
> +static inline struct nvmem_device *
> +nvmem_register_compat(const struct nvmem_config *c, struct device *base_dev)
> +{
> + return ERR_PTR(-ENOSYS);
> +}
> +#endif /* CONFIG_NVMEM && CONFIG_NVMEM_COMPAT */
> #endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
>

2015-12-15 10:06:12

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework



On 08/12/15 14:05, Andrew Lunn wrote:
> Add a regmap for accessing the EEPROM, and then use that with the
> NVMEM framework. Use it backward compatibility register function, so
> that the 'eeprom' file in sys is provided by the framework.
>
> Signed-off-by: Andrew Lunn <[email protected]>
> ---
> drivers/misc/eeprom/Kconfig | 3 +
> drivers/misc/eeprom/eeprom_93xx46.c | 121 ++++++++++++++++++++++++++++--------
> 2 files changed, 98 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index ff3e1dd751ec..5dfa2c2c2277 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -80,6 +80,9 @@ config EEPROM_93CX6
> config EEPROM_93XX46
> tristate "Microwire EEPROM 93XX46 support"
> depends on SPI && SYSFS
> + select REGMAP
> + select NVMEM
> + select NVMEM_COMPAT
> help
> Driver for the microwire EEPROM chipsets 93xx46x. The driver
> supports both read and write commands and also the command to
> diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
> index ff63f05edc76..aa75f59abfba 100644
> --- a/drivers/misc/eeprom/eeprom_93xx46.c
> +++ b/drivers/misc/eeprom/eeprom_93xx46.c
> @@ -15,7 +15,8 @@
> #include <linux/mutex.h>
> #include <linux/slab.h>
> #include <linux/spi/spi.h>
> -#include <linux/sysfs.h>
> +#include <linux/nvmem-provider.h>
> +#include <linux/regmap.h>
> #include <linux/eeprom_93xx46.h>
>
> #define OP_START 0x4
> @@ -28,25 +29,29 @@
> struct eeprom_93xx46_dev {
> struct spi_device *spi;
> struct eeprom_93xx46_platform_data *pdata;
> - struct bin_attribute bin;
> struct mutex lock;
> + struct regmap_config regmap_config;
> + struct nvmem_config nvmem_config;
> + struct nvmem_device *nvmem;
> int addrlen;
> + int size;
> };
>
> static ssize_t
> -eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj,
> - struct bin_attribute *bin_attr,
> - char *buf, loff_t off, size_t count)
> +eeprom_93xx46_read(struct eeprom_93xx46_dev *edev, char *buf,
> + unsigned off, size_t count)
> {
> - struct eeprom_93xx46_dev *edev;
> - struct device *dev;
> struct spi_message m;
> struct spi_transfer t[2];
> int bits, ret;
> u16 cmd_addr;
>
> - dev = container_of(kobj, struct device, kobj);
> - edev = dev_get_drvdata(dev);
> + if (unlikely(off >= edev->size))
> + return 0;
> + if ((off + count) > edev->size)
> + count = edev->size - off;
> + if (unlikely(!count))
> + return count;
>
> cmd_addr = OP_READ << edev->addrlen;
>
> @@ -94,6 +99,7 @@ eeprom_93xx46_bin_read(struct file *filp, struct kobject *kobj,
> return ret ? : count;
> }
>
> +
> static int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
> {
> struct spi_message m;
> @@ -182,16 +188,17 @@ eeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
> }
>
> static ssize_t
> -eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
> - struct bin_attribute *bin_attr,
> - char *buf, loff_t off, size_t count)
> +eeprom_93xx46_write(struct eeprom_93xx46_dev *edev, const char *buf,
> + loff_t off, size_t count)
> {
> - struct eeprom_93xx46_dev *edev;
> - struct device *dev;
> int i, ret, step = 1;
>
> - dev = container_of(kobj, struct device, kobj);
> - edev = dev_get_drvdata(dev);
> + if (unlikely(off >= edev->size))
> + return -EFBIG;
> + if ((off + count) > edev->size)
> + count = edev->size - off;
> + if (unlikely(!count))
> + return count;
>
> /* only write even number of bytes on 16-bit devices */
> if (edev->addrlen == 6) {
> @@ -228,6 +235,49 @@ eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj,
> return ret ? : count;
> }
>
> +/*
> + * Provide a regmap interface, which is registered with the NVMEM
> + * framework
> +*/
> +static int eeprom_93xx46_regmap_read(void *context, const void *reg,
> + size_t reg_size, void *val,
> + size_t val_size)
> +{
> + struct eeprom_93xx46_dev *eeprom_93xx46 = context;
> + off_t offset = *(u32 *)reg;
> + int err;
> +
> + err = eeprom_93xx46_read(eeprom_93xx46, val, offset, val_size);
> + if (err)
> + return err;
> + return 0;
> +}
> +
> +static int eeprom_93xx46_regmap_write(void *context, const void *data,
> + size_t count)
> +{
> + struct eeprom_93xx46_dev *eeprom_93xx46 = context;
> + const char *buf;
> + u32 offset;
> + size_t len;
> + int err;
> +
> + memcpy(&offset, data, sizeof(offset));
> + buf = (const char *)data + sizeof(offset);
> + len = count - sizeof(offset);
> +
> + err = eeprom_93xx46_write(eeprom_93xx46, buf, offset, len);
> + if (err)
> + return err;
> + return 0;
> +}
> +
> +static const struct regmap_bus eeprom_93xx46_regmap_bus = {
> + .read = eeprom_93xx46_regmap_read,
> + .write = eeprom_93xx46_regmap_write,
> + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
> +};
> +
> static int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
> {
> struct eeprom_93xx46_platform_data *pd = edev->pdata;
> @@ -298,6 +348,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
> {
> struct eeprom_93xx46_platform_data *pd;
> struct eeprom_93xx46_dev *edev;
> + struct regmap *regmap;
> int err;
>
> pd = spi->dev.platform_data;
> @@ -325,19 +376,36 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
> edev->spi = spi_dev_get(spi);
> edev->pdata = pd;
>
> - sysfs_bin_attr_init(&edev->bin);
> - edev->bin.attr.name = "eeprom";
> - edev->bin.attr.mode = S_IRUSR;
> - edev->bin.read = eeprom_93xx46_bin_read;
> - edev->bin.size = 128;
> + edev->size = 128;
> +
> if (!(pd->flags & EE_READONLY)) {
> - edev->bin.write = eeprom_93xx46_bin_write;
> - edev->bin.attr.mode |= S_IWUSR;
> }
>
> - err = sysfs_create_bin_file(&spi->dev.kobj, &edev->bin);
> - if (err)
> + edev->regmap_config.reg_bits = 32;
> + edev->regmap_config.val_bits = 8;
> + edev->regmap_config.reg_stride = 1;
> + edev->regmap_config.max_register = edev->size - 1;
> +
> + regmap = devm_regmap_init(&spi->dev, &eeprom_93xx46_regmap_bus, edev,
> + &edev->regmap_config);
> + if (IS_ERR(regmap)) {
> + dev_err(&spi->dev, "regmap init failed\n");
> + err = PTR_ERR(regmap);
> goto fail;
> + }
> +
> + edev->nvmem_config.name = dev_name(&spi->dev);
> + edev->nvmem_config.dev = &spi->dev;
> + edev->nvmem_config.read_only = pd->flags & EE_READONLY;
> + edev->nvmem_config.root_only = true;
> + edev->nvmem_config.owner = THIS_MODULE;
> +
> + edev->nvmem = nvmem_register_compat(&edev->nvmem_config,
> + &spi->dev);

Is there a reason for this driver to be using the old style?
I can understand the issues with at24/at25 but does this driver also
suffer from such issues?

IMO, If its possible we should discourage the compat api as much we can.

> + if (IS_ERR(edev->nvmem)) {
> + err = PTR_ERR(edev->nvmem);
> + goto fail;
> + }
>
> dev_info(&spi->dev, "%d-bit eeprom %s\n",
> (pd->flags & EE_ADDR8) ? 8 : 16,
> @@ -359,10 +427,11 @@ static int eeprom_93xx46_remove(struct spi_device *spi)
> {
> struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
>
> + nvmem_unregister(edev->nvmem);
> +
> if (!(edev->pdata->flags & EE_READONLY))
> device_remove_file(&spi->dev, &dev_attr_erase);
>
> - sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
> kfree(edev);
> return 0;
> }
>

2015-12-15 10:06:41

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 0/6] Convert existing EEPROM drivers to NVMEM


Thanks Andrew for looking into this.

On 08/12/15 14:05, Andrew Lunn wrote:
> This patches converts the old EEPROM drivers in driver/misc/eeprom to
> use the NVMEM framework. These drivers export there content in /sys as
> read only to root, since the EEPROM may contain sensitive information.
> So the first patch adds a flag so the NVMEM framework will create its
> file in /sys as root read only.
>
> To keep backwards compatibility with these older drivers, the contents
> of the EEPROM must be exports in sysfs in a file called eeprom in the
> devices node in sys, where as the NVMEM places them under class/nvmem.
> So add this optional backwards compatible to the framework.
>
> Then convert the at24, at25 and 93xx46 by adding regmap support,
> removing each drivers own /sys code and registering with the NVMEM
> framework.
>
> AT24 and 93xx46 has been boot tested, at25 compile tested only.
>
> Andrew Lunn (6):
> nvmem: Add flag to export NVMEM to root only
> nvmem: Add backwards compatibility support for older EEPROM drivers.
> eeprom: at24: extend driver to plug into the NVMEM framework
> eeprom: at25: Remove in kernel API for accessing the EEPROM
> eeprom: at25: extend driver to plug into the NVMEM framework
> eeprom: 93xx46: extend driver to plug into the NVMEM framework
>
> drivers/misc/eeprom/Kconfig | 9 +++
> drivers/misc/eeprom/at24.c | 119 +++++++++++++++++++----------
> drivers/misc/eeprom/at25.c | 147 ++++++++++++++++--------------------
> drivers/misc/eeprom/eeprom_93xx46.c | 121 ++++++++++++++++++++++-------
> drivers/nvmem/Kconfig | 7 ++
> drivers/nvmem/core.c | 132 ++++++++++++++++++++++++++++++--
> include/linux/nvmem-provider.h | 11 +++
> include/linux/spi/eeprom.h | 2 -
> 8 files changed, 393 insertions(+), 155 deletions(-)


I did test this patchset on my board with at24, series looks good.
Other than some comments on few patches.


--srini
>

2015-12-15 10:17:27

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework

> Is there a reason for this driver to be using the old style?
> I can understand the issues with at24/at25 but does this driver also
> suffer from such issues?

In order to keep backwards compatibility, we need the older file in
/sys. The only other option is to remove it and see if anybody
complains about us breaking the ABI.

Andrew

2015-12-15 10:27:14

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework

+ adding Anatolij

On 15/12/15 10:17, Andrew Lunn wrote:
>> Is there a reason for this driver to be using the old style?
>> I can understand the issues with at24/at25 but does this driver also
>> suffer from such issues?
>
> In order to keep backwards compatibility, we need the older file in
> /sys. The only other option is to remove it and see if anybody
> complains about us breaking the ABI.
We should atleast attempt to pitch in this direction, and ask if
somebody really cares if the location of the eeprom/nvmem file matters
to them?

We should probably check with Anatolij Gustschin.

Anatolij, Do you see any issues if we totally move this driver to nvmem
framework? Which involves relocating and renameing the old eeprom file
to /sys/bus/nvmem/devices/*/nvmem

--srini
>
> Andrew
>

2015-12-15 10:37:34

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework

On Tue, Dec 15, 2015 at 10:26:47AM +0000, Srinivas Kandagatla wrote:
> + adding Anatolij
>
> On 15/12/15 10:17, Andrew Lunn wrote:
> >>Is there a reason for this driver to be using the old style?
> >>I can understand the issues with at24/at25 but does this driver also
> >>suffer from such issues?
> >
> >In order to keep backwards compatibility, we need the older file in
> >/sys. The only other option is to remove it and see if anybody
> >complains about us breaking the ABI.
> We should atleast attempt to pitch in this direction, and ask if
> somebody really cares if the location of the eeprom/nvmem file
> matters to them?

I expect it does matter.

This driver does not implement the in kernel API for accessing the
EEPROM. That means all users are in user space. And if this file
moves, it seems very likely these user space users break.

Andrew

2015-12-15 10:47:16

by Wolfram Sang

[permalink] [raw]
Subject: Re: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework


> I expect it does matter.
>
> This driver does not implement the in kernel API for accessing the
> EEPROM. That means all users are in user space. And if this file
> moves, it seems very likely these user space users break.

I agree.


Attachments:
(No filename) (238.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2015-12-15 10:51:28

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework



On 15/12/15 10:37, Andrew Lunn wrote:
> On Tue, Dec 15, 2015 at 10:26:47AM +0000, Srinivas Kandagatla wrote:
>> + adding Anatolij
>>
>> On 15/12/15 10:17, Andrew Lunn wrote:
>>>> Is there a reason for this driver to be using the old style?
>>>> I can understand the issues with at24/at25 but does this driver also
>>>> suffer from such issues?
>>>
>>> In order to keep backwards compatibility, we need the older file in
>>> /sys. The only other option is to remove it and see if anybody
>>> complains about us breaking the ABI.
>> We should atleast attempt to pitch in this direction, and ask if
>> somebody really cares if the location of the eeprom/nvmem file
>> matters to them?
>
> I expect it does matter.
>
> This driver does not implement the in kernel API for accessing the
> EEPROM. That means all users are in user space. And if this file
> moves, it seems very likely these user space users break.

We have no choice I guess, other than adding the NEMEM_COMPAT flag to
this driver too :-)



>
> Andrew
>

2015-12-15 11:06:08

by Anatolij Gustschin

[permalink] [raw]
Subject: Re: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework

On Tue, 15 Dec 2015 10:26:47 +0000
Srinivas Kandagatla <[email protected]> wrote:
...
> Anatolij, Do you see any issues if we totally move this driver to nvmem
> framework? Which involves relocating and renameing the old eeprom file
> to /sys/bus/nvmem/devices/*/nvmem

I don't know how many driver users are there and if breaking the
compatibility matters for them. Relocating/renaming the old eeprom
file would be acceptable for me, provided it can be accessed from
user space as before.

--
Anatolij

2015-12-15 12:20:54

by Srinivas Kandagatla

[permalink] [raw]
Subject: Re: [PATCH 6/6] eeprom: 93xx46: extend driver to plug into the NVMEM framework



On 15/12/15 11:05, Anatolij Gustschin wrote:
> On Tue, 15 Dec 2015 10:26:47 +0000
> Srinivas Kandagatla <[email protected]> wrote:
> ...
>> Anatolij, Do you see any issues if we totally move this driver to nvmem
>> framework? Which involves relocating and renameing the old eeprom file
>> to /sys/bus/nvmem/devices/*/nvmem
>
> I don't know how many driver users are there and if breaking the
> compatibility matters for them. Relocating/renaming the old eeprom
> file would be acceptable for me, provided it can be accessed from
> user space as before.

Thanks for the quick reply, Yes we do indeed have exactly same access to
from the user-space by moving to nvmem interface.



--srini

>
> --
> Anatolij
>