All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] v4 Driver for Allwinner sunxi Security ID
@ 2013-06-17 20:59 ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 20:59 UTC (permalink / raw)
  To: arnd, gregkh
  Cc: maxime.ripard, linux-kernel, linux-arm-kernel, andy.shevchenko,
	linux, linus.walleij, linux-sunxi, Oliver Schinagl

Note, this is a resent because i messed up the first send.

Changes from v3:
  * Cleanup comments
  * Remove last byte masking and useless casting, the C standard guarntees
    we are ok
  * Removed some complexity from sid_read, thanks to Russel
  * Replace dev_info with dev_dbg reducing the verbosity
  * Removed driver version
  * Reorderd variable declrations based on usage, return value always last
  * Removed all goto in exchange for return, due to popular request
  * Reduced line count by removing extra lines

Changes from v2:
  * Removed the global pointer, we can change that when the need for external
    access arises
  * Fixed header inclusions
  * Corrected if guards. There where some crude mistakes there
  * Changed offset to an unsigned int so we don't have to worry about negatives
  * Cleaned up variable declarations
  * Changed ret value, ENXIO (No device/io) as that better matches a missing dt
  * Made the loading informercial print version so it is somewhat usefull

Changes from v1:
  * Renamed the sys-fs exported key to eeprom, since it really a read-only eeprom
  * Removed mention of sun[67]i since we haven't tested those
  * Fixed up mistakes in comments
  * Removed PAGE_SIZE references, since this is a binary only driver
  * Removed lookup table and calculate offsets better
  * Use proper endianess
  * Add the SID to seed the kernel entropy pool
  * Rewrite probe to use platform_get_resource/devm_ioremap_resource instead

The Allwinner A-series of SoC's have efuses exposed via registers to read the
factory programmed e-fuses. These should in theory be programmable but this is
still to be confirmed. It does appear that these fuses are unique enough to be
used as serial numbers, RSA keys, generate MAC addresses from etc. If it turns
out to be user programmable, the use obviously increases. Allwinner did use the
fuses initially to determine the chip-type.

This driver supports all currently known chips based on datasheets and 'dumped'
drivers that we have so far, the dts is only implemented for known chips.

It has been tested on a Cubieboard 1

This is my very first driver so please try to be gentle 

Oliver Schinagl (2):
  Initial support for Allwinner's Security ID fuses
  Add sunxi-sid to dts for sun4i and sun5i

 arch/arm/boot/dts/sun4i-a10.dtsi |   5 ++
 arch/arm/boot/dts/sun5i-a13.dtsi |   5 ++
 drivers/misc/eeprom/Kconfig      |  17 +++++
 drivers/misc/eeprom/Makefile     |   1 +
 drivers/misc/eeprom/sunxi_sid.c  | 147 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 175 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

-- 
1.8.1.5


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 0/2] v4 Driver for Allwinner sunxi Security ID
@ 2013-06-17 20:59 ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 20:59 UTC (permalink / raw)
  To: linux-arm-kernel

Note, this is a resent because i messed up the first send.

Changes from v3:
  * Cleanup comments
  * Remove last byte masking and useless casting, the C standard guarntees
    we are ok
  * Removed some complexity from sid_read, thanks to Russel
  * Replace dev_info with dev_dbg reducing the verbosity
  * Removed driver version
  * Reorderd variable declrations based on usage, return value always last
  * Removed all goto in exchange for return, due to popular request
  * Reduced line count by removing extra lines

Changes from v2:
  * Removed the global pointer, we can change that when the need for external
    access arises
  * Fixed header inclusions
  * Corrected if guards. There where some crude mistakes there
  * Changed offset to an unsigned int so we don't have to worry about negatives
  * Cleaned up variable declarations
  * Changed ret value, ENXIO (No device/io) as that better matches a missing dt
  * Made the loading informercial print version so it is somewhat usefull

Changes from v1:
  * Renamed the sys-fs exported key to eeprom, since it really a read-only eeprom
  * Removed mention of sun[67]i since we haven't tested those
  * Fixed up mistakes in comments
  * Removed PAGE_SIZE references, since this is a binary only driver
  * Removed lookup table and calculate offsets better
  * Use proper endianess
  * Add the SID to seed the kernel entropy pool
  * Rewrite probe to use platform_get_resource/devm_ioremap_resource instead

The Allwinner A-series of SoC's have efuses exposed via registers to read the
factory programmed e-fuses. These should in theory be programmable but this is
still to be confirmed. It does appear that these fuses are unique enough to be
used as serial numbers, RSA keys, generate MAC addresses from etc. If it turns
out to be user programmable, the use obviously increases. Allwinner did use the
fuses initially to determine the chip-type.

This driver supports all currently known chips based on datasheets and 'dumped'
drivers that we have so far, the dts is only implemented for known chips.

It has been tested on a Cubieboard 1

This is my very first driver so please try to be gentle 

Oliver Schinagl (2):
  Initial support for Allwinner's Security ID fuses
  Add sunxi-sid to dts for sun4i and sun5i

 arch/arm/boot/dts/sun4i-a10.dtsi |   5 ++
 arch/arm/boot/dts/sun5i-a13.dtsi |   5 ++
 drivers/misc/eeprom/Kconfig      |  17 +++++
 drivers/misc/eeprom/Makefile     |   1 +
 drivers/misc/eeprom/sunxi_sid.c  | 147 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 175 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

-- 
1.8.1.5

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 20:59 ` Oliver Schinagl
@ 2013-06-17 20:59   ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 20:59 UTC (permalink / raw)
  To: arnd, gregkh
  Cc: maxime.ripard, linux-kernel, linux-arm-kernel, andy.shevchenko,
	linux, linus.walleij, linux-sunxi, Oliver Schinagl

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses, seeds the kernel entropy and exports them as a sysfs node.

These fuses are most likly to be programmed at the factory, encoding
things like Chip ID, some sort of serial number etc and appear to be
reasonable unique.
While in theory, these should be writeable by the user, it will probably
be inconvinient to do so. Allwinner recommends that a certain input pin,
labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
needs to be applied to this pin.

Even so, they can still be used to generate a board-unique mac from, board
unique RSA key and seed the kernel RNG.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A10s, A13)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 drivers/misc/eeprom/Kconfig     |  17 +++++
 drivers/misc/eeprom/Makefile    |   1 +
 drivers/misc/eeprom/sunxi_sid.c | 147 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 165 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..c7bc6ed 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,21 @@ 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. Currently supported are:
+		sun4i (A10)
+		sun5i (A13)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..6a16c19
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2013 Oliver Schinagl
+ * http://www.linux-sunxi.org
+ *
+ * Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * 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, a 128 bit eeprom, 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/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define DRV_NAME "sunxi-sid"
+
+/* There are 4 32-bit keys */
+#define SID_KEYS 4
+/* Each key is 4 bytes long */
+#define SID_SIZE (SID_KEYS * 4)
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this resuls in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarly probed, this is not really an issue.
+ */
+static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
+			      const unsigned int offset)
+{
+	u32 sid_key;
+
+	if (offset >= SID_SIZE)
+		return 0;
+
+	sid_key = ioread32be(sid_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)
+{
+	int i;
+	struct platform_device *pdev;
+	void __iomem *sid_reg_base;
+
+	pdev = to_platform_device(kobj_to_dev(kobj));
+	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
+
+	if (pos < 0 || pos >= SID_SIZE)
+		return 0;
+	if (size > (SID_SIZE - pos))
+		size = SID_SIZE - pos;
+
+	for (i = 0; i < size; i++)
+		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
+
+	return i;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-sid", },
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static const struct bin_attribute sid_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO,
+	},
+	.size = SID_SIZE,
+	.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, "%s driver unloaded\n", DRV_NAME);
+
+	return 0;
+}
+
+static int __init sunxi_sid_probe(struct platform_device *pdev)
+{
+	u8 entropy[SID_SIZE];
+	unsigned int i;
+	struct resource *res;
+	void __iomem *sid_reg_base;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sid_reg_base))
+		return PTR_ERR(sid_reg_base);
+	platform_set_drvdata(pdev, sid_reg_base);
+
+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < SID_SIZE; i++)
+		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
+	add_device_randomness(entropy, SID_SIZE);
+	dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);
+
+	return 0;
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.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.8.1.5


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 20:59   ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 20:59 UTC (permalink / raw)
  To: linux-arm-kernel

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses, seeds the kernel entropy and exports them as a sysfs node.

These fuses are most likly to be programmed at the factory, encoding
things like Chip ID, some sort of serial number etc and appear to be
reasonable unique.
While in theory, these should be writeable by the user, it will probably
be inconvinient to do so. Allwinner recommends that a certain input pin,
labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
needs to be applied to this pin.

Even so, they can still be used to generate a board-unique mac from, board
unique RSA key and seed the kernel RNG.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A10s, A13)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 drivers/misc/eeprom/Kconfig     |  17 +++++
 drivers/misc/eeprom/Makefile    |   1 +
 drivers/misc/eeprom/sunxi_sid.c | 147 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 165 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..c7bc6ed 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,21 @@ 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. Currently supported are:
+		sun4i (A10)
+		sun5i (A13)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..6a16c19
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2013 Oliver Schinagl
+ * http://www.linux-sunxi.org
+ *
+ * Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * 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, a 128 bit eeprom, 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/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define DRV_NAME "sunxi-sid"
+
+/* There are 4 32-bit keys */
+#define SID_KEYS 4
+/* Each key is 4 bytes long */
+#define SID_SIZE (SID_KEYS * 4)
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this resuls in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarly probed, this is not really an issue.
+ */
+static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
+			      const unsigned int offset)
+{
+	u32 sid_key;
+
+	if (offset >= SID_SIZE)
+		return 0;
+
+	sid_key = ioread32be(sid_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)
+{
+	int i;
+	struct platform_device *pdev;
+	void __iomem *sid_reg_base;
+
+	pdev = to_platform_device(kobj_to_dev(kobj));
+	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
+
+	if (pos < 0 || pos >= SID_SIZE)
+		return 0;
+	if (size > (SID_SIZE - pos))
+		size = SID_SIZE - pos;
+
+	for (i = 0; i < size; i++)
+		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
+
+	return i;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-sid", },
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static const struct bin_attribute sid_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO,
+	},
+	.size = SID_SIZE,
+	.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, "%s driver unloaded\n", DRV_NAME);
+
+	return 0;
+}
+
+static int __init sunxi_sid_probe(struct platform_device *pdev)
+{
+	u8 entropy[SID_SIZE];
+	unsigned int i;
+	struct resource *res;
+	void __iomem *sid_reg_base;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sid_reg_base))
+		return PTR_ERR(sid_reg_base);
+	platform_set_drvdata(pdev, sid_reg_base);
+
+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < SID_SIZE; i++)
+		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
+	add_device_randomness(entropy, SID_SIZE);
+	dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);
+
+	return 0;
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.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.8.1.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 20:59   ` Oliver Schinagl
@ 2013-06-17 21:06     ` Tomasz Figa
  -1 siblings, 0 replies; 142+ messages in thread
From: Tomasz Figa @ 2013-06-17 21:06 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Oliver Schinagl, arnd, gregkh, linux, Oliver Schinagl,
	linus.walleij, linux-sunxi, linux-kernel, andy.shevchenko,
	maxime.ripard

Hi Oliver,

On Monday 17 of June 2013 22:59:37 Oliver Schinagl wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> node.
> 
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input
> pin, labeled 'efuse_vddq', be connected to GND. To write these fuses,
> 2.5 V needs to be applied to this pin.
> 
> Even so, they can still be used to generate a board-unique mac from,
> board unique RSA key and seed the kernel RNG.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)
> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  drivers/misc/eeprom/Kconfig     |  17 +++++
>  drivers/misc/eeprom/Makefile    |   1 +
>  drivers/misc/eeprom/sunxi_sid.c | 147
> ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165
> insertions(+)
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c

Looks good to me. Have my

Reviewed-by: Tomasz Figa <tomasz.figa@gmail.com>

Best regards,
Tomasz

> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..c7bc6ed 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,21 @@ 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. Currently supported are:
> +		sun4i (A10)
> +		sun5i (A13)
> +
> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID
> +
> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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 new file mode 100644
> index 0000000..6a16c19
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,147 @@
> +/*
> + * Copyright (c) 2013 Oliver Schinagl
> + * http://www.linux-sunxi.org
> + *
> + * Oliver Schinagl <oliver@schinagl.nl>
> + *
> + * 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, a 128 bit eeprom, 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/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/random.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +#define DRV_NAME "sunxi-sid"
> +
> +/* There are 4 32-bit keys */
> +#define SID_KEYS 4
> +/* Each key is 4 bytes long */
> +#define SID_SIZE (SID_KEYS * 4)
> +
> +/* We read the entire key, due to a 32 bit read alignment requirement.
> Since we + * want to return the requested byte, this resuls in somewhat
> slower code and + * uses 4 times more reads as needed but keeps code
> simpler. Since the SID is + * only very rarly probed, this is not
> really an issue.
> + */
> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> +			      const unsigned int offset)
> +{
> +	u32 sid_key;
> +
> +	if (offset >= SID_SIZE)
> +		return 0;
> +
> +	sid_key = ioread32be(sid_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)
> +{
> +	int i;
> +	struct platform_device *pdev;
> +	void __iomem *sid_reg_base;
> +
> +	pdev = to_platform_device(kobj_to_dev(kobj));
> +	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
> +
> +	if (pos < 0 || pos >= SID_SIZE)
> +		return 0;
> +	if (size > (SID_SIZE - pos))
> +		size = SID_SIZE - pos;
> +
> +	for (i = 0; i < size; i++)
> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> +
> +	return i;
> +}
> +
> +static const struct of_device_id sunxi_sid_of_match[] = {
> +	{ .compatible = "allwinner,sun4i-sid", },
> +	{/* sentinel */}
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> +
> +static const struct bin_attribute sid_bin_attr = {
> +	.attr = {
> +		.name = "eeprom",
> +		.mode = S_IRUGO,
> +	},
> +	.size = SID_SIZE,
> +	.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, "%s driver unloaded\n", DRV_NAME);
> +
> +	return 0;
> +}
> +
> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	u8 entropy[SID_SIZE];
> +	unsigned int i;
> +	struct resource *res;
> +	void __iomem *sid_reg_base;
> +	int ret;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(sid_reg_base))
> +		return PTR_ERR(sid_reg_base);
> +	platform_set_drvdata(pdev, sid_reg_base);
> +
> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < SID_SIZE; i++)
> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
> +	add_device_randomness(entropy, SID_SIZE);
> +	dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver sunxi_sid_driver = {
> +	.probe = sunxi_sid_probe,
> +	.remove = sunxi_sid_remove,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.owner = THIS_MODULE,
> +		.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");

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 21:06     ` Tomasz Figa
  0 siblings, 0 replies; 142+ messages in thread
From: Tomasz Figa @ 2013-06-17 21:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Oliver,

On Monday 17 of June 2013 22:59:37 Oliver Schinagl wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> node.
> 
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input
> pin, labeled 'efuse_vddq', be connected to GND. To write these fuses,
> 2.5 V needs to be applied to this pin.
> 
> Even so, they can still be used to generate a board-unique mac from,
> board unique RSA key and seed the kernel RNG.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)
> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  drivers/misc/eeprom/Kconfig     |  17 +++++
>  drivers/misc/eeprom/Makefile    |   1 +
>  drivers/misc/eeprom/sunxi_sid.c | 147
> ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165
> insertions(+)
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c

Looks good to me. Have my

Reviewed-by: Tomasz Figa <tomasz.figa@gmail.com>

Best regards,
Tomasz

> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..c7bc6ed 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,21 @@ 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. Currently supported are:
> +		sun4i (A10)
> +		sun5i (A13)
> +
> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID
> +
> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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 new file mode 100644
> index 0000000..6a16c19
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,147 @@
> +/*
> + * Copyright (c) 2013 Oliver Schinagl
> + * http://www.linux-sunxi.org
> + *
> + * Oliver Schinagl <oliver@schinagl.nl>
> + *
> + * 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, a 128 bit eeprom, 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/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/random.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +#define DRV_NAME "sunxi-sid"
> +
> +/* There are 4 32-bit keys */
> +#define SID_KEYS 4
> +/* Each key is 4 bytes long */
> +#define SID_SIZE (SID_KEYS * 4)
> +
> +/* We read the entire key, due to a 32 bit read alignment requirement.
> Since we + * want to return the requested byte, this resuls in somewhat
> slower code and + * uses 4 times more reads as needed but keeps code
> simpler. Since the SID is + * only very rarly probed, this is not
> really an issue.
> + */
> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> +			      const unsigned int offset)
> +{
> +	u32 sid_key;
> +
> +	if (offset >= SID_SIZE)
> +		return 0;
> +
> +	sid_key = ioread32be(sid_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)
> +{
> +	int i;
> +	struct platform_device *pdev;
> +	void __iomem *sid_reg_base;
> +
> +	pdev = to_platform_device(kobj_to_dev(kobj));
> +	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
> +
> +	if (pos < 0 || pos >= SID_SIZE)
> +		return 0;
> +	if (size > (SID_SIZE - pos))
> +		size = SID_SIZE - pos;
> +
> +	for (i = 0; i < size; i++)
> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> +
> +	return i;
> +}
> +
> +static const struct of_device_id sunxi_sid_of_match[] = {
> +	{ .compatible = "allwinner,sun4i-sid", },
> +	{/* sentinel */}
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> +
> +static const struct bin_attribute sid_bin_attr = {
> +	.attr = {
> +		.name = "eeprom",
> +		.mode = S_IRUGO,
> +	},
> +	.size = SID_SIZE,
> +	.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, "%s driver unloaded\n", DRV_NAME);
> +
> +	return 0;
> +}
> +
> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	u8 entropy[SID_SIZE];
> +	unsigned int i;
> +	struct resource *res;
> +	void __iomem *sid_reg_base;
> +	int ret;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(sid_reg_base))
> +		return PTR_ERR(sid_reg_base);
> +	platform_set_drvdata(pdev, sid_reg_base);
> +
> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < SID_SIZE; i++)
> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
> +	add_device_randomness(entropy, SID_SIZE);
> +	dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver sunxi_sid_driver = {
> +	.probe = sunxi_sid_probe,
> +	.remove = sunxi_sid_remove,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.owner = THIS_MODULE,
> +		.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");

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 20:59   ` Oliver Schinagl
@ 2013-06-17 22:58     ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-17 22:58 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: arnd, maxime.ripard, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
> 
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
> needs to be applied to this pin.
> 
> Even so, they can still be used to generate a board-unique mac from, board
> unique RSA key and seed the kernel RNG.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)
> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  drivers/misc/eeprom/Kconfig     |  17 +++++
>  drivers/misc/eeprom/Makefile    |   1 +
>  drivers/misc/eeprom/sunxi_sid.c | 147 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 165 insertions(+)
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> 
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..c7bc6ed 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,21 @@ 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. Currently supported are:
> +		sun4i (A10)
> +		sun5i (A13)
> +
> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID
> +
> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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
> new file mode 100644
> index 0000000..6a16c19
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,147 @@
> +/*
> + * Copyright (c) 2013 Oliver Schinagl
> + * http://www.linux-sunxi.org
> + *
> + * Oliver Schinagl <oliver@schinagl.nl>
> + *
> + * 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, a 128 bit eeprom, 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/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/random.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +#define DRV_NAME "sunxi-sid"
> +
> +/* There are 4 32-bit keys */
> +#define SID_KEYS 4
> +/* Each key is 4 bytes long */
> +#define SID_SIZE (SID_KEYS * 4)
> +
> +/* We read the entire key, due to a 32 bit read alignment requirement. Since we
> + * want to return the requested byte, this resuls in somewhat slower code and
> + * uses 4 times more reads as needed but keeps code simpler. Since the SID is
> + * only very rarly probed, this is not really an issue.
> + */
> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> +			      const unsigned int offset)
> +{
> +	u32 sid_key;
> +
> +	if (offset >= SID_SIZE)
> +		return 0;
> +
> +	sid_key = ioread32be(sid_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)
> +{
> +	int i;
> +	struct platform_device *pdev;
> +	void __iomem *sid_reg_base;
> +
> +	pdev = to_platform_device(kobj_to_dev(kobj));
> +	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
> +
> +	if (pos < 0 || pos >= SID_SIZE)
> +		return 0;
> +	if (size > (SID_SIZE - pos))
> +		size = SID_SIZE - pos;
> +
> +	for (i = 0; i < size; i++)
> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> +
> +	return i;
> +}
> +
> +static const struct of_device_id sunxi_sid_of_match[] = {
> +	{ .compatible = "allwinner,sun4i-sid", },
> +	{/* sentinel */}
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> +
> +static const struct bin_attribute sid_bin_attr = {
> +	.attr = {
> +		.name = "eeprom",
> +		.mode = S_IRUGO,
> +	},
> +	.size = SID_SIZE,
> +	.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, "%s driver unloaded\n", DRV_NAME);
> +
> +	return 0;
> +}
> +
> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	u8 entropy[SID_SIZE];
> +	unsigned int i;
> +	struct resource *res;
> +	void __iomem *sid_reg_base;
> +	int ret;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(sid_reg_base))
> +		return PTR_ERR(sid_reg_base);
> +	platform_set_drvdata(pdev, sid_reg_base);
> +
> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> +	if (ret)
> +		return ret;

You just raced with userspace, having the file show up after the device
was announced to users that it was there.  Please use the proper device
file api to add default attributes to prevent this from happening.

Bonus is it ends up making your driver smaller and simpler :)

> +	for (i = 0; i < SID_SIZE; i++)
> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
> +	add_device_randomness(entropy, SID_SIZE);

Really?  I don't mind it but is this something that is ok to add to the
pool?  Will it be different on different machines with this device?  Or
will it always be the same on all systems with this device?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 22:58     ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-17 22:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
> 
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
> needs to be applied to this pin.
> 
> Even so, they can still be used to generate a board-unique mac from, board
> unique RSA key and seed the kernel RNG.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)
> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  drivers/misc/eeprom/Kconfig     |  17 +++++
>  drivers/misc/eeprom/Makefile    |   1 +
>  drivers/misc/eeprom/sunxi_sid.c | 147 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 165 insertions(+)
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> 
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..c7bc6ed 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,21 @@ 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. Currently supported are:
> +		sun4i (A10)
> +		sun5i (A13)
> +
> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID
> +
> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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
> new file mode 100644
> index 0000000..6a16c19
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,147 @@
> +/*
> + * Copyright (c) 2013 Oliver Schinagl
> + * http://www.linux-sunxi.org
> + *
> + * Oliver Schinagl <oliver@schinagl.nl>
> + *
> + * 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, a 128 bit eeprom, 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/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/random.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +#define DRV_NAME "sunxi-sid"
> +
> +/* There are 4 32-bit keys */
> +#define SID_KEYS 4
> +/* Each key is 4 bytes long */
> +#define SID_SIZE (SID_KEYS * 4)
> +
> +/* We read the entire key, due to a 32 bit read alignment requirement. Since we
> + * want to return the requested byte, this resuls in somewhat slower code and
> + * uses 4 times more reads as needed but keeps code simpler. Since the SID is
> + * only very rarly probed, this is not really an issue.
> + */
> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> +			      const unsigned int offset)
> +{
> +	u32 sid_key;
> +
> +	if (offset >= SID_SIZE)
> +		return 0;
> +
> +	sid_key = ioread32be(sid_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)
> +{
> +	int i;
> +	struct platform_device *pdev;
> +	void __iomem *sid_reg_base;
> +
> +	pdev = to_platform_device(kobj_to_dev(kobj));
> +	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
> +
> +	if (pos < 0 || pos >= SID_SIZE)
> +		return 0;
> +	if (size > (SID_SIZE - pos))
> +		size = SID_SIZE - pos;
> +
> +	for (i = 0; i < size; i++)
> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> +
> +	return i;
> +}
> +
> +static const struct of_device_id sunxi_sid_of_match[] = {
> +	{ .compatible = "allwinner,sun4i-sid", },
> +	{/* sentinel */}
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> +
> +static const struct bin_attribute sid_bin_attr = {
> +	.attr = {
> +		.name = "eeprom",
> +		.mode = S_IRUGO,
> +	},
> +	.size = SID_SIZE,
> +	.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, "%s driver unloaded\n", DRV_NAME);
> +
> +	return 0;
> +}
> +
> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	u8 entropy[SID_SIZE];
> +	unsigned int i;
> +	struct resource *res;
> +	void __iomem *sid_reg_base;
> +	int ret;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(sid_reg_base))
> +		return PTR_ERR(sid_reg_base);
> +	platform_set_drvdata(pdev, sid_reg_base);
> +
> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> +	if (ret)
> +		return ret;

You just raced with userspace, having the file show up after the device
was announced to users that it was there.  Please use the proper device
file api to add default attributes to prevent this from happening.

Bonus is it ends up making your driver smaller and simpler :)

> +	for (i = 0; i < SID_SIZE; i++)
> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
> +	add_device_randomness(entropy, SID_SIZE);

Really?  I don't mind it but is this something that is ok to add to the
pool?  Will it be different on different machines with this device?  Or
will it always be the same on all systems with this device?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 22:58     ` Greg KH
@ 2013-06-17 23:23       ` Henrik Nordström
  -1 siblings, 0 replies; 142+ messages in thread
From: Henrik Nordström @ 2013-06-17 23:23 UTC (permalink / raw)
  To: linux-sunxi
  Cc: Oliver Schinagl, arnd, maxime.ripard, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij,
	Oliver Schinagl

mån 2013-06-17 klockan 15:58 -0700 skrev Greg KH:

> Really?  I don't mind it but is this something that is ok to add to the
> pool?  Will it be different on different machines with this device?  Or
> will it always be the same on all systems with this device?

The data is unique per CPU, so it's different on every machine and is
why it was suggested to have it added to the pool.

Regards
Henrik


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 23:23       ` Henrik Nordström
  0 siblings, 0 replies; 142+ messages in thread
From: Henrik Nordström @ 2013-06-17 23:23 UTC (permalink / raw)
  To: linux-arm-kernel

m?n 2013-06-17 klockan 15:58 -0700 skrev Greg KH:

> Really?  I don't mind it but is this something that is ok to add to the
> pool?  Will it be different on different machines with this device?  Or
> will it always be the same on all systems with this device?

The data is unique per CPU, so it's different on every machine and is
why it was suggested to have it added to the pool.

Regards
Henrik

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 20:59   ` Oliver Schinagl
@ 2013-06-18  5:41     ` Andy Shevchenko
  -1 siblings, 0 replies; 142+ messages in thread
From: Andy Shevchenko @ 2013-06-18  5:41 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Arnd Bergmann, Greg Kroah-Hartman, maxime.ripard, linux-kernel,
	linux-arm Mailing List, Russell King, Linus Walleij, linux-sunxi,
	Oliver Schinagl

On Mon, Jun 17, 2013 at 11:59 PM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
>
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
>
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
> needs to be applied to this pin.
>
> Even so, they can still be used to generate a board-unique mac from, board
> unique RSA key and seed the kernel RNG.
>

> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,147 @@

> +#include <linux/compiler.h>

I don't think you have to use this header explicitly.

> +#define DRV_NAME "sunxi-sid"

> +       if (size > (SID_SIZE - pos))

Useless internal braces.

> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +       device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> +       dev_dbg(&pdev->dev, "%s driver unloaded\n", DRV_NAME);

It's useless to use DRV_NAME in conjunction with dev_* macros. dev_*
will print driver name as a prefix.

--
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-18  5:41     ` Andy Shevchenko
  0 siblings, 0 replies; 142+ messages in thread
From: Andy Shevchenko @ 2013-06-18  5:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 17, 2013 at 11:59 PM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
>
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
>
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
> needs to be applied to this pin.
>
> Even so, they can still be used to generate a board-unique mac from, board
> unique RSA key and seed the kernel RNG.
>

> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,147 @@

> +#include <linux/compiler.h>

I don't think you have to use this header explicitly.

> +#define DRV_NAME "sunxi-sid"

> +       if (size > (SID_SIZE - pos))

Useless internal braces.

> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +       device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> +       dev_dbg(&pdev->dev, "%s driver unloaded\n", DRV_NAME);

It's useless to use DRV_NAME in conjunction with dev_* macros. dev_*
will print driver name as a prefix.

--
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 22:58     ` Greg KH
@ 2013-06-24  9:29       ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-06-24  9:29 UTC (permalink / raw)
  To: Greg KH
  Cc: Oliver Schinagl, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

[-- Attachment #1: Type: text/plain, Size: 1501 bytes --]

Hi Greg,

On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:

[..]

> > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> > +{
> > +	u8 entropy[SID_SIZE];
> > +	unsigned int i;
> > +	struct resource *res;
> > +	void __iomem *sid_reg_base;
> > +	int ret;
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> > +	if (IS_ERR(sid_reg_base))
> > +		return PTR_ERR(sid_reg_base);
> > +	platform_set_drvdata(pdev, sid_reg_base);
> > +
> > +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> > +	if (ret)
> > +		return ret;
> 
> You just raced with userspace, having the file show up after the device
> was announced to users that it was there.  Please use the proper device
> file api to add default attributes to prevent this from happening.

Sorry if the question looks dumb, but what kind of race can we generate
here?

The device_create_bin_file is the last call that we make (if we except
the entropy stuff, but it doesn't really matter here), so after we
created the file, we have everything properly initialised so that our
functions can be called, right?

And another dumb question for you, what is the "proper device file API"
you are referring to ? :)

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-24  9:29       ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-06-24  9:29 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Greg,

On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:

[..]

> > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> > +{
> > +	u8 entropy[SID_SIZE];
> > +	unsigned int i;
> > +	struct resource *res;
> > +	void __iomem *sid_reg_base;
> > +	int ret;
> > +
> > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> > +	if (IS_ERR(sid_reg_base))
> > +		return PTR_ERR(sid_reg_base);
> > +	platform_set_drvdata(pdev, sid_reg_base);
> > +
> > +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> > +	if (ret)
> > +		return ret;
> 
> You just raced with userspace, having the file show up after the device
> was announced to users that it was there.  Please use the proper device
> file api to add default attributes to prevent this from happening.

Sorry if the question looks dumb, but what kind of race can we generate
here?

The device_create_bin_file is the last call that we make (if we except
the entropy stuff, but it doesn't really matter here), so after we
created the file, we have everything properly initialised so that our
functions can be called, right?

And another dumb question for you, what is the "proper device file API"
you are referring to ? :)

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130624/2bb28f3d/attachment.sig>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24  9:29       ` Maxime Ripard
@ 2013-06-24 16:04         ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-24 16:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Oliver Schinagl, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> Hi Greg,
> 
> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> 
> [..]
> 
> > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> > > +{
> > > +	u8 entropy[SID_SIZE];
> > > +	unsigned int i;
> > > +	struct resource *res;
> > > +	void __iomem *sid_reg_base;
> > > +	int ret;
> > > +
> > > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> > > +	if (IS_ERR(sid_reg_base))
> > > +		return PTR_ERR(sid_reg_base);
> > > +	platform_set_drvdata(pdev, sid_reg_base);
> > > +
> > > +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> > > +	if (ret)
> > > +		return ret;
> > 
> > You just raced with userspace, having the file show up after the device
> > was announced to users that it was there.  Please use the proper device
> > file api to add default attributes to prevent this from happening.
> 
> Sorry if the question looks dumb, but what kind of race can we generate
> here?

Userspace gets told about the device from the driver core, udev runs and
reads all of the attributes, then your probe function comes along and
adds a new attribute.  Userspace will then not know about it at all.

> The device_create_bin_file is the last call that we make (if we except
> the entropy stuff, but it doesn't really matter here), so after we
> created the file, we have everything properly initialised so that our
> functions can be called, right?
> 
> And another dumb question for you, what is the "proper device file API"
> you are referring to ? :)

Please read Documentation/driver_model/device.txt and see the section on
Attributes for what to do.  If you have specific questions after reading
that, please let me know.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-24 16:04         ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-24 16:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> Hi Greg,
> 
> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> 
> [..]
> 
> > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> > > +{
> > > +	u8 entropy[SID_SIZE];
> > > +	unsigned int i;
> > > +	struct resource *res;
> > > +	void __iomem *sid_reg_base;
> > > +	int ret;
> > > +
> > > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> > > +	if (IS_ERR(sid_reg_base))
> > > +		return PTR_ERR(sid_reg_base);
> > > +	platform_set_drvdata(pdev, sid_reg_base);
> > > +
> > > +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> > > +	if (ret)
> > > +		return ret;
> > 
> > You just raced with userspace, having the file show up after the device
> > was announced to users that it was there.  Please use the proper device
> > file api to add default attributes to prevent this from happening.
> 
> Sorry if the question looks dumb, but what kind of race can we generate
> here?

Userspace gets told about the device from the driver core, udev runs and
reads all of the attributes, then your probe function comes along and
adds a new attribute.  Userspace will then not know about it at all.

> The device_create_bin_file is the last call that we make (if we except
> the entropy stuff, but it doesn't really matter here), so after we
> created the file, we have everything properly initialised so that our
> functions can be called, right?
> 
> And another dumb question for you, what is the "proper device file API"
> you are referring to ? :)

Please read Documentation/driver_model/device.txt and see the section on
Attributes for what to do.  If you have specific questions after reading
that, please let me know.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24 16:04         ` Greg KH
@ 2013-06-24 17:11           ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-24 17:11 UTC (permalink / raw)
  To: Greg KH
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

Hey Greg,
On 06/24/13 18:04, Greg KH wrote:
> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>> Hi Greg,
>>
>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>>> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>>
>> [..]
>>
>>>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>>>> +{
>>>> +	u8 entropy[SID_SIZE];
>>>> +	unsigned int i;
>>>> +	struct resource *res;
>>>> +	void __iomem *sid_reg_base;
>>>> +	int ret;
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>>>> +	if (IS_ERR(sid_reg_base))
>>>> +		return PTR_ERR(sid_reg_base);
>>>> +	platform_set_drvdata(pdev, sid_reg_base);
>>>> +
>>>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>>>> +	if (ret)
>>>> +		return ret;
>>>
>>> You just raced with userspace, having the file show up after the device
>>> was announced to users that it was there.  Please use the proper device
>>> file api to add default attributes to prevent this from happening.
>>
>> Sorry if the question looks dumb, but what kind of race can we generate
>> here?
>
> Userspace gets told about the device from the driver core, udev runs and
> reads all of the attributes, then your probe function comes along and
> adds a new attribute.  Userspace will then not know about it at all.
>
>> The device_create_bin_file is the last call that we make (if we except
>> the entropy stuff, but it doesn't really matter here), so after we
>> created the file, we have everything properly initialised so that our
>> functions can be called, right?
>>
>> And another dumb question for you, what is the "proper device file API"
>> you are referring to ? :)
>
> Please read Documentation/driver_model/device.txt and see the section on
> Attributes for what to do.  If you have specific questions after reading
> that, please let me know.
Since Maxime kinda asked for me, I hope you don't mind me following up.

That doc doesn't mention the binary interface at all. Initially I had 
both devices up, the 'read' device as a textual representation and added 
the binary one later. Maxime and I decided the binary one made more 
sense, as the only textual user would be a human and they don't poke 
that entry that often.

So what default way exists for binary files or how would that be solved?

Oliver
>
> thanks,
>
> greg k-h
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-24 17:11           ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-24 17:11 UTC (permalink / raw)
  To: linux-arm-kernel

Hey Greg,
On 06/24/13 18:04, Greg KH wrote:
> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>> Hi Greg,
>>
>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>>> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>>
>> [..]
>>
>>>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>>>> +{
>>>> +	u8 entropy[SID_SIZE];
>>>> +	unsigned int i;
>>>> +	struct resource *res;
>>>> +	void __iomem *sid_reg_base;
>>>> +	int ret;
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>>>> +	if (IS_ERR(sid_reg_base))
>>>> +		return PTR_ERR(sid_reg_base);
>>>> +	platform_set_drvdata(pdev, sid_reg_base);
>>>> +
>>>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>>>> +	if (ret)
>>>> +		return ret;
>>>
>>> You just raced with userspace, having the file show up after the device
>>> was announced to users that it was there.  Please use the proper device
>>> file api to add default attributes to prevent this from happening.
>>
>> Sorry if the question looks dumb, but what kind of race can we generate
>> here?
>
> Userspace gets told about the device from the driver core, udev runs and
> reads all of the attributes, then your probe function comes along and
> adds a new attribute.  Userspace will then not know about it at all.
>
>> The device_create_bin_file is the last call that we make (if we except
>> the entropy stuff, but it doesn't really matter here), so after we
>> created the file, we have everything properly initialised so that our
>> functions can be called, right?
>>
>> And another dumb question for you, what is the "proper device file API"
>> you are referring to ? :)
>
> Please read Documentation/driver_model/device.txt and see the section on
> Attributes for what to do.  If you have specific questions after reading
> that, please let me know.
Since Maxime kinda asked for me, I hope you don't mind me following up.

That doc doesn't mention the binary interface at all. Initially I had 
both devices up, the 'read' device as a textual representation and added 
the binary one later. Maxime and I decided the binary one made more 
sense, as the only textual user would be a human and they don't poke 
that entry that often.

So what default way exists for binary files or how would that be solved?

Oliver
>
> thanks,
>
> greg k-h
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24 17:11           ` Oliver Schinagl
@ 2013-06-24 18:15             ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-24 18:15 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
> Hey Greg,
> On 06/24/13 18:04, Greg KH wrote:
> >On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >>Hi Greg,
> >>
> >>On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >>>On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >>
> >>[..]
> >>
> >>>>+static int __init sunxi_sid_probe(struct platform_device *pdev)
> >>>>+{
> >>>>+	u8 entropy[SID_SIZE];
> >>>>+	unsigned int i;
> >>>>+	struct resource *res;
> >>>>+	void __iomem *sid_reg_base;
> >>>>+	int ret;
> >>>>+
> >>>>+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>>>+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >>>>+	if (IS_ERR(sid_reg_base))
> >>>>+		return PTR_ERR(sid_reg_base);
> >>>>+	platform_set_drvdata(pdev, sid_reg_base);
> >>>>+
> >>>>+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >>>>+	if (ret)
> >>>>+		return ret;
> >>>
> >>>You just raced with userspace, having the file show up after the device
> >>>was announced to users that it was there.  Please use the proper device
> >>>file api to add default attributes to prevent this from happening.
> >>
> >>Sorry if the question looks dumb, but what kind of race can we generate
> >>here?
> >
> >Userspace gets told about the device from the driver core, udev runs and
> >reads all of the attributes, then your probe function comes along and
> >adds a new attribute.  Userspace will then not know about it at all.
> >
> >>The device_create_bin_file is the last call that we make (if we except
> >>the entropy stuff, but it doesn't really matter here), so after we
> >>created the file, we have everything properly initialised so that our
> >>functions can be called, right?
> >>
> >>And another dumb question for you, what is the "proper device file API"
> >>you are referring to ? :)
> >
> >Please read Documentation/driver_model/device.txt and see the section on
> >Attributes for what to do.  If you have specific questions after reading
> >that, please let me know.
> Since Maxime kinda asked for me, I hope you don't mind me following up.
> 
> That doc doesn't mention the binary interface at all. Initially I
> had both devices up, the 'read' device as a textual representation
> and added the binary one later. Maxime and I decided the binary one
> made more sense, as the only textual user would be a human and they
> don't poke that entry that often.
> 
> So what default way exists for binary files or how would that be solved?

The same interface should work just fine for binary files, have you
tried it?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-24 18:15             ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-24 18:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
> Hey Greg,
> On 06/24/13 18:04, Greg KH wrote:
> >On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >>Hi Greg,
> >>
> >>On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >>>On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >>
> >>[..]
> >>
> >>>>+static int __init sunxi_sid_probe(struct platform_device *pdev)
> >>>>+{
> >>>>+	u8 entropy[SID_SIZE];
> >>>>+	unsigned int i;
> >>>>+	struct resource *res;
> >>>>+	void __iomem *sid_reg_base;
> >>>>+	int ret;
> >>>>+
> >>>>+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>>>+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >>>>+	if (IS_ERR(sid_reg_base))
> >>>>+		return PTR_ERR(sid_reg_base);
> >>>>+	platform_set_drvdata(pdev, sid_reg_base);
> >>>>+
> >>>>+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >>>>+	if (ret)
> >>>>+		return ret;
> >>>
> >>>You just raced with userspace, having the file show up after the device
> >>>was announced to users that it was there.  Please use the proper device
> >>>file api to add default attributes to prevent this from happening.
> >>
> >>Sorry if the question looks dumb, but what kind of race can we generate
> >>here?
> >
> >Userspace gets told about the device from the driver core, udev runs and
> >reads all of the attributes, then your probe function comes along and
> >adds a new attribute.  Userspace will then not know about it at all.
> >
> >>The device_create_bin_file is the last call that we make (if we except
> >>the entropy stuff, but it doesn't really matter here), so after we
> >>created the file, we have everything properly initialised so that our
> >>functions can be called, right?
> >>
> >>And another dumb question for you, what is the "proper device file API"
> >>you are referring to ? :)
> >
> >Please read Documentation/driver_model/device.txt and see the section on
> >Attributes for what to do.  If you have specific questions after reading
> >that, please let me know.
> Since Maxime kinda asked for me, I hope you don't mind me following up.
> 
> That doc doesn't mention the binary interface at all. Initially I
> had both devices up, the 'read' device as a textual representation
> and added the binary one later. Maxime and I decided the binary one
> made more sense, as the only textual user would be a human and they
> don't poke that entry that often.
> 
> So what default way exists for binary files or how would that be solved?

The same interface should work just fine for binary files, have you
tried it?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24 16:04         ` Greg KH
@ 2013-06-24 21:04           ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-06-24 21:04 UTC (permalink / raw)
  To: Greg KH
  Cc: Oliver Schinagl, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

[-- Attachment #1: Type: text/plain, Size: 1664 bytes --]

On Mon, Jun 24, 2013 at 09:04:40AM -0700, Greg KH wrote:
> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> > Hi Greg,
> > 
> > On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> > > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> > 
> > [..]
> > 
> > > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> > > > +{
> > > > +	u8 entropy[SID_SIZE];
> > > > +	unsigned int i;
> > > > +	struct resource *res;
> > > > +	void __iomem *sid_reg_base;
> > > > +	int ret;
> > > > +
> > > > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> > > > +	if (IS_ERR(sid_reg_base))
> > > > +		return PTR_ERR(sid_reg_base);
> > > > +	platform_set_drvdata(pdev, sid_reg_base);
> > > > +
> > > > +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> > > > +	if (ret)
> > > > +		return ret;
> > > 
> > > You just raced with userspace, having the file show up after the device
> > > was announced to users that it was there.  Please use the proper device
> > > file api to add default attributes to prevent this from happening.
> > 
> > Sorry if the question looks dumb, but what kind of race can we generate
> > here?
> 
> Userspace gets told about the device from the driver core, udev runs and
> reads all of the attributes, then your probe function comes along and
> adds a new attribute.  Userspace will then not know about it at all.

Hmm, I see.

Thanks for the explanations!

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-24 21:04           ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-06-24 21:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 24, 2013 at 09:04:40AM -0700, Greg KH wrote:
> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> > Hi Greg,
> > 
> > On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> > > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> > 
> > [..]
> > 
> > > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> > > > +{
> > > > +	u8 entropy[SID_SIZE];
> > > > +	unsigned int i;
> > > > +	struct resource *res;
> > > > +	void __iomem *sid_reg_base;
> > > > +	int ret;
> > > > +
> > > > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > > +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> > > > +	if (IS_ERR(sid_reg_base))
> > > > +		return PTR_ERR(sid_reg_base);
> > > > +	platform_set_drvdata(pdev, sid_reg_base);
> > > > +
> > > > +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> > > > +	if (ret)
> > > > +		return ret;
> > > 
> > > You just raced with userspace, having the file show up after the device
> > > was announced to users that it was there.  Please use the proper device
> > > file api to add default attributes to prevent this from happening.
> > 
> > Sorry if the question looks dumb, but what kind of race can we generate
> > here?
> 
> Userspace gets told about the device from the driver core, udev runs and
> reads all of the attributes, then your probe function comes along and
> adds a new attribute.  Userspace will then not know about it at all.

Hmm, I see.

Thanks for the explanations!

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130624/8f4b023d/attachment.sig>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24 18:15             ` Greg KH
@ 2013-06-24 21:21               ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-24 21:21 UTC (permalink / raw)
  To: Greg KH
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On 06/24/13 20:15, Greg KH wrote:
> On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
>> Hey Greg,
>> On 06/24/13 18:04, Greg KH wrote:
>>> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>>>> Hi Greg,
>>>>
>>>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>>>>> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>>>>
>>>> [..]
>>>>
>>>>>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>>>>>> +{
>>>>>> +	u8 entropy[SID_SIZE];
>>>>>> +	unsigned int i;
>>>>>> +	struct resource *res;
>>>>>> +	void __iomem *sid_reg_base;
>>>>>> +	int ret;
>>>>>> +
>>>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>>>>>> +	if (IS_ERR(sid_reg_base))
>>>>>> +		return PTR_ERR(sid_reg_base);
>>>>>> +	platform_set_drvdata(pdev, sid_reg_base);
>>>>>> +
>>>>>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>>>>>> +	if (ret)
>>>>>> +		return ret;
>>>>>
>>>>> You just raced with userspace, having the file show up after the device
>>>>> was announced to users that it was there.  Please use the proper device
>>>>> file api to add default attributes to prevent this from happening.
>>>>
>>>> Sorry if the question looks dumb, but what kind of race can we generate
>>>> here?
>>>
>>> Userspace gets told about the device from the driver core, udev runs and
>>> reads all of the attributes, then your probe function comes along and
>>> adds a new attribute.  Userspace will then not know about it at all.
>>>
>>>> The device_create_bin_file is the last call that we make (if we except
>>>> the entropy stuff, but it doesn't really matter here), so after we
>>>> created the file, we have everything properly initialised so that our
>>>> functions can be called, right?
>>>>
>>>> And another dumb question for you, what is the "proper device file API"
>>>> you are referring to ? :)
>>>
>>> Please read Documentation/driver_model/device.txt and see the section on
>>> Attributes for what to do.  If you have specific questions after reading
>>> that, please let me know.
>> Since Maxime kinda asked for me, I hope you don't mind me following up.
>>
>> That doc doesn't mention the binary interface at all. Initially I
>> had both devices up, the 'read' device as a textual representation
>> and added the binary one later. Maxime and I decided the binary one
>> made more sense, as the only textual user would be a human and they
>> don't poke that entry that often.
>>
>> So what default way exists for binary files or how would that be solved?
>
> The same interface should work just fine for binary files, have you
> tried it?
I'll just take the plunge and make myself look stupid ;)

I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO, 
sid_read, NULL); So far so good I'd hope.

Of course now I'll have to change the function's parameters from

static ssize_t sid_read(struct file *fd, struct kobject *kobj,
			struct bin_attribute *attr, char *buf,
			loff_t pos, size_t size)

to

static ssize_t sid_read(struct device *dev,
			struct device_attribute *attr, char *buf)

But now, I'm missing things like 'pos' and 'size', both which determine 
the requested bytes. True, in this specific driver we are talking about 
'only' 16 bytes, but what if it weren't but a few MiB and in sysfs we 
want to read some random byte, will we have to put the entire blok into 
the buffer?

So sorry for not understanding, but ... I don't understand :)

Oliver
>
> thanks,
>
> greg k-h
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-24 21:21               ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-24 21:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/24/13 20:15, Greg KH wrote:
> On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
>> Hey Greg,
>> On 06/24/13 18:04, Greg KH wrote:
>>> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>>>> Hi Greg,
>>>>
>>>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>>>>> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>>>>
>>>> [..]
>>>>
>>>>>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>>>>>> +{
>>>>>> +	u8 entropy[SID_SIZE];
>>>>>> +	unsigned int i;
>>>>>> +	struct resource *res;
>>>>>> +	void __iomem *sid_reg_base;
>>>>>> +	int ret;
>>>>>> +
>>>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>>>>>> +	if (IS_ERR(sid_reg_base))
>>>>>> +		return PTR_ERR(sid_reg_base);
>>>>>> +	platform_set_drvdata(pdev, sid_reg_base);
>>>>>> +
>>>>>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>>>>>> +	if (ret)
>>>>>> +		return ret;
>>>>>
>>>>> You just raced with userspace, having the file show up after the device
>>>>> was announced to users that it was there.  Please use the proper device
>>>>> file api to add default attributes to prevent this from happening.
>>>>
>>>> Sorry if the question looks dumb, but what kind of race can we generate
>>>> here?
>>>
>>> Userspace gets told about the device from the driver core, udev runs and
>>> reads all of the attributes, then your probe function comes along and
>>> adds a new attribute.  Userspace will then not know about it at all.
>>>
>>>> The device_create_bin_file is the last call that we make (if we except
>>>> the entropy stuff, but it doesn't really matter here), so after we
>>>> created the file, we have everything properly initialised so that our
>>>> functions can be called, right?
>>>>
>>>> And another dumb question for you, what is the "proper device file API"
>>>> you are referring to ? :)
>>>
>>> Please read Documentation/driver_model/device.txt and see the section on
>>> Attributes for what to do.  If you have specific questions after reading
>>> that, please let me know.
>> Since Maxime kinda asked for me, I hope you don't mind me following up.
>>
>> That doc doesn't mention the binary interface at all. Initially I
>> had both devices up, the 'read' device as a textual representation
>> and added the binary one later. Maxime and I decided the binary one
>> made more sense, as the only textual user would be a human and they
>> don't poke that entry that often.
>>
>> So what default way exists for binary files or how would that be solved?
>
> The same interface should work just fine for binary files, have you
> tried it?
I'll just take the plunge and make myself look stupid ;)

I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO, 
sid_read, NULL); So far so good I'd hope.

Of course now I'll have to change the function's parameters from

static ssize_t sid_read(struct file *fd, struct kobject *kobj,
			struct bin_attribute *attr, char *buf,
			loff_t pos, size_t size)

to

static ssize_t sid_read(struct device *dev,
			struct device_attribute *attr, char *buf)

But now, I'm missing things like 'pos' and 'size', both which determine 
the requested bytes. True, in this specific driver we are talking about 
'only' 16 bytes, but what if it weren't but a few MiB and in sysfs we 
want to read some random byte, will we have to put the entire blok into 
the buffer?

So sorry for not understanding, but ... I don't understand :)

Oliver
>
> thanks,
>
> greg k-h
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24 21:21               ` Oliver Schinagl
@ 2013-06-24 21:46                 ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-24 21:46 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Mon, Jun 24, 2013 at 11:21:16PM +0200, Oliver Schinagl wrote:
> On 06/24/13 20:15, Greg KH wrote:
> >On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
> >>Hey Greg,
> >>On 06/24/13 18:04, Greg KH wrote:
> >>>On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >>>>Hi Greg,
> >>>>
> >>>>On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >>>>>On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >>>>
> >>>>[..]
> >>>>
> >>>>>>+static int __init sunxi_sid_probe(struct platform_device *pdev)
> >>>>>>+{
> >>>>>>+	u8 entropy[SID_SIZE];
> >>>>>>+	unsigned int i;
> >>>>>>+	struct resource *res;
> >>>>>>+	void __iomem *sid_reg_base;
> >>>>>>+	int ret;
> >>>>>>+
> >>>>>>+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>>>>>+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >>>>>>+	if (IS_ERR(sid_reg_base))
> >>>>>>+		return PTR_ERR(sid_reg_base);
> >>>>>>+	platform_set_drvdata(pdev, sid_reg_base);
> >>>>>>+
> >>>>>>+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >>>>>>+	if (ret)
> >>>>>>+		return ret;
> >>>>>
> >>>>>You just raced with userspace, having the file show up after the device
> >>>>>was announced to users that it was there.  Please use the proper device
> >>>>>file api to add default attributes to prevent this from happening.
> >>>>
> >>>>Sorry if the question looks dumb, but what kind of race can we generate
> >>>>here?
> >>>
> >>>Userspace gets told about the device from the driver core, udev runs and
> >>>reads all of the attributes, then your probe function comes along and
> >>>adds a new attribute.  Userspace will then not know about it at all.
> >>>
> >>>>The device_create_bin_file is the last call that we make (if we except
> >>>>the entropy stuff, but it doesn't really matter here), so after we
> >>>>created the file, we have everything properly initialised so that our
> >>>>functions can be called, right?
> >>>>
> >>>>And another dumb question for you, what is the "proper device file API"
> >>>>you are referring to ? :)
> >>>
> >>>Please read Documentation/driver_model/device.txt and see the section on
> >>>Attributes for what to do.  If you have specific questions after reading
> >>>that, please let me know.
> >>Since Maxime kinda asked for me, I hope you don't mind me following up.
> >>
> >>That doc doesn't mention the binary interface at all. Initially I
> >>had both devices up, the 'read' device as a textual representation
> >>and added the binary one later. Maxime and I decided the binary one
> >>made more sense, as the only textual user would be a human and they
> >>don't poke that entry that often.
> >>
> >>So what default way exists for binary files or how would that be solved?
> >
> >The same interface should work just fine for binary files, have you
> >tried it?
> I'll just take the plunge and make myself look stupid ;)
> 
> I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO,
> sid_read, NULL); So far so good I'd hope.

Ick, no.

> Of course now I'll have to change the function's parameters from
> 
> static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> 			struct bin_attribute *attr, char *buf,
> 			loff_t pos, size_t size)
> 
> to
> 
> static ssize_t sid_read(struct device *dev,
> 			struct device_attribute *attr, char *buf)

Which is what do you do not want, as you find out:

> But now, I'm missing things like 'pos' and 'size', both which
> determine the requested bytes. True, in this specific driver we are
> talking about 'only' 16 bytes, but what if it weren't but a few MiB
> and in sysfs we want to read some random byte, will we have to put
> the entire blok into the buffer?
> 
> So sorry for not understanding, but ... I don't understand :)

Stick with a binary attribute, and attach that to the proper class
structure and all should be fine.

Ah crap, you're using a platform device.

{sigh}

Why?  Why not use a "real" device which has a "real" class, and then use
the interfaces there?

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-24 21:46                 ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-24 21:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 24, 2013 at 11:21:16PM +0200, Oliver Schinagl wrote:
> On 06/24/13 20:15, Greg KH wrote:
> >On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
> >>Hey Greg,
> >>On 06/24/13 18:04, Greg KH wrote:
> >>>On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >>>>Hi Greg,
> >>>>
> >>>>On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >>>>>On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >>>>
> >>>>[..]
> >>>>
> >>>>>>+static int __init sunxi_sid_probe(struct platform_device *pdev)
> >>>>>>+{
> >>>>>>+	u8 entropy[SID_SIZE];
> >>>>>>+	unsigned int i;
> >>>>>>+	struct resource *res;
> >>>>>>+	void __iomem *sid_reg_base;
> >>>>>>+	int ret;
> >>>>>>+
> >>>>>>+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>>>>>+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >>>>>>+	if (IS_ERR(sid_reg_base))
> >>>>>>+		return PTR_ERR(sid_reg_base);
> >>>>>>+	platform_set_drvdata(pdev, sid_reg_base);
> >>>>>>+
> >>>>>>+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >>>>>>+	if (ret)
> >>>>>>+		return ret;
> >>>>>
> >>>>>You just raced with userspace, having the file show up after the device
> >>>>>was announced to users that it was there.  Please use the proper device
> >>>>>file api to add default attributes to prevent this from happening.
> >>>>
> >>>>Sorry if the question looks dumb, but what kind of race can we generate
> >>>>here?
> >>>
> >>>Userspace gets told about the device from the driver core, udev runs and
> >>>reads all of the attributes, then your probe function comes along and
> >>>adds a new attribute.  Userspace will then not know about it at all.
> >>>
> >>>>The device_create_bin_file is the last call that we make (if we except
> >>>>the entropy stuff, but it doesn't really matter here), so after we
> >>>>created the file, we have everything properly initialised so that our
> >>>>functions can be called, right?
> >>>>
> >>>>And another dumb question for you, what is the "proper device file API"
> >>>>you are referring to ? :)
> >>>
> >>>Please read Documentation/driver_model/device.txt and see the section on
> >>>Attributes for what to do.  If you have specific questions after reading
> >>>that, please let me know.
> >>Since Maxime kinda asked for me, I hope you don't mind me following up.
> >>
> >>That doc doesn't mention the binary interface at all. Initially I
> >>had both devices up, the 'read' device as a textual representation
> >>and added the binary one later. Maxime and I decided the binary one
> >>made more sense, as the only textual user would be a human and they
> >>don't poke that entry that often.
> >>
> >>So what default way exists for binary files or how would that be solved?
> >
> >The same interface should work just fine for binary files, have you
> >tried it?
> I'll just take the plunge and make myself look stupid ;)
> 
> I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO,
> sid_read, NULL); So far so good I'd hope.

Ick, no.

> Of course now I'll have to change the function's parameters from
> 
> static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> 			struct bin_attribute *attr, char *buf,
> 			loff_t pos, size_t size)
> 
> to
> 
> static ssize_t sid_read(struct device *dev,
> 			struct device_attribute *attr, char *buf)

Which is what do you do not want, as you find out:

> But now, I'm missing things like 'pos' and 'size', both which
> determine the requested bytes. True, in this specific driver we are
> talking about 'only' 16 bytes, but what if it weren't but a few MiB
> and in sysfs we want to read some random byte, will we have to put
> the entire blok into the buffer?
> 
> So sorry for not understanding, but ... I don't understand :)

Stick with a binary attribute, and attach that to the proper class
structure and all should be fine.

Ah crap, you're using a platform device.

{sigh}

Why?  Why not use a "real" device which has a "real" class, and then use
the interfaces there?

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24 21:46                 ` Greg KH
@ 2013-06-26  8:32                   ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-26  8:32 UTC (permalink / raw)
  To: Greg KH
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On 24-06-13 23:46, Greg KH wrote:
> On Mon, Jun 24, 2013 at 11:21:16PM +0200, Oliver Schinagl wrote:
>> On 06/24/13 20:15, Greg KH wrote:
>>> On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
>>>> Hey Greg,
>>>> On 06/24/13 18:04, Greg KH wrote:
>>>>> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>>>>>> Hi Greg,
>>>>>>
>>>>>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>>>>>>> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>>>>>>
>>>>>> [..]
>>>>>>
>>>>>>>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>>>>>>>> +{
>>>>>>>> +	u8 entropy[SID_SIZE];
>>>>>>>> +	unsigned int i;
>>>>>>>> +	struct resource *res;
>>>>>>>> +	void __iomem *sid_reg_base;
>>>>>>>> +	int ret;
>>>>>>>> +
>>>>>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>>>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>>>>>>>> +	if (IS_ERR(sid_reg_base))
>>>>>>>> +		return PTR_ERR(sid_reg_base);
>>>>>>>> +	platform_set_drvdata(pdev, sid_reg_base);
>>>>>>>> +
>>>>>>>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>>>>>>>> +	if (ret)
>>>>>>>> +		return ret;
>>>>>>>
>>>>>>> You just raced with userspace, having the file show up after the device
>>>>>>> was announced to users that it was there.  Please use the proper device
>>>>>>> file api to add default attributes to prevent this from happening.
>>>>>>
>>>>>> Sorry if the question looks dumb, but what kind of race can we generate
>>>>>> here?
>>>>>
>>>>> Userspace gets told about the device from the driver core, udev runs and
>>>>> reads all of the attributes, then your probe function comes along and
>>>>> adds a new attribute.  Userspace will then not know about it at all.
>>>>>
>>>>>> The device_create_bin_file is the last call that we make (if we except
>>>>>> the entropy stuff, but it doesn't really matter here), so after we
>>>>>> created the file, we have everything properly initialised so that our
>>>>>> functions can be called, right?
>>>>>>
>>>>>> And another dumb question for you, what is the "proper device file API"
>>>>>> you are referring to ? :)
>>>>>
>>>>> Please read Documentation/driver_model/device.txt and see the section on
>>>>> Attributes for what to do.  If you have specific questions after reading
>>>>> that, please let me know.
>>>> Since Maxime kinda asked for me, I hope you don't mind me following up.
>>>>
>>>> That doc doesn't mention the binary interface at all. Initially I
>>>> had both devices up, the 'read' device as a textual representation
>>>> and added the binary one later. Maxime and I decided the binary one
>>>> made more sense, as the only textual user would be a human and they
>>>> don't poke that entry that often.
>>>>
>>>> So what default way exists for binary files or how would that be solved?
>>>
>>> The same interface should work just fine for binary files, have you
>>> tried it?
>> I'll just take the plunge and make myself look stupid ;)
>>
>> I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO,
>> sid_read, NULL); So far so good I'd hope.
>
> Ick, no.
>
>> Of course now I'll have to change the function's parameters from
>>
>> static ssize_t sid_read(struct file *fd, struct kobject *kobj,
>> 			struct bin_attribute *attr, char *buf,
>> 			loff_t pos, size_t size)
>>
>> to
>>
>> static ssize_t sid_read(struct device *dev,
>> 			struct device_attribute *attr, char *buf)
>
> Which is what do you do not want, as you find out:
>
>> But now, I'm missing things like 'pos' and 'size', both which
>> determine the requested bytes. True, in this specific driver we are
>> talking about 'only' 16 bytes, but what if it weren't but a few MiB
>> and in sysfs we want to read some random byte, will we have to put
>> the entire blok into the buffer?
>>
>> So sorry for not understanding, but ... I don't understand :)
>
> Stick with a binary attribute, and attach that to the proper class
> structure and all should be fine.
>
> Ah crap, you're using a platform device.
>
> {sigh}
>
> Why?  Why not use a "real" device which has a "real" class, and then use
> the interfaces there?
Because, as I was told, this really is a platform device. If you have 
some example code I can look at and learn from that would be awesome. 
I'm still learning after all, and apparently I'm doing it wrong now :)
>
> greg k-h
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-26  8:32                   ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-26  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 24-06-13 23:46, Greg KH wrote:
> On Mon, Jun 24, 2013 at 11:21:16PM +0200, Oliver Schinagl wrote:
>> On 06/24/13 20:15, Greg KH wrote:
>>> On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
>>>> Hey Greg,
>>>> On 06/24/13 18:04, Greg KH wrote:
>>>>> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>>>>>> Hi Greg,
>>>>>>
>>>>>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>>>>>>> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>>>>>>
>>>>>> [..]
>>>>>>
>>>>>>>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>>>>>>>> +{
>>>>>>>> +	u8 entropy[SID_SIZE];
>>>>>>>> +	unsigned int i;
>>>>>>>> +	struct resource *res;
>>>>>>>> +	void __iomem *sid_reg_base;
>>>>>>>> +	int ret;
>>>>>>>> +
>>>>>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>>>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>>>>>>>> +	if (IS_ERR(sid_reg_base))
>>>>>>>> +		return PTR_ERR(sid_reg_base);
>>>>>>>> +	platform_set_drvdata(pdev, sid_reg_base);
>>>>>>>> +
>>>>>>>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>>>>>>>> +	if (ret)
>>>>>>>> +		return ret;
>>>>>>>
>>>>>>> You just raced with userspace, having the file show up after the device
>>>>>>> was announced to users that it was there.  Please use the proper device
>>>>>>> file api to add default attributes to prevent this from happening.
>>>>>>
>>>>>> Sorry if the question looks dumb, but what kind of race can we generate
>>>>>> here?
>>>>>
>>>>> Userspace gets told about the device from the driver core, udev runs and
>>>>> reads all of the attributes, then your probe function comes along and
>>>>> adds a new attribute.  Userspace will then not know about it at all.
>>>>>
>>>>>> The device_create_bin_file is the last call that we make (if we except
>>>>>> the entropy stuff, but it doesn't really matter here), so after we
>>>>>> created the file, we have everything properly initialised so that our
>>>>>> functions can be called, right?
>>>>>>
>>>>>> And another dumb question for you, what is the "proper device file API"
>>>>>> you are referring to ? :)
>>>>>
>>>>> Please read Documentation/driver_model/device.txt and see the section on
>>>>> Attributes for what to do.  If you have specific questions after reading
>>>>> that, please let me know.
>>>> Since Maxime kinda asked for me, I hope you don't mind me following up.
>>>>
>>>> That doc doesn't mention the binary interface at all. Initially I
>>>> had both devices up, the 'read' device as a textual representation
>>>> and added the binary one later. Maxime and I decided the binary one
>>>> made more sense, as the only textual user would be a human and they
>>>> don't poke that entry that often.
>>>>
>>>> So what default way exists for binary files or how would that be solved?
>>>
>>> The same interface should work just fine for binary files, have you
>>> tried it?
>> I'll just take the plunge and make myself look stupid ;)
>>
>> I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO,
>> sid_read, NULL); So far so good I'd hope.
>
> Ick, no.
>
>> Of course now I'll have to change the function's parameters from
>>
>> static ssize_t sid_read(struct file *fd, struct kobject *kobj,
>> 			struct bin_attribute *attr, char *buf,
>> 			loff_t pos, size_t size)
>>
>> to
>>
>> static ssize_t sid_read(struct device *dev,
>> 			struct device_attribute *attr, char *buf)
>
> Which is what do you do not want, as you find out:
>
>> But now, I'm missing things like 'pos' and 'size', both which
>> determine the requested bytes. True, in this specific driver we are
>> talking about 'only' 16 bytes, but what if it weren't but a few MiB
>> and in sysfs we want to read some random byte, will we have to put
>> the entire blok into the buffer?
>>
>> So sorry for not understanding, but ... I don't understand :)
>
> Stick with a binary attribute, and attach that to the proper class
> structure and all should be fine.
>
> Ah crap, you're using a platform device.
>
> {sigh}
>
> Why?  Why not use a "real" device which has a "real" class, and then use
> the interfaces there?
Because, as I was told, this really is a platform device. If you have 
some example code I can look at and learn from that would be awesome. 
I'm still learning after all, and apparently I'm doing it wrong now :)
>
> greg k-h
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24 21:46                 ` Greg KH
@ 2013-06-26  9:10                   ` Russell King - ARM Linux
  -1 siblings, 0 replies; 142+ messages in thread
From: Russell King - ARM Linux @ 2013-06-26  9:10 UTC (permalink / raw)
  To: Greg KH
  Cc: Oliver Schinagl, Maxime Ripard, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Mon, Jun 24, 2013 at 02:46:15PM -0700, Greg KH wrote:
> Stick with a binary attribute, and attach that to the proper class
> structure and all should be fine.
> 
> Ah crap, you're using a platform device.
> 
> {sigh}
> 
> Why?  Why not use a "real" device which has a "real" class, and then use
> the interfaces there?

And why aren't platform devices "real" devices?  If platform devices are
second class devices then that's pretty crap because virtually all
devices on ARM are platform devices, not something like "first class"
PCI devices.

We could make them PCI devices if you want us to totally fsck with the
PCI code to bend it in ways it was never meant to, but I suspect that'll
upset the PCI guys.

No, platform devices must be first class devices just like any other.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-26  9:10                   ` Russell King - ARM Linux
  0 siblings, 0 replies; 142+ messages in thread
From: Russell King - ARM Linux @ 2013-06-26  9:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 24, 2013 at 02:46:15PM -0700, Greg KH wrote:
> Stick with a binary attribute, and attach that to the proper class
> structure and all should be fine.
> 
> Ah crap, you're using a platform device.
> 
> {sigh}
> 
> Why?  Why not use a "real" device which has a "real" class, and then use
> the interfaces there?

And why aren't platform devices "real" devices?  If platform devices are
second class devices then that's pretty crap because virtually all
devices on ARM are platform devices, not something like "first class"
PCI devices.

We could make them PCI devices if you want us to totally fsck with the
PCI code to bend it in ways it was never meant to, but I suspect that'll
upset the PCI guys.

No, platform devices must be first class devices just like any other.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-24 16:04         ` Greg KH
  (?)
@ 2013-06-26  9:22           ` Geert Uytterhoeven
  -1 siblings, 0 replies; 142+ messages in thread
From: Geert Uytterhoeven @ 2013-06-26  9:22 UTC (permalink / raw)
  To: Greg KH
  Cc: Maxime Ripard, Oliver Schinagl, Arnd Bergmann, linux-kernel,
	linux-arm-kernel, andy.shevchenko, Russell King, Linus Walleij,
	linux-sunxi, Oliver Schinagl, rtc-linux, kernel-janitors

On Mon, Jun 24, 2013 at 6:04 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>> > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>> > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> > > +{
>> > > + u8 entropy[SID_SIZE];
>> > > + unsigned int i;
>> > > + struct resource *res;
>> > > + void __iomem *sid_reg_base;
>> > > + int ret;
>> > > +
>> > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> > > + sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>> > > + if (IS_ERR(sid_reg_base))
>> > > +         return PTR_ERR(sid_reg_base);
>> > > + platform_set_drvdata(pdev, sid_reg_base);
>> > > +
>> > > + ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>> > > + if (ret)
>> > > +         return ret;
>> >
>> > You just raced with userspace, having the file show up after the device
>> > was announced to users that it was there.  Please use the proper device
>> > file api to add default attributes to prevent this from happening.
>>
>> Sorry if the question looks dumb, but what kind of race can we generate
>> here?
>
> Userspace gets told about the device from the driver core, udev runs and
> reads all of the attributes, then your probe function comes along and
> adds a new attribute.  Userspace will then not know about it at all.
>
>> The device_create_bin_file is the last call that we make (if we except
>> the entropy stuff, but it doesn't really matter here), so after we
>> created the file, we have everything properly initialised so that our
>> functions can be called, right?
>>
>> And another dumb question for you, what is the "proper device file API"
>> you are referring to ? :)
>
> Please read Documentation/driver_model/device.txt and see the section on
> Attributes for what to do.  If you have specific questions after reading
> that, please let me know.

Woops, then we have plenty of existing drivers to fix, e.g. all/most RTC drivers
exposing an NVRAM file through sysfs:

$ git grep -w sysfs_create_bin_file drivers/rtc/
drivers/rtc/rtc-cmos.c: retval = sysfs_create_bin_file(&dev->kobj, &nvram);
drivers/rtc/rtc-ds1305.c: status =
sysfs_create_bin_file(&spi->dev.kobj, &nvram);
drivers/rtc/rtc-ds1307.c: err =
sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
drivers/rtc/rtc-ds1511.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&ds1511_nvram_attr);
drivers/rtc/rtc-ds1553.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&ds1553_nvram_attr);
drivers/rtc/rtc-ds1742.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&pdata->nvram_attr);
drivers/rtc/rtc-m48t59.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&m48t59_nvram_attr);
drivers/rtc/rtc-rp5c01.c: error =
sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
drivers/rtc/rtc-stk17ta8.c: ret =
sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
drivers/rtc/rtc-tx4939.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&tx4939_rtc_nvram_attr);

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-26  9:22           ` Geert Uytterhoeven
  0 siblings, 0 replies; 142+ messages in thread
From: Geert Uytterhoeven @ 2013-06-26  9:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 24, 2013 at 6:04 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>> > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>> > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> > > +{
>> > > + u8 entropy[SID_SIZE];
>> > > + unsigned int i;
>> > > + struct resource *res;
>> > > + void __iomem *sid_reg_base;
>> > > + int ret;
>> > > +
>> > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> > > + sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>> > > + if (IS_ERR(sid_reg_base))
>> > > +         return PTR_ERR(sid_reg_base);
>> > > + platform_set_drvdata(pdev, sid_reg_base);
>> > > +
>> > > + ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>> > > + if (ret)
>> > > +         return ret;
>> >
>> > You just raced with userspace, having the file show up after the device
>> > was announced to users that it was there.  Please use the proper device
>> > file api to add default attributes to prevent this from happening.
>>
>> Sorry if the question looks dumb, but what kind of race can we generate
>> here?
>
> Userspace gets told about the device from the driver core, udev runs and
> reads all of the attributes, then your probe function comes along and
> adds a new attribute.  Userspace will then not know about it at all.
>
>> The device_create_bin_file is the last call that we make (if we except
>> the entropy stuff, but it doesn't really matter here), so after we
>> created the file, we have everything properly initialised so that our
>> functions can be called, right?
>>
>> And another dumb question for you, what is the "proper device file API"
>> you are referring to ? :)
>
> Please read Documentation/driver_model/device.txt and see the section on
> Attributes for what to do.  If you have specific questions after reading
> that, please let me know.

Woops, then we have plenty of existing drivers to fix, e.g. all/most RTC drivers
exposing an NVRAM file through sysfs:

$ git grep -w sysfs_create_bin_file drivers/rtc/
drivers/rtc/rtc-cmos.c: retval = sysfs_create_bin_file(&dev->kobj, &nvram);
drivers/rtc/rtc-ds1305.c: status sysfs_create_bin_file(&spi->dev.kobj, &nvram);
drivers/rtc/rtc-ds1307.c: err sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
drivers/rtc/rtc-ds1511.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&ds1511_nvram_attr);
drivers/rtc/rtc-ds1553.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&ds1553_nvram_attr);
drivers/rtc/rtc-ds1742.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&pdata->nvram_attr);
drivers/rtc/rtc-m48t59.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&m48t59_nvram_attr);
drivers/rtc/rtc-rp5c01.c: error sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
drivers/rtc/rtc-stk17ta8.c: ret sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
drivers/rtc/rtc-tx4939.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&tx4939_rtc_nvram_attr);

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-26  9:22           ` Geert Uytterhoeven
  0 siblings, 0 replies; 142+ messages in thread
From: Geert Uytterhoeven @ 2013-06-26  9:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 24, 2013 at 6:04 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>> > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>> > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> > > +{
>> > > + u8 entropy[SID_SIZE];
>> > > + unsigned int i;
>> > > + struct resource *res;
>> > > + void __iomem *sid_reg_base;
>> > > + int ret;
>> > > +
>> > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> > > + sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>> > > + if (IS_ERR(sid_reg_base))
>> > > +         return PTR_ERR(sid_reg_base);
>> > > + platform_set_drvdata(pdev, sid_reg_base);
>> > > +
>> > > + ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>> > > + if (ret)
>> > > +         return ret;
>> >
>> > You just raced with userspace, having the file show up after the device
>> > was announced to users that it was there.  Please use the proper device
>> > file api to add default attributes to prevent this from happening.
>>
>> Sorry if the question looks dumb, but what kind of race can we generate
>> here?
>
> Userspace gets told about the device from the driver core, udev runs and
> reads all of the attributes, then your probe function comes along and
> adds a new attribute.  Userspace will then not know about it at all.
>
>> The device_create_bin_file is the last call that we make (if we except
>> the entropy stuff, but it doesn't really matter here), so after we
>> created the file, we have everything properly initialised so that our
>> functions can be called, right?
>>
>> And another dumb question for you, what is the "proper device file API"
>> you are referring to ? :)
>
> Please read Documentation/driver_model/device.txt and see the section on
> Attributes for what to do.  If you have specific questions after reading
> that, please let me know.

Woops, then we have plenty of existing drivers to fix, e.g. all/most RTC drivers
exposing an NVRAM file through sysfs:

$ git grep -w sysfs_create_bin_file drivers/rtc/
drivers/rtc/rtc-cmos.c: retval = sysfs_create_bin_file(&dev->kobj, &nvram);
drivers/rtc/rtc-ds1305.c: status =
sysfs_create_bin_file(&spi->dev.kobj, &nvram);
drivers/rtc/rtc-ds1307.c: err =
sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
drivers/rtc/rtc-ds1511.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&ds1511_nvram_attr);
drivers/rtc/rtc-ds1553.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&ds1553_nvram_attr);
drivers/rtc/rtc-ds1742.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&pdata->nvram_attr);
drivers/rtc/rtc-m48t59.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&m48t59_nvram_attr);
drivers/rtc/rtc-rp5c01.c: error =
sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
drivers/rtc/rtc-stk17ta8.c: ret =
sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
drivers/rtc/rtc-tx4939.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
&tx4939_rtc_nvram_attr);

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-26  9:22           ` Geert Uytterhoeven
  (?)
@ 2013-06-26 17:49             ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-26 17:49 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Maxime Ripard, Oliver Schinagl, Arnd Bergmann, linux-kernel,
	linux-arm-kernel, andy.shevchenko, Russell King, Linus Walleij,
	linux-sunxi, Oliver Schinagl, rtc-linux, kernel-janitors

On Wed, Jun 26, 2013 at 11:22:30AM +0200, Geert Uytterhoeven wrote:
> On Mon, Jun 24, 2013 at 6:04 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> > On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >> > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >> > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> >> > > +{
> >> > > + u8 entropy[SID_SIZE];
> >> > > + unsigned int i;
> >> > > + struct resource *res;
> >> > > + void __iomem *sid_reg_base;
> >> > > + int ret;
> >> > > +
> >> > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> > > + sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >> > > + if (IS_ERR(sid_reg_base))
> >> > > +         return PTR_ERR(sid_reg_base);
> >> > > + platform_set_drvdata(pdev, sid_reg_base);
> >> > > +
> >> > > + ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >> > > + if (ret)
> >> > > +         return ret;
> >> >
> >> > You just raced with userspace, having the file show up after the device
> >> > was announced to users that it was there.  Please use the proper device
> >> > file api to add default attributes to prevent this from happening.
> >>
> >> Sorry if the question looks dumb, but what kind of race can we generate
> >> here?
> >
> > Userspace gets told about the device from the driver core, udev runs and
> > reads all of the attributes, then your probe function comes along and
> > adds a new attribute.  Userspace will then not know about it at all.
> >
> >> The device_create_bin_file is the last call that we make (if we except
> >> the entropy stuff, but it doesn't really matter here), so after we
> >> created the file, we have everything properly initialised so that our
> >> functions can be called, right?
> >>
> >> And another dumb question for you, what is the "proper device file API"
> >> you are referring to ? :)
> >
> > Please read Documentation/driver_model/device.txt and see the section on
> > Attributes for what to do.  If you have specific questions after reading
> > that, please let me know.
> 
> Woops, then we have plenty of existing drivers to fix, e.g. all/most RTC drivers
> exposing an NVRAM file through sysfs:
> 
> $ git grep -w sysfs_create_bin_file drivers/rtc/
> drivers/rtc/rtc-cmos.c: retval = sysfs_create_bin_file(&dev->kobj, &nvram);
> drivers/rtc/rtc-ds1305.c: status =
> sysfs_create_bin_file(&spi->dev.kobj, &nvram);
> drivers/rtc/rtc-ds1307.c: err =
> sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
> drivers/rtc/rtc-ds1511.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &ds1511_nvram_attr);
> drivers/rtc/rtc-ds1553.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &ds1553_nvram_attr);
> drivers/rtc/rtc-ds1742.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &pdata->nvram_attr);
> drivers/rtc/rtc-m48t59.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &m48t59_nvram_attr);
> drivers/rtc/rtc-rp5c01.c: error =
> sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
> drivers/rtc/rtc-stk17ta8.c: ret =
> sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
> drivers/rtc/rtc-tx4939.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &tx4939_rtc_nvram_attr);

Yes, they should all be fixed, along with any platform device that
creates a sysfs file in the probe function.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-26 17:49             ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-26 17:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 26, 2013 at 11:22:30AM +0200, Geert Uytterhoeven wrote:
> On Mon, Jun 24, 2013 at 6:04 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> > On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >> > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >> > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> >> > > +{
> >> > > + u8 entropy[SID_SIZE];
> >> > > + unsigned int i;
> >> > > + struct resource *res;
> >> > > + void __iomem *sid_reg_base;
> >> > > + int ret;
> >> > > +
> >> > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> > > + sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >> > > + if (IS_ERR(sid_reg_base))
> >> > > +         return PTR_ERR(sid_reg_base);
> >> > > + platform_set_drvdata(pdev, sid_reg_base);
> >> > > +
> >> > > + ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >> > > + if (ret)
> >> > > +         return ret;
> >> >
> >> > You just raced with userspace, having the file show up after the device
> >> > was announced to users that it was there.  Please use the proper device
> >> > file api to add default attributes to prevent this from happening.
> >>
> >> Sorry if the question looks dumb, but what kind of race can we generate
> >> here?
> >
> > Userspace gets told about the device from the driver core, udev runs and
> > reads all of the attributes, then your probe function comes along and
> > adds a new attribute.  Userspace will then not know about it at all.
> >
> >> The device_create_bin_file is the last call that we make (if we except
> >> the entropy stuff, but it doesn't really matter here), so after we
> >> created the file, we have everything properly initialised so that our
> >> functions can be called, right?
> >>
> >> And another dumb question for you, what is the "proper device file API"
> >> you are referring to ? :)
> >
> > Please read Documentation/driver_model/device.txt and see the section on
> > Attributes for what to do.  If you have specific questions after reading
> > that, please let me know.
> 
> Woops, then we have plenty of existing drivers to fix, e.g. all/most RTC drivers
> exposing an NVRAM file through sysfs:
> 
> $ git grep -w sysfs_create_bin_file drivers/rtc/
> drivers/rtc/rtc-cmos.c: retval = sysfs_create_bin_file(&dev->kobj, &nvram);
> drivers/rtc/rtc-ds1305.c: status > sysfs_create_bin_file(&spi->dev.kobj, &nvram);
> drivers/rtc/rtc-ds1307.c: err > sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
> drivers/rtc/rtc-ds1511.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &ds1511_nvram_attr);
> drivers/rtc/rtc-ds1553.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &ds1553_nvram_attr);
> drivers/rtc/rtc-ds1742.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &pdata->nvram_attr);
> drivers/rtc/rtc-m48t59.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &m48t59_nvram_attr);
> drivers/rtc/rtc-rp5c01.c: error > sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
> drivers/rtc/rtc-stk17ta8.c: ret > sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
> drivers/rtc/rtc-tx4939.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &tx4939_rtc_nvram_attr);

Yes, they should all be fixed, along with any platform device that
creates a sysfs file in the probe function.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-26 17:49             ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-26 17:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 26, 2013 at 11:22:30AM +0200, Geert Uytterhoeven wrote:
> On Mon, Jun 24, 2013 at 6:04 PM, Greg KH <gregkh@linuxfoundation.org> wrote:
> > On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >> > On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >> > > +static int __init sunxi_sid_probe(struct platform_device *pdev)
> >> > > +{
> >> > > + u8 entropy[SID_SIZE];
> >> > > + unsigned int i;
> >> > > + struct resource *res;
> >> > > + void __iomem *sid_reg_base;
> >> > > + int ret;
> >> > > +
> >> > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> > > + sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >> > > + if (IS_ERR(sid_reg_base))
> >> > > +         return PTR_ERR(sid_reg_base);
> >> > > + platform_set_drvdata(pdev, sid_reg_base);
> >> > > +
> >> > > + ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >> > > + if (ret)
> >> > > +         return ret;
> >> >
> >> > You just raced with userspace, having the file show up after the device
> >> > was announced to users that it was there.  Please use the proper device
> >> > file api to add default attributes to prevent this from happening.
> >>
> >> Sorry if the question looks dumb, but what kind of race can we generate
> >> here?
> >
> > Userspace gets told about the device from the driver core, udev runs and
> > reads all of the attributes, then your probe function comes along and
> > adds a new attribute.  Userspace will then not know about it at all.
> >
> >> The device_create_bin_file is the last call that we make (if we except
> >> the entropy stuff, but it doesn't really matter here), so after we
> >> created the file, we have everything properly initialised so that our
> >> functions can be called, right?
> >>
> >> And another dumb question for you, what is the "proper device file API"
> >> you are referring to ? :)
> >
> > Please read Documentation/driver_model/device.txt and see the section on
> > Attributes for what to do.  If you have specific questions after reading
> > that, please let me know.
> 
> Woops, then we have plenty of existing drivers to fix, e.g. all/most RTC drivers
> exposing an NVRAM file through sysfs:
> 
> $ git grep -w sysfs_create_bin_file drivers/rtc/
> drivers/rtc/rtc-cmos.c: retval = sysfs_create_bin_file(&dev->kobj, &nvram);
> drivers/rtc/rtc-ds1305.c: status =
> sysfs_create_bin_file(&spi->dev.kobj, &nvram);
> drivers/rtc/rtc-ds1307.c: err =
> sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
> drivers/rtc/rtc-ds1511.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &ds1511_nvram_attr);
> drivers/rtc/rtc-ds1553.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &ds1553_nvram_attr);
> drivers/rtc/rtc-ds1742.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &pdata->nvram_attr);
> drivers/rtc/rtc-m48t59.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &m48t59_nvram_attr);
> drivers/rtc/rtc-rp5c01.c: error =
> sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
> drivers/rtc/rtc-stk17ta8.c: ret =
> sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
> drivers/rtc/rtc-tx4939.c: ret = sysfs_create_bin_file(&pdev->dev.kobj,
> &tx4939_rtc_nvram_attr);

Yes, they should all be fixed, along with any platform device that
creates a sysfs file in the probe function.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-26  9:10                   ` Russell King - ARM Linux
@ 2013-06-26 17:51                     ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-26 17:51 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Oliver Schinagl, Maxime Ripard, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Wed, Jun 26, 2013 at 10:10:33AM +0100, Russell King - ARM Linux wrote:
> On Mon, Jun 24, 2013 at 02:46:15PM -0700, Greg KH wrote:
> > Stick with a binary attribute, and attach that to the proper class
> > structure and all should be fine.
> > 
> > Ah crap, you're using a platform device.
> > 
> > {sigh}
> > 
> > Why?  Why not use a "real" device which has a "real" class, and then use
> > the interfaces there?
> 
> And why aren't platform devices "real" devices?  If platform devices are
> second class devices then that's pretty crap because virtually all
> devices on ARM are platform devices, not something like "first class"
> PCI devices.

Ok, they are "real" devices, I'm just tired of seeing people throw
everything and the kitchen sink into them, don't you agree?

> We could make them PCI devices if you want us to totally fsck with the
> PCI code to bend it in ways it was never meant to, but I suspect that'll
> upset the PCI guys.
> 
> No, platform devices must be first class devices just like any other.

I was wrong, they can, and do, support default attribute groups, it's
just that it seems no one uses them (or if they did, my greping can't
find them...)

So they are "first class" devices, my mistake.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-26 17:51                     ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-26 17:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 26, 2013 at 10:10:33AM +0100, Russell King - ARM Linux wrote:
> On Mon, Jun 24, 2013 at 02:46:15PM -0700, Greg KH wrote:
> > Stick with a binary attribute, and attach that to the proper class
> > structure and all should be fine.
> > 
> > Ah crap, you're using a platform device.
> > 
> > {sigh}
> > 
> > Why?  Why not use a "real" device which has a "real" class, and then use
> > the interfaces there?
> 
> And why aren't platform devices "real" devices?  If platform devices are
> second class devices then that's pretty crap because virtually all
> devices on ARM are platform devices, not something like "first class"
> PCI devices.

Ok, they are "real" devices, I'm just tired of seeing people throw
everything and the kitchen sink into them, don't you agree?

> We could make them PCI devices if you want us to totally fsck with the
> PCI code to bend it in ways it was never meant to, but I suspect that'll
> upset the PCI guys.
> 
> No, platform devices must be first class devices just like any other.

I was wrong, they can, and do, support default attribute groups, it's
just that it seems no one uses them (or if they did, my greping can't
find them...)

So they are "first class" devices, my mistake.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-26  8:32                   ` Oliver Schinagl
@ 2013-06-26 17:51                     ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-26 17:51 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Wed, Jun 26, 2013 at 10:32:09AM +0200, Oliver Schinagl wrote:
> On 24-06-13 23:46, Greg KH wrote:
> >On Mon, Jun 24, 2013 at 11:21:16PM +0200, Oliver Schinagl wrote:
> >>On 06/24/13 20:15, Greg KH wrote:
> >>>On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
> >>>>Hey Greg,
> >>>>On 06/24/13 18:04, Greg KH wrote:
> >>>>>On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >>>>>>Hi Greg,
> >>>>>>
> >>>>>>On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >>>>>>>On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >>>>>>
> >>>>>>[..]
> >>>>>>
> >>>>>>>>+static int __init sunxi_sid_probe(struct platform_device *pdev)
> >>>>>>>>+{
> >>>>>>>>+	u8 entropy[SID_SIZE];
> >>>>>>>>+	unsigned int i;
> >>>>>>>>+	struct resource *res;
> >>>>>>>>+	void __iomem *sid_reg_base;
> >>>>>>>>+	int ret;
> >>>>>>>>+
> >>>>>>>>+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>>>>>>>+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >>>>>>>>+	if (IS_ERR(sid_reg_base))
> >>>>>>>>+		return PTR_ERR(sid_reg_base);
> >>>>>>>>+	platform_set_drvdata(pdev, sid_reg_base);
> >>>>>>>>+
> >>>>>>>>+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >>>>>>>>+	if (ret)
> >>>>>>>>+		return ret;
> >>>>>>>
> >>>>>>>You just raced with userspace, having the file show up after the device
> >>>>>>>was announced to users that it was there.  Please use the proper device
> >>>>>>>file api to add default attributes to prevent this from happening.
> >>>>>>
> >>>>>>Sorry if the question looks dumb, but what kind of race can we generate
> >>>>>>here?
> >>>>>
> >>>>>Userspace gets told about the device from the driver core, udev runs and
> >>>>>reads all of the attributes, then your probe function comes along and
> >>>>>adds a new attribute.  Userspace will then not know about it at all.
> >>>>>
> >>>>>>The device_create_bin_file is the last call that we make (if we except
> >>>>>>the entropy stuff, but it doesn't really matter here), so after we
> >>>>>>created the file, we have everything properly initialised so that our
> >>>>>>functions can be called, right?
> >>>>>>
> >>>>>>And another dumb question for you, what is the "proper device file API"
> >>>>>>you are referring to ? :)
> >>>>>
> >>>>>Please read Documentation/driver_model/device.txt and see the section on
> >>>>>Attributes for what to do.  If you have specific questions after reading
> >>>>>that, please let me know.
> >>>>Since Maxime kinda asked for me, I hope you don't mind me following up.
> >>>>
> >>>>That doc doesn't mention the binary interface at all. Initially I
> >>>>had both devices up, the 'read' device as a textual representation
> >>>>and added the binary one later. Maxime and I decided the binary one
> >>>>made more sense, as the only textual user would be a human and they
> >>>>don't poke that entry that often.
> >>>>
> >>>>So what default way exists for binary files or how would that be solved?
> >>>
> >>>The same interface should work just fine for binary files, have you
> >>>tried it?
> >>I'll just take the plunge and make myself look stupid ;)
> >>
> >>I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO,
> >>sid_read, NULL); So far so good I'd hope.
> >
> >Ick, no.
> >
> >>Of course now I'll have to change the function's parameters from
> >>
> >>static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> >>			struct bin_attribute *attr, char *buf,
> >>			loff_t pos, size_t size)
> >>
> >>to
> >>
> >>static ssize_t sid_read(struct device *dev,
> >>			struct device_attribute *attr, char *buf)
> >
> >Which is what do you do not want, as you find out:
> >
> >>But now, I'm missing things like 'pos' and 'size', both which
> >>determine the requested bytes. True, in this specific driver we are
> >>talking about 'only' 16 bytes, but what if it weren't but a few MiB
> >>and in sysfs we want to read some random byte, will we have to put
> >>the entire blok into the buffer?
> >>
> >>So sorry for not understanding, but ... I don't understand :)
> >
> >Stick with a binary attribute, and attach that to the proper class
> >structure and all should be fine.
> >
> >Ah crap, you're using a platform device.
> >
> >{sigh}
> >
> >Why?  Why not use a "real" device which has a "real" class, and then use
> >the interfaces there?
> Because, as I was told, this really is a platform device. If you
> have some example code I can look at and learn from that would be
> awesome. I'm still learning after all, and apparently I'm doing it
> wrong now :)

I was wrong, you can do this with a platform device just fine.  Set the
"groups" field in your platform device->device structure, and all will
work properly, right?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-26 17:51                     ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-06-26 17:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 26, 2013 at 10:32:09AM +0200, Oliver Schinagl wrote:
> On 24-06-13 23:46, Greg KH wrote:
> >On Mon, Jun 24, 2013 at 11:21:16PM +0200, Oliver Schinagl wrote:
> >>On 06/24/13 20:15, Greg KH wrote:
> >>>On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
> >>>>Hey Greg,
> >>>>On 06/24/13 18:04, Greg KH wrote:
> >>>>>On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
> >>>>>>Hi Greg,
> >>>>>>
> >>>>>>On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
> >>>>>>>On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
> >>>>>>
> >>>>>>[..]
> >>>>>>
> >>>>>>>>+static int __init sunxi_sid_probe(struct platform_device *pdev)
> >>>>>>>>+{
> >>>>>>>>+	u8 entropy[SID_SIZE];
> >>>>>>>>+	unsigned int i;
> >>>>>>>>+	struct resource *res;
> >>>>>>>>+	void __iomem *sid_reg_base;
> >>>>>>>>+	int ret;
> >>>>>>>>+
> >>>>>>>>+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>>>>>>>+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >>>>>>>>+	if (IS_ERR(sid_reg_base))
> >>>>>>>>+		return PTR_ERR(sid_reg_base);
> >>>>>>>>+	platform_set_drvdata(pdev, sid_reg_base);
> >>>>>>>>+
> >>>>>>>>+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >>>>>>>>+	if (ret)
> >>>>>>>>+		return ret;
> >>>>>>>
> >>>>>>>You just raced with userspace, having the file show up after the device
> >>>>>>>was announced to users that it was there.  Please use the proper device
> >>>>>>>file api to add default attributes to prevent this from happening.
> >>>>>>
> >>>>>>Sorry if the question looks dumb, but what kind of race can we generate
> >>>>>>here?
> >>>>>
> >>>>>Userspace gets told about the device from the driver core, udev runs and
> >>>>>reads all of the attributes, then your probe function comes along and
> >>>>>adds a new attribute.  Userspace will then not know about it at all.
> >>>>>
> >>>>>>The device_create_bin_file is the last call that we make (if we except
> >>>>>>the entropy stuff, but it doesn't really matter here), so after we
> >>>>>>created the file, we have everything properly initialised so that our
> >>>>>>functions can be called, right?
> >>>>>>
> >>>>>>And another dumb question for you, what is the "proper device file API"
> >>>>>>you are referring to ? :)
> >>>>>
> >>>>>Please read Documentation/driver_model/device.txt and see the section on
> >>>>>Attributes for what to do.  If you have specific questions after reading
> >>>>>that, please let me know.
> >>>>Since Maxime kinda asked for me, I hope you don't mind me following up.
> >>>>
> >>>>That doc doesn't mention the binary interface at all. Initially I
> >>>>had both devices up, the 'read' device as a textual representation
> >>>>and added the binary one later. Maxime and I decided the binary one
> >>>>made more sense, as the only textual user would be a human and they
> >>>>don't poke that entry that often.
> >>>>
> >>>>So what default way exists for binary files or how would that be solved?
> >>>
> >>>The same interface should work just fine for binary files, have you
> >>>tried it?
> >>I'll just take the plunge and make myself look stupid ;)
> >>
> >>I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO,
> >>sid_read, NULL); So far so good I'd hope.
> >
> >Ick, no.
> >
> >>Of course now I'll have to change the function's parameters from
> >>
> >>static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> >>			struct bin_attribute *attr, char *buf,
> >>			loff_t pos, size_t size)
> >>
> >>to
> >>
> >>static ssize_t sid_read(struct device *dev,
> >>			struct device_attribute *attr, char *buf)
> >
> >Which is what do you do not want, as you find out:
> >
> >>But now, I'm missing things like 'pos' and 'size', both which
> >>determine the requested bytes. True, in this specific driver we are
> >>talking about 'only' 16 bytes, but what if it weren't but a few MiB
> >>and in sysfs we want to read some random byte, will we have to put
> >>the entire blok into the buffer?
> >>
> >>So sorry for not understanding, but ... I don't understand :)
> >
> >Stick with a binary attribute, and attach that to the proper class
> >structure and all should be fine.
> >
> >Ah crap, you're using a platform device.
> >
> >{sigh}
> >
> >Why?  Why not use a "real" device which has a "real" class, and then use
> >the interfaces there?
> Because, as I was told, this really is a platform device. If you
> have some example code I can look at and learn from that would be
> awesome. I'm still learning after all, and apparently I'm doing it
> wrong now :)

I was wrong, you can do this with a platform device just fine.  Set the
"groups" field in your platform device->device structure, and all will
work properly, right?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-26 17:51                     ` Greg KH
@ 2013-07-05  7:24                       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-05  7:24 UTC (permalink / raw)
  To: Greg KH
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

Hey Greg,

Thanks for the blog post :) it was very helpful and at least something 
good came from the less-nice bit of the discussion, but:

On 26-06-13 19:51, Greg KH wrote:
> On Wed, Jun 26, 2013 at 10:32:09AM +0200, Oliver Schinagl wrote:
>> On 24-06-13 23:46, Greg KH wrote:
>>> On Mon, Jun 24, 2013 at 11:21:16PM +0200, Oliver Schinagl wrote:
>>>> On 06/24/13 20:15, Greg KH wrote:
>>>>> On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
>>>>>> Hey Greg,
>>>>>> On 06/24/13 18:04, Greg KH wrote:
>>>>>>> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>>>>>>>> Hi Greg,
>>>>>>>>
>>>>>>>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>>>>>>>>> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>>>>>>>>
>>>>>>>> [..]
>>>>>>>>
>>>>>>>>>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>>>>>>>>>> +{
>>>>>>>>>> +	u8 entropy[SID_SIZE];
>>>>>>>>>> +	unsigned int i;
>>>>>>>>>> +	struct resource *res;
>>>>>>>>>> +	void __iomem *sid_reg_base;
>>>>>>>>>> +	int ret;
>>>>>>>>>> +
>>>>>>>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>>>>>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>>>>>>>>>> +	if (IS_ERR(sid_reg_base))
>>>>>>>>>> +		return PTR_ERR(sid_reg_base);
>>>>>>>>>> +	platform_set_drvdata(pdev, sid_reg_base);
>>>>>>>>>> +
>>>>>>>>>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>>>>>>>>>> +	if (ret)
>>>>>>>>>> +		return ret;
>>>>>>>>>
>>>>>>>>> You just raced with userspace, having the file show up after the device
>>>>>>>>> was announced to users that it was there.  Please use the proper device
>>>>>>>>> file api to add default attributes to prevent this from happening.
>>>>>>>>
>>>>>>>> Sorry if the question looks dumb, but what kind of race can we generate
>>>>>>>> here?
>>>>>>>
>>>>>>> Userspace gets told about the device from the driver core, udev runs and
>>>>>>> reads all of the attributes, then your probe function comes along and
>>>>>>> adds a new attribute.  Userspace will then not know about it at all.
>>>>>>>
>>>>>>>> The device_create_bin_file is the last call that we make (if we except
>>>>>>>> the entropy stuff, but it doesn't really matter here), so after we
>>>>>>>> created the file, we have everything properly initialised so that our
>>>>>>>> functions can be called, right?
>>>>>>>>
>>>>>>>> And another dumb question for you, what is the "proper device file API"
>>>>>>>> you are referring to ? :)
>>>>>>>
>>>>>>> Please read Documentation/driver_model/device.txt and see the section on
>>>>>>> Attributes for what to do.  If you have specific questions after reading
>>>>>>> that, please let me know.
>>>>>> Since Maxime kinda asked for me, I hope you don't mind me following up.
>>>>>>
>>>>>> That doc doesn't mention the binary interface at all. Initially I
>>>>>> had both devices up, the 'read' device as a textual representation
>>>>>> and added the binary one later. Maxime and I decided the binary one
>>>>>> made more sense, as the only textual user would be a human and they
>>>>>> don't poke that entry that often.
>>>>>>
>>>>>> So what default way exists for binary files or how would that be solved?
>>>>>
>>>>> The same interface should work just fine for binary files, have you
>>>>> tried it?
>>>> I'll just take the plunge and make myself look stupid ;)
>>>>
>>>> I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO,
>>>> sid_read, NULL); So far so good I'd hope.
>>>
>>> Ick, no.
>>>
>>>> Of course now I'll have to change the function's parameters from
>>>>
>>>> static ssize_t sid_read(struct file *fd, struct kobject *kobj,
>>>> 			struct bin_attribute *attr, char *buf,
>>>> 			loff_t pos, size_t size)
>>>>
>>>> to
>>>>
>>>> static ssize_t sid_read(struct device *dev,
>>>> 			struct device_attribute *attr, char *buf)
>>>
>>> Which is what do you do not want, as you find out:
>>>
>>>> But now, I'm missing things like 'pos' and 'size', both which
>>>> determine the requested bytes. True, in this specific driver we are
>>>> talking about 'only' 16 bytes, but what if it weren't but a few MiB
>>>> and in sysfs we want to read some random byte, will we have to put
>>>> the entire blok into the buffer?
>>>>
>>>> So sorry for not understanding, but ... I don't understand :)
>>>
>>> Stick with a binary attribute, and attach that to the proper class
>>> structure and all should be fine.
>>>
>>> Ah crap, you're using a platform device.
>>>
>>> {sigh}
>>>
>>> Why?  Why not use a "real" device which has a "real" class, and then use
>>> the interfaces there?
>> Because, as I was told, this really is a platform device. If you
>> have some example code I can look at and learn from that would be
>> awesome. I'm still learning after all, and apparently I'm doing it
>> wrong now :)
>
> I was wrong, you can do this with a platform device just fine.  Set the
> "groups" field in your platform device->device structure, and all will
> work properly, right?
Not for me :(

Firstly, I have a platform_driver structure, but it has a .driver field 
and i can set the .groups field there just fine, as your blog post said 
I believe, so that got me on the right track.

static struct platform_driver sunxi_sid_driver = {
         .probe = sunxi_sid_probe,
         .remove = sunxi_sid_remove,
         .driver = {
                 .name = DRV_NAME,
                 .owner = THIS_MODULE,
                 .of_match_table = sunxi_sid_of_match,
                 .groups = sunxi_sid_attr_groups,
         },
};
module_platform_driver(sunxi_sid_driver);


After jumping through a few hoops, creating an array of 
attribute_groups, filling that with an array of attribute I finally can 
assign an attribute to .attr, but I have a bin_attribute.

static struct attribute *sunxi_sid_attrs[] = {
         &sid_bin_attr.attr,
         NULL,
};

static const struct attribute_group sunxi_sid_attr_group = {
         .attrs = sunxi_sid_attrs,
};

static const struct attribute_group *sunxi_sid_attr_groups[] = {
         &sunxi_sid_attr_group,
         NULL,
};

A feeble attempt to use the .attr from the bin_attribute makes it all 
crash naturally.

Being reminded of LDD3, chapter 14, section 2, re-reading sub-section 3) 
Binary Attributes

We clearly read:
"Binary attributes must be created explicitly; they cannot be set up as 
default attributes. To create a binary attribute, call:

int sysfs_create_bin_file();

Which brings us right back to where we started.

So I clearly am missing something ;)

The other 'broken' drivers that where linked earlier, also use the 
BINARY attributes.

So Greg, if you could be so kind and give me an example how to implement 
this properly, I am at loss and don't know :(

Oliver
>
> thanks,
>
> greg k-h
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-05  7:24                       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-05  7:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hey Greg,

Thanks for the blog post :) it was very helpful and at least something 
good came from the less-nice bit of the discussion, but:

On 26-06-13 19:51, Greg KH wrote:
> On Wed, Jun 26, 2013 at 10:32:09AM +0200, Oliver Schinagl wrote:
>> On 24-06-13 23:46, Greg KH wrote:
>>> On Mon, Jun 24, 2013 at 11:21:16PM +0200, Oliver Schinagl wrote:
>>>> On 06/24/13 20:15, Greg KH wrote:
>>>>> On Mon, Jun 24, 2013 at 07:11:35PM +0200, Oliver Schinagl wrote:
>>>>>> Hey Greg,
>>>>>> On 06/24/13 18:04, Greg KH wrote:
>>>>>>> On Mon, Jun 24, 2013 at 11:29:42AM +0200, Maxime Ripard wrote:
>>>>>>>> Hi Greg,
>>>>>>>>
>>>>>>>> On Mon, Jun 17, 2013 at 03:58:47PM -0700, Greg KH wrote:
>>>>>>>>> On Mon, Jun 17, 2013 at 10:59:37PM +0200, Oliver Schinagl wrote:
>>>>>>>>
>>>>>>>> [..]
>>>>>>>>
>>>>>>>>>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>>>>>>>>>> +{
>>>>>>>>>> +	u8 entropy[SID_SIZE];
>>>>>>>>>> +	unsigned int i;
>>>>>>>>>> +	struct resource *res;
>>>>>>>>>> +	void __iomem *sid_reg_base;
>>>>>>>>>> +	int ret;
>>>>>>>>>> +
>>>>>>>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>>>>>>>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>>>>>>>>>> +	if (IS_ERR(sid_reg_base))
>>>>>>>>>> +		return PTR_ERR(sid_reg_base);
>>>>>>>>>> +	platform_set_drvdata(pdev, sid_reg_base);
>>>>>>>>>> +
>>>>>>>>>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>>>>>>>>>> +	if (ret)
>>>>>>>>>> +		return ret;
>>>>>>>>>
>>>>>>>>> You just raced with userspace, having the file show up after the device
>>>>>>>>> was announced to users that it was there.  Please use the proper device
>>>>>>>>> file api to add default attributes to prevent this from happening.
>>>>>>>>
>>>>>>>> Sorry if the question looks dumb, but what kind of race can we generate
>>>>>>>> here?
>>>>>>>
>>>>>>> Userspace gets told about the device from the driver core, udev runs and
>>>>>>> reads all of the attributes, then your probe function comes along and
>>>>>>> adds a new attribute.  Userspace will then not know about it at all.
>>>>>>>
>>>>>>>> The device_create_bin_file is the last call that we make (if we except
>>>>>>>> the entropy stuff, but it doesn't really matter here), so after we
>>>>>>>> created the file, we have everything properly initialised so that our
>>>>>>>> functions can be called, right?
>>>>>>>>
>>>>>>>> And another dumb question for you, what is the "proper device file API"
>>>>>>>> you are referring to ? :)
>>>>>>>
>>>>>>> Please read Documentation/driver_model/device.txt and see the section on
>>>>>>> Attributes for what to do.  If you have specific questions after reading
>>>>>>> that, please let me know.
>>>>>> Since Maxime kinda asked for me, I hope you don't mind me following up.
>>>>>>
>>>>>> That doc doesn't mention the binary interface at all. Initially I
>>>>>> had both devices up, the 'read' device as a textual representation
>>>>>> and added the binary one later. Maxime and I decided the binary one
>>>>>> made more sense, as the only textual user would be a human and they
>>>>>> don't poke that entry that often.
>>>>>>
>>>>>> So what default way exists for binary files or how would that be solved?
>>>>>
>>>>> The same interface should work just fine for binary files, have you
>>>>> tried it?
>>>> I'll just take the plunge and make myself look stupid ;)
>>>>
>>>> I tried to change things around, used DEVICE_ATTR(eeprom, S_IRUGO,
>>>> sid_read, NULL); So far so good I'd hope.
>>>
>>> Ick, no.
>>>
>>>> Of course now I'll have to change the function's parameters from
>>>>
>>>> static ssize_t sid_read(struct file *fd, struct kobject *kobj,
>>>> 			struct bin_attribute *attr, char *buf,
>>>> 			loff_t pos, size_t size)
>>>>
>>>> to
>>>>
>>>> static ssize_t sid_read(struct device *dev,
>>>> 			struct device_attribute *attr, char *buf)
>>>
>>> Which is what do you do not want, as you find out:
>>>
>>>> But now, I'm missing things like 'pos' and 'size', both which
>>>> determine the requested bytes. True, in this specific driver we are
>>>> talking about 'only' 16 bytes, but what if it weren't but a few MiB
>>>> and in sysfs we want to read some random byte, will we have to put
>>>> the entire blok into the buffer?
>>>>
>>>> So sorry for not understanding, but ... I don't understand :)
>>>
>>> Stick with a binary attribute, and attach that to the proper class
>>> structure and all should be fine.
>>>
>>> Ah crap, you're using a platform device.
>>>
>>> {sigh}
>>>
>>> Why?  Why not use a "real" device which has a "real" class, and then use
>>> the interfaces there?
>> Because, as I was told, this really is a platform device. If you
>> have some example code I can look at and learn from that would be
>> awesome. I'm still learning after all, and apparently I'm doing it
>> wrong now :)
>
> I was wrong, you can do this with a platform device just fine.  Set the
> "groups" field in your platform device->device structure, and all will
> work properly, right?
Not for me :(

Firstly, I have a platform_driver structure, but it has a .driver field 
and i can set the .groups field there just fine, as your blog post said 
I believe, so that got me on the right track.

static struct platform_driver sunxi_sid_driver = {
         .probe = sunxi_sid_probe,
         .remove = sunxi_sid_remove,
         .driver = {
                 .name = DRV_NAME,
                 .owner = THIS_MODULE,
                 .of_match_table = sunxi_sid_of_match,
                 .groups = sunxi_sid_attr_groups,
         },
};
module_platform_driver(sunxi_sid_driver);


After jumping through a few hoops, creating an array of 
attribute_groups, filling that with an array of attribute I finally can 
assign an attribute to .attr, but I have a bin_attribute.

static struct attribute *sunxi_sid_attrs[] = {
         &sid_bin_attr.attr,
         NULL,
};

static const struct attribute_group sunxi_sid_attr_group = {
         .attrs = sunxi_sid_attrs,
};

static const struct attribute_group *sunxi_sid_attr_groups[] = {
         &sunxi_sid_attr_group,
         NULL,
};

A feeble attempt to use the .attr from the bin_attribute makes it all 
crash naturally.

Being reminded of LDD3, chapter 14, section 2, re-reading sub-section 3) 
Binary Attributes

We clearly read:
"Binary attributes must be created explicitly; they cannot be set up as 
default attributes. To create a binary attribute, call:

int sysfs_create_bin_file();

Which brings us right back to where we started.

So I clearly am missing something ;)

The other 'broken' drivers that where linked earlier, also use the 
BINARY attributes.

So Greg, if you could be so kind and give me an example how to implement 
this properly, I am at loss and don't know :(

Oliver
>
> thanks,
>
> greg k-h
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-05  7:24                       ` Oliver Schinagl
@ 2013-07-06 19:36                         ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-06 19:36 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Fri, Jul 05, 2013 at 09:24:47AM +0200, Oliver Schinagl wrote:
> The other 'broken' drivers that where linked earlier, also use the
> BINARY attributes.
> 
> So Greg, if you could be so kind and give me an example how to
> implement this properly, I am at loss and don't know :(

Ah crap, devices don't have a binary attribute group, like struct class
does.  I'll go add that on Monday and send you the patch to see if that
helps you out.  I'll also go through and fix up all of the binary
attribute drivers to keep them from doing that...

Sorry, I missed that earlier, but thanks for trying and pointing out my
mistake.

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-06 19:36                         ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-06 19:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 05, 2013 at 09:24:47AM +0200, Oliver Schinagl wrote:
> The other 'broken' drivers that where linked earlier, also use the
> BINARY attributes.
> 
> So Greg, if you could be so kind and give me an example how to
> implement this properly, I am at loss and don't know :(

Ah crap, devices don't have a binary attribute group, like struct class
does.  I'll go add that on Monday and send you the patch to see if that
helps you out.  I'll also go through and fix up all of the binary
attribute drivers to keep them from doing that...

Sorry, I missed that earlier, but thanks for trying and pointing out my
mistake.

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-06 19:36                         ` Greg KH
@ 2013-07-07  0:17                           ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-07  0:17 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, linux-sunxi,
	Oliver Schinagl

On Sat, Jul 06, 2013 at 12:36:46PM -0700, Greg KH wrote:
> On Fri, Jul 05, 2013 at 09:24:47AM +0200, Oliver Schinagl wrote:
> > The other 'broken' drivers that where linked earlier, also use the
> > BINARY attributes.
> > 
> > So Greg, if you could be so kind and give me an example how to
> > implement this properly, I am at loss and don't know :(
> 
> Ah crap, devices don't have a binary attribute group, like struct class
> does.  I'll go add that on Monday and send you the patch to see if that
> helps you out.  I'll also go through and fix up all of the binary
> attribute drivers to keep them from doing that...
> 
> Sorry, I missed that earlier, but thanks for trying and pointing out my
> mistake.

Can you try this patch out, with your driver, and see if it works for
you?

thanks,

greg k-h

------------------

Subject: driver core: add binary attributes to struct device

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

This lets a device provide a set of default binary attributes, like
normal attributes, that are initialized and torn down by the driver core
at the proper times, so that there are no races with userspace.

Reported-by: : Oliver Schinagl <oliver+list@schinagl.nl>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>


diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2499cef..4040191 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -433,7 +433,7 @@ static void device_remove_attributes(struct device *dev,
 }
 
 static int device_add_bin_attributes(struct device *dev,
-				     struct bin_attribute *attrs)
+				     const struct bin_attribute *attrs)
 {
 	int error = 0;
 	int i;
@@ -452,7 +452,7 @@ static int device_add_bin_attributes(struct device *dev,
 }
 
 static void device_remove_bin_attributes(struct device *dev,
-					 struct bin_attribute *attrs)
+					 const struct bin_attribute *attrs)
 {
 	int i;
 
@@ -516,8 +516,14 @@ static int device_add_attrs(struct device *dev)
 	if (error)
 		goto err_remove_type_groups;
 
+	error = device_add_bin_attributes(dev, dev->bin_attrs);
+	if (error)
+		goto err_remove_groups;
 	return 0;
 
+ err_remove_groups:
+	device_remove_groups(dev, dev->groups);
+
  err_remove_type_groups:
 	if (type)
 		device_remove_groups(dev, type->groups);
@@ -537,6 +543,7 @@ static void device_remove_attrs(struct device *dev)
 	const struct device_type *type = dev->type;
 
 	device_remove_groups(dev, dev->groups);
+	device_remove_bin_attributes(dev, dev->bin_attrs);
 
 	if (type)
 		device_remove_groups(dev, type->groups);
diff --git a/include/linux/device.h b/include/linux/device.h
index c0a1261..6620ad8 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -645,6 +645,7 @@ struct acpi_dev_node {
  * @knode_class: The node used to add the device to the class list.
  * @class:	The class of the device.
  * @groups:	Optional attribute groups.
+ * @bin_attrs:	Optional binary attributes for this device.
  * @release:	Callback to free the device after all references have
  * 		gone away. This should be set by the allocator of the
  * 		device (i.e. the bus driver that discovered the device).
@@ -717,6 +718,7 @@ struct device {
 	struct klist_node	knode_class;
 	struct class		*class;
 	const struct attribute_group **groups;	/* optional groups */
+	const struct bin_attribute *bin_attrs;
 
 	void	(*release)(struct device *dev);
 	struct iommu_group	*iommu_group;

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-07  0:17                           ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-07  0:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jul 06, 2013 at 12:36:46PM -0700, Greg KH wrote:
> On Fri, Jul 05, 2013 at 09:24:47AM +0200, Oliver Schinagl wrote:
> > The other 'broken' drivers that where linked earlier, also use the
> > BINARY attributes.
> > 
> > So Greg, if you could be so kind and give me an example how to
> > implement this properly, I am at loss and don't know :(
> 
> Ah crap, devices don't have a binary attribute group, like struct class
> does.  I'll go add that on Monday and send you the patch to see if that
> helps you out.  I'll also go through and fix up all of the binary
> attribute drivers to keep them from doing that...
> 
> Sorry, I missed that earlier, but thanks for trying and pointing out my
> mistake.

Can you try this patch out, with your driver, and see if it works for
you?

thanks,

greg k-h

------------------

Subject: driver core: add binary attributes to struct device

From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

This lets a device provide a set of default binary attributes, like
normal attributes, that are initialized and torn down by the driver core
at the proper times, so that there are no races with userspace.

Reported-by: : Oliver Schinagl <oliver+list@schinagl.nl>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>


diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2499cef..4040191 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -433,7 +433,7 @@ static void device_remove_attributes(struct device *dev,
 }
 
 static int device_add_bin_attributes(struct device *dev,
-				     struct bin_attribute *attrs)
+				     const struct bin_attribute *attrs)
 {
 	int error = 0;
 	int i;
@@ -452,7 +452,7 @@ static int device_add_bin_attributes(struct device *dev,
 }
 
 static void device_remove_bin_attributes(struct device *dev,
-					 struct bin_attribute *attrs)
+					 const struct bin_attribute *attrs)
 {
 	int i;
 
@@ -516,8 +516,14 @@ static int device_add_attrs(struct device *dev)
 	if (error)
 		goto err_remove_type_groups;
 
+	error = device_add_bin_attributes(dev, dev->bin_attrs);
+	if (error)
+		goto err_remove_groups;
 	return 0;
 
+ err_remove_groups:
+	device_remove_groups(dev, dev->groups);
+
  err_remove_type_groups:
 	if (type)
 		device_remove_groups(dev, type->groups);
@@ -537,6 +543,7 @@ static void device_remove_attrs(struct device *dev)
 	const struct device_type *type = dev->type;
 
 	device_remove_groups(dev, dev->groups);
+	device_remove_bin_attributes(dev, dev->bin_attrs);
 
 	if (type)
 		device_remove_groups(dev, type->groups);
diff --git a/include/linux/device.h b/include/linux/device.h
index c0a1261..6620ad8 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -645,6 +645,7 @@ struct acpi_dev_node {
  * @knode_class: The node used to add the device to the class list.
  * @class:	The class of the device.
  * @groups:	Optional attribute groups.
+ * @bin_attrs:	Optional binary attributes for this device.
  * @release:	Callback to free the device after all references have
  * 		gone away. This should be set by the allocator of the
  * 		device (i.e. the bus driver that discovered the device).
@@ -717,6 +718,7 @@ struct device {
 	struct klist_node	knode_class;
 	struct class		*class;
 	const struct attribute_group **groups;	/* optional groups */
+	const struct bin_attribute *bin_attrs;
 
 	void	(*release)(struct device *dev);
 	struct iommu_group	*iommu_group;

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-06 19:36                         ` Greg KH
@ 2013-07-15 21:16                           ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-15 21:16 UTC (permalink / raw)
  To: linux-sunxi
  Cc: Greg KH, Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, Oliver Schinagl

[-- Attachment #1: Type: text/plain, Size: 2497 bytes --]

On 07/06/13 21:36, Greg KH wrote:
> On Fri, Jul 05, 2013 at 09:24:47AM +0200, Oliver Schinagl wrote:
>> The other 'broken' drivers that where linked earlier, also use the
>> BINARY attributes.
>>
>> So Greg, if you could be so kind and give me an example how to
>> implement this properly, I am at loss and don't know :(
>
> Ah crap, devices don't have a binary attribute group, like struct class
> does.  I'll go add that on Monday and send you the patch to see if that
> helps you out.  I'll also go through and fix up all of the binary
> attribute drivers to keep them from doing that...
>
> Sorry, I missed that earlier, but thanks for trying and pointing out my
> mistake.
>
> greg k-h
>

Greg,

I know you are a busy man and I hate take away some of your time, but 
could you be so kind and point me into the right direction and show me 
what I should do?

With your latest patches for binary attributes and your blog post, I 
thought that you want to create your binary attributes before the probe 
function, to avoid the userspace race. To do that, we have two options, 
create them in init (ugly?) or fill the .group member if available so it 
gets automatically created from the register function.

Well in my case, I'm using the module_platform_driver() macro which 
expects the struct platform_driver. Platform_driver has a device_driver 
member .driver where the .groups is located. Great, using that works and 
we should have the sysfs entry race-free. However I don't know hot to 
exchange data between that and the rest of my driver.

Before I used to_platform_device(kobj_to_dev(kobj)) as passed via the 
.read function to obtain a platform_device where i could use 
platform_get_drvdata on. All was good, but that doesn't fly now and my 
knowledge is a bit short as to why.

The second method is finding some other shared structure given that we 
get a platform_device in the probe function, yet I couldn't find 
anything and this platform_device isn't the same as the one from the .read.

Of course using a global var bypasses this issue, but I'm sure it won't 
pass review ;)

So using these new patches for binary attributes, how can I pass data 
between my driver and the sysfs files using a platform_driver? Or are 
other 'hacks' needed and using the .groups attribute from 
platform_driver->device_driver->groups is really the wrong approach.

I did ask around and still haven't figured it out so far, so I do 
apologize if you feel I'm wasting your precious time.

Oliver

[-- Attachment #2: sunxi_sid.c --]
[-- Type: text/x-csrc, Size: 4119 bytes --]

/*
 * Copyright (c) 2013 Oliver Schinagl
 * http://www.linux-sunxi.org
 *
 * Oliver Schinagl <oliver@schinagl.nl>
 *
 * 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, a 128 bit eeprom, 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/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include <linux/sysfs.h>
#include <linux/types.h>

#define DRV_NAME "sunxi-sid"

/* There are 4 32-bit keys */
#define SID_KEYS 4
/* Each key is 4 bytes long */
#define SID_SIZE (SID_KEYS * 4)

/* We read the entire key, due to a 32 bit read alignment requirement. Since we
 * want to return the requested byte, this resuls in somewhat slower code and
 * uses 4 times more reads as needed but keeps code simpler. Since the SID is
 * only very rarly probed, this is not really an issue.
 */
static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
			      const unsigned int offset)
{
	u32 sid_key;

	if (offset >= SID_SIZE)
		return 0;

	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
	sid_key >>= (offset % 4) * 8;

	return sid_key; /* Only return the last byte */
}

static ssize_t eeprom_read(struct file *fd, struct kobject *kobj,
			struct bin_attribute *attr, char *buf,
			loff_t pos, size_t size)
{
	struct platform_device *pdev;
	void __iomem *sid_reg_base;
	int i;

	pdev = to_platform_device(kobj_to_dev(kobj));
	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
	printk("0x%x, 0x%x 0x%x 0x%x\n", kobj, kobj_to_dev(kobj), pdev, sid_reg_base);

	if (pos < 0 || pos >= SID_SIZE)
		return 0;
	if (size > SID_SIZE - pos)
		size = SID_SIZE - pos;

	for (i = 0; i < size; i++)
		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);

	return i;
}

static const struct of_device_id sunxi_sid_of_match[] = {
	{ .compatible = "allwinner,sun4i-sid", },
	{/* sentinel */},
};
MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);

static int sunxi_sid_remove(struct platform_device *pdev)
{
	dev_dbg(&pdev->dev, "%s driver unloaded\n", DRV_NAME);

	return 0;
}

static int __init sunxi_sid_probe(struct platform_device *pdev)
{
	struct resource *res;
	void __iomem *sid_reg_base;
	u8 entropy[SID_SIZE];
	unsigned int i;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(sid_reg_base))
		return PTR_ERR(sid_reg_base);
	platform_set_drvdata(pdev, sid_reg_base);
	printk("0x%x, 0%x, 0x%x\n", sid_reg_base, pdev, &pdev->dev.kobj);

	for (i = 0; i < SID_SIZE; i++)
		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
	add_device_randomness(entropy, SID_SIZE);
	dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);

	return 0;
}

struct bin_attribute sunxi_sid_bin_attr = __BIN_ATTR_RO(eeprom, SID_SIZE);

struct bin_attribute *sunxi_sid_bin_attrs[] = {
	&sunxi_sid_bin_attr,
	NULL,
};

static const struct attribute_group sunxi_sid_bin_group = {
	.bin_attrs = sunxi_sid_bin_attrs,
};

static const struct attribute_group *sunxi_sid_bin_groups[] = {
	&sunxi_sid_bin_group,
	NULL,
};

static struct platform_driver sunxi_sid_driver = {
	.probe = sunxi_sid_probe,
	.remove = sunxi_sid_remove,
	.driver = {
		.name = DRV_NAME,
		.owner = THIS_MODULE,
		.of_match_table = sunxi_sid_of_match,
		.groups = sunxi_sid_bin_groups,
	},
};
module_platform_driver(sunxi_sid_driver);

MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
MODULE_DESCRIPTION("Allwinner sunxi security id driver");
MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-15 21:16                           ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-15 21:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/06/13 21:36, Greg KH wrote:
> On Fri, Jul 05, 2013 at 09:24:47AM +0200, Oliver Schinagl wrote:
>> The other 'broken' drivers that where linked earlier, also use the
>> BINARY attributes.
>>
>> So Greg, if you could be so kind and give me an example how to
>> implement this properly, I am at loss and don't know :(
>
> Ah crap, devices don't have a binary attribute group, like struct class
> does.  I'll go add that on Monday and send you the patch to see if that
> helps you out.  I'll also go through and fix up all of the binary
> attribute drivers to keep them from doing that...
>
> Sorry, I missed that earlier, but thanks for trying and pointing out my
> mistake.
>
> greg k-h
>

Greg,

I know you are a busy man and I hate take away some of your time, but 
could you be so kind and point me into the right direction and show me 
what I should do?

With your latest patches for binary attributes and your blog post, I 
thought that you want to create your binary attributes before the probe 
function, to avoid the userspace race. To do that, we have two options, 
create them in init (ugly?) or fill the .group member if available so it 
gets automatically created from the register function.

Well in my case, I'm using the module_platform_driver() macro which 
expects the struct platform_driver. Platform_driver has a device_driver 
member .driver where the .groups is located. Great, using that works and 
we should have the sysfs entry race-free. However I don't know hot to 
exchange data between that and the rest of my driver.

Before I used to_platform_device(kobj_to_dev(kobj)) as passed via the 
.read function to obtain a platform_device where i could use 
platform_get_drvdata on. All was good, but that doesn't fly now and my 
knowledge is a bit short as to why.

The second method is finding some other shared structure given that we 
get a platform_device in the probe function, yet I couldn't find 
anything and this platform_device isn't the same as the one from the .read.

Of course using a global var bypasses this issue, but I'm sure it won't 
pass review ;)

So using these new patches for binary attributes, how can I pass data 
between my driver and the sysfs files using a platform_driver? Or are 
other 'hacks' needed and using the .groups attribute from 
platform_driver->device_driver->groups is really the wrong approach.

I did ask around and still haven't figured it out so far, so I do 
apologize if you feel I'm wasting your precious time.

Oliver
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sunxi_sid.c
Type: text/x-csrc
Size: 4119 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130715/7e9d8821/attachment-0001.bin>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-15 21:16                           ` Oliver Schinagl
@ 2013-07-16  6:41                             ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-16  6:41 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: linux-sunxi, Maxime Ripard, arnd, linux-kernel, linux-arm-kernel,
	andy.shevchenko, linux, linus.walleij, Oliver Schinagl

On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> 
> With your latest patches for binary attributes and your blog post, I 
> thought that you want to create your binary attributes before the probe 
> function, to avoid the userspace race. To do that, we have two options, 
> create them in init (ugly?) or fill the .group member if available so it 
> gets automatically created from the register function.

Yes, the .group thing should be what is needed here.

> Well in my case, I'm using the module_platform_driver() macro which 
> expects the struct platform_driver. Platform_driver has a device_driver 
> member .driver where the .groups is located. Great, using that works and 
> we should have the sysfs entry race-free. However I don't know hot to 
> exchange data between that and the rest of my driver.
> 
> Before I used to_platform_device(kobj_to_dev(kobj)) as passed via the 
> .read function to obtain a platform_device where i could use 
> platform_get_drvdata on. All was good, but that doesn't fly now and my 
> knowledge is a bit short as to why.

I don't understand, why not use the platform device that was passed to
the binary attribute write function?

> The second method is finding some other shared structure given that we 
> get a platform_device in the probe function, yet I couldn't find 
> anything and this platform_device isn't the same as the one from the .read.

It should be, why isn't it?

> Of course using a global var bypasses this issue, but I'm sure it won't 
> pass review ;)

The platform device structure should have what you need, right?

> So using these new patches for binary attributes, how can I pass data 
> between my driver and the sysfs files using a platform_driver? Or are 
> other 'hacks' needed and using the .groups attribute from 
> platform_driver->device_driver->groups is really the wrong approach.
> 
> I did ask around and still haven't figured it out so far, so I do 
> apologize if you feel I'm wasting your precious time.

How is the platform device not the same thing that was passed to your
probe function?

> 
> Oliver

> /*
>  * Copyright (c) 2013 Oliver Schinagl
>  * http://www.linux-sunxi.org
>  *
>  * Oliver Schinagl <oliver@schinagl.nl>
>  *
>  * 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, a 128 bit eeprom, 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/init.h>
> #include <linux/io.h>
> #include <linux/kernel.h>
> #include <linux/kobject.h>
> #include <linux/module.h>
> #include <linux/platform_device.h>
> #include <linux/random.h>
> #include <linux/sysfs.h>
> #include <linux/types.h>
> 
> #define DRV_NAME "sunxi-sid"
> 
> /* There are 4 32-bit keys */
> #define SID_KEYS 4
> /* Each key is 4 bytes long */
> #define SID_SIZE (SID_KEYS * 4)
> 
> /* We read the entire key, due to a 32 bit read alignment requirement. Since we
>  * want to return the requested byte, this resuls in somewhat slower code and
>  * uses 4 times more reads as needed but keeps code simpler. Since the SID is
>  * only very rarly probed, this is not really an issue.
>  */
> static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> 			      const unsigned int offset)
> {
> 	u32 sid_key;
> 
> 	if (offset >= SID_SIZE)
> 		return 0;
> 
> 	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
> 	sid_key >>= (offset % 4) * 8;
> 
> 	return sid_key; /* Only return the last byte */
> }
> 
> static ssize_t eeprom_read(struct file *fd, struct kobject *kobj,
> 			struct bin_attribute *attr, char *buf,
> 			loff_t pos, size_t size)
> {
> 	struct platform_device *pdev;
> 	void __iomem *sid_reg_base;
> 	int i;
> 
> 	pdev = to_platform_device(kobj_to_dev(kobj));
> 	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);

Great, isn't that what you need?

> 	printk("0x%x, 0x%x 0x%x 0x%x\n", kobj, kobj_to_dev(kobj), pdev, sid_reg_base);
> 
> 	if (pos < 0 || pos >= SID_SIZE)
> 		return 0;
> 	if (size > SID_SIZE - pos)
> 		size = SID_SIZE - pos;
> 
> 	for (i = 0; i < size; i++)
> 		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> 
> 	return i;
> }

What are you missing in this function that you have in your probe
function?

This driver looks fine, what is not working properly?

totally confused,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-16  6:41                             ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-16  6:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> 
> With your latest patches for binary attributes and your blog post, I 
> thought that you want to create your binary attributes before the probe 
> function, to avoid the userspace race. To do that, we have two options, 
> create them in init (ugly?) or fill the .group member if available so it 
> gets automatically created from the register function.

Yes, the .group thing should be what is needed here.

> Well in my case, I'm using the module_platform_driver() macro which 
> expects the struct platform_driver. Platform_driver has a device_driver 
> member .driver where the .groups is located. Great, using that works and 
> we should have the sysfs entry race-free. However I don't know hot to 
> exchange data between that and the rest of my driver.
> 
> Before I used to_platform_device(kobj_to_dev(kobj)) as passed via the 
> .read function to obtain a platform_device where i could use 
> platform_get_drvdata on. All was good, but that doesn't fly now and my 
> knowledge is a bit short as to why.

I don't understand, why not use the platform device that was passed to
the binary attribute write function?

> The second method is finding some other shared structure given that we 
> get a platform_device in the probe function, yet I couldn't find 
> anything and this platform_device isn't the same as the one from the .read.

It should be, why isn't it?

> Of course using a global var bypasses this issue, but I'm sure it won't 
> pass review ;)

The platform device structure should have what you need, right?

> So using these new patches for binary attributes, how can I pass data 
> between my driver and the sysfs files using a platform_driver? Or are 
> other 'hacks' needed and using the .groups attribute from 
> platform_driver->device_driver->groups is really the wrong approach.
> 
> I did ask around and still haven't figured it out so far, so I do 
> apologize if you feel I'm wasting your precious time.

How is the platform device not the same thing that was passed to your
probe function?

> 
> Oliver

> /*
>  * Copyright (c) 2013 Oliver Schinagl
>  * http://www.linux-sunxi.org
>  *
>  * Oliver Schinagl <oliver@schinagl.nl>
>  *
>  * 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, a 128 bit eeprom, 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/init.h>
> #include <linux/io.h>
> #include <linux/kernel.h>
> #include <linux/kobject.h>
> #include <linux/module.h>
> #include <linux/platform_device.h>
> #include <linux/random.h>
> #include <linux/sysfs.h>
> #include <linux/types.h>
> 
> #define DRV_NAME "sunxi-sid"
> 
> /* There are 4 32-bit keys */
> #define SID_KEYS 4
> /* Each key is 4 bytes long */
> #define SID_SIZE (SID_KEYS * 4)
> 
> /* We read the entire key, due to a 32 bit read alignment requirement. Since we
>  * want to return the requested byte, this resuls in somewhat slower code and
>  * uses 4 times more reads as needed but keeps code simpler. Since the SID is
>  * only very rarly probed, this is not really an issue.
>  */
> static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> 			      const unsigned int offset)
> {
> 	u32 sid_key;
> 
> 	if (offset >= SID_SIZE)
> 		return 0;
> 
> 	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
> 	sid_key >>= (offset % 4) * 8;
> 
> 	return sid_key; /* Only return the last byte */
> }
> 
> static ssize_t eeprom_read(struct file *fd, struct kobject *kobj,
> 			struct bin_attribute *attr, char *buf,
> 			loff_t pos, size_t size)
> {
> 	struct platform_device *pdev;
> 	void __iomem *sid_reg_base;
> 	int i;
> 
> 	pdev = to_platform_device(kobj_to_dev(kobj));
> 	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);

Great, isn't that what you need?

> 	printk("0x%x, 0x%x 0x%x 0x%x\n", kobj, kobj_to_dev(kobj), pdev, sid_reg_base);
> 
> 	if (pos < 0 || pos >= SID_SIZE)
> 		return 0;
> 	if (size > SID_SIZE - pos)
> 		size = SID_SIZE - pos;
> 
> 	for (i = 0; i < size; i++)
> 		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> 
> 	return i;
> }

What are you missing in this function that you have in your probe
function?

This driver looks fine, what is not working properly?

totally confused,

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-16  6:41                             ` Greg KH
@ 2013-07-16 21:02                               ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-16 21:02 UTC (permalink / raw)
  To: Greg KH
  Cc: Oliver Schinagl, linux-sunxi, Maxime Ripard, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij

On 07/16/13 08:41, Greg KH wrote:
> On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
>> With your latest patches for binary attributes and your blog post, I
>> thought that you want to create your binary attributes before the probe
>> function, to avoid the userspace race. To do that, we have two options,
>> create them in init (ugly?) or fill the .group member if available so it
>> gets automatically created from the register function.
> Yes, the .group thing should be what is needed here.
That's what I thought (and used).
>
>> Well in my case, I'm using the module_platform_driver() macro which
>> expects the struct platform_driver. Platform_driver has a device_driver
>> member .driver where the .groups is located. Great, using that works and
>> we should have the sysfs entry race-free. However I don't know hot to
>> exchange data between that and the rest of my driver.
>>
>> Before I used to_platform_device(kobj_to_dev(kobj)) as passed via the
>> .read function to obtain a platform_device where i could use
>> platform_get_drvdata on. All was good, but that doesn't fly now and my
>> knowledge is a bit short as to why.
> I don't understand, why not use the platform device that was passed to
> the binary attribute write function?
Because the pointers don't match and I get a null pointer from 
platform_get_data
>
>> The second method is finding some other shared structure given that we
>> get a platform_device in the probe function, yet I couldn't find
>> anything and this platform_device isn't the same as the one from the .read.
> It should be, why isn't it?
I think that's a little above my grasp :p
>
>> Of course using a global var bypasses this issue, but I'm sure it won't
>> pass review ;)
> The platform device structure should have what you need, right?
Should, but doesn't :(
>
>> So using these new patches for binary attributes, how can I pass data
>> between my driver and the sysfs files using a platform_driver? Or are
>> other 'hacks' needed and using the .groups attribute from
>> platform_driver->device_driver->groups is really the wrong approach.
>>
>> I did ask around and still haven't figured it out so far, so I do
>> apologize if you feel I'm wasting your precious time.
> How is the platform device not the same thing that was passed to your
> probe function?
I don't know :( But i'll add the relevant sections with printk results 
below, which I should have done before, then again those printk's were 
not supposed to be in that e-mail to begin with ;)

So if I'm not seeing something stupidly obvious, feel free to shout at me :)

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;
     void __iomem *sid_reg_base;
     int i;

     pdev = to_platform_device(kobj_to_dev(kobj));
     sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
     printk("0x%p, 0x%p, 0x%p, 0x%p\n", kobj, kobj_to_dev(kobj), pdev, 
sid_reg_base);

0xef1e7c80, 0xef1e7c78, 0xef1e7c68, 0x  (null)

     if (pos < 0 || pos >= SID_SIZE)
         return 0;
     if (size > SID_SIZE - pos)
         size = SID_SIZE - pos;

     for (i = 0; i < size; i++)
         buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);

     return i;
}


static struct bin_attribute sid_bin_attr = {
     .attr = { .name = "eeprom", .mode = S_IRUGO, },
     .size = SID_SIZE,
     .read = sid_read,
};

static struct bin_attribute *sunxi_sid_attrs[] = {
     &sid_bin_attr,
     NULL,
};

static const struct attribute_group sunxi_sid_group = {
     .bin_attrs = sunxi_sid_attrs,
};

static const struct attribute_group *sunxi_sid_groups[] = {
     &sunxi_sid_group,
     NULL,
};

static int __init sunxi_sid_probe(struct platform_device *pdev)
{
     struct resource *res;
     void __iomem *sid_reg_base;
     u8 entropy[SID_SIZE];
     unsigned int i;

     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
     if (IS_ERR(sid_reg_base))
         return PTR_ERR(sid_reg_base);
     platform_set_drvdata(pdev, sid_reg_base);

     for (i = 0; i < SID_SIZE; i++)
         entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
     add_device_randomness(entropy, SID_SIZE);
     dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);
     printk("0x%p, 0x%p\n", pdev, sid_reg_base);

0xef02b000, 0xf1c23800

     return 0;
}



^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-16 21:02                               ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-16 21:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/16/13 08:41, Greg KH wrote:
> On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
>> With your latest patches for binary attributes and your blog post, I
>> thought that you want to create your binary attributes before the probe
>> function, to avoid the userspace race. To do that, we have two options,
>> create them in init (ugly?) or fill the .group member if available so it
>> gets automatically created from the register function.
> Yes, the .group thing should be what is needed here.
That's what I thought (and used).
>
>> Well in my case, I'm using the module_platform_driver() macro which
>> expects the struct platform_driver. Platform_driver has a device_driver
>> member .driver where the .groups is located. Great, using that works and
>> we should have the sysfs entry race-free. However I don't know hot to
>> exchange data between that and the rest of my driver.
>>
>> Before I used to_platform_device(kobj_to_dev(kobj)) as passed via the
>> .read function to obtain a platform_device where i could use
>> platform_get_drvdata on. All was good, but that doesn't fly now and my
>> knowledge is a bit short as to why.
> I don't understand, why not use the platform device that was passed to
> the binary attribute write function?
Because the pointers don't match and I get a null pointer from 
platform_get_data
>
>> The second method is finding some other shared structure given that we
>> get a platform_device in the probe function, yet I couldn't find
>> anything and this platform_device isn't the same as the one from the .read.
> It should be, why isn't it?
I think that's a little above my grasp :p
>
>> Of course using a global var bypasses this issue, but I'm sure it won't
>> pass review ;)
> The platform device structure should have what you need, right?
Should, but doesn't :(
>
>> So using these new patches for binary attributes, how can I pass data
>> between my driver and the sysfs files using a platform_driver? Or are
>> other 'hacks' needed and using the .groups attribute from
>> platform_driver->device_driver->groups is really the wrong approach.
>>
>> I did ask around and still haven't figured it out so far, so I do
>> apologize if you feel I'm wasting your precious time.
> How is the platform device not the same thing that was passed to your
> probe function?
I don't know :( But i'll add the relevant sections with printk results 
below, which I should have done before, then again those printk's were 
not supposed to be in that e-mail to begin with ;)

So if I'm not seeing something stupidly obvious, feel free to shout at me :)

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;
     void __iomem *sid_reg_base;
     int i;

     pdev = to_platform_device(kobj_to_dev(kobj));
     sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
     printk("0x%p, 0x%p, 0x%p, 0x%p\n", kobj, kobj_to_dev(kobj), pdev, 
sid_reg_base);

0xef1e7c80, 0xef1e7c78, 0xef1e7c68, 0x  (null)

     if (pos < 0 || pos >= SID_SIZE)
         return 0;
     if (size > SID_SIZE - pos)
         size = SID_SIZE - pos;

     for (i = 0; i < size; i++)
         buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);

     return i;
}


static struct bin_attribute sid_bin_attr = {
     .attr = { .name = "eeprom", .mode = S_IRUGO, },
     .size = SID_SIZE,
     .read = sid_read,
};

static struct bin_attribute *sunxi_sid_attrs[] = {
     &sid_bin_attr,
     NULL,
};

static const struct attribute_group sunxi_sid_group = {
     .bin_attrs = sunxi_sid_attrs,
};

static const struct attribute_group *sunxi_sid_groups[] = {
     &sunxi_sid_group,
     NULL,
};

static int __init sunxi_sid_probe(struct platform_device *pdev)
{
     struct resource *res;
     void __iomem *sid_reg_base;
     u8 entropy[SID_SIZE];
     unsigned int i;

     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
     if (IS_ERR(sid_reg_base))
         return PTR_ERR(sid_reg_base);
     platform_set_drvdata(pdev, sid_reg_base);

     for (i = 0; i < SID_SIZE; i++)
         entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
     add_device_randomness(entropy, SID_SIZE);
     dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);
     printk("0x%p, 0x%p\n", pdev, sid_reg_base);

0xef02b000, 0xf1c23800

     return 0;
}

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-16 21:02                               ` Oliver Schinagl
@ 2013-07-17  4:20                                 ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-17  4:20 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Oliver Schinagl, linux-sunxi, Maxime Ripard, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij

On Tue, Jul 16, 2013 at 11:02:22PM +0200, Oliver Schinagl wrote:
> On 07/16/13 08:41, Greg KH wrote:
> > On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> >> With your latest patches for binary attributes and your blog post, I
> >> thought that you want to create your binary attributes before the probe
> >> function, to avoid the userspace race. To do that, we have two options,
> >> create them in init (ugly?) or fill the .group member if available so it
> >> gets automatically created from the register function.
> > Yes, the .group thing should be what is needed here.
> That's what I thought (and used).
> >
> >> Well in my case, I'm using the module_platform_driver() macro which
> >> expects the struct platform_driver. Platform_driver has a device_driver
> >> member .driver where the .groups is located. Great, using that works and
> >> we should have the sysfs entry race-free. However I don't know hot to
> >> exchange data between that and the rest of my driver.
> >>
> >> Before I used to_platform_device(kobj_to_dev(kobj)) as passed via the
> >> .read function to obtain a platform_device where i could use
> >> platform_get_drvdata on. All was good, but that doesn't fly now and my
> >> knowledge is a bit short as to why.
> > I don't understand, why not use the platform device that was passed to
> > the binary attribute write function?
> Because the pointers don't match and I get a null pointer from 
> platform_get_data

That's not good, that shouldn't happen.

> >> The second method is finding some other shared structure given that we
> >> get a platform_device in the probe function, yet I couldn't find
> >> anything and this platform_device isn't the same as the one from the .read.
> > It should be, why isn't it?
> I think that's a little above my grasp :p
> >
> >> Of course using a global var bypasses this issue, but I'm sure it won't
> >> pass review ;)
> > The platform device structure should have what you need, right?
> Should, but doesn't :(
> >
> >> So using these new patches for binary attributes, how can I pass data
> >> between my driver and the sysfs files using a platform_driver? Or are
> >> other 'hacks' needed and using the .groups attribute from
> >> platform_driver->device_driver->groups is really the wrong approach.
> >>
> >> I did ask around and still haven't figured it out so far, so I do
> >> apologize if you feel I'm wasting your precious time.
> > How is the platform device not the same thing that was passed to your
> > probe function?
> I don't know :( But i'll add the relevant sections with printk results 
> below, which I should have done before, then again those printk's were 
> not supposed to be in that e-mail to begin with ;)
> 
> So if I'm not seeing something stupidly obvious, feel free to shout at me :)

Your code looks good, and correct, to me, I don't see anything obviously
wrong.  What creates your platform device in the first place?

> 
> 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;
>      void __iomem *sid_reg_base;
>      int i;
> 
>      pdev = to_platform_device(kobj_to_dev(kobj));
>      sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
>      printk("0x%p, 0x%p, 0x%p, 0x%p\n", kobj, kobj_to_dev(kobj), pdev, 
> sid_reg_base);
> 
> 0xef1e7c80, 0xef1e7c78, 0xef1e7c68, 0x  (null)
> 
>      if (pos < 0 || pos >= SID_SIZE)
>          return 0;
>      if (size > SID_SIZE - pos)
>          size = SID_SIZE - pos;
> 
>      for (i = 0; i < size; i++)
>          buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> 
>      return i;
> }
> 
> 
> static struct bin_attribute sid_bin_attr = {
>      .attr = { .name = "eeprom", .mode = S_IRUGO, },
>      .size = SID_SIZE,
>      .read = sid_read,
> };
> 
> static struct bin_attribute *sunxi_sid_attrs[] = {
>      &sid_bin_attr,
>      NULL,
> };
> 
> static const struct attribute_group sunxi_sid_group = {
>      .bin_attrs = sunxi_sid_attrs,
> };

If you create a "normal" attribute here as well, does that work
properly?

> 
> static const struct attribute_group *sunxi_sid_groups[] = {
>      &sunxi_sid_group,
>      NULL,
> };
> 
> static int __init sunxi_sid_probe(struct platform_device *pdev)
> {
>      struct resource *res;
>      void __iomem *sid_reg_base;
>      u8 entropy[SID_SIZE];
>      unsigned int i;
> 
>      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>      sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>      if (IS_ERR(sid_reg_base))
>          return PTR_ERR(sid_reg_base);
>      platform_set_drvdata(pdev, sid_reg_base);
> 
>      for (i = 0; i < SID_SIZE; i++)
>          entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
>      add_device_randomness(entropy, SID_SIZE);
>      dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);
>      printk("0x%p, 0x%p\n", pdev, sid_reg_base);
> 
> 0xef02b000, 0xf1c23800

The memory locations are really different here, that's strange, I don't
know what is going on, sorry.

Try a text attribute to ensure that works properly.

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-17  4:20                                 ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-17  4:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 16, 2013 at 11:02:22PM +0200, Oliver Schinagl wrote:
> On 07/16/13 08:41, Greg KH wrote:
> > On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> >> With your latest patches for binary attributes and your blog post, I
> >> thought that you want to create your binary attributes before the probe
> >> function, to avoid the userspace race. To do that, we have two options,
> >> create them in init (ugly?) or fill the .group member if available so it
> >> gets automatically created from the register function.
> > Yes, the .group thing should be what is needed here.
> That's what I thought (and used).
> >
> >> Well in my case, I'm using the module_platform_driver() macro which
> >> expects the struct platform_driver. Platform_driver has a device_driver
> >> member .driver where the .groups is located. Great, using that works and
> >> we should have the sysfs entry race-free. However I don't know hot to
> >> exchange data between that and the rest of my driver.
> >>
> >> Before I used to_platform_device(kobj_to_dev(kobj)) as passed via the
> >> .read function to obtain a platform_device where i could use
> >> platform_get_drvdata on. All was good, but that doesn't fly now and my
> >> knowledge is a bit short as to why.
> > I don't understand, why not use the platform device that was passed to
> > the binary attribute write function?
> Because the pointers don't match and I get a null pointer from 
> platform_get_data

That's not good, that shouldn't happen.

> >> The second method is finding some other shared structure given that we
> >> get a platform_device in the probe function, yet I couldn't find
> >> anything and this platform_device isn't the same as the one from the .read.
> > It should be, why isn't it?
> I think that's a little above my grasp :p
> >
> >> Of course using a global var bypasses this issue, but I'm sure it won't
> >> pass review ;)
> > The platform device structure should have what you need, right?
> Should, but doesn't :(
> >
> >> So using these new patches for binary attributes, how can I pass data
> >> between my driver and the sysfs files using a platform_driver? Or are
> >> other 'hacks' needed and using the .groups attribute from
> >> platform_driver->device_driver->groups is really the wrong approach.
> >>
> >> I did ask around and still haven't figured it out so far, so I do
> >> apologize if you feel I'm wasting your precious time.
> > How is the platform device not the same thing that was passed to your
> > probe function?
> I don't know :( But i'll add the relevant sections with printk results 
> below, which I should have done before, then again those printk's were 
> not supposed to be in that e-mail to begin with ;)
> 
> So if I'm not seeing something stupidly obvious, feel free to shout at me :)

Your code looks good, and correct, to me, I don't see anything obviously
wrong.  What creates your platform device in the first place?

> 
> 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;
>      void __iomem *sid_reg_base;
>      int i;
> 
>      pdev = to_platform_device(kobj_to_dev(kobj));
>      sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
>      printk("0x%p, 0x%p, 0x%p, 0x%p\n", kobj, kobj_to_dev(kobj), pdev, 
> sid_reg_base);
> 
> 0xef1e7c80, 0xef1e7c78, 0xef1e7c68, 0x  (null)
> 
>      if (pos < 0 || pos >= SID_SIZE)
>          return 0;
>      if (size > SID_SIZE - pos)
>          size = SID_SIZE - pos;
> 
>      for (i = 0; i < size; i++)
>          buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> 
>      return i;
> }
> 
> 
> static struct bin_attribute sid_bin_attr = {
>      .attr = { .name = "eeprom", .mode = S_IRUGO, },
>      .size = SID_SIZE,
>      .read = sid_read,
> };
> 
> static struct bin_attribute *sunxi_sid_attrs[] = {
>      &sid_bin_attr,
>      NULL,
> };
> 
> static const struct attribute_group sunxi_sid_group = {
>      .bin_attrs = sunxi_sid_attrs,
> };

If you create a "normal" attribute here as well, does that work
properly?

> 
> static const struct attribute_group *sunxi_sid_groups[] = {
>      &sunxi_sid_group,
>      NULL,
> };
> 
> static int __init sunxi_sid_probe(struct platform_device *pdev)
> {
>      struct resource *res;
>      void __iomem *sid_reg_base;
>      u8 entropy[SID_SIZE];
>      unsigned int i;
> 
>      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>      sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>      if (IS_ERR(sid_reg_base))
>          return PTR_ERR(sid_reg_base);
>      platform_set_drvdata(pdev, sid_reg_base);
> 
>      for (i = 0; i < SID_SIZE; i++)
>          entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
>      add_device_randomness(entropy, SID_SIZE);
>      dev_dbg(&pdev->dev, "%s loaded\n", DRV_NAME);
>      printk("0x%p, 0x%p\n", pdev, sid_reg_base);
> 
> 0xef02b000, 0xf1c23800

The memory locations are really different here, that's strange, I don't
know what is going on, sorry.

Try a text attribute to ensure that works properly.

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-16  6:41                             ` Greg KH
@ 2013-07-17 11:46                               ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-07-17 11:46 UTC (permalink / raw)
  To: Greg KH
  Cc: Oliver Schinagl, linux-sunxi, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij,
	Oliver Schinagl

[-- Attachment #1: Type: text/plain, Size: 1646 bytes --]

On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
> On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> > So using these new patches for binary attributes, how can I pass data 
> > between my driver and the sysfs files using a platform_driver? Or are 
> > other 'hacks' needed and using the .groups attribute from 
> > platform_driver->device_driver->groups is really the wrong approach.
> > 
> > I did ask around and still haven't figured it out so far, so I do 
> > apologize if you feel I'm wasting your precious time.
> 
> How is the platform device not the same thing that was passed to your
> probe function?

One thing I don't get here is why it should be set in the
platform_driver structure. From my understanding of the device model,
and since what Oliver is trying to do is exposing a few bytes of memory
to sysfs, shouldn't the sysfs file be attached to the device instead?

I mean, here, the sysfs file will be created under something like
.../drivers/sunxi-sid/eeprom. What happens when you have several
instances of that driver loaded? I'd expect it to have several sysfs
files created, one for each instance. So to me, it should be in the
device structure, not the driver one.

Couldn't that be also the reason of Oliver's NULL pointer? If the kobj
is attached to the platform_driver and not to the platform_device, it
should definitely get nasty when we try to cast it and retrieve data
from it (and that would match the different pointers stuff as well.)

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-17 11:46                               ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-07-17 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
> On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> > So using these new patches for binary attributes, how can I pass data 
> > between my driver and the sysfs files using a platform_driver? Or are 
> > other 'hacks' needed and using the .groups attribute from 
> > platform_driver->device_driver->groups is really the wrong approach.
> > 
> > I did ask around and still haven't figured it out so far, so I do 
> > apologize if you feel I'm wasting your precious time.
> 
> How is the platform device not the same thing that was passed to your
> probe function?

One thing I don't get here is why it should be set in the
platform_driver structure. From my understanding of the device model,
and since what Oliver is trying to do is exposing a few bytes of memory
to sysfs, shouldn't the sysfs file be attached to the device instead?

I mean, here, the sysfs file will be created under something like
.../drivers/sunxi-sid/eeprom. What happens when you have several
instances of that driver loaded? I'd expect it to have several sysfs
files created, one for each instance. So to me, it should be in the
device structure, not the driver one.

Couldn't that be also the reason of Oliver's NULL pointer? If the kobj
is attached to the platform_driver and not to the platform_device, it
should definitely get nasty when we try to cast it and retrieve data
from it (and that would match the different pointers stuff as well.)

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130717/bc403ec4/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-17 11:46                               ` Maxime Ripard
@ 2013-07-17 16:17                                 ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-17 16:17 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Oliver Schinagl, linux-sunxi, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij,
	Oliver Schinagl

On Wed, Jul 17, 2013 at 01:46:50PM +0200, Maxime Ripard wrote:
> On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
> > On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> > > So using these new patches for binary attributes, how can I pass data 
> > > between my driver and the sysfs files using a platform_driver? Or are 
> > > other 'hacks' needed and using the .groups attribute from 
> > > platform_driver->device_driver->groups is really the wrong approach.
> > > 
> > > I did ask around and still haven't figured it out so far, so I do 
> > > apologize if you feel I'm wasting your precious time.
> > 
> > How is the platform device not the same thing that was passed to your
> > probe function?
> 
> One thing I don't get here is why it should be set in the
> platform_driver structure. From my understanding of the device model,
> and since what Oliver is trying to do is exposing a few bytes of memory
> to sysfs, shouldn't the sysfs file be attached to the device instead?

It will be created by the driver core for any device attached to the
driver automatically.

> I mean, here, the sysfs file will be created under something like
> .../drivers/sunxi-sid/eeprom. What happens when you have several
> instances of that driver loaded? I'd expect it to have several sysfs
> files created, one for each instance. So to me, it should be in the
> device structure, not the driver one.

You can't have multiple drivers with the same name loaded (or the same
module loaded multiple times.)  You can have multiple devices for a
single driver, which is what we do all the time.

> Couldn't that be also the reason of Oliver's NULL pointer? If the kobj
> is attached to the platform_driver and not to the platform_device, it
> should definitely get nasty when we try to cast it and retrieve data
> from it (and that would match the different pointers stuff as well.)

No, he's getting a kobject that looks quite different at probe that is
different from when the file callback happens, something is odd here...

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-17 16:17                                 ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-17 16:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 17, 2013 at 01:46:50PM +0200, Maxime Ripard wrote:
> On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
> > On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> > > So using these new patches for binary attributes, how can I pass data 
> > > between my driver and the sysfs files using a platform_driver? Or are 
> > > other 'hacks' needed and using the .groups attribute from 
> > > platform_driver->device_driver->groups is really the wrong approach.
> > > 
> > > I did ask around and still haven't figured it out so far, so I do 
> > > apologize if you feel I'm wasting your precious time.
> > 
> > How is the platform device not the same thing that was passed to your
> > probe function?
> 
> One thing I don't get here is why it should be set in the
> platform_driver structure. From my understanding of the device model,
> and since what Oliver is trying to do is exposing a few bytes of memory
> to sysfs, shouldn't the sysfs file be attached to the device instead?

It will be created by the driver core for any device attached to the
driver automatically.

> I mean, here, the sysfs file will be created under something like
> .../drivers/sunxi-sid/eeprom. What happens when you have several
> instances of that driver loaded? I'd expect it to have several sysfs
> files created, one for each instance. So to me, it should be in the
> device structure, not the driver one.

You can't have multiple drivers with the same name loaded (or the same
module loaded multiple times.)  You can have multiple devices for a
single driver, which is what we do all the time.

> Couldn't that be also the reason of Oliver's NULL pointer? If the kobj
> is attached to the platform_driver and not to the platform_device, it
> should definitely get nasty when we try to cast it and retrieve data
> from it (and that would match the different pointers stuff as well.)

No, he's getting a kobject that looks quite different at probe that is
different from when the file callback happens, something is odd here...

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-17 16:17                                 ` Greg KH
@ 2013-07-19  9:42                                   ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-07-19  9:42 UTC (permalink / raw)
  To: Greg KH
  Cc: Oliver Schinagl, linux-sunxi, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij,
	Oliver Schinagl

[-- Attachment #1: Type: text/plain, Size: 2233 bytes --]

On Wed, Jul 17, 2013 at 09:17:58AM -0700, Greg KH wrote:
> On Wed, Jul 17, 2013 at 01:46:50PM +0200, Maxime Ripard wrote:
> > On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
> > > On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> > > > So using these new patches for binary attributes, how can I pass data 
> > > > between my driver and the sysfs files using a platform_driver? Or are 
> > > > other 'hacks' needed and using the .groups attribute from 
> > > > platform_driver->device_driver->groups is really the wrong approach.
> > > > 
> > > > I did ask around and still haven't figured it out so far, so I do 
> > > > apologize if you feel I'm wasting your precious time.
> > > 
> > > How is the platform device not the same thing that was passed to your
> > > probe function?
> > 
> > One thing I don't get here is why it should be set in the
> > platform_driver structure. From my understanding of the device model,
> > and since what Oliver is trying to do is exposing a few bytes of memory
> > to sysfs, shouldn't the sysfs file be attached to the device instead?
> 
> It will be created by the driver core for any device attached to the
> driver automatically.
> 
> > I mean, here, the sysfs file will be created under something like
> > .../drivers/sunxi-sid/eeprom. What happens when you have several
> > instances of that driver loaded? I'd expect it to have several sysfs
> > files created, one for each instance. So to me, it should be in the
> > device structure, not the driver one.
> 
> You can't have multiple drivers with the same name loaded (or the same
> module loaded multiple times.)  You can have multiple devices for a
> single driver, which is what we do all the time.

Yes, I know that, and it's actually my point.
With the current oliver's code he pasted earlier in this thread:

# find /sys/ -name eeprom
/sys/bus/platform/drivers/sunxi-sid/eeprom

While I'd expect the eeprom file to be located in
/sys/bus/platform/devices/X.eeprom/eeprom like it used to be in the v4,
since it's an instance-specific content.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-19  9:42                                   ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-07-19  9:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 17, 2013 at 09:17:58AM -0700, Greg KH wrote:
> On Wed, Jul 17, 2013 at 01:46:50PM +0200, Maxime Ripard wrote:
> > On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
> > > On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> > > > So using these new patches for binary attributes, how can I pass data 
> > > > between my driver and the sysfs files using a platform_driver? Or are 
> > > > other 'hacks' needed and using the .groups attribute from 
> > > > platform_driver->device_driver->groups is really the wrong approach.
> > > > 
> > > > I did ask around and still haven't figured it out so far, so I do 
> > > > apologize if you feel I'm wasting your precious time.
> > > 
> > > How is the platform device not the same thing that was passed to your
> > > probe function?
> > 
> > One thing I don't get here is why it should be set in the
> > platform_driver structure. From my understanding of the device model,
> > and since what Oliver is trying to do is exposing a few bytes of memory
> > to sysfs, shouldn't the sysfs file be attached to the device instead?
> 
> It will be created by the driver core for any device attached to the
> driver automatically.
> 
> > I mean, here, the sysfs file will be created under something like
> > .../drivers/sunxi-sid/eeprom. What happens when you have several
> > instances of that driver loaded? I'd expect it to have several sysfs
> > files created, one for each instance. So to me, it should be in the
> > device structure, not the driver one.
> 
> You can't have multiple drivers with the same name loaded (or the same
> module loaded multiple times.)  You can have multiple devices for a
> single driver, which is what we do all the time.

Yes, I know that, and it's actually my point.
With the current oliver's code he pasted earlier in this thread:

# find /sys/ -name eeprom
/sys/bus/platform/drivers/sunxi-sid/eeprom

While I'd expect the eeprom file to be located in
/sys/bus/platform/devices/X.eeprom/eeprom like it used to be in the v4,
since it's an instance-specific content.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130719/02c9c251/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-19  9:42                                   ` Maxime Ripard
@ 2013-07-19 23:49                                     ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-19 23:49 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Oliver Schinagl, linux-sunxi, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij,
	Oliver Schinagl

On Fri, Jul 19, 2013 at 11:42:11AM +0200, Maxime Ripard wrote:
> On Wed, Jul 17, 2013 at 09:17:58AM -0700, Greg KH wrote:
> > On Wed, Jul 17, 2013 at 01:46:50PM +0200, Maxime Ripard wrote:
> > > On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
> > > > On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> > > > > So using these new patches for binary attributes, how can I pass data 
> > > > > between my driver and the sysfs files using a platform_driver? Or are 
> > > > > other 'hacks' needed and using the .groups attribute from 
> > > > > platform_driver->device_driver->groups is really the wrong approach.
> > > > > 
> > > > > I did ask around and still haven't figured it out so far, so I do 
> > > > > apologize if you feel I'm wasting your precious time.
> > > > 
> > > > How is the platform device not the same thing that was passed to your
> > > > probe function?
> > > 
> > > One thing I don't get here is why it should be set in the
> > > platform_driver structure. From my understanding of the device model,
> > > and since what Oliver is trying to do is exposing a few bytes of memory
> > > to sysfs, shouldn't the sysfs file be attached to the device instead?
> > 
> > It will be created by the driver core for any device attached to the
> > driver automatically.
> > 
> > > I mean, here, the sysfs file will be created under something like
> > > .../drivers/sunxi-sid/eeprom. What happens when you have several
> > > instances of that driver loaded? I'd expect it to have several sysfs
> > > files created, one for each instance. So to me, it should be in the
> > > device structure, not the driver one.
> > 
> > You can't have multiple drivers with the same name loaded (or the same
> > module loaded multiple times.)  You can have multiple devices for a
> > single driver, which is what we do all the time.
> 
> Yes, I know that, and it's actually my point.
> With the current oliver's code he pasted earlier in this thread:
> 
> # find /sys/ -name eeprom
> /sys/bus/platform/drivers/sunxi-sid/eeprom
> 
> While I'd expect the eeprom file to be located in
> /sys/bus/platform/devices/X.eeprom/eeprom like it used to be in the v4,
> since it's an instance-specific content.

Oh crap.  You are totally right.  That's why we added the new device
create call, to allow this to work properly.

Right now you are getting the kobject of the driver, not the device, in
the callback, which is not what you want (sure, if you only have once
instance, you can work around it, but don't it's the driver core's fault
for not giving you the correct api...)

Let me go look at how I can make this work "easier", give me a few days.

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-19 23:49                                     ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-19 23:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 19, 2013 at 11:42:11AM +0200, Maxime Ripard wrote:
> On Wed, Jul 17, 2013 at 09:17:58AM -0700, Greg KH wrote:
> > On Wed, Jul 17, 2013 at 01:46:50PM +0200, Maxime Ripard wrote:
> > > On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
> > > > On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
> > > > > So using these new patches for binary attributes, how can I pass data 
> > > > > between my driver and the sysfs files using a platform_driver? Or are 
> > > > > other 'hacks' needed and using the .groups attribute from 
> > > > > platform_driver->device_driver->groups is really the wrong approach.
> > > > > 
> > > > > I did ask around and still haven't figured it out so far, so I do 
> > > > > apologize if you feel I'm wasting your precious time.
> > > > 
> > > > How is the platform device not the same thing that was passed to your
> > > > probe function?
> > > 
> > > One thing I don't get here is why it should be set in the
> > > platform_driver structure. From my understanding of the device model,
> > > and since what Oliver is trying to do is exposing a few bytes of memory
> > > to sysfs, shouldn't the sysfs file be attached to the device instead?
> > 
> > It will be created by the driver core for any device attached to the
> > driver automatically.
> > 
> > > I mean, here, the sysfs file will be created under something like
> > > .../drivers/sunxi-sid/eeprom. What happens when you have several
> > > instances of that driver loaded? I'd expect it to have several sysfs
> > > files created, one for each instance. So to me, it should be in the
> > > device structure, not the driver one.
> > 
> > You can't have multiple drivers with the same name loaded (or the same
> > module loaded multiple times.)  You can have multiple devices for a
> > single driver, which is what we do all the time.
> 
> Yes, I know that, and it's actually my point.
> With the current oliver's code he pasted earlier in this thread:
> 
> # find /sys/ -name eeprom
> /sys/bus/platform/drivers/sunxi-sid/eeprom
> 
> While I'd expect the eeprom file to be located in
> /sys/bus/platform/devices/X.eeprom/eeprom like it used to be in the v4,
> since it's an instance-specific content.

Oh crap.  You are totally right.  That's why we added the new device
create call, to allow this to work properly.

Right now you are getting the kobject of the driver, not the device, in
the callback, which is not what you want (sure, if you only have once
instance, you can work around it, but don't it's the driver core's fault
for not giving you the correct api...)

Let me go look at how I can make this work "easier", give me a few days.

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-19 23:49                                     ` Greg KH
@ 2013-07-30 13:22                                       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-30 13:22 UTC (permalink / raw)
  To: Greg KH
  Cc: Maxime Ripard, Oliver Schinagl, linux-sunxi, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij

Hey Greg!

On 20-07-13 01:49, Greg KH wrote:
> On Fri, Jul 19, 2013 at 11:42:11AM +0200, Maxime Ripard wrote:
>> On Wed, Jul 17, 2013 at 09:17:58AM -0700, Greg KH wrote:
>>> On Wed, Jul 17, 2013 at 01:46:50PM +0200, Maxime Ripard wrote:
>>>> On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
>>>>> On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
>>>>>> So using these new patches for binary attributes, how can I pass data
>>>>>> between my driver and the sysfs files using a platform_driver? Or are
>>>>>> other 'hacks' needed and using the .groups attribute from
>>>>>> platform_driver->device_driver->groups is really the wrong approach.
>>>>>>
>>>>>> I did ask around and still haven't figured it out so far, so I do
>>>>>> apologize if you feel I'm wasting your precious time.
>>>>> How is the platform device not the same thing that was passed to your
>>>>> probe function?
>>>> One thing I don't get here is why it should be set in the
>>>> platform_driver structure. From my understanding of the device model,
>>>> and since what Oliver is trying to do is exposing a few bytes of memory
>>>> to sysfs, shouldn't the sysfs file be attached to the device instead?
>>> It will be created by the driver core for any device attached to the
>>> driver automatically.
>>>
>>>> I mean, here, the sysfs file will be created under something like
>>>> .../drivers/sunxi-sid/eeprom. What happens when you have several
>>>> instances of that driver loaded? I'd expect it to have several sysfs
>>>> files created, one for each instance. So to me, it should be in the
>>>> device structure, not the driver one.
>>> You can't have multiple drivers with the same name loaded (or the same
>>> module loaded multiple times.)  You can have multiple devices for a
>>> single driver, which is what we do all the time.
>> Yes, I know that, and it's actually my point.
>> With the current oliver's code he pasted earlier in this thread:
>>
>> # find /sys/ -name eeprom
>> /sys/bus/platform/drivers/sunxi-sid/eeprom
>>
>> While I'd expect the eeprom file to be located in
>> /sys/bus/platform/devices/X.eeprom/eeprom like it used to be in the v4,
>> since it's an instance-specific content.
> Oh crap.  You are totally right.  That's why we added the new device
> create call, to allow this to work properly.
>
> Right now you are getting the kobject of the driver, not the device, in
> the callback, which is not what you want (sure, if you only have once
> instance, you can work around it, but don't it's the driver core's fault
> for not giving you the correct api...)
>
> Let me go look at how I can make this work "easier", give me a few days.
Not wanting to be rude, but it has been a little more then a few days, 
any progress? Just want to know what I have to modify my driver to so it 
can go into the next merge window :)

oliver
>
> greg k-h


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-30 13:22                                       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-30 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hey Greg!

On 20-07-13 01:49, Greg KH wrote:
> On Fri, Jul 19, 2013 at 11:42:11AM +0200, Maxime Ripard wrote:
>> On Wed, Jul 17, 2013 at 09:17:58AM -0700, Greg KH wrote:
>>> On Wed, Jul 17, 2013 at 01:46:50PM +0200, Maxime Ripard wrote:
>>>> On Mon, Jul 15, 2013 at 11:41:07PM -0700, Greg KH wrote:
>>>>> On Mon, Jul 15, 2013 at 11:16:19PM +0200, Oliver Schinagl wrote:
>>>>>> So using these new patches for binary attributes, how can I pass data
>>>>>> between my driver and the sysfs files using a platform_driver? Or are
>>>>>> other 'hacks' needed and using the .groups attribute from
>>>>>> platform_driver->device_driver->groups is really the wrong approach.
>>>>>>
>>>>>> I did ask around and still haven't figured it out so far, so I do
>>>>>> apologize if you feel I'm wasting your precious time.
>>>>> How is the platform device not the same thing that was passed to your
>>>>> probe function?
>>>> One thing I don't get here is why it should be set in the
>>>> platform_driver structure. From my understanding of the device model,
>>>> and since what Oliver is trying to do is exposing a few bytes of memory
>>>> to sysfs, shouldn't the sysfs file be attached to the device instead?
>>> It will be created by the driver core for any device attached to the
>>> driver automatically.
>>>
>>>> I mean, here, the sysfs file will be created under something like
>>>> .../drivers/sunxi-sid/eeprom. What happens when you have several
>>>> instances of that driver loaded? I'd expect it to have several sysfs
>>>> files created, one for each instance. So to me, it should be in the
>>>> device structure, not the driver one.
>>> You can't have multiple drivers with the same name loaded (or the same
>>> module loaded multiple times.)  You can have multiple devices for a
>>> single driver, which is what we do all the time.
>> Yes, I know that, and it's actually my point.
>> With the current oliver's code he pasted earlier in this thread:
>>
>> # find /sys/ -name eeprom
>> /sys/bus/platform/drivers/sunxi-sid/eeprom
>>
>> While I'd expect the eeprom file to be located in
>> /sys/bus/platform/devices/X.eeprom/eeprom like it used to be in the v4,
>> since it's an instance-specific content.
> Oh crap.  You are totally right.  That's why we added the new device
> create call, to allow this to work properly.
>
> Right now you are getting the kobject of the driver, not the device, in
> the callback, which is not what you want (sure, if you only have once
> instance, you can work around it, but don't it's the driver core's fault
> for not giving you the correct api...)
>
> Let me go look at how I can make this work "easier", give me a few days.
Not wanting to be rude, but it has been a little more then a few days, 
any progress? Just want to know what I have to modify my driver to so it 
can go into the next merge window :)

oliver
>
> greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-30 13:22                                       ` Oliver Schinagl
@ 2013-07-30 14:20                                         ` Greg KH
  -1 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-30 14:20 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Maxime Ripard, Oliver Schinagl, linux-sunxi, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij

On Tue, Jul 30, 2013 at 03:22:55PM +0200, Oliver Schinagl wrote:
> >Let me go look at how I can make this work "easier", give me a few days.
> Not wanting to be rude, but it has been a little more then a few
> days, any progress? Just want to know what I have to modify my
> driver to so it can go into the next merge window :)

What?  Oh crap.

I saw this old email in my todo box last week and for some stupid reason
I thought I had already taken care of this, otherwise why would I have
left it around for so long?...

Ugh, very sorry about that...

Hm, this is a mess.  I hate platform devices...

Anyway, as you want to get this into 3.12, and I'm not going to be able
to get the core infrastructure into the platform device by then, just go
ahead and do a sysfs_create_group() call in your device probe callback
for now.  That will register the needed files for the device (not the
driver, DOH that was stupid of me...) and all should be ok.

Yes, you will still race with userspace, but as right now, there's no
way that _any_ platform driver can do this "correctly", you will be in
good company.  I'll clean up all platform drivers in a sweep of the tree
after 3.12 or so when I get the needed infrastructure in place for the
platform_driver code.

Again, very sorry for all of this, you have helped me out a lot in
figuring out that this is a mess, and should be fixed up better, but in
the end, you are pretty much back at the beginning of what you
originally wanted to do, right?

I owe you a beer, at the least, my apologies...

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-30 14:20                                         ` Greg KH
  0 siblings, 0 replies; 142+ messages in thread
From: Greg KH @ 2013-07-30 14:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 30, 2013 at 03:22:55PM +0200, Oliver Schinagl wrote:
> >Let me go look at how I can make this work "easier", give me a few days.
> Not wanting to be rude, but it has been a little more then a few
> days, any progress? Just want to know what I have to modify my
> driver to so it can go into the next merge window :)

What?  Oh crap.

I saw this old email in my todo box last week and for some stupid reason
I thought I had already taken care of this, otherwise why would I have
left it around for so long?...

Ugh, very sorry about that...

Hm, this is a mess.  I hate platform devices...

Anyway, as you want to get this into 3.12, and I'm not going to be able
to get the core infrastructure into the platform device by then, just go
ahead and do a sysfs_create_group() call in your device probe callback
for now.  That will register the needed files for the device (not the
driver, DOH that was stupid of me...) and all should be ok.

Yes, you will still race with userspace, but as right now, there's no
way that _any_ platform driver can do this "correctly", you will be in
good company.  I'll clean up all platform drivers in a sweep of the tree
after 3.12 or so when I get the needed infrastructure in place for the
platform_driver code.

Again, very sorry for all of this, you have helped me out a lot in
figuring out that this is a mess, and should be fixed up better, but in
the end, you are pretty much back at the beginning of what you
originally wanted to do, right?

I owe you a beer, at the least, my apologies...

greg k-h

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-07-30 14:20                                         ` Greg KH
@ 2013-07-30 17:39                                           ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-30 17:39 UTC (permalink / raw)
  To: Greg KH
  Cc: Oliver Schinagl, Maxime Ripard, linux-sunxi, arnd, linux-kernel,
	linux-arm-kernel, andy.shevchenko, linux, linus.walleij

On 30-07-13 16:20, Greg KH wrote:
> On Tue, Jul 30, 2013 at 03:22:55PM +0200, Oliver Schinagl wrote:
>>> Let me go look at how I can make this work "easier", give me a few days.
>> Not wanting to be rude, but it has been a little more then a few
>> days, any progress? Just want to know what I have to modify my
>> driver to so it can go into the next merge window :)
>
> What?  Oh crap.
>
> I saw this old email in my todo box last week and for some stupid reason
> I thought I had already taken care of this, otherwise why would I have
> left it around for so long?...
>
> Ugh, very sorry about that...
>
> Hm, this is a mess.  I hate platform devices...
>
> Anyway, as you want to get this into 3.12, and I'm not going to be able
> to get the core infrastructure into the platform device by then, just go
> ahead and do a sysfs_create_group() call in your device probe callback
> for now.  That will register the needed files for the device (not the
> driver, DOH that was stupid of me...) and all should be ok.
>
> Yes, you will still race with userspace, but as right now, there's no
> way that _any_ platform driver can do this "correctly", you will be in
> good company.  I'll clean up all platform drivers in a sweep of the tree
> after 3.12 or so when I get the needed infrastructure in place for the
> platform_driver code.
>
> Again, very sorry for all of this, you have helped me out a lot in
> figuring out that this is a mess, and should be fixed up better, but in
> the end, you are pretty much back at the beginning of what you
> originally wanted to do, right?
Alright, I'll modify it to use sysfs_create_group() and try to leave it 
as much as it is no to ease the transition.
>
> I owe you a beer, at the least, my apologies...
Pff, free booze is far better ;) I kid I kid, though Maxime helped a lot 
there.

Ok expect a v6 I think for review and hopefully merge tomorrow.

oliver

>
> greg k-h
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [linux-sunxi] Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-07-30 17:39                                           ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-07-30 17:39 UTC (permalink / raw)
  To: linux-arm-kernel

On 30-07-13 16:20, Greg KH wrote:
> On Tue, Jul 30, 2013 at 03:22:55PM +0200, Oliver Schinagl wrote:
>>> Let me go look at how I can make this work "easier", give me a few days.
>> Not wanting to be rude, but it has been a little more then a few
>> days, any progress? Just want to know what I have to modify my
>> driver to so it can go into the next merge window :)
>
> What?  Oh crap.
>
> I saw this old email in my todo box last week and for some stupid reason
> I thought I had already taken care of this, otherwise why would I have
> left it around for so long?...
>
> Ugh, very sorry about that...
>
> Hm, this is a mess.  I hate platform devices...
>
> Anyway, as you want to get this into 3.12, and I'm not going to be able
> to get the core infrastructure into the platform device by then, just go
> ahead and do a sysfs_create_group() call in your device probe callback
> for now.  That will register the needed files for the device (not the
> driver, DOH that was stupid of me...) and all should be ok.
>
> Yes, you will still race with userspace, but as right now, there's no
> way that _any_ platform driver can do this "correctly", you will be in
> good company.  I'll clean up all platform drivers in a sweep of the tree
> after 3.12 or so when I get the needed infrastructure in place for the
> platform_driver code.
>
> Again, very sorry for all of this, you have helped me out a lot in
> figuring out that this is a mess, and should be fixed up better, but in
> the end, you are pretty much back at the beginning of what you
> originally wanted to do, right?
Alright, I'll modify it to use sysfs_create_group() and try to leave it 
as much as it is no to ease the transition.
>
> I owe you a beer, at the least, my apologies...
Pff, free booze is far better ;) I kid I kid, though Maxime helped a lot 
there.

Ok expect a v6 I think for review and hopefully merge tomorrow.

oliver

>
> greg k-h
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-08-27 14:13   ` oliver+list at schinagl.nl
@ 2013-08-27 15:42     ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-08-27 15:42 UTC (permalink / raw)
  To: oliver+list
  Cc: arnd, gregkh, linux-arm-kernel, linux, linus.walleij,
	linux-kernel, andy.shevchenko, tomasz.figa, Oliver Schinagl

[-- Attachment #1: Type: text/plain, Size: 12394 bytes --]

On Tue, Aug 27, 2013 at 04:13:04PM +0200, oliver+list@schinagl.nl wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> node.
> 
> These fuses are most likly to be programmed at the factory, encoding
                       ^ likely
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. To write these fuses however,
> a 2.5 V programming voltage needs to be applied to this pin.
> 
> Even so, they can still be used to generate a board-unique mac from,
> board unique RSA key and seed the kernel RNG.
> 
> On sun7i additional storage is available, this is initially used for an
> UEFI BOOT key, Secure JTAG key, HDMI-HDCP key and vendor specific keys.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)

Speaking of which, any reason why you didn't add the A10s support in
your second patch?

> Allwinner sun7i (A20)
> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  Documentation/ABI/stable/sysfs-driver-sunxi-sid    |  22 +++
>  .../bindings/misc/allwinner,sunxi-sid.txt          |  16 ++
>  drivers/misc/eeprom/Kconfig                        |  19 +++
>  drivers/misc/eeprom/Makefile                       |   1 +
>  drivers/misc/eeprom/sunxi_sid.c                    | 177 +++++++++++++++++++++
>  5 files changed, 235 insertions(+)
>  create mode 100644 Documentation/ABI/stable/sysfs-driver-sunxi-sid
>  create mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> 
> diff --git a/Documentation/ABI/stable/sysfs-driver-sunxi-sid b/Documentation/ABI/stable/sysfs-driver-sunxi-sid
> new file mode 100644
> index 0000000..b04ec05
> --- /dev/null
> +++ b/Documentation/ABI/stable/sysfs-driver-sunxi-sid

I'm not sure this should go to the stable directory directly. Greg?
Isn't it suppose to go through testing/ before making it to stable/ ?

> @@ -0,0 +1,22 @@
> +What:		/sys/devices/soc.0/1c23800.eeprom/eeprom
                                     ^ and ^
are dynamic and depends on the number of instances of your driver, (in
this case) the base address of the device, the name of the root node in
the device tree, etc. so I wouldn't hardcode that in the documentation.

Sotheming like /sys/devices/*/<our-device>/eeprom maybe? 

> +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
> new file mode 100644
> index 0000000..2103a44
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
> @@ -0,0 +1,16 @@
> +Allwinner sunxi-sid
> +
> +Required properties:
> +- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-sid".
> +- reg: Should contain registers location and length
> +
> +Example for sun4i:
> +	sid@01c23800 {
> +		compatible = "allwinner,sun4i-sid";
> +		reg = <0x01c23800 0x10>
> +	};
> +Example for sun7i
> +	sid@01c23800 {
> +		compatible = "allwinner,sun7i-sid";
> +		reg = <0x01c23800 0x200>
> +	};
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..bc6a14c 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,23 @@ 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.
> +	  Currently supported are:
> +		sun4i (A10)
> +		sun5i (A10s, A13)
> +		sun7i (A20)

I'm not sure I like the currently supported driver list to be in
Kconfig. That means that you'll have to duplicate in with the driver and
the Documentation, I'm not sure it's worth it.

> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID

And I'm not very eager about putting URL there either. If the domain
name ever has to changed, or the wiki page changes, or whatever, you're
screwed.

> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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
> new file mode 100644
> index 0000000..6fac205
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,177 @@
> +/*
> + * 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/init.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 resuls in somewhat slower code and
> + * uses 4 times more reads as needed but keeps code simpler. Since the SID is
> + * only very rarly 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 struct bin_attribute *sunxi_sid_bin_attrs[] = {
> +	&sid_bin_attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group sunxi_sid_group = {
> +	.bin_attrs = sunxi_sid_bin_attrs,
> +};
> +
> +static const struct attribute_group *sunxi_sid_groups[] = {
> +	&sunxi_sid_group,
> +	NULL,
> +};
> +
> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +	struct sunxi_sid_data *sid_data;
> +
> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr); /* fixme */
> +	sid_data = platform_get_drvdata(pdev);
> +	devm_kfree(&pdev->dev, sid_data);
> +	dev_dbg(&pdev->dev, "driver unloaded\n");
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sunxi_sid_of_match[] = {
> +	{ .compatible = "allwinner,sun4i-sid", .data = (void *)16},
> +	{ .compatible = "allwinner,sun7i-sid", .data = (void *)512},
> +	{/* sentinel */},
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> +
> +static int __init 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; /* ugly */

Ugly? Why?

> +	if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) /* fixme */

And what is there to fix here?

For these two comments, either explain what you find so ugly/broken so
that someone reading your code can get what is wrong, or just remove
them, because keeping them like that is just confusing.

Maxime

> +		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,
> +		.owner = THIS_MODULE,
> +		.of_match_table = sunxi_sid_of_match,
> +		/* .groups = sunxi_sid_groups, proper way */
> +	},
> +};
> +module_platform_driver(sunxi_sid_driver);
> +
> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> +MODULE_LICENSE("GPL");
> -- 
> 1.8.1.5
> 

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-08-27 15:42     ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-08-27 15:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Aug 27, 2013 at 04:13:04PM +0200, oliver+list at schinagl.nl wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> node.
> 
> These fuses are most likly to be programmed at the factory, encoding
                       ^ likely
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. To write these fuses however,
> a 2.5 V programming voltage needs to be applied to this pin.
> 
> Even so, they can still be used to generate a board-unique mac from,
> board unique RSA key and seed the kernel RNG.
> 
> On sun7i additional storage is available, this is initially used for an
> UEFI BOOT key, Secure JTAG key, HDMI-HDCP key and vendor specific keys.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)

Speaking of which, any reason why you didn't add the A10s support in
your second patch?

> Allwinner sun7i (A20)
> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  Documentation/ABI/stable/sysfs-driver-sunxi-sid    |  22 +++
>  .../bindings/misc/allwinner,sunxi-sid.txt          |  16 ++
>  drivers/misc/eeprom/Kconfig                        |  19 +++
>  drivers/misc/eeprom/Makefile                       |   1 +
>  drivers/misc/eeprom/sunxi_sid.c                    | 177 +++++++++++++++++++++
>  5 files changed, 235 insertions(+)
>  create mode 100644 Documentation/ABI/stable/sysfs-driver-sunxi-sid
>  create mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> 
> diff --git a/Documentation/ABI/stable/sysfs-driver-sunxi-sid b/Documentation/ABI/stable/sysfs-driver-sunxi-sid
> new file mode 100644
> index 0000000..b04ec05
> --- /dev/null
> +++ b/Documentation/ABI/stable/sysfs-driver-sunxi-sid

I'm not sure this should go to the stable directory directly. Greg?
Isn't it suppose to go through testing/ before making it to stable/ ?

> @@ -0,0 +1,22 @@
> +What:		/sys/devices/soc.0/1c23800.eeprom/eeprom
                                     ^ and ^
are dynamic and depends on the number of instances of your driver, (in
this case) the base address of the device, the name of the root node in
the device tree, etc. so I wouldn't hardcode that in the documentation.

Sotheming like /sys/devices/*/<our-device>/eeprom maybe? 

> +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
> new file mode 100644
> index 0000000..2103a44
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
> @@ -0,0 +1,16 @@
> +Allwinner sunxi-sid
> +
> +Required properties:
> +- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-sid".
> +- reg: Should contain registers location and length
> +
> +Example for sun4i:
> +	sid at 01c23800 {
> +		compatible = "allwinner,sun4i-sid";
> +		reg = <0x01c23800 0x10>
> +	};
> +Example for sun7i
> +	sid at 01c23800 {
> +		compatible = "allwinner,sun7i-sid";
> +		reg = <0x01c23800 0x200>
> +	};
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..bc6a14c 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,23 @@ 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.
> +	  Currently supported are:
> +		sun4i (A10)
> +		sun5i (A10s, A13)
> +		sun7i (A20)

I'm not sure I like the currently supported driver list to be in
Kconfig. That means that you'll have to duplicate in with the driver and
the Documentation, I'm not sure it's worth it.

> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID

And I'm not very eager about putting URL there either. If the domain
name ever has to changed, or the wiki page changes, or whatever, you're
screwed.

> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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
> new file mode 100644
> index 0000000..6fac205
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,177 @@
> +/*
> + * 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/init.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 resuls in somewhat slower code and
> + * uses 4 times more reads as needed but keeps code simpler. Since the SID is
> + * only very rarly 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 struct bin_attribute *sunxi_sid_bin_attrs[] = {
> +	&sid_bin_attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group sunxi_sid_group = {
> +	.bin_attrs = sunxi_sid_bin_attrs,
> +};
> +
> +static const struct attribute_group *sunxi_sid_groups[] = {
> +	&sunxi_sid_group,
> +	NULL,
> +};
> +
> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +	struct sunxi_sid_data *sid_data;
> +
> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr); /* fixme */
> +	sid_data = platform_get_drvdata(pdev);
> +	devm_kfree(&pdev->dev, sid_data);
> +	dev_dbg(&pdev->dev, "driver unloaded\n");
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sunxi_sid_of_match[] = {
> +	{ .compatible = "allwinner,sun4i-sid", .data = (void *)16},
> +	{ .compatible = "allwinner,sun7i-sid", .data = (void *)512},
> +	{/* sentinel */},
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> +
> +static int __init 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; /* ugly */

Ugly? Why?

> +	if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) /* fixme */

And what is there to fix here?

For these two comments, either explain what you find so ugly/broken so
that someone reading your code can get what is wrong, or just remove
them, because keeping them like that is just confusing.

Maxime

> +		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,
> +		.owner = THIS_MODULE,
> +		.of_match_table = sunxi_sid_of_match,
> +		/* .groups = sunxi_sid_groups, proper way */
> +	},
> +};
> +module_platform_driver(sunxi_sid_driver);
> +
> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> +MODULE_LICENSE("GPL");
> -- 
> 1.8.1.5
> 

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130827/c7835b7a/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-08-27 14:13 [PATCHv5 0/2] Driver for Allwinner sunxi Security ID oliver+list
@ 2013-08-27 14:13   ` oliver+list at schinagl.nl
  0 siblings, 0 replies; 142+ messages in thread
From: oliver+list @ 2013-08-27 14:13 UTC (permalink / raw)
  To: arnd, gregkh
  Cc: linux-arm-kernel, linux, linus.walleij, linux-kernel,
	andy.shevchenko, maxime.ripard, tomasz.figa, Oliver Schinagl

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses, seeds the kernel entropy and exports them as a sysfs
node.

These fuses are most likly to be programmed at the factory, encoding
things like Chip ID, some sort of serial number etc and appear to be
reasonable unique.
While in theory, these should be writeable by the user, it will probably
be inconvinient to do so. Allwinner recommends that a certain input pin,
labeled 'efuse_vddq', be connected to GND. To write these fuses however,
a 2.5 V programming voltage needs to be applied to this pin.

Even so, they can still be used to generate a board-unique mac from,
board unique RSA key and seed the kernel RNG.

On sun7i additional storage is available, this is initially used for an
UEFI BOOT key, Secure JTAG key, HDMI-HDCP key and vendor specific keys.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A10s, A13)
Allwinner sun7i (A20)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 Documentation/ABI/stable/sysfs-driver-sunxi-sid    |  22 +++
 .../bindings/misc/allwinner,sunxi-sid.txt          |  16 ++
 drivers/misc/eeprom/Kconfig                        |  19 +++
 drivers/misc/eeprom/Makefile                       |   1 +
 drivers/misc/eeprom/sunxi_sid.c                    | 177 +++++++++++++++++++++
 5 files changed, 235 insertions(+)
 create mode 100644 Documentation/ABI/stable/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/Documentation/ABI/stable/sysfs-driver-sunxi-sid b/Documentation/ABI/stable/sysfs-driver-sunxi-sid
new file mode 100644
index 0000000..b04ec05
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-driver-sunxi-sid
@@ -0,0 +1,22 @@
+What:		/sys/devices/soc.0/1c23800.eeprom/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
new file mode 100644
index 0000000..2103a44
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
@@ -0,0 +1,16 @@
+Allwinner sunxi-sid
+
+Required properties:
+- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-sid".
+- reg: Should contain registers location and length
+
+Example for sun4i:
+	sid@01c23800 {
+		compatible = "allwinner,sun4i-sid";
+		reg = <0x01c23800 0x10>
+	};
+Example for sun7i
+	sid@01c23800 {
+		compatible = "allwinner,sun7i-sid";
+		reg = <0x01c23800 0x200>
+	};
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..bc6a14c 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,23 @@ 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.
+	  Currently supported are:
+		sun4i (A10)
+		sun5i (A10s, A13)
+		sun7i (A20)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..6fac205
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,177 @@
+/*
+ * 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/init.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 resuls in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarly 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 struct bin_attribute *sunxi_sid_bin_attrs[] = {
+	&sid_bin_attr,
+	NULL,
+};
+
+static const struct attribute_group sunxi_sid_group = {
+	.bin_attrs = sunxi_sid_bin_attrs,
+};
+
+static const struct attribute_group *sunxi_sid_groups[] = {
+	&sunxi_sid_group,
+	NULL,
+};
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	struct sunxi_sid_data *sid_data;
+
+	device_remove_bin_file(&pdev->dev, &sid_bin_attr); /* fixme */
+	sid_data = platform_get_drvdata(pdev);
+	devm_kfree(&pdev->dev, sid_data);
+	dev_dbg(&pdev->dev, "driver unloaded\n");
+
+	return 0;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-sid", .data = (void *)16},
+	{ .compatible = "allwinner,sun7i-sid", .data = (void *)512},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static int __init 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; /* ugly */
+	if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) /* fixme */
+		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,
+		.owner = THIS_MODULE,
+		.of_match_table = sunxi_sid_of_match,
+		/* .groups = sunxi_sid_groups, proper way */
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
-- 
1.8.1.5


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-08-27 14:13   ` oliver+list at schinagl.nl
  0 siblings, 0 replies; 142+ messages in thread
From: oliver+list at schinagl.nl @ 2013-08-27 14:13 UTC (permalink / raw)
  To: linux-arm-kernel

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses, seeds the kernel entropy and exports them as a sysfs
node.

These fuses are most likly to be programmed at the factory, encoding
things like Chip ID, some sort of serial number etc and appear to be
reasonable unique.
While in theory, these should be writeable by the user, it will probably
be inconvinient to do so. Allwinner recommends that a certain input pin,
labeled 'efuse_vddq', be connected to GND. To write these fuses however,
a 2.5 V programming voltage needs to be applied to this pin.

Even so, they can still be used to generate a board-unique mac from,
board unique RSA key and seed the kernel RNG.

On sun7i additional storage is available, this is initially used for an
UEFI BOOT key, Secure JTAG key, HDMI-HDCP key and vendor specific keys.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A10s, A13)
Allwinner sun7i (A20)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 Documentation/ABI/stable/sysfs-driver-sunxi-sid    |  22 +++
 .../bindings/misc/allwinner,sunxi-sid.txt          |  16 ++
 drivers/misc/eeprom/Kconfig                        |  19 +++
 drivers/misc/eeprom/Makefile                       |   1 +
 drivers/misc/eeprom/sunxi_sid.c                    | 177 +++++++++++++++++++++
 5 files changed, 235 insertions(+)
 create mode 100644 Documentation/ABI/stable/sysfs-driver-sunxi-sid
 create mode 100644 Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/Documentation/ABI/stable/sysfs-driver-sunxi-sid b/Documentation/ABI/stable/sysfs-driver-sunxi-sid
new file mode 100644
index 0000000..b04ec05
--- /dev/null
+++ b/Documentation/ABI/stable/sysfs-driver-sunxi-sid
@@ -0,0 +1,22 @@
+What:		/sys/devices/soc.0/1c23800.eeprom/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
new file mode 100644
index 0000000..2103a44
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/allwinner,sunxi-sid.txt
@@ -0,0 +1,16 @@
+Allwinner sunxi-sid
+
+Required properties:
+- compatible: "allwinner,sun4i-sid" or "allwinner,sun7i-sid".
+- reg: Should contain registers location and length
+
+Example for sun4i:
+	sid at 01c23800 {
+		compatible = "allwinner,sun4i-sid";
+		reg = <0x01c23800 0x10>
+	};
+Example for sun7i
+	sid at 01c23800 {
+		compatible = "allwinner,sun7i-sid";
+		reg = <0x01c23800 0x200>
+	};
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..bc6a14c 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,23 @@ 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.
+	  Currently supported are:
+		sun4i (A10)
+		sun5i (A10s, A13)
+		sun7i (A20)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..6fac205
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,177 @@
+/*
+ * 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/init.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 resuls in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarly 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 struct bin_attribute *sunxi_sid_bin_attrs[] = {
+	&sid_bin_attr,
+	NULL,
+};
+
+static const struct attribute_group sunxi_sid_group = {
+	.bin_attrs = sunxi_sid_bin_attrs,
+};
+
+static const struct attribute_group *sunxi_sid_groups[] = {
+	&sunxi_sid_group,
+	NULL,
+};
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	struct sunxi_sid_data *sid_data;
+
+	device_remove_bin_file(&pdev->dev, &sid_bin_attr); /* fixme */
+	sid_data = platform_get_drvdata(pdev);
+	devm_kfree(&pdev->dev, sid_data);
+	dev_dbg(&pdev->dev, "driver unloaded\n");
+
+	return 0;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-sid", .data = (void *)16},
+	{ .compatible = "allwinner,sun7i-sid", .data = (void *)512},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static int __init 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; /* ugly */
+	if (device_create_bin_file(&pdev->dev, &sid_bin_attr)) /* fixme */
+		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,
+		.owner = THIS_MODULE,
+		.of_match_table = sunxi_sid_of_match,
+		/* .groups = sunxi_sid_groups, proper way */
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
-- 
1.8.1.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 13:23             ` Tomasz Figa
@ 2013-06-17 13:47               ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 13:47 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: linux-arm-kernel, Tomasz Figa, linux, arnd, Oliver Schinagl,
	gregkh, linus.walleij, linux-kernel, andy.shevchenko,
	maxime.ripard, linux-sunxi

On 17-06-13 15:23, Tomasz Figa wrote:
> On Monday 17 of June 2013 15:10:47 Oliver Schinagl wrote:
>> On 17-06-13 14:51, Tomasz Figa wrote:
>>> On Monday 17 of June 2013 12:36:47 Oliver Schinagl wrote:
>>>> On 15-06-13 12:28, Tomasz Figa wrote:
<snip>
>> Now we pass this array to add_randomness(array, 16). So add_randomness
>> sees 16 ints in an array. So while there will be a lot of extra zero's,
>> there still be 16 elements copied/processed, no?
>
> The second argument of add_randomness is number of bytes, not number of
> elements in array, as far as I can tell.
Oh wow, very good catch. I had to dig a little into the source where it
said 'nbytes'. I guess the function prototype would have been nicer if it
said nbytes instead of size.

Anyway, with using an array of u8 this is nicely handled.

> Best regards,
> Tomasz
>
oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 13:47               ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 13:47 UTC (permalink / raw)
  To: linux-arm-kernel

On 17-06-13 15:23, Tomasz Figa wrote:
> On Monday 17 of June 2013 15:10:47 Oliver Schinagl wrote:
>> On 17-06-13 14:51, Tomasz Figa wrote:
>>> On Monday 17 of June 2013 12:36:47 Oliver Schinagl wrote:
>>>> On 15-06-13 12:28, Tomasz Figa wrote:
<snip>
>> Now we pass this array to add_randomness(array, 16). So add_randomness
>> sees 16 ints in an array. So while there will be a lot of extra zero's,
>> there still be 16 elements copied/processed, no?
>
> The second argument of add_randomness is number of bytes, not number of
> elements in array, as far as I can tell.
Oh wow, very good catch. I had to dig a little into the source where it
said 'nbytes'. I guess the function prototype would have been nicer if it
said nbytes instead of size.

Anyway, with using an array of u8 this is nicely handled.

> Best regards,
> Tomasz
>
oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 13:10           ` Oliver Schinagl
@ 2013-06-17 13:23             ` Tomasz Figa
  -1 siblings, 0 replies; 142+ messages in thread
From: Tomasz Figa @ 2013-06-17 13:23 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: linux-arm-kernel, Tomasz Figa, linux, arnd, Oliver Schinagl,
	gregkh, linus.walleij, linux-kernel, andy.shevchenko,
	maxime.ripard, linux-sunxi

On Monday 17 of June 2013 15:10:47 Oliver Schinagl wrote:
> On 17-06-13 14:51, Tomasz Figa wrote:
> > On Monday 17 of June 2013 12:36:47 Oliver Schinagl wrote:
> >> On 15-06-13 12:28, Tomasz Figa wrote:
> >>> Hi,
> >>> 
> >>> Some comments inline.
> >> 
> >> Thank you
> > 
> > You're welcome. :)
> > 
> >>> On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
> >>>> From: Oliver Schinagl <oliver@schinagl.nl>
> >>>> 
> >>>> Allwinner has electric fuses (efuse) on their line of chips. This
> >>>> driver
> >>>> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> >>>> node.
> 
> <snip>
> 
> >> I will change the comment, 'and 4 byte sized keys per SID' is probably
> >> better
> >> The array is 128 bits split into 32 bit words. Each 32 bit word consists
> >> of 8 bits (1 byte).
> >> So 4 * 4 = 16 bytes (SID_SIZE), is 128 bits.
> > 
> > What about:
> > 	/* There are 4 keys. */
> > 	#define SID_KEYS 4
> > 	/* Each key is 4 byte long (32-bit). */
> > 	#define SID_SIZE (SID_KEYS * 4)
> 
> I'll ommit the 'long (32-bit)' part but yeah that's probably enough.
> 
> <snip>
> 
> >>>> +
> >>>> +	if (offset >= SID_SIZE)
> >>>> +		goto exit;
> >>>> 
> >>> 		return 0; ...
> >> 
> >> I did say in the changelog I opted for goto over return. But since
> >> everybody keeps preferring returns (I personally like 'one single exit
> >> point much more' I have already changed it all over to many returns, who
> >> am I to argue :)
> > 
> > Well, single exit points makes sense (and is much nicer) when you have
> > something to do before exiting, take error paths as an example. But
> > jumping
> > just to return makes no sense, because when reading the code you must
> > scroll down to the label to check what actually happens.
> 
> But functions shouldn't be so large :p But that is the first reasonable
> reason I can live with :)
> 
> <snip>
> 
> >>>> +
> >>>> +	for (i = 0; i < SID_SIZE; i++)
> >>>> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
> >>> 
> >>> You seem to read bytes into an array of ints. Your entropy data will
> >>> always have most significant 24-bits cleared. Is this behavior correct?
> >> 
> >> Yes, though I changed it so that entropy is an array of u8's, since
> >> that's what sunxi_sid_read_byte returns.
> >> 
> >>>> +	add_device_randomness(entropy, SID_SIZE);
> >>> 
> >>> Now I'm pretty sure that above is not the correct behavior. You are
> >>> adding
> >>> here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16
> >>> ints (=4*SID_SIZE)...
> >> 
> >> Well technically, doesn't to compiler see that entropy is never larger
> >> then 8 bits and thus uses only 8 bits? uint8_atleast or something. But
> >> yeah, it's better to use the specified size to not waste 24 empty bits.
> > 
> > I mean, the loop fills the array with SID_SIZE ints, each with 3 zero
> > bytes and 1 byte of actual data, so you get:
> > 
> > S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S15 0x00 0x00 0x00
> 
> Ok, I get that
> 
> > but by calling add_device_randomness() with SID_SIZE as size argument, you
> > add only 16 first bytes of data from the array:
> > 
> > S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S3 0x00 0x00 0x00
> 
> That bit I'm not quite sure I understand:
> 
> We have an array of ints, { 0x00000000, 0x00000000, 0x00000000 .... }
> We read 1 byte and copy it to the array (x16) (say sid = 0xdeadbeef...)
> { 0x000000de, 0x000000ad, 0x000000be, ... }
> 
> Now we pass this array to add_randomness(array, 16). So add_randomness
> sees 16 ints in an array. So while there will be a lot of extra zero's,
> there still be 16 elements copied/processed, no?

The second argument of add_randomness is number of bytes, not number of 
elements in array, as far as I can tell.

Best regards,
Tomasz

> Otherwise, how does add_randomness() know it's dealing with bytes or
> ints? it just see's the pointer to an int array that is 16 long? Or what
> am I overlooking?
> 
> I did already change the array to be u8 big so it is only to help me
> understand.
> 
> > (little endianness assumed)
> > 
> > Best regards,
> > Tomasz
> > 
> > (for rest of comments I think it's enough said in Russell's and Maxime's
> > replies)
> 
> Yes it has :) thanks to all of you
> 
> Oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 13:23             ` Tomasz Figa
  0 siblings, 0 replies; 142+ messages in thread
From: Tomasz Figa @ 2013-06-17 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 17 of June 2013 15:10:47 Oliver Schinagl wrote:
> On 17-06-13 14:51, Tomasz Figa wrote:
> > On Monday 17 of June 2013 12:36:47 Oliver Schinagl wrote:
> >> On 15-06-13 12:28, Tomasz Figa wrote:
> >>> Hi,
> >>> 
> >>> Some comments inline.
> >> 
> >> Thank you
> > 
> > You're welcome. :)
> > 
> >>> On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
> >>>> From: Oliver Schinagl <oliver@schinagl.nl>
> >>>> 
> >>>> Allwinner has electric fuses (efuse) on their line of chips. This
> >>>> driver
> >>>> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> >>>> node.
> 
> <snip>
> 
> >> I will change the comment, 'and 4 byte sized keys per SID' is probably
> >> better
> >> The array is 128 bits split into 32 bit words. Each 32 bit word consists
> >> of 8 bits (1 byte).
> >> So 4 * 4 = 16 bytes (SID_SIZE), is 128 bits.
> > 
> > What about:
> > 	/* There are 4 keys. */
> > 	#define SID_KEYS 4
> > 	/* Each key is 4 byte long (32-bit). */
> > 	#define SID_SIZE (SID_KEYS * 4)
> 
> I'll ommit the 'long (32-bit)' part but yeah that's probably enough.
> 
> <snip>
> 
> >>>> +
> >>>> +	if (offset >= SID_SIZE)
> >>>> +		goto exit;
> >>>> 
> >>> 		return 0; ...
> >> 
> >> I did say in the changelog I opted for goto over return. But since
> >> everybody keeps preferring returns (I personally like 'one single exit
> >> point much more' I have already changed it all over to many returns, who
> >> am I to argue :)
> > 
> > Well, single exit points makes sense (and is much nicer) when you have
> > something to do before exiting, take error paths as an example. But
> > jumping
> > just to return makes no sense, because when reading the code you must
> > scroll down to the label to check what actually happens.
> 
> But functions shouldn't be so large :p But that is the first reasonable
> reason I can live with :)
> 
> <snip>
> 
> >>>> +
> >>>> +	for (i = 0; i < SID_SIZE; i++)
> >>>> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
> >>> 
> >>> You seem to read bytes into an array of ints. Your entropy data will
> >>> always have most significant 24-bits cleared. Is this behavior correct?
> >> 
> >> Yes, though I changed it so that entropy is an array of u8's, since
> >> that's what sunxi_sid_read_byte returns.
> >> 
> >>>> +	add_device_randomness(entropy, SID_SIZE);
> >>> 
> >>> Now I'm pretty sure that above is not the correct behavior. You are
> >>> adding
> >>> here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16
> >>> ints (=4*SID_SIZE)...
> >> 
> >> Well technically, doesn't to compiler see that entropy is never larger
> >> then 8 bits and thus uses only 8 bits? uint8_atleast or something. But
> >> yeah, it's better to use the specified size to not waste 24 empty bits.
> > 
> > I mean, the loop fills the array with SID_SIZE ints, each with 3 zero
> > bytes and 1 byte of actual data, so you get:
> > 
> > S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S15 0x00 0x00 0x00
> 
> Ok, I get that
> 
> > but by calling add_device_randomness() with SID_SIZE as size argument, you
> > add only 16 first bytes of data from the array:
> > 
> > S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S3 0x00 0x00 0x00
> 
> That bit I'm not quite sure I understand:
> 
> We have an array of ints, { 0x00000000, 0x00000000, 0x00000000 .... }
> We read 1 byte and copy it to the array (x16) (say sid = 0xdeadbeef...)
> { 0x000000de, 0x000000ad, 0x000000be, ... }
> 
> Now we pass this array to add_randomness(array, 16). So add_randomness
> sees 16 ints in an array. So while there will be a lot of extra zero's,
> there still be 16 elements copied/processed, no?

The second argument of add_randomness is number of bytes, not number of 
elements in array, as far as I can tell.

Best regards,
Tomasz

> Otherwise, how does add_randomness() know it's dealing with bytes or
> ints? it just see's the pointer to an int array that is 16 long? Or what
> am I overlooking?
> 
> I did already change the array to be u8 big so it is only to help me
> understand.
> 
> > (little endianness assumed)
> > 
> > Best regards,
> > Tomasz
> > 
> > (for rest of comments I think it's enough said in Russell's and Maxime's
> > replies)
> 
> Yes it has :) thanks to all of you
> 
> Oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 12:51         ` Tomasz Figa
@ 2013-06-17 13:10           ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 13:10 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: linux-arm-kernel, Tomasz Figa, linux, arnd, Oliver Schinagl,
	gregkh, linus.walleij, linux-kernel, andy.shevchenko,
	maxime.ripard, linux-sunxi

On 17-06-13 14:51, Tomasz Figa wrote:
> On Monday 17 of June 2013 12:36:47 Oliver Schinagl wrote:
>> On 15-06-13 12:28, Tomasz Figa wrote:
>>> Hi,
>>>
>>> Some comments inline.
>>
>> Thank you
>
> You're welcome. :)
>
>>> On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
>>>> From: Oliver Schinagl <oliver@schinagl.nl>
>>>>
>>>> Allwinner has electric fuses (efuse) on their line of chips. This driver
>>>> reads those fuses, seeds the kernel entropy and exports them as a sysfs
>>>> node.
<snip>
>> I will change the comment, 'and 4 byte sized keys per SID' is probably
>> better
>> The array is 128 bits split into 32 bit words. Each 32 bit word consists
>> of 8 bits (1 byte).
>> So 4 * 4 = 16 bytes (SID_SIZE), is 128 bits.
>>
>
> What about:
>
> 	/* There are 4 keys. */
> 	#define SID_KEYS 4
> 	/* Each key is 4 byte long (32-bit). */
> 	#define SID_SIZE (SID_KEYS * 4)
>
I'll ommit the 'long (32-bit)' part but yeah that's probably enough.

<snip>
>>>> +
>>>> +	if (offset >= SID_SIZE)
>>>> +		goto exit;
>>>>
>>> 		return 0; ...
>>
>> I did say in the changelog I opted for goto over return. But since
>> everybody keeps preferring returns (I personally like 'one single exit
>> point much more' I have already changed it all over to many returns, who
>> am I to argue :)
>
> Well, single exit points makes sense (and is much nicer) when you have
> something to do before exiting, take error paths as an example. But jumping
> just to return makes no sense, because when reading the code you must scroll
> down to the label to check what actually happens.
But functions shouldn't be so large :p But that is the first reasonable 
reason I can live with :)

<snip>
>>
>>>> +
>>>> +	for (i = 0; i < SID_SIZE; i++)
>>>> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
>>>
>>> You seem to read bytes into an array of ints. Your entropy data will
>>> always have most significant 24-bits cleared. Is this behavior correct?
>>
>> Yes, though I changed it so that entropy is an array of u8's, since
>> that's what sunxi_sid_read_byte returns.
>>
>>>> +	add_device_randomness(entropy, SID_SIZE);
>>>
>>> Now I'm pretty sure that above is not the correct behavior. You are adding
>>> here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16
>>> ints (=4*SID_SIZE)...
>>
>> Well technically, doesn't to compiler see that entropy is never larger
>> then 8 bits and thus uses only 8 bits? uint8_atleast or something. But
>> yeah, it's better to use the specified size to not waste 24 empty bits.
>
> I mean, the loop fills the array with SID_SIZE ints, each with 3 zero bytes and
> 1 byte of actual data, so you get:
>
> S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S15 0x00 0x00 0x00
>
Ok, I get that
> but by calling add_device_randomness() with SID_SIZE as size argument, you add
> only 16 first bytes of data from the array:
>
> S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S3 0x00 0x00 0x00
That bit I'm not quite sure I understand:

We have an array of ints, { 0x00000000, 0x00000000, 0x00000000 .... }
We read 1 byte and copy it to the array (x16) (say sid = 0xdeadbeef...)
{ 0x000000de, 0x000000ad, 0x000000be, ... }

Now we pass this array to add_randomness(array, 16). So add_randomness 
sees 16 ints in an array. So while there will be a lot of extra zero's, 
there still be 16 elements copied/processed, no?

Otherwise, how does add_randomness() know it's dealing with bytes or 
ints? it just see's the pointer to an int array that is 16 long? Or what 
am I overlooking?

I did already change the array to be u8 big so it is only to help me 
understand.
>
> (little endianness assumed)
>
> Best regards,
> Tomasz
>
> (for rest of comments I think it's enough said in Russell's and Maxime's
> replies)
Yes it has :) thanks to all of you

Oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 13:10           ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 13:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 17-06-13 14:51, Tomasz Figa wrote:
> On Monday 17 of June 2013 12:36:47 Oliver Schinagl wrote:
>> On 15-06-13 12:28, Tomasz Figa wrote:
>>> Hi,
>>>
>>> Some comments inline.
>>
>> Thank you
>
> You're welcome. :)
>
>>> On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
>>>> From: Oliver Schinagl <oliver@schinagl.nl>
>>>>
>>>> Allwinner has electric fuses (efuse) on their line of chips. This driver
>>>> reads those fuses, seeds the kernel entropy and exports them as a sysfs
>>>> node.
<snip>
>> I will change the comment, 'and 4 byte sized keys per SID' is probably
>> better
>> The array is 128 bits split into 32 bit words. Each 32 bit word consists
>> of 8 bits (1 byte).
>> So 4 * 4 = 16 bytes (SID_SIZE), is 128 bits.
>>
>
> What about:
>
> 	/* There are 4 keys. */
> 	#define SID_KEYS 4
> 	/* Each key is 4 byte long (32-bit). */
> 	#define SID_SIZE (SID_KEYS * 4)
>
I'll ommit the 'long (32-bit)' part but yeah that's probably enough.

<snip>
>>>> +
>>>> +	if (offset >= SID_SIZE)
>>>> +		goto exit;
>>>>
>>> 		return 0; ...
>>
>> I did say in the changelog I opted for goto over return. But since
>> everybody keeps preferring returns (I personally like 'one single exit
>> point much more' I have already changed it all over to many returns, who
>> am I to argue :)
>
> Well, single exit points makes sense (and is much nicer) when you have
> something to do before exiting, take error paths as an example. But jumping
> just to return makes no sense, because when reading the code you must scroll
> down to the label to check what actually happens.
But functions shouldn't be so large :p But that is the first reasonable 
reason I can live with :)

<snip>
>>
>>>> +
>>>> +	for (i = 0; i < SID_SIZE; i++)
>>>> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
>>>
>>> You seem to read bytes into an array of ints. Your entropy data will
>>> always have most significant 24-bits cleared. Is this behavior correct?
>>
>> Yes, though I changed it so that entropy is an array of u8's, since
>> that's what sunxi_sid_read_byte returns.
>>
>>>> +	add_device_randomness(entropy, SID_SIZE);
>>>
>>> Now I'm pretty sure that above is not the correct behavior. You are adding
>>> here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16
>>> ints (=4*SID_SIZE)...
>>
>> Well technically, doesn't to compiler see that entropy is never larger
>> then 8 bits and thus uses only 8 bits? uint8_atleast or something. But
>> yeah, it's better to use the specified size to not waste 24 empty bits.
>
> I mean, the loop fills the array with SID_SIZE ints, each with 3 zero bytes and
> 1 byte of actual data, so you get:
>
> S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S15 0x00 0x00 0x00
>
Ok, I get that
> but by calling add_device_randomness() with SID_SIZE as size argument, you add
> only 16 first bytes of data from the array:
>
> S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S3 0x00 0x00 0x00
That bit I'm not quite sure I understand:

We have an array of ints, { 0x00000000, 0x00000000, 0x00000000 .... }
We read 1 byte and copy it to the array (x16) (say sid = 0xdeadbeef...)
{ 0x000000de, 0x000000ad, 0x000000be, ... }

Now we pass this array to add_randomness(array, 16). So add_randomness 
sees 16 ints in an array. So while there will be a lot of extra zero's, 
there still be 16 elements copied/processed, no?

Otherwise, how does add_randomness() know it's dealing with bytes or 
ints? it just see's the pointer to an int array that is 16 long? Or what 
am I overlooking?

I did already change the array to be u8 big so it is only to help me 
understand.
>
> (little endianness assumed)
>
> Best regards,
> Tomasz
>
> (for rest of comments I think it's enough said in Russell's and Maxime's
> replies)
Yes it has :) thanks to all of you

Oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 10:36       ` Oliver Schinagl
@ 2013-06-17 12:51         ` Tomasz Figa
  -1 siblings, 0 replies; 142+ messages in thread
From: Tomasz Figa @ 2013-06-17 12:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Oliver Schinagl, Tomasz Figa, linux, arnd, Oliver Schinagl,
	gregkh, linus.walleij, linux-kernel, andy.shevchenko,
	maxime.ripard

On Monday 17 of June 2013 12:36:47 Oliver Schinagl wrote:
> On 15-06-13 12:28, Tomasz Figa wrote:
> > Hi,
> > 
> > Some comments inline.
> 
> Thank you

You're welcome. :)

> > On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
> >> From: Oliver Schinagl <oliver@schinagl.nl>
> >> 
> >> Allwinner has electric fuses (efuse) on their line of chips. This driver
> >> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> >> node.
> >> 
> >> These fuses are most likly to be programmed at the factory, encoding
> >> things like Chip ID, some sort of serial number etc and appear to be
> >> reasonable unique.
> >> While in theory, these should be writeable by the user, it will probably
> >> be inconvinient to do so. Allwinner recommends that a certain input
> >> pin, labeled 'efuse_vddq', be connected to GND. To write these fuses,
> >> 2.5 V needs to be applied to this pin.
> >> 
> >> Even so, they can still be used to generate a board-unique mac from,
> >> board unique RSA key and seed the kernel RNG.
> >> 
> >> Currently supported are the following known chips:
> >> Allwinner sun4i (A10)
> >> Allwinner sun5i (A10s, A13)
> >> 
> >> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> >> ---
> >> 
> >>   drivers/misc/eeprom/Kconfig     |  17 ++++
> >>   drivers/misc/eeprom/Makefile    |   1 +
> >>   drivers/misc/eeprom/sunxi_sid.c | 167
> >> 
> >> ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185
> >> insertions(+)
> >> 
> >>   create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> >> 
> >> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> >> index 04f2e1f..c7bc6ed 100644
> >> --- a/drivers/misc/eeprom/Kconfig
> >> +++ b/drivers/misc/eeprom/Kconfig
> >> @@ -96,4 +96,21 @@ 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. Currently supported are:
> >> +		sun4i (A10)
> >> +		sun5i (A13)
> >> +
> >> +	  Due to the potential risks involved with changing e-fuses,
> >> +	  this driver is read-only
> >> +
> >> +	  For more information visit http://linux-sunxi.org/SID
> >> +
> >> +	  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 fc1e81d..9507aec 100644
> >> --- a/drivers/misc/eeprom/Makefile
> >> +++ b/drivers/misc/eeprom/Makefile
> >> @@ -4,4 +4,5 @@ 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 new file mode 100644
> >> index 0000000..f014e1b
> >> --- /dev/null
> >> +++ b/drivers/misc/eeprom/sunxi_sid.c
> >> @@ -0,0 +1,167 @@
> >> +/*
> >> + * Copyright (c) 2013 Oliver Schinagl
> >> + * http://www.linux-sunxi.org
> >> + *
> >> + * Oliver Schinagl <oliver@schinagl.nl>
> >> + *
> >> + * 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, a 128 bit eeprom, in
> >> byte + * sized chunks.
> >> + */
> >> +
> >> +#include <linux/compiler.h>
> >> +#include <linux/device.h>
> >> +#include <linux/err.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/export.h>
> >> +#include <linux/fs.h>
> >> +#include <linux/init.h>
> >> +#include <linux/io.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/kobject.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/random.h>
> >> +#include <linux/stat.h>
> >> +#include <linux/sysfs.h>
> >> +#include <linux/types.h>
> >> +
> >> +#define DRV_NAME "sunxi-sid"
> >> +#define DRV_VERSION "1.0"
> > 
> > What is this version thingy?
> > 
> > Is there a versioning scheme defined for this driver? Do you expect it to
> > be changed every modification of this driver?
> > 
> > I don't see any point of having such thing in a project with a version
> > control system, where you have all change history.
> 
> Well we export something to userspace, while trivial there is the
> possibility it changes over time. Say A40 which outputs 256 bits instead
> of the current 128 bits. That would validate a bump in version number.
> It's purely so the user can be aware of differences in the driver. So
> maybe DRV_A[BP]I_VERSION would be better?
> 
> >> +
> >> +/* There are 4 32-bit keys */
> >> +#define SID_KEYS 4
> >> +/* and 4 byte sized keys per 32-bit key */
> >> +#define SID_SIZE (SID_KEYS * 4)
> >> 
> >  From this definition it looks like there are just 4 32-bit keys, I don't
> > 
> > see those extra four byte-sized keys accounted by this size.
> 
> I will change the comment, 'and 4 byte sized keys per SID' is probably
> better
> The array is 128 bits split into 32 bit words. Each 32 bit word consists
> of 8 bits (1 byte).
> So 4 * 4 = 16 bytes (SID_SIZE), is 128 bits.
> 

What about:

	/* There are 4 keys. */
	#define SID_KEYS 4
	/* Each key is 4 byte long (32-bit). */
	#define SID_SIZE (SID_KEYS * 4)

> >> +
> >> +
> > 
> > One _empty_ line is enough to separate definitions from code.
> 
> Okay, I find it personally a little clearer to separate them, but sure.
> 
> >> +/* We read the entire key, but only return the requested byte. This is
> >> of + * course slower then it could be and uses 4 times more reads as
> >> needed but + * keeps code simpler.
> > 
> > I have no idea how often this is going to be read, but since the whole sid
> > is really small (16 bytes), maybe it would be better to simply read the ID
> > in probe to a buffer and then just memcpy from it in read().
> 
> The sid will be read once (well all 16 bytes) during probe and after
> that only on user request. Right now we don't have a user (yet) other
> then the sysfs entry.
> 
> In future, this key can be used to read the MAC (low reads) or AES keys
> for example (also low reads).
> 
> Initially I had such an approach, but Maxime recommended against having
> the value cached.
> 
> As I wrote to andy, the only 'more efficient' way would be to store the
> previously read key and see on the next read if its the same, So best
> case, we could save 4 reads. I think it makes the code unnecessarily
> complex for something that is read so little.

OK. If it's not to be read too often then it's fine.

> >> + */
> >> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> >> +			      const unsigned int offset)
> >> +{
> >> +	u32 sid_key = 0;
> >> 
> > 	u32 sid_key; ...
> 
> Indeed, a left over from a previous version. It does no longer need to
> be initted.
> 
> >> +
> >> +	if (offset >= SID_SIZE)
> >> +		goto exit;
> >> 
> > 		return 0; ...
> 
> I did say in the changelog I opted for goto over return. But since
> everybody keeps preferring returns (I personally like 'one single exit
> point much more' I have already changed it all over to many returns, who
> am I to argue :)

Well, single exit points makes sense (and is much nicer) when you have 
something to do before exiting, take error paths as an example. But jumping 
just to return makes no sense, because when reading the code you must scroll 
down to the label to check what actually happens.

> >> +
> >> +	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
> >> +	sid_key >>= (offset % 4) * 8;
> >> +	sid_key &= 0xff;
> >> +	/* fall through */
> >> +
> > 
> >> +exit:
> > ...and now magically here you can remove two unneeded lines.
> > 
> >> +	return (u8)sid_key;
> > 
> > Unnecessary casting.
> 
> Unnecessary because of the &= 0xff above, or because you can put a 32bit
> int in an 8bit int without worries? (we only want 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)
> >> +{
> >> +	int i;
> >> +	struct platform_device *pdev;
> >> +	void __iomem *sid_reg_base;
> >> +
> >> +	pdev = (struct platform_device
> >> *)to_platform_device(kobj_to_dev(kobj)); +	sid_reg_base = (void
> > 
> > __iomem
> > 
> >> *)platform_get_drvdata(pdev);
> >> +
> >> +	for (i = 0; i < size; i++) {
> >> +		if ((pos + i) >= SID_SIZE || (pos < 0))
> >> +			break;
> >> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> >> +	}
> > 
> > This could be greatly simplified if you just read the whole sid to memory
> > in probe and memcpy from it here.
> 
> But can't because we don't want to cache it.
> 
> >> +	return i;
> >> +}
> >> +
> >> +static const struct of_device_id sunxi_sid_of_match[] = {
> >> +	{
> >> +		.compatible = "allwinner,sun4i-sid",
> >> +	},
> > 
> > Above 3 lines could be put in single line.
> 
> okay
> 
> >> +	{/* sentinel */}
> >> +};
> >> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> >> +
> >> +static const struct bin_attribute sid_bin_attr = {
> >> +	.attr = {
> >> +		.name = "eeprom",
> >> +		.mode = S_IRUGO,
> >> +	},
> >> +	.size = SID_SIZE,
> >> +	.read = sid_read,
> >> +};
> >> +
> >> +static int sunxi_sid_remove(struct platform_device *pdev)
> >> +{
> >> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> >> +	dev_info(&pdev->dev, "sunxi SID driver unloaded\n");
> > 
> > Please either make this dev_dbg or remove it completely, as it is not
> > something that users should be concerned about.
> 
> dev_dbg might be better for the remove, thanks
> 
> >> +	return 0;
> >> +}
> >> +
> >> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> >> +{
> >> +	int entropy[SID_SIZE], i;
> >> +	struct resource *res;
> >> +	void __iomem *sid_reg_base;
> >> +	int ret;
> >> +
> >> +	if (!pdev->dev.of_node) {
> >> +		dev_err(&pdev->dev, "No devicetree data available\n");
> >> +		ret = -ENXIO;
> >> +		goto exit;
> >> +	}
> > 
> > What is this check for? You don't seem to need anything from dev.of_node
> > in this driver.
> 
> My understanding was, that when using the device tree, we check if the
> device tree is atleast available. And we use platform_get_resource,
> doesn't that get the data from the device tree?

When you call platform_get_resource(), it looks at platform_device you pass to 
it and takes all resources from an array that is generated early at bootup (in 
case when DT is available). It will return an error pointer if there is no 
resource satisfying your requirements in this array.

In addition devm_ioremap_resource() checks the resource pointer, so if it's an 
error pointer it will print a message and return an error as well.

> >> +
> >> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >> +	if (IS_ERR(sid_reg_base)) {
> >> +		ret = PTR_ERR(sid_reg_base);
> >> +		goto exit;
> >> +	}
> > 
> > One of the points of having devm_ helpers was removing the need to use
> > error paths at functions end. You can save 2 lines of code by changing
> > 
> > this check to:
> > 	if (IS_ERR(sid_reg_base))
> > 	
> > 		return PTR_ERR(sid_reg_base);
> 
> Okay
> 
> >> +	platform_set_drvdata(pdev, sid_reg_base);
> >> +
> >> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >> +	if (ret) {
> >> +		dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
> >> +		goto exit;
> >> +	}
> > 
> > Same here.
> 
> Yeah, many returns, check
> 
> >> +
> >> +	for (i = 0; i < SID_SIZE; i++)
> >> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
> > 
> > You seem to read bytes into an array of ints. Your entropy data will
> > always have most significant 24-bits cleared. Is this behavior correct?
> 
> Yes, though I changed it so that entropy is an array of u8's, since
> that's what sunxi_sid_read_byte returns.
> 
> >> +	add_device_randomness(entropy, SID_SIZE);
> > 
> > Now I'm pretty sure that above is not the correct behavior. You are adding
> > here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16
> > ints (=4*SID_SIZE)...
> 
> Well technically, doesn't to compiler see that entropy is never larger
> then 8 bits and thus uses only 8 bits? uint8_atleast or something. But
> yeah, it's better to use the specified size to not waste 24 empty bits.

I mean, the loop fills the array with SID_SIZE ints, each with 3 zero bytes and 
1 byte of actual data, so you get:

S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S15 0x00 0x00 0x00

but by calling add_device_randomness() with SID_SIZE as size argument, you add 
only 16 first bytes of data from the array:

S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S3 0x00 0x00 0x00

(little endianness assumed)

Best regards,
Tomasz

(for rest of comments I think it's enough said in Russell's and Maxime's 
replies)

> >> +	dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
> > 
> > Same comment as for the message in remove().
> 
> Though with the DRV_(A[BP]I_)VERSION this is purly informational, I
> changed it to only show in the dev_dbg as requested.
> 
> >> +	ret = 0;
> >> +	/* fall through */
> >> +
> >> +exit:
> >> +	return ret;
> > 
> > Above 4 non-empty lines can be replaced by a single
> > 
> > 	return 0;
> > 	
> >> +}
> >> +
> >> +static struct platform_driver sunxi_sid_driver = {
> >> +	.probe = sunxi_sid_probe,
> >> +	.remove = sunxi_sid_remove,
> >> +	.driver = {
> >> +		.name = DRV_NAME,
> >> +		.owner = THIS_MODULE,
> >> +		.of_match_table = sunxi_sid_of_match,
> >> +	},
> >> +};
> >> +module_platform_driver(sunxi_sid_driver);
> >> +
> >> +
> > 
> > One empty line is enough.
> 
> Okay
> 
> > Best regards,
> > Tomasz
> > 
> >> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> >> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> >> +MODULE_VERSION(DRV_VERSION);
> >> +MODULE_LICENSE("GPL");
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 12:51         ` Tomasz Figa
  0 siblings, 0 replies; 142+ messages in thread
From: Tomasz Figa @ 2013-06-17 12:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 17 of June 2013 12:36:47 Oliver Schinagl wrote:
> On 15-06-13 12:28, Tomasz Figa wrote:
> > Hi,
> > 
> > Some comments inline.
> 
> Thank you

You're welcome. :)

> > On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
> >> From: Oliver Schinagl <oliver@schinagl.nl>
> >> 
> >> Allwinner has electric fuses (efuse) on their line of chips. This driver
> >> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> >> node.
> >> 
> >> These fuses are most likly to be programmed at the factory, encoding
> >> things like Chip ID, some sort of serial number etc and appear to be
> >> reasonable unique.
> >> While in theory, these should be writeable by the user, it will probably
> >> be inconvinient to do so. Allwinner recommends that a certain input
> >> pin, labeled 'efuse_vddq', be connected to GND. To write these fuses,
> >> 2.5 V needs to be applied to this pin.
> >> 
> >> Even so, they can still be used to generate a board-unique mac from,
> >> board unique RSA key and seed the kernel RNG.
> >> 
> >> Currently supported are the following known chips:
> >> Allwinner sun4i (A10)
> >> Allwinner sun5i (A10s, A13)
> >> 
> >> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> >> ---
> >> 
> >>   drivers/misc/eeprom/Kconfig     |  17 ++++
> >>   drivers/misc/eeprom/Makefile    |   1 +
> >>   drivers/misc/eeprom/sunxi_sid.c | 167
> >> 
> >> ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185
> >> insertions(+)
> >> 
> >>   create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> >> 
> >> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> >> index 04f2e1f..c7bc6ed 100644
> >> --- a/drivers/misc/eeprom/Kconfig
> >> +++ b/drivers/misc/eeprom/Kconfig
> >> @@ -96,4 +96,21 @@ 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. Currently supported are:
> >> +		sun4i (A10)
> >> +		sun5i (A13)
> >> +
> >> +	  Due to the potential risks involved with changing e-fuses,
> >> +	  this driver is read-only
> >> +
> >> +	  For more information visit http://linux-sunxi.org/SID
> >> +
> >> +	  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 fc1e81d..9507aec 100644
> >> --- a/drivers/misc/eeprom/Makefile
> >> +++ b/drivers/misc/eeprom/Makefile
> >> @@ -4,4 +4,5 @@ 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 new file mode 100644
> >> index 0000000..f014e1b
> >> --- /dev/null
> >> +++ b/drivers/misc/eeprom/sunxi_sid.c
> >> @@ -0,0 +1,167 @@
> >> +/*
> >> + * Copyright (c) 2013 Oliver Schinagl
> >> + * http://www.linux-sunxi.org
> >> + *
> >> + * Oliver Schinagl <oliver@schinagl.nl>
> >> + *
> >> + * 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, a 128 bit eeprom, in
> >> byte + * sized chunks.
> >> + */
> >> +
> >> +#include <linux/compiler.h>
> >> +#include <linux/device.h>
> >> +#include <linux/err.h>
> >> +#include <linux/errno.h>
> >> +#include <linux/export.h>
> >> +#include <linux/fs.h>
> >> +#include <linux/init.h>
> >> +#include <linux/io.h>
> >> +#include <linux/kernel.h>
> >> +#include <linux/kobject.h>
> >> +#include <linux/module.h>
> >> +#include <linux/of_address.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/random.h>
> >> +#include <linux/stat.h>
> >> +#include <linux/sysfs.h>
> >> +#include <linux/types.h>
> >> +
> >> +#define DRV_NAME "sunxi-sid"
> >> +#define DRV_VERSION "1.0"
> > 
> > What is this version thingy?
> > 
> > Is there a versioning scheme defined for this driver? Do you expect it to
> > be changed every modification of this driver?
> > 
> > I don't see any point of having such thing in a project with a version
> > control system, where you have all change history.
> 
> Well we export something to userspace, while trivial there is the
> possibility it changes over time. Say A40 which outputs 256 bits instead
> of the current 128 bits. That would validate a bump in version number.
> It's purely so the user can be aware of differences in the driver. So
> maybe DRV_A[BP]I_VERSION would be better?
> 
> >> +
> >> +/* There are 4 32-bit keys */
> >> +#define SID_KEYS 4
> >> +/* and 4 byte sized keys per 32-bit key */
> >> +#define SID_SIZE (SID_KEYS * 4)
> >> 
> >  From this definition it looks like there are just 4 32-bit keys, I don't
> > 
> > see those extra four byte-sized keys accounted by this size.
> 
> I will change the comment, 'and 4 byte sized keys per SID' is probably
> better
> The array is 128 bits split into 32 bit words. Each 32 bit word consists
> of 8 bits (1 byte).
> So 4 * 4 = 16 bytes (SID_SIZE), is 128 bits.
> 

What about:

	/* There are 4 keys. */
	#define SID_KEYS 4
	/* Each key is 4 byte long (32-bit). */
	#define SID_SIZE (SID_KEYS * 4)

> >> +
> >> +
> > 
> > One _empty_ line is enough to separate definitions from code.
> 
> Okay, I find it personally a little clearer to separate them, but sure.
> 
> >> +/* We read the entire key, but only return the requested byte. This is
> >> of + * course slower then it could be and uses 4 times more reads as
> >> needed but + * keeps code simpler.
> > 
> > I have no idea how often this is going to be read, but since the whole sid
> > is really small (16 bytes), maybe it would be better to simply read the ID
> > in probe to a buffer and then just memcpy from it in read().
> 
> The sid will be read once (well all 16 bytes) during probe and after
> that only on user request. Right now we don't have a user (yet) other
> then the sysfs entry.
> 
> In future, this key can be used to read the MAC (low reads) or AES keys
> for example (also low reads).
> 
> Initially I had such an approach, but Maxime recommended against having
> the value cached.
> 
> As I wrote to andy, the only 'more efficient' way would be to store the
> previously read key and see on the next read if its the same, So best
> case, we could save 4 reads. I think it makes the code unnecessarily
> complex for something that is read so little.

OK. If it's not to be read too often then it's fine.

> >> + */
> >> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> >> +			      const unsigned int offset)
> >> +{
> >> +	u32 sid_key = 0;
> >> 
> > 	u32 sid_key; ...
> 
> Indeed, a left over from a previous version. It does no longer need to
> be initted.
> 
> >> +
> >> +	if (offset >= SID_SIZE)
> >> +		goto exit;
> >> 
> > 		return 0; ...
> 
> I did say in the changelog I opted for goto over return. But since
> everybody keeps preferring returns (I personally like 'one single exit
> point much more' I have already changed it all over to many returns, who
> am I to argue :)

Well, single exit points makes sense (and is much nicer) when you have 
something to do before exiting, take error paths as an example. But jumping 
just to return makes no sense, because when reading the code you must scroll 
down to the label to check what actually happens.

> >> +
> >> +	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
> >> +	sid_key >>= (offset % 4) * 8;
> >> +	sid_key &= 0xff;
> >> +	/* fall through */
> >> +
> > 
> >> +exit:
> > ...and now magically here you can remove two unneeded lines.
> > 
> >> +	return (u8)sid_key;
> > 
> > Unnecessary casting.
> 
> Unnecessary because of the &= 0xff above, or because you can put a 32bit
> int in an 8bit int without worries? (we only want 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)
> >> +{
> >> +	int i;
> >> +	struct platform_device *pdev;
> >> +	void __iomem *sid_reg_base;
> >> +
> >> +	pdev = (struct platform_device
> >> *)to_platform_device(kobj_to_dev(kobj)); +	sid_reg_base = (void
> > 
> > __iomem
> > 
> >> *)platform_get_drvdata(pdev);
> >> +
> >> +	for (i = 0; i < size; i++) {
> >> +		if ((pos + i) >= SID_SIZE || (pos < 0))
> >> +			break;
> >> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> >> +	}
> > 
> > This could be greatly simplified if you just read the whole sid to memory
> > in probe and memcpy from it here.
> 
> But can't because we don't want to cache it.
> 
> >> +	return i;
> >> +}
> >> +
> >> +static const struct of_device_id sunxi_sid_of_match[] = {
> >> +	{
> >> +		.compatible = "allwinner,sun4i-sid",
> >> +	},
> > 
> > Above 3 lines could be put in single line.
> 
> okay
> 
> >> +	{/* sentinel */}
> >> +};
> >> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> >> +
> >> +static const struct bin_attribute sid_bin_attr = {
> >> +	.attr = {
> >> +		.name = "eeprom",
> >> +		.mode = S_IRUGO,
> >> +	},
> >> +	.size = SID_SIZE,
> >> +	.read = sid_read,
> >> +};
> >> +
> >> +static int sunxi_sid_remove(struct platform_device *pdev)
> >> +{
> >> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> >> +	dev_info(&pdev->dev, "sunxi SID driver unloaded\n");
> > 
> > Please either make this dev_dbg or remove it completely, as it is not
> > something that users should be concerned about.
> 
> dev_dbg might be better for the remove, thanks
> 
> >> +	return 0;
> >> +}
> >> +
> >> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> >> +{
> >> +	int entropy[SID_SIZE], i;
> >> +	struct resource *res;
> >> +	void __iomem *sid_reg_base;
> >> +	int ret;
> >> +
> >> +	if (!pdev->dev.of_node) {
> >> +		dev_err(&pdev->dev, "No devicetree data available\n");
> >> +		ret = -ENXIO;
> >> +		goto exit;
> >> +	}
> > 
> > What is this check for? You don't seem to need anything from dev.of_node
> > in this driver.
> 
> My understanding was, that when using the device tree, we check if the
> device tree is atleast available. And we use platform_get_resource,
> doesn't that get the data from the device tree?

When you call platform_get_resource(), it looks at platform_device you pass to 
it and takes all resources from an array that is generated early at bootup (in 
case when DT is available). It will return an error pointer if there is no 
resource satisfying your requirements in this array.

In addition devm_ioremap_resource() checks the resource pointer, so if it's an 
error pointer it will print a message and return an error as well.

> >> +
> >> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> >> +	if (IS_ERR(sid_reg_base)) {
> >> +		ret = PTR_ERR(sid_reg_base);
> >> +		goto exit;
> >> +	}
> > 
> > One of the points of having devm_ helpers was removing the need to use
> > error paths at functions end. You can save 2 lines of code by changing
> > 
> > this check to:
> > 	if (IS_ERR(sid_reg_base))
> > 	
> > 		return PTR_ERR(sid_reg_base);
> 
> Okay
> 
> >> +	platform_set_drvdata(pdev, sid_reg_base);
> >> +
> >> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> >> +	if (ret) {
> >> +		dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
> >> +		goto exit;
> >> +	}
> > 
> > Same here.
> 
> Yeah, many returns, check
> 
> >> +
> >> +	for (i = 0; i < SID_SIZE; i++)
> >> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
> > 
> > You seem to read bytes into an array of ints. Your entropy data will
> > always have most significant 24-bits cleared. Is this behavior correct?
> 
> Yes, though I changed it so that entropy is an array of u8's, since
> that's what sunxi_sid_read_byte returns.
> 
> >> +	add_device_randomness(entropy, SID_SIZE);
> > 
> > Now I'm pretty sure that above is not the correct behavior. You are adding
> > here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16
> > ints (=4*SID_SIZE)...
> 
> Well technically, doesn't to compiler see that entropy is never larger
> then 8 bits and thus uses only 8 bits? uint8_atleast or something. But
> yeah, it's better to use the specified size to not waste 24 empty bits.

I mean, the loop fills the array with SID_SIZE ints, each with 3 zero bytes and 
1 byte of actual data, so you get:

S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S15 0x00 0x00 0x00

but by calling add_device_randomness() with SID_SIZE as size argument, you add 
only 16 first bytes of data from the array:

S0 0x00 0x00 0x00 S1 0x00 0x00 0x00 ... S3 0x00 0x00 0x00

(little endianness assumed)

Best regards,
Tomasz

(for rest of comments I think it's enough said in Russell's and Maxime's 
replies)

> >> +	dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
> > 
> > Same comment as for the message in remove().
> 
> Though with the DRV_(A[BP]I_)VERSION this is purly informational, I
> changed it to only show in the dev_dbg as requested.
> 
> >> +	ret = 0;
> >> +	/* fall through */
> >> +
> >> +exit:
> >> +	return ret;
> > 
> > Above 4 non-empty lines can be replaced by a single
> > 
> > 	return 0;
> > 	
> >> +}
> >> +
> >> +static struct platform_driver sunxi_sid_driver = {
> >> +	.probe = sunxi_sid_probe,
> >> +	.remove = sunxi_sid_remove,
> >> +	.driver = {
> >> +		.name = DRV_NAME,
> >> +		.owner = THIS_MODULE,
> >> +		.of_match_table = sunxi_sid_of_match,
> >> +	},
> >> +};
> >> +module_platform_driver(sunxi_sid_driver);
> >> +
> >> +
> > 
> > One empty line is enough.
> 
> Okay
> 
> > Best regards,
> > Tomasz
> > 
> >> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> >> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> >> +MODULE_VERSION(DRV_VERSION);
> >> +MODULE_LICENSE("GPL");
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 11:51         ` Maxime Ripard
@ 2013-06-17 12:04           ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 12:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Tomasz Figa, linux-arm-kernel, arnd, gregkh, linux,
	Oliver Schinagl, linus.walleij, linux-kernel, andy.shevchenko,
	linux-sunxi

On 17-06-13 13:51, Maxime Ripard wrote:
> On Mon, Jun 17, 2013 at 12:36:47PM +0200, Oliver Schinagl wrote:
>> On 15-06-13 12:28, Tomasz Figa wrote:
>>>> +#define DRV_VERSION "1.0"
>>>
>>> What is this version thingy?
>>>
>>> Is there a versioning scheme defined for this driver? Do you expect it to
>>> be changed every modification of this driver?
>>>
>>> I don't see any point of having such thing in a project with a version
>>> control system, where you have all change history.
>> Well we export something to userspace, while trivial there is the
>> possibility it changes over time. Say A40 which outputs 256 bits
>> instead of the current 128 bits. That would validate a bump in
>> version number. It's purely so the user can be aware of differences
>> in the driver. So maybe DRV_A[BP]I_VERSION would be better?
>
> Except that in that case, the userspace API won't change. You'll still
> call read on the same file in sysfs. The only thing that will change
> will be the number of bytes returned by your read function, which is
> (or should be) totally fine.
Aye, russel pointed this out as well, and I agree.
>
>>>> +/* We read the entire key, but only return the requested byte. This is
>>>> of + * course slower then it could be and uses 4 times more reads as
>>>> needed but + * keeps code simpler.
>>>
>>> I have no idea how often this is going to be read, but since the whole sid
>>> is really small (16 bytes), maybe it would be better to simply read the ID
>>> in probe to a buffer and then just memcpy from it in read().
>> The sid will be read once (well all 16 bytes) during probe and after
>> that only on user request. Right now we don't have a user (yet)
>> other then the sysfs entry.
>>
>> In future, this key can be used to read the MAC (low reads) or AES
>> keys for example (also low reads).
>>
>> Initially I had such an approach, but Maxime recommended against
>> having the value cached.
>>
>> As I wrote to andy, the only 'more efficient' way would be to store
>> the previously read key and see on the next read if its the same, So
>> best case, we could save 4 reads. I think it makes the code
>> unnecessarily complex for something that is read so little.
>
> I asked Oliver that because I felt like it could still be updated by the
> user, and sysfs should report that.
>
> And since it's not like it would be used extensively and very often,
> it's not a big deal anyway.
Actually it might still be possible to change the sid. We have figured 
out how we possible can program it (the 2.5 EFUSE_VDD pin, which olimex 
actually mapped out on the board) but requires someone to actually take 
the plunge and test it. So in theory, it can be changed still.
>
>>>> +
>>>> +	if (offset >= SID_SIZE)
>>>> +		goto exit;
>>>
>>> 		return 0; ...
>> I did say in the changelog I opted for goto over return. But since
>> everybody keeps preferring returns (I personally like 'one single
>> exit point much more' I have already changed it all over to many
>> returns, who am I to argue :)
>
> Yet, you don't have a single exit point neither, you have several of
> them. You can say that you have a single return statement in your code,
> which is true, yet you have several times a jump to this location, so we
> can definitely say that you actually have several exit points. Please
> also refer to the chapter 7 of the Documentation/CodingStyle file.
>
You are right of course :)
>>>> +	return (u8)sid_key;
>>>
>>> Unnecessary casting.
>> Unnecessary because of the &= 0xff above, or because you can put a
>> 32bit int in an 8bit int without worries? (we only want the last
>> byte).
>
> The latter. The & 0xff only filter out non-relevant informations from
> your 32-bits integer in that case, that's all, it doesn't do any
> casting.
So for clarity not leave the cast? Will it hurt? Will the compiler not 
do the cast anyway?
>
>>>> +	for (i = 0; i < size; i++) {
>>>> +		if ((pos + i) >= SID_SIZE || (pos < 0))
>>>> +			break;
>>>> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
>>>> +	}
>>>
>>> This could be greatly simplified if you just read the whole sid to memory
>>> in probe and memcpy from it here.
>> But can't because we don't want to cache it.
>
> And we can't simply use memcpy, since we will need to do some endianness
> conversions. The data stored in the SID are big-endian, while we're
> running most likely in little endian mode.
>
>>>> +	if (!pdev->dev.of_node) {
>>>> +		dev_err(&pdev->dev, "No devicetree data available\n");
>>>> +		ret = -ENXIO;
>>>> +		goto exit;
>>>> +	}
>>>
>>> What is this check for? You don't seem to need anything from dev.of_node
>>> in this driver.
>> My understanding was, that when using the device tree, we check if
>> the device tree is atleast available. And we use
>> platform_get_resource, doesn't that get the data from the device
>> tree?
>
> If there's no device tree, you won't be probed in the first place. And
> resources get filled by the kernel from the device tree automatically at
> boot, so you're safe to assume that the resources are there when you get
> probed.
Ahh, assumption, the mother.
But I put my trust in you ;)

I'll remove it
>
> You need this check when you actually need some more informations from
> the DT, the value of an additional property for example.
I'll learn about that soon enough ;)
>
> Maxime
Thanks again maxime :)
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 12:04           ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 12:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 17-06-13 13:51, Maxime Ripard wrote:
> On Mon, Jun 17, 2013 at 12:36:47PM +0200, Oliver Schinagl wrote:
>> On 15-06-13 12:28, Tomasz Figa wrote:
>>>> +#define DRV_VERSION "1.0"
>>>
>>> What is this version thingy?
>>>
>>> Is there a versioning scheme defined for this driver? Do you expect it to
>>> be changed every modification of this driver?
>>>
>>> I don't see any point of having such thing in a project with a version
>>> control system, where you have all change history.
>> Well we export something to userspace, while trivial there is the
>> possibility it changes over time. Say A40 which outputs 256 bits
>> instead of the current 128 bits. That would validate a bump in
>> version number. It's purely so the user can be aware of differences
>> in the driver. So maybe DRV_A[BP]I_VERSION would be better?
>
> Except that in that case, the userspace API won't change. You'll still
> call read on the same file in sysfs. The only thing that will change
> will be the number of bytes returned by your read function, which is
> (or should be) totally fine.
Aye, russel pointed this out as well, and I agree.
>
>>>> +/* We read the entire key, but only return the requested byte. This is
>>>> of + * course slower then it could be and uses 4 times more reads as
>>>> needed but + * keeps code simpler.
>>>
>>> I have no idea how often this is going to be read, but since the whole sid
>>> is really small (16 bytes), maybe it would be better to simply read the ID
>>> in probe to a buffer and then just memcpy from it in read().
>> The sid will be read once (well all 16 bytes) during probe and after
>> that only on user request. Right now we don't have a user (yet)
>> other then the sysfs entry.
>>
>> In future, this key can be used to read the MAC (low reads) or AES
>> keys for example (also low reads).
>>
>> Initially I had such an approach, but Maxime recommended against
>> having the value cached.
>>
>> As I wrote to andy, the only 'more efficient' way would be to store
>> the previously read key and see on the next read if its the same, So
>> best case, we could save 4 reads. I think it makes the code
>> unnecessarily complex for something that is read so little.
>
> I asked Oliver that because I felt like it could still be updated by the
> user, and sysfs should report that.
>
> And since it's not like it would be used extensively and very often,
> it's not a big deal anyway.
Actually it might still be possible to change the sid. We have figured 
out how we possible can program it (the 2.5 EFUSE_VDD pin, which olimex 
actually mapped out on the board) but requires someone to actually take 
the plunge and test it. So in theory, it can be changed still.
>
>>>> +
>>>> +	if (offset >= SID_SIZE)
>>>> +		goto exit;
>>>
>>> 		return 0; ...
>> I did say in the changelog I opted for goto over return. But since
>> everybody keeps preferring returns (I personally like 'one single
>> exit point much more' I have already changed it all over to many
>> returns, who am I to argue :)
>
> Yet, you don't have a single exit point neither, you have several of
> them. You can say that you have a single return statement in your code,
> which is true, yet you have several times a jump to this location, so we
> can definitely say that you actually have several exit points. Please
> also refer to the chapter 7 of the Documentation/CodingStyle file.
>
You are right of course :)
>>>> +	return (u8)sid_key;
>>>
>>> Unnecessary casting.
>> Unnecessary because of the &= 0xff above, or because you can put a
>> 32bit int in an 8bit int without worries? (we only want the last
>> byte).
>
> The latter. The & 0xff only filter out non-relevant informations from
> your 32-bits integer in that case, that's all, it doesn't do any
> casting.
So for clarity not leave the cast? Will it hurt? Will the compiler not 
do the cast anyway?
>
>>>> +	for (i = 0; i < size; i++) {
>>>> +		if ((pos + i) >= SID_SIZE || (pos < 0))
>>>> +			break;
>>>> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
>>>> +	}
>>>
>>> This could be greatly simplified if you just read the whole sid to memory
>>> in probe and memcpy from it here.
>> But can't because we don't want to cache it.
>
> And we can't simply use memcpy, since we will need to do some endianness
> conversions. The data stored in the SID are big-endian, while we're
> running most likely in little endian mode.
>
>>>> +	if (!pdev->dev.of_node) {
>>>> +		dev_err(&pdev->dev, "No devicetree data available\n");
>>>> +		ret = -ENXIO;
>>>> +		goto exit;
>>>> +	}
>>>
>>> What is this check for? You don't seem to need anything from dev.of_node
>>> in this driver.
>> My understanding was, that when using the device tree, we check if
>> the device tree is atleast available. And we use
>> platform_get_resource, doesn't that get the data from the device
>> tree?
>
> If there's no device tree, you won't be probed in the first place. And
> resources get filled by the kernel from the device tree automatically at
> boot, so you're safe to assume that the resources are there when you get
> probed.
Ahh, assumption, the mother.
But I put my trust in you ;)

I'll remove it
>
> You need this check when you actually need some more informations from
> the DT, the value of an additional property for example.
I'll learn about that soon enough ;)
>
> Maxime
Thanks again maxime :)
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 10:36       ` Oliver Schinagl
@ 2013-06-17 11:51         ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-06-17 11:51 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Tomasz Figa, linux-arm-kernel, arnd, gregkh, linux,
	Oliver Schinagl, linus.walleij, linux-kernel, andy.shevchenko

On Mon, Jun 17, 2013 at 12:36:47PM +0200, Oliver Schinagl wrote:
> On 15-06-13 12:28, Tomasz Figa wrote:
> >>+#define DRV_VERSION "1.0"
> >
> >What is this version thingy?
> >
> >Is there a versioning scheme defined for this driver? Do you expect it to
> >be changed every modification of this driver?
> >
> >I don't see any point of having such thing in a project with a version
> >control system, where you have all change history.
> Well we export something to userspace, while trivial there is the
> possibility it changes over time. Say A40 which outputs 256 bits
> instead of the current 128 bits. That would validate a bump in
> version number. It's purely so the user can be aware of differences
> in the driver. So maybe DRV_A[BP]I_VERSION would be better?

Except that in that case, the userspace API won't change. You'll still
call read on the same file in sysfs. The only thing that will change
will be the number of bytes returned by your read function, which is
(or should be) totally fine.

> >>+/* We read the entire key, but only return the requested byte. This is
> >>of + * course slower then it could be and uses 4 times more reads as
> >>needed but + * keeps code simpler.
> >
> >I have no idea how often this is going to be read, but since the whole sid
> >is really small (16 bytes), maybe it would be better to simply read the ID
> >in probe to a buffer and then just memcpy from it in read().
> The sid will be read once (well all 16 bytes) during probe and after
> that only on user request. Right now we don't have a user (yet)
> other then the sysfs entry.
> 
> In future, this key can be used to read the MAC (low reads) or AES
> keys for example (also low reads).
> 
> Initially I had such an approach, but Maxime recommended against
> having the value cached.
> 
> As I wrote to andy, the only 'more efficient' way would be to store
> the previously read key and see on the next read if its the same, So
> best case, we could save 4 reads. I think it makes the code
> unnecessarily complex for something that is read so little.

I asked Oliver that because I felt like it could still be updated by the
user, and sysfs should report that.

And since it's not like it would be used extensively and very often,
it's not a big deal anyway.

> >>+
> >>+	if (offset >= SID_SIZE)
> >>+		goto exit;
> >
> >		return 0; ...
> I did say in the changelog I opted for goto over return. But since
> everybody keeps preferring returns (I personally like 'one single
> exit point much more' I have already changed it all over to many
> returns, who am I to argue :)

Yet, you don't have a single exit point neither, you have several of
them. You can say that you have a single return statement in your code,
which is true, yet you have several times a jump to this location, so we
can definitely say that you actually have several exit points. Please
also refer to the chapter 7 of the Documentation/CodingStyle file.

> >>+	return (u8)sid_key;
> >
> >Unnecessary casting.
> Unnecessary because of the &= 0xff above, or because you can put a
> 32bit int in an 8bit int without worries? (we only want the last
> byte).

The latter. The & 0xff only filter out non-relevant informations from
your 32-bits integer in that case, that's all, it doesn't do any
casting.

> >>+	for (i = 0; i < size; i++) {
> >>+		if ((pos + i) >= SID_SIZE || (pos < 0))
> >>+			break;
> >>+		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> >>+	}
> >
> >This could be greatly simplified if you just read the whole sid to memory
> >in probe and memcpy from it here.
> But can't because we don't want to cache it.

And we can't simply use memcpy, since we will need to do some endianness
conversions. The data stored in the SID are big-endian, while we're
running most likely in little endian mode.

> >>+	if (!pdev->dev.of_node) {
> >>+		dev_err(&pdev->dev, "No devicetree data available\n");
> >>+		ret = -ENXIO;
> >>+		goto exit;
> >>+	}
> >
> >What is this check for? You don't seem to need anything from dev.of_node
> >in this driver.
> My understanding was, that when using the device tree, we check if
> the device tree is atleast available. And we use
> platform_get_resource, doesn't that get the data from the device
> tree?

If there's no device tree, you won't be probed in the first place. And
resources get filled by the kernel from the device tree automatically at
boot, so you're safe to assume that the resources are there when you get
probed.

You need this check when you actually need some more informations from
the DT, the value of an additionnal property for example.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 11:51         ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-06-17 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 17, 2013 at 12:36:47PM +0200, Oliver Schinagl wrote:
> On 15-06-13 12:28, Tomasz Figa wrote:
> >>+#define DRV_VERSION "1.0"
> >
> >What is this version thingy?
> >
> >Is there a versioning scheme defined for this driver? Do you expect it to
> >be changed every modification of this driver?
> >
> >I don't see any point of having such thing in a project with a version
> >control system, where you have all change history.
> Well we export something to userspace, while trivial there is the
> possibility it changes over time. Say A40 which outputs 256 bits
> instead of the current 128 bits. That would validate a bump in
> version number. It's purely so the user can be aware of differences
> in the driver. So maybe DRV_A[BP]I_VERSION would be better?

Except that in that case, the userspace API won't change. You'll still
call read on the same file in sysfs. The only thing that will change
will be the number of bytes returned by your read function, which is
(or should be) totally fine.

> >>+/* We read the entire key, but only return the requested byte. This is
> >>of + * course slower then it could be and uses 4 times more reads as
> >>needed but + * keeps code simpler.
> >
> >I have no idea how often this is going to be read, but since the whole sid
> >is really small (16 bytes), maybe it would be better to simply read the ID
> >in probe to a buffer and then just memcpy from it in read().
> The sid will be read once (well all 16 bytes) during probe and after
> that only on user request. Right now we don't have a user (yet)
> other then the sysfs entry.
> 
> In future, this key can be used to read the MAC (low reads) or AES
> keys for example (also low reads).
> 
> Initially I had such an approach, but Maxime recommended against
> having the value cached.
> 
> As I wrote to andy, the only 'more efficient' way would be to store
> the previously read key and see on the next read if its the same, So
> best case, we could save 4 reads. I think it makes the code
> unnecessarily complex for something that is read so little.

I asked Oliver that because I felt like it could still be updated by the
user, and sysfs should report that.

And since it's not like it would be used extensively and very often,
it's not a big deal anyway.

> >>+
> >>+	if (offset >= SID_SIZE)
> >>+		goto exit;
> >
> >		return 0; ...
> I did say in the changelog I opted for goto over return. But since
> everybody keeps preferring returns (I personally like 'one single
> exit point much more' I have already changed it all over to many
> returns, who am I to argue :)

Yet, you don't have a single exit point neither, you have several of
them. You can say that you have a single return statement in your code,
which is true, yet you have several times a jump to this location, so we
can definitely say that you actually have several exit points. Please
also refer to the chapter 7 of the Documentation/CodingStyle file.

> >>+	return (u8)sid_key;
> >
> >Unnecessary casting.
> Unnecessary because of the &= 0xff above, or because you can put a
> 32bit int in an 8bit int without worries? (we only want the last
> byte).

The latter. The & 0xff only filter out non-relevant informations from
your 32-bits integer in that case, that's all, it doesn't do any
casting.

> >>+	for (i = 0; i < size; i++) {
> >>+		if ((pos + i) >= SID_SIZE || (pos < 0))
> >>+			break;
> >>+		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> >>+	}
> >
> >This could be greatly simplified if you just read the whole sid to memory
> >in probe and memcpy from it here.
> But can't because we don't want to cache it.

And we can't simply use memcpy, since we will need to do some endianness
conversions. The data stored in the SID are big-endian, while we're
running most likely in little endian mode.

> >>+	if (!pdev->dev.of_node) {
> >>+		dev_err(&pdev->dev, "No devicetree data available\n");
> >>+		ret = -ENXIO;
> >>+		goto exit;
> >>+	}
> >
> >What is this check for? You don't seem to need anything from dev.of_node
> >in this driver.
> My understanding was, that when using the device tree, we check if
> the device tree is atleast available. And we use
> platform_get_resource, doesn't that get the data from the device
> tree?

If there's no device tree, you won't be probed in the first place. And
resources get filled by the kernel from the device tree automatically at
boot, so you're safe to assume that the resources are there when you get
probed.

You need this check when you actually need some more informations from
the DT, the value of an additionnal property for example.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 11:25         ` Russell King - ARM Linux
@ 2013-06-17 11:32           ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 11:32 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Tomasz Figa, linux-arm-kernel, arnd, gregkh, Oliver Schinagl,
	linus.walleij, linux-kernel, andy.shevchenko, maxime.ripard,
	linux-sunxi

On 17-06-13 13:25, Russell King - ARM Linux wrote:
> On Mon, Jun 17, 2013 at 12:36:47PM +0200, Oliver Schinagl wrote:
>> On 15-06-13 12:28, Tomasz Figa wrote:
>>> What is this version thingy?
>>>
>>> Is there a versioning scheme defined for this driver? Do you expect it to
>>> be changed every modification of this driver?
>>>
>>> I don't see any point of having such thing in a project with a version
>>> control system, where you have all change history.
>> Well we export something to userspace, while trivial there is the
>> possibility it changes over time. Say A40 which outputs 256 bits instead
>> of the current 128 bits. That would validate a bump in version number.
>> It's purely so the user can be aware of differences in the driver. So
>> maybe DRV_A[BP]I_VERSION would be better?
>
> What is better to do is to export such things as properties, or
> design the API in such a way that the length of the ID is reportable.
>
> However, it's actually quite easy to do if you only care about the
> number of bytes - you just arrange for the read() function to return
> the number of bytes read.  So in the case of 128 bits available, that's
> 16 bytes, so a read() of the sysfs attribute with a buffer of (say)
> 256 bytes should report only 16 bytes read.
>
> If it were to become 256 bytes later, then the read() would return
> 32 bytes read.  So there's no need for any new APIs to do this.
That makes sense for the sysfs bit and as the only user, I guess makes 
the version information obsolete for now.
>
> Also, this is over-complicated:
>
> +       for (i = 0; i < size; i++) {
> +               if ((pos + i) >= SID_SIZE || (pos < 0))
> +                       break;
> +               buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> +       }
>
> Maybe:
> 	if (pos < 0 || pos >= SID_SIZE)
> 		return 0;
> 	if (size > SID_SIZE - pos)
> 		size = SID_SIZE - pos;
>
> 	for (i = 0; i < size; i++)
> 		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
>
> 	return size;
>
I do like your approach, but takes a second to read ;) How is it less 
complicated though? It's more LOC i suppose. I do appreciate that we 
only perform the read function when our size is correct, thus making the 
for loop only execute the minimally required code. While in this driver 
is insignificant and not important, I am a proponent of it.
Consider it changed.

Will wait a bit for Thomaz to optionally reply and then send yet a 
nother version ;)

Thanks for your time,

Oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 11:32           ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 11:32 UTC (permalink / raw)
  To: linux-arm-kernel

On 17-06-13 13:25, Russell King - ARM Linux wrote:
> On Mon, Jun 17, 2013 at 12:36:47PM +0200, Oliver Schinagl wrote:
>> On 15-06-13 12:28, Tomasz Figa wrote:
>>> What is this version thingy?
>>>
>>> Is there a versioning scheme defined for this driver? Do you expect it to
>>> be changed every modification of this driver?
>>>
>>> I don't see any point of having such thing in a project with a version
>>> control system, where you have all change history.
>> Well we export something to userspace, while trivial there is the
>> possibility it changes over time. Say A40 which outputs 256 bits instead
>> of the current 128 bits. That would validate a bump in version number.
>> It's purely so the user can be aware of differences in the driver. So
>> maybe DRV_A[BP]I_VERSION would be better?
>
> What is better to do is to export such things as properties, or
> design the API in such a way that the length of the ID is reportable.
>
> However, it's actually quite easy to do if you only care about the
> number of bytes - you just arrange for the read() function to return
> the number of bytes read.  So in the case of 128 bits available, that's
> 16 bytes, so a read() of the sysfs attribute with a buffer of (say)
> 256 bytes should report only 16 bytes read.
>
> If it were to become 256 bytes later, then the read() would return
> 32 bytes read.  So there's no need for any new APIs to do this.
That makes sense for the sysfs bit and as the only user, I guess makes 
the version information obsolete for now.
>
> Also, this is over-complicated:
>
> +       for (i = 0; i < size; i++) {
> +               if ((pos + i) >= SID_SIZE || (pos < 0))
> +                       break;
> +               buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> +       }
>
> Maybe:
> 	if (pos < 0 || pos >= SID_SIZE)
> 		return 0;
> 	if (size > SID_SIZE - pos)
> 		size = SID_SIZE - pos;
>
> 	for (i = 0; i < size; i++)
> 		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
>
> 	return size;
>
I do like your approach, but takes a second to read ;) How is it less 
complicated though? It's more LOC i suppose. I do appreciate that we 
only perform the read function when our size is correct, thus making the 
for loop only execute the minimally required code. While in this driver 
is insignificant and not important, I am a proponent of it.
Consider it changed.

Will wait a bit for Thomaz to optionally reply and then send yet a 
nother version ;)

Thanks for your time,

Oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-17 10:36       ` Oliver Schinagl
@ 2013-06-17 11:25         ` Russell King - ARM Linux
  -1 siblings, 0 replies; 142+ messages in thread
From: Russell King - ARM Linux @ 2013-06-17 11:25 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Tomasz Figa, linux-arm-kernel, arnd, gregkh, Oliver Schinagl,
	linus.walleij, linux-kernel, andy.shevchenko, maxime.ripard

On Mon, Jun 17, 2013 at 12:36:47PM +0200, Oliver Schinagl wrote:
> On 15-06-13 12:28, Tomasz Figa wrote:
>> What is this version thingy?
>>
>> Is there a versioning scheme defined for this driver? Do you expect it to
>> be changed every modification of this driver?
>>
>> I don't see any point of having such thing in a project with a version
>> control system, where you have all change history.
> Well we export something to userspace, while trivial there is the  
> possibility it changes over time. Say A40 which outputs 256 bits instead  
> of the current 128 bits. That would validate a bump in version number.  
> It's purely so the user can be aware of differences in the driver. So  
> maybe DRV_A[BP]I_VERSION would be better?

What is better to do is to export such things as properties, or
design the API in such a way that the length of the ID is reportable.

However, it's actually quite easy to do if you only care about the
number of bytes - you just arrange for the read() function to return
the number of bytes read.  So in the case of 128 bits available, that's
16 bytes, so a read() of the sysfs attribute with a buffer of (say)
256 bytes should report only 16 bytes read.

If it were to become 256 bytes later, then the read() would return
32 bytes read.  So there's no need for any new APIs to do this.

Also, this is over-complicated:

+       for (i = 0; i < size; i++) {
+               if ((pos + i) >= SID_SIZE || (pos < 0))
+                       break;
+               buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
+       }

Maybe:
	if (pos < 0 || pos >= SID_SIZE)
		return 0;
	if (size > SID_SIZE - pos)
		size = SID_SIZE - pos;

	for (i = 0; i < size; i++)
		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);

	return size;

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 11:25         ` Russell King - ARM Linux
  0 siblings, 0 replies; 142+ messages in thread
From: Russell King - ARM Linux @ 2013-06-17 11:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 17, 2013 at 12:36:47PM +0200, Oliver Schinagl wrote:
> On 15-06-13 12:28, Tomasz Figa wrote:
>> What is this version thingy?
>>
>> Is there a versioning scheme defined for this driver? Do you expect it to
>> be changed every modification of this driver?
>>
>> I don't see any point of having such thing in a project with a version
>> control system, where you have all change history.
> Well we export something to userspace, while trivial there is the  
> possibility it changes over time. Say A40 which outputs 256 bits instead  
> of the current 128 bits. That would validate a bump in version number.  
> It's purely so the user can be aware of differences in the driver. So  
> maybe DRV_A[BP]I_VERSION would be better?

What is better to do is to export such things as properties, or
design the API in such a way that the length of the ID is reportable.

However, it's actually quite easy to do if you only care about the
number of bytes - you just arrange for the read() function to return
the number of bytes read.  So in the case of 128 bits available, that's
16 bytes, so a read() of the sysfs attribute with a buffer of (say)
256 bytes should report only 16 bytes read.

If it were to become 256 bytes later, then the read() would return
32 bytes read.  So there's no need for any new APIs to do this.

Also, this is over-complicated:

+       for (i = 0; i < size; i++) {
+               if ((pos + i) >= SID_SIZE || (pos < 0))
+                       break;
+               buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
+       }

Maybe:
	if (pos < 0 || pos >= SID_SIZE)
		return 0;
	if (size > SID_SIZE - pos)
		size = SID_SIZE - pos;

	for (i = 0; i < size; i++)
		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);

	return size;

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-15 10:28     ` Tomasz Figa
@ 2013-06-17 10:36       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 10:36 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: linux-arm-kernel, arnd, gregkh, linux, Oliver Schinagl,
	linus.walleij, linux-kernel, andy.shevchenko, maxime.ripard

On 15-06-13 12:28, Tomasz Figa wrote:
> Hi,
>
> Some comments inline.
Thank you
>
> On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
>> From: Oliver Schinagl <oliver@schinagl.nl>
>>
>> Allwinner has electric fuses (efuse) on their line of chips. This driver
>> reads those fuses, seeds the kernel entropy and exports them as a sysfs
>> node.
>>
>> These fuses are most likly to be programmed at the factory, encoding
>> things like Chip ID, some sort of serial number etc and appear to be
>> reasonable unique.
>> While in theory, these should be writeable by the user, it will probably
>> be inconvinient to do so. Allwinner recommends that a certain input
>> pin, labeled 'efuse_vddq', be connected to GND. To write these fuses,
>> 2.5 V needs to be applied to this pin.
>>
>> Even so, they can still be used to generate a board-unique mac from,
>> board unique RSA key and seed the kernel RNG.
>>
>> Currently supported are the following known chips:
>> Allwinner sun4i (A10)
>> Allwinner sun5i (A10s, A13)
>>
>> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
>> ---
>>   drivers/misc/eeprom/Kconfig     |  17 ++++
>>   drivers/misc/eeprom/Makefile    |   1 +
>>   drivers/misc/eeprom/sunxi_sid.c | 167
>> ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185
>> insertions(+)
>>   create mode 100644 drivers/misc/eeprom/sunxi_sid.c
>>
>> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
>> index 04f2e1f..c7bc6ed 100644
>> --- a/drivers/misc/eeprom/Kconfig
>> +++ b/drivers/misc/eeprom/Kconfig
>> @@ -96,4 +96,21 @@ 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. Currently supported are:
>> +		sun4i (A10)
>> +		sun5i (A13)
>> +
>> +	  Due to the potential risks involved with changing e-fuses,
>> +	  this driver is read-only
>> +
>> +	  For more information visit http://linux-sunxi.org/SID
>> +
>> +	  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 fc1e81d..9507aec 100644
>> --- a/drivers/misc/eeprom/Makefile
>> +++ b/drivers/misc/eeprom/Makefile
>> @@ -4,4 +4,5 @@ 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 new file mode 100644
>> index 0000000..f014e1b
>> --- /dev/null
>> +++ b/drivers/misc/eeprom/sunxi_sid.c
>> @@ -0,0 +1,167 @@
>> +/*
>> + * Copyright (c) 2013 Oliver Schinagl
>> + * http://www.linux-sunxi.org
>> + *
>> + * Oliver Schinagl <oliver@schinagl.nl>
>> + *
>> + * 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, a 128 bit eeprom, in
>> byte + * sized chunks.
>> + */
>> +
>> +#include <linux/compiler.h>
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/errno.h>
>> +#include <linux/export.h>
>> +#include <linux/fs.h>
>> +#include <linux/init.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/kobject.h>
>> +#include <linux/module.h>
>> +#include <linux/of_address.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/random.h>
>> +#include <linux/stat.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/types.h>
>> +
>> +#define DRV_NAME "sunxi-sid"
>> +#define DRV_VERSION "1.0"
>
> What is this version thingy?
>
> Is there a versioning scheme defined for this driver? Do you expect it to
> be changed every modification of this driver?
>
> I don't see any point of having such thing in a project with a version
> control system, where you have all change history.
Well we export something to userspace, while trivial there is the 
possibility it changes over time. Say A40 which outputs 256 bits instead 
of the current 128 bits. That would validate a bump in version number. 
It's purely so the user can be aware of differences in the driver. So 
maybe DRV_A[BP]I_VERSION would be better?
>
>> +
>> +/* There are 4 32-bit keys */
>> +#define SID_KEYS 4
>> +/* and 4 byte sized keys per 32-bit key */
>> +#define SID_SIZE (SID_KEYS * 4)
>
>  From this definition it looks like there are just 4 32-bit keys, I don't
> see those extra four byte-sized keys accounted by this size.
I will change the comment, 'and 4 byte sized keys per SID' is probably 
better
The array is 128 bits split into 32 bit words. Each 32 bit word consists 
of 8 bits (1 byte).
So 4 * 4 = 16 bytes (SID_SIZE), is 128 bits.
>
>> +
>> +
>
> One _empty_ line is enough to separate definitions from code.
Okay, I find it personally a little clearer to separate them, but sure.
>
>> +/* We read the entire key, but only return the requested byte. This is
>> of + * course slower then it could be and uses 4 times more reads as
>> needed but + * keeps code simpler.
>
> I have no idea how often this is going to be read, but since the whole sid
> is really small (16 bytes), maybe it would be better to simply read the ID
> in probe to a buffer and then just memcpy from it in read().
The sid will be read once (well all 16 bytes) during probe and after 
that only on user request. Right now we don't have a user (yet) other 
then the sysfs entry.

In future, this key can be used to read the MAC (low reads) or AES keys 
for example (also low reads).

Initially I had such an approach, but Maxime recommended against having 
the value cached.

As I wrote to andy, the only 'more efficient' way would be to store the 
previously read key and see on the next read if its the same, So best 
case, we could save 4 reads. I think it makes the code unnecessarily 
complex for something that is read so little.
>
>> + */
>> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
>> +			      const unsigned int offset)
>> +{
>> +	u32 sid_key = 0;
>
> 	u32 sid_key; ...
Indeed, a left over from a previous version. It does no longer need to 
be initted.
>
>> +
>> +	if (offset >= SID_SIZE)
>> +		goto exit;
>
> 		return 0; ...
I did say in the changelog I opted for goto over return. But since 
everybody keeps preferring returns (I personally like 'one single exit 
point much more' I have already changed it all over to many returns, who 
am I to argue :)
>
>> +
>> +	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
>> +	sid_key >>= (offset % 4) * 8;
>> +	sid_key &= 0xff;
>> +	/* fall through */
>> +
>> +exit:
>
> ...and now magically here you can remove two unneeded lines.
>
>> +	return (u8)sid_key;
>
> Unnecessary casting.
Unnecessary because of the &= 0xff above, or because you can put a 32bit 
int in an 8bit int without worries? (we only want 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)
>> +{
>> +	int i;
>> +	struct platform_device *pdev;
>> +	void __iomem *sid_reg_base;
>> +
>> +	pdev = (struct platform_device
>> *)to_platform_device(kobj_to_dev(kobj)); +	sid_reg_base = (void
> __iomem
>> *)platform_get_drvdata(pdev);
>> +
>> +	for (i = 0; i < size; i++) {
>> +		if ((pos + i) >= SID_SIZE || (pos < 0))
>> +			break;
>> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
>> +	}
>
> This could be greatly simplified if you just read the whole sid to memory
> in probe and memcpy from it here.
But can't because we don't want to cache it.
>
>> +	return i;
>> +}
>> +
>> +static const struct of_device_id sunxi_sid_of_match[] = {
>> +	{
>> +		.compatible = "allwinner,sun4i-sid",
>> +	},
>
> Above 3 lines could be put in single line.
okay
>
>> +	{/* sentinel */}
>> +};
>> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
>> +
>> +static const struct bin_attribute sid_bin_attr = {
>> +	.attr = {
>> +		.name = "eeprom",
>> +		.mode = S_IRUGO,
>> +	},
>> +	.size = SID_SIZE,
>> +	.read = sid_read,
>> +};
>> +
>> +static int sunxi_sid_remove(struct platform_device *pdev)
>> +{
>> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
>> +	dev_info(&pdev->dev, "sunxi SID driver unloaded\n");
>
> Please either make this dev_dbg or remove it completely, as it is not
> something that users should be concerned about.
dev_dbg might be better for the remove, thanks
>
>> +	return 0;
>> +}
>> +
>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> +{
>> +	int entropy[SID_SIZE], i;
>> +	struct resource *res;
>> +	void __iomem *sid_reg_base;
>> +	int ret;
>> +
>> +	if (!pdev->dev.of_node) {
>> +		dev_err(&pdev->dev, "No devicetree data available\n");
>> +		ret = -ENXIO;
>> +		goto exit;
>> +	}
>
> What is this check for? You don't seem to need anything from dev.of_node
> in this driver.
My understanding was, that when using the device tree, we check if the 
device tree is atleast available. And we use platform_get_resource, 
doesn't that get the data from the device tree?
>
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(sid_reg_base)) {
>> +		ret = PTR_ERR(sid_reg_base);
>> +		goto exit;
>> +	}
>
> One of the points of having devm_ helpers was removing the need to use
> error paths at functions end. You can save 2 lines of code by changing
> this check to:
>
> 	if (IS_ERR(sid_reg_base))
> 		return PTR_ERR(sid_reg_base);
Okay
>
>> +	platform_set_drvdata(pdev, sid_reg_base);
>> +
>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
>> +		goto exit;
>> +	}
>
> Same here.
Yeah, many returns, check
>
>> +
>> +	for (i = 0; i < SID_SIZE; i++)
>> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
>
> You seem to read bytes into an array of ints. Your entropy data will
> always have most significant 24-bits cleared. Is this behavior correct?
Yes, though I changed it so that entropy is an array of u8's, since 
that's what sunxi_sid_read_byte returns.
>
>> +	add_device_randomness(entropy, SID_SIZE);
>
> Now I'm pretty sure that above is not the correct behavior. You are adding
> here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16
> ints (=4*SID_SIZE)...
Well technically, doesn't to compiler see that entropy is never larger 
then 8 bits and thus uses only 8 bits? uint8_atleast or something. But 
yeah, it's better to use the specified size to not waste 24 empty bits.
>
>> +	dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
>
> Same comment as for the message in remove().
Though with the DRV_(A[BP]I_)VERSION this is purly informational, I 
changed it to only show in the dev_dbg as requested.
>
>> +	ret = 0;
>> +	/* fall through */
>> +
>> +exit:
>> +	return ret;
>
> Above 4 non-empty lines can be replaced by a single
>
> 	return 0;
>
>> +}
>> +
>> +static struct platform_driver sunxi_sid_driver = {
>> +	.probe = sunxi_sid_probe,
>> +	.remove = sunxi_sid_remove,
>> +	.driver = {
>> +		.name = DRV_NAME,
>> +		.owner = THIS_MODULE,
>> +		.of_match_table = sunxi_sid_of_match,
>> +	},
>> +};
>> +module_platform_driver(sunxi_sid_driver);
>> +
>> +
>
> One empty line is enough.
Okay
>
> Best regards,
> Tomasz
>
>> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
>> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
>> +MODULE_VERSION(DRV_VERSION);
>> +MODULE_LICENSE("GPL");


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-17 10:36       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-17 10:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 15-06-13 12:28, Tomasz Figa wrote:
> Hi,
>
> Some comments inline.
Thank you
>
> On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
>> From: Oliver Schinagl <oliver@schinagl.nl>
>>
>> Allwinner has electric fuses (efuse) on their line of chips. This driver
>> reads those fuses, seeds the kernel entropy and exports them as a sysfs
>> node.
>>
>> These fuses are most likly to be programmed at the factory, encoding
>> things like Chip ID, some sort of serial number etc and appear to be
>> reasonable unique.
>> While in theory, these should be writeable by the user, it will probably
>> be inconvinient to do so. Allwinner recommends that a certain input
>> pin, labeled 'efuse_vddq', be connected to GND. To write these fuses,
>> 2.5 V needs to be applied to this pin.
>>
>> Even so, they can still be used to generate a board-unique mac from,
>> board unique RSA key and seed the kernel RNG.
>>
>> Currently supported are the following known chips:
>> Allwinner sun4i (A10)
>> Allwinner sun5i (A10s, A13)
>>
>> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
>> ---
>>   drivers/misc/eeprom/Kconfig     |  17 ++++
>>   drivers/misc/eeprom/Makefile    |   1 +
>>   drivers/misc/eeprom/sunxi_sid.c | 167
>> ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185
>> insertions(+)
>>   create mode 100644 drivers/misc/eeprom/sunxi_sid.c
>>
>> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
>> index 04f2e1f..c7bc6ed 100644
>> --- a/drivers/misc/eeprom/Kconfig
>> +++ b/drivers/misc/eeprom/Kconfig
>> @@ -96,4 +96,21 @@ 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. Currently supported are:
>> +		sun4i (A10)
>> +		sun5i (A13)
>> +
>> +	  Due to the potential risks involved with changing e-fuses,
>> +	  this driver is read-only
>> +
>> +	  For more information visit http://linux-sunxi.org/SID
>> +
>> +	  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 fc1e81d..9507aec 100644
>> --- a/drivers/misc/eeprom/Makefile
>> +++ b/drivers/misc/eeprom/Makefile
>> @@ -4,4 +4,5 @@ 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 new file mode 100644
>> index 0000000..f014e1b
>> --- /dev/null
>> +++ b/drivers/misc/eeprom/sunxi_sid.c
>> @@ -0,0 +1,167 @@
>> +/*
>> + * Copyright (c) 2013 Oliver Schinagl
>> + * http://www.linux-sunxi.org
>> + *
>> + * Oliver Schinagl <oliver@schinagl.nl>
>> + *
>> + * 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, a 128 bit eeprom, in
>> byte + * sized chunks.
>> + */
>> +
>> +#include <linux/compiler.h>
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/errno.h>
>> +#include <linux/export.h>
>> +#include <linux/fs.h>
>> +#include <linux/init.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/kobject.h>
>> +#include <linux/module.h>
>> +#include <linux/of_address.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/random.h>
>> +#include <linux/stat.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/types.h>
>> +
>> +#define DRV_NAME "sunxi-sid"
>> +#define DRV_VERSION "1.0"
>
> What is this version thingy?
>
> Is there a versioning scheme defined for this driver? Do you expect it to
> be changed every modification of this driver?
>
> I don't see any point of having such thing in a project with a version
> control system, where you have all change history.
Well we export something to userspace, while trivial there is the 
possibility it changes over time. Say A40 which outputs 256 bits instead 
of the current 128 bits. That would validate a bump in version number. 
It's purely so the user can be aware of differences in the driver. So 
maybe DRV_A[BP]I_VERSION would be better?
>
>> +
>> +/* There are 4 32-bit keys */
>> +#define SID_KEYS 4
>> +/* and 4 byte sized keys per 32-bit key */
>> +#define SID_SIZE (SID_KEYS * 4)
>
>  From this definition it looks like there are just 4 32-bit keys, I don't
> see those extra four byte-sized keys accounted by this size.
I will change the comment, 'and 4 byte sized keys per SID' is probably 
better
The array is 128 bits split into 32 bit words. Each 32 bit word consists 
of 8 bits (1 byte).
So 4 * 4 = 16 bytes (SID_SIZE), is 128 bits.
>
>> +
>> +
>
> One _empty_ line is enough to separate definitions from code.
Okay, I find it personally a little clearer to separate them, but sure.
>
>> +/* We read the entire key, but only return the requested byte. This is
>> of + * course slower then it could be and uses 4 times more reads as
>> needed but + * keeps code simpler.
>
> I have no idea how often this is going to be read, but since the whole sid
> is really small (16 bytes), maybe it would be better to simply read the ID
> in probe to a buffer and then just memcpy from it in read().
The sid will be read once (well all 16 bytes) during probe and after 
that only on user request. Right now we don't have a user (yet) other 
then the sysfs entry.

In future, this key can be used to read the MAC (low reads) or AES keys 
for example (also low reads).

Initially I had such an approach, but Maxime recommended against having 
the value cached.

As I wrote to andy, the only 'more efficient' way would be to store the 
previously read key and see on the next read if its the same, So best 
case, we could save 4 reads. I think it makes the code unnecessarily 
complex for something that is read so little.
>
>> + */
>> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
>> +			      const unsigned int offset)
>> +{
>> +	u32 sid_key = 0;
>
> 	u32 sid_key; ...
Indeed, a left over from a previous version. It does no longer need to 
be initted.
>
>> +
>> +	if (offset >= SID_SIZE)
>> +		goto exit;
>
> 		return 0; ...
I did say in the changelog I opted for goto over return. But since 
everybody keeps preferring returns (I personally like 'one single exit 
point much more' I have already changed it all over to many returns, who 
am I to argue :)
>
>> +
>> +	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
>> +	sid_key >>= (offset % 4) * 8;
>> +	sid_key &= 0xff;
>> +	/* fall through */
>> +
>> +exit:
>
> ...and now magically here you can remove two unneeded lines.
>
>> +	return (u8)sid_key;
>
> Unnecessary casting.
Unnecessary because of the &= 0xff above, or because you can put a 32bit 
int in an 8bit int without worries? (we only want 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)
>> +{
>> +	int i;
>> +	struct platform_device *pdev;
>> +	void __iomem *sid_reg_base;
>> +
>> +	pdev = (struct platform_device
>> *)to_platform_device(kobj_to_dev(kobj)); +	sid_reg_base = (void
> __iomem
>> *)platform_get_drvdata(pdev);
>> +
>> +	for (i = 0; i < size; i++) {
>> +		if ((pos + i) >= SID_SIZE || (pos < 0))
>> +			break;
>> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
>> +	}
>
> This could be greatly simplified if you just read the whole sid to memory
> in probe and memcpy from it here.
But can't because we don't want to cache it.
>
>> +	return i;
>> +}
>> +
>> +static const struct of_device_id sunxi_sid_of_match[] = {
>> +	{
>> +		.compatible = "allwinner,sun4i-sid",
>> +	},
>
> Above 3 lines could be put in single line.
okay
>
>> +	{/* sentinel */}
>> +};
>> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
>> +
>> +static const struct bin_attribute sid_bin_attr = {
>> +	.attr = {
>> +		.name = "eeprom",
>> +		.mode = S_IRUGO,
>> +	},
>> +	.size = SID_SIZE,
>> +	.read = sid_read,
>> +};
>> +
>> +static int sunxi_sid_remove(struct platform_device *pdev)
>> +{
>> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
>> +	dev_info(&pdev->dev, "sunxi SID driver unloaded\n");
>
> Please either make this dev_dbg or remove it completely, as it is not
> something that users should be concerned about.
dev_dbg might be better for the remove, thanks
>
>> +	return 0;
>> +}
>> +
>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> +{
>> +	int entropy[SID_SIZE], i;
>> +	struct resource *res;
>> +	void __iomem *sid_reg_base;
>> +	int ret;
>> +
>> +	if (!pdev->dev.of_node) {
>> +		dev_err(&pdev->dev, "No devicetree data available\n");
>> +		ret = -ENXIO;
>> +		goto exit;
>> +	}
>
> What is this check for? You don't seem to need anything from dev.of_node
> in this driver.
My understanding was, that when using the device tree, we check if the 
device tree is atleast available. And we use platform_get_resource, 
doesn't that get the data from the device tree?
>
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(sid_reg_base)) {
>> +		ret = PTR_ERR(sid_reg_base);
>> +		goto exit;
>> +	}
>
> One of the points of having devm_ helpers was removing the need to use
> error paths at functions end. You can save 2 lines of code by changing
> this check to:
>
> 	if (IS_ERR(sid_reg_base))
> 		return PTR_ERR(sid_reg_base);
Okay
>
>> +	platform_set_drvdata(pdev, sid_reg_base);
>> +
>> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
>> +		goto exit;
>> +	}
>
> Same here.
Yeah, many returns, check
>
>> +
>> +	for (i = 0; i < SID_SIZE; i++)
>> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
>
> You seem to read bytes into an array of ints. Your entropy data will
> always have most significant 24-bits cleared. Is this behavior correct?
Yes, though I changed it so that entropy is an array of u8's, since 
that's what sunxi_sid_read_byte returns.
>
>> +	add_device_randomness(entropy, SID_SIZE);
>
> Now I'm pretty sure that above is not the correct behavior. You are adding
> here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16
> ints (=4*SID_SIZE)...
Well technically, doesn't to compiler see that entropy is never larger 
then 8 bits and thus uses only 8 bits? uint8_atleast or something. But 
yeah, it's better to use the specified size to not waste 24 empty bits.
>
>> +	dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
>
> Same comment as for the message in remove().
Though with the DRV_(A[BP]I_)VERSION this is purly informational, I 
changed it to only show in the dev_dbg as requested.
>
>> +	ret = 0;
>> +	/* fall through */
>> +
>> +exit:
>> +	return ret;
>
> Above 4 non-empty lines can be replaced by a single
>
> 	return 0;
>
>> +}
>> +
>> +static struct platform_driver sunxi_sid_driver = {
>> +	.probe = sunxi_sid_probe,
>> +	.remove = sunxi_sid_remove,
>> +	.driver = {
>> +		.name = DRV_NAME,
>> +		.owner = THIS_MODULE,
>> +		.of_match_table = sunxi_sid_of_match,
>> +	},
>> +};
>> +module_platform_driver(sunxi_sid_driver);
>> +
>> +
>
> One empty line is enough.
Okay
>
> Best regards,
> Tomasz
>
>> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
>> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
>> +MODULE_VERSION(DRV_VERSION);
>> +MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-14 23:16   ` Oliver Schinagl
@ 2013-06-15 10:28     ` Tomasz Figa
  -1 siblings, 0 replies; 142+ messages in thread
From: Tomasz Figa @ 2013-06-15 10:28 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Oliver Schinagl, arnd, gregkh, linux, Oliver Schinagl,
	linus.walleij, linux-kernel, andy.shevchenko, maxime.ripard

Hi,

Some comments inline.

On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> node.
> 
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input
> pin, labeled 'efuse_vddq', be connected to GND. To write these fuses,
> 2.5 V needs to be applied to this pin.
> 
> Even so, they can still be used to generate a board-unique mac from,
> board unique RSA key and seed the kernel RNG.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)
> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  drivers/misc/eeprom/Kconfig     |  17 ++++
>  drivers/misc/eeprom/Makefile    |   1 +
>  drivers/misc/eeprom/sunxi_sid.c | 167
> ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185
> insertions(+)
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> 
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..c7bc6ed 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,21 @@ 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. Currently supported are:
> +		sun4i (A10)
> +		sun5i (A13)
> +
> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID
> +
> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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 new file mode 100644
> index 0000000..f014e1b
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,167 @@
> +/*
> + * Copyright (c) 2013 Oliver Schinagl
> + * http://www.linux-sunxi.org
> + *
> + * Oliver Schinagl <oliver@schinagl.nl>
> + *
> + * 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, a 128 bit eeprom, in
> byte + * sized chunks.
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/random.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +#define DRV_NAME "sunxi-sid"
> +#define DRV_VERSION "1.0"

What is this version thingy?

Is there a versioning scheme defined for this driver? Do you expect it to 
be changed every modification of this driver?

I don't see any point of having such thing in a project with a version 
control system, where you have all change history.

> +
> +/* There are 4 32-bit keys */
> +#define SID_KEYS 4
> +/* and 4 byte sized keys per 32-bit key */
> +#define SID_SIZE (SID_KEYS * 4)

>From this definition it looks like there are just 4 32-bit keys, I don't 
see those extra four byte-sized keys accounted by this size.

> +
> +

One _empty_ line is enough to separate definitions from code.

> +/* We read the entire key, but only return the requested byte. This is
> of + * course slower then it could be and uses 4 times more reads as
> needed but + * keeps code simpler.

I have no idea how often this is going to be read, but since the whole sid 
is really small (16 bytes), maybe it would be better to simply read the ID 
in probe to a buffer and then just memcpy from it in read().

> + */
> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> +			      const unsigned int offset)
> +{
> +	u32 sid_key = 0;

	u32 sid_key; ...

> +
> +	if (offset >= SID_SIZE)
> +		goto exit;

		return 0; ...

> +
> +	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
> +	sid_key >>= (offset % 4) * 8;
> +	sid_key &= 0xff;
> +	/* fall through */
> +
> +exit:

...and now magically here you can remove two unneeded lines.

> +	return (u8)sid_key;

Unnecessary casting.

> +}
> +
> +static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> +			struct bin_attribute *attr, char *buf,
> +			loff_t pos, size_t size)
> +{
> +	int i;
> +	struct platform_device *pdev;
> +	void __iomem *sid_reg_base;
> +
> +	pdev = (struct platform_device
> *)to_platform_device(kobj_to_dev(kobj)); +	sid_reg_base = (void 
__iomem
> *)platform_get_drvdata(pdev);
> +
> +	for (i = 0; i < size; i++) {
> +		if ((pos + i) >= SID_SIZE || (pos < 0))
> +			break;
> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> +	}

This could be greatly simplified if you just read the whole sid to memory 
in probe and memcpy from it here.

> +	return i;
> +}
> +
> +static const struct of_device_id sunxi_sid_of_match[] = {
> +	{
> +		.compatible = "allwinner,sun4i-sid",
> +	},

Above 3 lines could be put in single line.

> +	{/* sentinel */}
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> +
> +static const struct bin_attribute sid_bin_attr = {
> +	.attr = {
> +		.name = "eeprom",
> +		.mode = S_IRUGO,
> +	},
> +	.size = SID_SIZE,
> +	.read = sid_read,
> +};
> +
> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> +	dev_info(&pdev->dev, "sunxi SID driver unloaded\n");

Please either make this dev_dbg or remove it completely, as it is not 
something that users should be concerned about.

> +	return 0;
> +}
> +
> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	int entropy[SID_SIZE], i;
> +	struct resource *res;
> +	void __iomem *sid_reg_base;
> +	int ret;
> +
> +	if (!pdev->dev.of_node) {
> +		dev_err(&pdev->dev, "No devicetree data available\n");
> +		ret = -ENXIO;
> +		goto exit;
> +	}

What is this check for? You don't seem to need anything from dev.of_node 
in this driver.

> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(sid_reg_base)) {
> +		ret = PTR_ERR(sid_reg_base);
> +		goto exit;
> +	}

One of the points of having devm_ helpers was removing the need to use 
error paths at functions end. You can save 2 lines of code by changing 
this check to:

	if (IS_ERR(sid_reg_base))
		return PTR_ERR(sid_reg_base);

> +	platform_set_drvdata(pdev, sid_reg_base);
> +
> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
> +		goto exit;
> +	}

Same here.

> +
> +	for (i = 0; i < SID_SIZE; i++)
> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);

You seem to read bytes into an array of ints. Your entropy data will 
always have most significant 24-bits cleared. Is this behavior correct?

> +	add_device_randomness(entropy, SID_SIZE);

Now I'm pretty sure that above is not the correct behavior. You are adding 
here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16 
ints (=4*SID_SIZE)...

> +	dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);

Same comment as for the message in remove().

> +	ret = 0;
> +	/* fall through */
> +
> +exit:
> +	return ret;

Above 4 non-empty lines can be replaced by a single

	return 0;

> +}
> +
> +static struct platform_driver sunxi_sid_driver = {
> +	.probe = sunxi_sid_probe,
> +	.remove = sunxi_sid_remove,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.owner = THIS_MODULE,
> +		.of_match_table = sunxi_sid_of_match,
> +	},
> +};
> +module_platform_driver(sunxi_sid_driver);
> +
> +

One empty line is enough.

Best regards,
Tomasz

> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> +MODULE_VERSION(DRV_VERSION);
> +MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-15 10:28     ` Tomasz Figa
  0 siblings, 0 replies; 142+ messages in thread
From: Tomasz Figa @ 2013-06-15 10:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

Some comments inline.

On Saturday 15 of June 2013 01:16:20 Oliver Schinagl wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs
> node.
> 
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input
> pin, labeled 'efuse_vddq', be connected to GND. To write these fuses,
> 2.5 V needs to be applied to this pin.
> 
> Even so, they can still be used to generate a board-unique mac from,
> board unique RSA key and seed the kernel RNG.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)
> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  drivers/misc/eeprom/Kconfig     |  17 ++++
>  drivers/misc/eeprom/Makefile    |   1 +
>  drivers/misc/eeprom/sunxi_sid.c | 167
> ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185
> insertions(+)
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> 
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..c7bc6ed 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,21 @@ 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. Currently supported are:
> +		sun4i (A10)
> +		sun5i (A13)
> +
> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID
> +
> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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 new file mode 100644
> index 0000000..f014e1b
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,167 @@
> +/*
> + * Copyright (c) 2013 Oliver Schinagl
> + * http://www.linux-sunxi.org
> + *
> + * Oliver Schinagl <oliver@schinagl.nl>
> + *
> + * 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, a 128 bit eeprom, in
> byte + * sized chunks.
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/random.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +#define DRV_NAME "sunxi-sid"
> +#define DRV_VERSION "1.0"

What is this version thingy?

Is there a versioning scheme defined for this driver? Do you expect it to 
be changed every modification of this driver?

I don't see any point of having such thing in a project with a version 
control system, where you have all change history.

> +
> +/* There are 4 32-bit keys */
> +#define SID_KEYS 4
> +/* and 4 byte sized keys per 32-bit key */
> +#define SID_SIZE (SID_KEYS * 4)

>From this definition it looks like there are just 4 32-bit keys, I don't 
see those extra four byte-sized keys accounted by this size.

> +
> +

One _empty_ line is enough to separate definitions from code.

> +/* We read the entire key, but only return the requested byte. This is
> of + * course slower then it could be and uses 4 times more reads as
> needed but + * keeps code simpler.

I have no idea how often this is going to be read, but since the whole sid 
is really small (16 bytes), maybe it would be better to simply read the ID 
in probe to a buffer and then just memcpy from it in read().

> + */
> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> +			      const unsigned int offset)
> +{
> +	u32 sid_key = 0;

	u32 sid_key; ...

> +
> +	if (offset >= SID_SIZE)
> +		goto exit;

		return 0; ...

> +
> +	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
> +	sid_key >>= (offset % 4) * 8;
> +	sid_key &= 0xff;
> +	/* fall through */
> +
> +exit:

...and now magically here you can remove two unneeded lines.

> +	return (u8)sid_key;

Unnecessary casting.

> +}
> +
> +static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> +			struct bin_attribute *attr, char *buf,
> +			loff_t pos, size_t size)
> +{
> +	int i;
> +	struct platform_device *pdev;
> +	void __iomem *sid_reg_base;
> +
> +	pdev = (struct platform_device
> *)to_platform_device(kobj_to_dev(kobj)); +	sid_reg_base = (void 
__iomem
> *)platform_get_drvdata(pdev);
> +
> +	for (i = 0; i < size; i++) {
> +		if ((pos + i) >= SID_SIZE || (pos < 0))
> +			break;
> +		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
> +	}

This could be greatly simplified if you just read the whole sid to memory 
in probe and memcpy from it here.

> +	return i;
> +}
> +
> +static const struct of_device_id sunxi_sid_of_match[] = {
> +	{
> +		.compatible = "allwinner,sun4i-sid",
> +	},

Above 3 lines could be put in single line.

> +	{/* sentinel */}
> +};
> +MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
> +
> +static const struct bin_attribute sid_bin_attr = {
> +	.attr = {
> +		.name = "eeprom",
> +		.mode = S_IRUGO,
> +	},
> +	.size = SID_SIZE,
> +	.read = sid_read,
> +};
> +
> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> +	dev_info(&pdev->dev, "sunxi SID driver unloaded\n");

Please either make this dev_dbg or remove it completely, as it is not 
something that users should be concerned about.

> +	return 0;
> +}
> +
> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	int entropy[SID_SIZE], i;
> +	struct resource *res;
> +	void __iomem *sid_reg_base;
> +	int ret;
> +
> +	if (!pdev->dev.of_node) {
> +		dev_err(&pdev->dev, "No devicetree data available\n");
> +		ret = -ENXIO;
> +		goto exit;
> +	}

What is this check for? You don't seem to need anything from dev.of_node 
in this driver.

> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(sid_reg_base)) {
> +		ret = PTR_ERR(sid_reg_base);
> +		goto exit;
> +	}

One of the points of having devm_ helpers was removing the need to use 
error paths at functions end. You can save 2 lines of code by changing 
this check to:

	if (IS_ERR(sid_reg_base))
		return PTR_ERR(sid_reg_base);

> +	platform_set_drvdata(pdev, sid_reg_base);
> +
> +	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
> +		goto exit;
> +	}

Same here.

> +
> +	for (i = 0; i < SID_SIZE; i++)
> +		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);

You seem to read bytes into an array of ints. Your entropy data will 
always have most significant 24-bits cleared. Is this behavior correct?

> +	add_device_randomness(entropy, SID_SIZE);

Now I'm pretty sure that above is not the correct behavior. You are adding 
here first 16 bytes (=SID_SIZE) of entropy[], while it is an array of 16 
ints (=4*SID_SIZE)...

> +	dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);

Same comment as for the message in remove().

> +	ret = 0;
> +	/* fall through */
> +
> +exit:
> +	return ret;

Above 4 non-empty lines can be replaced by a single

	return 0;

> +}
> +
> +static struct platform_driver sunxi_sid_driver = {
> +	.probe = sunxi_sid_probe,
> +	.remove = sunxi_sid_remove,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.owner = THIS_MODULE,
> +		.of_match_table = sunxi_sid_of_match,
> +	},
> +};
> +module_platform_driver(sunxi_sid_driver);
> +
> +

One empty line is enough.

Best regards,
Tomasz

> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> +MODULE_VERSION(DRV_VERSION);
> +MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-15  2:14     ` Andy Shevchenko
@ 2013-06-15  9:34       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-15  9:34 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Arnd Bergmann, Greg Kroah-Hartman, maxime.ripard, linux-kernel,
	linux-arm Mailing List, Russell King, Linus Walleij,
	Oliver Schinagl

On 06/15/13 04:14, Andy Shevchenko wrote:
> On Sat, Jun 15, 2013 at 2:16 AM, Oliver Schinagl
> <oliver+list@schinagl.nl> wrote:
>> From: Oliver Schinagl <oliver@schinagl.nl>
>>
>> Allwinner has electric fuses (efuse) on their line of chips. This driver
>> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
>>
>> These fuses are most likly to be programmed at the factory, encoding
>> things like Chip ID, some sort of serial number etc and appear to be
>> reasonable unique.
>> While in theory, these should be writeable by the user, it will probably
>> be inconvinient to do so. Allwinner recommends that a certain input pin,
>> labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
>> needs to be applied to this pin.
>>
>> Even so, they can still be used to generate a board-unique mac from, board
>> unique RSA key and seed the kernel RNG.
>>
>> Currently supported are the following known chips:
>> Allwinner sun4i (A10)
>> Allwinner sun5i (A10s, A13)
>
> Few comments below.
>
>> +++ b/drivers/misc/eeprom/sunxi_sid.c
>
>> +#include <linux/compiler.h>
>
> Are you sure this has to be explicitly mentioned?
Well we use __iomem from it, so I think yes
>
>> +#define SID_SIZE (SID_KEYS * 4)
>> +
>> +
>
> Extra line.
to seperate defines/includes from the code?
>
>> +/* We read the entire key, but only return the requested byte. This is of
>> + * course slower then it could be and uses 4 times more reads as needed but
>> + * keeps code simpler.
>
> May be better to rewrite this logic and save CPU and I/O resources?
Well we can only read 32 bits at a time and we only want to return 8 
bits. The only think I can think of, is read 32 bits and store those 
statically to the function and store with an extra int the location. 
Then check against the location and if it's the same use the int. Not 
sure all that is worth it.
>
>> + */
>> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
>> +                             const unsigned int offset)
>> +{
>> +       u32 sid_key = 0;
>> +
>> +       if (offset >= SID_SIZE)
>> +               goto exit;
>
> Just return here.
Well as said before, return vs goto; i choose goto ;)
>
>> +       sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
>> +       sid_key >>= (offset % 4) * 8;
>> +       sid_key &= 0xff;
>
> Redundant 0xff.
Yes, but does clarify the intention, which helps in readability?
>
>> +       /* fall through */
>> +
>> +exit:
>> +       return (u8)sid_key;
>
> No need to have explicit casting here.
Also here, it makes the intention clear, that we are only interested in 
the last 8 bits. The compiler should optimize this and the above bit 
away so it's only for readability.
>
>> +       pdev = (struct platform_device *)to_platform_device(kobj_to_dev(kobj));
>
> Ditto.
Yes, I just looked more closy to container_of, and the 'const 
typeof(((type *)0)->member) takes care of the typecast, does it not?
>
>> +       sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
>
> Ditto.
Not sure on this one, since technically, it returns only void * (always) 
and we had a void '__iomem *' pointer. for clarity and completness I 
would keep it?
>
>> +static int sunxi_sid_remove(struct platform_device *pdev)
>> +{
>> +       device_remove_bin_file(&pdev->dev, &sid_bin_attr);
>> +       dev_info(&pdev->dev, "sunxi SID driver unloaded\n");
>
> Often this is useless message. In what case this is crucial?
well it's dev_info, so it is only information to the user.
>
>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> +{
>> +       int entropy[SID_SIZE], i;
>> +       struct resource *res;
>> +       void __iomem *sid_reg_base;
>> +       int ret;
>> +
>> +       if (!pdev->dev.of_node) {
>> +               dev_err(&pdev->dev, "No devicetree data available\n");
>> +               ret = -ENXIO;
>> +               goto exit;
>
> You have only return, use it. It's common practice in the .probe() function.
>
>> +       if (IS_ERR(sid_reg_base)) {
>> +               ret = PTR_ERR(sid_reg_base);
>> +               goto exit;
>
> Ditto.
>
>> +       ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
>> +               goto exit;
>
> Ditto.
>
>> +       dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
>> +       ret = 0;
>> +       /* fall through */
>
> Ditto.
>
>> +
>> +exit:
>> +       return ret;
>
> Useless lines.
>
>> +module_platform_driver(sunxi_sid_driver);
>> +
>> +
>
> Extra line.
Seperate the code from the trailing macro's
>
>
> --
> With Best Regards,
> Andy Shevchenko
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-15  9:34       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-15  9:34 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/15/13 04:14, Andy Shevchenko wrote:
> On Sat, Jun 15, 2013 at 2:16 AM, Oliver Schinagl
> <oliver+list@schinagl.nl> wrote:
>> From: Oliver Schinagl <oliver@schinagl.nl>
>>
>> Allwinner has electric fuses (efuse) on their line of chips. This driver
>> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
>>
>> These fuses are most likly to be programmed at the factory, encoding
>> things like Chip ID, some sort of serial number etc and appear to be
>> reasonable unique.
>> While in theory, these should be writeable by the user, it will probably
>> be inconvinient to do so. Allwinner recommends that a certain input pin,
>> labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
>> needs to be applied to this pin.
>>
>> Even so, they can still be used to generate a board-unique mac from, board
>> unique RSA key and seed the kernel RNG.
>>
>> Currently supported are the following known chips:
>> Allwinner sun4i (A10)
>> Allwinner sun5i (A10s, A13)
>
> Few comments below.
>
>> +++ b/drivers/misc/eeprom/sunxi_sid.c
>
>> +#include <linux/compiler.h>
>
> Are you sure this has to be explicitly mentioned?
Well we use __iomem from it, so I think yes
>
>> +#define SID_SIZE (SID_KEYS * 4)
>> +
>> +
>
> Extra line.
to seperate defines/includes from the code?
>
>> +/* We read the entire key, but only return the requested byte. This is of
>> + * course slower then it could be and uses 4 times more reads as needed but
>> + * keeps code simpler.
>
> May be better to rewrite this logic and save CPU and I/O resources?
Well we can only read 32 bits at a time and we only want to return 8 
bits. The only think I can think of, is read 32 bits and store those 
statically to the function and store with an extra int the location. 
Then check against the location and if it's the same use the int. Not 
sure all that is worth it.
>
>> + */
>> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
>> +                             const unsigned int offset)
>> +{
>> +       u32 sid_key = 0;
>> +
>> +       if (offset >= SID_SIZE)
>> +               goto exit;
>
> Just return here.
Well as said before, return vs goto; i choose goto ;)
>
>> +       sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
>> +       sid_key >>= (offset % 4) * 8;
>> +       sid_key &= 0xff;
>
> Redundant 0xff.
Yes, but does clarify the intention, which helps in readability?
>
>> +       /* fall through */
>> +
>> +exit:
>> +       return (u8)sid_key;
>
> No need to have explicit casting here.
Also here, it makes the intention clear, that we are only interested in 
the last 8 bits. The compiler should optimize this and the above bit 
away so it's only for readability.
>
>> +       pdev = (struct platform_device *)to_platform_device(kobj_to_dev(kobj));
>
> Ditto.
Yes, I just looked more closy to container_of, and the 'const 
typeof(((type *)0)->member) takes care of the typecast, does it not?
>
>> +       sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
>
> Ditto.
Not sure on this one, since technically, it returns only void * (always) 
and we had a void '__iomem *' pointer. for clarity and completness I 
would keep it?
>
>> +static int sunxi_sid_remove(struct platform_device *pdev)
>> +{
>> +       device_remove_bin_file(&pdev->dev, &sid_bin_attr);
>> +       dev_info(&pdev->dev, "sunxi SID driver unloaded\n");
>
> Often this is useless message. In what case this is crucial?
well it's dev_info, so it is only information to the user.
>
>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> +{
>> +       int entropy[SID_SIZE], i;
>> +       struct resource *res;
>> +       void __iomem *sid_reg_base;
>> +       int ret;
>> +
>> +       if (!pdev->dev.of_node) {
>> +               dev_err(&pdev->dev, "No devicetree data available\n");
>> +               ret = -ENXIO;
>> +               goto exit;
>
> You have only return, use it. It's common practice in the .probe() function.
>
>> +       if (IS_ERR(sid_reg_base)) {
>> +               ret = PTR_ERR(sid_reg_base);
>> +               goto exit;
>
> Ditto.
>
>> +       ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
>> +               goto exit;
>
> Ditto.
>
>> +       dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
>> +       ret = 0;
>> +       /* fall through */
>
> Ditto.
>
>> +
>> +exit:
>> +       return ret;
>
> Useless lines.
>
>> +module_platform_driver(sunxi_sid_driver);
>> +
>> +
>
> Extra line.
Seperate the code from the trailing macro's
>
>
> --
> With Best Regards,
> Andy Shevchenko
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-14 23:16   ` Oliver Schinagl
@ 2013-06-15  2:14     ` Andy Shevchenko
  -1 siblings, 0 replies; 142+ messages in thread
From: Andy Shevchenko @ 2013-06-15  2:14 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Arnd Bergmann, Greg Kroah-Hartman, maxime.ripard, linux-kernel,
	linux-arm Mailing List, Russell King, Linus Walleij,
	Oliver Schinagl

On Sat, Jun 15, 2013 at 2:16 AM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
>
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
>
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
> needs to be applied to this pin.
>
> Even so, they can still be used to generate a board-unique mac from, board
> unique RSA key and seed the kernel RNG.
>
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)

Few comments below.

> +++ b/drivers/misc/eeprom/sunxi_sid.c

> +#include <linux/compiler.h>

Are you sure this has to be explicitly mentioned?

> +#define SID_SIZE (SID_KEYS * 4)
> +
> +

Extra line.

> +/* We read the entire key, but only return the requested byte. This is of
> + * course slower then it could be and uses 4 times more reads as needed but
> + * keeps code simpler.

May be better to rewrite this logic and save CPU and I/O resources?

> + */
> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> +                             const unsigned int offset)
> +{
> +       u32 sid_key = 0;
> +
> +       if (offset >= SID_SIZE)
> +               goto exit;

Just return here.

> +       sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
> +       sid_key >>= (offset % 4) * 8;
> +       sid_key &= 0xff;

Redundant 0xff.

> +       /* fall through */
> +
> +exit:
> +       return (u8)sid_key;

No need to have explicit casting here.

> +       pdev = (struct platform_device *)to_platform_device(kobj_to_dev(kobj));

Ditto.

> +       sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);

Ditto.

> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +       device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> +       dev_info(&pdev->dev, "sunxi SID driver unloaded\n");

Often this is useless message. In what case this is crucial?

> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +       int entropy[SID_SIZE], i;
> +       struct resource *res;
> +       void __iomem *sid_reg_base;
> +       int ret;
> +
> +       if (!pdev->dev.of_node) {
> +               dev_err(&pdev->dev, "No devicetree data available\n");
> +               ret = -ENXIO;
> +               goto exit;

You have only return, use it. It's common practice in the .probe() function.

> +       if (IS_ERR(sid_reg_base)) {
> +               ret = PTR_ERR(sid_reg_base);
> +               goto exit;

Ditto.

> +       ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
> +               goto exit;

Ditto.

> +       dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
> +       ret = 0;
> +       /* fall through */

Ditto.

> +
> +exit:
> +       return ret;

Useless lines.

> +module_platform_driver(sunxi_sid_driver);
> +
> +

Extra line.


--
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-15  2:14     ` Andy Shevchenko
  0 siblings, 0 replies; 142+ messages in thread
From: Andy Shevchenko @ 2013-06-15  2:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jun 15, 2013 at 2:16 AM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
>
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
>
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
> needs to be applied to this pin.
>
> Even so, they can still be used to generate a board-unique mac from, board
> unique RSA key and seed the kernel RNG.
>
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s, A13)

Few comments below.

> +++ b/drivers/misc/eeprom/sunxi_sid.c

> +#include <linux/compiler.h>

Are you sure this has to be explicitly mentioned?

> +#define SID_SIZE (SID_KEYS * 4)
> +
> +

Extra line.

> +/* We read the entire key, but only return the requested byte. This is of
> + * course slower then it could be and uses 4 times more reads as needed but
> + * keeps code simpler.

May be better to rewrite this logic and save CPU and I/O resources?

> + */
> +static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
> +                             const unsigned int offset)
> +{
> +       u32 sid_key = 0;
> +
> +       if (offset >= SID_SIZE)
> +               goto exit;

Just return here.

> +       sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
> +       sid_key >>= (offset % 4) * 8;
> +       sid_key &= 0xff;

Redundant 0xff.

> +       /* fall through */
> +
> +exit:
> +       return (u8)sid_key;

No need to have explicit casting here.

> +       pdev = (struct platform_device *)to_platform_device(kobj_to_dev(kobj));

Ditto.

> +       sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);

Ditto.

> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +       device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> +       dev_info(&pdev->dev, "sunxi SID driver unloaded\n");

Often this is useless message. In what case this is crucial?

> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +       int entropy[SID_SIZE], i;
> +       struct resource *res;
> +       void __iomem *sid_reg_base;
> +       int ret;
> +
> +       if (!pdev->dev.of_node) {
> +               dev_err(&pdev->dev, "No devicetree data available\n");
> +               ret = -ENXIO;
> +               goto exit;

You have only return, use it. It's common practice in the .probe() function.

> +       if (IS_ERR(sid_reg_base)) {
> +               ret = PTR_ERR(sid_reg_base);
> +               goto exit;

Ditto.

> +       ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
> +               goto exit;

Ditto.

> +       dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
> +       ret = 0;
> +       /* fall through */

Ditto.

> +
> +exit:
> +       return ret;

Useless lines.

> +module_platform_driver(sunxi_sid_driver);
> +
> +

Extra line.


--
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-14 23:16 [PATCH 0/2] v3 Driver for Allwinner sunxi Security ID Oliver Schinagl
@ 2013-06-14 23:16   ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-14 23:16 UTC (permalink / raw)
  To: arnd, gregkh
  Cc: maxime.ripard, linux-kernel, linux-arm-kernel, andy.shevchenko,
	linux, linus.walleij, Oliver Schinagl

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses, seeds the kernel entropy and exports them as a sysfs node.

These fuses are most likly to be programmed at the factory, encoding
things like Chip ID, some sort of serial number etc and appear to be
reasonable unique.
While in theory, these should be writeable by the user, it will probably
be inconvinient to do so. Allwinner recommends that a certain input pin,
labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
needs to be applied to this pin.

Even so, they can still be used to generate a board-unique mac from, board
unique RSA key and seed the kernel RNG.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A10s, A13)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 drivers/misc/eeprom/Kconfig     |  17 ++++
 drivers/misc/eeprom/Makefile    |   1 +
 drivers/misc/eeprom/sunxi_sid.c | 167 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 185 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..c7bc6ed 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,21 @@ 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. Currently supported are:
+		sun4i (A10)
+		sun5i (A13)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..f014e1b
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2013 Oliver Schinagl
+ * http://www.linux-sunxi.org
+ *
+ * Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * 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, a 128 bit eeprom, in byte
+ * sized chunks.
+ */
+
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define DRV_NAME "sunxi-sid"
+#define DRV_VERSION "1.0"
+
+/* There are 4 32-bit keys */
+#define SID_KEYS 4
+/* and 4 byte sized keys per 32-bit key */
+#define SID_SIZE (SID_KEYS * 4)
+
+
+/* We read the entire key, but only return the requested byte. This is of
+ * course slower then it could be and uses 4 times more reads as needed but
+ * keeps code simpler.
+ */
+static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
+			      const unsigned int offset)
+{
+	u32 sid_key = 0;
+
+	if (offset >= SID_SIZE)
+		goto exit;
+
+	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
+	sid_key >>= (offset % 4) * 8;
+	sid_key &= 0xff;
+	/* fall through */
+
+exit:
+	return (u8)sid_key;
+}
+
+static ssize_t sid_read(struct file *fd, struct kobject *kobj,
+			struct bin_attribute *attr, char *buf,
+			loff_t pos, size_t size)
+{
+	int i;
+	struct platform_device *pdev;
+	void __iomem *sid_reg_base;
+
+	pdev = (struct platform_device *)to_platform_device(kobj_to_dev(kobj));
+	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
+
+	for (i = 0; i < size; i++) {
+		if ((pos + i) >= SID_SIZE || (pos < 0))
+			break;
+		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
+	}
+
+	return i;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{
+		.compatible = "allwinner,sun4i-sid",
+	},
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static const struct bin_attribute sid_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO,
+	},
+	.size = SID_SIZE,
+	.read = sid_read,
+};
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
+	dev_info(&pdev->dev, "sunxi SID driver unloaded\n");
+
+	return 0;
+}
+
+static int __init sunxi_sid_probe(struct platform_device *pdev)
+{
+	int entropy[SID_SIZE], i;
+	struct resource *res;
+	void __iomem *sid_reg_base;
+	int ret;
+
+	if (!pdev->dev.of_node) {
+		dev_err(&pdev->dev, "No devicetree data available\n");
+		ret = -ENXIO;
+		goto exit;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sid_reg_base)) {
+		ret = PTR_ERR(sid_reg_base);
+		goto exit;
+	}
+	platform_set_drvdata(pdev, sid_reg_base);
+
+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
+		goto exit;
+	}
+
+	for (i = 0; i < SID_SIZE; i++)
+		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
+	add_device_randomness(entropy, SID_SIZE);
+	dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
+	ret = 0;
+	/* fall through */
+
+exit:
+	return ret;
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.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_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
-- 
1.8.1.5


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-14 23:16   ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-14 23:16 UTC (permalink / raw)
  To: linux-arm-kernel

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses, seeds the kernel entropy and exports them as a sysfs node.

These fuses are most likly to be programmed at the factory, encoding
things like Chip ID, some sort of serial number etc and appear to be
reasonable unique.
While in theory, these should be writeable by the user, it will probably
be inconvinient to do so. Allwinner recommends that a certain input pin,
labeled 'efuse_vddq', be connected to GND. To write these fuses, 2.5 V
needs to be applied to this pin.

Even so, they can still be used to generate a board-unique mac from, board
unique RSA key and seed the kernel RNG.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A10s, A13)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 drivers/misc/eeprom/Kconfig     |  17 ++++
 drivers/misc/eeprom/Makefile    |   1 +
 drivers/misc/eeprom/sunxi_sid.c | 167 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 185 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..c7bc6ed 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,21 @@ 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. Currently supported are:
+		sun4i (A10)
+		sun5i (A13)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..f014e1b
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2013 Oliver Schinagl
+ * http://www.linux-sunxi.org
+ *
+ * Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * 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, a 128 bit eeprom, in byte
+ * sized chunks.
+ */
+
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define DRV_NAME "sunxi-sid"
+#define DRV_VERSION "1.0"
+
+/* There are 4 32-bit keys */
+#define SID_KEYS 4
+/* and 4 byte sized keys per 32-bit key */
+#define SID_SIZE (SID_KEYS * 4)
+
+
+/* We read the entire key, but only return the requested byte. This is of
+ * course slower then it could be and uses 4 times more reads as needed but
+ * keeps code simpler.
+ */
+static u8 sunxi_sid_read_byte(const void __iomem *sid_reg_base,
+			      const unsigned int offset)
+{
+	u32 sid_key = 0;
+
+	if (offset >= SID_SIZE)
+		goto exit;
+
+	sid_key = ioread32be(sid_reg_base + round_down(offset, 4));
+	sid_key >>= (offset % 4) * 8;
+	sid_key &= 0xff;
+	/* fall through */
+
+exit:
+	return (u8)sid_key;
+}
+
+static ssize_t sid_read(struct file *fd, struct kobject *kobj,
+			struct bin_attribute *attr, char *buf,
+			loff_t pos, size_t size)
+{
+	int i;
+	struct platform_device *pdev;
+	void __iomem *sid_reg_base;
+
+	pdev = (struct platform_device *)to_platform_device(kobj_to_dev(kobj));
+	sid_reg_base = (void __iomem *)platform_get_drvdata(pdev);
+
+	for (i = 0; i < size; i++) {
+		if ((pos + i) >= SID_SIZE || (pos < 0))
+			break;
+		buf[i] = sunxi_sid_read_byte(sid_reg_base, pos + i);
+	}
+
+	return i;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{
+		.compatible = "allwinner,sun4i-sid",
+	},
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static const struct bin_attribute sid_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO,
+	},
+	.size = SID_SIZE,
+	.read = sid_read,
+};
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
+	dev_info(&pdev->dev, "sunxi SID driver unloaded\n");
+
+	return 0;
+}
+
+static int __init sunxi_sid_probe(struct platform_device *pdev)
+{
+	int entropy[SID_SIZE], i;
+	struct resource *res;
+	void __iomem *sid_reg_base;
+	int ret;
+
+	if (!pdev->dev.of_node) {
+		dev_err(&pdev->dev, "No devicetree data available\n");
+		ret = -ENXIO;
+		goto exit;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sid_reg_base)) {
+		ret = PTR_ERR(sid_reg_base);
+		goto exit;
+	}
+	platform_set_drvdata(pdev, sid_reg_base);
+
+	ret = device_create_bin_file(&pdev->dev, &sid_bin_attr);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to create sysfs bin entry\n");
+		goto exit;
+	}
+
+	for (i = 0; i < SID_SIZE; i++)
+		entropy[i] = sunxi_sid_read_byte(sid_reg_base, i);
+	add_device_randomness(entropy, SID_SIZE);
+	dev_info(&pdev->dev, "sunxi SID ver %s loaded\n", DRV_VERSION);
+	ret = 0;
+	/* fall through */
+
+exit:
+	return ret;
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.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_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
-- 
1.8.1.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-10 21:43       ` Oliver Schinagl
@ 2013-06-11 10:51         ` Andy Shevchenko
  -1 siblings, 0 replies; 142+ messages in thread
From: Andy Shevchenko @ 2013-06-11 10:51 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: maxime.ripard, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-arm Mailing List, Oliver Schinagl

On Tue, Jun 11, 2013 at 12:43 AM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:
> On 06/06/13 21:16, Andy Shevchenko wrote:
>> On Sun, Jun 2, 2013 at 5:58 PM, Oliver Schinagl <oliver+list@schinagl.nl>
>> wrote:
>>> From: Oliver Schinagl <oliver@schinagl.nl>

>>> +       if (likely((SID_SIZE))) {
>>
>> Extra braces.
>> Use antipattern here.
>
> While I accidentally dropped the pointer here, sorry for the confusion, what
> is antipattern? I have asked around and nobody really knew.

In this case instead of doing...

if (likely(condition)) {
 do_smth();
}
do_very_few_ops();
return;

...better to do

if(unlikely(!condition)) {
 do_very_few_ops();
 return;
}

do_smth();
return;

It takes more lines of code, but increases readability a lot.

>>> +       if (unlikely(!pdev->dev.of_node)) {
>>> +               dev_err(dev, "No devicetree data available\n");
>>> +               ret = -EFAULT;
>>> +               goto exit;
>>
>>
>> Plain return here and in entire function where it applies.
>
> Why? I know there's conflicting preferences here. The general consensus
> seems, don't return mid function if you don't absolutely have to. Yet, you
> make it sound, just return wherever. I take it that really is just a
> preference? I think i see both constructs throughout the kernel. So one
> review prefers the one method, the next the other?

Usually it makes sense when you have to free resources or do something
like that. You have plain return statement under exit label.

>>> +       ret = device_create_bin_file(dev, &sid_bin_attr);
>>> +       if (unlikely(ret)) {
>>
>> Any benifit of (un)likely in probe()?
>
> Does it hurt however in any way though? It's just a compiler optimization
> isn't it.

It hurts readability. probe() function is usually doesn't require
fastest execution. Moreover, [1] tells us "You should use it only in
cases when the likeliest branch is very very very likely, or when the
unlikeliest branch is very very very unlikely."

There also an article [2] about cache issues. Bad usage of the
likely/unlikely macros might lead to performance degradation (cache
misses). You have to think about those macros really carefully.

[1] http://kernelnewbies.org/FAQ/LikelyUnlikely
[2] http://dslab.lzu.edu.cn:8080/docs/publications/NicholasMcGuire.pdf

--
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-11 10:51         ` Andy Shevchenko
  0 siblings, 0 replies; 142+ messages in thread
From: Andy Shevchenko @ 2013-06-11 10:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 11, 2013 at 12:43 AM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:
> On 06/06/13 21:16, Andy Shevchenko wrote:
>> On Sun, Jun 2, 2013 at 5:58 PM, Oliver Schinagl <oliver+list@schinagl.nl>
>> wrote:
>>> From: Oliver Schinagl <oliver@schinagl.nl>

>>> +       if (likely((SID_SIZE))) {
>>
>> Extra braces.
>> Use antipattern here.
>
> While I accidentally dropped the pointer here, sorry for the confusion, what
> is antipattern? I have asked around and nobody really knew.

In this case instead of doing...

if (likely(condition)) {
 do_smth();
}
do_very_few_ops();
return;

...better to do

if(unlikely(!condition)) {
 do_very_few_ops();
 return;
}

do_smth();
return;

It takes more lines of code, but increases readability a lot.

>>> +       if (unlikely(!pdev->dev.of_node)) {
>>> +               dev_err(dev, "No devicetree data available\n");
>>> +               ret = -EFAULT;
>>> +               goto exit;
>>
>>
>> Plain return here and in entire function where it applies.
>
> Why? I know there's conflicting preferences here. The general consensus
> seems, don't return mid function if you don't absolutely have to. Yet, you
> make it sound, just return wherever. I take it that really is just a
> preference? I think i see both constructs throughout the kernel. So one
> review prefers the one method, the next the other?

Usually it makes sense when you have to free resources or do something
like that. You have plain return statement under exit label.

>>> +       ret = device_create_bin_file(dev, &sid_bin_attr);
>>> +       if (unlikely(ret)) {
>>
>> Any benifit of (un)likely in probe()?
>
> Does it hurt however in any way though? It's just a compiler optimization
> isn't it.

It hurts readability. probe() function is usually doesn't require
fastest execution. Moreover, [1] tells us "You should use it only in
cases when the likeliest branch is very very very likely, or when the
unlikeliest branch is very very very unlikely."

There also an article [2] about cache issues. Bad usage of the
likely/unlikely macros might lead to performance degradation (cache
misses). You have to think about those macros really carefully.

[1] http://kernelnewbies.org/FAQ/LikelyUnlikely
[2] http://dslab.lzu.edu.cn:8080/docs/publications/NicholasMcGuire.pdf

--
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-06 19:16     ` Andy Shevchenko
@ 2013-06-10 21:43       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-10 21:43 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: maxime.ripard, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-arm Mailing List, Oliver Schinagl

On 06/06/13 21:16, Andy Shevchenko wrote:

Thank you andy for your review, I do have a few questions/comments if 
you don't mind.
> On Sun, Jun 2, 2013 at 5:58 PM, Oliver Schinagl <oliver+list@schinagl.nl> wrote:
>> From: Oliver Schinagl <oliver@schinagl.nl>
<snip>
>> +       if (likely((SID_SIZE))) {
>
> Extra braces.
> Use antipattern here.

While I accidentally dropped the pointer here, sorry for the confusion, 
what is antipattern? I have asked around and nobody really knew.

Wikipedia mentions it as a software development thing, but you make it 
sound like it is some sort of tool?

<snip>
>> +       if (unlikely(!pdev->dev.of_node)) {
>> +               dev_err(dev, "No devicetree data available\n");
>> +               ret = -EFAULT;
>> +               goto exit;
>
> Plain return here and in entire function where it applies.
Why? I know there's conflicting preferences here. The general consensus 
seems, don't return mid function if you don't absolutely have to. Yet, 
you make it sound, just return wherever. I take it that really is just a 
preference? I think i see both constructs throughout the kernel. So one 
review prefers the one method, the next the other?
<snip>
>> +
>> +       ret = device_create_bin_file(dev, &sid_bin_attr);
>> +       if (unlikely(ret)) {
>
> Any benifit of (un)likely in probe()?
Does it hurt however in any way though? It's just a compiler 
optimization isn't it.

<snip>
>
> --
> With Best Regards,
> Andy Shevchenko
>
Thank you for your time, it is much appreciated :)

Oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-10 21:43       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-10 21:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/13 21:16, Andy Shevchenko wrote:

Thank you andy for your review, I do have a few questions/comments if 
you don't mind.
> On Sun, Jun 2, 2013 at 5:58 PM, Oliver Schinagl <oliver+list@schinagl.nl> wrote:
>> From: Oliver Schinagl <oliver@schinagl.nl>
<snip>
>> +       if (likely((SID_SIZE))) {
>
> Extra braces.
> Use antipattern here.

While I accidentally dropped the pointer here, sorry for the confusion, 
what is antipattern? I have asked around and nobody really knew.

Wikipedia mentions it as a software development thing, but you make it 
sound like it is some sort of tool?

<snip>
>> +       if (unlikely(!pdev->dev.of_node)) {
>> +               dev_err(dev, "No devicetree data available\n");
>> +               ret = -EFAULT;
>> +               goto exit;
>
> Plain return here and in entire function where it applies.
Why? I know there's conflicting preferences here. The general consensus 
seems, don't return mid function if you don't absolutely have to. Yet, 
you make it sound, just return wherever. I take it that really is just a 
preference? I think i see both constructs throughout the kernel. So one 
review prefers the one method, the next the other?
<snip>
>> +
>> +       ret = device_create_bin_file(dev, &sid_bin_attr);
>> +       if (unlikely(ret)) {
>
> Any benifit of (un)likely in probe()?
Does it hurt however in any way though? It's just a compiler 
optimization isn't it.

<snip>
>
> --
> With Best Regards,
> Andy Shevchenko
>
Thank you for your time, it is much appreciated :)

Oliver

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-02 14:58   ` Oliver Schinagl
@ 2013-06-06 19:16     ` Andy Shevchenko
  -1 siblings, 0 replies; 142+ messages in thread
From: Andy Shevchenko @ 2013-06-06 19:16 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: maxime.ripard, Arnd Bergmann, Greg Kroah-Hartman, linux-kernel,
	linux-arm Mailing List, Oliver Schinagl

On Sun, Jun 2, 2013 at 5:58 PM, Oliver Schinagl <oliver+list@schinagl.nl> wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
>
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
>
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. From the name however it is
> highly likly that this name is the programming voltage, required to
> write these fuses.
> Even so, they can still be used to generate a board-unique mac from, board
> unique RSA key and seed the kernel RNG.
>
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A13)

Few commets below.

> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,172 @@

> +#define DRV_NAME "sunxi-sid"
> +#define DRV_VERSION "1.0"


> +static void __iomem *p_sid_reg_base;
So, why it's global?


> +/* We read the entire key, but only return the requested byte. This is of
> + * course slower then it could be and uses 4 times more reads as needed but
> + * keeps code a simpler.
> + */
> +u8 sunxi_sid_read_byte(const int offset)
> +{
> +       u32 sid_key;
> +       u8 ret;
> +
> +       ret = 0;

ret is redundant variable in this function.

> +       if (likely((SID_SIZE))) {

Extra braces.
Use antipattern here.

> +               sid_key = ioread32be(p_sid_reg_base + round_down(offset, 4));
> +               sid_key >>= (offset % 4) * 8;
> +               ret = sid_key & 0xff;

No need to do & 0xff, since return type is byte.

> +static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> +                       struct bin_attribute *attr, char *buf,
> +                       loff_t pos, size_t size)
> +{
> +       ssize_t ret;
> +       int i;
> +
> +       ret = -EPERM;

When will it happen?
Moreover, ret is redundant.

> +
> +       if ((likely(size > 0)) && ((size + pos) <= SID_SIZE)) {

Extra braces in second part of condition.
Use antipattern.

> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +       int entropy[SID_SIZE], i, ret;

Usually ret variable is located at the end of definition block.
Moreover, there is no relationship between those three. It means one
line per variable.

> +       struct device *dev;
> +       struct resource *res;
> +       void __iomem *sid_reg_base;
> +
> +       dev = &pdev->dev;

Please, be consistent, somewhere you still use &pdev->dev.
I recomend to use &pdev->dev everywhere in probe(), since we don't
know if the device will be probed successfully.

> +       if (unlikely(!pdev->dev.of_node)) {
> +               dev_err(dev, "No devicetree data available\n");
> +               ret = -EFAULT;
> +               goto exit;

Plain return here and in entire function where it applies.

> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(sid_reg_base)) {
> +               dev_err(dev, "Unable to obtain resource\n");

Redundant message. You have not to duplicate this.

> +               ret = PTR_ERR(sid_reg_base);
> +               goto exit;
> +       }
> +       platform_set_drvdata(pdev, sid_reg_base);
> +       p_sid_reg_base = sid_reg_base;
> +
> +       ret = device_create_bin_file(dev, &sid_bin_attr);
> +       if (unlikely(ret)) {

Any benifit of (un)likely in probe()?

> +
> +
> +exit:
> +       return ret;

Remove those two and empty lines.

--
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-06 19:16     ` Andy Shevchenko
  0 siblings, 0 replies; 142+ messages in thread
From: Andy Shevchenko @ 2013-06-06 19:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jun 2, 2013 at 5:58 PM, Oliver Schinagl <oliver+list@schinagl.nl> wrote:
> From: Oliver Schinagl <oliver@schinagl.nl>
>
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses, seeds the kernel entropy and exports them as a sysfs node.
>
> These fuses are most likly to be programmed at the factory, encoding
> things like Chip ID, some sort of serial number etc and appear to be
> reasonable unique.
> While in theory, these should be writeable by the user, it will probably
> be inconvinient to do so. Allwinner recommends that a certain input pin,
> labeled 'efuse_vddq', be connected to GND. From the name however it is
> highly likly that this name is the programming voltage, required to
> write these fuses.
> Even so, they can still be used to generate a board-unique mac from, board
> unique RSA key and seed the kernel RNG.
>
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A13)

Few commets below.

> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,172 @@

> +#define DRV_NAME "sunxi-sid"
> +#define DRV_VERSION "1.0"


> +static void __iomem *p_sid_reg_base;
So, why it's global?


> +/* We read the entire key, but only return the requested byte. This is of
> + * course slower then it could be and uses 4 times more reads as needed but
> + * keeps code a simpler.
> + */
> +u8 sunxi_sid_read_byte(const int offset)
> +{
> +       u32 sid_key;
> +       u8 ret;
> +
> +       ret = 0;

ret is redundant variable in this function.

> +       if (likely((SID_SIZE))) {

Extra braces.
Use antipattern here.

> +               sid_key = ioread32be(p_sid_reg_base + round_down(offset, 4));
> +               sid_key >>= (offset % 4) * 8;
> +               ret = sid_key & 0xff;

No need to do & 0xff, since return type is byte.

> +static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> +                       struct bin_attribute *attr, char *buf,
> +                       loff_t pos, size_t size)
> +{
> +       ssize_t ret;
> +       int i;
> +
> +       ret = -EPERM;

When will it happen?
Moreover, ret is redundant.

> +
> +       if ((likely(size > 0)) && ((size + pos) <= SID_SIZE)) {

Extra braces in second part of condition.
Use antipattern.

> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +       int entropy[SID_SIZE], i, ret;

Usually ret variable is located at the end of definition block.
Moreover, there is no relationship between those three. It means one
line per variable.

> +       struct device *dev;
> +       struct resource *res;
> +       void __iomem *sid_reg_base;
> +
> +       dev = &pdev->dev;

Please, be consistent, somewhere you still use &pdev->dev.
I recomend to use &pdev->dev everywhere in probe(), since we don't
know if the device will be probed successfully.

> +       if (unlikely(!pdev->dev.of_node)) {
> +               dev_err(dev, "No devicetree data available\n");
> +               ret = -EFAULT;
> +               goto exit;

Plain return here and in entire function where it applies.

> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(sid_reg_base)) {
> +               dev_err(dev, "Unable to obtain resource\n");

Redundant message. You have not to duplicate this.

> +               ret = PTR_ERR(sid_reg_base);
> +               goto exit;
> +       }
> +       platform_set_drvdata(pdev, sid_reg_base);
> +       p_sid_reg_base = sid_reg_base;
> +
> +       ret = device_create_bin_file(dev, &sid_bin_attr);
> +       if (unlikely(ret)) {

Any benifit of (un)likely in probe()?

> +
> +
> +exit:
> +       return ret;

Remove those two and empty lines.

--
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-02 15:09     ` Russell King - ARM Linux
@ 2013-06-02 15:21       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-02 15:21 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: maxime.ripard, arnd, gregkh, Oliver Schinagl, linux-kernel,
	linux-arm-kernel

On 06/02/13 17:09, Russell King - ARM Linux wrote:
> On Sun, Jun 02, 2013 at 04:58:49PM +0200, Oliver Schinagl wrote:
>> +#include <asm/io.h>
>
> We have an include file called linux/io.h.  Please use linux/*.h files which
> include asm/*.h files in preference to directly using asm/*.h.
>
> In fact, no driver should include an asm/*.h header.
And I didn't have that there, but it kept refusing to find ioread32be. 
Of course, now I change it back to linux/io.h (which I had, I swear) and 
all works swell.

Concider it changed.
>
>> +#include <linux/compiler.h>
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/errno.h>
>> +#include <linux/export.h>
>> +#include <linux/fs.h>
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/kobject.h>
>> +#include <linux/module.h>
>> +#include <linux/of_address.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/random.h>
>> +#include <linux/stat.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/types.h>
>> +
>> +#define DRV_NAME "sunxi-sid"
>> +#define DRV_VERSION "1.0"
>> +
>> +/* There are 4 32-bit keys */
>> +#define SID_KEYS 4
>> +/* and 4 byte sized keys per 32-bit key */
>> +#define SID_SIZE (SID_KEYS * 4)
>> +
>> +static void __iomem *p_sid_reg_base;
>> +
>> +/* We read the entire key, but only return the requested byte. This is of
>> + * course slower then it could be and uses 4 times more reads as needed but
>> + * keeps code a simpler.
>> + */
>> +u8 sunxi_sid_read_byte(const int offset)
>> +{
>> +	u32 sid_key;
>> +	u8 ret;
>> +
>> +	ret = 0;
>> +
>> +	if (likely((SID_SIZE))) {
>> +		sid_key = ioread32be(p_sid_reg_base + round_down(offset, 4));
>> +		sid_key >>= (offset % 4) * 8;
>> +		ret = sid_key & 0xff;
>> +	}
>
> What happens if you unbind the device in sysfs and then try and use
> this function?
>
>> +static int sunxi_sid_remove(struct platform_device *pdev)
>> +{
>> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
>> +	dev_info(&pdev->dev, "Sunxi SID driver unloaded successfully.\n");
>
> Maybe you want to set p_sid_reg_base to NULL here?
>
>> +
>> +	return 0;
>> +}
>> +
>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> +{
>> +	int entropy[SID_SIZE], i, ret;
>> +	struct device *dev;
>> +	struct resource *res;
>> +	void __iomem *sid_reg_base;
>> +
>> +	dev = &pdev->dev;
>> +	if (unlikely(!pdev->dev.of_node)) {
>> +		dev_err(dev, "No devicetree data available\n");
>> +		ret = -EFAULT;
>> +		goto exit;
>> +	}
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(sid_reg_base)) {
>> +		dev_err(dev, "Unable to obtain resource\n");
>> +		ret = PTR_ERR(sid_reg_base);
>> +		goto exit;
>> +	}
>> +	platform_set_drvdata(pdev, sid_reg_base);
>> +	p_sid_reg_base = sid_reg_base;
>
> So what happens if you have two of these devices?  Maybe you want to check
> whether p_sid_reg_base is already set?
>
>> +
>> +	ret = device_create_bin_file(dev, &sid_bin_attr);
>> +	if (unlikely(ret)) {
>> +		dev_err(dev, "Unable to create sysfs bin entry\n");
>> +		goto exit;
>> +	}
>> +
>> +	for (i = 0; i < SID_SIZE; i++)
>> +		entropy[i] = sunxi_sid_read_byte(i);
>> +	add_device_randomness(entropy, SID_SIZE);
>> +
>> +	dev_info(dev, "Sunxi SID driver loaded successfully.\n");
>
> Do we really need to report that the driver "loaded successfully" ?
> Do we need lots of lines in the kernel log telling us simply that
> random driver X was built into the kernel or the module was loaded?
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-02 15:21       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-02 15:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/02/13 17:09, Russell King - ARM Linux wrote:
> On Sun, Jun 02, 2013 at 04:58:49PM +0200, Oliver Schinagl wrote:
>> +#include <asm/io.h>
>
> We have an include file called linux/io.h.  Please use linux/*.h files which
> include asm/*.h files in preference to directly using asm/*.h.
>
> In fact, no driver should include an asm/*.h header.
And I didn't have that there, but it kept refusing to find ioread32be. 
Of course, now I change it back to linux/io.h (which I had, I swear) and 
all works swell.

Concider it changed.
>
>> +#include <linux/compiler.h>
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/errno.h>
>> +#include <linux/export.h>
>> +#include <linux/fs.h>
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/kobject.h>
>> +#include <linux/module.h>
>> +#include <linux/of_address.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/random.h>
>> +#include <linux/stat.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/types.h>
>> +
>> +#define DRV_NAME "sunxi-sid"
>> +#define DRV_VERSION "1.0"
>> +
>> +/* There are 4 32-bit keys */
>> +#define SID_KEYS 4
>> +/* and 4 byte sized keys per 32-bit key */
>> +#define SID_SIZE (SID_KEYS * 4)
>> +
>> +static void __iomem *p_sid_reg_base;
>> +
>> +/* We read the entire key, but only return the requested byte. This is of
>> + * course slower then it could be and uses 4 times more reads as needed but
>> + * keeps code a simpler.
>> + */
>> +u8 sunxi_sid_read_byte(const int offset)
>> +{
>> +	u32 sid_key;
>> +	u8 ret;
>> +
>> +	ret = 0;
>> +
>> +	if (likely((SID_SIZE))) {
>> +		sid_key = ioread32be(p_sid_reg_base + round_down(offset, 4));
>> +		sid_key >>= (offset % 4) * 8;
>> +		ret = sid_key & 0xff;
>> +	}
>
> What happens if you unbind the device in sysfs and then try and use
> this function?
>
>> +static int sunxi_sid_remove(struct platform_device *pdev)
>> +{
>> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
>> +	dev_info(&pdev->dev, "Sunxi SID driver unloaded successfully.\n");
>
> Maybe you want to set p_sid_reg_base to NULL here?
>
>> +
>> +	return 0;
>> +}
>> +
>> +static int __init sunxi_sid_probe(struct platform_device *pdev)
>> +{
>> +	int entropy[SID_SIZE], i, ret;
>> +	struct device *dev;
>> +	struct resource *res;
>> +	void __iomem *sid_reg_base;
>> +
>> +	dev = &pdev->dev;
>> +	if (unlikely(!pdev->dev.of_node)) {
>> +		dev_err(dev, "No devicetree data available\n");
>> +		ret = -EFAULT;
>> +		goto exit;
>> +	}
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(sid_reg_base)) {
>> +		dev_err(dev, "Unable to obtain resource\n");
>> +		ret = PTR_ERR(sid_reg_base);
>> +		goto exit;
>> +	}
>> +	platform_set_drvdata(pdev, sid_reg_base);
>> +	p_sid_reg_base = sid_reg_base;
>
> So what happens if you have two of these devices?  Maybe you want to check
> whether p_sid_reg_base is already set?
>
>> +
>> +	ret = device_create_bin_file(dev, &sid_bin_attr);
>> +	if (unlikely(ret)) {
>> +		dev_err(dev, "Unable to create sysfs bin entry\n");
>> +		goto exit;
>> +	}
>> +
>> +	for (i = 0; i < SID_SIZE; i++)
>> +		entropy[i] = sunxi_sid_read_byte(i);
>> +	add_device_randomness(entropy, SID_SIZE);
>> +
>> +	dev_info(dev, "Sunxi SID driver loaded successfully.\n");
>
> Do we really need to report that the driver "loaded successfully" ?
> Do we need lots of lines in the kernel log telling us simply that
> random driver X was built into the kernel or the module was loaded?
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-02 14:58   ` Oliver Schinagl
@ 2013-06-02 15:09     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 142+ messages in thread
From: Russell King - ARM Linux @ 2013-06-02 15:09 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: maxime.ripard, arnd, gregkh, Oliver Schinagl, linux-kernel,
	linux-arm-kernel

On Sun, Jun 02, 2013 at 04:58:49PM +0200, Oliver Schinagl wrote:
> +#include <asm/io.h>

We have an include file called linux/io.h.  Please use linux/*.h files which
include asm/*.h files in preference to directly using asm/*.h.

In fact, no driver should include an asm/*.h header.

> +#include <linux/compiler.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/random.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +#define DRV_NAME "sunxi-sid"
> +#define DRV_VERSION "1.0"
> +
> +/* There are 4 32-bit keys */
> +#define SID_KEYS 4
> +/* and 4 byte sized keys per 32-bit key */
> +#define SID_SIZE (SID_KEYS * 4)
> +
> +static void __iomem *p_sid_reg_base;
> +
> +/* We read the entire key, but only return the requested byte. This is of
> + * course slower then it could be and uses 4 times more reads as needed but
> + * keeps code a simpler.
> + */
> +u8 sunxi_sid_read_byte(const int offset)
> +{
> +	u32 sid_key;
> +	u8 ret;
> +
> +	ret = 0;
> +
> +	if (likely((SID_SIZE))) {
> +		sid_key = ioread32be(p_sid_reg_base + round_down(offset, 4));
> +		sid_key >>= (offset % 4) * 8;
> +		ret = sid_key & 0xff;
> +	}

What happens if you unbind the device in sysfs and then try and use
this function?

> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> +	dev_info(&pdev->dev, "Sunxi SID driver unloaded successfully.\n");

Maybe you want to set p_sid_reg_base to NULL here?

> +
> +	return 0;
> +}
> +
> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	int entropy[SID_SIZE], i, ret;
> +	struct device *dev;
> +	struct resource *res;
> +	void __iomem *sid_reg_base;
> +
> +	dev = &pdev->dev;
> +	if (unlikely(!pdev->dev.of_node)) {
> +		dev_err(dev, "No devicetree data available\n");
> +		ret = -EFAULT;
> +		goto exit;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(sid_reg_base)) {
> +		dev_err(dev, "Unable to obtain resource\n");
> +		ret = PTR_ERR(sid_reg_base);
> +		goto exit;
> +	}
> +	platform_set_drvdata(pdev, sid_reg_base);
> +	p_sid_reg_base = sid_reg_base;

So what happens if you have two of these devices?  Maybe you want to check
whether p_sid_reg_base is already set?

> +
> +	ret = device_create_bin_file(dev, &sid_bin_attr);
> +	if (unlikely(ret)) {
> +		dev_err(dev, "Unable to create sysfs bin entry\n");
> +		goto exit;
> +	}
> +
> +	for (i = 0; i < SID_SIZE; i++)
> +		entropy[i] = sunxi_sid_read_byte(i);
> +	add_device_randomness(entropy, SID_SIZE);
> +
> +	dev_info(dev, "Sunxi SID driver loaded successfully.\n");

Do we really need to report that the driver "loaded successfully" ?
Do we need lots of lines in the kernel log telling us simply that
random driver X was built into the kernel or the module was loaded?

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-02 15:09     ` Russell King - ARM Linux
  0 siblings, 0 replies; 142+ messages in thread
From: Russell King - ARM Linux @ 2013-06-02 15:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jun 02, 2013 at 04:58:49PM +0200, Oliver Schinagl wrote:
> +#include <asm/io.h>

We have an include file called linux/io.h.  Please use linux/*.h files which
include asm/*.h files in preference to directly using asm/*.h.

In fact, no driver should include an asm/*.h header.

> +#include <linux/compiler.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/random.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +#define DRV_NAME "sunxi-sid"
> +#define DRV_VERSION "1.0"
> +
> +/* There are 4 32-bit keys */
> +#define SID_KEYS 4
> +/* and 4 byte sized keys per 32-bit key */
> +#define SID_SIZE (SID_KEYS * 4)
> +
> +static void __iomem *p_sid_reg_base;
> +
> +/* We read the entire key, but only return the requested byte. This is of
> + * course slower then it could be and uses 4 times more reads as needed but
> + * keeps code a simpler.
> + */
> +u8 sunxi_sid_read_byte(const int offset)
> +{
> +	u32 sid_key;
> +	u8 ret;
> +
> +	ret = 0;
> +
> +	if (likely((SID_SIZE))) {
> +		sid_key = ioread32be(p_sid_reg_base + round_down(offset, 4));
> +		sid_key >>= (offset % 4) * 8;
> +		ret = sid_key & 0xff;
> +	}

What happens if you unbind the device in sysfs and then try and use
this function?

> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
> +	dev_info(&pdev->dev, "Sunxi SID driver unloaded successfully.\n");

Maybe you want to set p_sid_reg_base to NULL here?

> +
> +	return 0;
> +}
> +
> +static int __init sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	int entropy[SID_SIZE], i, ret;
> +	struct device *dev;
> +	struct resource *res;
> +	void __iomem *sid_reg_base;
> +
> +	dev = &pdev->dev;
> +	if (unlikely(!pdev->dev.of_node)) {
> +		dev_err(dev, "No devicetree data available\n");
> +		ret = -EFAULT;
> +		goto exit;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(sid_reg_base)) {
> +		dev_err(dev, "Unable to obtain resource\n");
> +		ret = PTR_ERR(sid_reg_base);
> +		goto exit;
> +	}
> +	platform_set_drvdata(pdev, sid_reg_base);
> +	p_sid_reg_base = sid_reg_base;

So what happens if you have two of these devices?  Maybe you want to check
whether p_sid_reg_base is already set?

> +
> +	ret = device_create_bin_file(dev, &sid_bin_attr);
> +	if (unlikely(ret)) {
> +		dev_err(dev, "Unable to create sysfs bin entry\n");
> +		goto exit;
> +	}
> +
> +	for (i = 0; i < SID_SIZE; i++)
> +		entropy[i] = sunxi_sid_read_byte(i);
> +	add_device_randomness(entropy, SID_SIZE);
> +
> +	dev_info(dev, "Sunxi SID driver loaded successfully.\n");

Do we really need to report that the driver "loaded successfully" ?
Do we need lots of lines in the kernel log telling us simply that
random driver X was built into the kernel or the module was loaded?

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-06-02 14:58 [PATCH 0/2] v2 Driver for Allwinner sunxi Security ID Oliver Schinagl
@ 2013-06-02 14:58   ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-02 14:58 UTC (permalink / raw)
  To: maxime.ripard, arnd, gregkh
  Cc: linux-kernel, linux-arm-kernel, Oliver Schinagl

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses, seeds the kernel entropy and exports them as a sysfs node.

These fuses are most likly to be programmed at the factory, encoding
things like Chip ID, some sort of serial number etc and appear to be
reasonable unique.
While in theory, these should be writeable by the user, it will probably
be inconvinient to do so. Allwinner recommends that a certain input pin,
labeled 'efuse_vddq', be connected to GND. From the name however it is
highly likly that this name is the programming voltage, required to
write these fuses.
Even so, they can still be used to generate a board-unique mac from, board
unique RSA key and seed the kernel RNG.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A13)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 drivers/misc/eeprom/Kconfig     |  17 ++++
 drivers/misc/eeprom/Makefile    |   1 +
 drivers/misc/eeprom/sunxi_sid.c | 172 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..c7bc6ed 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,21 @@ 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. Currently supported are:
+		sun4i (A10)
+		sun5i (A13)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..4ec86d5
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2013 Oliver Schinagl
+ * http://www.linux-sunxi.org
+ *
+ * Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * 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, a 128 bit eeprom, in byte
+ * sized chunks.
+ */
+
+#include <asm/io.h>
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define DRV_NAME "sunxi-sid"
+#define DRV_VERSION "1.0"
+
+/* There are 4 32-bit keys */
+#define SID_KEYS 4
+/* and 4 byte sized keys per 32-bit key */
+#define SID_SIZE (SID_KEYS * 4)
+
+static void __iomem *p_sid_reg_base;
+
+/* We read the entire key, but only return the requested byte. This is of
+ * course slower then it could be and uses 4 times more reads as needed but
+ * keeps code a simpler.
+ */
+u8 sunxi_sid_read_byte(const int offset)
+{
+	u32 sid_key;
+	u8 ret;
+
+	ret = 0;
+
+	if (likely((SID_SIZE))) {
+		sid_key = ioread32be(p_sid_reg_base + round_down(offset, 4));
+		sid_key >>= (offset % 4) * 8;
+		ret = sid_key & 0xff;
+	}
+
+	return ret;
+}
+
+static ssize_t sid_read(struct file *fd, struct kobject *kobj,
+			struct bin_attribute *attr, char *buf,
+			loff_t pos, size_t size)
+{
+	ssize_t ret;
+	int i;
+
+	ret = -EPERM;
+
+	if ((likely(size > 0)) && ((size + pos) <= SID_SIZE)) {
+		for (i = 0; i < size; i++)
+			buf[i] = sunxi_sid_read_byte(pos + i);
+		ret = (ssize_t)size;
+	} else {
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{
+		.compatible = "allwinner,sun4i-sid",
+	},
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static const struct bin_attribute sid_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO,
+	},
+	.size = SID_SIZE,
+	.read = sid_read,
+};
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
+	dev_info(&pdev->dev, "Sunxi SID driver unloaded successfully.\n");
+
+	return 0;
+}
+
+static int __init sunxi_sid_probe(struct platform_device *pdev)
+{
+	int entropy[SID_SIZE], i, ret;
+	struct device *dev;
+	struct resource *res;
+	void __iomem *sid_reg_base;
+
+	dev = &pdev->dev;
+	if (unlikely(!pdev->dev.of_node)) {
+		dev_err(dev, "No devicetree data available\n");
+		ret = -EFAULT;
+		goto exit;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sid_reg_base)) {
+		dev_err(dev, "Unable to obtain resource\n");
+		ret = PTR_ERR(sid_reg_base);
+		goto exit;
+	}
+	platform_set_drvdata(pdev, sid_reg_base);
+	p_sid_reg_base = sid_reg_base;
+
+	ret = device_create_bin_file(dev, &sid_bin_attr);
+	if (unlikely(ret)) {
+		dev_err(dev, "Unable to create sysfs bin entry\n");
+		goto exit;
+	}
+
+	for (i = 0; i < SID_SIZE; i++)
+		entropy[i] = sunxi_sid_read_byte(i);
+	add_device_randomness(entropy, SID_SIZE);
+
+	dev_info(dev, "Sunxi SID driver loaded successfully.\n");
+
+	return 0;
+
+
+exit:
+	return ret;
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.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_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
-- 
1.8.1.5


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-06-02 14:58   ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-06-02 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses, seeds the kernel entropy and exports them as a sysfs node.

These fuses are most likly to be programmed at the factory, encoding
things like Chip ID, some sort of serial number etc and appear to be
reasonable unique.
While in theory, these should be writeable by the user, it will probably
be inconvinient to do so. Allwinner recommends that a certain input pin,
labeled 'efuse_vddq', be connected to GND. From the name however it is
highly likly that this name is the programming voltage, required to
write these fuses.
Even so, they can still be used to generate a board-unique mac from, board
unique RSA key and seed the kernel RNG.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A13)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 drivers/misc/eeprom/Kconfig     |  17 ++++
 drivers/misc/eeprom/Makefile    |   1 +
 drivers/misc/eeprom/sunxi_sid.c | 172 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..c7bc6ed 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,21 @@ 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. Currently supported are:
+		sun4i (A10)
+		sun5i (A13)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..4ec86d5
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2013 Oliver Schinagl
+ * http://www.linux-sunxi.org
+ *
+ * Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * 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, a 128 bit eeprom, in byte
+ * sized chunks.
+ */
+
+#include <asm/io.h>
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define DRV_NAME "sunxi-sid"
+#define DRV_VERSION "1.0"
+
+/* There are 4 32-bit keys */
+#define SID_KEYS 4
+/* and 4 byte sized keys per 32-bit key */
+#define SID_SIZE (SID_KEYS * 4)
+
+static void __iomem *p_sid_reg_base;
+
+/* We read the entire key, but only return the requested byte. This is of
+ * course slower then it could be and uses 4 times more reads as needed but
+ * keeps code a simpler.
+ */
+u8 sunxi_sid_read_byte(const int offset)
+{
+	u32 sid_key;
+	u8 ret;
+
+	ret = 0;
+
+	if (likely((SID_SIZE))) {
+		sid_key = ioread32be(p_sid_reg_base + round_down(offset, 4));
+		sid_key >>= (offset % 4) * 8;
+		ret = sid_key & 0xff;
+	}
+
+	return ret;
+}
+
+static ssize_t sid_read(struct file *fd, struct kobject *kobj,
+			struct bin_attribute *attr, char *buf,
+			loff_t pos, size_t size)
+{
+	ssize_t ret;
+	int i;
+
+	ret = -EPERM;
+
+	if ((likely(size > 0)) && ((size + pos) <= SID_SIZE)) {
+		for (i = 0; i < size; i++)
+			buf[i] = sunxi_sid_read_byte(pos + i);
+		ret = (ssize_t)size;
+	} else {
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{
+		.compatible = "allwinner,sun4i-sid",
+	},
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static const struct bin_attribute sid_bin_attr = {
+	.attr = {
+		.name = "eeprom",
+		.mode = S_IRUGO,
+	},
+	.size = SID_SIZE,
+	.read = sid_read,
+};
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
+	dev_info(&pdev->dev, "Sunxi SID driver unloaded successfully.\n");
+
+	return 0;
+}
+
+static int __init sunxi_sid_probe(struct platform_device *pdev)
+{
+	int entropy[SID_SIZE], i, ret;
+	struct device *dev;
+	struct resource *res;
+	void __iomem *sid_reg_base;
+
+	dev = &pdev->dev;
+	if (unlikely(!pdev->dev.of_node)) {
+		dev_err(dev, "No devicetree data available\n");
+		ret = -EFAULT;
+		goto exit;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid_reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sid_reg_base)) {
+		dev_err(dev, "Unable to obtain resource\n");
+		ret = PTR_ERR(sid_reg_base);
+		goto exit;
+	}
+	platform_set_drvdata(pdev, sid_reg_base);
+	p_sid_reg_base = sid_reg_base;
+
+	ret = device_create_bin_file(dev, &sid_bin_attr);
+	if (unlikely(ret)) {
+		dev_err(dev, "Unable to create sysfs bin entry\n");
+		goto exit;
+	}
+
+	for (i = 0; i < SID_SIZE; i++)
+		entropy[i] = sunxi_sid_read_byte(i);
+	add_device_randomness(entropy, SID_SIZE);
+
+	dev_info(dev, "Sunxi SID driver loaded successfully.\n");
+
+	return 0;
+
+
+exit:
+	return ret;
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.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_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
-- 
1.8.1.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-25 19:25             ` Oliver Schinagl
@ 2013-05-26  9:35               ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-26  9:35 UTC (permalink / raw)
  To: Oliver Schinagl; +Cc: linux-arm-kernel, gregkh, linux-kernel, arnd

On Sat, May 25, 2013 at 09:25:51PM +0200, Oliver Schinagl wrote:
> On 05/25/13 14:22, Maxime Ripard wrote:
> >What about:
> >
> >val = ioread32be(base + (key / 4));
> >val >>= (key % 4) * 8;
> >return val & 0xff;
> >
> >No lookup table, no weird swich statement, and you get the endianness
> >conversion only when you need it.
> Ok I think I like the Endianess, ioread32be does the right thing
> then? I'll read up on that.
> As for key / 4; how will that work without the lut?
> 
> Lets take byte 14 (out of the available 16). Byte 14 (0x0e) is
> located in SID_KEY3, so base + 0x0c. We need to write a whole 32bit
> word to keep with alignment, the registers go wakko if you do
> unaligned reads. So we need to read the entire 32 bits, then find
> our byte.
> 
> key / 4 for 14 yields 0x03. So we have base + 0x03, which is not
> what we want. We want base + 0x0c, which is either ((key >> 2) <<
> 2)) Or, ((key / 4) * 4)) which to me, are both equally confusing.

The statement you make that 3 isn't the index you want depends on your
pointer type so it might be what you want, or might not.

If it's still not what you want, you can always use round_down(key, 4).

> So we either use the look up table, which is a little cleaner and is a
> bit more future proof if either a) there's more 'eeprom like'
> storage which can be combined herein or b) 'a' next version has
> non-continuing regions. Granted neither is something to worry about
> right now.

I don't see how it's cleaner (you have three indirections to get
the value that is actually used) or future proof (you have to extend
this lookup table every time you have a slightly larger size).

So I'm sorry but this lookup table holding only the index times 4 is
a non-sense, could we please stop arguing about this?

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-26  9:35               ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-26  9:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 25, 2013 at 09:25:51PM +0200, Oliver Schinagl wrote:
> On 05/25/13 14:22, Maxime Ripard wrote:
> >What about:
> >
> >val = ioread32be(base + (key / 4));
> >val >>= (key % 4) * 8;
> >return val & 0xff;
> >
> >No lookup table, no weird swich statement, and you get the endianness
> >conversion only when you need it.
> Ok I think I like the Endianess, ioread32be does the right thing
> then? I'll read up on that.
> As for key / 4; how will that work without the lut?
> 
> Lets take byte 14 (out of the available 16). Byte 14 (0x0e) is
> located in SID_KEY3, so base + 0x0c. We need to write a whole 32bit
> word to keep with alignment, the registers go wakko if you do
> unaligned reads. So we need to read the entire 32 bits, then find
> our byte.
> 
> key / 4 for 14 yields 0x03. So we have base + 0x03, which is not
> what we want. We want base + 0x0c, which is either ((key >> 2) <<
> 2)) Or, ((key / 4) * 4)) which to me, are both equally confusing.

The statement you make that 3 isn't the index you want depends on your
pointer type so it might be what you want, or might not.

If it's still not what you want, you can always use round_down(key, 4).

> So we either use the look up table, which is a little cleaner and is a
> bit more future proof if either a) there's more 'eeprom like'
> storage which can be combined herein or b) 'a' next version has
> non-continuing regions. Granted neither is something to worry about
> right now.

I don't see how it's cleaner (you have three indirections to get
the value that is actually used) or future proof (you have to extend
this lookup table every time you have a slightly larger size).

So I'm sorry but this lookup table holding only the index times 4 is
a non-sense, could we please stop arguing about this?

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-25 12:22           ` Maxime Ripard
@ 2013-05-25 19:25             ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-25 19:25 UTC (permalink / raw)
  To: Maxime Ripard; +Cc: linux-arm-kernel, gregkh, linux-kernel, arnd

On 05/25/13 14:22, Maxime Ripard wrote:
> Hi Oliver,
>
> On Fri, May 24, 2013 at 11:50:38PM +0200, Oliver Schinagl wrote:
>> On 05/18/13 19:19, Oliver Schinagl wrote:
>> <snip>
>>>>> +
>>>>> +
>>>>> +/* We read the entire key, using a look up table. Returned is only the
>>>>> + * requested byte. This is of course slower then it could be and uses 4 times
>>>>> + * more reads as needed but keeps code a little simpler.
>>>>> + */
>>>>> +u8 sunxi_sid_read_byte(const int key)
>>>>> +{
>>>>> +	u32 sid_key;
>>>>> +	u8 ret;
>>>>> +
>>>>> +	ret = 0;
>>>>> +	if (likely((key <= SUNXI_SID_SIZE))) {
>>>>> +		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
>>>>> +		switch (key % 4) {
>>>>> +		case 0:
>>>>> +			ret = (sid_key >> 24) & 0xff;
>>>>> +			break;
>>>>> +		case 1:
>>>>> +			ret = (sid_key >> 16) & 0xff;
>>>>> +			break;
>>>>> +		case 2:
>>>>> +			ret = (sid_key >> 8) & 0xff;
>>>>> +			break;
>>>>> +		case 3:
>>>>> +			ret = sid_key & 0xff;
>>>>> +			break;
>>>>> +		}
>>>>> +	}
>>>>
>>>> Come on, you can do better. This lookup table is useless.
>>> I didn't want to depend on the fixed layout of memory, but consider it
>>> removed.
>> But i'm not smart enough :p
>>
>> We can either use the look up table (which does have benefits as its
>> potentially more future proof), or do some ((key >> 2) << 2) to
>> 'drop' the LSB's that we want to ignore (unless there's some smarter
>> way).
>>
>> Personally, I think the LUT is a little cleaner and more readable,
>> but I guess if you look at poor efficiency, the lut costs some
>> memory, the left/right shift cost an additional >> 2 ... what you
>> prefer.
>
> What about:
>
> val = ioread32be(base + (key / 4));
> val >>= (key % 4) * 8;
> return val & 0xff;
>
> No lookup table, no weird swich statement, and you get the endianness
> conversion only when you need it.
Ok I think I like the Endianess, ioread32be does the right thing then? 
I'll read up on that.
As for key / 4; how will that work without the lut?

Lets take byte 14 (out of the available 16). Byte 14 (0x0e) is located 
in SID_KEY3, so base + 0x0c. We need to write a whole 32bit word to keep 
with alignment, the registers go wakko if you do unaligned reads. So we 
need to read the entire 32 bits, then find our byte.

key / 4 for 14 yields 0x03. So we have base + 0x03, which is not what we 
want. We want base + 0x0c, which is either ((key >> 2) << 2)) Or, ((key 
/ 4) * 4)) which to me, are both equally confusing. So we either use the 
look up table, which is a little cleaner and is a bit more future proof 
if either a) there's more 'eeprom like' storage which can be combined 
herein or b) 'a' next version has non-continuing regions. Granted 
neither is something to worry about right now.

Turl already mentioned the calculated shift, instead of the switch. I 
agree to also like it better and have already rewritten that bit.


If I made a really stupid thinking mistake or my math is somehow wrong, 
feel free to point it out :) I don't mind manning up to my mistakes :)
>
> Maxime
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-25 19:25             ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-25 19:25 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/25/13 14:22, Maxime Ripard wrote:
> Hi Oliver,
>
> On Fri, May 24, 2013 at 11:50:38PM +0200, Oliver Schinagl wrote:
>> On 05/18/13 19:19, Oliver Schinagl wrote:
>> <snip>
>>>>> +
>>>>> +
>>>>> +/* We read the entire key, using a look up table. Returned is only the
>>>>> + * requested byte. This is of course slower then it could be and uses 4 times
>>>>> + * more reads as needed but keeps code a little simpler.
>>>>> + */
>>>>> +u8 sunxi_sid_read_byte(const int key)
>>>>> +{
>>>>> +	u32 sid_key;
>>>>> +	u8 ret;
>>>>> +
>>>>> +	ret = 0;
>>>>> +	if (likely((key <= SUNXI_SID_SIZE))) {
>>>>> +		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
>>>>> +		switch (key % 4) {
>>>>> +		case 0:
>>>>> +			ret = (sid_key >> 24) & 0xff;
>>>>> +			break;
>>>>> +		case 1:
>>>>> +			ret = (sid_key >> 16) & 0xff;
>>>>> +			break;
>>>>> +		case 2:
>>>>> +			ret = (sid_key >> 8) & 0xff;
>>>>> +			break;
>>>>> +		case 3:
>>>>> +			ret = sid_key & 0xff;
>>>>> +			break;
>>>>> +		}
>>>>> +	}
>>>>
>>>> Come on, you can do better. This lookup table is useless.
>>> I didn't want to depend on the fixed layout of memory, but consider it
>>> removed.
>> But i'm not smart enough :p
>>
>> We can either use the look up table (which does have benefits as its
>> potentially more future proof), or do some ((key >> 2) << 2) to
>> 'drop' the LSB's that we want to ignore (unless there's some smarter
>> way).
>>
>> Personally, I think the LUT is a little cleaner and more readable,
>> but I guess if you look at poor efficiency, the lut costs some
>> memory, the left/right shift cost an additional >> 2 ... what you
>> prefer.
>
> What about:
>
> val = ioread32be(base + (key / 4));
> val >>= (key % 4) * 8;
> return val & 0xff;
>
> No lookup table, no weird swich statement, and you get the endianness
> conversion only when you need it.
Ok I think I like the Endianess, ioread32be does the right thing then? 
I'll read up on that.
As for key / 4; how will that work without the lut?

Lets take byte 14 (out of the available 16). Byte 14 (0x0e) is located 
in SID_KEY3, so base + 0x0c. We need to write a whole 32bit word to keep 
with alignment, the registers go wakko if you do unaligned reads. So we 
need to read the entire 32 bits, then find our byte.

key / 4 for 14 yields 0x03. So we have base + 0x03, which is not what we 
want. We want base + 0x0c, which is either ((key >> 2) << 2)) Or, ((key 
/ 4) * 4)) which to me, are both equally confusing. So we either use the 
look up table, which is a little cleaner and is a bit more future proof 
if either a) there's more 'eeprom like' storage which can be combined 
herein or b) 'a' next version has non-continuing regions. Granted 
neither is something to worry about right now.

Turl already mentioned the calculated shift, instead of the switch. I 
agree to also like it better and have already rewritten that bit.


If I made a really stupid thinking mistake or my math is somehow wrong, 
feel free to point it out :) I don't mind manning up to my mistakes :)
>
> Maxime
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-24 21:50         ` Oliver Schinagl
@ 2013-05-25 12:22           ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-25 12:22 UTC (permalink / raw)
  To: Oliver Schinagl; +Cc: linux-arm-kernel, gregkh, linux-kernel, arnd

Hi Oliver,

On Fri, May 24, 2013 at 11:50:38PM +0200, Oliver Schinagl wrote:
> On 05/18/13 19:19, Oliver Schinagl wrote:
> <snip>
> >>>+
> >>>+
> >>>+/* We read the entire key, using a look up table. Returned is only the
> >>>+ * requested byte. This is of course slower then it could be and uses 4 times
> >>>+ * more reads as needed but keeps code a little simpler.
> >>>+ */
> >>>+u8 sunxi_sid_read_byte(const int key)
> >>>+{
> >>>+	u32 sid_key;
> >>>+	u8 ret;
> >>>+
> >>>+	ret = 0;
> >>>+	if (likely((key <= SUNXI_SID_SIZE))) {
> >>>+		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
> >>>+		switch (key % 4) {
> >>>+		case 0:
> >>>+			ret = (sid_key >> 24) & 0xff;
> >>>+			break;
> >>>+		case 1:
> >>>+			ret = (sid_key >> 16) & 0xff;
> >>>+			break;
> >>>+		case 2:
> >>>+			ret = (sid_key >> 8) & 0xff;
> >>>+			break;
> >>>+		case 3:
> >>>+			ret = sid_key & 0xff;
> >>>+			break;
> >>>+		}
> >>>+	}
> >>
> >>Come on, you can do better. This lookup table is useless.
> >I didn't want to depend on the fixed layout of memory, but consider it
> >removed.
> But i'm not smart enough :p
> 
> We can either use the look up table (which does have benefits as its
> potentially more future proof), or do some ((key >> 2) << 2) to
> 'drop' the LSB's that we want to ignore (unless there's some smarter
> way).
> 
> Personally, I think the LUT is a little cleaner and more readable,
> but I guess if you look at poor efficiency, the lut costs some
> memory, the left/right shift cost an additional >> 2 ... what you
> prefer.

What about:

val = ioread32be(base + (key / 4));
val >>= (key % 4) * 8;
return val & 0xff;

No lookup table, no weird swich statement, and you get the endianness
conversion only when you need it.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-25 12:22           ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-25 12:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Oliver,

On Fri, May 24, 2013 at 11:50:38PM +0200, Oliver Schinagl wrote:
> On 05/18/13 19:19, Oliver Schinagl wrote:
> <snip>
> >>>+
> >>>+
> >>>+/* We read the entire key, using a look up table. Returned is only the
> >>>+ * requested byte. This is of course slower then it could be and uses 4 times
> >>>+ * more reads as needed but keeps code a little simpler.
> >>>+ */
> >>>+u8 sunxi_sid_read_byte(const int key)
> >>>+{
> >>>+	u32 sid_key;
> >>>+	u8 ret;
> >>>+
> >>>+	ret = 0;
> >>>+	if (likely((key <= SUNXI_SID_SIZE))) {
> >>>+		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
> >>>+		switch (key % 4) {
> >>>+		case 0:
> >>>+			ret = (sid_key >> 24) & 0xff;
> >>>+			break;
> >>>+		case 1:
> >>>+			ret = (sid_key >> 16) & 0xff;
> >>>+			break;
> >>>+		case 2:
> >>>+			ret = (sid_key >> 8) & 0xff;
> >>>+			break;
> >>>+		case 3:
> >>>+			ret = sid_key & 0xff;
> >>>+			break;
> >>>+		}
> >>>+	}
> >>
> >>Come on, you can do better. This lookup table is useless.
> >I didn't want to depend on the fixed layout of memory, but consider it
> >removed.
> But i'm not smart enough :p
> 
> We can either use the look up table (which does have benefits as its
> potentially more future proof), or do some ((key >> 2) << 2) to
> 'drop' the LSB's that we want to ignore (unless there's some smarter
> way).
> 
> Personally, I think the LUT is a little cleaner and more readable,
> but I guess if you look at poor efficiency, the lut costs some
> memory, the left/right shift cost an additional >> 2 ... what you
> prefer.

What about:

val = ioread32be(base + (key / 4));
val >>= (key % 4) * 8;
return val & 0xff;

No lookup table, no weird swich statement, and you get the endianness
conversion only when you need it.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-18 17:19       ` Oliver Schinagl
@ 2013-05-24 21:50         ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-24 21:50 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Maxime Ripard, arnd, gregkh, linux-kernel, linux-arm-kernel

On 05/18/13 19:19, Oliver Schinagl wrote:
<snip>
>>> +
>>> +
>>> +/* We read the entire key, using a look up table. Returned is only the
>>> + * requested byte. This is of course slower then it could be and uses 4 times
>>> + * more reads as needed but keeps code a little simpler.
>>> + */
>>> +u8 sunxi_sid_read_byte(const int key)
>>> +{
>>> +	u32 sid_key;
>>> +	u8 ret;
>>> +
>>> +	ret = 0;
>>> +	if (likely((key <= SUNXI_SID_SIZE))) {
>>> +		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
>>> +		switch (key % 4) {
>>> +		case 0:
>>> +			ret = (sid_key >> 24) & 0xff;
>>> +			break;
>>> +		case 1:
>>> +			ret = (sid_key >> 16) & 0xff;
>>> +			break;
>>> +		case 2:
>>> +			ret = (sid_key >> 8) & 0xff;
>>> +			break;
>>> +		case 3:
>>> +			ret = sid_key & 0xff;
>>> +			break;
>>> +		}
>>> +	}
>>
>> Come on, you can do better. This lookup table is useless.
> I didn't want to depend on the fixed layout of memory, but consider it
> removed.
But i'm not smart enough :p

We can either use the look up table (which does have benefits as its 
potentially more future proof), or do some ((key >> 2) << 2) to 'drop' 
the LSB's that we want to ignore (unless there's some smarter way).

Personally, I think the LUT is a little cleaner and more readable, but I 
guess if you look at poor efficiency, the lut costs some memory, the 
left/right shift cost an additional >> 2 ... what you prefer.
>>
>> Also, why the first key is the one with the MSBs?
>> I'd expect that the key 0 is the one holding the LSBs.
> Strangely enough, they have swapped the MSB and LSB bytes. I double
> checked it with u-boot and yep, swapped. Though in the end, if we write
> stuff there and we read stuff from there, order doesn't matter? So what
> do we prefer. Have it so that it makes sense and ignore how u-boot reads
> it, or correct it and be consistent?
>
You had me confused and I was looking at this for a little while. 
Bit-ordering does not change, Byte endianness is a different story of 
course. As it is now, I decided to use Big endianess. So now a 32bit key 
looks like:
0x162367c7 and if we read one byte at a time, we get 0x16, 0x23, 0x67 
and 0xc7. I made a comment that data is read as Big endian. If it is 
important, for eeprom data, to be stored little endian, I'll obviously 
change it per request.


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-24 21:50         ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-24 21:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/18/13 19:19, Oliver Schinagl wrote:
<snip>
>>> +
>>> +
>>> +/* We read the entire key, using a look up table. Returned is only the
>>> + * requested byte. This is of course slower then it could be and uses 4 times
>>> + * more reads as needed but keeps code a little simpler.
>>> + */
>>> +u8 sunxi_sid_read_byte(const int key)
>>> +{
>>> +	u32 sid_key;
>>> +	u8 ret;
>>> +
>>> +	ret = 0;
>>> +	if (likely((key <= SUNXI_SID_SIZE))) {
>>> +		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
>>> +		switch (key % 4) {
>>> +		case 0:
>>> +			ret = (sid_key >> 24) & 0xff;
>>> +			break;
>>> +		case 1:
>>> +			ret = (sid_key >> 16) & 0xff;
>>> +			break;
>>> +		case 2:
>>> +			ret = (sid_key >> 8) & 0xff;
>>> +			break;
>>> +		case 3:
>>> +			ret = sid_key & 0xff;
>>> +			break;
>>> +		}
>>> +	}
>>
>> Come on, you can do better. This lookup table is useless.
> I didn't want to depend on the fixed layout of memory, but consider it
> removed.
But i'm not smart enough :p

We can either use the look up table (which does have benefits as its 
potentially more future proof), or do some ((key >> 2) << 2) to 'drop' 
the LSB's that we want to ignore (unless there's some smarter way).

Personally, I think the LUT is a little cleaner and more readable, but I 
guess if you look@poor efficiency, the lut costs some memory, the 
left/right shift cost an additional >> 2 ... what you prefer.
>>
>> Also, why the first key is the one with the MSBs?
>> I'd expect that the key 0 is the one holding the LSBs.
> Strangely enough, they have swapped the MSB and LSB bytes. I double
> checked it with u-boot and yep, swapped. Though in the end, if we write
> stuff there and we read stuff from there, order doesn't matter? So what
> do we prefer. Have it so that it makes sense and ignore how u-boot reads
> it, or correct it and be consistent?
>
You had me confused and I was looking at this for a little while. 
Bit-ordering does not change, Byte endianness is a different story of 
course. As it is now, I decided to use Big endianess. So now a 32bit key 
looks like:
0x162367c7 and if we read one byte at a time, we get 0x16, 0x23, 0x67 
and 0xc7. I made a comment that data is read as Big endian. If it is 
important, for eeprom data, to be stored little endian, I'll obviously 
change it per request.

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-23 15:05           ` Oliver Schinagl
@ 2013-05-23 15:27             ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-23 15:27 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Linus Walleij, Arnd Bergmann, Greg KH, Oliver Schinagl,
	linux-kernel, linux-arm-kernel

On Thu, May 23, 2013 at 05:05:21PM +0200, Oliver Schinagl wrote:
> On 05/23/13 16:58, Maxime Ripard wrote:
> >On Thu, May 23, 2013 at 10:10:17AM +0200, Oliver Schinagl wrote:
> >>Then, i'm not sure if the driver is the best for this to be loaded?
> >>Maxime, what do you think? Personally I would feel more in having
> >>this in the mach-sunxi/core.c bit, but then again, this is currently
> >>a module and wouldn't be useful to have there. Maxime is far more
> >>knowledgeable to answer that.
> >
> >Hmmm, I don't understand what you mean here. Could you explain what you
> >have in mind?
> I've thought about it a little, and don't think core.c is a good
> spot, since the module will have to be loaded, or available there.
> And that's really early.
> 
> So I guess, during probe, controlled by a parameter perhaps, load
> all 16 bytes into the random pool as Linus suggested?

Yeah, though I don't really know what the parameter would be useful for,
but yes, do it in the driver's probe.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-23 15:27             ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-23 15:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 23, 2013 at 05:05:21PM +0200, Oliver Schinagl wrote:
> On 05/23/13 16:58, Maxime Ripard wrote:
> >On Thu, May 23, 2013 at 10:10:17AM +0200, Oliver Schinagl wrote:
> >>Then, i'm not sure if the driver is the best for this to be loaded?
> >>Maxime, what do you think? Personally I would feel more in having
> >>this in the mach-sunxi/core.c bit, but then again, this is currently
> >>a module and wouldn't be useful to have there. Maxime is far more
> >>knowledgeable to answer that.
> >
> >Hmmm, I don't understand what you mean here. Could you explain what you
> >have in mind?
> I've thought about it a little, and don't think core.c is a good
> spot, since the module will have to be loaded, or available there.
> And that's really early.
> 
> So I guess, during probe, controlled by a parameter perhaps, load
> all 16 bytes into the random pool as Linus suggested?

Yeah, though I don't really know what the parameter would be useful for,
but yes, do it in the driver's probe.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-23 14:58         ` Maxime Ripard
@ 2013-05-23 15:05           ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-23 15:05 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Linus Walleij, Arnd Bergmann, Greg KH, Oliver Schinagl,
	linux-kernel, linux-arm-kernel

On 05/23/13 16:58, Maxime Ripard wrote:
> On Thu, May 23, 2013 at 10:10:17AM +0200, Oliver Schinagl wrote:
>> Then, i'm not sure if the driver is the best for this to be loaded?
>> Maxime, what do you think? Personally I would feel more in having
>> this in the mach-sunxi/core.c bit, but then again, this is currently
>> a module and wouldn't be useful to have there. Maxime is far more
>> knowledgeable to answer that.
>
> Hmmm, I don't understand what you mean here. Could you explain what you
> have in mind?
I've thought about it a little, and don't think core.c is a good spot, 
since the module will have to be loaded, or available there. And that's 
really early.

So I guess, during probe, controlled by a parameter perhaps, load all 16 
bytes into the random pool as Linus suggested?
>
> Thanks,
> Maxime
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-23 15:05           ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-23 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/23/13 16:58, Maxime Ripard wrote:
> On Thu, May 23, 2013 at 10:10:17AM +0200, Oliver Schinagl wrote:
>> Then, i'm not sure if the driver is the best for this to be loaded?
>> Maxime, what do you think? Personally I would feel more in having
>> this in the mach-sunxi/core.c bit, but then again, this is currently
>> a module and wouldn't be useful to have there. Maxime is far more
>> knowledgeable to answer that.
>
> Hmmm, I don't understand what you mean here. Could you explain what you
> have in mind?
I've thought about it a little, and don't think core.c is a good spot, 
since the module will have to be loaded, or available there. And that's 
really early.

So I guess, during probe, controlled by a parameter perhaps, load all 16 
bytes into the random pool as Linus suggested?
>
> Thanks,
> Maxime
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-23  8:10       ` Oliver Schinagl
@ 2013-05-23 14:58         ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-23 14:58 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Linus Walleij, Arnd Bergmann, Greg KH, Oliver Schinagl,
	linux-kernel, linux-arm-kernel

On Thu, May 23, 2013 at 10:10:17AM +0200, Oliver Schinagl wrote:
> Then, i'm not sure if the driver is the best for this to be loaded?
> Maxime, what do you think? Personally I would feel more in having
> this in the mach-sunxi/core.c bit, but then again, this is currently
> a module and wouldn't be useful to have there. Maxime is far more
> knowledgeable to answer that.

Hmmm, I don't understand what you mean here. Could you explain what you
have in mind?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-23 14:58         ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-23 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 23, 2013 at 10:10:17AM +0200, Oliver Schinagl wrote:
> Then, i'm not sure if the driver is the best for this to be loaded?
> Maxime, what do you think? Personally I would feel more in having
> this in the mach-sunxi/core.c bit, but then again, this is currently
> a module and wouldn't be useful to have there. Maxime is far more
> knowledgeable to answer that.

Hmmm, I don't understand what you mean here. Could you explain what you
have in mind?

Thanks,
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-23  8:10       ` Oliver Schinagl
@ 2013-05-23  8:20         ` Linus Walleij
  -1 siblings, 0 replies; 142+ messages in thread
From: Linus Walleij @ 2013-05-23  8:20 UTC (permalink / raw)
  To: Oliver Schinagl, Theodore Ts'o
  Cc: Maxime Ripard, Arnd Bergmann, Greg KH, Oliver Schinagl,
	linux-kernel, linux-arm-kernel

On Thu, May 23, 2013 at 10:10 AM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:
> On 05/23/13 09:56, Linus Walleij wrote:
>>
>> On Fri, May 17, 2013 at 3:35 PM, Oliver Schinagl
>> <oliver+list@schinagl.nl> wrote:
>>
>> (...)
>>>
>>> While initially these fuses are used to somewhat determin the chipID,
>>> these
>>> appear to be writeable by the user and thus can be used for other
>>> purpouses.
>>> For example storing a 128 bit root key, a unique serial number, which
>>> could
>>> then even be used as a MAC address.
>>
>> (...)
>> Then follows some code to read out the keys from sysfs I guess..
>>>
>>> +static int __init sid_probe(struct platform_device *pdev)
>>
>>
>> It's really simple to actually make the kernel use this to seed the
>> entropy pool.
>>
>> #include <linux/random.h>
>> add_device_randomness(u8 *, num);
>>
>> If you know after probe that you can read out a number of bytes
>> of device-unique data, I think you should add those bytes to the
>> entropy pool like this.
>
> While that is a great idea, we can't guarantee device uniqueness. We've
> already seen some chips that where 'forgotten' to program and default set to
> all 0. I guess that doesn't have to be a bad thing.

Ted can confirm but AFAIK that is not a problem. This device-unique
numer is just one of the things mixed into the pool, if it's on some
devices just an array of zeroes it does not make things worse, but
in the cases when there is some uniqueness in it make things better.

> It should probably be noted, that the sunxi series have a hardware crypto
> engine, with hardware random seed generator, one for a later project.

That will anyway be augmented with the contents of the entropy
pool rather than returned to random clients right off if I know the
recent changes to random code right.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-23  8:20         ` Linus Walleij
  0 siblings, 0 replies; 142+ messages in thread
From: Linus Walleij @ 2013-05-23  8:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 23, 2013 at 10:10 AM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:
> On 05/23/13 09:56, Linus Walleij wrote:
>>
>> On Fri, May 17, 2013 at 3:35 PM, Oliver Schinagl
>> <oliver+list@schinagl.nl> wrote:
>>
>> (...)
>>>
>>> While initially these fuses are used to somewhat determin the chipID,
>>> these
>>> appear to be writeable by the user and thus can be used for other
>>> purpouses.
>>> For example storing a 128 bit root key, a unique serial number, which
>>> could
>>> then even be used as a MAC address.
>>
>> (...)
>> Then follows some code to read out the keys from sysfs I guess..
>>>
>>> +static int __init sid_probe(struct platform_device *pdev)
>>
>>
>> It's really simple to actually make the kernel use this to seed the
>> entropy pool.
>>
>> #include <linux/random.h>
>> add_device_randomness(u8 *, num);
>>
>> If you know after probe that you can read out a number of bytes
>> of device-unique data, I think you should add those bytes to the
>> entropy pool like this.
>
> While that is a great idea, we can't guarantee device uniqueness. We've
> already seen some chips that where 'forgotten' to program and default set to
> all 0. I guess that doesn't have to be a bad thing.

Ted can confirm but AFAIK that is not a problem. This device-unique
numer is just one of the things mixed into the pool, if it's on some
devices just an array of zeroes it does not make things worse, but
in the cases when there is some uniqueness in it make things better.

> It should probably be noted, that the sunxi series have a hardware crypto
> engine, with hardware random seed generator, one for a later project.

That will anyway be augmented with the contents of the entropy
pool rather than returned to random clients right off if I know the
recent changes to random code right.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-23  7:56     ` Linus Walleij
@ 2013-05-23  8:10       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-23  8:10 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Maxime Ripard, Arnd Bergmann, Greg KH, Oliver Schinagl,
	linux-kernel, linux-arm-kernel

On 05/23/13 09:56, Linus Walleij wrote:
> On Fri, May 17, 2013 at 3:35 PM, Oliver Schinagl
> <oliver+list@schinagl.nl> wrote:
>
> (...)
>> While initially these fuses are used to somewhat determin the chipID, these
>> appear to be writeable by the user and thus can be used for other purpouses.
>> For example storing a 128 bit root key, a unique serial number, which could
>> then even be used as a MAC address.
> (...)
> Then follows some code to read out the keys from sysfs I guess..
>> +static int __init sid_probe(struct platform_device *pdev)
>
> It's really simple to actually make the kernel use this to seed the
> entropy pool.
>
> #include <linux/random.h>
> add_device_randomness(u8 *, num);
>
> If you know after probe that you can read out a number of bytes
> of device-unique data, I think you should add those bytes to the
> entropy pool like this.
While that is a great idea, we can't guarantee device uniqueness. We've 
already seen some chips that where 'forgotten' to program and default 
set to all 0. I guess that doesn't have to be a bad thing.

Then, i'm not sure if the driver is the best for this to be loaded? 
Maxime, what do you think? Personally I would feel more in having this 
in the mach-sunxi/core.c bit, but then again, this is currently a module 
and wouldn't be useful to have there. Maxime is far more knowledgeable 
to answer that.

It should probably be noted, that the sunxi series have a hardware 
crypto engine, with hardware random seed generator, one for a later project.
>
> Yours,
> Linus Walleij
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-23  8:10       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-23  8:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/23/13 09:56, Linus Walleij wrote:
> On Fri, May 17, 2013 at 3:35 PM, Oliver Schinagl
> <oliver+list@schinagl.nl> wrote:
>
> (...)
>> While initially these fuses are used to somewhat determin the chipID, these
>> appear to be writeable by the user and thus can be used for other purpouses.
>> For example storing a 128 bit root key, a unique serial number, which could
>> then even be used as a MAC address.
> (...)
> Then follows some code to read out the keys from sysfs I guess..
>> +static int __init sid_probe(struct platform_device *pdev)
>
> It's really simple to actually make the kernel use this to seed the
> entropy pool.
>
> #include <linux/random.h>
> add_device_randomness(u8 *, num);
>
> If you know after probe that you can read out a number of bytes
> of device-unique data, I think you should add those bytes to the
> entropy pool like this.
While that is a great idea, we can't guarantee device uniqueness. We've 
already seen some chips that where 'forgotten' to program and default 
set to all 0. I guess that doesn't have to be a bad thing.

Then, i'm not sure if the driver is the best for this to be loaded? 
Maxime, what do you think? Personally I would feel more in having this 
in the mach-sunxi/core.c bit, but then again, this is currently a module 
and wouldn't be useful to have there. Maxime is far more knowledgeable 
to answer that.

It should probably be noted, that the sunxi series have a hardware 
crypto engine, with hardware random seed generator, one for a later project.
>
> Yours,
> Linus Walleij
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-17 13:35   ` Oliver Schinagl
@ 2013-05-23  7:56     ` Linus Walleij
  -1 siblings, 0 replies; 142+ messages in thread
From: Linus Walleij @ 2013-05-23  7:56 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: Maxime Ripard, Arnd Bergmann, Greg KH, Oliver Schinagl,
	linux-kernel, linux-arm-kernel

On Fri, May 17, 2013 at 3:35 PM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:

(...)
> While initially these fuses are used to somewhat determin the chipID, these
> appear to be writeable by the user and thus can be used for other purpouses.
> For example storing a 128 bit root key, a unique serial number, which could
> then even be used as a MAC address.
(...)
Then follows some code to read out the keys from sysfs I guess..
> +static int __init sid_probe(struct platform_device *pdev)

It's really simple to actually make the kernel use this to seed the
entropy pool.

#include <linux/random.h>
add_device_randomness(u8 *, num);

If you know after probe that you can read out a number of bytes
of device-unique data, I think you should add those bytes to the
entropy pool like this.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-23  7:56     ` Linus Walleij
  0 siblings, 0 replies; 142+ messages in thread
From: Linus Walleij @ 2013-05-23  7:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, May 17, 2013 at 3:35 PM, Oliver Schinagl
<oliver+list@schinagl.nl> wrote:

(...)
> While initially these fuses are used to somewhat determin the chipID, these
> appear to be writeable by the user and thus can be used for other purpouses.
> For example storing a 128 bit root key, a unique serial number, which could
> then even be used as a MAC address.
(...)
Then follows some code to read out the keys from sysfs I guess..
> +static int __init sid_probe(struct platform_device *pdev)

It's really simple to actually make the kernel use this to seed the
entropy pool.

#include <linux/random.h>
add_device_randomness(u8 *, num);

If you know after probe that you can read out a number of bytes
of device-unique data, I think you should add those bytes to the
entropy pool like this.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-18 17:19       ` Oliver Schinagl
@ 2013-05-19 15:22         ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-19 15:22 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: arnd, gregkh, linux-kernel, linux-arm-kernel, Oliver Schinagl

On Sat, May 18, 2013 at 07:19:43PM +0200, Oliver Schinagl wrote:
> On 05/17/13 23:18, Maxime Ripard wrote:
> >Hi Oliver,
> >
> >Le 17/05/2013 15:35, Oliver Schinagl a écrit :
> >>From: Oliver Schinagl <oliver@schinagl.nl>
> >>
> >>Allwinner has electric fuses (efuse) on their line of chips. This driver
> >>reads those fuses and exports them as a sysfs node. Also a symbol is exported
> >>for in-kernel useage.
> >>
> >>While initially these fuses are used to somewhat determin the chipID, these
> >>appear to be writeable by the user and thus can be used for other purpouses.
> >>For example storing a 128 bit root key, a unique serial number, which could
> >>then even be used as a MAC address.
> >>
> >>Because writing to e-fuses can be potentially dangerous, and are certainly
> >>not as often writable (if at all) as flash memory, these shouldn't be easily
> >>changeable, hence only a read-only mode. An offline tool to write the fuses
> >>is in the works.
> >>
> >>Currently supported are the following known chips:
> >>Allwinner sun4i (A10)
> >>Allwinner sun5i (A10s A13)
> >>Allwinner sun6i (A31, A31s)
> >>Allwinner sun7i (A20)
> >
> >Since I don't think those patches have been tested on sun6i/sun7i, and
> >that there's not even kernel support for those, maybe it's not worth
> >mentionning them?
> A31 is out in the wild, but haven't seen that functionality in, I
> have seen the register named and defined, just not used, so that
> could go until confirmed.
> 
> A20 has the same feature as we can see in the dumped sources. [0]

Yet, we can't even boot a mainline kernel, and this list will probably
need some update when new SoCs come out.

Anyway, it's not a big deal.

> 
> 
> >
> >>
> >>Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> >>---
> >>  drivers/misc/eeprom/Kconfig     |  19 ++++
> >>  drivers/misc/eeprom/Makefile    |   1 +
> >>  drivers/misc/eeprom/sunxi_sid.c | 218 ++++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 238 insertions(+)
> >>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> >>
> >>diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> >>index 04f2e1f..c9ddda5 100644
> >>--- a/drivers/misc/eeprom/Kconfig
> >>+++ b/drivers/misc/eeprom/Kconfig
> >>@@ -96,4 +96,23 @@ 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. Currently supported are:
> >>+		sun4i (A10)
> >>+		sun5i (A10s, A12, A13)
> >>+		sun6i (A31)
> >>+		sun7i (A20)
> >
> >Same things here.
> >
> >>+
> >>+	  Due to the potential risks involved with changing e-fuses,
> >>+	  this driver is read-only
> >>+
> >>+	  For more information visit http://linux-sunxi.org/SID
> >>+
> >>+	  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 fc1e81d..9507aec 100644
> >>--- a/drivers/misc/eeprom/Makefile
> >>+++ b/drivers/misc/eeprom/Makefile
> >>@@ -4,4 +4,5 @@ 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
> >>new file mode 100644
> >>index 0000000..953f137
> >>--- /dev/null
> >>+++ b/drivers/misc/eeprom/sunxi_sid.c
> >>@@ -0,0 +1,218 @@
> >>+/*
> >>+ * Copyright (c) 2013 Oliver Schinagl
> >>+ * http://www.linux-sunxi.org
> >>+ *
> >>+ * Oliver Schinagl <oliver@schinagl.nl>
> >>+ *
> >>+ * 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, a 128 bit eeprom, in chunks
> >>+ * of 8 bytes.
> >
> >16 bytes or 8 bits? because 8 bytes != 128 bits.
> fixed, it was late when I wrote that :( It is indeed 8 bits, e.g.
> byte sized chunks.
> 
> >
> >>+ */
> >>+
> >>+#include <linux/compiler.h>
> >>+#include <linux/device.h>
> >>+#include <linux/errno.h>
> >>+#include <linux/export.h>
> >>+#include <linux/fs.h>
> >>+#include <linux/init.h>
> >>+#include <linux/io.h>
> >>+#include <linux/kobject.h>
> >>+#include <linux/module.h>
> >>+#include <linux/of_address.h>
> >>+#include <linux/platform_device.h>
> >>+#include <linux/stat.h>
> >>+#include <linux/sysfs.h>
> >>+#include <linux/types.h>
> >>+
> >>+
> >>+#define DRV_NAME "sunxi-sid"
> >>+#define DRV_VERSION "1.0"
> >>+
> >>+/* Register offsets */
> >>+#define SUNXI_SID_KEY0 0x00
> >>+#define SUNXI_SID_KEY1 0x04
> >>+#define SUNXI_SID_KEY2 0x08
> >>+#define SUNXI_SID_KEY3 0x0c
> >>+
> >>+/* There are 4 32-bit keys */
> >>+#define SUNXI_SID_KEYS 4
> >>+/* and 4 32-bit keys per 32-bit key */
> >
> >The comment is wrong here.
> Same as above, corrected.
> 
> >
> >>+#define SUNXI_SID_SIZE (SUNXI_SID_KEYS * 4)
> >>+
> >>+#if (SUNXI_SID_SIZE > PAGE_SIZE)
> >>+#error "SUNXI_SID_SIZE is larger then the target's PAGE_SIZE, ENOMEM."
> >>+#endif
> >
> >Hmmmm, I don't follow you here, what's the relation between your driver
> >and PAGE_SIZE?
> Nothing, I thought there was, but isn't. removed.
> >
> >>+
> >>+static u8 keys_lut[] = {
> >>+	SUNXI_SID_KEY0,
> >>+	SUNXI_SID_KEY1,
> >>+	SUNXI_SID_KEY2,
> >>+	SUNXI_SID_KEY3,
> >>+};
> >>+
> >>+struct sid_priv {
> >>+	void __iomem *sid_base;
> >>+};
> >>+
> >>+struct sid_priv *p;
> >
> >What's the point of having a structure here? And why putting a global
> >value, !static, with a generic name, while you could have an
> >instance-specific one?
> Forgot the static keyword, and the struct kept on shrinking until
> only the base address was left. I guess memory wise it shouldn't
> make a difference, but the compiler also doesn't agree, so gone it
> is :)
> >
> >struct file has a private_data field, use it.
> But since we don't 'open' it, we can't use that, as we talked on IRC.

Then, use the passed kobject to retrieve its parent device structure,
and from there, get the drvdata to get back on your feet.

Actually, you already seem to do that and I overlooked that part in my
previous review.

So just use the priv structure you have defined in your read function
and that is useless right now.

> >
> >>+
> >>+
> >>+/* We read the entire key, using a look up table. Returned is only the
> >>+ * requested byte. This is of course slower then it could be and uses 4 times
> >>+ * more reads as needed but keeps code a little simpler.
> >>+ */
> >>+u8 sunxi_sid_read_byte(const int key)
> >>+{
> >>+	u32 sid_key;
> >>+	u8 ret;
> >>+
> >>+	ret = 0;
> >>+	if (likely((key <= SUNXI_SID_SIZE))) {
> >>+		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
> >>+		switch (key % 4) {
> >>+		case 0:
> >>+			ret = (sid_key >> 24) & 0xff;
> >>+			break;
> >>+		case 1:
> >>+			ret = (sid_key >> 16) & 0xff;
> >>+			break;
> >>+		case 2:
> >>+			ret = (sid_key >> 8) & 0xff;
> >>+			break;
> >>+		case 3:
> >>+			ret = sid_key & 0xff;
> >>+			break;
> >>+		}
> >>+	}
> >
> >Come on, you can do better. This lookup table is useless.
> I didn't want to depend on the fixed layout of memory, but consider
> it removed.
> >
> >Also, why the first key is the one with the MSBs?
> >I'd expect that the key 0 is the one holding the LSBs.
> Strangely enough, they have swapped the MSB and LSB bytes. I double
> checked it with u-boot and yep, swapped. Though in the end, if we
> write stuff there and we read stuff from there, order doesn't
> matter? So what do we prefer. Have it so that it makes sense and
> ignore how u-boot reads it, or correct it and be consistent?

Which u-boot are you talking about?
I'd really prefer to have a sane and logical behaviour rather than a
broken one, even though it used to be like that in the
Allwinner-provided kernel.

> >
> >>+
> >>+	return ret;
> >>+}
> >>+
> >>+static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> >>+			struct bin_attribute *attr, char *buf,
> >>+			loff_t pos, size_t size)
> >>+{
> >>+	ssize_t ret;
> >>+	struct device *dev;
> >>+	struct sid_priv *priv;
> >>+	int i;
> >>+
> >>+	ret = -EPERM;
> >>+	dev = kobj_to_dev(kobj);
> >>+	priv = dev_get_drvdata(dev);
> >>+
> >>+	if ((likely(size > 0)) && ((size + pos) <= SUNXI_SID_SIZE)) {
> >>+		for (i = 0; i < size; i++) {
> >>+			buf[i] = sunxi_sid_read_byte(pos + i);
> >>+		}
> >>+		if (i < PAGE_SIZE) {
> >>+			buf[i] = '\0';
> >>+			ret = (ssize_t)size;
> >>+		} else {
> >>+			ret = -ENOMEM;
> >>+		}
> >
> >Hmmmm, what? Why returning \0 here? It's not a string, it's binary data.
> >What's the relation with PAGE_SIZE again?
> I thought that buf is at most PAGE_SIZE large [1] "sysfs allocates a
> buffer of size (PAGE_SIZE) and passes it to the method."

And you already check the size passed.

> >
> >Just return the number of bytes read, that's it.
> Yes, had forgotten that this was of course the binary read function
> and not the text version. So yeah, in the binary case, gone.
> >
> >>+	} else {
> >>+		buf[0] = '\0';
> >>+		ret = 0;
> >>+	}
> >>+
> >>+	return ret;
> >>+}
> >>+
> >>+static struct of_device_id sid_of_match[] = {
> >>+	{
> >>+		.compatible = "allwinner,sun4i-sid",
> >>+	},
> >>+	{/* sentinel */}
> >>+};
> >>+MODULE_DEVICE_TABLE(of, sid_of_match);
> >>+
> >>+static struct bin_attribute sid_bin_attr = {
> >>+	.attr = {
> >>+		.name = "key",
> >>+		.mode = S_IRUGO,
> >>+	},
> >>+	.size = SUNXI_SID_SIZE,
> >>+	.read = sid_read,
> >>+};
> >>+
> >>+static int sid_remove(struct platform_device *pdev)
> >>+{
> >>+	struct device *dev = &pdev->dev;
> >>+	struct sid_priv *priv;
> >>+
> >>+	priv = dev_get_drvdata(dev);
> >>+	device_remove_bin_file(dev, &sid_bin_attr);
> >>+	iounmap(priv->sid_base);
> >>+	devm_kfree(dev, priv);
> >>+	return 0;
> >>+}
> >>+
> >>+static int __init sid_probe(struct platform_device *pdev)
> >>+{
> >>+	int ret;
> >>+	struct device *dev = &pdev->dev;
> >>+	struct sid_priv *priv;
> >>+
> >>+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> >>+	p = priv;
> >>+
> >>+	dev_set_drvdata(dev, priv);
> >>+
> >>+	if (!priv) {
> >>+		dev_err(dev, "Unable to allocate device private data\n");
> >>+		ret = -ENOMEM;
> >>+		goto exit;
> >>+	}
> >
> >Isn't it a bit weird to check for the memory allocation after using the
> Yes, more 'oops'. Re-arranged.
> >variable. Also, you don't really need the dev_err, since if the kernel
> >fails to allocate some memory, it will tell you anyway.
> I had it there mostly for consistency, the other 2 did the same
> check. Initially I had 5 functions here, but you corrected me on
> that :)
> 
> >
> >>+	priv->sid_base = of_iomap(dev->of_node, 0);
> >>+	if (!priv->sid_base) {
> >>+		dev_err(dev, "Unable to map memory region\n");
> >>+		ret = -ENOMEM;
> >>+		goto exit_free;
> >>+	}
> >>+
> >>+	ret = device_create_bin_file(dev, &sid_bin_attr);
> >>+	if (ret) {
> >>+		dev_err(dev, "Unable to create sysfs bin entry\n");
> >>+		goto exit_unmap;
> >>+	}
> >
> >Hmmm, maybe it's not worth all these gotos just for an iounmap, I'd
> >probably return right away, but that's your call.
> I saw a lot of drivers do the goto: dance in init/probe/exit/remove
> functions, I don't think the overhead here would be so bad?

It's not really that it's bad, but using return directly would take less
code overall, but that's not a big deal, if you prefer to keep it that
way, I'm fine with it.

> >
> >>+	dev_info(dev, "Sunxi security ID driver loaded successfully.\n");
> >>+
> >>+	return 0;
> >>+
> >>+
> >>+exit_unmap:
> >>+	iounmap(priv->sid_base);
> >>+exit_free:
> >>+	devm_kfree(dev, priv);
> >>+exit:
> >>+	return ret;
> >>+}
> >>+
> >>+static struct platform_driver sid_driver = {
> >>+	.probe = sid_probe,
> >>+	.remove = sid_remove,
> >>+	.driver = {
> >>+		.name = DRV_NAME,
> >>+		.owner = THIS_MODULE,
> >>+		.of_match_table = sid_of_match,
> >>+	},
> >>+};
> >>+module_platform_driver(sid_driver);
> >>+
> >>+
> >>+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> >>+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> >>+MODULE_VERSION(DRV_VERSION);
> >>+MODULE_LICENSE("GPL");
> >>
> >
> >Thanks for this driver!
> >Maxime
> >
> You are welcome! :D While awaiting more feedback, i've pushed the
> current version to my github [2].
> 
> Oliver
> 
> [0] https://github.com/amery/linux-allwinner/blob/lichee-3.3/sun7i-dev/arch/arm/mach-sun7i/security_id.c#L91
> [1] https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
> [2] https://github.com/oliv3r/linux/blob/wip/sunxi-security-id/drivers/misc/eeprom/sunxi_sid.c

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-19 15:22         ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-19 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 18, 2013 at 07:19:43PM +0200, Oliver Schinagl wrote:
> On 05/17/13 23:18, Maxime Ripard wrote:
> >Hi Oliver,
> >
> >Le 17/05/2013 15:35, Oliver Schinagl a ?crit :
> >>From: Oliver Schinagl <oliver@schinagl.nl>
> >>
> >>Allwinner has electric fuses (efuse) on their line of chips. This driver
> >>reads those fuses and exports them as a sysfs node. Also a symbol is exported
> >>for in-kernel useage.
> >>
> >>While initially these fuses are used to somewhat determin the chipID, these
> >>appear to be writeable by the user and thus can be used for other purpouses.
> >>For example storing a 128 bit root key, a unique serial number, which could
> >>then even be used as a MAC address.
> >>
> >>Because writing to e-fuses can be potentially dangerous, and are certainly
> >>not as often writable (if at all) as flash memory, these shouldn't be easily
> >>changeable, hence only a read-only mode. An offline tool to write the fuses
> >>is in the works.
> >>
> >>Currently supported are the following known chips:
> >>Allwinner sun4i (A10)
> >>Allwinner sun5i (A10s A13)
> >>Allwinner sun6i (A31, A31s)
> >>Allwinner sun7i (A20)
> >
> >Since I don't think those patches have been tested on sun6i/sun7i, and
> >that there's not even kernel support for those, maybe it's not worth
> >mentionning them?
> A31 is out in the wild, but haven't seen that functionality in, I
> have seen the register named and defined, just not used, so that
> could go until confirmed.
> 
> A20 has the same feature as we can see in the dumped sources. [0]

Yet, we can't even boot a mainline kernel, and this list will probably
need some update when new SoCs come out.

Anyway, it's not a big deal.

> 
> 
> >
> >>
> >>Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> >>---
> >>  drivers/misc/eeprom/Kconfig     |  19 ++++
> >>  drivers/misc/eeprom/Makefile    |   1 +
> >>  drivers/misc/eeprom/sunxi_sid.c | 218 ++++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 238 insertions(+)
> >>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> >>
> >>diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> >>index 04f2e1f..c9ddda5 100644
> >>--- a/drivers/misc/eeprom/Kconfig
> >>+++ b/drivers/misc/eeprom/Kconfig
> >>@@ -96,4 +96,23 @@ 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. Currently supported are:
> >>+		sun4i (A10)
> >>+		sun5i (A10s, A12, A13)
> >>+		sun6i (A31)
> >>+		sun7i (A20)
> >
> >Same things here.
> >
> >>+
> >>+	  Due to the potential risks involved with changing e-fuses,
> >>+	  this driver is read-only
> >>+
> >>+	  For more information visit http://linux-sunxi.org/SID
> >>+
> >>+	  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 fc1e81d..9507aec 100644
> >>--- a/drivers/misc/eeprom/Makefile
> >>+++ b/drivers/misc/eeprom/Makefile
> >>@@ -4,4 +4,5 @@ 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
> >>new file mode 100644
> >>index 0000000..953f137
> >>--- /dev/null
> >>+++ b/drivers/misc/eeprom/sunxi_sid.c
> >>@@ -0,0 +1,218 @@
> >>+/*
> >>+ * Copyright (c) 2013 Oliver Schinagl
> >>+ * http://www.linux-sunxi.org
> >>+ *
> >>+ * Oliver Schinagl <oliver@schinagl.nl>
> >>+ *
> >>+ * 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, a 128 bit eeprom, in chunks
> >>+ * of 8 bytes.
> >
> >16 bytes or 8 bits? because 8 bytes != 128 bits.
> fixed, it was late when I wrote that :( It is indeed 8 bits, e.g.
> byte sized chunks.
> 
> >
> >>+ */
> >>+
> >>+#include <linux/compiler.h>
> >>+#include <linux/device.h>
> >>+#include <linux/errno.h>
> >>+#include <linux/export.h>
> >>+#include <linux/fs.h>
> >>+#include <linux/init.h>
> >>+#include <linux/io.h>
> >>+#include <linux/kobject.h>
> >>+#include <linux/module.h>
> >>+#include <linux/of_address.h>
> >>+#include <linux/platform_device.h>
> >>+#include <linux/stat.h>
> >>+#include <linux/sysfs.h>
> >>+#include <linux/types.h>
> >>+
> >>+
> >>+#define DRV_NAME "sunxi-sid"
> >>+#define DRV_VERSION "1.0"
> >>+
> >>+/* Register offsets */
> >>+#define SUNXI_SID_KEY0 0x00
> >>+#define SUNXI_SID_KEY1 0x04
> >>+#define SUNXI_SID_KEY2 0x08
> >>+#define SUNXI_SID_KEY3 0x0c
> >>+
> >>+/* There are 4 32-bit keys */
> >>+#define SUNXI_SID_KEYS 4
> >>+/* and 4 32-bit keys per 32-bit key */
> >
> >The comment is wrong here.
> Same as above, corrected.
> 
> >
> >>+#define SUNXI_SID_SIZE (SUNXI_SID_KEYS * 4)
> >>+
> >>+#if (SUNXI_SID_SIZE > PAGE_SIZE)
> >>+#error "SUNXI_SID_SIZE is larger then the target's PAGE_SIZE, ENOMEM."
> >>+#endif
> >
> >Hmmmm, I don't follow you here, what's the relation between your driver
> >and PAGE_SIZE?
> Nothing, I thought there was, but isn't. removed.
> >
> >>+
> >>+static u8 keys_lut[] = {
> >>+	SUNXI_SID_KEY0,
> >>+	SUNXI_SID_KEY1,
> >>+	SUNXI_SID_KEY2,
> >>+	SUNXI_SID_KEY3,
> >>+};
> >>+
> >>+struct sid_priv {
> >>+	void __iomem *sid_base;
> >>+};
> >>+
> >>+struct sid_priv *p;
> >
> >What's the point of having a structure here? And why putting a global
> >value, !static, with a generic name, while you could have an
> >instance-specific one?
> Forgot the static keyword, and the struct kept on shrinking until
> only the base address was left. I guess memory wise it shouldn't
> make a difference, but the compiler also doesn't agree, so gone it
> is :)
> >
> >struct file has a private_data field, use it.
> But since we don't 'open' it, we can't use that, as we talked on IRC.

Then, use the passed kobject to retrieve its parent device structure,
and from there, get the drvdata to get back on your feet.

Actually, you already seem to do that and I overlooked that part in my
previous review.

So just use the priv structure you have defined in your read function
and that is useless right now.

> >
> >>+
> >>+
> >>+/* We read the entire key, using a look up table. Returned is only the
> >>+ * requested byte. This is of course slower then it could be and uses 4 times
> >>+ * more reads as needed but keeps code a little simpler.
> >>+ */
> >>+u8 sunxi_sid_read_byte(const int key)
> >>+{
> >>+	u32 sid_key;
> >>+	u8 ret;
> >>+
> >>+	ret = 0;
> >>+	if (likely((key <= SUNXI_SID_SIZE))) {
> >>+		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
> >>+		switch (key % 4) {
> >>+		case 0:
> >>+			ret = (sid_key >> 24) & 0xff;
> >>+			break;
> >>+		case 1:
> >>+			ret = (sid_key >> 16) & 0xff;
> >>+			break;
> >>+		case 2:
> >>+			ret = (sid_key >> 8) & 0xff;
> >>+			break;
> >>+		case 3:
> >>+			ret = sid_key & 0xff;
> >>+			break;
> >>+		}
> >>+	}
> >
> >Come on, you can do better. This lookup table is useless.
> I didn't want to depend on the fixed layout of memory, but consider
> it removed.
> >
> >Also, why the first key is the one with the MSBs?
> >I'd expect that the key 0 is the one holding the LSBs.
> Strangely enough, they have swapped the MSB and LSB bytes. I double
> checked it with u-boot and yep, swapped. Though in the end, if we
> write stuff there and we read stuff from there, order doesn't
> matter? So what do we prefer. Have it so that it makes sense and
> ignore how u-boot reads it, or correct it and be consistent?

Which u-boot are you talking about?
I'd really prefer to have a sane and logical behaviour rather than a
broken one, even though it used to be like that in the
Allwinner-provided kernel.

> >
> >>+
> >>+	return ret;
> >>+}
> >>+
> >>+static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> >>+			struct bin_attribute *attr, char *buf,
> >>+			loff_t pos, size_t size)
> >>+{
> >>+	ssize_t ret;
> >>+	struct device *dev;
> >>+	struct sid_priv *priv;
> >>+	int i;
> >>+
> >>+	ret = -EPERM;
> >>+	dev = kobj_to_dev(kobj);
> >>+	priv = dev_get_drvdata(dev);
> >>+
> >>+	if ((likely(size > 0)) && ((size + pos) <= SUNXI_SID_SIZE)) {
> >>+		for (i = 0; i < size; i++) {
> >>+			buf[i] = sunxi_sid_read_byte(pos + i);
> >>+		}
> >>+		if (i < PAGE_SIZE) {
> >>+			buf[i] = '\0';
> >>+			ret = (ssize_t)size;
> >>+		} else {
> >>+			ret = -ENOMEM;
> >>+		}
> >
> >Hmmmm, what? Why returning \0 here? It's not a string, it's binary data.
> >What's the relation with PAGE_SIZE again?
> I thought that buf is at most PAGE_SIZE large [1] "sysfs allocates a
> buffer of size (PAGE_SIZE) and passes it to the method."

And you already check the size passed.

> >
> >Just return the number of bytes read, that's it.
> Yes, had forgotten that this was of course the binary read function
> and not the text version. So yeah, in the binary case, gone.
> >
> >>+	} else {
> >>+		buf[0] = '\0';
> >>+		ret = 0;
> >>+	}
> >>+
> >>+	return ret;
> >>+}
> >>+
> >>+static struct of_device_id sid_of_match[] = {
> >>+	{
> >>+		.compatible = "allwinner,sun4i-sid",
> >>+	},
> >>+	{/* sentinel */}
> >>+};
> >>+MODULE_DEVICE_TABLE(of, sid_of_match);
> >>+
> >>+static struct bin_attribute sid_bin_attr = {
> >>+	.attr = {
> >>+		.name = "key",
> >>+		.mode = S_IRUGO,
> >>+	},
> >>+	.size = SUNXI_SID_SIZE,
> >>+	.read = sid_read,
> >>+};
> >>+
> >>+static int sid_remove(struct platform_device *pdev)
> >>+{
> >>+	struct device *dev = &pdev->dev;
> >>+	struct sid_priv *priv;
> >>+
> >>+	priv = dev_get_drvdata(dev);
> >>+	device_remove_bin_file(dev, &sid_bin_attr);
> >>+	iounmap(priv->sid_base);
> >>+	devm_kfree(dev, priv);
> >>+	return 0;
> >>+}
> >>+
> >>+static int __init sid_probe(struct platform_device *pdev)
> >>+{
> >>+	int ret;
> >>+	struct device *dev = &pdev->dev;
> >>+	struct sid_priv *priv;
> >>+
> >>+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> >>+	p = priv;
> >>+
> >>+	dev_set_drvdata(dev, priv);
> >>+
> >>+	if (!priv) {
> >>+		dev_err(dev, "Unable to allocate device private data\n");
> >>+		ret = -ENOMEM;
> >>+		goto exit;
> >>+	}
> >
> >Isn't it a bit weird to check for the memory allocation after using the
> Yes, more 'oops'. Re-arranged.
> >variable. Also, you don't really need the dev_err, since if the kernel
> >fails to allocate some memory, it will tell you anyway.
> I had it there mostly for consistency, the other 2 did the same
> check. Initially I had 5 functions here, but you corrected me on
> that :)
> 
> >
> >>+	priv->sid_base = of_iomap(dev->of_node, 0);
> >>+	if (!priv->sid_base) {
> >>+		dev_err(dev, "Unable to map memory region\n");
> >>+		ret = -ENOMEM;
> >>+		goto exit_free;
> >>+	}
> >>+
> >>+	ret = device_create_bin_file(dev, &sid_bin_attr);
> >>+	if (ret) {
> >>+		dev_err(dev, "Unable to create sysfs bin entry\n");
> >>+		goto exit_unmap;
> >>+	}
> >
> >Hmmm, maybe it's not worth all these gotos just for an iounmap, I'd
> >probably return right away, but that's your call.
> I saw a lot of drivers do the goto: dance in init/probe/exit/remove
> functions, I don't think the overhead here would be so bad?

It's not really that it's bad, but using return directly would take less
code overall, but that's not a big deal, if you prefer to keep it that
way, I'm fine with it.

> >
> >>+	dev_info(dev, "Sunxi security ID driver loaded successfully.\n");
> >>+
> >>+	return 0;
> >>+
> >>+
> >>+exit_unmap:
> >>+	iounmap(priv->sid_base);
> >>+exit_free:
> >>+	devm_kfree(dev, priv);
> >>+exit:
> >>+	return ret;
> >>+}
> >>+
> >>+static struct platform_driver sid_driver = {
> >>+	.probe = sid_probe,
> >>+	.remove = sid_remove,
> >>+	.driver = {
> >>+		.name = DRV_NAME,
> >>+		.owner = THIS_MODULE,
> >>+		.of_match_table = sid_of_match,
> >>+	},
> >>+};
> >>+module_platform_driver(sid_driver);
> >>+
> >>+
> >>+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> >>+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> >>+MODULE_VERSION(DRV_VERSION);
> >>+MODULE_LICENSE("GPL");
> >>
> >
> >Thanks for this driver!
> >Maxime
> >
> You are welcome! :D While awaiting more feedback, i've pushed the
> current version to my github [2].
> 
> Oliver
> 
> [0] https://github.com/amery/linux-allwinner/blob/lichee-3.3/sun7i-dev/arch/arm/mach-sun7i/security_id.c#L91
> [1] https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
> [2] https://github.com/oliv3r/linux/blob/wip/sunxi-security-id/drivers/misc/eeprom/sunxi_sid.c

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-17 21:18     ` Maxime Ripard
@ 2013-05-18 17:19       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-18 17:19 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: arnd, gregkh, linux-kernel, linux-arm-kernel, Oliver Schinagl

On 05/17/13 23:18, Maxime Ripard wrote:
> Hi Oliver,
>
> Le 17/05/2013 15:35, Oliver Schinagl a écrit :
>> From: Oliver Schinagl <oliver@schinagl.nl>
>>
>> Allwinner has electric fuses (efuse) on their line of chips. This driver
>> reads those fuses and exports them as a sysfs node. Also a symbol is exported
>> for in-kernel useage.
>>
>> While initially these fuses are used to somewhat determin the chipID, these
>> appear to be writeable by the user and thus can be used for other purpouses.
>> For example storing a 128 bit root key, a unique serial number, which could
>> then even be used as a MAC address.
>>
>> Because writing to e-fuses can be potentially dangerous, and are certainly
>> not as often writable (if at all) as flash memory, these shouldn't be easily
>> changeable, hence only a read-only mode. An offline tool to write the fuses
>> is in the works.
>>
>> Currently supported are the following known chips:
>> Allwinner sun4i (A10)
>> Allwinner sun5i (A10s A13)
>> Allwinner sun6i (A31, A31s)
>> Allwinner sun7i (A20)
>
> Since I don't think those patches have been tested on sun6i/sun7i, and
> that there's not even kernel support for those, maybe it's not worth
> mentionning them?
A31 is out in the wild, but haven't seen that functionality in, I have 
seen the register named and defined, just not used, so that could go 
until confirmed.

A20 has the same feature as we can see in the dumped sources. [0]


>
>>
>> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
>> ---
>>   drivers/misc/eeprom/Kconfig     |  19 ++++
>>   drivers/misc/eeprom/Makefile    |   1 +
>>   drivers/misc/eeprom/sunxi_sid.c | 218 ++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 238 insertions(+)
>>   create mode 100644 drivers/misc/eeprom/sunxi_sid.c
>>
>> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
>> index 04f2e1f..c9ddda5 100644
>> --- a/drivers/misc/eeprom/Kconfig
>> +++ b/drivers/misc/eeprom/Kconfig
>> @@ -96,4 +96,23 @@ 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. Currently supported are:
>> +		sun4i (A10)
>> +		sun5i (A10s, A12, A13)
>> +		sun6i (A31)
>> +		sun7i (A20)
>
> Same things here.
>
>> +
>> +	  Due to the potential risks involved with changing e-fuses,
>> +	  this driver is read-only
>> +
>> +	  For more information visit http://linux-sunxi.org/SID
>> +
>> +	  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 fc1e81d..9507aec 100644
>> --- a/drivers/misc/eeprom/Makefile
>> +++ b/drivers/misc/eeprom/Makefile
>> @@ -4,4 +4,5 @@ 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
>> new file mode 100644
>> index 0000000..953f137
>> --- /dev/null
>> +++ b/drivers/misc/eeprom/sunxi_sid.c
>> @@ -0,0 +1,218 @@
>> +/*
>> + * Copyright (c) 2013 Oliver Schinagl
>> + * http://www.linux-sunxi.org
>> + *
>> + * Oliver Schinagl <oliver@schinagl.nl>
>> + *
>> + * 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, a 128 bit eeprom, in chunks
>> + * of 8 bytes.
>
> 16 bytes or 8 bits? because 8 bytes != 128 bits.
fixed, it was late when I wrote that :( It is indeed 8 bits, e.g. byte 
sized chunks.

>
>> + */
>> +
>> +#include <linux/compiler.h>
>> +#include <linux/device.h>
>> +#include <linux/errno.h>
>> +#include <linux/export.h>
>> +#include <linux/fs.h>
>> +#include <linux/init.h>
>> +#include <linux/io.h>
>> +#include <linux/kobject.h>
>> +#include <linux/module.h>
>> +#include <linux/of_address.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/stat.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/types.h>
>> +
>> +
>> +#define DRV_NAME "sunxi-sid"
>> +#define DRV_VERSION "1.0"
>> +
>> +/* Register offsets */
>> +#define SUNXI_SID_KEY0 0x00
>> +#define SUNXI_SID_KEY1 0x04
>> +#define SUNXI_SID_KEY2 0x08
>> +#define SUNXI_SID_KEY3 0x0c
>> +
>> +/* There are 4 32-bit keys */
>> +#define SUNXI_SID_KEYS 4
>> +/* and 4 32-bit keys per 32-bit key */
>
> The comment is wrong here.
Same as above, corrected.

>
>> +#define SUNXI_SID_SIZE (SUNXI_SID_KEYS * 4)
>> +
>> +#if (SUNXI_SID_SIZE > PAGE_SIZE)
>> +#error "SUNXI_SID_SIZE is larger then the target's PAGE_SIZE, ENOMEM."
>> +#endif
>
> Hmmmm, I don't follow you here, what's the relation between your driver
> and PAGE_SIZE?
Nothing, I thought there was, but isn't. removed.
>
>> +
>> +static u8 keys_lut[] = {
>> +	SUNXI_SID_KEY0,
>> +	SUNXI_SID_KEY1,
>> +	SUNXI_SID_KEY2,
>> +	SUNXI_SID_KEY3,
>> +};
>> +
>> +struct sid_priv {
>> +	void __iomem *sid_base;
>> +};
>> +
>> +struct sid_priv *p;
>
> What's the point of having a structure here? And why putting a global
> value, !static, with a generic name, while you could have an
> instance-specific one?
Forgot the static keyword, and the struct kept on shrinking until only 
the base address was left. I guess memory wise it shouldn't make a 
difference, but the compiler also doesn't agree, so gone it is :)
>
> struct file has a private_data field, use it.
But since we don't 'open' it, we can't use that, as we talked on IRC.

>
>> +
>> +
>> +/* We read the entire key, using a look up table. Returned is only the
>> + * requested byte. This is of course slower then it could be and uses 4 times
>> + * more reads as needed but keeps code a little simpler.
>> + */
>> +u8 sunxi_sid_read_byte(const int key)
>> +{
>> +	u32 sid_key;
>> +	u8 ret;
>> +
>> +	ret = 0;
>> +	if (likely((key <= SUNXI_SID_SIZE))) {
>> +		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
>> +		switch (key % 4) {
>> +		case 0:
>> +			ret = (sid_key >> 24) & 0xff;
>> +			break;
>> +		case 1:
>> +			ret = (sid_key >> 16) & 0xff;
>> +			break;
>> +		case 2:
>> +			ret = (sid_key >> 8) & 0xff;
>> +			break;
>> +		case 3:
>> +			ret = sid_key & 0xff;
>> +			break;
>> +		}
>> +	}
>
> Come on, you can do better. This lookup table is useless.
I didn't want to depend on the fixed layout of memory, but consider it 
removed.
>
> Also, why the first key is the one with the MSBs?
> I'd expect that the key 0 is the one holding the LSBs.
Strangely enough, they have swapped the MSB and LSB bytes. I double 
checked it with u-boot and yep, swapped. Though in the end, if we write 
stuff there and we read stuff from there, order doesn't matter? So what 
do we prefer. Have it so that it makes sense and ignore how u-boot reads 
it, or correct it and be consistent?

>
>> +
>> +	return ret;
>> +}
>> +
>> +static ssize_t sid_read(struct file *fd, struct kobject *kobj,
>> +			struct bin_attribute *attr, char *buf,
>> +			loff_t pos, size_t size)
>> +{
>> +	ssize_t ret;
>> +	struct device *dev;
>> +	struct sid_priv *priv;
>> +	int i;
>> +
>> +	ret = -EPERM;
>> +	dev = kobj_to_dev(kobj);
>> +	priv = dev_get_drvdata(dev);
>> +
>> +	if ((likely(size > 0)) && ((size + pos) <= SUNXI_SID_SIZE)) {
>> +		for (i = 0; i < size; i++) {
>> +			buf[i] = sunxi_sid_read_byte(pos + i);
>> +		}
>> +		if (i < PAGE_SIZE) {
>> +			buf[i] = '\0';
>> +			ret = (ssize_t)size;
>> +		} else {
>> +			ret = -ENOMEM;
>> +		}
>
> Hmmmm, what? Why returning \0 here? It's not a string, it's binary data.
> What's the relation with PAGE_SIZE again?
I thought that buf is at most PAGE_SIZE large [1] "sysfs allocates a 
buffer of size (PAGE_SIZE) and passes it to the method."
>
> Just return the number of bytes read, that's it.
Yes, had forgotten that this was of course the binary read function and 
not the text version. So yeah, in the binary case, gone.
>
>> +	} else {
>> +		buf[0] = '\0';
>> +		ret = 0;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static struct of_device_id sid_of_match[] = {
>> +	{
>> +		.compatible = "allwinner,sun4i-sid",
>> +	},
>> +	{/* sentinel */}
>> +};
>> +MODULE_DEVICE_TABLE(of, sid_of_match);
>> +
>> +static struct bin_attribute sid_bin_attr = {
>> +	.attr = {
>> +		.name = "key",
>> +		.mode = S_IRUGO,
>> +	},
>> +	.size = SUNXI_SID_SIZE,
>> +	.read = sid_read,
>> +};
>> +
>> +static int sid_remove(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct sid_priv *priv;
>> +
>> +	priv = dev_get_drvdata(dev);
>> +	device_remove_bin_file(dev, &sid_bin_attr);
>> +	iounmap(priv->sid_base);
>> +	devm_kfree(dev, priv);
>> +	return 0;
>> +}
>> +
>> +static int __init sid_probe(struct platform_device *pdev)
>> +{
>> +	int ret;
>> +	struct device *dev = &pdev->dev;
>> +	struct sid_priv *priv;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	p = priv;
>> +
>> +	dev_set_drvdata(dev, priv);
>> +
>> +	if (!priv) {
>> +		dev_err(dev, "Unable to allocate device private data\n");
>> +		ret = -ENOMEM;
>> +		goto exit;
>> +	}
>
> Isn't it a bit weird to check for the memory allocation after using the
Yes, more 'oops'. Re-arranged.
> variable. Also, you don't really need the dev_err, since if the kernel
> fails to allocate some memory, it will tell you anyway.
I had it there mostly for consistency, the other 2 did the same check. 
Initially I had 5 functions here, but you corrected me on that :)

>
>> +	priv->sid_base = of_iomap(dev->of_node, 0);
>> +	if (!priv->sid_base) {
>> +		dev_err(dev, "Unable to map memory region\n");
>> +		ret = -ENOMEM;
>> +		goto exit_free;
>> +	}
>> +
>> +	ret = device_create_bin_file(dev, &sid_bin_attr);
>> +	if (ret) {
>> +		dev_err(dev, "Unable to create sysfs bin entry\n");
>> +		goto exit_unmap;
>> +	}
>
> Hmmm, maybe it's not worth all these gotos just for an iounmap, I'd
> probably return right away, but that's your call.
I saw a lot of drivers do the goto: dance in init/probe/exit/remove 
functions, I don't think the overhead here would be so bad?
>
>> +	dev_info(dev, "Sunxi security ID driver loaded successfully.\n");
>> +
>> +	return 0;
>> +
>> +
>> +exit_unmap:
>> +	iounmap(priv->sid_base);
>> +exit_free:
>> +	devm_kfree(dev, priv);
>> +exit:
>> +	return ret;
>> +}
>> +
>> +static struct platform_driver sid_driver = {
>> +	.probe = sid_probe,
>> +	.remove = sid_remove,
>> +	.driver = {
>> +		.name = DRV_NAME,
>> +		.owner = THIS_MODULE,
>> +		.of_match_table = sid_of_match,
>> +	},
>> +};
>> +module_platform_driver(sid_driver);
>> +
>> +
>> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
>> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
>> +MODULE_VERSION(DRV_VERSION);
>> +MODULE_LICENSE("GPL");
>>
>
> Thanks for this driver!
> Maxime
>
You are welcome! :D While awaiting more feedback, i've pushed the 
current version to my github [2].

Oliver

[0] 
https://github.com/amery/linux-allwinner/blob/lichee-3.3/sun7i-dev/arch/arm/mach-sun7i/security_id.c#L91
[1] https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
[2] 
https://github.com/oliv3r/linux/blob/wip/sunxi-security-id/drivers/misc/eeprom/sunxi_sid.c

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-18 17:19       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-18 17:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/17/13 23:18, Maxime Ripard wrote:
> Hi Oliver,
>
> Le 17/05/2013 15:35, Oliver Schinagl a ?crit :
>> From: Oliver Schinagl <oliver@schinagl.nl>
>>
>> Allwinner has electric fuses (efuse) on their line of chips. This driver
>> reads those fuses and exports them as a sysfs node. Also a symbol is exported
>> for in-kernel useage.
>>
>> While initially these fuses are used to somewhat determin the chipID, these
>> appear to be writeable by the user and thus can be used for other purpouses.
>> For example storing a 128 bit root key, a unique serial number, which could
>> then even be used as a MAC address.
>>
>> Because writing to e-fuses can be potentially dangerous, and are certainly
>> not as often writable (if at all) as flash memory, these shouldn't be easily
>> changeable, hence only a read-only mode. An offline tool to write the fuses
>> is in the works.
>>
>> Currently supported are the following known chips:
>> Allwinner sun4i (A10)
>> Allwinner sun5i (A10s A13)
>> Allwinner sun6i (A31, A31s)
>> Allwinner sun7i (A20)
>
> Since I don't think those patches have been tested on sun6i/sun7i, and
> that there's not even kernel support for those, maybe it's not worth
> mentionning them?
A31 is out in the wild, but haven't seen that functionality in, I have 
seen the register named and defined, just not used, so that could go 
until confirmed.

A20 has the same feature as we can see in the dumped sources. [0]


>
>>
>> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
>> ---
>>   drivers/misc/eeprom/Kconfig     |  19 ++++
>>   drivers/misc/eeprom/Makefile    |   1 +
>>   drivers/misc/eeprom/sunxi_sid.c | 218 ++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 238 insertions(+)
>>   create mode 100644 drivers/misc/eeprom/sunxi_sid.c
>>
>> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
>> index 04f2e1f..c9ddda5 100644
>> --- a/drivers/misc/eeprom/Kconfig
>> +++ b/drivers/misc/eeprom/Kconfig
>> @@ -96,4 +96,23 @@ 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. Currently supported are:
>> +		sun4i (A10)
>> +		sun5i (A10s, A12, A13)
>> +		sun6i (A31)
>> +		sun7i (A20)
>
> Same things here.
>
>> +
>> +	  Due to the potential risks involved with changing e-fuses,
>> +	  this driver is read-only
>> +
>> +	  For more information visit http://linux-sunxi.org/SID
>> +
>> +	  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 fc1e81d..9507aec 100644
>> --- a/drivers/misc/eeprom/Makefile
>> +++ b/drivers/misc/eeprom/Makefile
>> @@ -4,4 +4,5 @@ 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
>> new file mode 100644
>> index 0000000..953f137
>> --- /dev/null
>> +++ b/drivers/misc/eeprom/sunxi_sid.c
>> @@ -0,0 +1,218 @@
>> +/*
>> + * Copyright (c) 2013 Oliver Schinagl
>> + * http://www.linux-sunxi.org
>> + *
>> + * Oliver Schinagl <oliver@schinagl.nl>
>> + *
>> + * 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, a 128 bit eeprom, in chunks
>> + * of 8 bytes.
>
> 16 bytes or 8 bits? because 8 bytes != 128 bits.
fixed, it was late when I wrote that :( It is indeed 8 bits, e.g. byte 
sized chunks.

>
>> + */
>> +
>> +#include <linux/compiler.h>
>> +#include <linux/device.h>
>> +#include <linux/errno.h>
>> +#include <linux/export.h>
>> +#include <linux/fs.h>
>> +#include <linux/init.h>
>> +#include <linux/io.h>
>> +#include <linux/kobject.h>
>> +#include <linux/module.h>
>> +#include <linux/of_address.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/stat.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/types.h>
>> +
>> +
>> +#define DRV_NAME "sunxi-sid"
>> +#define DRV_VERSION "1.0"
>> +
>> +/* Register offsets */
>> +#define SUNXI_SID_KEY0 0x00
>> +#define SUNXI_SID_KEY1 0x04
>> +#define SUNXI_SID_KEY2 0x08
>> +#define SUNXI_SID_KEY3 0x0c
>> +
>> +/* There are 4 32-bit keys */
>> +#define SUNXI_SID_KEYS 4
>> +/* and 4 32-bit keys per 32-bit key */
>
> The comment is wrong here.
Same as above, corrected.

>
>> +#define SUNXI_SID_SIZE (SUNXI_SID_KEYS * 4)
>> +
>> +#if (SUNXI_SID_SIZE > PAGE_SIZE)
>> +#error "SUNXI_SID_SIZE is larger then the target's PAGE_SIZE, ENOMEM."
>> +#endif
>
> Hmmmm, I don't follow you here, what's the relation between your driver
> and PAGE_SIZE?
Nothing, I thought there was, but isn't. removed.
>
>> +
>> +static u8 keys_lut[] = {
>> +	SUNXI_SID_KEY0,
>> +	SUNXI_SID_KEY1,
>> +	SUNXI_SID_KEY2,
>> +	SUNXI_SID_KEY3,
>> +};
>> +
>> +struct sid_priv {
>> +	void __iomem *sid_base;
>> +};
>> +
>> +struct sid_priv *p;
>
> What's the point of having a structure here? And why putting a global
> value, !static, with a generic name, while you could have an
> instance-specific one?
Forgot the static keyword, and the struct kept on shrinking until only 
the base address was left. I guess memory wise it shouldn't make a 
difference, but the compiler also doesn't agree, so gone it is :)
>
> struct file has a private_data field, use it.
But since we don't 'open' it, we can't use that, as we talked on IRC.

>
>> +
>> +
>> +/* We read the entire key, using a look up table. Returned is only the
>> + * requested byte. This is of course slower then it could be and uses 4 times
>> + * more reads as needed but keeps code a little simpler.
>> + */
>> +u8 sunxi_sid_read_byte(const int key)
>> +{
>> +	u32 sid_key;
>> +	u8 ret;
>> +
>> +	ret = 0;
>> +	if (likely((key <= SUNXI_SID_SIZE))) {
>> +		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
>> +		switch (key % 4) {
>> +		case 0:
>> +			ret = (sid_key >> 24) & 0xff;
>> +			break;
>> +		case 1:
>> +			ret = (sid_key >> 16) & 0xff;
>> +			break;
>> +		case 2:
>> +			ret = (sid_key >> 8) & 0xff;
>> +			break;
>> +		case 3:
>> +			ret = sid_key & 0xff;
>> +			break;
>> +		}
>> +	}
>
> Come on, you can do better. This lookup table is useless.
I didn't want to depend on the fixed layout of memory, but consider it 
removed.
>
> Also, why the first key is the one with the MSBs?
> I'd expect that the key 0 is the one holding the LSBs.
Strangely enough, they have swapped the MSB and LSB bytes. I double 
checked it with u-boot and yep, swapped. Though in the end, if we write 
stuff there and we read stuff from there, order doesn't matter? So what 
do we prefer. Have it so that it makes sense and ignore how u-boot reads 
it, or correct it and be consistent?

>
>> +
>> +	return ret;
>> +}
>> +
>> +static ssize_t sid_read(struct file *fd, struct kobject *kobj,
>> +			struct bin_attribute *attr, char *buf,
>> +			loff_t pos, size_t size)
>> +{
>> +	ssize_t ret;
>> +	struct device *dev;
>> +	struct sid_priv *priv;
>> +	int i;
>> +
>> +	ret = -EPERM;
>> +	dev = kobj_to_dev(kobj);
>> +	priv = dev_get_drvdata(dev);
>> +
>> +	if ((likely(size > 0)) && ((size + pos) <= SUNXI_SID_SIZE)) {
>> +		for (i = 0; i < size; i++) {
>> +			buf[i] = sunxi_sid_read_byte(pos + i);
>> +		}
>> +		if (i < PAGE_SIZE) {
>> +			buf[i] = '\0';
>> +			ret = (ssize_t)size;
>> +		} else {
>> +			ret = -ENOMEM;
>> +		}
>
> Hmmmm, what? Why returning \0 here? It's not a string, it's binary data.
> What's the relation with PAGE_SIZE again?
I thought that buf is at most PAGE_SIZE large [1] "sysfs allocates a 
buffer of size (PAGE_SIZE) and passes it to the method."
>
> Just return the number of bytes read, that's it.
Yes, had forgotten that this was of course the binary read function and 
not the text version. So yeah, in the binary case, gone.
>
>> +	} else {
>> +		buf[0] = '\0';
>> +		ret = 0;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +static struct of_device_id sid_of_match[] = {
>> +	{
>> +		.compatible = "allwinner,sun4i-sid",
>> +	},
>> +	{/* sentinel */}
>> +};
>> +MODULE_DEVICE_TABLE(of, sid_of_match);
>> +
>> +static struct bin_attribute sid_bin_attr = {
>> +	.attr = {
>> +		.name = "key",
>> +		.mode = S_IRUGO,
>> +	},
>> +	.size = SUNXI_SID_SIZE,
>> +	.read = sid_read,
>> +};
>> +
>> +static int sid_remove(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct sid_priv *priv;
>> +
>> +	priv = dev_get_drvdata(dev);
>> +	device_remove_bin_file(dev, &sid_bin_attr);
>> +	iounmap(priv->sid_base);
>> +	devm_kfree(dev, priv);
>> +	return 0;
>> +}
>> +
>> +static int __init sid_probe(struct platform_device *pdev)
>> +{
>> +	int ret;
>> +	struct device *dev = &pdev->dev;
>> +	struct sid_priv *priv;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	p = priv;
>> +
>> +	dev_set_drvdata(dev, priv);
>> +
>> +	if (!priv) {
>> +		dev_err(dev, "Unable to allocate device private data\n");
>> +		ret = -ENOMEM;
>> +		goto exit;
>> +	}
>
> Isn't it a bit weird to check for the memory allocation after using the
Yes, more 'oops'. Re-arranged.
> variable. Also, you don't really need the dev_err, since if the kernel
> fails to allocate some memory, it will tell you anyway.
I had it there mostly for consistency, the other 2 did the same check. 
Initially I had 5 functions here, but you corrected me on that :)

>
>> +	priv->sid_base = of_iomap(dev->of_node, 0);
>> +	if (!priv->sid_base) {
>> +		dev_err(dev, "Unable to map memory region\n");
>> +		ret = -ENOMEM;
>> +		goto exit_free;
>> +	}
>> +
>> +	ret = device_create_bin_file(dev, &sid_bin_attr);
>> +	if (ret) {
>> +		dev_err(dev, "Unable to create sysfs bin entry\n");
>> +		goto exit_unmap;
>> +	}
>
> Hmmm, maybe it's not worth all these gotos just for an iounmap, I'd
> probably return right away, but that's your call.
I saw a lot of drivers do the goto: dance in init/probe/exit/remove 
functions, I don't think the overhead here would be so bad?
>
>> +	dev_info(dev, "Sunxi security ID driver loaded successfully.\n");
>> +
>> +	return 0;
>> +
>> +
>> +exit_unmap:
>> +	iounmap(priv->sid_base);
>> +exit_free:
>> +	devm_kfree(dev, priv);
>> +exit:
>> +	return ret;
>> +}
>> +
>> +static struct platform_driver sid_driver = {
>> +	.probe = sid_probe,
>> +	.remove = sid_remove,
>> +	.driver = {
>> +		.name = DRV_NAME,
>> +		.owner = THIS_MODULE,
>> +		.of_match_table = sid_of_match,
>> +	},
>> +};
>> +module_platform_driver(sid_driver);
>> +
>> +
>> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
>> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
>> +MODULE_VERSION(DRV_VERSION);
>> +MODULE_LICENSE("GPL");
>>
>
> Thanks for this driver!
> Maxime
>
You are welcome! :D While awaiting more feedback, i've pushed the 
current version to my github [2].

Oliver

[0] 
https://github.com/amery/linux-allwinner/blob/lichee-3.3/sun7i-dev/arch/arm/mach-sun7i/security_id.c#L91
[1] https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
[2] 
https://github.com/oliv3r/linux/blob/wip/sunxi-security-id/drivers/misc/eeprom/sunxi_sid.c

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-17 13:35   ` Oliver Schinagl
@ 2013-05-17 21:18     ` Maxime Ripard
  -1 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-17 21:18 UTC (permalink / raw)
  To: Oliver Schinagl
  Cc: arnd, gregkh, linux-kernel, linux-arm-kernel, Oliver Schinagl

Hi Oliver,

Le 17/05/2013 15:35, Oliver Schinagl a écrit :
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses and exports them as a sysfs node. Also a symbol is exported
> for in-kernel useage.
> 
> While initially these fuses are used to somewhat determin the chipID, these
> appear to be writeable by the user and thus can be used for other purpouses.
> For example storing a 128 bit root key, a unique serial number, which could
> then even be used as a MAC address.
> 
> Because writing to e-fuses can be potentially dangerous, and are certainly
> not as often writable (if at all) as flash memory, these shouldn't be easily
> changeable, hence only a read-only mode. An offline tool to write the fuses
> is in the works.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s A13)
> Allwinner sun6i (A31, A31s)
> Allwinner sun7i (A20)

Since I don't think those patches have been tested on sun6i/sun7i, and
that there's not even kernel support for those, maybe it's not worth
mentionning them?

> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  drivers/misc/eeprom/Kconfig     |  19 ++++
>  drivers/misc/eeprom/Makefile    |   1 +
>  drivers/misc/eeprom/sunxi_sid.c | 218 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 238 insertions(+)
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> 
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..c9ddda5 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,23 @@ 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. Currently supported are:
> +		sun4i (A10)
> +		sun5i (A10s, A12, A13)
> +		sun6i (A31)
> +		sun7i (A20)

Same things here.

> +
> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID
> +
> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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
> new file mode 100644
> index 0000000..953f137
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,218 @@
> +/*
> + * Copyright (c) 2013 Oliver Schinagl
> + * http://www.linux-sunxi.org
> + *
> + * Oliver Schinagl <oliver@schinagl.nl>
> + *
> + * 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, a 128 bit eeprom, in chunks
> + * of 8 bytes.

16 bytes or 8 bits? because 8 bytes != 128 bits.

> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +
> +#define DRV_NAME "sunxi-sid"
> +#define DRV_VERSION "1.0"
> +
> +/* Register offsets */
> +#define SUNXI_SID_KEY0 0x00
> +#define SUNXI_SID_KEY1 0x04
> +#define SUNXI_SID_KEY2 0x08
> +#define SUNXI_SID_KEY3 0x0c
> +
> +/* There are 4 32-bit keys */
> +#define SUNXI_SID_KEYS 4
> +/* and 4 32-bit keys per 32-bit key */

The comment is wrong here.

> +#define SUNXI_SID_SIZE (SUNXI_SID_KEYS * 4)
> +
> +#if (SUNXI_SID_SIZE > PAGE_SIZE)
> +#error "SUNXI_SID_SIZE is larger then the target's PAGE_SIZE, ENOMEM."
> +#endif

Hmmmm, I don't follow you here, what's the relation between your driver
and PAGE_SIZE?

> +
> +static u8 keys_lut[] = {
> +	SUNXI_SID_KEY0,
> +	SUNXI_SID_KEY1,
> +	SUNXI_SID_KEY2,
> +	SUNXI_SID_KEY3,
> +};
> +
> +struct sid_priv {
> +	void __iomem *sid_base;
> +};
> +
> +struct sid_priv *p;

What's the point of having a structure here? And why putting a global
value, !static, with a generic name, while you could have an
instance-specific one?

struct file has a private_data field, use it.

> +
> +
> +/* We read the entire key, using a look up table. Returned is only the
> + * requested byte. This is of course slower then it could be and uses 4 times
> + * more reads as needed but keeps code a little simpler.
> + */
> +u8 sunxi_sid_read_byte(const int key)
> +{
> +	u32 sid_key;
> +	u8 ret;
> +
> +	ret = 0;
> +	if (likely((key <= SUNXI_SID_SIZE))) {
> +		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
> +		switch (key % 4) {
> +		case 0:
> +			ret = (sid_key >> 24) & 0xff;
> +			break;
> +		case 1:
> +			ret = (sid_key >> 16) & 0xff;
> +			break;
> +		case 2:
> +			ret = (sid_key >> 8) & 0xff;
> +			break;
> +		case 3:
> +			ret = sid_key & 0xff;
> +			break;
> +		}
> +	}

Come on, you can do better. This lookup table is useless.

Also, why the first key is the one with the MSBs?
I'd expect that the key 0 is the one holding the LSBs.

> +
> +	return ret;
> +}
> +
> +static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> +			struct bin_attribute *attr, char *buf,
> +			loff_t pos, size_t size)
> +{
> +	ssize_t ret;
> +	struct device *dev;
> +	struct sid_priv *priv;
> +	int i;
> +
> +	ret = -EPERM;
> +	dev = kobj_to_dev(kobj);
> +	priv = dev_get_drvdata(dev);
> +
> +	if ((likely(size > 0)) && ((size + pos) <= SUNXI_SID_SIZE)) {
> +		for (i = 0; i < size; i++) {
> +			buf[i] = sunxi_sid_read_byte(pos + i);
> +		}
> +		if (i < PAGE_SIZE) {
> +			buf[i] = '\0';
> +			ret = (ssize_t)size;
> +		} else {
> +			ret = -ENOMEM;
> +		}

Hmmmm, what? Why returning \0 here? It's not a string, it's binary data.
What's the relation with PAGE_SIZE again?

Just return the number of bytes read, that's it.

> +	} else {
> +		buf[0] = '\0';
> +		ret = 0;
> +	}
> +
> +	return ret;
> +}
> +
> +static struct of_device_id sid_of_match[] = {
> +	{
> +		.compatible = "allwinner,sun4i-sid",
> +	},
> +	{/* sentinel */}
> +};
> +MODULE_DEVICE_TABLE(of, sid_of_match);
> +
> +static struct bin_attribute sid_bin_attr = {
> +	.attr = {
> +		.name = "key",
> +		.mode = S_IRUGO,
> +	},
> +	.size = SUNXI_SID_SIZE,
> +	.read = sid_read,
> +};
> +
> +static int sid_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct sid_priv *priv;
> +
> +	priv = dev_get_drvdata(dev);
> +	device_remove_bin_file(dev, &sid_bin_attr);
> +	iounmap(priv->sid_base);
> +	devm_kfree(dev, priv);
> +	return 0;
> +}
> +
> +static int __init sid_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct device *dev = &pdev->dev;
> +	struct sid_priv *priv;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	p = priv;
> +
> +	dev_set_drvdata(dev, priv);
> +
> +	if (!priv) {
> +		dev_err(dev, "Unable to allocate device private data\n");
> +		ret = -ENOMEM;
> +		goto exit;
> +	}

Isn't it a bit weird to check for the memory allocation after using the
variable. Also, you don't really need the dev_err, since if the kernel
fails to allocate some memory, it will tell you anyway.

> +	priv->sid_base = of_iomap(dev->of_node, 0);
> +	if (!priv->sid_base) {
> +		dev_err(dev, "Unable to map memory region\n");
> +		ret = -ENOMEM;
> +		goto exit_free;
> +	}
> +
> +	ret = device_create_bin_file(dev, &sid_bin_attr);
> +	if (ret) {
> +		dev_err(dev, "Unable to create sysfs bin entry\n");
> +		goto exit_unmap;
> +	}

Hmmm, maybe it's not worth all these gotos just for an iounmap, I'd
probably return right away, but that's your call.

> +	dev_info(dev, "Sunxi security ID driver loaded successfully.\n");
> +
> +	return 0;
> +
> +
> +exit_unmap:
> +	iounmap(priv->sid_base);
> +exit_free:
> +	devm_kfree(dev, priv);
> +exit:
> +	return ret;
> +}
> +
> +static struct platform_driver sid_driver = {
> +	.probe = sid_probe,
> +	.remove = sid_remove,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.owner = THIS_MODULE,
> +		.of_match_table = sid_of_match,
> +	},
> +};
> +module_platform_driver(sid_driver);
> +
> +
> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> +MODULE_VERSION(DRV_VERSION);
> +MODULE_LICENSE("GPL");
> 

Thanks for this driver!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-17 21:18     ` Maxime Ripard
  0 siblings, 0 replies; 142+ messages in thread
From: Maxime Ripard @ 2013-05-17 21:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Oliver,

Le 17/05/2013 15:35, Oliver Schinagl a ?crit :
> From: Oliver Schinagl <oliver@schinagl.nl>
> 
> Allwinner has electric fuses (efuse) on their line of chips. This driver
> reads those fuses and exports them as a sysfs node. Also a symbol is exported
> for in-kernel useage.
> 
> While initially these fuses are used to somewhat determin the chipID, these
> appear to be writeable by the user and thus can be used for other purpouses.
> For example storing a 128 bit root key, a unique serial number, which could
> then even be used as a MAC address.
> 
> Because writing to e-fuses can be potentially dangerous, and are certainly
> not as often writable (if at all) as flash memory, these shouldn't be easily
> changeable, hence only a read-only mode. An offline tool to write the fuses
> is in the works.
> 
> Currently supported are the following known chips:
> Allwinner sun4i (A10)
> Allwinner sun5i (A10s A13)
> Allwinner sun6i (A31, A31s)
> Allwinner sun7i (A20)

Since I don't think those patches have been tested on sun6i/sun7i, and
that there's not even kernel support for those, maybe it's not worth
mentionning them?

> 
> Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
> ---
>  drivers/misc/eeprom/Kconfig     |  19 ++++
>  drivers/misc/eeprom/Makefile    |   1 +
>  drivers/misc/eeprom/sunxi_sid.c | 218 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 238 insertions(+)
>  create mode 100644 drivers/misc/eeprom/sunxi_sid.c
> 
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index 04f2e1f..c9ddda5 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -96,4 +96,23 @@ 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. Currently supported are:
> +		sun4i (A10)
> +		sun5i (A10s, A12, A13)
> +		sun6i (A31)
> +		sun7i (A20)

Same things here.

> +
> +	  Due to the potential risks involved with changing e-fuses,
> +	  this driver is read-only
> +
> +	  For more information visit http://linux-sunxi.org/SID
> +
> +	  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 fc1e81d..9507aec 100644
> --- a/drivers/misc/eeprom/Makefile
> +++ b/drivers/misc/eeprom/Makefile
> @@ -4,4 +4,5 @@ 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
> new file mode 100644
> index 0000000..953f137
> --- /dev/null
> +++ b/drivers/misc/eeprom/sunxi_sid.c
> @@ -0,0 +1,218 @@
> +/*
> + * Copyright (c) 2013 Oliver Schinagl
> + * http://www.linux-sunxi.org
> + *
> + * Oliver Schinagl <oliver@schinagl.nl>
> + *
> + * 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, a 128 bit eeprom, in chunks
> + * of 8 bytes.

16 bytes or 8 bits? because 8 bytes != 128 bits.

> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/stat.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>
> +
> +
> +#define DRV_NAME "sunxi-sid"
> +#define DRV_VERSION "1.0"
> +
> +/* Register offsets */
> +#define SUNXI_SID_KEY0 0x00
> +#define SUNXI_SID_KEY1 0x04
> +#define SUNXI_SID_KEY2 0x08
> +#define SUNXI_SID_KEY3 0x0c
> +
> +/* There are 4 32-bit keys */
> +#define SUNXI_SID_KEYS 4
> +/* and 4 32-bit keys per 32-bit key */

The comment is wrong here.

> +#define SUNXI_SID_SIZE (SUNXI_SID_KEYS * 4)
> +
> +#if (SUNXI_SID_SIZE > PAGE_SIZE)
> +#error "SUNXI_SID_SIZE is larger then the target's PAGE_SIZE, ENOMEM."
> +#endif

Hmmmm, I don't follow you here, what's the relation between your driver
and PAGE_SIZE?

> +
> +static u8 keys_lut[] = {
> +	SUNXI_SID_KEY0,
> +	SUNXI_SID_KEY1,
> +	SUNXI_SID_KEY2,
> +	SUNXI_SID_KEY3,
> +};
> +
> +struct sid_priv {
> +	void __iomem *sid_base;
> +};
> +
> +struct sid_priv *p;

What's the point of having a structure here? And why putting a global
value, !static, with a generic name, while you could have an
instance-specific one?

struct file has a private_data field, use it.

> +
> +
> +/* We read the entire key, using a look up table. Returned is only the
> + * requested byte. This is of course slower then it could be and uses 4 times
> + * more reads as needed but keeps code a little simpler.
> + */
> +u8 sunxi_sid_read_byte(const int key)
> +{
> +	u32 sid_key;
> +	u8 ret;
> +
> +	ret = 0;
> +	if (likely((key <= SUNXI_SID_SIZE))) {
> +		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
> +		switch (key % 4) {
> +		case 0:
> +			ret = (sid_key >> 24) & 0xff;
> +			break;
> +		case 1:
> +			ret = (sid_key >> 16) & 0xff;
> +			break;
> +		case 2:
> +			ret = (sid_key >> 8) & 0xff;
> +			break;
> +		case 3:
> +			ret = sid_key & 0xff;
> +			break;
> +		}
> +	}

Come on, you can do better. This lookup table is useless.

Also, why the first key is the one with the MSBs?
I'd expect that the key 0 is the one holding the LSBs.

> +
> +	return ret;
> +}
> +
> +static ssize_t sid_read(struct file *fd, struct kobject *kobj,
> +			struct bin_attribute *attr, char *buf,
> +			loff_t pos, size_t size)
> +{
> +	ssize_t ret;
> +	struct device *dev;
> +	struct sid_priv *priv;
> +	int i;
> +
> +	ret = -EPERM;
> +	dev = kobj_to_dev(kobj);
> +	priv = dev_get_drvdata(dev);
> +
> +	if ((likely(size > 0)) && ((size + pos) <= SUNXI_SID_SIZE)) {
> +		for (i = 0; i < size; i++) {
> +			buf[i] = sunxi_sid_read_byte(pos + i);
> +		}
> +		if (i < PAGE_SIZE) {
> +			buf[i] = '\0';
> +			ret = (ssize_t)size;
> +		} else {
> +			ret = -ENOMEM;
> +		}

Hmmmm, what? Why returning \0 here? It's not a string, it's binary data.
What's the relation with PAGE_SIZE again?

Just return the number of bytes read, that's it.

> +	} else {
> +		buf[0] = '\0';
> +		ret = 0;
> +	}
> +
> +	return ret;
> +}
> +
> +static struct of_device_id sid_of_match[] = {
> +	{
> +		.compatible = "allwinner,sun4i-sid",
> +	},
> +	{/* sentinel */}
> +};
> +MODULE_DEVICE_TABLE(of, sid_of_match);
> +
> +static struct bin_attribute sid_bin_attr = {
> +	.attr = {
> +		.name = "key",
> +		.mode = S_IRUGO,
> +	},
> +	.size = SUNXI_SID_SIZE,
> +	.read = sid_read,
> +};
> +
> +static int sid_remove(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct sid_priv *priv;
> +
> +	priv = dev_get_drvdata(dev);
> +	device_remove_bin_file(dev, &sid_bin_attr);
> +	iounmap(priv->sid_base);
> +	devm_kfree(dev, priv);
> +	return 0;
> +}
> +
> +static int __init sid_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct device *dev = &pdev->dev;
> +	struct sid_priv *priv;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	p = priv;
> +
> +	dev_set_drvdata(dev, priv);
> +
> +	if (!priv) {
> +		dev_err(dev, "Unable to allocate device private data\n");
> +		ret = -ENOMEM;
> +		goto exit;
> +	}

Isn't it a bit weird to check for the memory allocation after using the
variable. Also, you don't really need the dev_err, since if the kernel
fails to allocate some memory, it will tell you anyway.

> +	priv->sid_base = of_iomap(dev->of_node, 0);
> +	if (!priv->sid_base) {
> +		dev_err(dev, "Unable to map memory region\n");
> +		ret = -ENOMEM;
> +		goto exit_free;
> +	}
> +
> +	ret = device_create_bin_file(dev, &sid_bin_attr);
> +	if (ret) {
> +		dev_err(dev, "Unable to create sysfs bin entry\n");
> +		goto exit_unmap;
> +	}

Hmmm, maybe it's not worth all these gotos just for an iounmap, I'd
probably return right away, but that's your call.

> +	dev_info(dev, "Sunxi security ID driver loaded successfully.\n");
> +
> +	return 0;
> +
> +
> +exit_unmap:
> +	iounmap(priv->sid_base);
> +exit_free:
> +	devm_kfree(dev, priv);
> +exit:
> +	return ret;
> +}
> +
> +static struct platform_driver sid_driver = {
> +	.probe = sid_probe,
> +	.remove = sid_remove,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.owner = THIS_MODULE,
> +		.of_match_table = sid_of_match,
> +	},
> +};
> +module_platform_driver(sid_driver);
> +
> +
> +MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
> +MODULE_DESCRIPTION("Allwinner sunxi security id driver");
> +MODULE_VERSION(DRV_VERSION);
> +MODULE_LICENSE("GPL");
> 

Thanks for this driver!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-17 13:45     ` Arnd Bergmann
@ 2013-05-17 18:54       ` Oliver Schinagl
  -1 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-17 18:54 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, maxime.ripard, arnd, gregkh, Oliver Schinagl,
	linux-kernel

On 05/17/13 15:45, Arnd Bergmann wrote:
> On Friday 17 May 2013 15:35:43 Oliver Schinagl wrote:
>> +static struct bin_attribute sid_bin_attr = {
>> +       .attr = {
>> +               .name = "key",
>> +               .mode = S_IRUGO,
>> +       },
>> +       .size = SUNXI_SID_SIZE,
>> +       .read = sid_read,
>> +};
>
> I believe all the other drivers in drivers/misc/eeprom use "eeprom"
> as the name for the attribute, so using "key" here is a bit inconsistent.
>
> Can you change that?
Changed, will wait for more feedback and then use that in the final version.

Should there also be a symlink elsewhere in /sys? Just curious is all.
>
> 	Arnd
>


^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-17 18:54       ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-17 18:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/17/13 15:45, Arnd Bergmann wrote:
> On Friday 17 May 2013 15:35:43 Oliver Schinagl wrote:
>> +static struct bin_attribute sid_bin_attr = {
>> +       .attr = {
>> +               .name = "key",
>> +               .mode = S_IRUGO,
>> +       },
>> +       .size = SUNXI_SID_SIZE,
>> +       .read = sid_read,
>> +};
>
> I believe all the other drivers in drivers/misc/eeprom use "eeprom"
> as the name for the attribute, so using "key" here is a bit inconsistent.
>
> Can you change that?
Changed, will wait for more feedback and then use that in the final version.

Should there also be a symlink elsewhere in /sys? Just curious is all.
>
> 	Arnd
>

^ permalink raw reply	[flat|nested] 142+ messages in thread

* Re: [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-17 13:35   ` Oliver Schinagl
@ 2013-05-17 13:45     ` Arnd Bergmann
  -1 siblings, 0 replies; 142+ messages in thread
From: Arnd Bergmann @ 2013-05-17 13:45 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Oliver Schinagl, maxime.ripard, arnd, gregkh, Oliver Schinagl,
	linux-kernel

On Friday 17 May 2013 15:35:43 Oliver Schinagl wrote:
> +static struct bin_attribute sid_bin_attr = {
> +       .attr = {
> +               .name = "key",
> +               .mode = S_IRUGO,
> +       },
> +       .size = SUNXI_SID_SIZE,
> +       .read = sid_read,
> +};

I believe all the other drivers in drivers/misc/eeprom use "eeprom"
as the name for the attribute, so using "key" here is a bit inconsistent.

Can you change that?

	Arnd

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-17 13:45     ` Arnd Bergmann
  0 siblings, 0 replies; 142+ messages in thread
From: Arnd Bergmann @ 2013-05-17 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 17 May 2013 15:35:43 Oliver Schinagl wrote:
> +static struct bin_attribute sid_bin_attr = {
> +       .attr = {
> +               .name = "key",
> +               .mode = S_IRUGO,
> +       },
> +       .size = SUNXI_SID_SIZE,
> +       .read = sid_read,
> +};

I believe all the other drivers in drivers/misc/eeprom use "eeprom"
as the name for the attribute, so using "key" here is a bit inconsistent.

Can you change that?

	Arnd

^ permalink raw reply	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
  2013-05-17 13:35 [PATCH 0/2] Driver for Allwinner sunxi Security ID Oliver Schinagl
@ 2013-05-17 13:35   ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-17 13:35 UTC (permalink / raw)
  To: maxime.ripard, arnd, gregkh
  Cc: linux-kernel, linux-arm-kernel, Oliver Schinagl

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses and exports them as a sysfs node. Also a symbol is exported
for in-kernel useage.

While initially these fuses are used to somewhat determin the chipID, these
appear to be writeable by the user and thus can be used for other purpouses.
For example storing a 128 bit root key, a unique serial number, which could
then even be used as a MAC address.

Because writing to e-fuses can be potentially dangerous, and are certainly
not as often writable (if at all) as flash memory, these shouldn't be easily
changeable, hence only a read-only mode. An offline tool to write the fuses
is in the works.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A10s A13)
Allwinner sun6i (A31, A31s)
Allwinner sun7i (A20)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 drivers/misc/eeprom/Kconfig     |  19 ++++
 drivers/misc/eeprom/Makefile    |   1 +
 drivers/misc/eeprom/sunxi_sid.c | 218 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 238 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..c9ddda5 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,23 @@ 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. Currently supported are:
+		sun4i (A10)
+		sun5i (A10s, A12, A13)
+		sun6i (A31)
+		sun7i (A20)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..953f137
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2013 Oliver Schinagl
+ * http://www.linux-sunxi.org
+ *
+ * Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * 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, a 128 bit eeprom, in chunks
+ * of 8 bytes.
+ */
+
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+
+#define DRV_NAME "sunxi-sid"
+#define DRV_VERSION "1.0"
+
+/* Register offsets */
+#define SUNXI_SID_KEY0 0x00
+#define SUNXI_SID_KEY1 0x04
+#define SUNXI_SID_KEY2 0x08
+#define SUNXI_SID_KEY3 0x0c
+
+/* There are 4 32-bit keys */
+#define SUNXI_SID_KEYS 4
+/* and 4 32-bit keys per 32-bit key */
+#define SUNXI_SID_SIZE (SUNXI_SID_KEYS * 4)
+
+#if (SUNXI_SID_SIZE > PAGE_SIZE)
+#error "SUNXI_SID_SIZE is larger then the target's PAGE_SIZE, ENOMEM."
+#endif
+
+static u8 keys_lut[] = {
+	SUNXI_SID_KEY0,
+	SUNXI_SID_KEY1,
+	SUNXI_SID_KEY2,
+	SUNXI_SID_KEY3,
+};
+
+struct sid_priv {
+	void __iomem *sid_base;
+};
+
+struct sid_priv *p;
+
+
+/* We read the entire key, using a look up table. Returned is only the
+ * requested byte. This is of course slower then it could be and uses 4 times
+ * more reads as needed but keeps code a little simpler.
+ */
+u8 sunxi_sid_read_byte(const int key)
+{
+	u32 sid_key;
+	u8 ret;
+
+	ret = 0;
+	if (likely((key <= SUNXI_SID_SIZE))) {
+		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
+		switch (key % 4) {
+		case 0:
+			ret = (sid_key >> 24) & 0xff;
+			break;
+		case 1:
+			ret = (sid_key >> 16) & 0xff;
+			break;
+		case 2:
+			ret = (sid_key >> 8) & 0xff;
+			break;
+		case 3:
+			ret = sid_key & 0xff;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static ssize_t sid_read(struct file *fd, struct kobject *kobj,
+			struct bin_attribute *attr, char *buf,
+			loff_t pos, size_t size)
+{
+	ssize_t ret;
+	struct device *dev;
+	struct sid_priv *priv;
+	int i;
+
+	ret = -EPERM;
+	dev = kobj_to_dev(kobj);
+	priv = dev_get_drvdata(dev);
+
+	if ((likely(size > 0)) && ((size + pos) <= SUNXI_SID_SIZE)) {
+		for (i = 0; i < size; i++) {
+			buf[i] = sunxi_sid_read_byte(pos + i);
+		}
+		if (i < PAGE_SIZE) {
+			buf[i] = '\0';
+			ret = (ssize_t)size;
+		} else {
+			ret = -ENOMEM;
+		}
+	} else {
+		buf[0] = '\0';
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static struct of_device_id sid_of_match[] = {
+	{
+		.compatible = "allwinner,sun4i-sid",
+	},
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, sid_of_match);
+
+static struct bin_attribute sid_bin_attr = {
+	.attr = {
+		.name = "key",
+		.mode = S_IRUGO,
+	},
+	.size = SUNXI_SID_SIZE,
+	.read = sid_read,
+};
+
+static int sid_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sid_priv *priv;
+
+	priv = dev_get_drvdata(dev);
+	device_remove_bin_file(dev, &sid_bin_attr);
+	iounmap(priv->sid_base);
+	devm_kfree(dev, priv);
+	return 0;
+}
+
+static int __init sid_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct sid_priv *priv;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	p = priv;
+
+	dev_set_drvdata(dev, priv);
+
+	if (!priv) {
+		dev_err(dev, "Unable to allocate device private data\n");
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	priv->sid_base = of_iomap(dev->of_node, 0);
+	if (!priv->sid_base) {
+		dev_err(dev, "Unable to map memory region\n");
+		ret = -ENOMEM;
+		goto exit_free;
+	}
+
+	ret = device_create_bin_file(dev, &sid_bin_attr);
+	if (ret) {
+		dev_err(dev, "Unable to create sysfs bin entry\n");
+		goto exit_unmap;
+	}
+
+	dev_info(dev, "Sunxi security ID driver loaded successfully.\n");
+
+	return 0;
+
+
+exit_unmap:
+	iounmap(priv->sid_base);
+exit_free:
+	devm_kfree(dev, priv);
+exit:
+	return ret;
+}
+
+static struct platform_driver sid_driver = {
+	.probe = sid_probe,
+	.remove = sid_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = sid_of_match,
+	},
+};
+module_platform_driver(sid_driver);
+
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
-- 
1.8.1.5


^ permalink raw reply related	[flat|nested] 142+ messages in thread

* [PATCH 1/2] Initial support for Allwinner's Security ID fuses
@ 2013-05-17 13:35   ` Oliver Schinagl
  0 siblings, 0 replies; 142+ messages in thread
From: Oliver Schinagl @ 2013-05-17 13:35 UTC (permalink / raw)
  To: linux-arm-kernel

From: Oliver Schinagl <oliver@schinagl.nl>

Allwinner has electric fuses (efuse) on their line of chips. This driver
reads those fuses and exports them as a sysfs node. Also a symbol is exported
for in-kernel useage.

While initially these fuses are used to somewhat determin the chipID, these
appear to be writeable by the user and thus can be used for other purpouses.
For example storing a 128 bit root key, a unique serial number, which could
then even be used as a MAC address.

Because writing to e-fuses can be potentially dangerous, and are certainly
not as often writable (if at all) as flash memory, these shouldn't be easily
changeable, hence only a read-only mode. An offline tool to write the fuses
is in the works.

Currently supported are the following known chips:
Allwinner sun4i (A10)
Allwinner sun5i (A10s A13)
Allwinner sun6i (A31, A31s)
Allwinner sun7i (A20)

Signed-off-by: Oliver Schinagl <oliver@schinagl.nl>
---
 drivers/misc/eeprom/Kconfig     |  19 ++++
 drivers/misc/eeprom/Makefile    |   1 +
 drivers/misc/eeprom/sunxi_sid.c | 218 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 238 insertions(+)
 create mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 04f2e1f..c9ddda5 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,4 +96,23 @@ 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. Currently supported are:
+		sun4i (A10)
+		sun5i (A10s, A12, A13)
+		sun6i (A31)
+		sun7i (A20)
+
+	  Due to the potential risks involved with changing e-fuses,
+	  this driver is read-only
+
+	  For more information visit http://linux-sunxi.org/SID
+
+	  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 fc1e81d..9507aec 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,4 +4,5 @@ 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
new file mode 100644
index 0000000..953f137
--- /dev/null
+++ b/drivers/misc/eeprom/sunxi_sid.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2013 Oliver Schinagl
+ * http://www.linux-sunxi.org
+ *
+ * Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * 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, a 128 bit eeprom, in chunks
+ * of 8 bytes.
+ */
+
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+
+#define DRV_NAME "sunxi-sid"
+#define DRV_VERSION "1.0"
+
+/* Register offsets */
+#define SUNXI_SID_KEY0 0x00
+#define SUNXI_SID_KEY1 0x04
+#define SUNXI_SID_KEY2 0x08
+#define SUNXI_SID_KEY3 0x0c
+
+/* There are 4 32-bit keys */
+#define SUNXI_SID_KEYS 4
+/* and 4 32-bit keys per 32-bit key */
+#define SUNXI_SID_SIZE (SUNXI_SID_KEYS * 4)
+
+#if (SUNXI_SID_SIZE > PAGE_SIZE)
+#error "SUNXI_SID_SIZE is larger then the target's PAGE_SIZE, ENOMEM."
+#endif
+
+static u8 keys_lut[] = {
+	SUNXI_SID_KEY0,
+	SUNXI_SID_KEY1,
+	SUNXI_SID_KEY2,
+	SUNXI_SID_KEY3,
+};
+
+struct sid_priv {
+	void __iomem *sid_base;
+};
+
+struct sid_priv *p;
+
+
+/* We read the entire key, using a look up table. Returned is only the
+ * requested byte. This is of course slower then it could be and uses 4 times
+ * more reads as needed but keeps code a little simpler.
+ */
+u8 sunxi_sid_read_byte(const int key)
+{
+	u32 sid_key;
+	u8 ret;
+
+	ret = 0;
+	if (likely((key <= SUNXI_SID_SIZE))) {
+		sid_key = ioread32(p->sid_base + keys_lut[key >> 2]);
+		switch (key % 4) {
+		case 0:
+			ret = (sid_key >> 24) & 0xff;
+			break;
+		case 1:
+			ret = (sid_key >> 16) & 0xff;
+			break;
+		case 2:
+			ret = (sid_key >> 8) & 0xff;
+			break;
+		case 3:
+			ret = sid_key & 0xff;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static ssize_t sid_read(struct file *fd, struct kobject *kobj,
+			struct bin_attribute *attr, char *buf,
+			loff_t pos, size_t size)
+{
+	ssize_t ret;
+	struct device *dev;
+	struct sid_priv *priv;
+	int i;
+
+	ret = -EPERM;
+	dev = kobj_to_dev(kobj);
+	priv = dev_get_drvdata(dev);
+
+	if ((likely(size > 0)) && ((size + pos) <= SUNXI_SID_SIZE)) {
+		for (i = 0; i < size; i++) {
+			buf[i] = sunxi_sid_read_byte(pos + i);
+		}
+		if (i < PAGE_SIZE) {
+			buf[i] = '\0';
+			ret = (ssize_t)size;
+		} else {
+			ret = -ENOMEM;
+		}
+	} else {
+		buf[0] = '\0';
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static struct of_device_id sid_of_match[] = {
+	{
+		.compatible = "allwinner,sun4i-sid",
+	},
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, sid_of_match);
+
+static struct bin_attribute sid_bin_attr = {
+	.attr = {
+		.name = "key",
+		.mode = S_IRUGO,
+	},
+	.size = SUNXI_SID_SIZE,
+	.read = sid_read,
+};
+
+static int sid_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sid_priv *priv;
+
+	priv = dev_get_drvdata(dev);
+	device_remove_bin_file(dev, &sid_bin_attr);
+	iounmap(priv->sid_base);
+	devm_kfree(dev, priv);
+	return 0;
+}
+
+static int __init sid_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct device *dev = &pdev->dev;
+	struct sid_priv *priv;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	p = priv;
+
+	dev_set_drvdata(dev, priv);
+
+	if (!priv) {
+		dev_err(dev, "Unable to allocate device private data\n");
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	priv->sid_base = of_iomap(dev->of_node, 0);
+	if (!priv->sid_base) {
+		dev_err(dev, "Unable to map memory region\n");
+		ret = -ENOMEM;
+		goto exit_free;
+	}
+
+	ret = device_create_bin_file(dev, &sid_bin_attr);
+	if (ret) {
+		dev_err(dev, "Unable to create sysfs bin entry\n");
+		goto exit_unmap;
+	}
+
+	dev_info(dev, "Sunxi security ID driver loaded successfully.\n");
+
+	return 0;
+
+
+exit_unmap:
+	iounmap(priv->sid_base);
+exit_free:
+	devm_kfree(dev, priv);
+exit:
+	return ret;
+}
+
+static struct platform_driver sid_driver = {
+	.probe = sid_probe,
+	.remove = sid_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = sid_of_match,
+	},
+};
+module_platform_driver(sid_driver);
+
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
-- 
1.8.1.5

^ permalink raw reply related	[flat|nested] 142+ messages in thread

end of thread, other threads:[~2013-08-27 15:42 UTC | newest]

Thread overview: 142+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-17 20:59 [PATCH 0/2] v4 Driver for Allwinner sunxi Security ID Oliver Schinagl
2013-06-17 20:59 ` Oliver Schinagl
2013-06-17 20:59 ` [PATCH 1/2] Initial support for Allwinner's Security ID fuses Oliver Schinagl
2013-06-17 20:59   ` Oliver Schinagl
2013-06-17 21:06   ` Tomasz Figa
2013-06-17 21:06     ` Tomasz Figa
2013-06-17 22:58   ` Greg KH
2013-06-17 22:58     ` Greg KH
2013-06-17 23:23     ` [linux-sunxi] " Henrik Nordström
2013-06-17 23:23       ` Henrik Nordström
2013-06-24  9:29     ` Maxime Ripard
2013-06-24  9:29       ` Maxime Ripard
2013-06-24 16:04       ` Greg KH
2013-06-24 16:04         ` Greg KH
2013-06-24 17:11         ` Oliver Schinagl
2013-06-24 17:11           ` Oliver Schinagl
2013-06-24 18:15           ` Greg KH
2013-06-24 18:15             ` Greg KH
2013-06-24 21:21             ` Oliver Schinagl
2013-06-24 21:21               ` Oliver Schinagl
2013-06-24 21:46               ` Greg KH
2013-06-24 21:46                 ` Greg KH
2013-06-26  8:32                 ` Oliver Schinagl
2013-06-26  8:32                   ` Oliver Schinagl
2013-06-26 17:51                   ` Greg KH
2013-06-26 17:51                     ` Greg KH
2013-07-05  7:24                     ` Oliver Schinagl
2013-07-05  7:24                       ` Oliver Schinagl
2013-07-06 19:36                       ` Greg KH
2013-07-06 19:36                         ` Greg KH
2013-07-07  0:17                         ` Greg KH
2013-07-07  0:17                           ` Greg KH
2013-07-15 21:16                         ` [linux-sunxi] " Oliver Schinagl
2013-07-15 21:16                           ` Oliver Schinagl
2013-07-16  6:41                           ` Greg KH
2013-07-16  6:41                             ` Greg KH
2013-07-16 21:02                             ` Oliver Schinagl
2013-07-16 21:02                               ` Oliver Schinagl
2013-07-17  4:20                               ` Greg KH
2013-07-17  4:20                                 ` Greg KH
2013-07-17 11:46                             ` Maxime Ripard
2013-07-17 11:46                               ` Maxime Ripard
2013-07-17 16:17                               ` Greg KH
2013-07-17 16:17                                 ` Greg KH
2013-07-19  9:42                                 ` Maxime Ripard
2013-07-19  9:42                                   ` Maxime Ripard
2013-07-19 23:49                                   ` Greg KH
2013-07-19 23:49                                     ` Greg KH
2013-07-30 13:22                                     ` Oliver Schinagl
2013-07-30 13:22                                       ` Oliver Schinagl
2013-07-30 14:20                                       ` Greg KH
2013-07-30 14:20                                         ` Greg KH
2013-07-30 17:39                                         ` Oliver Schinagl
2013-07-30 17:39                                           ` Oliver Schinagl
2013-06-26  9:10                 ` Russell King - ARM Linux
2013-06-26  9:10                   ` Russell King - ARM Linux
2013-06-26 17:51                   ` Greg KH
2013-06-26 17:51                     ` Greg KH
2013-06-24 21:04         ` Maxime Ripard
2013-06-24 21:04           ` Maxime Ripard
2013-06-26  9:22         ` Geert Uytterhoeven
2013-06-26  9:22           ` Geert Uytterhoeven
2013-06-26  9:22           ` Geert Uytterhoeven
2013-06-26 17:49           ` Greg KH
2013-06-26 17:49             ` Greg KH
2013-06-26 17:49             ` Greg KH
2013-06-18  5:41   ` Andy Shevchenko
2013-06-18  5:41     ` Andy Shevchenko
  -- strict thread matches above, loose matches on Subject: below --
2013-08-27 14:13 [PATCHv5 0/2] Driver for Allwinner sunxi Security ID oliver+list
2013-08-27 14:13 ` [PATCH 1/2] Initial support for Allwinner's Security ID fuses oliver+list
2013-08-27 14:13   ` oliver+list at schinagl.nl
2013-08-27 15:42   ` Maxime Ripard
2013-08-27 15:42     ` Maxime Ripard
2013-06-14 23:16 [PATCH 0/2] v3 Driver for Allwinner sunxi Security ID Oliver Schinagl
2013-06-14 23:16 ` [PATCH 1/2] Initial support for Allwinner's Security ID fuses Oliver Schinagl
2013-06-14 23:16   ` Oliver Schinagl
2013-06-15  2:14   ` Andy Shevchenko
2013-06-15  2:14     ` Andy Shevchenko
2013-06-15  9:34     ` Oliver Schinagl
2013-06-15  9:34       ` Oliver Schinagl
2013-06-15 10:28   ` Tomasz Figa
2013-06-15 10:28     ` Tomasz Figa
2013-06-17 10:36     ` Oliver Schinagl
2013-06-17 10:36       ` Oliver Schinagl
2013-06-17 11:25       ` Russell King - ARM Linux
2013-06-17 11:25         ` Russell King - ARM Linux
2013-06-17 11:32         ` Oliver Schinagl
2013-06-17 11:32           ` Oliver Schinagl
2013-06-17 11:51       ` Maxime Ripard
2013-06-17 11:51         ` Maxime Ripard
2013-06-17 12:04         ` Oliver Schinagl
2013-06-17 12:04           ` Oliver Schinagl
2013-06-17 12:51       ` Tomasz Figa
2013-06-17 12:51         ` Tomasz Figa
2013-06-17 13:10         ` Oliver Schinagl
2013-06-17 13:10           ` Oliver Schinagl
2013-06-17 13:23           ` Tomasz Figa
2013-06-17 13:23             ` Tomasz Figa
2013-06-17 13:47             ` Oliver Schinagl
2013-06-17 13:47               ` Oliver Schinagl
2013-06-02 14:58 [PATCH 0/2] v2 Driver for Allwinner sunxi Security ID Oliver Schinagl
2013-06-02 14:58 ` [PATCH 1/2] Initial support for Allwinner's Security ID fuses Oliver Schinagl
2013-06-02 14:58   ` Oliver Schinagl
2013-06-02 15:09   ` Russell King - ARM Linux
2013-06-02 15:09     ` Russell King - ARM Linux
2013-06-02 15:21     ` Oliver Schinagl
2013-06-02 15:21       ` Oliver Schinagl
2013-06-06 19:16   ` Andy Shevchenko
2013-06-06 19:16     ` Andy Shevchenko
2013-06-10 21:43     ` Oliver Schinagl
2013-06-10 21:43       ` Oliver Schinagl
2013-06-11 10:51       ` Andy Shevchenko
2013-06-11 10:51         ` Andy Shevchenko
2013-05-17 13:35 [PATCH 0/2] Driver for Allwinner sunxi Security ID Oliver Schinagl
2013-05-17 13:35 ` [PATCH 1/2] Initial support for Allwinner's Security ID fuses Oliver Schinagl
2013-05-17 13:35   ` Oliver Schinagl
2013-05-17 13:45   ` Arnd Bergmann
2013-05-17 13:45     ` Arnd Bergmann
2013-05-17 18:54     ` Oliver Schinagl
2013-05-17 18:54       ` Oliver Schinagl
2013-05-17 21:18   ` Maxime Ripard
2013-05-17 21:18     ` Maxime Ripard
2013-05-18 17:19     ` Oliver Schinagl
2013-05-18 17:19       ` Oliver Schinagl
2013-05-19 15:22       ` Maxime Ripard
2013-05-19 15:22         ` Maxime Ripard
2013-05-24 21:50       ` Oliver Schinagl
2013-05-24 21:50         ` Oliver Schinagl
2013-05-25 12:22         ` Maxime Ripard
2013-05-25 12:22           ` Maxime Ripard
2013-05-25 19:25           ` Oliver Schinagl
2013-05-25 19:25             ` Oliver Schinagl
2013-05-26  9:35             ` Maxime Ripard
2013-05-26  9:35               ` Maxime Ripard
2013-05-23  7:56   ` Linus Walleij
2013-05-23  7:56     ` Linus Walleij
2013-05-23  8:10     ` Oliver Schinagl
2013-05-23  8:10       ` Oliver Schinagl
2013-05-23  8:20       ` Linus Walleij
2013-05-23  8:20         ` Linus Walleij
2013-05-23 14:58       ` Maxime Ripard
2013-05-23 14:58         ` Maxime Ripard
2013-05-23 15:05         ` Oliver Schinagl
2013-05-23 15:05           ` Oliver Schinagl
2013-05-23 15:27           ` Maxime Ripard
2013-05-23 15:27             ` Maxime Ripard

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.