Linux userland API discussions
 help / color / mirror / Atom feed
* [PATCH v2 07/18] drivers: reset: Add STM32 reset driver
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
	Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Arnd Bergmann, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

The STM32 MCUs family IP can be reset by accessing some shared registers.

The specificity is that some reset lines are used by the timers.
At timer initialization time, the timer has to be reset, that's why
we cannot use a regular driver.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/reset/Makefile                   |   1 +
 drivers/reset/reset-stm32.c              | 124 +++++++++++++++++++++++++++++++
 include/dt-bindings/reset/st,stm32f429.h |  85 +++++++++++++++++++++
 3 files changed, 210 insertions(+)
 create mode 100644 drivers/reset/reset-stm32.c
 create mode 100644 include/dt-bindings/reset/st,stm32f429.h

diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 157d421..aed12d1 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,5 +1,6 @@
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
 obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
 obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
+obj-$(CONFIG_ARCH_STM32) += reset-stm32.o
 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
 obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/reset-stm32.c b/drivers/reset/reset-stm32.c
new file mode 100644
index 0000000..7a96677
--- /dev/null
+++ b/drivers/reset/reset-stm32.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Heavily based on sunxi driver from Maxime Ripard.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+struct stm32_reset_data {
+	spinlock_t			lock;
+	void __iomem			*membase;
+	struct reset_controller_dev	rcdev;
+};
+
+static int stm32_reset_assert(struct reset_controller_dev *rcdev,
+			      unsigned long id)
+{
+	struct stm32_reset_data *data = container_of(rcdev,
+						     struct stm32_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl_relaxed(data->membase + (bank * 4));
+	writel_relaxed(reg | BIT(offset), data->membase + (bank * 4));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
+				unsigned long id)
+{
+	struct stm32_reset_data *data = container_of(rcdev,
+						     struct stm32_reset_data,
+						     rcdev);
+	int bank = id / BITS_PER_LONG;
+	int offset = id % BITS_PER_LONG;
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&data->lock, flags);
+
+	reg = readl_relaxed(data->membase + (bank * 4));
+	writel_relaxed(reg & ~BIT(offset), data->membase + (bank * 4));
+
+	spin_unlock_irqrestore(&data->lock, flags);
+
+	return 0;
+}
+
+static struct reset_control_ops stm32_reset_ops = {
+	.assert		= stm32_reset_assert,
+	.deassert	= stm32_reset_deassert,
+};
+
+static void stm32_reset_init(struct device_node *np)
+{
+	struct stm32_reset_data *data;
+	struct resource res;
+	resource_size_t size;
+	int err;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return;
+
+	err = of_address_to_resource(np, 0, &res);
+	if (err)
+		goto err_alloc;
+
+	size = resource_size(&res);
+	if (!request_mem_region(res.start, size, np->name)) {
+		err = -EINVAL;
+		goto err_alloc;
+	}
+
+	data->membase = ioremap(res.start, size);
+	if (!data->membase) {
+		err = -ENOMEM;
+		goto err_alloc;
+	}
+
+	spin_lock_init(&data->lock);
+
+	data->rcdev.owner = THIS_MODULE;
+	data->rcdev.nr_resets = size * 8;
+	data->rcdev.ops = &stm32_reset_ops;
+	data->rcdev.of_node = np;
+
+	err = reset_controller_register(&data->rcdev);
+	if (err)
+		goto err_iomap;
+
+	pr_info("%s: %d reset lines registered\n", np->full_name,
+			data->rcdev.nr_resets);
+	return;
+
+err_iomap:
+	iounmap(data->membase);
+err_alloc:
+	kfree(data);
+	pr_err("%s: Reset ctrl registration failed (%d).\n",
+			np->full_name, err);
+}
+
+RESET_CONTROLLER_OF_DECLARE(stm32, "st,stm32-reset", stm32_reset_init);
+
diff --git a/include/dt-bindings/reset/st,stm32f429.h b/include/dt-bindings/reset/st,stm32f429.h
new file mode 100644
index 0000000..04f2ba8
--- /dev/null
+++ b/include/dt-bindings/reset/st,stm32f429.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef _DT_BINDINGS_RESET_STM32F429_H
+#define _DT_BINDINGS_RESET_STM32F429_H
+
+/* AHB1 */
+#define GPIOA_RESET	0
+#define GPIOB_RESET	1
+#define GPIOC_RESET	2
+#define GPIOD_RESET	3
+#define GPIOE_RESET	4
+#define GPIOF_RESET	5
+#define GPIOG_RESET	6
+#define GPIOH_RESET	7
+#define GPIOI_RESET	8
+#define GPIOJ_RESET	9
+#define GPIOK_RESET	10
+#define CRC_RESET	12
+#define DMA1_RESET	21
+#define DMA2_RESET	22
+#define DMA2D_RESET	23
+#define ETHMAC_RESET	25
+#define OTGHS_RESET	29
+
+/* AHB2 */
+#define DCMI_RESET	32
+#define CRYP_RESET	36
+#define HASH_RESET	37
+#define RNG_RESET	38
+#define OTGFS_RESET	39
+
+/* AHB3 */
+#define FMC_RESET	64
+
+/* APB1 */
+#define TIM2_RESET	128
+#define TIM3_RESET	129
+#define TIM4_RESET	130
+#define TIM5_RESET	131
+#define TIM6_RESET	132
+#define TIM7_RESET	133
+#define TIM12_RESET	134
+#define TIM13_RESET	135
+#define TIM14_RESET	136
+#define WWDG_RESET	139
+#define SPI2_RESET	142
+#define SPI3_RESET	143
+#define UART2_RESET	145
+#define UART3_RESET	146
+#define UART4_RESET	147
+#define UART5_RESET	148
+#define I2C1_RESET	149
+#define I2C2_RESET	150
+#define I2C3_RESET	151
+#define CAN1_RESET	153
+#define CAN2_RESET	154
+#define PWR_RESET	156
+#define DAC_RESET	157
+#define UART7_RESET	158
+#define UART8_RESET	159
+
+/* APB2 */
+#define TIM1_RESET	160
+#define TIM8_RESET	161
+#define USART1_RESET	164
+#define USART6_RESET	165
+#define ADC_RESET	168
+#define SDIO_RESET	171
+#define SPI1_RESET	172
+#define SPI4_RESET	173
+#define SYSCFG_RESET	174
+#define TIM9_RESET	176
+#define TIM10_RESET	177
+#define TIM11_RESET	178
+#define SPI5_RESET	180
+#define SPI6_RESET	181
+#define SAI1_RESET	182
+#define LTDC_RESET	186
+
+#endif /* _DT_BINDINGS_RESET_STM32F429_H */
+
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 06/18] dt-bindings: Document the STM32 reset bindings
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
	Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Arnd Bergmann, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

This adds documentation of device tree bindings for the
STM32 reset controller.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 .../devicetree/bindings/reset/st,stm32-reset.txt   | 36 ++++++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-reset.txt

diff --git a/Documentation/devicetree/bindings/reset/st,stm32-reset.txt b/Documentation/devicetree/bindings/reset/st,stm32-reset.txt
new file mode 100644
index 0000000..5982528
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/st,stm32-reset.txt
@@ -0,0 +1,36 @@
+STMicroelectronics STM32 Peripheral Reset Controller
+====================================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+- compatible: Should be "st,stm32-reset"
+- reg: should be register base and length as documented in the
+  datasheet
+- #reset-cells: 1, see below
+
+example:
+
+reset_ahb1: reset@40023810 {
+	#reset-cells = <1>;
+	compatible = "st,stm32-reset";
+	reg = <0x40023810 0x4>;
+};
+
+Specifying softreset control of devices
+=======================================
+
+Device nodes should specify the reset channel required in their "resets"
+property, containing a phandle to the reset device node and an index specifying
+which channel to use, as described in reset.txt
+
+example:
+
+	timer2 {
+		resets			= <&resets TIM2_RESET>;
+	};
+
+Macro definitions for the supported reset channels can be found in:
+
+include/dt-bindings/reset/st,stm32f429.h
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 05/18] reset: Add reset_controller_of_init() function
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
	Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Arnd Bergmann, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Some platforms need to initialize the reset controller before the timers.

This patch introduces a reset_controller_of_init() function that can be
called before the timers intialization.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/reset/core.c              | 27 +++++++++++++++++++++++++++
 include/asm-generic/vmlinux.lds.h |  4 +++-
 include/linux/reset-controller.h  |  6 ++++++
 3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 7955e00..7eef63e 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -86,6 +86,33 @@ void reset_controller_unregister(struct reset_controller_dev *rcdev)
 }
 EXPORT_SYMBOL_GPL(reset_controller_unregister);
 
+extern struct of_device_id __reset_ctrl_of_table[];
+
+static const struct of_device_id __reset_ctrl_of_table_sentinel
+	__used __section(__reset_ctrl_of_table_end);
+
+/**
+ * reset_controller_of_init - scan and init reset controllers from the DT
+ *
+ * This function scas the device tree for matching reset controllers. It is
+ * used on machines that need reset controls at early stage. To use it, the
+ * controller driver has to be registred with RESET_CONTROLLER_OF_DECLARE().
+ */
+void __init reset_controller_of_init(void)
+{
+	struct device_node *np;
+	const struct of_device_id *match;
+	of_init_fn_1 init_func;
+
+	for_each_matching_node_and_match(np, __reset_ctrl_of_table, &match) {
+		if (!of_device_is_available(np))
+			continue;
+
+		init_func = match->data;
+		init_func(np);
+	}
+}
+
 /**
  * reset_control_reset - reset the controlled device
  * @rstc: reset controller
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index bee5d68..1f96365 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -168,6 +168,7 @@
 #define RESERVEDMEM_OF_TABLES()	OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem)
 #define CPU_METHOD_OF_TABLES()	OF_TABLE(CONFIG_SMP, cpu_method)
 #define EARLYCON_OF_TABLES()	OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon)
+#define RESET_CTRL_OF_TABLES()	OF_TABLE(CONFIG_RESET_CONTROLLER, reset_ctrl)
 
 #define KERNEL_DTB()							\
 	STRUCT_ALIGN();							\
@@ -502,7 +503,8 @@
 	CPU_METHOD_OF_TABLES()						\
 	KERNEL_DTB()							\
 	IRQCHIP_OF_MATCH_TABLE()					\
-	EARLYCON_OF_TABLES()
+	EARLYCON_OF_TABLES()						\
+	RESET_CTRL_OF_TABLES()
 
 #define INIT_TEXT							\
 	*(.init.text)							\
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index ce6b962..f8a030a 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -51,4 +51,10 @@ struct reset_controller_dev {
 int reset_controller_register(struct reset_controller_dev *rcdev);
 void reset_controller_unregister(struct reset_controller_dev *rcdev);
 
+
+#define RESET_CONTROLLER_OF_DECLARE(name, compat, fn) \
+	OF_DECLARE_1(reset_ctrl, name, compat, fn)
+
+void reset_controller_of_init(void);
+
 #endif
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 04/18] clocksource: Add ARM System timer driver
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
	Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Arnd Bergmann, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

This patch adds clocksource support for ARMv7-M's System timer,
also known as SysTick.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/clocksource/Kconfig          |  7 ++++
 drivers/clocksource/Makefile         |  1 +
 drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
 3 files changed, 86 insertions(+)
 create mode 100644 drivers/clocksource/armv7m_systick.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index fc01ec2..fb6011e 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -124,6 +124,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
 	help
 	 Use ARM global timer clock source as sched_clock
 
+config ARMV7M_SYSTICK
+	bool
+	select CLKSRC_OF if OF
+	select CLKSRC_MMIO
+	help
+	  This options enables support for the ARMv7M system timer unit
+
 config ATMEL_PIT
 	select CLKSRC_OF if OF
 	def_bool SOC_AT91SAM9 || SOC_SAMA5
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 94d90b2..eeea736 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_MTK_TIMER)		+= mtk_timer.o
 
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
 obj-$(CONFIG_ARM_GLOBAL_TIMER)		+= arm_global_timer.o
+obj-$(CONFIG_ARMV7M_SYSTICK)		+= armv7m_systick.o
 obj-$(CONFIG_CLKSRC_METAG_GENERIC)	+= metag_generic.o
 obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST)	+= dummy_timer.o
 obj-$(CONFIG_ARCH_KEYSTONE)		+= timer-keystone.o
diff --git a/drivers/clocksource/armv7m_systick.c b/drivers/clocksource/armv7m_systick.c
new file mode 100644
index 0000000..23d8249
--- /dev/null
+++ b/drivers/clocksource/armv7m_systick.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) Maxime Coquelin 2015
+ * Author:  Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/bitops.h>
+
+#define SYST_CSR	0x00
+#define SYST_RVR	0x04
+#define SYST_CVR	0x08
+#define SYST_CALIB	0x0c
+
+#define SYST_CSR_ENABLE BIT(0)
+
+#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
+
+static void __init system_timer_of_register(struct device_node *np)
+{
+	struct clk *clk;
+	void __iomem *base;
+	u32 rate = 0;
+	int ret;
+
+	base = of_iomap(np, 0);
+	if (!base) {
+		pr_warn("system-timer: invalid base address\n");
+		return;
+	}
+
+	clk = of_clk_get(np, 0);
+	if (!IS_ERR(clk)) {
+		ret = clk_prepare_enable(clk);
+		if (ret) {
+			clk_put(clk);
+			goto out_unmap;
+		}
+
+		rate = clk_get_rate(clk);
+	}
+
+	/* If no clock found, try to get clock-frequency property */
+	if (!rate) {
+		ret = of_property_read_u32(np, "clock-frequency", &rate);
+		if (ret)
+			goto out_unmap;
+	}
+
+	writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
+	writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
+
+	ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
+			200, 24, clocksource_mmio_readl_down);
+	if (ret) {
+		pr_err("failed to init clocksource (%d)\n", ret);
+		goto out_clk_disable;
+	}
+
+	pr_info("ARM System timer initialized as clocksource\n");
+
+	return;
+
+out_clk_disable:
+	if (!IS_ERR(clk))
+		clk_disable_unprepare(clk);
+out_unmap:
+	iounmap(base);
+	WARN(ret, "ARM System timer register failed (%d)\n", ret);
+}
+
+CLOCKSOURCE_OF_DECLARE(arm_systick, "arm,armv7m-systick",
+			system_timer_of_register);
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 03/18] dt-bindings: Document the ARM System timer bindings
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
	Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Arnd Bergmann, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

This adds documentation of device tree bindings for the
ARM System timer.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 .../devicetree/bindings/arm/armv7m_systick.txt     | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt

diff --git a/Documentation/devicetree/bindings/arm/armv7m_systick.txt b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
new file mode 100644
index 0000000..7cf4a24
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/armv7m_systick.txt
@@ -0,0 +1,26 @@
+* ARMv7M System Timer
+
+ARMv7-M includes a system timer, known as SysTick. Current driver only
+implements the clocksource feature.
+
+Required properties:
+- compatible	  : Should be "arm,armv7m-systick"
+- reg		  : The address range of the timer
+
+Required clocking property, have to be one of:
+- clocks	  : The input clock of the timer
+- clock-frequency : The rate in HZ in input of the ARM SysTick
+
+Examples:
+
+systick: timer@e000e010 {
+	compatible = "arm,armv7m-systick";
+	reg = <0xe000e010 0x10>;
+	clocks = <&clk_systick>;
+};
+
+systick: timer@e000e010 {
+	compatible = "arm,armv7m-systick";
+	reg = <0xe000e010 0x10>;
+	clock-frequency = <90000000>;
+};
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 02/18] ARM: ARMv7M: Enlarge vector table to 256 entries
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
	Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Arnd Bergmann, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

>From Cortex-M reference manuals, the nvic supports up to 240 interrupts.
So the number of entries in vectors table is up to 256.

This patch adds a new config flag to specify the number of external interrupts.
Some ifdeferies are added in order to respect the natural alignment without
wasting too much space on smaller systems.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 arch/arm/kernel/entry-v7m.S | 13 +++++++++----
 arch/arm/mm/Kconfig         | 15 +++++++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index 8944f49..68cde36 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -117,9 +117,14 @@ ENTRY(__switch_to)
 ENDPROC(__switch_to)
 
 	.data
-	.align	8
+#if CONFIG_CPUV7M_NUM_IRQ <= 112
+	.align	9
+#else
+	.align	10
+#endif
+
 /*
- * Vector table (64 words => 256 bytes natural alignment)
+ * Vector table (Natural alignment need to be ensured)
  */
 ENTRY(vector_table)
 	.long	0			@ 0 - Reset stack pointer
@@ -138,6 +143,6 @@ ENTRY(vector_table)
 	.long	__invalid_entry		@ 13 - Reserved
 	.long	__pendsv_entry		@ 14 - PendSV
 	.long	__invalid_entry		@ 15 - SysTick
-	.rept	64 - 16
-	.long	__irq_entry		@ 16..64 - External Interrupts
+	.rept	CONFIG_CPUV7M_NUM_IRQ
+	.long	__irq_entry		@ External Interrupts
 	.endr
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index c43c714..27eb835 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -604,6 +604,21 @@ config CPU_USE_DOMAINS
 	  This option enables or disables the use of domain switching
 	  via the set_fs() function.
 
+config CPUV7M_NUM_IRQ
+	int "Number of external interrupts connected to the NVIC"
+	depends on CPU_V7M
+	default 90 if ARCH_STM32
+	default 38 if ARCH_EFM32
+	default 240
+	help
+	  This option indicates the number of interrupts connected to the NVIC.
+	  The value can be larger than the real number of interrupts supported
+	  by the system, but must not be lower.
+	  The default value is 240, corresponding to the maximum number of
+	  interrupts supported by the NVIC on Cortex-M family.
+
+	  If unsure, keep default value.
+
 #
 # CPU supports 36-bit I/O
 #
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 01/18] scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP Kernel
From: Maxime Coquelin @ 2015-02-20 18:01 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
	Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Arnd Bergmann, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will
In-Reply-To: <1424455277-29983-1-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

When Kernel is executed in place from ROM, the symbol addresses can be
lower than the page offset.

Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 scripts/link-vmlinux.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 86a4fe7..b055d9d 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -82,7 +82,7 @@ kallsyms()
 		kallsymopt="${kallsymopt} --all-symbols"
 	fi
 
-	if [ -n "${CONFIG_ARM}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
+	if [ -n "${CONFIG_ARM}" ] && [ -z "${CONFIG_XIP_KERNEL}" ] && [ -n "${CONFIG_PAGE_OFFSET}" ]; then
 		kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
 	fi
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2 00/18] Add support to STMicroelectronics STM32 family
From: Maxime Coquelin @ 2015-02-20 18:00 UTC (permalink / raw)
  To: u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ, afaerber-l3A5Bk7waGM,
	geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
	Jonathan Corbet, Maxime Coquelin, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
	Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
	Arnd Bergmann, Andrew Morton, David S. Miller,
	Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
	Will

Thanks for the first round of reviews.
Most of the comments made have been taken into account (see below for details),
except that I failed to find an easy/clean way to move vector_table location in
order to limit the waste of memory.
If you have any idea/example to do that, I will be pleased to add it in next
version of the series.

STM32 MCUs are Cortex-M CPU, used in various applications (consumer
electronics, industrial applications, hobbyists...).
Datasheets, user and programming manuals are publicly available on
STMicroelectronics website.

With this series applied, the STM32F419 Discovery can boot succesfully.

Changes since v1:
-----------------
 - Move bindings documentation in their own patches (Andreas)
 - Rename ARM System timer to armv7m-systick (Rob)
 - Add clock-frequency property handling in armv7m-systick (Rob)
 - Re-factor the reset controllers into a single controller (Philipp)
 - Add kerneldoc to reset_controller_of_init (Philipp)
 - Add named constants in include/dt-bindings/reset/ (Philipp)
 - Make pinctrl driver to depend on ARCH_STM32 or COMPILE_TEST (Geert)
 - Introduce CPUV7M_NUM_IRQ config flag to indicate the number of interrupts
supported by the MCU, in order to limit memory waste in vectors' table (Uwe)


Maxime Coquelin (18):
  scripts: link-vmlinux: Don't pass page offset to kallsyms if XIP
    Kernel
  ARM: ARMv7M: Enlarge vector table to 256 entries
  dt-bindings: Document the ARM System timer bindings
  clocksource: Add ARM System timer driver
  reset: Add reset_controller_of_init() function
  dt-bindings: Document the STM32 reset bindings
  drivers: reset: Add STM32 reset driver
  dt-bindings: Document the STM32 timer bindings
  clockevent: Add STM32 Timer driver
  dt-bindings: Document the STM32 pin controller
  pinctrl: Add pinctrl driver for STM32 MCUs
  dt-bindings: Document the STM32 USART bindings
  serial: stm32-usart: Add STM32 USART Driver
  ARM: Add STM32 family machine
  ARM: dts: Add ARM System timer as clockevent in armv7m
  ARM: dts: Introduce STM32F429 MCU
  ARM: configs: Add STM32 defconfig
  MAINTAINERS: Add entry for STM32 MCUs

 Documentation/arm/stm32/overview.txt               |  32 +
 Documentation/arm/stm32/stm32f429-overview.txt     |  22 +
 .../devicetree/bindings/arm/armv7m_systick.txt     |  26 +
 .../devicetree/bindings/pinctrl/pinctrl-stm32.txt  |  99 +++
 .../devicetree/bindings/reset/st,stm32-reset.txt   |  36 +
 .../devicetree/bindings/serial/st,stm32-usart.txt  |  18 +
 .../devicetree/bindings/timer/st,stm32-timer.txt   |  19 +
 MAINTAINERS                                        |   7 +
 arch/arm/Kconfig                                   |  22 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/armv7-m.dtsi                     |   7 +
 arch/arm/boot/dts/stm32f429-disco.dts              |  41 ++
 arch/arm/boot/dts/stm32f429.dtsi                   | 396 +++++++++++
 arch/arm/configs/stm32_defconfig                   |  72 ++
 arch/arm/kernel/entry-v7m.S                        |  13 +-
 arch/arm/mach-stm32/Makefile                       |   1 +
 arch/arm/mach-stm32/Makefile.boot                  |   0
 arch/arm/mach-stm32/board-dt.c                     |  31 +
 arch/arm/mm/Kconfig                                |  15 +
 drivers/clocksource/Kconfig                        |  16 +
 drivers/clocksource/Makefile                       |   2 +
 drivers/clocksource/armv7m_systick.c               |  78 +++
 drivers/clocksource/timer-stm32.c                  | 187 +++++
 drivers/pinctrl/Kconfig                            |  10 +
 drivers/pinctrl/Makefile                           |   1 +
 drivers/pinctrl/pinctrl-stm32.c                    | 779 +++++++++++++++++++++
 drivers/reset/Makefile                             |   1 +
 drivers/reset/core.c                               |  27 +
 drivers/reset/reset-stm32.c                        | 124 ++++
 drivers/tty/serial/Kconfig                         |  17 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/stm32-usart.c                   | 695 ++++++++++++++++++
 include/asm-generic/vmlinux.lds.h                  |   4 +-
 include/dt-bindings/pinctrl/pinctrl-stm32.h        |  43 ++
 include/dt-bindings/reset/st,stm32f429.h           |  85 +++
 include/linux/reset-controller.h                   |   6 +
 include/uapi/linux/serial_core.h                   |   3 +
 scripts/link-vmlinux.sh                            |   2 +-
 39 files changed, 2934 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/arm/stm32/overview.txt
 create mode 100644 Documentation/arm/stm32/stm32f429-overview.txt
 create mode 100644 Documentation/devicetree/bindings/arm/armv7m_systick.txt
 create mode 100644 Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
 create mode 100644 Documentation/devicetree/bindings/reset/st,stm32-reset.txt
 create mode 100644 Documentation/devicetree/bindings/serial/st,stm32-usart.txt
 create mode 100644 Documentation/devicetree/bindings/timer/st,stm32-timer.txt
 create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
 create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
 create mode 100644 arch/arm/configs/stm32_defconfig
 create mode 100644 arch/arm/mach-stm32/Makefile
 create mode 100644 arch/arm/mach-stm32/Makefile.boot
 create mode 100644 arch/arm/mach-stm32/board-dt.c
 create mode 100644 drivers/clocksource/armv7m_systick.c
 create mode 100644 drivers/clocksource/timer-stm32.c
 create mode 100644 drivers/pinctrl/pinctrl-stm32.c
 create mode 100644 drivers/reset/reset-stm32.c
 create mode 100644 drivers/tty/serial/stm32-usart.c
 create mode 100644 include/dt-bindings/pinctrl/pinctrl-stm32.h
 create mode 100644 include/dt-bindings/reset/st,stm32f429.h

-- 
1.9.1

^ permalink raw reply

* Re: [RFC PATCH 3/3] eeprom: qfprom: Add Qualcomm QFPROM support.
From: Russell King - ARM Linux @ 2015-02-20 17:48 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel, devicetree, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api, broonie, Stephen Boyd,
	linux-kernel, Rob Herring, Kumar Gala, Maxime Ripard
In-Reply-To: <1424365731-26768-1-git-send-email-srinivas.kandagatla@linaro.org>

On Thu, Feb 19, 2015 at 05:08:51PM +0000, Srinivas Kandagatla wrote:
> +static int qfprom_remove(struct platform_device *pdev)
> +{
> +	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
> +
> +	return eeprom_unregister(eeprom);

Same problem...

> +static int qfprom_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	void __iomem *base;
> +	struct device *dev = &pdev->dev;
> +	struct eeprom_device *eeprom;
> +	int rval;
> +
> +	eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
> +	if (!eeprom)
> +		return -ENOMEM;
...
> +	rval = eeprom_register(eeprom);

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply

* Re: [RFC PATCH 2/3] eeprom: sunxi: Move the SID driver to the eeprom framework
From: Russell King - ARM Linux @ 2015-02-20 17:47 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api-u79uwXL29TY76Z2rM5mHXA,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, Stephen Boyd,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Kumar Gala,
	Maxime Ripard
In-Reply-To: <1424365720-26725-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

On Thu, Feb 19, 2015 at 05:08:40PM +0000, Srinivas Kandagatla wrote:
> +static int sunxi_sid_probe(struct platform_device *pdev)
> +{
> +	const struct of_device_id *device;
> +	struct eeprom_sid *sid;
> +	struct resource *res;
> +	struct eeprom_device *eeprom;
> +	struct device *dev = &pdev->dev;
> +	int rval;
> +
> +	sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
> +	if (!sid)
> +		return -ENOMEM;
> +
> +	eeprom = &sid->eeprom;
...
> +	rval = eeprom_register(eeprom);
> +	if (rval)
> +		return rval;
...
> +static int sunxi_sid_remove(struct platform_device *pdev)
> +{
> +	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
> +
> +	return eeprom_unregister(eeprom);

As pointed out in the previous patch, this is unsafe as the eeprom
structure contains a struct device.

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Russell King - ARM Linux @ 2015-02-20 17:46 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api-u79uwXL29TY76Z2rM5mHXA,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, Stephen Boyd,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Kumar Gala,
	Maxime Ripard
In-Reply-To: <1424365708-26681-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

On Thu, Feb 19, 2015 at 05:08:28PM +0000, Srinivas Kandagatla wrote:
> +static struct class eeprom_class = {
> +	.name		= "eeprom",
> +	.dev_groups	= eeprom_dev_groups,
> +};
> +
> +int eeprom_register(struct eeprom_device *eeprom)
> +{
> +	int rval;
> +
> +	if (!eeprom->regmap || !eeprom->size) {
> +		dev_err(eeprom->dev, "Regmap not found\n");
> +		return -EINVAL;
> +	}
> +
> +	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
> +	if (eeprom->id < 0)
> +		return eeprom->id;
> +
> +	eeprom->edev.class = &eeprom_class;
> +	eeprom->edev.parent = eeprom->dev;
> +	eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
> +	dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
> +
> +	device_initialize(&eeprom->edev);
> +
> +	dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
> +		dev_name(&eeprom->edev));
> +
> +	rval = device_add(&eeprom->edev);
> +	if (rval)
> +		return rval;
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_add(&eeprom->list, &eeprom_list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(eeprom_register);
> +
> +int eeprom_unregister(struct eeprom_device *eeprom)
> +{
> +	device_del(&eeprom->edev);
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_del(&eeprom->list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;

There's problems with this.  "edev" is embedded into eeprom, and "edev"
is a refcounted structure - it has a lifetime, and the lifetime of
eeprom is thus determined by edev.

What this means is that calling eeprom_unregister() and then freeing
the eeprom structure is a potentially unsafe operation - the memory
backing edev must only be freed when the release method for the
struct device has been called.

> +struct eeprom_device {
> +	struct regmap		*regmap;
> +	int			stride;
> +	size_t			size;
> +	struct device		*dev;

Failing to understand and address the driver model life time issues is
a major blocker for this patch.  Sorry.

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Rob Herring @ 2015-02-20 17:21 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala,
	linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Stephen Boyd,
	Arnd Bergmann, Mark Brown, Greg Kroah-Hartman
In-Reply-To: <1424365708-26681-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

On Thu, Feb 19, 2015 at 11:08 AM, Srinivas Kandagatla
<srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> From: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>
> Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
> duplicate pretty much the same code to register a sysfs file, allow in-kernel
> users to access the content of the devices they were driving, etc.
>
> This was also a problem as far as other in-kernel users were involved, since
> the solutions used were pretty much different from on driver to another, there
> was a rather big abstraction leak.
>
> This introduction of this framework aims at solving this. It also introduces DT
> representation for consumer devices to go get the data they require (MAC
> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
>
> Having regmap interface to this framework would give much better
> abstraction for eeproms on different buses.
>
> Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>  drivers/Kconfig                                    |   2 +
>  drivers/Makefile                                   |   1 +
>  drivers/eeprom/Kconfig                             |  19 ++
>  drivers/eeprom/Makefile                            |   9 +
>  drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
>  include/linux/eeprom-consumer.h                    |  73 ++++++
>  include/linux/eeprom-provider.h                    |  51 ++++

Who is going to be the maintainer for this?

>  8 files changed, 493 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>  create mode 100644 drivers/eeprom/Kconfig
>  create mode 100644 drivers/eeprom/Makefile
>  create mode 100644 drivers/eeprom/core.c
>  create mode 100644 include/linux/eeprom-consumer.h
>  create mode 100644 include/linux/eeprom-provider.h
>
> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> new file mode 100644
> index 0000000..9ec1ec2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt

Please make bindings a separate patch.

> @@ -0,0 +1,48 @@
> += EEPROM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in EEPROMs.
> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on an EEPROM-like device, for the OS to be able to retrieve
> +these information and act upon it. Obviously, the OS has to know
> +about where to retrieve these data from, and where they are stored on
> +the storage device.
> +
> +This document is here to document this.
> +
> += Data providers =
> +
> +Required properties:
> +#eeprom-cells: Number of cells in an eeprom specifier; The common
> +               case is 2.

We already have eeproms in DTs, it would be nice to be able to support
them with this framework as well.

> +
> +For example:
> +
> +       at24: eeprom@42 {
> +               #eeprom-cells = <2>;
> +       };
> +
> += Data consumers =
> +
> +Required properties:
> +
> +eeproms: List of phandle and data cell specifier triplet, one triplet
> +        for each data cell the device might be interested in. The
> +        triplet consists of the phandle to the eeprom provider, then
> +        the offset in byte within that storage device, and the length
> +        in byte of the data we care about.

The problem with this is it assumes you know who the consumer is and
that it is a DT node. For example, how would you describe a serial
number?

Rob

> +
> +Optional properties:
> +
> +eeprom-names: List of data cell name strings sorted in the same order
> +             as the resets property. Consumers drivers will use
> +             eeprom-names to differentiate between multiple cells,
> +             and hence being able to know what these cells are for.
> +
> +For example:
> +
> +       device {
> +               eeproms = <&at24 14 42>;
> +               eeprom-names = "soc-rev-id";
> +       };
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index c70d6e4..d7afc82 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
>
>  source "drivers/android/Kconfig"
>
> +source "drivers/eeprom/Kconfig"
> +
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 527a6da..57eb5b0 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)           += ras/
>  obj-$(CONFIG_THUNDERBOLT)      += thunderbolt/
>  obj-$(CONFIG_CORESIGHT)                += coresight/
>  obj-$(CONFIG_ANDROID)          += android/
> +obj-$(CONFIG_EEPROM)           += eeprom/
> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
> new file mode 100644
> index 0000000..2c5452a
> --- /dev/null
> +++ b/drivers/eeprom/Kconfig
> @@ -0,0 +1,19 @@
> +menuconfig EEPROM
> +       bool "EEPROM Support"
> +       depends on OF
> +       help
> +         Support for EEPROM alike devices.
> +
> +         This framework is designed to provide a generic interface to EEPROM
> +         from both the Linux Kernel and the userspace.
> +
> +         If unsure, say no.
> +
> +if EEPROM
> +
> +config EEPROM_DEBUG
> +       bool "EEPROM debug support"
> +       help
> +         Say yes here to enable debugging support.
> +
> +endif
> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
> new file mode 100644
> index 0000000..e130079
> --- /dev/null
> +++ b/drivers/eeprom/Makefile
> @@ -0,0 +1,9 @@
> +#
> +# Makefile for eeprom drivers.
> +#
> +
> +ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
> +
> +obj-$(CONFIG_EEPROM)           += core.o
> +
> +# Devices
> diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
> new file mode 100644
> index 0000000..bc877a6
> --- /dev/null
> +++ b/drivers/eeprom/core.c
> @@ -0,0 +1,290 @@
> +/*
> + * EEPROM framework core.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/eeprom-provider.h>
> +#include <linux/eeprom-consumer.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/idr.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +
> +struct eeprom_cell {
> +       struct eeprom_device *eeprom;
> +       loff_t offset;
> +       size_t count;
> +};
> +
> +static DEFINE_MUTEX(eeprom_list_mutex);
> +static LIST_HEAD(eeprom_list);
> +static DEFINE_IDA(eeprom_ida);
> +
> +static ssize_t bin_attr_eeprom_read_write(struct kobject *kobj,
> +                                   char *buf, loff_t offset,
> +                                   size_t count, bool read)
> +{
> +       struct device *dev = container_of(kobj, struct device, kobj);
> +       struct eeprom_device *eeprom = container_of(dev, struct eeprom_device,
> +                                                   edev);
> +       int rc;
> +
> +       if (offset > eeprom->size)
> +               return 0;
> +
> +       if (offset + count > eeprom->size)
> +               count = eeprom->size - offset;
> +
> +       if (read)
> +               rc = regmap_bulk_read(eeprom->regmap, offset,
> +                                     buf, count/eeprom->stride);
> +       else
> +               rc = regmap_bulk_write(eeprom->regmap, offset,
> +                                      buf, count/eeprom->stride);
> +
> +       if (IS_ERR_VALUE(rc))
> +               return 0;
> +
> +       return count;
> +}
> +
> +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
> +                                   struct bin_attribute *attr,
> +                                   char *buf, loff_t offset, size_t count)
> +{
> +       return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
> +}
> +
> +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
> +                                    struct bin_attribute *attr,
> +                                    char *buf, loff_t offset, size_t count)
> +{
> +       return bin_attr_eeprom_read_write(kobj, buf, offset, count, false);
> +}
> +
> +static struct bin_attribute bin_attr_eeprom = {
> +       .attr   = {
> +               .name   = "eeprom",
> +               .mode   = 0660,
> +       },
> +       .read   = bin_attr_eeprom_read,
> +       .write  = bin_attr_eeprom_write,
> +};
> +
> +static struct bin_attribute *eeprom_bin_attributes[] = {
> +       &bin_attr_eeprom,
> +       NULL,
> +};
> +
> +static const struct attribute_group eeprom_bin_group = {
> +       .bin_attrs      = eeprom_bin_attributes,
> +};
> +
> +static const struct attribute_group *eeprom_dev_groups[] = {
> +       &eeprom_bin_group,
> +       NULL,
> +};
> +
> +static struct class eeprom_class = {
> +       .name           = "eeprom",
> +       .dev_groups     = eeprom_dev_groups,
> +};
> +
> +int eeprom_register(struct eeprom_device *eeprom)
> +{
> +       int rval;
> +
> +       if (!eeprom->regmap || !eeprom->size) {
> +               dev_err(eeprom->dev, "Regmap not found\n");
> +               return -EINVAL;
> +       }
> +
> +       eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
> +       if (eeprom->id < 0)
> +               return eeprom->id;
> +
> +       eeprom->edev.class = &eeprom_class;
> +       eeprom->edev.parent = eeprom->dev;
> +       eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
> +       dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
> +
> +       device_initialize(&eeprom->edev);
> +
> +       dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
> +               dev_name(&eeprom->edev));
> +
> +       rval = device_add(&eeprom->edev);
> +       if (rval)
> +               return rval;
> +
> +       mutex_lock(&eeprom_list_mutex);
> +       list_add(&eeprom->list, &eeprom_list);
> +       mutex_unlock(&eeprom_list_mutex);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(eeprom_register);
> +
> +int eeprom_unregister(struct eeprom_device *eeprom)
> +{
> +       device_del(&eeprom->edev);
> +
> +       mutex_lock(&eeprom_list_mutex);
> +       list_del(&eeprom->list);
> +       mutex_unlock(&eeprom_list_mutex);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(eeprom_unregister);
> +
> +static struct eeprom_cell *__eeprom_cell_get(struct device_node *node,
> +                                            int index)
> +{
> +       struct of_phandle_args args;
> +       struct eeprom_cell *cell;
> +       struct eeprom_device *e, *eeprom = NULL;
> +       int ret;
> +
> +       ret = of_parse_phandle_with_args(node, "eeproms",
> +                                        "#eeprom-cells", index, &args);
> +       if (ret)
> +               return ERR_PTR(ret);
> +
> +       if (args.args_count != 2)
> +               return ERR_PTR(-EINVAL);
> +
> +       mutex_lock(&eeprom_list_mutex);
> +
> +       list_for_each_entry(e, &eeprom_list, list) {
> +               if (args.np == e->edev.of_node) {
> +                       eeprom = e;
> +                       break;
> +               }
> +       }
> +       mutex_unlock(&eeprom_list_mutex);
> +
> +       if (!eeprom)
> +               return ERR_PTR(-EPROBE_DEFER);
> +
> +       cell = kzalloc(sizeof(*cell), GFP_KERNEL);
> +       if (!cell)
> +               return ERR_PTR(-ENOMEM);
> +
> +       cell->eeprom = eeprom;
> +       cell->offset = args.args[0];
> +       cell->count = args.args[1];
> +
> +       return cell;
> +}
> +
> +static struct eeprom_cell *__eeprom_cell_get_byname(struct device_node *node,
> +                                                   const char *id)
> +{
> +       int index = 0;
> +
> +       if (id)
> +               index = of_property_match_string(node,
> +                                                "eeprom-names",
> +                                                id);
> +       return __eeprom_cell_get(node, index);
> +
> +}
> +
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index)
> +{
> +       if (!dev)
> +               return ERR_PTR(-EINVAL);
> +
> +       /* First, attempt to retrieve the cell through the DT */
> +       if (dev->of_node)
> +               return __eeprom_cell_get(dev->of_node, index);
> +
> +       /* We don't support anything else yet */
> +       return ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL(eeprom_cell_get);
> +
> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev, const char *id)
> +{
> +       if (!dev)
> +               return ERR_PTR(-EINVAL);
> +
> +       if (id && dev->of_node)
> +               return __eeprom_cell_get_byname(dev->of_node, id);
> +
> +       /* We don't support anything else yet */
> +       return ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL(eeprom_cell_get_byname);
> +
> +void eeprom_cell_put(struct eeprom_cell *cell)
> +{
> +       kfree(cell);
> +}
> +EXPORT_SYMBOL(eeprom_cell_put);
> +
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
> +{
> +       struct eeprom_device *eeprom = cell->eeprom;
> +       char *buf;
> +       int rc;
> +
> +       if (!eeprom || !eeprom->regmap)
> +               return ERR_PTR(-EINVAL);
> +
> +       buf = kzalloc(cell->count, GFP_KERNEL);
> +       if (!buf)
> +               return ERR_PTR(-ENOMEM);
> +
> +       rc = regmap_bulk_read(eeprom->regmap, cell->offset,
> +                             buf, cell->count/eeprom->stride);
> +       if (IS_ERR_VALUE(rc)) {
> +               kfree(buf);
> +               return ERR_PTR(rc);
> +       }
> +
> +       *len = cell->count;
> +
> +       return buf;
> +}
> +EXPORT_SYMBOL(eeprom_cell_read);
> +
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
> +{
> +       struct eeprom_device *eeprom = cell->eeprom;
> +
> +       if (!eeprom || !eeprom->regmap)
> +               return -EINVAL;
> +
> +       return regmap_bulk_write(eeprom->regmap, cell->offset,
> +                                buf, cell->count/eeprom->stride);
> +}
> +EXPORT_SYMBOL(eeprom_cell_write);
> +
> +static int eeprom_init(void)
> +{
> +       return class_register(&eeprom_class);
> +}
> +
> +static void eeprom_exit(void)
> +{
> +       class_unregister(&eeprom_class);
> +}
> +
> +subsys_initcall(eeprom_init);
> +module_exit(eeprom_exit);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org");
> +MODULE_DESCRIPTION("EEPROM Driver Core");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
> new file mode 100644
> index 0000000..706ae9d
> --- /dev/null
> +++ b/include/linux/eeprom-consumer.h
> @@ -0,0 +1,73 @@
> +/*
> + * EEPROM framework consumer.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_CONSUMER_H
> +#define _LINUX_EEPROM_CONSUMER_H
> +
> +struct eeprom_cell;
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given index.
> + *
> + * @dev: Device that will be interacted with
> + * @index: Index of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given name.
> + *
> + * @dev: Device that will be interacted with
> + * @name: Name of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev,
> +                                          const char *name);
> +
> +/**
> + * eeprom_cell_put(): Release previously allocated eeprom cell.
> + *
> + * @cell: Previously allocated eeprom cell by eeprom_cell_get()
> + * or eeprom_cell_get_byname().
> + */
> +void eeprom_cell_put(struct eeprom_cell *cell);
> +
> +/**
> + * eeprom_cell_read(): Read a given eeprom cell
> + *
> + * @cell: eeprom cell to be read.
> + * @len: pointer to length of cell which will be populated on successful read.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a char * bufffer.  The buffer should be freed by the consumer with a
> + * kfree().
> + */
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
> +
> +/**
> + * eeprom_cell_write(): Write to a given eeprom cell
> + *
> + * @cell: eeprom cell to be written.
> + * @buf: Buffer to be written.
> + * @len: length of buffer to be written to eeprom cell.
> + *
> + * The return value will be an non zero on error or a zero on successful write.
> + */
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
> +
> +#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
> diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
> new file mode 100644
> index 0000000..3943c2f
> --- /dev/null
> +++ b/include/linux/eeprom-provider.h
> @@ -0,0 +1,51 @@
> +/*
> + * EEPROM framework provider.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_PROVIDER_H
> +#define _LINUX_EEPROM_PROVIDER_H
> +
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +#include <linux/list.h>
> +
> +struct eeprom_device {
> +       struct regmap           *regmap;
> +       int                     stride;
> +       size_t                  size;
> +       struct device           *dev;
> +
> +       /* Internal to framework */
> +       struct device           edev;
> +       int                     id;
> +       struct list_head        list;
> +};
> +
> +/**
> + * eeprom_register(): Register a eeprom device for given eeprom.
> + * Also creates an binary entry in /sys/class/eeprom/eeprom[id]/eeprom
> + *
> + * @eeprom: eeprom device that needs to be created
> + *
> + * The return value will be an error code on error or a zero on success.
> + * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
> + */
> +int eeprom_register(struct eeprom_device *eeprom);
> +
> +/**
> + * eeprom_unregister(): Unregister previously registered eeprom device
> + *
> + * @eeprom: Pointer to previously registered eeprom device.
> + *
> + * The return value will be an non zero on error or a zero on success.
> + */
> +int eeprom_unregister(struct eeprom_device *eeprom);
> +
> +#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
> --
> 1.9.1
>

^ permalink raw reply

* Re: [GIT PULL] Kselftest updates for 3.20-rc1
From: Shuah Khan @ 2015-02-20 16:00 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-kernel, linux-api
In-Reply-To: <54D8FE1C.5040303@osg.samsung.com>

On 02/09/2015 11:36 AM, Shuah Khan wrote:
> Hi Linus,
>
> Please pull the following Kselftest updates for 3.20-rc1
>
> thanks,
> -- Shuah

Hi Linus,

Hope this work is on the list to be pulled in for 3.20. Please let
me know if there are any problems.

thanks,
-- Shuah
>
> The following changes since commit 97bf6af1f928216fd6c5a66e8a57bfa95a659672:
>
>    Linux 3.19-rc1 (2014-12-20 17:08:50 -0800)
>
> are available in the git repository at:
>
>    git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
> tags/linux-kselftest-3.20-rc1
>
> for you to fetch changes up to 6ddf898c23d62c974e148efd9e509731324a167a:
>
>    selftests/exec: Check if the syscall exists and bail if not
> (2015-02-04 10:17:35 -0700)
>
> ----------------------------------------------------------------
> Kselftest updates for 3.20-rc1
>
> This update adds:
> - Kselftest install target feature
> - Fix for selftests/exec test
>
> ----------------------------------------------------------------
> Michael Ellerman (1):
>        selftests/exec: Check if the syscall exists and bail if not
>
> Shuah Khan (20):
>        selftests/breakpoints: add install target to enable test install
>        selftests/cpu-hotplug: add install target to enable test install
>        selftests/efivarfs: add install target to enable test install
>        selftests/firmware: add install target to enable test install
>        selftests/ftrace: add install target to enable test install
>        selftests/ipc: add install target to enable test install
>        selftests/kcmp: add install target to enable test install
>        selftests/memfd: add install target to enable test install
>        selftests/memory-hotplug: add install target to enable test install
>        selftests/mount: add install target to enable test install
>        selftests/mqueue: add install target to enable test install
>        selftests/net: add install target to enable test install
>        selftests/ptrace: add install target to enable test install
>        selftests/size: add install target to enable test install
>        selftests/sysctl: add install target to enable test install
>        selftests/timers: add install target to enable test install
>        selftests/user: add install target to enable test install
>        selftests/vm: add install target to enable test install
>        selftests: add install target to enable test install
>        kbuild: add a new kselftest_install make target to install selftests
>
>   Makefile                                           | 14 +++++-
>   tools/testing/selftests/Makefile                   | 54
> +++++++++++++++++++++-
>   tools/testing/selftests/breakpoints/Makefile       | 19 +++++++-
>   tools/testing/selftests/cpu-hotplug/Makefile       | 14 +++++-
>   .../{on-off-test.sh => cpu-on-off-test.sh}         |  0
>   tools/testing/selftests/efivarfs/Makefile          | 16 ++++++-
>   tools/testing/selftests/exec/execveat.c            | 10 +++-
>   tools/testing/selftests/firmware/Makefile          | 43 ++++++++++-------
>   tools/testing/selftests/ftrace/Makefile            | 13 +++++-
>   tools/testing/selftests/ipc/Makefile               | 19 +++++++-
>   tools/testing/selftests/kcmp/Makefile              | 13 +++++-
>   tools/testing/selftests/memfd/Makefile             | 17 +++++--
>   tools/testing/selftests/memory-hotplug/Makefile    | 14 +++++-
>   .../{on-off-test.sh => mem-on-off-test.sh}         |  0
>   tools/testing/selftests/mount/Makefile             | 12 ++++-
>   tools/testing/selftests/mqueue/Makefile            | 18 ++++++--
>   tools/testing/selftests/net/Makefile               | 20 ++++++--
>   tools/testing/selftests/ptrace/Makefile            | 16 +++++--
>   tools/testing/selftests/size/Makefile              | 12 ++++-
>   tools/testing/selftests/sysctl/Makefile            | 17 ++++++-
>   tools/testing/selftests/timers/Makefile            | 12 ++++-
>   tools/testing/selftests/user/Makefile              | 12 ++++-
>   tools/testing/selftests/vm/Makefile                | 11 ++++-
>   23 files changed, 326 insertions(+), 50 deletions(-)
>   rename tools/testing/selftests/cpu-hotplug/{on-off-test.sh =>
> cpu-on-off-test.sh} (100%)
>   rename tools/testing/selftests/memory-hotplug/{on-off-test.sh =>
> mem-on-off-test.sh} (100%)
>


-- 
Shuah Khan
Sr. Linux Kernel Developer
Samsung Research America (Silicon Valley)
shuahkh@osg.samsung.com | (970) 217-8978

^ permalink raw reply

* Re: Documenting MS_LAZYTIME
From: Eric Sandeen @ 2015-02-20 15:49 UTC (permalink / raw)
  To: Michael Kerrisk, Theodore Ts'o
  Cc: Ext4 Developers List, Linux btrfs Developers List, XFS Developers,
	linux-man, Linux-Fsdevel, Linux API
In-Reply-To: <CAHO5Pa0k7QkV_6BDjwTVxa7LV9tFyN9nGFFcSvOC6HYO08wfrw@mail.gmail.com>

On 2/20/15 2:50 AM, Michael Kerrisk wrote:
> Hello Ted,
> 
> Based on your commit message 0ae45f63d4e, I I wrote the documentation
> below for MS_LAZYTIME, to go into the mount(2) man page. Could you
> please check it over and let me know if it's accurate. In particular,
> I added pieces marked with "*" below that were not part of the commit
> message and I'd like confirmation that they're accurate.
> 
> Thanks,
> 
> Michael
> 
> [[
>        MS_LAZYTIME (since Linux 3.20)
>               Only  update  filetimes (atime, mtime, ctime) on the in-
>               memory version of the file  inode.   The  on-disk  time‐
>               stamps are updated only when:

"filetimes" and "file inode" seems a bit awkward.  How about:

>        MS_LAZYTIME (since Linux 3.20)
>		Reduce on-disk updates of inode timestamps (atime, mtime, ctime)
> 		by maintaining these changes only in memory, unless:

(maybe I'm bike-shedding too much, if so, sorry).

>               (a)  the inode needs to be updated for some change unre‐
>                    lated to file timestamps;
> 
>               (b)  the application  employs  fsync(2),  syncfs(2),  or
>                    sync(2);
> 
>               (c)  an undeleted inode is evicted from memory; or
> 
> *             (d)  more than 24 hours have passed since the i-node was
> *                  written to disk.

Please don't use "i-node" - simply "inode" is much more common in the manpages
AFAICT.

>               This mount option significantly reduces  writes  to  the
>               inode  table  for workloads that perform frequent random
>               writes to preallocated files.

This seems like an overly specific description of a single workload out
of many which may benefit, but what do others think?  "inode table" is also
fairly extN-specific.

-Eric
 
> *             As at Linux 3.20, this option is supported only on ext4.
> ]]
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: Documenting MS_LAZYTIME
From: Michael Kerrisk (man-pages) @ 2015-02-20 13:22 UTC (permalink / raw)
  To: Andreas Dilger
  Cc: Theodore Ts'o, Ext4 Developers List,
	Linux btrfs Developers List, XFS Developers, linux-man,
	Linux-Fsdevel, Linux API
In-Reply-To: <44893EA7-B11A-469A-9911-6CE2E8B26EB4@dilger.ca>

On 20 February 2015 at 13:32, Andreas Dilger <adilger@dilger.ca> wrote:
> On Feb 20, 2015, at 1:50 AM, Michael Kerrisk <mtk.manpages@gmail.com> wrote:
>>
>> Hello Ted,
>>
>> Based on your commit message 0ae45f63d4e, I I wrote the documentation
>> below for MS_LAZYTIME, to go into the mount(2) man page. Could you
>> please check it over and let me know if it's accurate. In particular,
>> I added pieces marked with "*" below that were not part of the commit
>> message and I'd like confirmation that they're accurate.
>>
>> Thanks,
>>
>> Michael
>>
>> [[
>>       MS_LAZYTIME (since Linux 3.20)
>>              Only  update  filetimes (atime, mtime, ctime) on the in-
>>              memory version of the file  inode.   The  on-disk  time‐
>>              stamps are updated only when:
>>
>>              (a)  the inode needs to be updated for some change unre‐
>>                   lated to file timestamps;
>>
>>              (b)  the application  employs  fsync(2),  syncfs(2),  or
>>                   sync(2);
>>
>>              (c)  an undeleted inode is evicted from memory; or
>>
>> *             (d)  more than 24 hours have passed since the i-node was
>> *                  written to disk.
>>
>>              This mount option significantly reduces  writes  to  the
>>              inode  table  for workloads that perform frequent random
>>              writes to preallocated files.
>>
>> *             As at Linux 3.20, this option is supported only on ext4.
>
> I _think_ that the lazytime mount option is generic for all filesystems.
> I believe ext4 has an extra optimization for it, but that's it.

Ah yes, looking at the code again, that makes sense. I think you're
right, and I've struck that last sentence. Thanks, Andreas.

Cheers,

Michael


-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: Documenting MS_LAZYTIME
From: Andreas Dilger @ 2015-02-20 12:32 UTC (permalink / raw)
  To: Michael Kerrisk
  Cc: Theodore Ts'o, Ext4 Developers List,
	Linux btrfs Developers List, XFS Developers,
	linux-man-u79uwXL29TY76Z2rM5mHXA, Linux-Fsdevel, Linux API
In-Reply-To: <CAHO5Pa0k7QkV_6BDjwTVxa7LV9tFyN9nGFFcSvOC6HYO08wfrw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Feb 20, 2015, at 1:50 AM, Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> 
> Hello Ted,
> 
> Based on your commit message 0ae45f63d4e, I I wrote the documentation
> below for MS_LAZYTIME, to go into the mount(2) man page. Could you
> please check it over and let me know if it's accurate. In particular,
> I added pieces marked with "*" below that were not part of the commit
> message and I'd like confirmation that they're accurate.
> 
> Thanks,
> 
> Michael
> 
> [[
>       MS_LAZYTIME (since Linux 3.20)
>              Only  update  filetimes (atime, mtime, ctime) on the in-
>              memory version of the file  inode.   The  on-disk  time‐
>              stamps are updated only when:
> 
>              (a)  the inode needs to be updated for some change unre‐
>                   lated to file timestamps;
> 
>              (b)  the application  employs  fsync(2),  syncfs(2),  or
>                   sync(2);
> 
>              (c)  an undeleted inode is evicted from memory; or
> 
> *             (d)  more than 24 hours have passed since the i-node was
> *                  written to disk.
> 
>              This mount option significantly reduces  writes  to  the
>              inode  table  for workloads that perform frequent random
>              writes to preallocated files.
> 
> *             As at Linux 3.20, this option is supported only on ext4.

I _think_ that the lazytime mount option is generic for all filesystems.
I believe ext4 has an extra optimization for it, but that's it.

Cheers, Andreas

^ permalink raw reply

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Srinivas Kandagatla @ 2015-02-20 10:24 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, Greg Kroah-Hartman
In-Reply-To: <54E6ECEA.7020604-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>



On 20/02/15 08:14, Srinivas Kandagatla wrote:
>>
>> Doesn't this need some sort of select REGMAP somewhere?
> May be depends REGMAP would be good.
You are right, just realized that
it should be "select REGMAP"

and for QFPROM it should be "select REGMAP_MMIO"

--srini

^ permalink raw reply

* Documenting MS_LAZYTIME
From: Michael Kerrisk @ 2015-02-20  8:50 UTC (permalink / raw)
  To: Theodore Ts'o
  Cc: Ext4 Developers List, Linux btrfs Developers List, XFS Developers,
	linux-man-u79uwXL29TY76Z2rM5mHXA, Linux-Fsdevel, Linux API

Hello Ted,

Based on your commit message 0ae45f63d4e, I I wrote the documentation
below for MS_LAZYTIME, to go into the mount(2) man page. Could you
please check it over and let me know if it's accurate. In particular,
I added pieces marked with "*" below that were not part of the commit
message and I'd like confirmation that they're accurate.

Thanks,

Michael

[[
       MS_LAZYTIME (since Linux 3.20)
              Only  update  filetimes (atime, mtime, ctime) on the in-
              memory version of the file  inode.   The  on-disk  time‐
              stamps are updated only when:

              (a)  the inode needs to be updated for some change unre‐
                   lated to file timestamps;

              (b)  the application  employs  fsync(2),  syncfs(2),  or
                   sync(2);

              (c)  an undeleted inode is evicted from memory; or

*             (d)  more than 24 hours have passed since the i-node was
*                  written to disk.

              This mount option significantly reduces  writes  to  the
              inode  table  for workloads that perform frequent random
              writes to preallocated files.

*             As at Linux 3.20, this option is supported only on ext4.
]]

-- 
Michael Kerrisk Linux man-pages maintainer;
http://www.kernel.org/doc/man-pages/
Author of "The Linux Programming Interface", http://blog.man7.org/
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Srinivas Kandagatla @ 2015-02-20  8:27 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api-u79uwXL29TY76Z2rM5mHXA,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, Stephen Boyd,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Kumar Gala,
	Maxime Ripard
In-Reply-To: <20150219181230.GC795-g2DYL2Zd6BY@public.gmane.org>

Thanks Andrew for your comments,

On 19/02/15 18:12, Andrew Lunn wrote:
>> +
>> +Required properties:
>> +
>> +eeproms: List of phandle and data cell specifier triplet, one triplet
>> +	 for each data cell the device might be interested in. The
>> +	 triplet consists of the phandle to the eeprom provider, then
>> +	 the offset in byte within that storage device, and the length
>
> bytes
>
>> +	 in byte of the data we care about.
>
> bytes
Yep will fix it in next version.
>
>> +
>> +Optional properties:
>> +
>> +eeprom-names: List of data cell name strings sorted in the same order
>> + 	      as the resets property. Consumers drivers will use
>
> resets? I guess this text was cut/paste from the reset documentation?\
>
I think so. Will fix it.
>> + 	      eeprom-names to differentiate between multiple cells,
>> + 	      and hence being able to know what these cells are for.
>> +
>> +For example:
>> +
>> +	device {
>> +		eeproms = <&at24 14 42>;
>
> I like to use 42, but is it realistic to have a soc-rev-id which is 42
> bytes long?  How about using 42 as the offset and a sensible length of
> say 4?
Ok, will fix it..
>
>> +		eeprom-names = "soc-rev-id";
>> +menuconfig EEPROM
>> +	bool "EEPROM Support"
>> +	depends on OF
>> +	help
>> +	  Support for EEPROM alike devices.
>
> like.
Ok
>
>> +
>> +	  This framework is designed to provide a generic interface to EEPROM
>
> EPROMs
Ok.
>
>> +
>> +
>> +static ssize_t bin_attr_eeprom_read_write(struct kobject *kobj,
>> +				    char *buf, loff_t offset,
>> +				    size_t count, bool read)
>> +{
>> +	struct device *dev = container_of(kobj, struct device, kobj);
>> +	struct eeprom_device *eeprom = container_of(dev, struct eeprom_device,
>> +						    edev);
>> +	int rc;
>> +
>> +	if (offset > eeprom->size)
>> +		return 0;
>> +
>> +	if (offset + count > eeprom->size)
>> +		count = eeprom->size - offset;
>> +
>> +	if (read)
>> +		rc = regmap_bulk_read(eeprom->regmap, offset,
>> +				      buf, count/eeprom->stride);
>
> This division will round down, so you could get one less byte than
> what you expected, and the value you actually return. It seems like
> there should be a check here, the count is a multiple of stride and
> return an error if it is not.
Thats a good catch, I will fix this for other such instances too.
>
>> +	else
>> +		rc = regmap_bulk_write(eeprom->regmap, offset,
>> +				       buf, count/eeprom->stride);
>> +
>> +	if (IS_ERR_VALUE(rc))
>> +		return 0;
>> +
>
> I don't think returning 0 here, and above is the best thing to
> do. Return the real error code from regmap, or EINVAL or some other
> error code for going off the end of the eerpom.
Ok, I will fix the return value here for both the cases.

>
>> +	return count;
>> +}
>> +
>> +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
>> +				    struct bin_attribute *attr,
>> +				    char *buf, loff_t offset, size_t count)
>> +{
>> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
>> +}
>> +
>> +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
>> +				     struct bin_attribute *attr,
>> +				     char *buf, loff_t offset, size_t count)
>> +{
>> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, false);
>> +}
>>
>
> These two functions seem to be identical. So just have one of them?

One is read and other is write.. there is a true and false flag at the 
end of the call to bin_attr_eeprom_read_write().
>
> +
>> +static struct bin_attribute bin_attr_eeprom = {
>> +	.attr	= {
>> +		.name	= "eeprom",
>> +		.mode	= 0660,
>
> Symbolic values like S_IRUGO | S_IWUSR would be better.
Yep, thats correct, I will fix it.
>
> Are you also sure you want group write?
>
S_IWUSR should be enough.

>> +	},
>> +	.read	= bin_attr_eeprom_read,
>> +	.write	= bin_attr_eeprom_write,
>> +};
>> +
>> +static struct eeprom_cell *__eeprom_cell_get(struct device_node *node,
>> +					     int index)
>> +{
>> +	struct of_phandle_args args;
>> +	struct eeprom_cell *cell;
>> +	struct eeprom_device *e, *eeprom = NULL;
>> +	int ret;
>> +
>> +	ret = of_parse_phandle_with_args(node, "eeproms",
>> +					 "#eeprom-cells", index, &args);
>> +	if (ret)
>> +		return ERR_PTR(ret);
>> +
>> +	if (args.args_count != 2)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	mutex_lock(&eeprom_list_mutex);
>> +
>> +	list_for_each_entry(e, &eeprom_list, list) {
>> +		if (args.np == e->edev.of_node) {
>> +			eeprom = e;
>> +			break;
>> +		}
>> +	}
>> +	mutex_unlock(&eeprom_list_mutex);
>
> Shouldn't you increment a reference count to the eeprom here?  You are
> going to have trouble if the eeprom is unregistered and there is a
> call still referring to it.
Yes, Stephen Byod also pointed the same, having owner in eeprom_device 
should fix this.
I will fix it in next version.

>
>> +
>> +	if (!eeprom)
>> +		return ERR_PTR(-EPROBE_DEFER);
>> +
>> +	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
>> +	if (!cell)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	cell->eeprom = eeprom;
>> +	cell->offset = args.args[0];
>> +	cell->count = args.args[1];
>> +
>> +	return cell;
>> +}
>> +
>> +
>> diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
>> new file mode 100644
>> index 0000000..706ae9d
>> --- /dev/null
>> +++ b/include/linux/eeprom-consumer.h
>> @@ -0,0 +1,73 @@
>> +/*
>> + * EEPROM framework consumer.
>> + *
>> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2.  This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef _LINUX_EEPROM_CONSUMER_H
>> +#define _LINUX_EEPROM_CONSUMER_H
>> +
>> +struct eeprom_cell;
>> +
>> +/**
>> + * eeprom_cell_get(): Get eeprom cell of device form a given index.
>
> of a device for a
>
Ok, will be fixed in next version.
>> + *
>> + * @dev: Device that will be interacted with
>> + * @index: Index of the eeprom cell.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
>> + * eeprom_cell_put().
>> + */
>> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);
>> +
>> +/**
>> + * eeprom_cell_get(): Get eeprom cell of device form a given name.
>
> same again
Ok, will be fixed in next version.
>
>> + *
>> + * @dev: Device that will be interacted with
>> + * @name: Name of the eeprom cell.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
>> + * eeprom_cell_put().
>> + */
>> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev,
>> +					   const char *name);
>> +
>> +/**
>> + * eeprom_cell_put(): Release previously allocated eeprom cell.
>> + *
>> + * @cell: Previously allocated eeprom cell by eeprom_cell_get()
>> + * or eeprom_cell_get_byname().
>> + */
>> +void eeprom_cell_put(struct eeprom_cell *cell);
>> +
>> +/**
>> + * eeprom_cell_read(): Read a given eeprom cell
>> + *
>> + * @cell: eeprom cell to be read.
>> + * @len: pointer to length of cell which will be populated on successful read.
>> + *
>> + * The return value will be an ERR_PTR() on error or a valid pointer
>> + * to a char * bufffer.  The buffer should be freed by the consumer with a
>> + * kfree().
>> + */
>> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);
>
> Would void * be better than char *? I guess the contents is mostly
> data, not strings.
Yes, thats sounds sensible.
>
>        Andrew
>
>> +
>> +/**

>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Srinivas Kandagatla @ 2015-02-20  8:14 UTC (permalink / raw)
  To: Stephen Boyd, linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Arnd Bergmann, broonie,
	Greg Kroah-Hartman
In-Reply-To: <54E69DB0.60701@codeaurora.org>



On 20/02/15 02:36, Stephen Boyd wrote:
> On 02/19/15 09:08, Srinivas Kandagatla wrote:
>> diff --git a/drivers/Kconfig b/drivers/Kconfig
>> index c70d6e4..d7afc82 100644
>> --- a/drivers/Kconfig
>> +++ b/drivers/Kconfig
>> @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
>>
>>   source "drivers/android/Kconfig"
>>
>> +source "drivers/eeprom/Kconfig"
>> +
>>   endmenu
>> diff --git a/drivers/Makefile b/drivers/Makefile
>> index 527a6da..57eb5b0 100644
>> --- a/drivers/Makefile
>> +++ b/drivers/Makefile
>> @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
>>   obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
>>   obj-$(CONFIG_CORESIGHT)		+= coresight/
>>   obj-$(CONFIG_ANDROID)		+= android/
>> +obj-$(CONFIG_EEPROM)		+= eeprom/
>> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
>> new file mode 100644
>> index 0000000..2c5452a
>> --- /dev/null
>> +++ b/drivers/eeprom/Kconfig
>> @@ -0,0 +1,19 @@
>> +menuconfig EEPROM
>> +	bool "EEPROM Support"
>> +	depends on OF
>
> Doesn't this need some sort of select REGMAP somewhere?
May be depends REGMAP would be good.

>
> Also, why do we need to use regmap for the eeprom framework read/write
> ops? I liked the simple eeprom::{read,write} API that Maxime had. The
> regmap part could be a regmap-eeprom driver that implements read/write
> ops like you've done in the core.
regmap bus does the same job.

The only reason for using regmap here is to have more generic drivers 
for eeprom providers based on different buses like mmio, i2c, spi...
As of today we could just make the qfprom eeprom provider as more 
generic eeprom-mmio provider. May be sunxi_sid could reuse it too with 
some effort.

In future It may be possible to have eeprom-i2c or eeprom-spi providers.

>

>> +
>> +struct eeprom_device {
>> +	struct regmap		*regmap;
>> +	int			stride;
>> +	size_t			size;
>> +	struct device		*dev;
>> +
>> +	/* Internal to framework */
>> +	struct device		edev;
>> +	int			id;
>> +	struct list_head	list;
>
> Should there be a module owner here to handle module removal?
>

Good point, we should do some reference counting.

^ permalink raw reply

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Stephen Boyd @ 2015-02-20  2:36 UTC (permalink / raw)
  To: Srinivas Kandagatla,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, Greg Kroah-Hartman
In-Reply-To: <1424365708-26681-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

On 02/19/15 09:08, Srinivas Kandagatla wrote:
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index c70d6e4..d7afc82 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
>  
>  source "drivers/android/Kconfig"
>  
> +source "drivers/eeprom/Kconfig"
> +
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 527a6da..57eb5b0 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
>  obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
>  obj-$(CONFIG_CORESIGHT)		+= coresight/
>  obj-$(CONFIG_ANDROID)		+= android/
> +obj-$(CONFIG_EEPROM)		+= eeprom/
> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
> new file mode 100644
> index 0000000..2c5452a
> --- /dev/null
> +++ b/drivers/eeprom/Kconfig
> @@ -0,0 +1,19 @@
> +menuconfig EEPROM
> +	bool "EEPROM Support"
> +	depends on OF

Doesn't this need some sort of select REGMAP somewhere?

Also, why do we need to use regmap for the eeprom framework read/write
ops? I liked the simple eeprom::{read,write} API that Maxime had. The
regmap part could be a regmap-eeprom driver that implements read/write
ops like you've done in the core.

> +	help
> +	  Support for EEPROM alike devices.
> +
> +	  This framework is designed to provide a generic interface to EEPROM
> +	  from both the Linux Kernel and the userspace.
> +
> +	  If unsure, say no.
> +
> +if EEPROM
> +
> +config EEPROM_DEBUG
> +	bool "EEPROM debug support"
> +	help
> +	  Say yes here to enable debugging support.
> +
> +endif
>
> diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
> new file mode 100644
> index 0000000..3943c2f
> --- /dev/null
> +++ b/include/linux/eeprom-provider.h
> @@ -0,0 +1,51 @@
> +/*
> + * EEPROM framework provider.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_PROVIDER_H
> +#define _LINUX_EEPROM_PROVIDER_H
> +
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +#include <linux/list.h>
> +
> +struct eeprom_device {
> +	struct regmap		*regmap;
> +	int			stride;
> +	size_t			size;
> +	struct device		*dev;
> +
> +	/* Internal to framework */
> +	struct device		edev;
> +	int			id;
> +	struct list_head	list;

Should there be a module owner here to handle module removal?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [PATCH 0/7] [RFC] kernel: add a netlink interface to get information about processes
From: Andrew Vagin @ 2015-02-19 21:39 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Pavel Emelyanov, Roger Luethi, Oleg Nesterov, Cyrill Gorcunov,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Andrew Morton, Linux API, Andrey Vagin
In-Reply-To: <CALCETrU5B+1g9B3GH2WpPMaB98thXxpL1fAsHjssK1t_fDM_ZQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Wed, Feb 18, 2015 at 05:18:38PM -0800, Andy Lutomirski wrote:
> On Feb 18, 2015 6:27 AM, "Andrew Vagin" <avagin-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org> wrote:
> >
> > On Tue, Feb 17, 2015 at 11:05:31AM -0800, Andy Lutomirski wrote:
> > > On Feb 17, 2015 12:40 AM, "Andrey Vagin" <avagin-GEFAQzZX7r8dnm+yROfE0A@public.gmane.org> wrote:
> > > >
> > > > Here is a preview version. It provides restricted set of functionality.
> > > > I would like to collect feedback about this idea.
> > > >
> > > > Currently we use the proc file system, where all information are
> > > > presented in text files, what is convenient for humans.  But if we need
> > > > to get information about processes from code (e.g. in C), the procfs
> > > > doesn't look so cool.
> > > >
> > > > From code we would prefer to get information in binary format and to be
> > > > able to specify which information and for which tasks are required. Here
> > > > is a new interface with all these features, which is called task_diag.
> > > > In addition it's much faster than procfs.
> > > >
> > > > task_diag is based on netlink sockets and looks like socket-diag, which
> > > > is used to get information about sockets.
> > > >
> > > > A request is described by the task_diag_pid structure:
> > > >
> > > > struct task_diag_pid {
> > > >        __u64   show_flags;      /* specify which information are required */
> > > >        __u64   dump_stratagy;   /* specify a group of processes */
> > > >
> > > >        __u32   pid;
> > > > };
> > > >
> > > > A respone is a set of netlink messages. Each message describes one task.
> > > > All task properties are divided on groups. A message contains the
> > > > TASK_DIAG_MSG group and other groups if they have been requested in
> > > > show_flags. For example, if show_flags contains TASK_DIAG_SHOW_CRED, a
> > > > response will contain the TASK_DIAG_CRED group which is described by the
> > > > task_diag_creds structure.
> > > >
> > > > struct task_diag_msg {
> > > >         __u32   tgid;
> > > >         __u32   pid;
> > > >         __u32   ppid;
> > > >         __u32   tpid;
> > > >         __u32   sid;
> > > >         __u32   pgid;
> > > >         __u8    state;
> > > >         char    comm[TASK_DIAG_COMM_LEN];
> > > > };
> > > >
> > > > Another good feature of task_diag is an ability to request information
> > > > for a few processes. Currently here are two stratgies
> > > > TASK_DIAG_DUMP_ALL      - get information for all tasks
> > > > TASK_DIAG_DUMP_CHILDREN - get information for children of a specified
> > > >                           tasks
> > > >
> > > > The task diag is much faster than the proc file system. We don't need to
> > > > create a new file descriptor for each task. We need to send a request
> > > > and get a response. It allows to get information for a few task in one
> > > > request-response iteration.
> > > >
> > > > I have compared performance of procfs and task-diag for the
> > > > "ps ax -o pid,ppid" command.
> > > >
> > > > A test stand contains 10348 processes.
> > > > $ ps ax -o pid,ppid | wc -l
> > > > 10348
> > > >
> > > > $ time ps ax -o pid,ppid > /dev/null
> > > >
> > > > real    0m1.073s
> > > > user    0m0.086s
> > > > sys     0m0.903s
> > > >
> > > > $ time ./task_diag_all > /dev/null
> > > >
> > > > real    0m0.037s
> > > > user    0m0.004s
> > > > sys     0m0.020s
> > > >
> > > > And here are statistics about syscalls which were called by each
> > > > command.
> > > > $ perf stat -e syscalls:sys_exit* -- ps ax -o pid,ppid  2>&1 | grep syscalls | sort -n -r | head -n 5
> > > >             20,713      syscalls:sys_exit_open
> > > >             20,710      syscalls:sys_exit_close
> > > >             20,708      syscalls:sys_exit_read
> > > >             10,348      syscalls:sys_exit_newstat
> > > >                 31      syscalls:sys_exit_write
> > > >
> > > > $ perf stat -e syscalls:sys_exit* -- ./task_diag_all  2>&1 | grep syscalls | sort -n -r | head -n 5
> > > >                114      syscalls:sys_exit_recvfrom
> > > >                 49      syscalls:sys_exit_write
> > > >                  8      syscalls:sys_exit_mmap
> > > >                  4      syscalls:sys_exit_mprotect
> > > >                  3      syscalls:sys_exit_newfstat
> > > >
> > > > You can find the test program from this experiment in the last patch.
> > > >
> > > > The idea of this functionality was suggested by Pavel Emelyanov
> > > > (xemul@), when he found that operations with /proc forms a significant
> > > > part of a checkpointing time.
> > > >
> > > > Ten years ago here was attempt to add a netlink interface to access to /proc
> > > > information:
> > > > http://lwn.net/Articles/99600/
> > >
> > > I don't suppose this could use real syscalls instead of netlink.  If
> > > nothing else, netlink seems to conflate pid and net namespaces.
> >
> > What do you mean by "conflate pid and net namespaces"?
> 
> A netlink socket is bound to a network namespace, but you should be
> returning data specific to a pid namespace.

Here is a good question. When we mount a procfs instance, the current
pidns is saved on a superblock. Then if we read data from
this procfs from another pidns, we will see pid-s from the pidns where
this procfs has been mounted.

$ unshare -p -- bash -c '(bash)'
$ cat /proc/self/status | grep ^Pid:
Pid:	15770
$ echo $$
1

A similar situation with socket_diag. A socket_diag socket is bound to a
network namespace. If we open a socket_diag socket and change a network
namespace, it will return infromation about the initial netns.

In this version I always use a current pid namespace.
But to be consistant with other kernel logic, a socket diag has to be
linked with a pidns where it has been created.

> 
> On a related note, how does this interact with hidepid?  More

Currently it always work as procfs with hidepid = 2 (highest level of
security).

> generally, what privileges are you requiring to obtain what data?

It dumps information only if ptrace_may_access(tsk, PTRACE_MODE_READ) returns true

> 
> >
> > >
> > > Also, using an asynchronous interface (send, poll?, recv) for
> > > something that's inherently synchronous (as the kernel a local
> > > question) seems awkward to me.
> >
> > Actually all requests are handled synchronously. We call sendmsg to send
> > a request and it is handled in this syscall.
> >  2)               |  netlink_sendmsg() {
> >  2)               |    netlink_unicast() {
> >  2)               |      taskdiag_doit() {
> >  2)   2.153 us    |        task_diag_fill();
> >  2)               |        netlink_unicast() {
> >  2)   0.185 us    |          netlink_attachskb();
> >  2)   0.291 us    |          __netlink_sendskb();
> >  2)   2.452 us    |        }
> >  2) + 33.625 us   |      }
> >  2) + 54.611 us   |    }
> >  2) + 76.370 us   |  }
> >  2)               |  netlink_recvmsg() {
> >  2)   1.178 us    |    skb_recv_datagram();
> >  2) + 46.953 us   |  }
> >
> > If we request information for a group of tasks (NLM_F_DUMP), a first
> > portion of data is filled from the sendmsg syscall. And then when we read
> > it, the kernel fills the next portion.
> >
> >  3)               |  netlink_sendmsg() {
> >  3)               |    __netlink_dump_start() {
> >  3)               |      netlink_dump() {
> >  3)               |        taskdiag_dumpid() {
> >  3)   0.685 us    |          task_diag_fill();
> > ...
> >  3)   0.224 us    |          task_diag_fill();
> >  3) + 74.028 us   |        }
> >  3) + 88.757 us   |      }
> >  3) + 89.296 us   |    }
> >  3) + 98.705 us   |  }
> >  3)               |  netlink_recvmsg() {
> >  3)               |    netlink_dump() {
> >  3)               |      taskdiag_dumpid() {
> >  3)   0.594 us    |        task_diag_fill();
> > ...
> >  3)   0.242 us    |        task_diag_fill();
> >  3) + 60.634 us   |      }
> >  3) + 72.803 us   |    }
> >  3) + 88.005 us   |  }
> >  3)               |  netlink_recvmsg() {
> >  3)               |    netlink_dump() {
> >  3)   2.403 us    |      taskdiag_dumpid();
> >  3) + 26.236 us   |    }
> >  3) + 40.522 us   |  }
> >  0) + 20.407 us   |  netlink_recvmsg();
> >
> >
> > netlink is really good for this type of tasks.  It allows to create an
> > extendable interface which can be easy customized for different needs.
> >
> > I don't think that we would want to create another similar interface
> > just to be independent from network subsystem.
> 
> I guess this is a bit streamy in that you ask one question and get
> multiple answers.

It's like seq_file in procfs. The kernel allocates a buffer then fills
it, copies it into userspace, fills it again, ... repeats these actions.
And we can read data from file by portions.

Actually here is one more analogy. When we open a file in procfs,
we sends a request to the kernel and a file path is a request body in
this case. But in case of procfs, we can't construct requests, we only
have a set of predefined requests.

> 
> >
> > Thanks,
> > Andrew
> >
> > >
> > > --Andy

^ permalink raw reply

* Re: [RFC PATCH 1/3] eeprom: Add a simple EEPROM framework
From: Andrew Lunn @ 2015-02-19 18:12 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Arnd Bergmann, Pawel Moll,
	Greg Kroah-Hartman, linux-api-u79uwXL29TY76Z2rM5mHXA,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, Stephen Boyd,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Kumar Gala,
	Maxime Ripard
In-Reply-To: <1424365708-26681-1-git-send-email-srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

On Thu, Feb 19, 2015 at 05:08:28PM +0000, Srinivas Kandagatla wrote:
> From: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> 
> Up until now, EEPROM drivers were stored in drivers/misc, where they all had to
> duplicate pretty much the same code to register a sysfs file, allow in-kernel
> users to access the content of the devices they were driving, etc.
> 
> This was also a problem as far as other in-kernel users were involved, since
> the solutions used were pretty much different from on driver to another, there
> was a rather big abstraction leak.
> 
> This introduction of this framework aims at solving this. It also introduces DT
> representation for consumer devices to go get the data they require (MAC
> Addresses, SoC/Revision ID, part numbers, and so on) from the EEPROMs.
> 
> Having regmap interface to this framework would give much better
> abstraction for eeproms on different buses.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> [srinivas.kandagatla: Moved to regmap based and cleanedup apis]
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  .../devicetree/bindings/eeprom/eeprom.txt          |  48 ++++
>  drivers/Kconfig                                    |   2 +
>  drivers/Makefile                                   |   1 +
>  drivers/eeprom/Kconfig                             |  19 ++
>  drivers/eeprom/Makefile                            |   9 +
>  drivers/eeprom/core.c                              | 290 +++++++++++++++++++++
>  include/linux/eeprom-consumer.h                    |  73 ++++++
>  include/linux/eeprom-provider.h                    |  51 ++++
>  8 files changed, 493 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/eeprom/eeprom.txt
>  create mode 100644 drivers/eeprom/Kconfig
>  create mode 100644 drivers/eeprom/Makefile
>  create mode 100644 drivers/eeprom/core.c
>  create mode 100644 include/linux/eeprom-consumer.h
>  create mode 100644 include/linux/eeprom-provider.h
> 
> diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> new file mode 100644
> index 0000000..9ec1ec2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
> @@ -0,0 +1,48 @@
> += EEPROM Data Device Tree Bindings =
> +
> +This binding is intended to represent the location of hardware
> +configuration data stored in EEPROMs.
> +
> +On a significant proportion of boards, the manufacturer has stored
> +some data on an EEPROM-like device, for the OS to be able to retrieve
> +these information and act upon it. Obviously, the OS has to know
> +about where to retrieve these data from, and where they are stored on
> +the storage device.
> +
> +This document is here to document this.
> +
> += Data providers =
> +
> +Required properties:
> +#eeprom-cells:	Number of cells in an eeprom specifier; The common
> +		case is 2.
> +
> +For example:
> +
> +	at24: eeprom@42 {
> +		#eeprom-cells = <2>;
> +	};
> +
> += Data consumers =
> +
> +Required properties:
> +
> +eeproms: List of phandle and data cell specifier triplet, one triplet
> +	 for each data cell the device might be interested in. The
> +	 triplet consists of the phandle to the eeprom provider, then
> +	 the offset in byte within that storage device, and the length

bytes

> +	 in byte of the data we care about.

bytes

> +
> +Optional properties:
> +
> +eeprom-names: List of data cell name strings sorted in the same order
> + 	      as the resets property. Consumers drivers will use

resets? I guess this text was cut/paste from the reset documentation?\

> + 	      eeprom-names to differentiate between multiple cells,
> + 	      and hence being able to know what these cells are for.
> +
> +For example:
> +
> +	device {
> +		eeproms = <&at24 14 42>;

I like to use 42, but is it realistic to have a soc-rev-id which is 42
bytes long?  How about using 42 as the offset and a sensible length of
say 4?

> +		eeprom-names = "soc-rev-id";
> +	};
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index c70d6e4..d7afc82 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -184,4 +184,6 @@ source "drivers/thunderbolt/Kconfig"
>  
>  source "drivers/android/Kconfig"
>  
> +source "drivers/eeprom/Kconfig"
> +
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 527a6da..57eb5b0 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -165,3 +165,4 @@ obj-$(CONFIG_RAS)		+= ras/
>  obj-$(CONFIG_THUNDERBOLT)	+= thunderbolt/
>  obj-$(CONFIG_CORESIGHT)		+= coresight/
>  obj-$(CONFIG_ANDROID)		+= android/
> +obj-$(CONFIG_EEPROM)		+= eeprom/
> diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
> new file mode 100644
> index 0000000..2c5452a
> --- /dev/null
> +++ b/drivers/eeprom/Kconfig
> @@ -0,0 +1,19 @@
> +menuconfig EEPROM
> +	bool "EEPROM Support"
> +	depends on OF
> +	help
> +	  Support for EEPROM alike devices.

like.

> +
> +	  This framework is designed to provide a generic interface to EEPROM

EPROMs

> +	  from both the Linux Kernel and the userspace.
> +
> +	  If unsure, say no.
> +
> +if EEPROM
> +
> +config EEPROM_DEBUG
> +	bool "EEPROM debug support"
> +	help
> +	  Say yes here to enable debugging support.
> +
> +endif
> diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
> new file mode 100644
> index 0000000..e130079
> --- /dev/null
> +++ b/drivers/eeprom/Makefile
> @@ -0,0 +1,9 @@
> +#
> +# Makefile for eeprom drivers.
> +#
> +
> +ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
> +
> +obj-$(CONFIG_EEPROM)		+= core.o
> +
> +# Devices
> diff --git a/drivers/eeprom/core.c b/drivers/eeprom/core.c
> new file mode 100644
> index 0000000..bc877a6
> --- /dev/null
> +++ b/drivers/eeprom/core.c
> @@ -0,0 +1,290 @@
> +/*
> + * EEPROM framework core.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/eeprom-provider.h>
> +#include <linux/eeprom-consumer.h>
> +#include <linux/export.h>
> +#include <linux/fs.h>
> +#include <linux/idr.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +
> +struct eeprom_cell {
> +	struct eeprom_device *eeprom;
> +	loff_t offset;
> +	size_t count;
> +};
> +
> +static DEFINE_MUTEX(eeprom_list_mutex);
> +static LIST_HEAD(eeprom_list);
> +static DEFINE_IDA(eeprom_ida);
> +
> +static ssize_t bin_attr_eeprom_read_write(struct kobject *kobj,
> +				    char *buf, loff_t offset,
> +				    size_t count, bool read)
> +{
> +	struct device *dev = container_of(kobj, struct device, kobj);
> +	struct eeprom_device *eeprom = container_of(dev, struct eeprom_device,
> +						    edev);
> +	int rc;
> +
> +	if (offset > eeprom->size)
> +		return 0;
> +
> +	if (offset + count > eeprom->size)
> +		count = eeprom->size - offset;
> +
> +	if (read)
> +		rc = regmap_bulk_read(eeprom->regmap, offset,
> +				      buf, count/eeprom->stride);

This division will round down, so you could get one less byte than
what you expected, and the value you actually return. It seems like
there should be a check here, the count is a multiple of stride and
return an error if it is not.

> +	else
> +		rc = regmap_bulk_write(eeprom->regmap, offset,
> +				       buf, count/eeprom->stride);
> +
> +	if (IS_ERR_VALUE(rc))
> +		return 0;
> +

I don't think returning 0 here, and above is the best thing to
do. Return the real error code from regmap, or EINVAL or some other
error code for going off the end of the eerpom.

> +	return count;
> +}
> +
> +static ssize_t bin_attr_eeprom_read(struct file *filp, struct kobject *kobj,
> +				    struct bin_attribute *attr,
> +				    char *buf, loff_t offset, size_t count)
> +{
> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, true);
> +}
> +
> +static ssize_t bin_attr_eeprom_write(struct file *filp, struct kobject *kobj,
> +				     struct bin_attribute *attr,
> +				     char *buf, loff_t offset, size_t count)
> +{
> +	return bin_attr_eeprom_read_write(kobj, buf, offset, count, false);
> +}
> 

These two functions seem to be identical. So just have one of them?

+
> +static struct bin_attribute bin_attr_eeprom = {
> +	.attr	= {
> +		.name	= "eeprom",
> +		.mode	= 0660,

Symbolic values like S_IRUGO | S_IWUSR would be better.

Are you also sure you want group write?

> +	},
> +	.read	= bin_attr_eeprom_read,
> +	.write	= bin_attr_eeprom_write,
> +};
> +
> +static struct bin_attribute *eeprom_bin_attributes[] = {
> +	&bin_attr_eeprom,
> +	NULL,
> +};
> +
> +static const struct attribute_group eeprom_bin_group = {
> +	.bin_attrs	= eeprom_bin_attributes,
> +};
> +
> +static const struct attribute_group *eeprom_dev_groups[] = {
> +	&eeprom_bin_group,
> +	NULL,
> +};
> +
> +static struct class eeprom_class = {
> +	.name		= "eeprom",
> +	.dev_groups	= eeprom_dev_groups,
> +};
> +
> +int eeprom_register(struct eeprom_device *eeprom)
> +{
> +	int rval;
> +
> +	if (!eeprom->regmap || !eeprom->size) {
> +		dev_err(eeprom->dev, "Regmap not found\n");
> +		return -EINVAL;
> +	}
> +
> +	eeprom->id = ida_simple_get(&eeprom_ida, 0, 0, GFP_KERNEL);
> +	if (eeprom->id < 0)
> +		return eeprom->id;
> +
> +	eeprom->edev.class = &eeprom_class;
> +	eeprom->edev.parent = eeprom->dev;
> +	eeprom->edev.of_node = eeprom->dev ? eeprom->dev->of_node : NULL;
> +	dev_set_name(&eeprom->edev, "eeprom%d", eeprom->id);
> +
> +	device_initialize(&eeprom->edev);
> +
> +	dev_dbg(&eeprom->edev, "Registering eeprom device %s\n",
> +		dev_name(&eeprom->edev));
> +
> +	rval = device_add(&eeprom->edev);
> +	if (rval)
> +		return rval;
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_add(&eeprom->list, &eeprom_list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(eeprom_register);
> +
> +int eeprom_unregister(struct eeprom_device *eeprom)
> +{
> +	device_del(&eeprom->edev);
> +
> +	mutex_lock(&eeprom_list_mutex);
> +	list_del(&eeprom->list);
> +	mutex_unlock(&eeprom_list_mutex);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(eeprom_unregister);
> +
> +static struct eeprom_cell *__eeprom_cell_get(struct device_node *node,
> +					     int index)
> +{
> +	struct of_phandle_args args;
> +	struct eeprom_cell *cell;
> +	struct eeprom_device *e, *eeprom = NULL;
> +	int ret;
> +
> +	ret = of_parse_phandle_with_args(node, "eeproms",
> +					 "#eeprom-cells", index, &args);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	if (args.args_count != 2)
> +		return ERR_PTR(-EINVAL);
> +
> +	mutex_lock(&eeprom_list_mutex);
> +
> +	list_for_each_entry(e, &eeprom_list, list) {
> +		if (args.np == e->edev.of_node) {
> +			eeprom = e;
> +			break;
> +		}
> +	}
> +	mutex_unlock(&eeprom_list_mutex);

Shouldn't you increment a reference count to the eeprom here?  You are
going to have trouble if the eeprom is unregistered and there is a
call still referring to it.

> +
> +	if (!eeprom)
> +		return ERR_PTR(-EPROBE_DEFER);
> +
> +	cell = kzalloc(sizeof(*cell), GFP_KERNEL);
> +	if (!cell)
> +		return ERR_PTR(-ENOMEM);
> +
> +	cell->eeprom = eeprom;
> +	cell->offset = args.args[0];
> +	cell->count = args.args[1];
> +
> +	return cell;
> +}
> +
> +static struct eeprom_cell *__eeprom_cell_get_byname(struct device_node *node,
> +						    const char *id)
> +{
> +	int index = 0;
> +
> +	if (id)
> +		index = of_property_match_string(node,
> +						 "eeprom-names",
> +						 id);
> +	return __eeprom_cell_get(node, index);
> +
> +}
> +
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index)
> +{
> +	if (!dev)
> +		return ERR_PTR(-EINVAL);
> +
> +	/* First, attempt to retrieve the cell through the DT */
> +	if (dev->of_node)
> +		return __eeprom_cell_get(dev->of_node, index);
> +
> +	/* We don't support anything else yet */
> +	return ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL(eeprom_cell_get);
> +
> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev, const char *id)
> +{
> +	if (!dev)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (id && dev->of_node)
> +		return __eeprom_cell_get_byname(dev->of_node, id);
> +
> +	/* We don't support anything else yet */
> +	return ERR_PTR(-ENODEV);
> +}
> +EXPORT_SYMBOL(eeprom_cell_get_byname);
> +
> +void eeprom_cell_put(struct eeprom_cell *cell)
> +{
> +	kfree(cell);
> +}
> +EXPORT_SYMBOL(eeprom_cell_put);
> +
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len)
> +{
> +	struct eeprom_device *eeprom = cell->eeprom;
> +	char *buf;
> +	int rc;
> +
> +	if (!eeprom || !eeprom->regmap)
> +		return ERR_PTR(-EINVAL);
> +
> +	buf = kzalloc(cell->count, GFP_KERNEL);
> +	if (!buf)
> +		return ERR_PTR(-ENOMEM);
> +
> +	rc = regmap_bulk_read(eeprom->regmap, cell->offset,
> +			      buf, cell->count/eeprom->stride);

Same comment as above.

> +	if (IS_ERR_VALUE(rc)) {
> +		kfree(buf);
> +		return ERR_PTR(rc);
> +	}
> +
> +	*len = cell->count;
> +
> +	return buf;
> +}
> +EXPORT_SYMBOL(eeprom_cell_read);
> +
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len)
> +{
> +	struct eeprom_device *eeprom = cell->eeprom;
> +
> +	if (!eeprom || !eeprom->regmap)
> +		return -EINVAL;
> +
> +	return regmap_bulk_write(eeprom->regmap, cell->offset,
> +				 buf, cell->count/eeprom->stride);
> +}
> +EXPORT_SYMBOL(eeprom_cell_write);
> +
> +static int eeprom_init(void)
> +{
> +	return class_register(&eeprom_class);
> +}
> +
> +static void eeprom_exit(void)
> +{
> +	class_unregister(&eeprom_class);
> +}
> +
> +subsys_initcall(eeprom_init);
> +module_exit(eeprom_exit);
> +
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org");
> +MODULE_DESCRIPTION("EEPROM Driver Core");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/eeprom-consumer.h b/include/linux/eeprom-consumer.h
> new file mode 100644
> index 0000000..706ae9d
> --- /dev/null
> +++ b/include/linux/eeprom-consumer.h
> @@ -0,0 +1,73 @@
> +/*
> + * EEPROM framework consumer.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_CONSUMER_H
> +#define _LINUX_EEPROM_CONSUMER_H
> +
> +struct eeprom_cell;
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given index.

of a device for a 

> + *
> + * @dev: Device that will be interacted with
> + * @index: Index of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get(struct device *dev, int index);
> +
> +/**
> + * eeprom_cell_get(): Get eeprom cell of device form a given name.

same again

> + *
> + * @dev: Device that will be interacted with
> + * @name: Name of the eeprom cell.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a struct eeprom_cell.  The eeprom_cell will be freed by the
> + * eeprom_cell_put().
> + */
> +struct eeprom_cell *eeprom_cell_get_byname(struct device *dev,
> +					   const char *name);
> +
> +/**
> + * eeprom_cell_put(): Release previously allocated eeprom cell.
> + *
> + * @cell: Previously allocated eeprom cell by eeprom_cell_get()
> + * or eeprom_cell_get_byname().
> + */
> +void eeprom_cell_put(struct eeprom_cell *cell);
> +
> +/**
> + * eeprom_cell_read(): Read a given eeprom cell
> + *
> + * @cell: eeprom cell to be read.
> + * @len: pointer to length of cell which will be populated on successful read.
> + *
> + * The return value will be an ERR_PTR() on error or a valid pointer
> + * to a char * bufffer.  The buffer should be freed by the consumer with a
> + * kfree().
> + */
> +char *eeprom_cell_read(struct eeprom_cell *cell, ssize_t *len);

Would void * be better than char *? I guess the contents is mostly
data, not strings.

      Andrew
 
> +
> +/**
> + * eeprom_cell_write(): Write to a given eeprom cell
> + *
> + * @cell: eeprom cell to be written.
> + * @buf: Buffer to be written.
> + * @len: length of buffer to be written to eeprom cell.
> + *
> + * The return value will be an non zero on error or a zero on successful write.
> + */
> +int eeprom_cell_write(struct eeprom_cell *cell, const char *buf, ssize_t len);
> +
> +#endif  /* ifndef _LINUX_EEPROM_CONSUMER_H */
> diff --git a/include/linux/eeprom-provider.h b/include/linux/eeprom-provider.h
> new file mode 100644
> index 0000000..3943c2f
> --- /dev/null
> +++ b/include/linux/eeprom-provider.h
> @@ -0,0 +1,51 @@
> +/*
> + * EEPROM framework provider.
> + *
> + * Copyright (C) 2015 Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + * Copyright (C) 2013 Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2.  This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef _LINUX_EEPROM_PROVIDER_H
> +#define _LINUX_EEPROM_PROVIDER_H
> +
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +#include <linux/list.h>
> +
> +struct eeprom_device {
> +	struct regmap		*regmap;
> +	int			stride;
> +	size_t			size;
> +	struct device		*dev;
> +
> +	/* Internal to framework */
> +	struct device		edev;
> +	int			id;
> +	struct list_head	list;
> +};
> +
> +/**
> + * eeprom_register(): Register a eeprom device for given eeprom.
> + * Also creates an binary entry in /sys/class/eeprom/eeprom[id]/eeprom
> + *
> + * @eeprom: eeprom device that needs to be created
> + *
> + * The return value will be an error code on error or a zero on success.
> + * The eeprom_device and sysfs entery will be freed by the eeprom_unregister().
> + */
> +int eeprom_register(struct eeprom_device *eeprom);
> +
> +/**
> + * eeprom_unregister(): Unregister previously registered eeprom device
> + *
> + * @eeprom: Pointer to previously registered eeprom device.
> + *
> + * The return value will be an non zero on error or a zero on success.
> + */
> +int eeprom_unregister(struct eeprom_device *eeprom);
> +
> +#endif  /* ifndef _LINUX_EEPROM_PROVIDER_H */
> -- 
> 1.9.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [RFC PATCH 3/3] eeprom: qfprom: Add Qualcomm QFPROM support.
From: Srinivas Kandagatla @ 2015-02-19 17:08 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, Srinivas Kandagatla
In-Reply-To: <1424365639-26634-1-git-send-email-srinivas.kandagatla@linaro.org>

This patch adds QFPROM support driver which is used by other drivers
like thermal sensor and cpufreq.

On MSM parts there are some efuses (called qfprom) these fuses store things like
calibration data, speed bins.. etc. Drivers like cpufreq, thermal sensors would
read out this data for configuring the driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/eeprom/Kconfig  |  6 ++++
 drivers/eeprom/Makefile |  1 +
 drivers/eeprom/qfprom.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)
 create mode 100644 drivers/eeprom/qfprom.c

diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 39235a9..b0c94cb 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -26,4 +26,10 @@ config EEPROM_SUNXI_SID
 	  This driver can also be built as a module. If so, the module
 	  will be called sunxi_sid.
 
+config QCOM_QFPROM
+	tristate "QCOM QFPROM Support"
+        depends on EEPROM
+	help
+          Say y here to enable QFPROM support. The QFPROM provides access
+          functions for QFPROM data to rest of the drivers via eeprom interface.
 endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index 661422c..f99c824 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_EEPROM)		+= core.o
 
 # Devices
 obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
+obj-$(CONFIG_QCOM_QFPROM)	+= qfprom.o
diff --git a/drivers/eeprom/qfprom.c b/drivers/eeprom/qfprom.c
new file mode 100644
index 0000000..da31b36
--- /dev/null
+++ b/drivers/eeprom/qfprom.c
@@ -0,0 +1,75 @@
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/eeprom-provider.h>
+
+static struct regmap_config qfprom_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static int qfprom_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static int qfprom_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	void __iomem *base;
+	struct device *dev = &pdev->dev;
+	struct eeprom_device *eeprom;
+	int rval;
+
+	eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
+	if (!eeprom)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	qfprom_regmap_config.max_register = resource_size(res) - 1;
+
+	eeprom->regmap = devm_regmap_init_mmio(dev, base,
+					       &qfprom_regmap_config);
+	if (IS_ERR(eeprom->regmap)) {
+		dev_err(dev, "regmap init failed\n");
+		return PTR_ERR(eeprom->regmap);
+	}
+
+	eeprom->dev = dev;
+	eeprom->stride = qfprom_regmap_config.reg_stride;
+	eeprom->size = resource_size(res) - 1;
+	rval = eeprom_register(eeprom);
+	if (rval)
+		return rval;
+
+	platform_set_drvdata(pdev, eeprom);
+	return 0;
+}
+
+static const struct of_device_id qfprom_of_match[] = {
+	{ .compatible = "qcom,qfprom"},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, qfprom_of_match);
+
+static struct platform_driver qfprom_driver = {
+	.probe = qfprom_probe,
+	.remove = qfprom_remove,
+	.driver = {
+		.name = "qcom,qfprom",
+		.of_match_table = qfprom_of_match,
+	},
+};
+module_platform_driver(qfprom_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm QFPROM driver");
+MODULE_LICENSE("GPL2");
-- 
1.9.1

^ permalink raw reply related

* [RFC PATCH 2/3] eeprom: sunxi: Move the SID driver to the eeprom framework
From: Srinivas Kandagatla @ 2015-02-19 17:08 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, Rob Herring, Pawel Moll, Kumar Gala, linux-api,
	linux-kernel, devicetree, Stephen Boyd, Arnd Bergmann, broonie,
	Greg Kroah-Hartman, Srinivas Kandagatla
In-Reply-To: <1424365639-26634-1-git-send-email-srinivas.kandagatla@linaro.org>

From: Maxime Ripard <maxime.ripard@free-electrons.com>

Now that we have the EEPROM framework, we can consolidate the common driver
code. Move the driver to the framework, and hopefully, it will fix the sysfs
file creation race.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
[srinivas.kandagatla: Moved to regmap based EEPROM framework]
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/ABI/testing/sysfs-driver-sunxi-sid |  22 ----
 drivers/eeprom/Kconfig                           |  10 ++
 drivers/eeprom/Makefile                          |   1 +
 drivers/eeprom/eeprom-sunxi-sid.c                | 125 ++++++++++++++++++
 drivers/misc/eeprom/Kconfig                      |  13 --
 drivers/misc/eeprom/Makefile                     |   1 -
 drivers/misc/eeprom/sunxi_sid.c                  | 156 -----------------------
 7 files changed, 136 insertions(+), 192 deletions(-)
 delete mode 100644 Documentation/ABI/testing/sysfs-driver-sunxi-sid
 create mode 100644 drivers/eeprom/eeprom-sunxi-sid.c
 delete mode 100644 drivers/misc/eeprom/sunxi_sid.c

diff --git a/Documentation/ABI/testing/sysfs-driver-sunxi-sid b/Documentation/ABI/testing/sysfs-driver-sunxi-sid
deleted file mode 100644
index ffb9536..0000000
--- a/Documentation/ABI/testing/sysfs-driver-sunxi-sid
+++ /dev/null
@@ -1,22 +0,0 @@
-What:		/sys/devices/*/<our-device>/eeprom
-Date:		August 2013
-Contact:	Oliver Schinagl <oliver@schinagl.nl>
-Description:	read-only access to the SID (Security-ID) on current
-		A-series SoC's from Allwinner. Currently supports A10, A10s, A13
-		and A20 CPU's. The earlier A1x series of SoCs exports 16 bytes,
-		whereas the newer A20 SoC exposes 512 bytes split into sections.
-		Besides the 16 bytes of SID, there's also an SJTAG area,
-		HDMI-HDCP key and some custom keys. Below a quick overview, for
-		details see the user manual:
-		0x000  128 bit root-key (sun[457]i)
-		0x010  128 bit boot-key (sun7i)
-		0x020   64 bit security-jtag-key (sun7i)
-		0x028   16 bit key configuration (sun7i)
-		0x02b   16 bit custom-vendor-key (sun7i)
-		0x02c  320 bit low general key (sun7i)
-		0x040   32 bit read-control access (sun7i)
-		0x064  224 bit low general key (sun7i)
-		0x080 2304 bit HDCP-key (sun7i)
-		0x1a0  768 bit high general key (sun7i)
-Users:		any user space application which wants to read the SID on
-		Allwinner's A-series of CPU's.
diff --git a/drivers/eeprom/Kconfig b/drivers/eeprom/Kconfig
index 2c5452a..39235a9 100644
--- a/drivers/eeprom/Kconfig
+++ b/drivers/eeprom/Kconfig
@@ -16,4 +16,14 @@ config EEPROM_DEBUG
 	help
 	  Say yes here to enable debugging support.
 
+config EEPROM_SUNXI_SID
+	depends on ARCH_SUNXI
+	tristate "Allwinner SoCs SID support"
+	help
+	  This is a driver for the 'security ID' available on various Allwinner
+	  devices.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called sunxi_sid.
+
 endif
diff --git a/drivers/eeprom/Makefile b/drivers/eeprom/Makefile
index e130079..661422c 100644
--- a/drivers/eeprom/Makefile
+++ b/drivers/eeprom/Makefile
@@ -7,3 +7,4 @@ ccflags-$(CONFIG_EEPROM_DEBUG) += -DDEBUG
 obj-$(CONFIG_EEPROM)		+= core.o
 
 # Devices
+obj-$(CONFIG_EEPROM_SUNXI_SID)	+= eeprom-sunxi-sid.o
diff --git a/drivers/eeprom/eeprom-sunxi-sid.c b/drivers/eeprom/eeprom-sunxi-sid.c
new file mode 100644
index 0000000..f2939b9
--- /dev/null
+++ b/drivers/eeprom/eeprom-sunxi-sid.c
@@ -0,0 +1,125 @@
+/*
+ * Allwinner sunXi SoCs Security ID support.
+ *
+ * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/eeprom-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct eeprom_sid {
+	void __iomem	*membase;
+	struct eeprom_device eeprom;
+};
+
+/* We read the entire key, due to a 32 bit read alignment requirement. Since we
+ * want to return the requested byte, this results in somewhat slower code and
+ * uses 4 times more reads as needed but keeps code simpler. Since the SID is
+ * only very rarely probed, this is not really an issue.
+ */
+static int sunxi_sid_reg_read(void *context,
+			      unsigned int offset, unsigned int *val)
+{
+	struct eeprom_sid *sid  = context;
+	u32 sid_key;
+
+	sid_key = ioread32be(sid->membase + round_down(offset, 4));
+	sid_key >>= (offset % 4) * 8;
+
+	*val = sid_key;
+
+	return 0;
+}
+
+static bool sunxi_sid_writeable_reg(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct of_device_id sunxi_sid_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
+	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
+	{/* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
+
+static struct regmap_config sunxi_sid_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_stride = 1,
+	.reg_read = sunxi_sid_reg_read,
+	.writeable_reg = sunxi_sid_writeable_reg,
+};
+
+static int sunxi_sid_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *device;
+	struct eeprom_sid *sid;
+	struct resource *res;
+	struct eeprom_device *eeprom;
+	struct device *dev = &pdev->dev;
+	int rval;
+
+	sid = devm_kzalloc(dev, sizeof(*sid), GFP_KERNEL);
+	if (!sid)
+		return -ENOMEM;
+
+	eeprom = &sid->eeprom;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sid->membase = devm_ioremap_resource(dev, res);
+	if (IS_ERR(sid->membase))
+		return PTR_ERR(sid->membase);
+
+	device = of_match_device(sunxi_sid_of_match, dev);
+	if (!device)
+		return -ENODEV;
+
+	sunxi_sid_regmap_config.max_register = (unsigned int)device->data - 1;
+
+	eeprom->regmap = devm_regmap_init(dev, NULL,
+					  sid, &sunxi_sid_regmap_config);
+	if (IS_ERR(eeprom->regmap))
+		return PTR_ERR(eeprom->regmap);
+
+	eeprom->dev = dev;
+	eeprom->stride = sunxi_sid_regmap_config.reg_stride;
+	eeprom->size = sunxi_sid_regmap_config.max_register;
+	rval = eeprom_register(eeprom);
+	if (rval)
+		return rval;
+
+	platform_set_drvdata(pdev, eeprom);
+
+	return 0;
+}
+
+static int sunxi_sid_remove(struct platform_device *pdev)
+{
+	struct eeprom_device *eeprom = platform_get_drvdata(pdev);
+
+	return eeprom_unregister(eeprom);
+}
+
+static struct platform_driver sunxi_sid_driver = {
+	.probe = sunxi_sid_probe,
+	.remove = sunxi_sid_remove,
+	.driver = {
+		.name = "sunxi-sid",
+		.of_match_table = sunxi_sid_of_match,
+	},
+};
+module_platform_driver(sunxi_sid_driver);
+
+MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
+MODULE_DESCRIPTION("Allwinner sunxi security id driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..04f2e1f 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -96,17 +96,4 @@ config EEPROM_DIGSY_MTC_CFG
 
 	  If unsure, say N.
 
-config EEPROM_SUNXI_SID
-	tristate "Allwinner sunxi security ID support"
-	depends on ARCH_SUNXI && SYSFS
-	help
-	  This is a driver for the 'security ID' available on various Allwinner
-	  devices.
-
-	  Due to the potential risks involved with changing e-fuses,
-	  this driver is read-only.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called sunxi_sid.
-
 endmenu
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..fc1e81d 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -4,5 +4,4 @@ obj-$(CONFIG_EEPROM_LEGACY)	+= eeprom.o
 obj-$(CONFIG_EEPROM_MAX6875)	+= max6875.o
 obj-$(CONFIG_EEPROM_93CX6)	+= eeprom_93cx6.o
 obj-$(CONFIG_EEPROM_93XX46)	+= eeprom_93xx46.o
-obj-$(CONFIG_EEPROM_SUNXI_SID)	+= sunxi_sid.o
 obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o
diff --git a/drivers/misc/eeprom/sunxi_sid.c b/drivers/misc/eeprom/sunxi_sid.c
deleted file mode 100644
index 8385177..0000000
--- a/drivers/misc/eeprom/sunxi_sid.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2013 Oliver Schinagl <oliver@schinagl.nl>
- * http://www.linux-sunxi.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * This driver exposes the Allwinner security ID, efuses exported in byte-
- * sized chunks.
- */
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kobject.h>
-#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-
-#define DRV_NAME "sunxi-sid"
-
-struct sunxi_sid_data {
-	void __iomem *reg_base;
-	unsigned int keysize;
-};
-
-/* We read the entire key, due to a 32 bit read alignment requirement. Since we
- * want to return the requested byte, this results in somewhat slower code and
- * uses 4 times more reads as needed but keeps code simpler. Since the SID is
- * only very rarely probed, this is not really an issue.
- */
-static u8 sunxi_sid_read_byte(const struct sunxi_sid_data *sid_data,
-			      const unsigned int offset)
-{
-	u32 sid_key;
-
-	if (offset >= sid_data->keysize)
-		return 0;
-
-	sid_key = ioread32be(sid_data->reg_base + round_down(offset, 4));
-	sid_key >>= (offset % 4) * 8;
-
-	return sid_key; /* Only return the last byte */
-}
-
-static ssize_t sid_read(struct file *fd, struct kobject *kobj,
-			struct bin_attribute *attr, char *buf,
-			loff_t pos, size_t size)
-{
-	struct platform_device *pdev;
-	struct sunxi_sid_data *sid_data;
-	int i;
-
-	pdev = to_platform_device(kobj_to_dev(kobj));
-	sid_data = platform_get_drvdata(pdev);
-
-	if (pos < 0 || pos >= sid_data->keysize)
-		return 0;
-	if (size > sid_data->keysize - pos)
-		size = sid_data->keysize - pos;
-
-	for (i = 0; i < size; i++)
-		buf[i] = sunxi_sid_read_byte(sid_data, pos + i);
-
-	return i;
-}
-
-static struct bin_attribute sid_bin_attr = {
-	.attr = { .name = "eeprom", .mode = S_IRUGO, },
-	.read = sid_read,
-};
-
-static int sunxi_sid_remove(struct platform_device *pdev)
-{
-	device_remove_bin_file(&pdev->dev, &sid_bin_attr);
-	dev_dbg(&pdev->dev, "driver unloaded\n");
-
-	return 0;
-}
-
-static const struct of_device_id sunxi_sid_of_match[] = {
-	{ .compatible = "allwinner,sun4i-a10-sid", .data = (void *)16},
-	{ .compatible = "allwinner,sun7i-a20-sid", .data = (void *)512},
-	{/* sentinel */},
-};
-MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
-
-static int sunxi_sid_probe(struct platform_device *pdev)
-{
-	struct sunxi_sid_data *sid_data;
-	struct resource *res;
-	const struct of_device_id *of_dev_id;
-	u8 *entropy;
-	unsigned int i;
-
-	sid_data = devm_kzalloc(&pdev->dev, sizeof(struct sunxi_sid_data),
-				GFP_KERNEL);
-	if (!sid_data)
-		return -ENOMEM;
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	sid_data->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(sid_data->reg_base))
-		return PTR_ERR(sid_data->reg_base);
-
-	of_dev_id = of_match_device(sunxi_sid_of_match, &pdev->dev);
-	if (!of_dev_id)
-		return -ENODEV;
-	sid_data->keysize = (int)of_dev_id->data;
-
-	platform_set_drvdata(pdev, sid_data);
-
-	sid_bin_attr.size = sid_data->keysize;
-	if (device_create_bin_file(&pdev->dev, &sid_bin_attr))
-		return -ENODEV;
-
-	entropy = kzalloc(sizeof(u8) * sid_data->keysize, GFP_KERNEL);
-	for (i = 0; i < sid_data->keysize; i++)
-		entropy[i] = sunxi_sid_read_byte(sid_data, i);
-	add_device_randomness(entropy, sid_data->keysize);
-	kfree(entropy);
-
-	dev_dbg(&pdev->dev, "loaded\n");
-
-	return 0;
-}
-
-static struct platform_driver sunxi_sid_driver = {
-	.probe = sunxi_sid_probe,
-	.remove = sunxi_sid_remove,
-	.driver = {
-		.name = DRV_NAME,
-		.of_match_table = sunxi_sid_of_match,
-	},
-};
-module_platform_driver(sunxi_sid_driver);
-
-MODULE_AUTHOR("Oliver Schinagl <oliver@schinagl.nl>");
-MODULE_DESCRIPTION("Allwinner sunxi security id driver");
-MODULE_LICENSE("GPL");
-- 
1.9.1

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox