LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device
@ 2015-01-12 12:34 Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor Chanwoo Choi
                   ` (9 more replies)
  0 siblings, 10 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patchset add new devfreq_event class to provide raw data to determine
current utilization of device  which is used for devfreq governor.

The following description explains the feature of two kind of devfreq class:
- devfreq class (existing)
 : devfreq consumer device use raw data from devfreq_event device for
   determining proper current system state and change voltage/frequency
   dynamically using various governors.
- devfreq_event class (new)
 : Provide measured raw data to devfreq device for governor

---------
Changelog:

Changes from v7:
(https://lkml.org/lkml/2015/1/7/795)
- Use EXPORT_SYMBOL_GPL macro instead of EXPORT_SYMBOL
- Fix the binding document of exynos-ppmu.c driver
- Drop the devfreq-event type patch because it isnt' clear
- Fix bug of devfreq_event_add_edev() when fail to execute device_register()
- Modify resource free operation on following functions:
  : devfreq_event_remove_edev()
  : devfreq_event_release_edev()

Changes from v6:
(https://lkml.org/lkml/2014/12/28/139)
- This patchset is based on v3.19-rc3.
1. devfreq-event class driver
- Fix build break if devfreq-event framework is off
- Add resource-managed function for devfreq-event device
: devm_devfreq_event_add_edev()
: devm_devfreq_event_remove_edev()

Changes from v5:
(https://lkml.org/lkml/2014/12/22/527)
- Rebase these patch-set on v3.19-rc1 and Test it.
1. exynos-ppmu.c
- Change the error value when of_iomap() fail to map the memory
- Remove owner setting of platform_driver
- Add exynos_ppmu_disable() function
2. exynos dts file
- Add PPMU node to Exynos3250-based Monk board
- Remove ppmu_cpu node on Exynos4412-based TRATS2 board and add ppmu_leftbus/rightbus node

Changes from v4:
(https://lkml.org/lkml/2014/12/16/511)
1. devfreq-event class driver
- Add devfreq_event_get_edev_count() function
- Modify the simple description of devfreq-event framework in devfreq-event.c
- Minimize the usage range of global lock usage in devfreq_event_add_edev()
- Remove '_is_enabled()' function pointer in devfreq_event_ops structure
- Add separte CONFIG_PM_DEVFREQ_EVENT configuration
- Add new devfreq-event.h header file including devfreq-event helper functions
2. exynos dts file
- Add new patch to support PPMU with DEVFREQ-event on Exynos4412-based TRATS2

Changes from v3:
(https://lkml.org/lkml/2014/12/12/219)
1. devfreq-event class driver
- Fix return value of devfreq_event_get_event()
- Add new structure devfreq_event_data for devfreq_event_get_event()
- Modify the prototype of devfreq_event_get_event() function
- Call of_node_put after calling of_parse_phandle() to decrement refcount
2. exynos-ppmu driver
- Modify usage of devfreq_event_get_event() function
  according to new prototype of this funciton
- Add the additional description to exynos-ppmu.txt how to add PPMU node
  in board dts file
- Use 'PPMU_EVENT' macro to remove duplicate codes
- Add the support of PPMU for Exynos5260
3. exynos dts file
- Add missing PPMU_FSYS node to exynos3250.dtsi
- Fix 'ppmu_mfc_l' node name as 'ppmu_mfc' because exynos3250 has only one MFC IP.
- Add missing PPMU_ACP/G3D to exynos4.dtsi
4. etc
- Fix wrong abbreviation of PPMU (PPMU :Platform Performance Monitoring Unit)
- Add new patch to support the PPMU of Exynos5260 SoC

Changes from v2:
(https://lkml.org/lkml/2014/12/9/304)
1. devfreq-event class driver
- Rename all the helper functions of devfreq-event device
- Add devfreq_event_remove_edev() instead of devfreq_put_event_dev()
- Add devfreq_event_release_edev() to initialize it before put device
- Add the detailed description of devfreq-event API
- Add the attributes of devfreq-event class (enable_count)
- Check the overflow about event/total_event data in devfreq_event_get_event()
- Remove the 'exclusive flag' feature
- Set set_event()/get_event() functions as mandary
- Add missing of_node_put() call
- Change variable type of 'get_event()' funciton from 'int' to 'u64'
2. exynos-ppmu driver
- Remove un-used field (struct devfreq)
- Use 'of_get_child_by_name()' instead of 'of_find_node_by_name()'
- Add missing of_node_put() call
- Fix wrong clock control
- Use devfreq_event_remove_edev() instead of devfreq_remove_device()
- Add the documentation for exynos-ppmu driver
- Remove 'enable/disable/is_enabled/reset' function of exynos-ppmu driver
3. exynos3250-rinato.dts
- Add ppmu_{leftbus|rightbus} dt node and remove ppmu_cpu dt node

Changes from v1:
(https://lkml.org/lkml/2014/9/5/11)
- Code clean
- Add the description of devfreq-event structure
- Add 'is_enabled' function to devfreq_event_ops structure
- Add 'enable_count' field to devfreq_event_dev structure
- Check whether devfreq-event device is enabled or not
  during calling devfreq_event API
- Define the type of devfreq-event device as following
  : DEVFREQ_EVENT_TYPE_RAW_DATA
  : DEVFREQ_EVENT_TYPE_UTILIZATION
  : DEVFREQ_EVENT_TYPE_BANDWIDTH
  : DEVFREQ_EVENT_TYPE_LATENCY
- Add the exclusive feature of devfreq-event device.
  If devfreq-event device is used on only on devfreq driver,
  should used 'devfreq_enable_event_dev_exclusive()' function
- Add new patch6 for test on Exynos3250-based Rinato board

Chanwoo Choi (9):
  devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor
  devfreq: event: Add resource-managed function for devfreq-event device
  devfreq: event: Add exynos-ppmu devfreq-event driver
  devfreq: event: Add documentation for exynos-ppmu devfreq-event driver
  ARM: dts: Add PPMU dt node for Exynos3250 SoC
  ARM: dts: Add PPMU dt node for Exynos4 SoCs
  ARM: dts: Add PPMU dt node for Exynos5260 SoC
  ARM: dts: exynos: Add PPMU node to Exynos3250-based Rinato/Monk board
  ARM: dts: exynos: Add PPMU node for Exynos4412-based TRATS2 board

 .../bindings/devfreq/event/exynos-ppmu.txt         | 110 +++++
 arch/arm/boot/dts/exynos3250-monk.dts              |  40 ++
 arch/arm/boot/dts/exynos3250-rinato.dts            |  40 ++
 arch/arm/boot/dts/exynos3250.dtsi                  |  74 +++
 arch/arm/boot/dts/exynos4.dtsi                     | 108 +++++
 arch/arm/boot/dts/exynos4210.dtsi                  |   8 +
 arch/arm/boot/dts/exynos4412-trats2.dts            |  40 ++
 arch/arm/boot/dts/exynos5260.dtsi                  |  90 ++++
 drivers/devfreq/Kconfig                            |   2 +
 drivers/devfreq/Makefile                           |   6 +-
 drivers/devfreq/devfreq-event.c                    | 511 +++++++++++++++++++++
 drivers/devfreq/event/Kconfig                      |  25 +
 drivers/devfreq/event/Makefile                     |   2 +
 drivers/devfreq/event/exynos-ppmu.c                | 398 ++++++++++++++++
 include/linux/devfreq-event.h                      | 186 ++++++++
 15 files changed, 1639 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt
 create mode 100644 drivers/devfreq/devfreq-event.c
 create mode 100644 drivers/devfreq/event/Kconfig
 create mode 100644 drivers/devfreq/event/Makefile
 create mode 100644 drivers/devfreq/event/exynos-ppmu.c
 create mode 100644 include/linux/devfreq-event.h

-- 
1.8.5.5


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

* [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-19 10:12   ` Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 2/9] devfreq: event: Add resource-managed function for devfreq-event device Chanwoo Choi
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patch add new devfreq_event class for devfreq_event device which provide
raw data (e.g., memory bus utilization/GPU utilization). This raw data from
devfreq_event data would be used for the governor of devfreq subsystem.
- devfreq_event device : Provide raw data for governor of existing devfreq device
- devfreq device       : Monitor device state and change frequency/voltage of device
                         using the raw data from devfreq_event device

The devfreq subsystem support generic DVFS(Dynamic Voltage/Frequency Scaling)
for Non-CPU Devices. The devfreq device would dertermine current device state
using various governor (e.g., ondemand, performance, powersave). After completed
determination of system state, devfreq device would change the frequency/voltage
of devfreq device according to the result of governor.

But, devfreq governor must need basic data which indicates current device state.
Existing devfreq subsystem only consider devfreq device which check current system
state and determine proper system state using basic data. There is no subsystem
for device providing basic data to devfreq device.

The devfreq subsystem must need devfreq_event device(data-provider device) for
existing devfreq device. So, this patch add new devfreq_event class for
devfreq_event device which read various basic data(e.g, memory bus utilization,
GPU utilization) and provide measured data to existing devfreq device through
standard APIs of devfreq_event class.

The following description explains the feature of two kind of devfreq class:
- devfreq class (existing)
 : devfreq consumer device use raw data from devfreq_event device for
   determining proper current system state and change voltage/frequency
   dynamically using various governors.

- devfreq_event class (new)
 : Provide measured raw data to devfreq device for governor

Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/devfreq/Kconfig         |   2 +
 drivers/devfreq/Makefile        |   6 +-
 drivers/devfreq/devfreq-event.c | 448 ++++++++++++++++++++++++++++++++++++++++
 drivers/devfreq/event/Kconfig   |  16 ++
 drivers/devfreq/event/Makefile  |   1 +
 include/linux/devfreq-event.h   | 170 +++++++++++++++
 6 files changed, 642 insertions(+), 1 deletion(-)
 create mode 100644 drivers/devfreq/devfreq-event.c
 create mode 100644 drivers/devfreq/event/Kconfig
 create mode 100644 drivers/devfreq/event/Makefile
 create mode 100644 include/linux/devfreq-event.h

diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index faf4e70..21f8f17 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -87,4 +87,6 @@ config ARM_EXYNOS5_BUS_DEVFREQ
 	  It reads PPMU counters of memory controllers and adjusts the
 	  operating frequencies and voltages with OPP support.
 
+source "drivers/devfreq/event/Kconfig"
+
 endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 16138c9..c449336 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -1,4 +1,5 @@
-obj-$(CONFIG_PM_DEVFREQ)	+= devfreq.o
+obj-$(CONFIG_PM_DEVFREQ)		+= devfreq.o
+obj-$(CONFIG_PM_DEVFREQ_EVENT)		+= devfreq-event.o
 obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)	+= governor_simpleondemand.o
 obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)	+= governor_performance.o
 obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
@@ -7,3 +8,6 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
 # DEVFREQ Drivers
 obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos/
 obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)	+= exynos/
+
+# DEVFREQ Event Drivers
+obj-$(CONFIG_PM_DEVFREQ_EVENT)		+= event/
diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c
new file mode 100644
index 0000000..9ba5ba4
--- /dev/null
+++ b/drivers/devfreq/devfreq-event.c
@@ -0,0 +1,448 @@
+/*
+ * devfreq-event: a framework to provide raw data and events of devfreq devices
+ *
+ * Copyright (C) 2014 Samsung Electronics
+ * Author: Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver is based on drivers/devfreq/devfreq.c.
+ */
+
+#include <linux/devfreq-event.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/of.h>
+
+static struct class *devfreq_event_class;
+
+/* The list of all devfreq event list */
+static LIST_HEAD(devfreq_event_list);
+static DEFINE_MUTEX(devfreq_event_list_lock);
+
+#define to_devfreq_event(DEV) container_of(DEV, struct devfreq_event_dev, dev)
+
+/**
+ * devfreq_event_enable_edev() - Enable the devfreq-event dev and increase
+ *				 the enable_count of devfreq-event dev.
+ * @edev	: the devfreq-event device
+ *
+ * Note that this function increase the enable_count and enable the
+ * devfreq-event device. The devfreq-event device should be enabled before
+ * using it by devfreq device.
+ */
+int devfreq_event_enable_edev(struct devfreq_event_dev *edev)
+{
+	int ret = 0;
+
+	if (!edev || !edev->desc)
+		return -EINVAL;
+
+	mutex_lock(&edev->lock);
+	if (edev->desc->ops && edev->desc->ops->enable) {
+		ret = edev->desc->ops->enable(edev);
+		if (ret < 0)
+			goto err;
+	}
+	edev->enable_count++;
+err:
+	mutex_unlock(&edev->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_enable_edev);
+
+/**
+ * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease
+ *				  the enable_count of the devfreq-event dev.
+ * @edev	: the devfreq-event device
+ *
+ * Note that this function decrease the enable_count and disable the
+ * devfreq-event device. After the devfreq-event device is disabled,
+ * devfreq device can't use the devfreq-event device for get/set/reset
+ * operations.
+ */
+int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
+{
+	int ret = 0;
+
+	if (!edev || !edev->desc)
+		return -EINVAL;
+
+	mutex_lock(&edev->lock);
+	if (edev->enable_count > 0) {
+		edev->enable_count--;
+	} else {
+		dev_warn(&edev->dev, "unbalanced enable_count\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (edev->desc->ops && edev->desc->ops->disable) {
+		ret = edev->desc->ops->disable(edev);
+		if (ret < 0) {
+			edev->enable_count++;
+			goto err;
+		}
+	}
+err:
+	mutex_unlock(&edev->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_disable_edev);
+
+/**
+ * devfreq_event_is_enabled() - Check whether devfreq-event dev is enabled or
+ *				not.
+ * @edev	: the devfreq-event device
+ *
+ * Note that this function check whether devfreq-event dev is enabled or not.
+ * If return true, the devfreq-event dev is enabeld. If return false, the
+ * devfreq-event dev is disabled.
+ */
+bool devfreq_event_is_enabled(struct devfreq_event_dev *edev)
+{
+	bool enabled = false;
+
+	if (!edev || !edev->desc)
+		return enabled;
+
+	mutex_lock(&edev->lock);
+
+	if (edev->enable_count > 0)
+		enabled = true;
+
+	mutex_unlock(&edev->lock);
+
+	return enabled;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_is_enabled);
+
+/**
+ * devfreq_event_set_event() - Set event to devfreq-event dev to start.
+ * @edev	: the devfreq-event device
+ *
+ * Note that this function set the event to the devfreq-event device to start
+ * for getting the event data which could be various event type.
+ */
+int devfreq_event_set_event(struct devfreq_event_dev *edev)
+{
+	int ret;
+
+	if (!edev || !edev->desc)
+		return -EINVAL;
+
+	if (!edev->desc->ops || !edev->desc->ops->set_event)
+		return -EINVAL;
+
+	if (!devfreq_event_is_enabled(edev))
+		return -EPERM;
+
+	mutex_lock(&edev->lock);
+	ret = edev->desc->ops->set_event(edev);
+	mutex_unlock(&edev->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_set_event);
+
+/**
+ * devfreq_event_get_event() - Get event and total_event from devfreq-event dev.
+ * @edev	: the devfreq-event device
+ * @edata	: the calculated data of devfreq-event device
+ *
+ * Note that this function get the calculated event data from devfreq-event dev
+ * after stoping the progress of whole sequence of devfreq-event dev.
+ */
+int devfreq_event_get_event(struct devfreq_event_dev *edev,
+			    struct devfreq_event_data *edata)
+{
+	int ret;
+
+	if (!edev || !edev->desc)
+		return -EINVAL;
+
+	if (!edev->desc->ops || !edev->desc->ops->get_event)
+		return -EINVAL;
+
+	if (!devfreq_event_is_enabled(edev))
+		return -EINVAL;
+
+	edata->event = edata->total_event = 0;
+
+	mutex_lock(&edev->lock);
+	ret = edev->desc->ops->get_event(edev, edata);
+	mutex_unlock(&edev->lock);
+
+	if ((edata->total_event <= 0)
+		|| (edata->event > edata->total_event)) {
+		edata->event = edata->total_event = 0;
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_get_event);
+
+/**
+ * devfreq_event_reset_event() - Reset all opeations of devfreq-event dev.
+ * @edev	: the devfreq-event device
+ *
+ * Note that this function stop all operations of devfreq-event dev and reset
+ * the current event data to make the devfreq-event device into initial state.
+ */
+int devfreq_event_reset_event(struct devfreq_event_dev *edev)
+{
+	int ret = 0;
+
+	if (!edev || !edev->desc)
+		return -EINVAL;
+
+	if (!devfreq_event_is_enabled(edev))
+		return -EPERM;
+
+	mutex_lock(&edev->lock);
+	if (edev->desc->ops && edev->desc->ops->reset)
+		ret = edev->desc->ops->reset(edev);
+	mutex_unlock(&edev->lock);
+
+	if (ret < 0)
+		return -EINVAL;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_reset_event);
+
+/**
+ * devfreq_event_get_drvdata() - Return driver-data of devfreq-event dev.
+ * @edev	: the devfreq-event device
+ *
+ * Note that this function return the driver-data of devfreq-event device.
+ */
+void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev)
+{
+	return edev->desc->driver_data;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_get_drvdata);
+
+/**
+ * devfreq_event_get_edev_by_phandle() - Get the devfreq-event dev from
+ *					 devicetree.
+ * @dev		: the pointer to the given device
+ * @index	: the index into list of devfreq-event device
+ *
+ * Note that this function return the pointer of devfreq-event device.
+ */
+struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev,
+						      int index)
+{
+	struct device_node *node;
+	struct devfreq_event_dev *edev;
+
+	if (!dev->of_node) {
+		dev_err(dev, "device does not have a device node entry\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	node = of_parse_phandle(dev->of_node, "devfreq-events", index);
+	if (!node) {
+		dev_err(dev, "failed to get phandle in %s node\n",
+			dev->of_node->full_name);
+		return ERR_PTR(-ENODEV);
+	}
+
+	mutex_lock(&devfreq_event_list_lock);
+	list_for_each_entry(edev, &devfreq_event_list, node) {
+		if (!strcmp(edev->desc->name, node->name))
+			goto out;
+	}
+	edev = NULL;
+out:
+	mutex_unlock(&devfreq_event_list_lock);
+
+	if (!edev) {
+		dev_err(dev, "unable to get devfreq-event device : %s\n",
+			node->name);
+		of_node_put(node);
+		return ERR_PTR(-ENODEV);
+	}
+
+	of_node_put(node);
+
+	return edev;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle);
+
+/**
+ * devfreq_event_get_edev_count() - Get the count of devfreq-event dev
+ * @dev		: the pointer to the given device
+ *
+ * Note that this function return the count of devfreq-event devices.
+ */
+int devfreq_event_get_edev_count(struct device *dev)
+{
+	int count;
+
+	if (!dev->of_node) {
+		dev_err(dev, "device does not have a device node entry\n");
+		return -EINVAL;
+	}
+
+	count = of_property_count_elems_of_size(dev->of_node, "devfreq-events",
+						sizeof(u32));
+	if (count < 0 ) {
+		dev_err(dev,
+			"failed to get the count of devfreq-event in %s node\n",
+			dev->of_node->full_name);
+		return count;
+	}
+
+	return count;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count);
+
+static void devfreq_event_release_edev(struct device *dev)
+{
+	struct devfreq_event_dev *edev = to_devfreq_event(dev);
+
+	kfree(edev);
+}
+
+/**
+ * devfreq_event_add_edev() - Add new devfreq-event device.
+ * @dev		: the device owning the devfreq-event device being created
+ * @desc	: the devfreq-event device's decriptor which include essential
+ *		  data for devfreq-event device.
+ *
+ * Note that this function add new devfreq-event device to devfreq-event class
+ * list and register the device of the devfreq-event device.
+ */
+struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
+						struct devfreq_event_desc *desc)
+{
+	struct devfreq_event_dev *edev;
+	static atomic_t event_no = ATOMIC_INIT(0);
+	int ret;
+
+	if (!dev || !desc)
+		return ERR_PTR(-EINVAL);
+
+	if (!desc->name || !desc->ops)
+		return ERR_PTR(-EINVAL);
+
+	if (!desc->ops->set_event || !desc->ops->get_event)
+		return ERR_PTR(-EINVAL);
+
+	edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL);
+	if (!edev)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&edev->lock);
+	edev->desc = desc;
+	edev->dev.parent = dev;
+	edev->dev.class = devfreq_event_class;
+	edev->dev.release = devfreq_event_release_edev;
+
+	dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1);
+	ret = device_register(&edev->dev);
+	if (ret < 0) {
+		put_device(&edev->dev);
+		return ERR_PTR(ret);
+	}
+	dev_set_drvdata(&edev->dev, edev);
+
+	INIT_LIST_HEAD(&edev->node);
+
+	mutex_lock(&devfreq_event_list_lock);
+	list_add(&edev->node, &devfreq_event_list);
+	mutex_unlock(&devfreq_event_list_lock);
+
+	return edev;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_add_edev);
+
+/**
+ * devfreq_event_remove_edev() - Remove the devfreq-event device registered.
+ * @dev		: the devfreq-event device
+ *
+ * Note that this function remove the registered devfreq-event device.
+ */
+int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
+{
+	if (!edev)
+		return -EINVAL;
+
+	mutex_lock(&devfreq_event_list_lock);
+	WARN_ON(edev->enable_count);
+	list_del(&edev->node);
+	device_unregister(&edev->dev);
+	mutex_unlock(&devfreq_event_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_remove_edev);
+
+/*
+ * Device attributes for devfreq-event class.
+ */
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct devfreq_event_dev *edev = to_devfreq_event(dev);
+
+	if (!edev || !edev->desc)
+		return -EINVAL;
+
+	return sprintf(buf, "%s\n", edev->desc->name);
+}
+static DEVICE_ATTR_RO(name);
+
+static ssize_t enable_count_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct devfreq_event_dev *edev = to_devfreq_event(dev);
+
+	if (!edev || !edev->desc)
+		return -EINVAL;
+
+	return sprintf(buf, "%d\n", edev->enable_count);
+}
+static DEVICE_ATTR_RO(enable_count);
+
+static struct attribute *devfreq_event_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_enable_count.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(devfreq_event);
+
+static int __init devfreq_event_init(void)
+{
+	devfreq_event_class = class_create(THIS_MODULE, "devfreq-event");
+	if (IS_ERR(devfreq_event_class)) {
+		pr_err("%s: couldn't create class\n", __FILE__);
+		return PTR_ERR(devfreq_event_class);
+	}
+
+	devfreq_event_class->dev_groups = devfreq_event_groups;
+
+	return 0;
+}
+subsys_initcall(devfreq_event_init);
+
+static void __exit devfreq_event_exit(void)
+{
+	class_destroy(devfreq_event_class);
+}
+module_exit(devfreq_event_exit);
+
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_DESCRIPTION("DEVFREQ-Event class support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig
new file mode 100644
index 0000000..1ced42c
--- /dev/null
+++ b/drivers/devfreq/event/Kconfig
@@ -0,0 +1,16 @@
+menuconfig PM_DEVFREQ_EVENT
+	bool "DEVFREQ-Event device Support"
+	help
+	  The devfreq-event device provide the raw data and events which
+	  indicate the current state of devfreq-event device. The provided
+	  data from devfreq-event device is used to monitor the state of
+	  device and determine the suitable size of resource to reduce the
+	  wasted resource.
+
+	  The devfreq-event device can support the various type of events
+	  (e.g., raw data, utilization, latency, bandwidth). The events
+	  may be used by devfreq governor and other subsystem.
+
+if PM_DEVFREQ_EVENT
+
+endif # PM_DEVFREQ_EVENT
diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile
new file mode 100644
index 0000000..dc56005
--- /dev/null
+++ b/drivers/devfreq/event/Makefile
@@ -0,0 +1 @@
+# Exynos DEVFREQ Event Drivers
diff --git a/include/linux/devfreq-event.h b/include/linux/devfreq-event.h
new file mode 100644
index 0000000..b7363f5
--- /dev/null
+++ b/include/linux/devfreq-event.h
@@ -0,0 +1,170 @@
+/*
+ * devfreq-event: a framework to provide raw data and events of devfreq devices
+ *
+ * Copyright (C) 2014 Samsung Electronics
+ * Author: Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_DEVFREQ_EVENT_H__
+#define __LINUX_DEVFREQ_EVENT_H__
+
+#include <linux/device.h>
+
+/**
+ * struct devfreq_event_dev - the devfreq-event device
+ *
+ * @node	: Contain the devfreq-event device that have been registered.
+ * @dev		: the device registered by devfreq-event class. dev.parent is
+ *		  the device using devfreq-event.
+ * @lock	: a mutex to protect accessing devfreq-event.
+ * @enable_count: the number of enable function have been called.
+ * @desc	: the description for devfreq-event device.
+ *
+ * This structure contains devfreq-event device information.
+ */
+struct devfreq_event_dev {
+	struct list_head node;
+
+	struct device dev;
+	struct mutex lock;
+	u32 enable_count;
+
+	const struct devfreq_event_desc *desc;
+};
+
+/**
+ * struct devfreq_event_data - the devfreq-event data
+ *
+ * @event	: the load of devfreq-event device for polling period
+ * @total_event	: the total load of devfreq-event device for polling period
+ *
+ * This structure contains the data of devfreq-event device for polling period.
+ */
+struct devfreq_event_data {
+	unsigned long event;
+	unsigned long total_event;
+};
+
+/**
+ * struct devfreq_event_ops - the operations of devfreq-event device
+ *
+ * @enable	: Enable the devfreq-event device.
+ * @disable	: Disable the devfreq-event device.
+ * @reset	: Reset all setting of the devfreq-event device.
+ * @set_event	: Set the specific event type for the devfreq-event device.
+ * @get_event	: Get the result of the devfreq-event devie with specific
+ *		  event type.
+ *
+ * This structure contains devfreq-event device operations which can be
+ * implemented by devfreq-event device drivers.
+ */
+struct devfreq_event_ops {
+	/* Optional functions */
+	int (*enable)(struct devfreq_event_dev *edev);
+	int (*disable)(struct devfreq_event_dev *edev);
+	int (*reset)(struct devfreq_event_dev *edev);
+
+	/* Mandatory functions */
+	int (*set_event)(struct devfreq_event_dev *edev);
+	int (*get_event)(struct devfreq_event_dev *edev,
+			 struct devfreq_event_data *edata);
+};
+
+/**
+ * struct devfreq_event_desc - the descriptor of devfreq-event device
+ *
+ * @name	: the name of devfreq-event device.
+ * @driver_data	: the private data for devfreq-event driver.
+ * @ops		: the operation to control devfreq-event device.
+ *
+ * Each devfreq-event device is described with a this structure.
+ * This structure contains the various data for devfreq-event device.
+ */
+struct devfreq_event_desc {
+	const char *name;
+	void *driver_data;
+
+	struct devfreq_event_ops *ops;
+};
+
+#if defined(CONFIG_PM_DEVFREQ_EVENT)
+extern int devfreq_event_enable_edev(struct devfreq_event_dev *edev);
+extern int devfreq_event_disable_edev(struct devfreq_event_dev *edev);
+extern bool devfreq_event_is_enabled(struct devfreq_event_dev *edev);
+extern int devfreq_event_set_event(struct devfreq_event_dev *edev);
+extern int devfreq_event_get_event(struct devfreq_event_dev *edev,
+				struct devfreq_event_data *edata);
+extern int devfreq_event_reset_event(struct devfreq_event_dev *edev);
+extern void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev);
+extern struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(
+				struct device *dev, int index);
+extern int devfreq_event_get_edev_count(struct device *dev);
+extern struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
+				struct devfreq_event_desc *desc);
+extern int devfreq_event_remove_edev(struct devfreq_event_dev *edev);
+
+#else
+static inline int devfreq_event_enable_edev(struct devfreq_event_dev *edev)
+{
+	return -EINVAL;
+}
+
+static inline int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
+{
+	return -EINVAL;
+}
+
+static inline bool devfreq_event_is_enabled(struct devfreq_event_dev *edev)
+{
+	return false;
+}
+
+static inline int devfreq_event_set_event(struct devfreq_event_dev *edev)
+{
+	return -EINVAL;
+}
+
+static inline int devfreq_event_get_event(struct devfreq_event_dev *edev,
+					struct devfreq_event_data *edata)
+{
+	return -EINVAL;
+}
+
+static inline int devfreq_event_reset_event(struct devfreq_event_dev *edev)
+{
+	return -EINVAL;
+}
+
+static inline void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(
+					struct device *dev, int index)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int devfreq_event_get_edev_count(struct device *dev)
+{
+	return -EINVAL;
+}
+
+static inline struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
+					struct devfreq_event_desc *desc)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_PM_DEVFREQ_EVENT */
+
+#endif /* __LINUX_DEVFREQ_EVENT_H__ */
-- 
1.8.5.5


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

* [PATCHv8 2/9] devfreq: event: Add resource-managed function for devfreq-event device
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 3/9] devfreq: event: Add exynos-ppmu devfreq-event driver Chanwoo Choi
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patch add the resource-managed function for devfreq-event device as
following functions. The devm_devfreq_event_add_edev() manages automatically
the memory of devfreq-event device using resource management.
- devm_devfreq_event_add_edev()
- devm_devfreq_event_remove_edev()

Cc: Myungjoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 drivers/devfreq/devfreq-event.c | 63 +++++++++++++++++++++++++++++++++++++++++
 include/linux/devfreq-event.h   | 16 +++++++++++
 2 files changed, 79 insertions(+)

diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c
index 9ba5ba4..57529af 100644
--- a/drivers/devfreq/devfreq-event.c
+++ b/drivers/devfreq/devfreq-event.c
@@ -389,6 +389,69 @@ int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
 }
 EXPORT_SYMBOL_GPL(devfreq_event_remove_edev);
 
+static int devm_devfreq_event_match(struct device *dev, void *res, void *data)
+{
+	struct devfreq_event_dev **r = res;
+
+	if (WARN_ON(!r || !*r))
+		return 0;
+
+	return *r == data;
+}
+
+static void devm_devfreq_event_release(struct device *dev, void *res)
+{
+	devfreq_event_remove_edev(*(struct devfreq_event_dev **)res);
+}
+
+/**
+ * devm_devfreq_event_add_edev() - Resource-managed devfreq_event_add_edev()
+ * @dev		: the device owning the devfreq-event device being created
+ * @desc	: the devfreq-event device's decriptor which include essential
+ *		  data for devfreq-event device.
+ *
+ * Note that this function manages automatically the memory of devfreq-event
+ * device using device resource management and simplify the free operation
+ * for memory of devfreq-event device.
+ */
+struct devfreq_event_dev *devm_devfreq_event_add_edev(struct device *dev,
+						struct devfreq_event_desc *desc)
+{
+	struct devfreq_event_dev **ptr, *edev;
+
+	ptr = devres_alloc(devm_devfreq_event_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	edev = devfreq_event_add_edev(dev, desc);
+	if (IS_ERR(edev)) {
+		devres_free(ptr);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	*ptr = edev;
+	devres_add(dev, ptr);
+
+	return edev;
+}
+EXPORT_SYMBOL_GPL(devm_devfreq_event_add_edev);
+
+/**
+ * devm_devfreq_event_remove_edev()- Resource-managed devfreq_event_remove_edev()
+ * @dev		: the device owning the devfreq-event device being created
+ * @edev	: the devfreq-event device
+ *
+ * Note that this function manages automatically the memory of devfreq-event
+ * device using device resource management.
+ */
+void devm_devfreq_event_remove_edev(struct device *dev,
+				struct devfreq_event_dev *edev)
+{
+	WARN_ON(devres_release(dev, devm_devfreq_event_release,
+			       devm_devfreq_event_match, edev));
+}
+EXPORT_SYMBOL_GPL(devm_devfreq_event_remove_edev);
+
 /*
  * Device attributes for devfreq-event class.
  */
diff --git a/include/linux/devfreq-event.h b/include/linux/devfreq-event.h
index b7363f5..b6e3afa 100644
--- a/include/linux/devfreq-event.h
+++ b/include/linux/devfreq-event.h
@@ -106,6 +106,10 @@ extern int devfreq_event_get_edev_count(struct device *dev);
 extern struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
 				struct devfreq_event_desc *desc);
 extern int devfreq_event_remove_edev(struct devfreq_event_dev *edev);
+extern struct devfreq_event_dev *devm_devfreq_event_add_edev(struct device *dev,
+				struct devfreq_event_desc *desc);
+extern void devm_devfreq_event_remove_edev(struct device *dev,
+				struct devfreq_event_dev *edev);
 
 #else
 static inline int devfreq_event_enable_edev(struct devfreq_event_dev *edev)
@@ -165,6 +169,18 @@ static inline int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
 {
 	return -EINVAL;
 }
+
+static inline struct devfreq_event_dev *devm_devfreq_event_add_edev(
+					struct device *dev,
+					struct devfreq_event_desc *desc)
+{
+	return ERR_PTR(-EINVAL);
+}
+
+static inline void devm_devfreq_event_remove_edev(struct device *dev,
+					struct devfreq_event_dev *edev)
+{
+}
 #endif /* CONFIG_PM_DEVFREQ_EVENT */
 
 #endif /* __LINUX_DEVFREQ_EVENT_H__ */
-- 
1.8.5.5


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

* [PATCHv8 3/9] devfreq: event: Add exynos-ppmu devfreq-event driver
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 2/9] devfreq: event: Add resource-managed function for devfreq-event device Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 4/9] devfreq: event: Add documentation for " Chanwoo Choi
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patch adds exynos-ppmu devfreq-event driver to get performance data
of each IP for Samsung Exynos SoC. These event from Exynos PPMU provide
useful information about the behavior of the SoC that you can use when
analyzing system performance, and made visible and can be counted using
logic in each IP.

This patch is based on existing drivers/devfreq/exynos/exynos-ppmu.c

Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
---
 drivers/devfreq/event/Kconfig       |   9 +
 drivers/devfreq/event/Makefile      |   1 +
 drivers/devfreq/event/exynos-ppmu.c | 398 ++++++++++++++++++++++++++++++++++++
 3 files changed, 408 insertions(+)
 create mode 100644 drivers/devfreq/event/exynos-ppmu.c

diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig
index 1ced42c..a11720a 100644
--- a/drivers/devfreq/event/Kconfig
+++ b/drivers/devfreq/event/Kconfig
@@ -13,4 +13,13 @@ menuconfig PM_DEVFREQ_EVENT
 
 if PM_DEVFREQ_EVENT
 
+config DEVFREQ_EVENT_EXYNOS_PPMU
+	bool "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver"
+	depends on ARCH_EXYNOS
+	select PM_OPP
+	help
+	  This add the devfreq-event driver for Exynos SoC. It provides PPMU
+	  (Platform Performance Monitoring Unit) counters to estimate the
+	  utilization of each module.
+
 endif # PM_DEVFREQ_EVENT
diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile
index dc56005..be146ea 100644
--- a/drivers/devfreq/event/Makefile
+++ b/drivers/devfreq/event/Makefile
@@ -1 +1,2 @@
 # Exynos DEVFREQ Event Drivers
+obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o
diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c
new file mode 100644
index 0000000..4dd78c5
--- /dev/null
+++ b/drivers/devfreq/event/exynos-ppmu.c
@@ -0,0 +1,398 @@
+/*
+ * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author : Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver is based on drivers/devfreq/exynos/exynos_ppmu.c
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
+#include <linux/devfreq-event.h>
+
+#define PPMU_ENABLE             BIT(0)
+#define PPMU_DISABLE            0x0
+#define PPMU_CYCLE_RESET        BIT(1)
+#define PPMU_COUNTER_RESET      BIT(2)
+
+#define PPMU_ENABLE_COUNT0      BIT(0)
+#define PPMU_ENABLE_COUNT1      BIT(1)
+#define PPMU_ENABLE_COUNT2      BIT(2)
+#define PPMU_ENABLE_COUNT3      BIT(3)
+#define PPMU_ENABLE_CYCLE       BIT(31)
+
+#define PPMU_CNTENS		0x10
+#define PPMU_CNTENC		0x20
+#define PPMU_FLAG		0x50
+#define PPMU_CCNT_OVERFLOW	BIT(31)
+#define PPMU_CCNT		0x100
+
+#define PPMU_PMCNT0		0x110
+#define PPMU_PMCNT_OFFSET	0x10
+#define PMCNT_OFFSET(x)		(PPMU_PMCNT0 + (PPMU_PMCNT_OFFSET * x))
+
+#define PPMU_BEVT0SEL		0x1000
+#define PPMU_BEVTSEL_OFFSET	0x100
+#define PPMU_BEVTSEL(x)		(PPMU_BEVT0SEL + (x * PPMU_BEVTSEL_OFFSET))
+
+#define RD_DATA_COUNT		0x5
+#define WR_DATA_COUNT		0x6
+#define RDWR_DATA_COUNT		0x7
+
+enum ppmu_counter {
+	PPMU_PMNCNT0 = 0,
+	PPMU_PMNCNT1,
+	PPMU_PMNCNT2,
+	PPMU_PMNCNT3,
+
+	PPMU_PMNCNT_MAX,
+};
+
+struct exynos_ppmu_data {
+	struct devfreq_event_dev **edev;
+	struct devfreq_event_desc *desc;
+	unsigned int num_events;
+
+	struct device *dev;
+	struct clk *clk_ppmu;
+	struct mutex lock;
+
+	struct __exynos_ppmu {
+		void __iomem *base;
+		unsigned int event[PPMU_PMNCNT_MAX];
+		unsigned int count[PPMU_PMNCNT_MAX];
+		bool ccnt_overflow;
+		bool count_overflow[PPMU_PMNCNT_MAX];
+	} ppmu;
+};
+
+#define PPMU_EVENT(name)			\
+	{ "ppmu-event0-"#name, PPMU_PMNCNT0 },	\
+	{ "ppmu-event1-"#name, PPMU_PMNCNT1 },	\
+	{ "ppmu-event2-"#name, PPMU_PMNCNT2 },	\
+	{ "ppmu-event3-"#name, PPMU_PMNCNT3 }
+
+struct __exynos_ppmu_events {
+	char *name;
+	int id;
+} ppmu_events[] = {
+	/* For Exynos3250, Exynos4 and Exynos5260 */
+	PPMU_EVENT(g3d),
+	PPMU_EVENT(fsys),
+
+	/* For Exynos4 SoCs and Exynos3250 */
+	PPMU_EVENT(dmc0),
+	PPMU_EVENT(dmc1),
+	PPMU_EVENT(cpu),
+	PPMU_EVENT(rightbus),
+	PPMU_EVENT(leftbus),
+	PPMU_EVENT(lcd0),
+	PPMU_EVENT(camif),
+
+	/* Only for Exynos3250 and Exynos5260 */
+	PPMU_EVENT(mfc),
+
+	/* Only for Exynos4 SoCs */
+	PPMU_EVENT(mfc-left),
+	PPMU_EVENT(mfc-right),
+
+	/* Only for Exynos5260 SoCs */
+	PPMU_EVENT(drex0-s0),
+	PPMU_EVENT(drex0-s1),
+	PPMU_EVENT(drex1-s0),
+	PPMU_EVENT(drex1-s1),
+	PPMU_EVENT(eagle),
+	PPMU_EVENT(kfc),
+	PPMU_EVENT(isp),
+	PPMU_EVENT(fimc),
+	PPMU_EVENT(gscl),
+	PPMU_EVENT(mscl),
+	PPMU_EVENT(fimd0x),
+	PPMU_EVENT(fimd1x),
+	{ /* sentinel */ },
+};
+
+static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ppmu_events); i++)
+		if (!strcmp(edev->desc->name, ppmu_events[i].name))
+			return ppmu_events[i].id;
+
+	return -EINVAL;
+}
+
+static int exynos_ppmu_reset(struct devfreq_event_dev *edev)
+{
+	struct exynos_ppmu_data *data = devfreq_event_get_drvdata(edev);
+
+	__raw_writel(PPMU_CYCLE_RESET | PPMU_COUNTER_RESET, data->ppmu.base);
+	__raw_writel(PPMU_ENABLE_CYCLE  |
+		     PPMU_ENABLE_COUNT0 |
+		     PPMU_ENABLE_COUNT1 |
+		     PPMU_ENABLE_COUNT2 |
+		     PPMU_ENABLE_COUNT3,
+		     data->ppmu.base + PPMU_CNTENS);
+
+	return 0;
+}
+
+static int exynos_ppmu_disable(struct devfreq_event_dev *edev)
+{
+	struct exynos_ppmu_data *data = devfreq_event_get_drvdata(edev);
+
+	/* Reset the performance and cycle counters */
+	exynos_ppmu_reset(edev);
+
+	/* Disable event of PPMU */
+	__raw_writel(PPMU_ENABLE_CYCLE  |
+		     PPMU_ENABLE_COUNT0 |
+		     PPMU_ENABLE_COUNT1 |
+		     PPMU_ENABLE_COUNT2 |
+		     PPMU_ENABLE_COUNT3,
+		     data->ppmu.base + PPMU_CNTENC);
+
+	/* Stop monitoring of PPMU IP */
+	__raw_writel(PPMU_DISABLE, data->ppmu.base);
+
+	return 0;
+}
+
+static int exynos_ppmu_set_event(struct devfreq_event_dev *edev)
+{
+	struct exynos_ppmu_data *data = devfreq_event_get_drvdata(edev);
+	int id = exynos_ppmu_find_ppmu_id(edev);
+
+	if (id < 0)
+		return id;
+
+	/* Reset the performance and cycle counters */
+	exynos_ppmu_reset(edev);
+
+	/* Setup count registers to monitor read/write transactions */
+	__raw_writel(RDWR_DATA_COUNT, data->ppmu.base + PPMU_BEVTSEL(id));
+
+	/* Start monitoring of PPMU IP */
+	__raw_writel(PPMU_ENABLE, data->ppmu.base);
+
+	return 0;
+}
+
+static int exynos_ppmu_get_event(struct devfreq_event_dev *edev,
+				struct devfreq_event_data *edata)
+{
+	struct exynos_ppmu_data *data = devfreq_event_get_drvdata(edev);
+	int id = exynos_ppmu_find_ppmu_id(edev);
+
+	if (id < 0)
+		return -EINVAL;
+
+	/* Stop monitoring of PPMU IP */
+	__raw_writel(PPMU_DISABLE, data->ppmu.base);
+
+	/* Read total count cycle from of PPMU IP */
+	edata->total_event = __raw_readl(data->ppmu.base + PPMU_CCNT);
+
+	if (id == PPMU_PMNCNT3)
+		edata->event =
+			((__raw_readl(data->ppmu.base + PMCNT_OFFSET(id)) << 8)
+			| __raw_readl(data->ppmu.base + PMCNT_OFFSET(id + 1)));
+	else
+		edata->event = __raw_readl(data->ppmu.base + PMCNT_OFFSET(id));
+
+	dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name,
+					edata->event, edata->total_event);
+
+	return 0;
+}
+
+static struct devfreq_event_ops exynos_ppmu_ops = {
+	.disable = exynos_ppmu_disable,
+	.set_event = exynos_ppmu_set_event,
+	.get_event = exynos_ppmu_get_event,
+};
+
+static int of_get_devfreq_events(struct device_node *np,
+				 struct exynos_ppmu_data *data)
+{
+	struct devfreq_event_desc *desc;
+	struct device *dev = data->dev;
+	struct device_node *events_np, *node;
+	int i, j, count;
+
+	events_np = of_get_child_by_name(np, "events");
+	if (!events_np) {
+		dev_err(dev,
+			"failed to get child node of devfreq-event devices\n");
+		return -EINVAL;
+	}
+
+	count = of_get_child_count(events_np);
+	desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+	data->num_events = count;
+
+	j = 0;
+	for_each_child_of_node(events_np, node) {
+		for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) {
+			if (!ppmu_events[i].name)
+				continue;
+
+			if (!of_node_cmp(node->name, ppmu_events[i].name))
+				break;
+		}
+
+		if (i == ARRAY_SIZE(ppmu_events)) {
+			dev_warn(dev,
+				"don't know how to configure events : %s\n",
+				node->name);
+			continue;
+		}
+
+		desc[j].ops = &exynos_ppmu_ops;
+		desc[j].driver_data = data;
+
+		of_property_read_string(node, "event-name", &desc[j].name);
+
+		j++;
+
+		of_node_put(node);
+	}
+	data->desc = desc;
+
+	of_node_put(events_np);
+
+	return 0;
+}
+
+static int exynos_ppmu_parse_dt(struct exynos_ppmu_data *data)
+{
+	struct device *dev = data->dev;
+	struct device_node *np = dev->of_node;
+	int ret = 0;
+
+	if (!np) {
+		dev_err(dev, "failed to find devicetree node\n");
+		return -EINVAL;
+	}
+
+	/* Maps the memory mapped IO to control PPMU register */
+	data->ppmu.base = of_iomap(np, 0);
+	if (IS_ERR_OR_NULL(data->ppmu.base)) {
+		dev_err(dev, "failed to map memory region\n");
+		return -ENOMEM;
+	}
+
+	data->clk_ppmu = devm_clk_get(dev, "ppmu");
+	if (IS_ERR(data->clk_ppmu)) {
+		data->clk_ppmu = NULL;
+		dev_warn(dev, "cannot get PPMU clock\n");
+	}
+
+	ret = of_get_devfreq_events(np, data);
+	if (ret < 0) {
+		dev_err(dev, "failed to parse exynos ppmu dt node\n");
+		goto err;
+	}
+
+	return 0;
+
+err:
+	iounmap(data->ppmu.base);
+
+	return ret;
+}
+
+static int exynos_ppmu_probe(struct platform_device *pdev)
+{
+	struct exynos_ppmu_data *data;
+	struct devfreq_event_dev **edev;
+	struct devfreq_event_desc *desc;
+	int i, ret = 0, size;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->lock);
+	data->dev = &pdev->dev;
+
+	/* Parse dt data to get resource */
+	ret = exynos_ppmu_parse_dt(data);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"failed to parse devicetree for resource\n");
+		return ret;
+	}
+	desc = data->desc;
+
+	size = sizeof(struct devfreq_event_dev *) * data->num_events;
+	data->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+	if (!data->edev) {
+		dev_err(&pdev->dev,
+			"failed to allocate memory devfreq-event devices\n");
+		return -ENOMEM;
+	}
+	edev = data->edev;
+	platform_set_drvdata(pdev, data);
+
+	for (i = 0; i < data->num_events; i++) {
+		edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]);
+		if (IS_ERR(edev)) {
+			ret = PTR_ERR(edev);
+			dev_err(&pdev->dev,
+				"failed to add devfreq-event device\n");
+			goto err;
+		}
+	}
+
+	clk_prepare_enable(data->clk_ppmu);
+
+	return 0;
+err:
+	iounmap(data->ppmu.base);
+
+	return ret;
+}
+
+static int exynos_ppmu_remove(struct platform_device *pdev)
+{
+	struct exynos_ppmu_data *data = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(data->clk_ppmu);
+	iounmap(data->ppmu.base);
+
+	return 0;
+}
+
+static struct of_device_id exynos_ppmu_id_match[] = {
+	{ .compatible = "samsung,exynos-ppmu", },
+	{ /* sentinel */ },
+};
+
+static struct platform_driver exynos_ppmu_driver = {
+	.probe	= exynos_ppmu_probe,
+	.remove	= exynos_ppmu_remove,
+	.driver = {
+		.name	= "exynos-ppmu",
+		.of_match_table = exynos_ppmu_id_match,
+	},
+};
+module_platform_driver(exynos_ppmu_driver);
+
+MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
-- 
1.8.5.5


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

* [PATCHv8 4/9] devfreq: event: Add documentation for exynos-ppmu devfreq-event driver
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
                   ` (2 preceding siblings ...)
  2015-01-12 12:34 ` [PATCHv8 3/9] devfreq: event: Add exynos-ppmu devfreq-event driver Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 5/9] ARM: dts: Add PPMU dt node for Exynos3250 SoC Chanwoo Choi
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patch adds the documentation for Exynos PPMU (Platform Performance
Monitoring Unit) devfreq-event driver.

Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
---
 .../bindings/devfreq/event/exynos-ppmu.txt         | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt

diff --git a/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt
new file mode 100644
index 0000000..b54bf3a
--- /dev/null
+++ b/Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt
@@ -0,0 +1,110 @@
+
+* Samsung Exynos PPMU (Platform Performance Monitoring Unit) device
+
+The Samsung Exynos SoC has PPMU (Platform Performance Monitoring Unit) for
+each IP. PPMU provides the primitive values to get performance data. These
+PPMU events provide information of the SoC's behaviors so that you may
+use to analyze system performance, to make behaviors visible and to count
+usages of each IP (DMC, CPU, RIGHTBUS, LEFTBUS, CAM interface, LCD, G3D, MFC).
+The Exynos PPMU driver uses the devfreq-event class to provide event data
+to various devfreq devices. The devfreq devices would use the event data when
+derterming the current state of each IP.
+
+Required properties:
+- compatible: Should be "samsung,exynos-ppmu".
+- reg: physical base address of each PPMU and length of memory mapped region.
+
+Optional properties:
+- clock-names : the name of clock used by the PPMU, "ppmu"
+- clocks : phandles for clock specified in "clock-names" property
+- #clock-cells: should be 1.
+
+Example1 : PPMU nodes in exynos3250.dtsi are listed below.
+
+		ppmu_dmc0: ppmu_dmc0@106a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106a0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_dmc1: ppmu_dmc1@106b0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106b0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_cpu: ppmu_cpu@106c0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106c0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_rightbus: ppmu_rightbus@112a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x112a0000 0x2000>;
+			clocks = <&cmu CLK_PPMURIGHT>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_leftbus: ppmu_leftbus0@116a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x116a0000 0x2000>;
+			clocks = <&cmu CLK_PPMULEFT>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+Example2 : Events of each PPMU node in exynos3250-rinato.dts are listed below.
+
+	&ppmu_dmc0 {
+		status = "okay";
+
+		events {
+			ppmu_dmc0_3: ppmu-event3-dmc0 {
+				event-name = "ppmu-event3-dmc0";
+			};
+
+			ppmu_dmc0_2: ppmu-event2-dmc0 {
+				event-name = "ppmu-event2-dmc0";
+			};
+
+			ppmu_dmc0_1: ppmu-event1-dmc0 {
+				event-name = "ppmu-event1-dmc0";
+			};
+
+			ppmu_dmc0_0: ppmu-event0-dmc0 {
+				event-name = "ppmu-event0-dmc0";
+			};
+		};
+	};
+
+	&ppmu_dmc1 {
+		status = "okay";
+
+		events {
+			ppmu_dmc1_3: ppmu-event3-dmc1 {
+				event-name = "ppmu-event3-dmc1";
+			};
+		};
+	};
+
+	&ppmu_leftbus {
+		status = "okay";
+
+		events {
+			ppmu_leftbus_3: ppmu-event3-leftbus {
+				event-name = "ppmu-event3-leftbus";
+			};
+		};
+	};
+
+	&ppmu_rightbus {
+		status = "okay";
+
+		events {
+			ppmu_rightbus_3: ppmu-event3-rightbus {
+				event-name = "ppmu-event3-rightbus";
+			};
+		};
+	};
-- 
1.8.5.5


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

* [PATCHv8 5/9] ARM: dts: Add PPMU dt node for Exynos3250 SoC
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
                   ` (3 preceding siblings ...)
  2015-01-12 12:34 ` [PATCHv8 4/9] devfreq: event: Add documentation for " Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 6/9] ARM: dts: Add PPMU dt node for Exynos4 SoCs Chanwoo Choi
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patch add PPMU (Platform Performance Monitoring Unit) dt node
to estimate the utilization of each IP in Exynos SoC throught DEVFREQ Event
subsystem.

This patch adds following PPMU dt nodes:
- PPMU_DMC0     0x106a0000
- PPMU_DMC1     0x106b0000
- PPMU_RIGHTBUS 0x112A0000
- PPMU_LEFTBUS  0x116A0000
- PPMU_CAMIF    0x11AC0000
- PPMU_LCD0     0x11E40000
- PPMU_FSYS     0x12630000
- PPMU_3D       0x13220000
- PPMU_MFC      0x13660000
- PPMU_CPU      0x106c0000

Cc: Kukjin Kim <kgene@kernel.org>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
---
 arch/arm/boot/dts/exynos3250.dtsi | 74 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 2246549..9ed1260 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -515,6 +515,80 @@
 			compatible = "arm,cortex-a7-pmu";
 			interrupts = <0 18 0>, <0 19 0>;
 		};
+
+		ppmu_dmc0: ppmu_dmc0@106a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106a0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_dmc1: ppmu_dmc1@106b0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106b0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_cpu: ppmu_cpu@106c0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x106c0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_rightbus: ppmu_rightbus@112a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x112a0000 0x2000>;
+			clocks = <&cmu CLK_PPMURIGHT>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_leftbus: ppmu_leftbus0@116a0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x116a0000 0x2000>;
+			clocks = <&cmu CLK_PPMULEFT>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_camif: ppmu_camif@11ac0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x11ac0000 0x2000>;
+			clocks = <&cmu CLK_PPMUCAMIF>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_lcd0: ppmu_lcd0@11e40000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x11e40000 0x2000>;
+			clocks = <&cmu CLK_PPMULCD0>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_fsys: ppmu_fsys@12630000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x12630000 0x2000>;
+			clocks = <&cmu CLK_PPMUFILE>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_g3d: ppmu_g3d@13220000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13220000 0x2000>;
+			clocks = <&cmu CLK_PPMUG3D>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
+
+		ppmu_mfc: ppmu_mfc@13660000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13660000 0x2000>;
+			clocks = <&cmu CLK_PPMUMFC_L>;
+			clock-names = "ppmu";
+			status = "disabled";
+		};
 	};
 };
 
-- 
1.8.5.5


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

* [PATCHv8 6/9] ARM: dts: Add PPMU dt node for Exynos4 SoCs
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
                   ` (4 preceding siblings ...)
  2015-01-12 12:34 ` [PATCHv8 5/9] ARM: dts: Add PPMU dt node for Exynos3250 SoC Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 7/9] ARM: dts: Add PPMU dt node for Exynos5260 SoC Chanwoo Choi
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patch add PPMU (Platform Performance Monitoring Unit) dt node for Exynos4
(Exynos4210/4212/4412) SoC. PPMU dt node is used to monitor the utilization of
each IP.

The Exynos4210/Exynos4212/Exynos4412 SoC includes following PPMUs:
- PPMU_DMC0      0x106A_0000
- PPMU_DMC1      0x106B_0000
- PPMU_CPU       0x106C_0000
- PPMU_ACP       0x10AE_0000
- PPMU_RIGHT_BUS 0x112A_0000
- PPMU_LEFT_BUS  0x116A_0000
- PPMU_FSYS      0x1263_0000
- PPMU_LCD0      0x11E4_0000
- PPMU_CAMIF     0x11AC_0000
- PPMU_IMAGE     0x12AA_0000
- PPMU_TV        0x12E4_0000
- PPMU_3D        0x1322_0000
- PPMU_MFC_LEFT  0x1366_0000
- PPMU_MFC_RIGHT 0x1367_0000

Additionally, the Exynos4210 SoC includes following PPMUs:
- PPMU_LCD1      0x1224_0000

Cc: Kukjin Kim <kgene@kernel.org>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
---
 arch/arm/boot/dts/exynos4.dtsi    | 108 ++++++++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/exynos4210.dtsi |   8 +++
 2 files changed, 116 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index b8168f1..70064dc 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -645,4 +645,112 @@
 		samsung,sysreg = <&sys_reg>;
 		status = "disabled";
 	};
+
+	ppmu_dmc0: ppmu_dmc0@106a0000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x106a0000 0x2000>;
+		clocks = <&clock CLK_PPMUDMC0>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_dmc1: ppmu_dmc1@106b0000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x106b0000 0x2000>;
+		clocks = <&clock CLK_PPMUDMC1>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_cpu: ppmu_cpu@106c0000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x106c0000 0x2000>;
+		clocks = <&clock CLK_PPMUCPU>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_acp: ppmu_acp@10ae0000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x106e0000 0x2000>;
+		status = "disabled";
+	};
+
+	ppmu_rightbus: ppmu_rightbus@112a0000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x112a0000 0x2000>;
+		clocks = <&clock CLK_PPMURIGHT>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_leftbus: ppmu_leftbus0@116a0000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x116a0000 0x2000>;
+		clocks = <&clock CLK_PPMULEFT>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_camif: ppmu_camif@11ac0000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x11ac0000 0x2000>;
+		clocks = <&clock CLK_PPMUCAMIF>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_lcd0: ppmu_lcd0@11e40000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x11e40000 0x2000>;
+		clocks = <&clock CLK_PPMULCD0>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_fsys: ppmu_g3d@12630000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x12630000 0x2000>;
+		status = "disabled";
+	};
+
+	ppmu_image: ppmu_image@12aa0000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x12aa0000 0x2000>;
+		clocks = <&clock CLK_PPMUIMAGE>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_tv: ppmu_tv@12e40000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x12e40000 0x2000>;
+		clocks = <&clock CLK_PPMUTV>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_g3d: ppmu_g3d@13220000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x13220000 0x2000>;
+		clocks = <&clock CLK_PPMUG3D>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_mfc_left: ppmu_mfc_left@13660000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x13660000 0x2000>;
+		clocks = <&clock CLK_PPMUMFC_L>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
+
+	ppmu_mfc_right: ppmu_mfc_right@13670000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x13670000 0x2000>;
+		clocks = <&clock CLK_PPMUMFC_R>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
 };
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index bcc9e63..b2598de 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -192,4 +192,12 @@
 			samsung,lcd-wb;
 		};
 	};
+
+	ppmu_lcd1: ppmu_lcd1@12240000 {
+		compatible = "samsung,exynos-ppmu";
+		reg = <0x12240000 0x2000>;
+		clocks = <&clock CLK_PPMULCD1>;
+		clock-names = "ppmu";
+		status = "disabled";
+	};
 };
-- 
1.8.5.5


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

* [PATCHv8 7/9] ARM: dts: Add PPMU dt node for Exynos5260 SoC
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
                   ` (5 preceding siblings ...)
  2015-01-12 12:34 ` [PATCHv8 6/9] ARM: dts: Add PPMU dt node for Exynos4 SoCs Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-19 10:01   ` Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 8/9] ARM: dts: exynos: Add PPMU node to Exynos3250-based Rinato/Monk board Chanwoo Choi
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc, Jonghwan Choi

This patch adds PPMU (Performance Profiling Monitoring Unit) dt node
Exynos5260 SoC.

Exynos5260 SoC has following PPMU IPs:
- PPMU_DREX0_S0 0x10c60000
- PPMU_DREX0_S1 0x10c70000
- PPMU_DREX1_S0 0x10c80000
- PPMU_DREX1_S1 0x10c90000
- PPMU_EAGLE    0x10cc0000
- PPMU_KFC      0x10cd0000
- PPMU_MFC      0x11040000
- PPMU_G3D      0x11880000
- PPMU_FSYS     0x12220000
- PPMU_ISP      0x13370000
- PPMU_FICM     0x13cb0000
- PPMU_GSCL     0x13e60000
- PPMU_MSCL     0x13ee0000
- PPMU_FIMD0X   0x145b0000
- PPMU_FIMD1X   0x145c0000

The drivers/devfreq/exynos/exynos5_bus.c supports the memory bus frequency/
voltage scaling of Exynos5260 SoC with DEVFREQ framework.

Cc: Kukjin Kim <kgene@kernel.org>
Cc: Abhilash Kesavan <a.kesavan@samsung.com>
Cc: Jonghwan Choi <jhbird.choi@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
---
 arch/arm/boot/dts/exynos5260.dtsi | 90 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/arch/arm/boot/dts/exynos5260.dtsi b/arch/arm/boot/dts/exynos5260.dtsi
index 36da38e..26f3074 100644
--- a/arch/arm/boot/dts/exynos5260.dtsi
+++ b/arch/arm/boot/dts/exynos5260.dtsi
@@ -307,6 +307,96 @@
 			fifo-depth = <64>;
 			status = "disabled";
 		};
+
+		ppmu_drex0_s0: ppmu_drex0_s0@10c60000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x10c60000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_drex0_s1: ppmu_drex0_s1@10c70000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x10c70000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_drex1_s0: ppmu_drex1_s0@10c80000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x10c80000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_drex1_s1: ppmu_drex1_s1@10c90000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x10c90000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_eagle: ppmu_eagle@10cc0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x10cc0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_kfc: ppmu_kfc@10cd0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x10cd0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_mfc: ppmu_mfc@11040000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x11040000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_g3d: ppmu_g3d@11880000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x11880000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_fsys: ppmu_fsys@12220000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x12220000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_isp: ppmu_isp@13370000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13370000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_fimc: ppmu_fimc@13cb0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13cb0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_gscl: ppmu_gscl@13e60000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13e60000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_mscl: ppmu_gscl@13ee0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x13ee0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_fimd0x: ppmu_fimd0x@145b0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x145b0000 0x2000>;
+			status = "disabled";
+		};
+
+		ppmu_fimd1x: ppmu_fimd1x@145c0000 {
+			compatible = "samsung,exynos-ppmu";
+			reg = <0x145c0000 0x2000>;
+			status = "disabled";
+		};
 	};
 };
 
-- 
1.8.5.5


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

* [PATCHv8 8/9] ARM: dts: exynos: Add PPMU node to Exynos3250-based Rinato/Monk board
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
                   ` (6 preceding siblings ...)
  2015-01-12 12:34 ` [PATCHv8 7/9] ARM: dts: Add PPMU dt node for Exynos5260 SoC Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-12 12:34 ` [PATCHv8 9/9] ARM: dts: exynos: Add PPMU node for Exynos4412-based TRATS2 board Chanwoo Choi
  2015-01-19  0:50 ` [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
  9 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patch add PPMU dt node to Exynos3250-base Rinato/Monk board. The PPMU node
is used to get the utilization of DMC0/DMC1/LEFTBUS/RIGHTBUS Block.

Cc: Kukjin Kim <kgene@kernel.org>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/boot/dts/exynos3250-monk.dts   | 40 +++++++++++++++++++++++++++++++++
 arch/arm/boot/dts/exynos3250-rinato.dts | 40 +++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)

diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts
index 24822aa..fcceb59 100644
--- a/arch/arm/boot/dts/exynos3250-monk.dts
+++ b/arch/arm/boot/dts/exynos3250-monk.dts
@@ -420,6 +420,46 @@
 	status = "okay";
 };
 
+&ppmu_dmc0 {
+	status = "okay";
+
+	events {
+		ppmu_dmc0_3: ppmu-event3-dmc0 {
+			event-name = "ppmu-event3-dmc0";
+		};
+	};
+};
+
+&ppmu_dmc1 {
+	status = "okay";
+
+	events {
+		ppmu_dmc1_3: ppmu-event3-dmc1 {
+			event-name = "ppmu-event3-dmc1";
+		};
+	};
+};
+
+&ppmu_leftbus {
+	status = "okay";
+
+	events {
+		ppmu_leftbus_3: ppmu-event3-leftbus {
+			event-name = "ppmu-event3-leftbus";
+		};
+	};
+};
+
+&ppmu_rightbus {
+	status = "okay";
+
+	events {
+		ppmu_rightbus_3: ppmu-event3-rightbus {
+			event-name = "ppmu-event3-rightbus";
+		};
+	};
+};
+
 &xusbxti {
 	clock-frequency = <24000000>;
 };
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 7cc52b5..9dd1ce1 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -595,6 +595,46 @@
 	status = "okay";
 };
 
+&ppmu_dmc0 {
+	status = "okay";
+
+	events {
+		ppmu_dmc0_3: ppmu-event3-dmc0 {
+			event-name = "ppmu-event3-dmc0";
+		};
+	};
+};
+
+&ppmu_dmc1 {
+	status = "okay";
+
+	events {
+		ppmu_dmc1_3: ppmu-event3-dmc1 {
+			event-name = "ppmu-event3-dmc1";
+		};
+	};
+};
+
+&ppmu_leftbus {
+	status = "okay";
+
+	events {
+		ppmu_leftbus_3: ppmu-event3-leftbus {
+			event-name = "ppmu-event3-leftbus";
+		};
+	};
+};
+
+&ppmu_rightbus {
+	status = "okay";
+
+	events {
+		ppmu_rightbus_3: ppmu-event3-rightbus {
+			event-name = "ppmu-event3-rightbus";
+		};
+	};
+};
+
 &xusbxti {
 	clock-frequency = <24000000>;
 };
-- 
1.8.5.5


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

* [PATCHv8 9/9] ARM: dts: exynos: Add PPMU node for Exynos4412-based TRATS2 board
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
                   ` (7 preceding siblings ...)
  2015-01-12 12:34 ` [PATCHv8 8/9] ARM: dts: exynos: Add PPMU node to Exynos3250-based Rinato/Monk board Chanwoo Choi
@ 2015-01-12 12:34 ` Chanwoo Choi
  2015-01-19  0:50 ` [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
  9 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-12 12:34 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: kyungmin.park, rafael.j.wysocki, mark.rutland, a.kesavan,
	tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt, cw00.choi,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

This patch add dt node for PPMU_{DMC0|DMC1|LEFTBUS|RIGHTBUS} for
exynos4412-trats2 board. Each PPMU dt node includes one event of 'PPMU Count3'.

Cc: Kukjin Kim <kgene@kernel.org>
Cc: Myungjoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: MyungJoo Ham <myungjoo.ham@samsung.com>
---
 arch/arm/boot/dts/exynos4412-trats2.dts | 40 +++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index c9b70b6..bee0eed 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -877,6 +877,46 @@
 	};
 };
 
+&ppmu_dmc0 {
+	status = "okay";
+
+	events {
+		ppmu_dmc0_3: ppmu-event3-dmc0 {
+			event-name = "ppmu-event3-dmc0";
+		};
+	};
+};
+
+&ppmu_dmc1 {
+	status = "okay";
+
+	events {
+		ppmu_dmc1_3: ppmu-event3-dmc1 {
+			event-name = "ppmu-event3-dmc1";
+		};
+	};
+};
+
+&ppmu_leftbus {
+	status = "okay";
+
+	events {
+		ppmu_leftbus_3: ppmu-event3-leftbus {
+			event-name = "ppmu-event3-leftbus";
+		};
+	};
+};
+
+&ppmu_rightbus {
+	status = "okay";
+
+	events {
+		ppmu_rightbus_3: ppmu-event3-rightbus {
+			event-name = "ppmu-event3-rightbus";
+		};
+	};
+};
+
 &pinctrl_0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&sleep0>;
-- 
1.8.5.5


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

* Re: [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device
  2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
                   ` (8 preceding siblings ...)
  2015-01-12 12:34 ` [PATCHv8 9/9] ARM: dts: exynos: Add PPMU node for Exynos4412-based TRATS2 board Chanwoo Choi
@ 2015-01-19  0:50 ` Chanwoo Choi
  9 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-19  0:50 UTC (permalink / raw)
  To: myungjoo.ham, kgene
  Cc: Chanwoo Choi, kyungmin.park, rafael.j.wysocki, mark.rutland,
	a.kesavan, tomasz.figa, k.kozlowski, b.zolnierkie, robh+dt,
	inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

Dear Myungjoo and Kukjin,

Could you please review this patchset?

The some patch of this patchset received the acked message
by Myungjoo Ham (DEVFREQ maintainer). But, this patchset must
need to review. I'd like to merge this patch in next kernel (3.20).

Best Regards,
Chanwoo Choi

On 01/12/2015 09:34 PM, Chanwoo Choi wrote:
> This patchset add new devfreq_event class to provide raw data to determine
> current utilization of device  which is used for devfreq governor.
> 
> The following description explains the feature of two kind of devfreq class:
> - devfreq class (existing)
>  : devfreq consumer device use raw data from devfreq_event device for
>    determining proper current system state and change voltage/frequency
>    dynamically using various governors.
> - devfreq_event class (new)
>  : Provide measured raw data to devfreq device for governor
> 
> ---------
> Changelog:
> 
> Changes from v7:
> (https://lkml.org/lkml/2015/1/7/795)
> - Use EXPORT_SYMBOL_GPL macro instead of EXPORT_SYMBOL
> - Fix the binding document of exynos-ppmu.c driver
> - Drop the devfreq-event type patch because it isnt' clear
> - Fix bug of devfreq_event_add_edev() when fail to execute device_register()
> - Modify resource free operation on following functions:
>   : devfreq_event_remove_edev()
>   : devfreq_event_release_edev()
> 
> Changes from v6:
> (https://lkml.org/lkml/2014/12/28/139)
> - This patchset is based on v3.19-rc3.
> 1. devfreq-event class driver
> - Fix build break if devfreq-event framework is off
> - Add resource-managed function for devfreq-event device
> : devm_devfreq_event_add_edev()
> : devm_devfreq_event_remove_edev()
> 
> Changes from v5:
> (https://lkml.org/lkml/2014/12/22/527)
> - Rebase these patch-set on v3.19-rc1 and Test it.
> 1. exynos-ppmu.c
> - Change the error value when of_iomap() fail to map the memory
> - Remove owner setting of platform_driver
> - Add exynos_ppmu_disable() function
> 2. exynos dts file
> - Add PPMU node to Exynos3250-based Monk board
> - Remove ppmu_cpu node on Exynos4412-based TRATS2 board and add ppmu_leftbus/rightbus node
> 
> Changes from v4:
> (https://lkml.org/lkml/2014/12/16/511)
> 1. devfreq-event class driver
> - Add devfreq_event_get_edev_count() function
> - Modify the simple description of devfreq-event framework in devfreq-event.c
> - Minimize the usage range of global lock usage in devfreq_event_add_edev()
> - Remove '_is_enabled()' function pointer in devfreq_event_ops structure
> - Add separte CONFIG_PM_DEVFREQ_EVENT configuration
> - Add new devfreq-event.h header file including devfreq-event helper functions
> 2. exynos dts file
> - Add new patch to support PPMU with DEVFREQ-event on Exynos4412-based TRATS2
> 
> Changes from v3:
> (https://lkml.org/lkml/2014/12/12/219)
> 1. devfreq-event class driver
> - Fix return value of devfreq_event_get_event()
> - Add new structure devfreq_event_data for devfreq_event_get_event()
> - Modify the prototype of devfreq_event_get_event() function
> - Call of_node_put after calling of_parse_phandle() to decrement refcount
> 2. exynos-ppmu driver
> - Modify usage of devfreq_event_get_event() function
>   according to new prototype of this funciton
> - Add the additional description to exynos-ppmu.txt how to add PPMU node
>   in board dts file
> - Use 'PPMU_EVENT' macro to remove duplicate codes
> - Add the support of PPMU for Exynos5260
> 3. exynos dts file
> - Add missing PPMU_FSYS node to exynos3250.dtsi
> - Fix 'ppmu_mfc_l' node name as 'ppmu_mfc' because exynos3250 has only one MFC IP.
> - Add missing PPMU_ACP/G3D to exynos4.dtsi
> 4. etc
> - Fix wrong abbreviation of PPMU (PPMU :Platform Performance Monitoring Unit)
> - Add new patch to support the PPMU of Exynos5260 SoC
> 
> Changes from v2:
> (https://lkml.org/lkml/2014/12/9/304)
> 1. devfreq-event class driver
> - Rename all the helper functions of devfreq-event device
> - Add devfreq_event_remove_edev() instead of devfreq_put_event_dev()
> - Add devfreq_event_release_edev() to initialize it before put device
> - Add the detailed description of devfreq-event API
> - Add the attributes of devfreq-event class (enable_count)
> - Check the overflow about event/total_event data in devfreq_event_get_event()
> - Remove the 'exclusive flag' feature
> - Set set_event()/get_event() functions as mandary
> - Add missing of_node_put() call
> - Change variable type of 'get_event()' funciton from 'int' to 'u64'
> 2. exynos-ppmu driver
> - Remove un-used field (struct devfreq)
> - Use 'of_get_child_by_name()' instead of 'of_find_node_by_name()'
> - Add missing of_node_put() call
> - Fix wrong clock control
> - Use devfreq_event_remove_edev() instead of devfreq_remove_device()
> - Add the documentation for exynos-ppmu driver
> - Remove 'enable/disable/is_enabled/reset' function of exynos-ppmu driver
> 3. exynos3250-rinato.dts
> - Add ppmu_{leftbus|rightbus} dt node and remove ppmu_cpu dt node
> 
> Changes from v1:
> (https://lkml.org/lkml/2014/9/5/11)
> - Code clean
> - Add the description of devfreq-event structure
> - Add 'is_enabled' function to devfreq_event_ops structure
> - Add 'enable_count' field to devfreq_event_dev structure
> - Check whether devfreq-event device is enabled or not
>   during calling devfreq_event API
> - Define the type of devfreq-event device as following
>   : DEVFREQ_EVENT_TYPE_RAW_DATA
>   : DEVFREQ_EVENT_TYPE_UTILIZATION
>   : DEVFREQ_EVENT_TYPE_BANDWIDTH
>   : DEVFREQ_EVENT_TYPE_LATENCY
> - Add the exclusive feature of devfreq-event device.
>   If devfreq-event device is used on only on devfreq driver,
>   should used 'devfreq_enable_event_dev_exclusive()' function
> - Add new patch6 for test on Exynos3250-based Rinato board
> 
> Chanwoo Choi (9):
>   devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor
>   devfreq: event: Add resource-managed function for devfreq-event device
>   devfreq: event: Add exynos-ppmu devfreq-event driver
>   devfreq: event: Add documentation for exynos-ppmu devfreq-event driver
>   ARM: dts: Add PPMU dt node for Exynos3250 SoC
>   ARM: dts: Add PPMU dt node for Exynos4 SoCs
>   ARM: dts: Add PPMU dt node for Exynos5260 SoC
>   ARM: dts: exynos: Add PPMU node to Exynos3250-based Rinato/Monk board
>   ARM: dts: exynos: Add PPMU node for Exynos4412-based TRATS2 board
> 
>  .../bindings/devfreq/event/exynos-ppmu.txt         | 110 +++++
>  arch/arm/boot/dts/exynos3250-monk.dts              |  40 ++
>  arch/arm/boot/dts/exynos3250-rinato.dts            |  40 ++
>  arch/arm/boot/dts/exynos3250.dtsi                  |  74 +++
>  arch/arm/boot/dts/exynos4.dtsi                     | 108 +++++
>  arch/arm/boot/dts/exynos4210.dtsi                  |   8 +
>  arch/arm/boot/dts/exynos4412-trats2.dts            |  40 ++
>  arch/arm/boot/dts/exynos5260.dtsi                  |  90 ++++
>  drivers/devfreq/Kconfig                            |   2 +
>  drivers/devfreq/Makefile                           |   6 +-
>  drivers/devfreq/devfreq-event.c                    | 511 +++++++++++++++++++++
>  drivers/devfreq/event/Kconfig                      |  25 +
>  drivers/devfreq/event/Makefile                     |   2 +
>  drivers/devfreq/event/exynos-ppmu.c                | 398 ++++++++++++++++
>  include/linux/devfreq-event.h                      | 186 ++++++++
>  15 files changed, 1639 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/devfreq/event/exynos-ppmu.txt
>  create mode 100644 drivers/devfreq/devfreq-event.c
>  create mode 100644 drivers/devfreq/event/Kconfig
>  create mode 100644 drivers/devfreq/event/Makefile
>  create mode 100644 drivers/devfreq/event/exynos-ppmu.c
>  create mode 100644 include/linux/devfreq-event.h
> 


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

* Re: [PATCHv8 7/9] ARM: dts: Add PPMU dt node for Exynos5260 SoC
  2015-01-12 12:34 ` [PATCHv8 7/9] ARM: dts: Add PPMU dt node for Exynos5260 SoC Chanwoo Choi
@ 2015-01-19 10:01   ` Chanwoo Choi
  0 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-19 10:01 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: myungjoo.ham, kgene, kyungmin.park, rafael.j.wysocki,
	mark.rutland, a.kesavan, tomasz.figa, k.kozlowski, b.zolnierkie,
	robh+dt, inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc, Jonghwan Choi

Dear all,

I'll drop this patch because I can't test it on Exynos5260-based board.

Best Regards,
Chanwoo Choi

On 01/12/2015 09:34 PM, Chanwoo Choi wrote:
> This patch adds PPMU (Performance Profiling Monitoring Unit) dt node
> Exynos5260 SoC.
> 
> Exynos5260 SoC has following PPMU IPs:
> - PPMU_DREX0_S0 0x10c60000
> - PPMU_DREX0_S1 0x10c70000
> - PPMU_DREX1_S0 0x10c80000
> - PPMU_DREX1_S1 0x10c90000
> - PPMU_EAGLE    0x10cc0000
> - PPMU_KFC      0x10cd0000
> - PPMU_MFC      0x11040000
> - PPMU_G3D      0x11880000
> - PPMU_FSYS     0x12220000
> - PPMU_ISP      0x13370000
> - PPMU_FICM     0x13cb0000
> - PPMU_GSCL     0x13e60000
> - PPMU_MSCL     0x13ee0000
> - PPMU_FIMD0X   0x145b0000
> - PPMU_FIMD1X   0x145c0000
> 
> The drivers/devfreq/exynos/exynos5_bus.c supports the memory bus frequency/
> voltage scaling of Exynos5260 SoC with DEVFREQ framework.
> 
> Cc: Kukjin Kim <kgene@kernel.org>
> Cc: Abhilash Kesavan <a.kesavan@samsung.com>
> Cc: Jonghwan Choi <jhbird.choi@samsung.com>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  arch/arm/boot/dts/exynos5260.dtsi | 90 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 90 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/exynos5260.dtsi b/arch/arm/boot/dts/exynos5260.dtsi
> index 36da38e..26f3074 100644
> --- a/arch/arm/boot/dts/exynos5260.dtsi
> +++ b/arch/arm/boot/dts/exynos5260.dtsi
> @@ -307,6 +307,96 @@
>  			fifo-depth = <64>;
>  			status = "disabled";
>  		};
> +
> +		ppmu_drex0_s0: ppmu_drex0_s0@10c60000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x10c60000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_drex0_s1: ppmu_drex0_s1@10c70000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x10c70000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_drex1_s0: ppmu_drex1_s0@10c80000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x10c80000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_drex1_s1: ppmu_drex1_s1@10c90000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x10c90000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_eagle: ppmu_eagle@10cc0000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x10cc0000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_kfc: ppmu_kfc@10cd0000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x10cd0000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_mfc: ppmu_mfc@11040000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x11040000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_g3d: ppmu_g3d@11880000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x11880000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_fsys: ppmu_fsys@12220000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x12220000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_isp: ppmu_isp@13370000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x13370000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_fimc: ppmu_fimc@13cb0000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x13cb0000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_gscl: ppmu_gscl@13e60000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x13e60000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_mscl: ppmu_gscl@13ee0000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x13ee0000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_fimd0x: ppmu_fimd0x@145b0000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x145b0000 0x2000>;
> +			status = "disabled";
> +		};
> +
> +		ppmu_fimd1x: ppmu_fimd1x@145c0000 {
> +			compatible = "samsung,exynos-ppmu";
> +			reg = <0x145c0000 0x2000>;
> +			status = "disabled";
> +		};
>  	};
>  };
>  
> 


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

* Re: [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor
  2015-01-12 12:34 ` [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor Chanwoo Choi
@ 2015-01-19 10:12   ` Chanwoo Choi
  0 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-19 10:12 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: myungjoo.ham, kgene, kyungmin.park, rafael.j.wysocki,
	mark.rutland, a.kesavan, tomasz.figa, k.kozlowski, b.zolnierkie,
	robh+dt, inki.dae, linux-pm, linux-kernel, linux-arm-kernel,
	linux-samsung-soc

Dear Myungjoo,

Following patches need to review from you (DEVFREQ maintainer). Please review these patches.
- [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor
- [PATCHv8 2/9] devfreq: event: Add resource-managed function for devfreq-event device

Best Regards,
Chanwoo Choi

On 01/12/2015 09:34 PM, Chanwoo Choi wrote:
> This patch add new devfreq_event class for devfreq_event device which provide
> raw data (e.g., memory bus utilization/GPU utilization). This raw data from
> devfreq_event data would be used for the governor of devfreq subsystem.
> - devfreq_event device : Provide raw data for governor of existing devfreq device
> - devfreq device       : Monitor device state and change frequency/voltage of device
>                          using the raw data from devfreq_event device
> 
> The devfreq subsystem support generic DVFS(Dynamic Voltage/Frequency Scaling)
> for Non-CPU Devices. The devfreq device would dertermine current device state
> using various governor (e.g., ondemand, performance, powersave). After completed
> determination of system state, devfreq device would change the frequency/voltage
> of devfreq device according to the result of governor.
> 
> But, devfreq governor must need basic data which indicates current device state.
> Existing devfreq subsystem only consider devfreq device which check current system
> state and determine proper system state using basic data. There is no subsystem
> for device providing basic data to devfreq device.
> 
> The devfreq subsystem must need devfreq_event device(data-provider device) for
> existing devfreq device. So, this patch add new devfreq_event class for
> devfreq_event device which read various basic data(e.g, memory bus utilization,
> GPU utilization) and provide measured data to existing devfreq device through
> standard APIs of devfreq_event class.
> 
> The following description explains the feature of two kind of devfreq class:
> - devfreq class (existing)
>  : devfreq consumer device use raw data from devfreq_event device for
>    determining proper current system state and change voltage/frequency
>    dynamically using various governors.
> 
> - devfreq_event class (new)
>  : Provide measured raw data to devfreq device for governor
> 
> Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
> Cc: Kyungmin Park <kyungmin.park@samsung.com>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  drivers/devfreq/Kconfig         |   2 +
>  drivers/devfreq/Makefile        |   6 +-
>  drivers/devfreq/devfreq-event.c | 448 ++++++++++++++++++++++++++++++++++++++++
>  drivers/devfreq/event/Kconfig   |  16 ++
>  drivers/devfreq/event/Makefile  |   1 +
>  include/linux/devfreq-event.h   | 170 +++++++++++++++
>  6 files changed, 642 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/devfreq/devfreq-event.c
>  create mode 100644 drivers/devfreq/event/Kconfig
>  create mode 100644 drivers/devfreq/event/Makefile
>  create mode 100644 include/linux/devfreq-event.h
> 
> diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
> index faf4e70..21f8f17 100644
> --- a/drivers/devfreq/Kconfig
> +++ b/drivers/devfreq/Kconfig
> @@ -87,4 +87,6 @@ config ARM_EXYNOS5_BUS_DEVFREQ
>  	  It reads PPMU counters of memory controllers and adjusts the
>  	  operating frequencies and voltages with OPP support.
>  
> +source "drivers/devfreq/event/Kconfig"
> +
>  endif # PM_DEVFREQ
> diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
> index 16138c9..c449336 100644
> --- a/drivers/devfreq/Makefile
> +++ b/drivers/devfreq/Makefile
> @@ -1,4 +1,5 @@
> -obj-$(CONFIG_PM_DEVFREQ)	+= devfreq.o
> +obj-$(CONFIG_PM_DEVFREQ)		+= devfreq.o
> +obj-$(CONFIG_PM_DEVFREQ_EVENT)		+= devfreq-event.o
>  obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)	+= governor_simpleondemand.o
>  obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)	+= governor_performance.o
>  obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
> @@ -7,3 +8,6 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
>  # DEVFREQ Drivers
>  obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ)	+= exynos/
>  obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ)	+= exynos/
> +
> +# DEVFREQ Event Drivers
> +obj-$(CONFIG_PM_DEVFREQ_EVENT)		+= event/
> diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c
> new file mode 100644
> index 0000000..9ba5ba4
> --- /dev/null
> +++ b/drivers/devfreq/devfreq-event.c
> @@ -0,0 +1,448 @@
> +/*
> + * devfreq-event: a framework to provide raw data and events of devfreq devices
> + *
> + * Copyright (C) 2014 Samsung Electronics
> + * Author: Chanwoo Choi <cw00.choi@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This driver is based on drivers/devfreq/devfreq.c.
> + */
> +
> +#include <linux/devfreq-event.h>
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/list.h>
> +#include <linux/of.h>
> +
> +static struct class *devfreq_event_class;
> +
> +/* The list of all devfreq event list */
> +static LIST_HEAD(devfreq_event_list);
> +static DEFINE_MUTEX(devfreq_event_list_lock);
> +
> +#define to_devfreq_event(DEV) container_of(DEV, struct devfreq_event_dev, dev)
> +
> +/**
> + * devfreq_event_enable_edev() - Enable the devfreq-event dev and increase
> + *				 the enable_count of devfreq-event dev.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function increase the enable_count and enable the
> + * devfreq-event device. The devfreq-event device should be enabled before
> + * using it by devfreq device.
> + */
> +int devfreq_event_enable_edev(struct devfreq_event_dev *edev)
> +{
> +	int ret = 0;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	mutex_lock(&edev->lock);
> +	if (edev->desc->ops && edev->desc->ops->enable) {
> +		ret = edev->desc->ops->enable(edev);
> +		if (ret < 0)
> +			goto err;
> +	}
> +	edev->enable_count++;
> +err:
> +	mutex_unlock(&edev->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_enable_edev);
> +
> +/**
> + * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease
> + *				  the enable_count of the devfreq-event dev.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function decrease the enable_count and disable the
> + * devfreq-event device. After the devfreq-event device is disabled,
> + * devfreq device can't use the devfreq-event device for get/set/reset
> + * operations.
> + */
> +int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
> +{
> +	int ret = 0;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	mutex_lock(&edev->lock);
> +	if (edev->enable_count > 0) {
> +		edev->enable_count--;
> +	} else {
> +		dev_warn(&edev->dev, "unbalanced enable_count\n");
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	if (edev->desc->ops && edev->desc->ops->disable) {
> +		ret = edev->desc->ops->disable(edev);
> +		if (ret < 0) {
> +			edev->enable_count++;
> +			goto err;
> +		}
> +	}
> +err:
> +	mutex_unlock(&edev->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_disable_edev);
> +
> +/**
> + * devfreq_event_is_enabled() - Check whether devfreq-event dev is enabled or
> + *				not.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function check whether devfreq-event dev is enabled or not.
> + * If return true, the devfreq-event dev is enabeld. If return false, the
> + * devfreq-event dev is disabled.
> + */
> +bool devfreq_event_is_enabled(struct devfreq_event_dev *edev)
> +{
> +	bool enabled = false;
> +
> +	if (!edev || !edev->desc)
> +		return enabled;
> +
> +	mutex_lock(&edev->lock);
> +
> +	if (edev->enable_count > 0)
> +		enabled = true;
> +
> +	mutex_unlock(&edev->lock);
> +
> +	return enabled;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_is_enabled);
> +
> +/**
> + * devfreq_event_set_event() - Set event to devfreq-event dev to start.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function set the event to the devfreq-event device to start
> + * for getting the event data which could be various event type.
> + */
> +int devfreq_event_set_event(struct devfreq_event_dev *edev)
> +{
> +	int ret;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	if (!edev->desc->ops || !edev->desc->ops->set_event)
> +		return -EINVAL;
> +
> +	if (!devfreq_event_is_enabled(edev))
> +		return -EPERM;
> +
> +	mutex_lock(&edev->lock);
> +	ret = edev->desc->ops->set_event(edev);
> +	mutex_unlock(&edev->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_set_event);
> +
> +/**
> + * devfreq_event_get_event() - Get event and total_event from devfreq-event dev.
> + * @edev	: the devfreq-event device
> + * @edata	: the calculated data of devfreq-event device
> + *
> + * Note that this function get the calculated event data from devfreq-event dev
> + * after stoping the progress of whole sequence of devfreq-event dev.
> + */
> +int devfreq_event_get_event(struct devfreq_event_dev *edev,
> +			    struct devfreq_event_data *edata)
> +{
> +	int ret;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	if (!edev->desc->ops || !edev->desc->ops->get_event)
> +		return -EINVAL;
> +
> +	if (!devfreq_event_is_enabled(edev))
> +		return -EINVAL;
> +
> +	edata->event = edata->total_event = 0;
> +
> +	mutex_lock(&edev->lock);
> +	ret = edev->desc->ops->get_event(edev, edata);
> +	mutex_unlock(&edev->lock);
> +
> +	if ((edata->total_event <= 0)
> +		|| (edata->event > edata->total_event)) {
> +		edata->event = edata->total_event = 0;
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_get_event);
> +
> +/**
> + * devfreq_event_reset_event() - Reset all opeations of devfreq-event dev.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function stop all operations of devfreq-event dev and reset
> + * the current event data to make the devfreq-event device into initial state.
> + */
> +int devfreq_event_reset_event(struct devfreq_event_dev *edev)
> +{
> +	int ret = 0;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	if (!devfreq_event_is_enabled(edev))
> +		return -EPERM;
> +
> +	mutex_lock(&edev->lock);
> +	if (edev->desc->ops && edev->desc->ops->reset)
> +		ret = edev->desc->ops->reset(edev);
> +	mutex_unlock(&edev->lock);
> +
> +	if (ret < 0)
> +		return -EINVAL;
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_reset_event);
> +
> +/**
> + * devfreq_event_get_drvdata() - Return driver-data of devfreq-event dev.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function return the driver-data of devfreq-event device.
> + */
> +void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev)
> +{
> +	return edev->desc->driver_data;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_get_drvdata);
> +
> +/**
> + * devfreq_event_get_edev_by_phandle() - Get the devfreq-event dev from
> + *					 devicetree.
> + * @dev		: the pointer to the given device
> + * @index	: the index into list of devfreq-event device
> + *
> + * Note that this function return the pointer of devfreq-event device.
> + */
> +struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev,
> +						      int index)
> +{
> +	struct device_node *node;
> +	struct devfreq_event_dev *edev;
> +
> +	if (!dev->of_node) {
> +		dev_err(dev, "device does not have a device node entry\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	node = of_parse_phandle(dev->of_node, "devfreq-events", index);
> +	if (!node) {
> +		dev_err(dev, "failed to get phandle in %s node\n",
> +			dev->of_node->full_name);
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	mutex_lock(&devfreq_event_list_lock);
> +	list_for_each_entry(edev, &devfreq_event_list, node) {
> +		if (!strcmp(edev->desc->name, node->name))
> +			goto out;
> +	}
> +	edev = NULL;
> +out:
> +	mutex_unlock(&devfreq_event_list_lock);
> +
> +	if (!edev) {
> +		dev_err(dev, "unable to get devfreq-event device : %s\n",
> +			node->name);
> +		of_node_put(node);
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	of_node_put(node);
> +
> +	return edev;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle);
> +
> +/**
> + * devfreq_event_get_edev_count() - Get the count of devfreq-event dev
> + * @dev		: the pointer to the given device
> + *
> + * Note that this function return the count of devfreq-event devices.
> + */
> +int devfreq_event_get_edev_count(struct device *dev)
> +{
> +	int count;
> +
> +	if (!dev->of_node) {
> +		dev_err(dev, "device does not have a device node entry\n");
> +		return -EINVAL;
> +	}
> +
> +	count = of_property_count_elems_of_size(dev->of_node, "devfreq-events",
> +						sizeof(u32));
> +	if (count < 0 ) {
> +		dev_err(dev,
> +			"failed to get the count of devfreq-event in %s node\n",
> +			dev->of_node->full_name);
> +		return count;
> +	}
> +
> +	return count;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count);
> +
> +static void devfreq_event_release_edev(struct device *dev)
> +{
> +	struct devfreq_event_dev *edev = to_devfreq_event(dev);
> +
> +	kfree(edev);
> +}
> +
> +/**
> + * devfreq_event_add_edev() - Add new devfreq-event device.
> + * @dev		: the device owning the devfreq-event device being created
> + * @desc	: the devfreq-event device's decriptor which include essential
> + *		  data for devfreq-event device.
> + *
> + * Note that this function add new devfreq-event device to devfreq-event class
> + * list and register the device of the devfreq-event device.
> + */
> +struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
> +						struct devfreq_event_desc *desc)
> +{
> +	struct devfreq_event_dev *edev;
> +	static atomic_t event_no = ATOMIC_INIT(0);
> +	int ret;
> +
> +	if (!dev || !desc)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!desc->name || !desc->ops)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!desc->ops->set_event || !desc->ops->get_event)
> +		return ERR_PTR(-EINVAL);
> +
> +	edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL);
> +	if (!edev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mutex_init(&edev->lock);
> +	edev->desc = desc;
> +	edev->dev.parent = dev;
> +	edev->dev.class = devfreq_event_class;
> +	edev->dev.release = devfreq_event_release_edev;
> +
> +	dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1);
> +	ret = device_register(&edev->dev);
> +	if (ret < 0) {
> +		put_device(&edev->dev);
> +		return ERR_PTR(ret);
> +	}
> +	dev_set_drvdata(&edev->dev, edev);
> +
> +	INIT_LIST_HEAD(&edev->node);
> +
> +	mutex_lock(&devfreq_event_list_lock);
> +	list_add(&edev->node, &devfreq_event_list);
> +	mutex_unlock(&devfreq_event_list_lock);
> +
> +	return edev;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_add_edev);
> +
> +/**
> + * devfreq_event_remove_edev() - Remove the devfreq-event device registered.
> + * @dev		: the devfreq-event device
> + *
> + * Note that this function remove the registered devfreq-event device.
> + */
> +int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
> +{
> +	if (!edev)
> +		return -EINVAL;
> +
> +	mutex_lock(&devfreq_event_list_lock);
> +	WARN_ON(edev->enable_count);
> +	list_del(&edev->node);
> +	device_unregister(&edev->dev);
> +	mutex_unlock(&devfreq_event_list_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_remove_edev);
> +
> +/*
> + * Device attributes for devfreq-event class.
> + */
> +static ssize_t name_show(struct device *dev, struct device_attribute *attr,
> +			 char *buf)
> +{
> +	struct devfreq_event_dev *edev = to_devfreq_event(dev);
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	return sprintf(buf, "%s\n", edev->desc->name);
> +}
> +static DEVICE_ATTR_RO(name);
> +
> +static ssize_t enable_count_show(struct device *dev,
> +				  struct device_attribute *attr, char *buf)
> +{
> +	struct devfreq_event_dev *edev = to_devfreq_event(dev);
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	return sprintf(buf, "%d\n", edev->enable_count);
> +}
> +static DEVICE_ATTR_RO(enable_count);
> +
> +static struct attribute *devfreq_event_attrs[] = {
> +	&dev_attr_name.attr,
> +	&dev_attr_enable_count.attr,
> +	NULL,
> +};
> +ATTRIBUTE_GROUPS(devfreq_event);
> +
> +static int __init devfreq_event_init(void)
> +{
> +	devfreq_event_class = class_create(THIS_MODULE, "devfreq-event");
> +	if (IS_ERR(devfreq_event_class)) {
> +		pr_err("%s: couldn't create class\n", __FILE__);
> +		return PTR_ERR(devfreq_event_class);
> +	}
> +
> +	devfreq_event_class->dev_groups = devfreq_event_groups;
> +
> +	return 0;
> +}
> +subsys_initcall(devfreq_event_init);
> +
> +static void __exit devfreq_event_exit(void)
> +{
> +	class_destroy(devfreq_event_class);
> +}
> +module_exit(devfreq_event_exit);
> +
> +MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
> +MODULE_DESCRIPTION("DEVFREQ-Event class support");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig
> new file mode 100644
> index 0000000..1ced42c
> --- /dev/null
> +++ b/drivers/devfreq/event/Kconfig
> @@ -0,0 +1,16 @@
> +menuconfig PM_DEVFREQ_EVENT
> +	bool "DEVFREQ-Event device Support"
> +	help
> +	  The devfreq-event device provide the raw data and events which
> +	  indicate the current state of devfreq-event device. The provided
> +	  data from devfreq-event device is used to monitor the state of
> +	  device and determine the suitable size of resource to reduce the
> +	  wasted resource.
> +
> +	  The devfreq-event device can support the various type of events
> +	  (e.g., raw data, utilization, latency, bandwidth). The events
> +	  may be used by devfreq governor and other subsystem.
> +
> +if PM_DEVFREQ_EVENT
> +
> +endif # PM_DEVFREQ_EVENT
> diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile
> new file mode 100644
> index 0000000..dc56005
> --- /dev/null
> +++ b/drivers/devfreq/event/Makefile
> @@ -0,0 +1 @@
> +# Exynos DEVFREQ Event Drivers
> diff --git a/include/linux/devfreq-event.h b/include/linux/devfreq-event.h
> new file mode 100644
> index 0000000..b7363f5
> --- /dev/null
> +++ b/include/linux/devfreq-event.h
> @@ -0,0 +1,170 @@
> +/*
> + * devfreq-event: a framework to provide raw data and events of devfreq devices
> + *
> + * Copyright (C) 2014 Samsung Electronics
> + * Author: Chanwoo Choi <cw00.choi@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __LINUX_DEVFREQ_EVENT_H__
> +#define __LINUX_DEVFREQ_EVENT_H__
> +
> +#include <linux/device.h>
> +
> +/**
> + * struct devfreq_event_dev - the devfreq-event device
> + *
> + * @node	: Contain the devfreq-event device that have been registered.
> + * @dev		: the device registered by devfreq-event class. dev.parent is
> + *		  the device using devfreq-event.
> + * @lock	: a mutex to protect accessing devfreq-event.
> + * @enable_count: the number of enable function have been called.
> + * @desc	: the description for devfreq-event device.
> + *
> + * This structure contains devfreq-event device information.
> + */
> +struct devfreq_event_dev {
> +	struct list_head node;
> +
> +	struct device dev;
> +	struct mutex lock;
> +	u32 enable_count;
> +
> +	const struct devfreq_event_desc *desc;
> +};
> +
> +/**
> + * struct devfreq_event_data - the devfreq-event data
> + *
> + * @event	: the load of devfreq-event device for polling period
> + * @total_event	: the total load of devfreq-event device for polling period
> + *
> + * This structure contains the data of devfreq-event device for polling period.
> + */
> +struct devfreq_event_data {
> +	unsigned long event;
> +	unsigned long total_event;
> +};
> +
> +/**
> + * struct devfreq_event_ops - the operations of devfreq-event device
> + *
> + * @enable	: Enable the devfreq-event device.
> + * @disable	: Disable the devfreq-event device.
> + * @reset	: Reset all setting of the devfreq-event device.
> + * @set_event	: Set the specific event type for the devfreq-event device.
> + * @get_event	: Get the result of the devfreq-event devie with specific
> + *		  event type.
> + *
> + * This structure contains devfreq-event device operations which can be
> + * implemented by devfreq-event device drivers.
> + */
> +struct devfreq_event_ops {
> +	/* Optional functions */
> +	int (*enable)(struct devfreq_event_dev *edev);
> +	int (*disable)(struct devfreq_event_dev *edev);
> +	int (*reset)(struct devfreq_event_dev *edev);
> +
> +	/* Mandatory functions */
> +	int (*set_event)(struct devfreq_event_dev *edev);
> +	int (*get_event)(struct devfreq_event_dev *edev,
> +			 struct devfreq_event_data *edata);
> +};
> +
> +/**
> + * struct devfreq_event_desc - the descriptor of devfreq-event device
> + *
> + * @name	: the name of devfreq-event device.
> + * @driver_data	: the private data for devfreq-event driver.
> + * @ops		: the operation to control devfreq-event device.
> + *
> + * Each devfreq-event device is described with a this structure.
> + * This structure contains the various data for devfreq-event device.
> + */
> +struct devfreq_event_desc {
> +	const char *name;
> +	void *driver_data;
> +
> +	struct devfreq_event_ops *ops;
> +};
> +
> +#if defined(CONFIG_PM_DEVFREQ_EVENT)
> +extern int devfreq_event_enable_edev(struct devfreq_event_dev *edev);
> +extern int devfreq_event_disable_edev(struct devfreq_event_dev *edev);
> +extern bool devfreq_event_is_enabled(struct devfreq_event_dev *edev);
> +extern int devfreq_event_set_event(struct devfreq_event_dev *edev);
> +extern int devfreq_event_get_event(struct devfreq_event_dev *edev,
> +				struct devfreq_event_data *edata);
> +extern int devfreq_event_reset_event(struct devfreq_event_dev *edev);
> +extern void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev);
> +extern struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(
> +				struct device *dev, int index);
> +extern int devfreq_event_get_edev_count(struct device *dev);
> +extern struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
> +				struct devfreq_event_desc *desc);
> +extern int devfreq_event_remove_edev(struct devfreq_event_dev *edev);
> +
> +#else
> +static inline int devfreq_event_enable_edev(struct devfreq_event_dev *edev)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline bool devfreq_event_is_enabled(struct devfreq_event_dev *edev)
> +{
> +	return false;
> +}
> +
> +static inline int devfreq_event_set_event(struct devfreq_event_dev *edev)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline int devfreq_event_get_event(struct devfreq_event_dev *edev,
> +					struct devfreq_event_data *edata)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline int devfreq_event_reset_event(struct devfreq_event_dev *edev)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev)
> +{
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +static inline struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(
> +					struct device *dev, int index)
> +{
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +static inline int devfreq_event_get_edev_count(struct device *dev)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
> +					struct devfreq_event_desc *desc)
> +{
> +	return ERR_PTR(-EINVAL);
> +}
> +
> +static inline int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
> +{
> +	return -EINVAL;
> +}
> +#endif /* CONFIG_PM_DEVFREQ_EVENT */
> +
> +#endif /* __LINUX_DEVFREQ_EVENT_H__ */
> 


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

* Re: [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor
  2015-01-20  6:59 MyungJoo Ham
@ 2015-01-20  7:25 ` Chanwoo Choi
  0 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-20  7:25 UTC (permalink / raw)
  To: myungjoo.ham
  Cc: kgene, 박경민,
	rafael.j.wysocki, mark.rutland, ABHILASH KESAVAN, tomasz.figa,
	Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz, robh+dt,
	대인기,
	linux-pm, linux-kernel, linux-arm-kernel, linux-samsung-soc

Dear Myungjoo,

On 01/20/2015 03:59 PM, MyungJoo Ham wrote:
>>  
>> Dear Myungjoo,
>>
>> On 01/20/2015 01:34 PM, MyungJoo Ham wrote:
>>>>   
> []
>>>> +
>>>> +	mutex_lock(&edev->lock);
>>>> +	if (edev->desc->ops && edev->desc->ops->enable) {
>>>> +		ret = edev->desc->ops->enable(edev);
>>>> +		if (ret < 0)
>>>> +			goto err;
>>>> +	}
>>>
>>> Is there any reason to call enable(edev) even when enable_count is already > 0 
>>> while you do not call disable(edev) while enable_count > 0?
>>>
>>> I think this may incur errors in the related device drivers.
>>> (e.g., incorrect pairing of clk/runtime-pm/regulator enable/disable
>>> at the device driver side)
>>
>> You're right. This part has potential errors. I'll fix it as following:
>> If edev is already enabled, devfreq_event_enable_edev() will just return
>> without any operation because devfreq-event(edev) can handle only one event
>> at the same time.
>>
>> 	mutex_lock(&edev->lock);
>> 	if (edev->enable_count)
>> 		dev_warn(&edev->dev, "%s is already enabled\n", edev->desc->name);
>> 		ret = -EINVAL;
>> 		goto err;
>> 	}
>>
>> 	if (edev->desc->ops && edev->desc->ops->enable) {		
>> 		ret = edev->desc->ops->enable(edev);
>> 		if (ret < 0)
>> 			goto err;
>> 	}
>> 	edev->enable_count++;
> 
> No, your suggested modification creates another bug.
> 
> It should not emit "warn" when enable_count > 0 at enable().
> It is a natural behavior from drivers.
> - You may have multiple drivers using edev.
> - You may have multiple threads using edev.

The devfreq-event cannot be used in multiple drivers in current version
If multiple driver set the event to devfreq-event device by using
devfreq_event_set_event() at the same time, previous event will be ignored.

If multiple drivers want to use devfreq-event device at the same time,
I have to implement additional feature.

> 
> Thus, the above 12 lines should be replaced with:
> 
> 	if (edev->desc->ops && edev->desc->ops->enable &&
> 	    edev->enable_count == 0) {
> 		ret = edev->desc->ops->enable(edev);
> 		if (ret < 0)
> 			goto err;
> 	}
> 	edev->enable_count++;
> 
>> 	
>>
>>>
>>>> +	edev->enable_count++;
>>>> +err:
>>>> +	mutex_unlock(&edev->lock);
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(devfreq_event_enable_edev);
>>>> +
>>>> +/**
>>>> + * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease
>>>> + *				  the enable_count of the devfreq-event dev.
>>>> + * @edev	: the devfreq-event device
>>>> + *
>>>> + * Note that this function decrease the enable_count and disable the
>>>> + * devfreq-event device. After the devfreq-event device is disabled,
>>>> + * devfreq device can't use the devfreq-event device for get/set/reset
>>>> + * operations.
>>>> + */
>>>> +int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
>>>> +{
>>>> +	int ret = 0;
>>>> +
>>>> +	if (!edev || !edev->desc)
>>>> +		return -EINVAL;
>>>> +
>>>> +	mutex_lock(&edev->lock);
>>>> +	if (edev->enable_count > 0) {
>>>> +		edev->enable_count--;
>>>> +	} else {
>>>> +		dev_warn(&edev->dev, "unbalanced enable_count\n");
>>>> +		ret = -EINVAL;
>>>> +		goto err;
>>>> +	}
>>>> +
>>>> +	if (edev->desc->ops && edev->desc->ops->disable) {
>>>> +		ret = edev->desc->ops->disable(edev);
>>>> +		if (ret < 0) {
>>>> +			edev->enable_count++;
>>>> +			goto err;
>>>> +		}
> 
> Anyway, have you seen other subsystems doing fall-back operations as you've
> done by "edev->enable_count++" here? Or is this your own idea on falling back
> from errors with a disable callback?

I removed "edev->enable_count++" when fail to diable devfreq-event
and modify it as following:

	+int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
	+{
	+	int ret = 0;
	+
	+	if (!edev || !edev->desc)
	+		return -EINVAL;
	+
	+	mutex_lock(&edev->lock);
	+	if (!edev->enable_count) {
	+		dev_warn(&edev->dev,
	+			"%s is already disabled\n", edev->desc->name);
	+		goto err;
	+	}
	+	
	+	if (edev->desc->ops && edev->desc->ops->disable) {
	+		ret = edev->desc->ops->disable(edev);
	+		if (ret < 0)
	+			goto err;
	+	}
	+	edev->enable_count--;
	+err:
	+	mutex_unlock(&edev->lock);
	+
	+	return ret;
	+}
	+EXPORT_SYMBOL_GPL(devfreq_event_disable_edev);

> 
>>>> +	}
>>>
>>> You did it correctly with disable here;
>>> not calling it when it is not required.
> 
> Uh..yeah.. the original patch was incorrect..
> 
>>
>> As I explained, I'll fix it as following:
>>
>> 	mutex_lock(&edev->lock);
>> 	if (!edev->enable_count) {
>> 		dev_warn(&edev->dev, "%s is already disabled\n", edev->desc->name);
>> 		ret = -EINVAL;
>> 		goto err;
>> 	}
>>
>> 	if (edev->desc->ops && edev->desc->ops->disable) {
>> 		ret = edev->desc->ops->disable(edev);
>> 		if (ret < 0)
>> 			goto err;		
>> 	}
>> 	edev->enable_count--;
> 
> Uh.... I'd say it is still incorrect.

I explained it about this problem on the upper.

> 
> 	mutex_lock(&edev->lock);
> 	if (!edev->enable_count) {
> 		dev_warn(&edev->dev, "%s is already disabled\n", edev->desc->name);
> 		ret = -EINVAL;
> 		goto err;
> 	}
> 
> 	edev->enable_count--;
> 	if (edev->desc->ops && edev->desc->ops->disable &&
> 	    !edev->enable_count) {
> 		ret = edev->desc->ops->disable(edev);
> 		if (ret < 0)
> 			goto err;		
> 	}

[snip]

Best Regards,
Chanwoo Choi


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

* Re: [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor
  2015-01-20  4:34 [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor MyungJoo Ham
@ 2015-01-20  5:29 ` Chanwoo Choi
  0 siblings, 0 replies; 16+ messages in thread
From: Chanwoo Choi @ 2015-01-20  5:29 UTC (permalink / raw)
  To: myungjoo.ham
  Cc: kgene, 박경민,
	rafael.j.wysocki, mark.rutland, ABHILASH KESAVAN, tomasz.figa,
	Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz, robh+dt,
	대인기,
	linux-pm, linux-kernel, linux-arm-kernel, linux-samsung-soc

Dear Myungjoo,

On 01/20/2015 01:34 PM, MyungJoo Ham wrote:
>>   
>>  This patch add new devfreq_event class for devfreq_event device which provide
>> raw data (e.g., memory bus utilization/GPU utilization). This raw data from
>> devfreq_event data would be used for the governor of devfreq subsystem.
>> - devfreq_event device : Provide raw data for governor of existing devfreq device
>> - devfreq device       : Monitor device state and change frequency/voltage of device
>>                          using the raw data from devfreq_event device
>>
>> The devfreq subsystem support generic DVFS(Dynamic Voltage/Frequency Scaling)
>> for Non-CPU Devices. The devfreq device would dertermine current device state
>> using various governor (e.g., ondemand, performance, powersave). After completed
>> determination of system state, devfreq device would change the frequency/voltage
>> of devfreq device according to the result of governor.
>>
>> But, devfreq governor must need basic data which indicates current device state.
>> Existing devfreq subsystem only consider devfreq device which check current system
>> state and determine proper system state using basic data. There is no subsystem
>> for device providing basic data to devfreq device.
>>
>> The devfreq subsystem must need devfreq_event device(data-provider device) for
>> existing devfreq device. So, this patch add new devfreq_event class for
>> devfreq_event device which read various basic data(e.g, memory bus utilization,
>> GPU utilization) and provide measured data to existing devfreq device through
>> standard APIs of devfreq_event class.
>>
>> The following description explains the feature of two kind of devfreq class:
>> - devfreq class (existing)
>>  : devfreq consumer device use raw data from devfreq_event device for
>>    determining proper current system state and change voltage/frequency
>>    dynamically using various governors.
>>
>> - devfreq_event class (new)
>>  : Provide measured raw data to devfreq device for governor
>>
>> Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
>> Cc: Kyungmin Park <kyungmin.park@samsung.com>
>> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
>> ---
> 
> []
> 
>> +/**
>> + * devfreq_event_enable_edev() - Enable the devfreq-event dev and increase
>> + *				 the enable_count of devfreq-event dev.
>> + * @edev	: the devfreq-event device
>> + *
>> + * Note that this function increase the enable_count and enable the
>> + * devfreq-event device. The devfreq-event device should be enabled before
>> + * using it by devfreq device.
>> + */
>> +int devfreq_event_enable_edev(struct devfreq_event_dev *edev)
>> +{
>> +	int ret = 0;
>> +
>> +	if (!edev || !edev->desc)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&edev->lock);
>> +	if (edev->desc->ops && edev->desc->ops->enable) {
>> +		ret = edev->desc->ops->enable(edev);
>> +		if (ret < 0)
>> +			goto err;
>> +	}
> 
> Is there any reason to call enable(edev) even when enable_count is already > 0 
> while you do not call disable(edev) while enable_count > 0?
> 
> I think this may incur errors in the related device drivers.
> (e.g., incorrect pairing of clk/runtime-pm/regulator enable/disable
> at the device driver side)

You're right. This part has potential errors. I'll fix it as following:
If edev is already enabled, devfreq_event_enable_edev() will just return
without any operation because devfreq-event(edev) can handle only one event
at the same time.
 
	mutex_lock(&edev->lock);
	if (edev->enable_count)
		dev_warn(&edev->dev, "%s is already enabled\n", edev->desc->name);
		ret = -EINVAL;
		goto err;
	}

	if (edev->desc->ops && edev->desc->ops->enable) {		
		ret = edev->desc->ops->enable(edev);
		if (ret < 0)
			goto err;
	}
	edev->enable_count++;
	

> 
>> +	edev->enable_count++;
>> +err:
>> +	mutex_unlock(&edev->lock);
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(devfreq_event_enable_edev);
>> +
>> +/**
>> + * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease
>> + *				  the enable_count of the devfreq-event dev.
>> + * @edev	: the devfreq-event device
>> + *
>> + * Note that this function decrease the enable_count and disable the
>> + * devfreq-event device. After the devfreq-event device is disabled,
>> + * devfreq device can't use the devfreq-event device for get/set/reset
>> + * operations.
>> + */
>> +int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
>> +{
>> +	int ret = 0;
>> +
>> +	if (!edev || !edev->desc)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&edev->lock);
>> +	if (edev->enable_count > 0) {
>> +		edev->enable_count--;
>> +	} else {
>> +		dev_warn(&edev->dev, "unbalanced enable_count\n");
>> +		ret = -EINVAL;
>> +		goto err;
>> +	}
>> +
>> +	if (edev->desc->ops && edev->desc->ops->disable) {
>> +		ret = edev->desc->ops->disable(edev);
>> +		if (ret < 0) {
>> +			edev->enable_count++;
>> +			goto err;
>> +		}
>> +	}
> 
> You did it correctly with disable here;
> not calling it when it is not required.

As I explained, I'll fix it as following:

	mutex_lock(&edev->lock);
	if (!edev->enable_count) {
		dev_warn(&edev->dev, "%s is already disabled\n", edev->desc->name);
		ret = -EINVAL;
		goto err;
	}

	if (edev->desc->ops && edev->desc->ops->disable) {
		ret = edev->desc->ops->disable(edev);
		if (ret < 0)
			goto err;		
	}
	edev->enable_count--;

> 
>> +err:
>> +	mutex_unlock(&edev->lock);
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(devfreq_event_disable_edev);
>> +
> 
> []
>> +EXPORT_SYMBOL_GPL(devfreq_event_is_enabled);
> []
> 
>> +EXPORT_SYMBOL_GPL(devfreq_event_set_event);
> []
> 
>> +
>> +/**
>> + * devfreq_event_get_event() - Get event and total_event from devfreq-event dev.
>> + * @edev	: the devfreq-event device
>> + * @edata	: the calculated data of devfreq-event device
>> + *
>> + * Note that this function get the calculated event data from devfreq-event dev
>> + * after stoping the progress of whole sequence of devfreq-event dev.
>> + */
>> +int devfreq_event_get_event(struct devfreq_event_dev *edev,
>> +			    struct devfreq_event_data *edata)
>> +{
>> +	int ret;
>> +
>> +	if (!edev || !edev->desc)
>> +		return -EINVAL;
>> +
>> +	if (!edev->desc->ops || !edev->desc->ops->get_event)
>> +		return -EINVAL;
>> +
>> +	if (!devfreq_event_is_enabled(edev))
>> +		return -EINVAL;
>> +
>> +	edata->event = edata->total_event = 0;
>> +
>> +	mutex_lock(&edev->lock);
>> +	ret = edev->desc->ops->get_event(edev, edata);
>> +	mutex_unlock(&edev->lock);
>> +
>> +	if ((edata->total_event <= 0)
>> +		|| (edata->event > edata->total_event)) {
>> +		edata->event = edata->total_event = 0;
>> +		ret = -EINVAL;
> 
> total_event is unsigned. (cannot be < 0)
> 
> Plus, get_event() may already have returned a negative value with
> the intention of giving a error different from EINVAL.
> 
> I would just simply set total_event = event = 0 if ret < 0

OK, I'll fix it as following:

	if (ret < 0)
		edata->total_event = edata->event = 0;
> 
> 
>> +	}
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(devfreq_event_get_event);
>> +
>> +/**
>> + * devfreq_event_reset_event() - Reset all opeations of devfreq-event dev.
>> + * @edev	: the devfreq-event device
>> + *
>> + * Note that this function stop all operations of devfreq-event dev and reset
>> + * the current event data to make the devfreq-event device into initial state.
>> + */
>> +int devfreq_event_reset_event(struct devfreq_event_dev *edev)
>> +{
>> +	int ret = 0;
>> +
>> +	if (!edev || !edev->desc)
>> +		return -EINVAL;
>> +
>> +	if (!devfreq_event_is_enabled(edev))
>> +		return -EPERM;
>> +
>> +	mutex_lock(&edev->lock);
>> +	if (edev->desc->ops && edev->desc->ops->reset)
>> +		ret = edev->desc->ops->reset(edev);
>> +	mutex_unlock(&edev->lock);
> 
> In the context of the get_event() handling "load",
> aren't you supposed to set total_event = event = 0; here?

But, devfreq_event_reset_event() function cannot handle edata instance
because edata is not included in edev. The edata instance is only used in devfreq_event_get_event().

> 
>> +
>> +	if (ret < 0)
>> +		return -EINVAL;
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(devfreq_event_reset_event);
>> +
>> +/**
>> + * devfreq_event_get_drvdata() - Return driver-data of devfreq-event dev.
>> + * @edev	: the devfreq-event device
>> + *
>> + * Note that this function return the driver-data of devfreq-event device.
>> + */
>> +void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev)
>> +{
>> +	return edev->desc->driver_data;
>> +}
>> +EXPORT_SYMBOL_GPL(devfreq_event_get_drvdata);
> 
> Looks like you can simply write this in the header file.
> (either #define or static inline function)

OK, I'll modify it by using static inline function.

> 
> []
> 
>> +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle);
> []
>> +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count);
> []
> 
>> +/**
>> + * devfreq_event_add_edev() - Add new devfreq-event device.
>> + * @dev		: the device owning the devfreq-event device being created
>> + * @desc	: the devfreq-event device's decriptor which include essential
>> + *		  data for devfreq-event device.
>> + *
>> + * Note that this function add new devfreq-event device to devfreq-event class
>> + * list and register the device of the devfreq-event device.
>> + */
>> +struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
>> +						struct devfreq_event_desc *desc)
>> +{
>> +	struct devfreq_event_dev *edev;
>> +	static atomic_t event_no = ATOMIC_INIT(0);
>> +	int ret;
>> +
>> +	if (!dev || !desc)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	if (!desc->name || !desc->ops)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	if (!desc->ops->set_event || !desc->ops->get_event)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL);
> 
> devm_* here? (seeing no free)

Free edev instance in devfreq_event_release_edev() as following:

	+
	+static void devfreq_event_release_edev(struct device *dev)
	+{
	+	struct devfreq_event_dev *edev = to_devfreq_event(dev);
	+
	+	kfree(edev);
	+}

> 
>> +	if (!edev)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	mutex_init(&edev->lock);
>> +	edev->desc = desc;
>> +	edev->dev.parent = dev;
>> +	edev->dev.class = devfreq_event_class;
>> +	edev->dev.release = devfreq_event_release_edev;
>> +
>> +	dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1);
>> +	ret = device_register(&edev->dev);
>> +	if (ret < 0) {
>> +		put_device(&edev->dev);
>> +		return ERR_PTR(ret);
>> +	}
>> +	dev_set_drvdata(&edev->dev, edev);
>> +
>> +	INIT_LIST_HEAD(&edev->node);
>> +
>> +	mutex_lock(&devfreq_event_list_lock);
>> +	list_add(&edev->node, &devfreq_event_list);
>> +	mutex_unlock(&devfreq_event_list_lock);
>> +
>> +	return edev;
>> +}
>> +EXPORT_SYMBOL_GPL(devfreq_event_add_edev);
>> +
>> +/**
>> + * devfreq_event_remove_edev() - Remove the devfreq-event device registered.
>> + * @dev		: the devfreq-event device
>> + *
>> + * Note that this function remove the registered devfreq-event device.
>> + */
>> +int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
>> +{
>> +	if (!edev)
>> +		return -EINVAL;
>> +
>> +	mutex_lock(&devfreq_event_list_lock);
>> +	WARN_ON(edev->enable_count);
> 
> Let's WARN before mutex_lock();

OK.

> 
>> +	list_del(&edev->node);
>> +	device_unregister(&edev->dev);
> 
> Let's unregister after mutex_unlock();
> 
> The two lines do not need to be protected by the mutex.

OK.

> 
>> +	mutex_unlock(&devfreq_event_list_lock);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(devfreq_event_remove_edev);
>> +
> 
> []
> 
>> diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig
>> new file mode 100644
>> index 0000000..1ced42c
>> --- /dev/null
>> +++ b/drivers/devfreq/event/Kconfig
>> @@ -0,0 +1,16 @@
>> +menuconfig PM_DEVFREQ_EVENT
>> +	bool "DEVFREQ-Event device Support"
>> +	help
>> +	  The devfreq-event device provide the raw data and events which
>> +	  indicate the current state of devfreq-event device. The provided
>> +	  data from devfreq-event device is used to monitor the state of
>> +	  device and determine the suitable size of resource to reduce the
>> +	  wasted resource.
>> +
>> +	  The devfreq-event device can support the various type of events
>> +	  (e.g., raw data, utilization, latency, bandwidth). The events
>> +	  may be used by devfreq governor and other subsystem.
>> +
>> +if PM_DEVFREQ_EVENT
>> +
>> +endif # PM_DEVFREQ_EVENT
>> diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile
>> new file mode 100644
>> index 0000000..dc56005
>> --- /dev/null
>> +++ b/drivers/devfreq/event/Makefile
>> @@ -0,0 +1 @@
>> +# Exynos DEVFREQ Event Drivers
>> diff --git a/include/linux/devfreq-event.h b/include/linux/devfreq-event.h
>> new file mode 100644
>> index 0000000..b7363f5
>> --- /dev/null
>> +++ b/include/linux/devfreq-event.h
>> @@ -0,0 +1,170 @@
>> +/*
>> + * devfreq-event: a framework to provide raw data and events of devfreq devices
>> + *
>> + * Copyright (C) 2014 Samsung Electronics
>> + * Author: Chanwoo Choi <cw00.choi@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifndef __LINUX_DEVFREQ_EVENT_H__
>> +#define __LINUX_DEVFREQ_EVENT_H__
>> +
>> +#include <linux/device.h>
>> +
>> +/**
>> + * struct devfreq_event_dev - the devfreq-event device
>> + *
>> + * @node	: Contain the devfreq-event device that have been registered.
>> + * @dev		: the device registered by devfreq-event class. dev.parent is
>> + *		  the device using devfreq-event.
>> + * @lock	: a mutex to protect accessing devfreq-event.
>> + * @enable_count: the number of enable function have been called.
>> + * @desc	: the description for devfreq-event device.
>> + *
>> + * This structure contains devfreq-event device information.
>> + */
>> +struct devfreq_event_dev {
>> +	struct list_head node;
>> +
>> +	struct device dev;
>> +	struct mutex lock;
>> +	u32 enable_count;
>> +
>> +	const struct devfreq_event_desc *desc;
>> +};
>> +
>> +/**
>> + * struct devfreq_event_data - the devfreq-event data
>> + *
>> + * @event	: the load of devfreq-event device for polling period
>> + * @total_event	: the total load of devfreq-event device for polling period
>> + *
>> + * This structure contains the data of devfreq-event device for polling period.
>> + */
>> +struct devfreq_event_data {
>> +	unsigned long event;
>> +	unsigned long total_event;
>> +};
> 
> I would like to rephrase and rename as follows:
> 
> + * @load_count		: load count of devfreq-event device for the given period.
> + * @total_count	: total count of devfreq-event device for the given period.
> + *			each count may represent a clock cycle,
> + *			a time unit (ns/us/...), or anything the device driver wants.
> + *			Generally, utilization is load_count / total_count.

OK, I'll change it.

Thanks for your review.

Best Regards,
Chanwoo Choi


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

* Re: [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor
@ 2015-01-20  4:34 MyungJoo Ham
  2015-01-20  5:29 ` Chanwoo Choi
  0 siblings, 1 reply; 16+ messages in thread
From: MyungJoo Ham @ 2015-01-20  4:34 UTC (permalink / raw)
  To: 최찬우, kgene
  Cc: 박경민,
	rafael.j.wysocki, mark.rutland, ABHILASH KESAVAN, tomasz.figa,
	Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz, robh+dt,
	대인기,
	linux-pm, linux-kernel, linux-arm-kernel, linux-samsung-soc

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=utf-8, Size: 13286 bytes --]

>   
>  This patch add new devfreq_event class for devfreq_event device which provide
> raw data (e.g., memory bus utilization/GPU utilization). This raw data from
> devfreq_event data would be used for the governor of devfreq subsystem.
> - devfreq_event device : Provide raw data for governor of existing devfreq device
> - devfreq device       : Monitor device state and change frequency/voltage of device
>                          using the raw data from devfreq_event device
> 
> The devfreq subsystem support generic DVFS(Dynamic Voltage/Frequency Scaling)
> for Non-CPU Devices. The devfreq device would dertermine current device state
> using various governor (e.g., ondemand, performance, powersave). After completed
> determination of system state, devfreq device would change the frequency/voltage
> of devfreq device according to the result of governor.
> 
> But, devfreq governor must need basic data which indicates current device state.
> Existing devfreq subsystem only consider devfreq device which check current system
> state and determine proper system state using basic data. There is no subsystem
> for device providing basic data to devfreq device.
> 
> The devfreq subsystem must need devfreq_event device(data-provider device) for
> existing devfreq device. So, this patch add new devfreq_event class for
> devfreq_event device which read various basic data(e.g, memory bus utilization,
> GPU utilization) and provide measured data to existing devfreq device through
> standard APIs of devfreq_event class.
> 
> The following description explains the feature of two kind of devfreq class:
> - devfreq class (existing)
>  : devfreq consumer device use raw data from devfreq_event device for
>    determining proper current system state and change voltage/frequency
>    dynamically using various governors.
> 
> - devfreq_event class (new)
>  : Provide measured raw data to devfreq device for governor
> 
> Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
> Cc: Kyungmin Park <kyungmin.park@samsung.com>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---

[]

> +/**
> + * devfreq_event_enable_edev() - Enable the devfreq-event dev and increase
> + *				 the enable_count of devfreq-event dev.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function increase the enable_count and enable the
> + * devfreq-event device. The devfreq-event device should be enabled before
> + * using it by devfreq device.
> + */
> +int devfreq_event_enable_edev(struct devfreq_event_dev *edev)
> +{
> +	int ret = 0;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	mutex_lock(&edev->lock);
> +	if (edev->desc->ops && edev->desc->ops->enable) {
> +		ret = edev->desc->ops->enable(edev);
> +		if (ret < 0)
> +			goto err;
> +	}

Is there any reason to call enable(edev) even when enable_count is already > 0 
while you do not call disable(edev) while enable_count > 0?

I think this may incur errors in the related device drivers.
(e.g., incorrect pairing of clk/runtime-pm/regulator enable/disable
at the device driver side)

> +	edev->enable_count++;
> +err:
> +	mutex_unlock(&edev->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_enable_edev);
> +
> +/**
> + * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease
> + *				  the enable_count of the devfreq-event dev.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function decrease the enable_count and disable the
> + * devfreq-event device. After the devfreq-event device is disabled,
> + * devfreq device can't use the devfreq-event device for get/set/reset
> + * operations.
> + */
> +int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
> +{
> +	int ret = 0;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	mutex_lock(&edev->lock);
> +	if (edev->enable_count > 0) {
> +		edev->enable_count--;
> +	} else {
> +		dev_warn(&edev->dev, "unbalanced enable_count\n");
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +
> +	if (edev->desc->ops && edev->desc->ops->disable) {
> +		ret = edev->desc->ops->disable(edev);
> +		if (ret < 0) {
> +			edev->enable_count++;
> +			goto err;
> +		}
> +	}

You did it correctly with disable here;
not calling it when it is not required.

> +err:
> +	mutex_unlock(&edev->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_disable_edev);
> +

[]
> +EXPORT_SYMBOL_GPL(devfreq_event_is_enabled);
[]

> +EXPORT_SYMBOL_GPL(devfreq_event_set_event);
[]

> +
> +/**
> + * devfreq_event_get_event() - Get event and total_event from devfreq-event dev.
> + * @edev	: the devfreq-event device
> + * @edata	: the calculated data of devfreq-event device
> + *
> + * Note that this function get the calculated event data from devfreq-event dev
> + * after stoping the progress of whole sequence of devfreq-event dev.
> + */
> +int devfreq_event_get_event(struct devfreq_event_dev *edev,
> +			    struct devfreq_event_data *edata)
> +{
> +	int ret;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	if (!edev->desc->ops || !edev->desc->ops->get_event)
> +		return -EINVAL;
> +
> +	if (!devfreq_event_is_enabled(edev))
> +		return -EINVAL;
> +
> +	edata->event = edata->total_event = 0;
> +
> +	mutex_lock(&edev->lock);
> +	ret = edev->desc->ops->get_event(edev, edata);
> +	mutex_unlock(&edev->lock);
> +
> +	if ((edata->total_event <= 0)
> +		|| (edata->event > edata->total_event)) {
> +		edata->event = edata->total_event = 0;
> +		ret = -EINVAL;

total_event is unsigned. (cannot be < 0)

Plus, get_event() may already have returned a negative value with
the intention of giving a error different from EINVAL.

I would just simply set total_event = event = 0 if ret < 0.


> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_get_event);
> +
> +/**
> + * devfreq_event_reset_event() - Reset all opeations of devfreq-event dev.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function stop all operations of devfreq-event dev and reset
> + * the current event data to make the devfreq-event device into initial state.
> + */
> +int devfreq_event_reset_event(struct devfreq_event_dev *edev)
> +{
> +	int ret = 0;
> +
> +	if (!edev || !edev->desc)
> +		return -EINVAL;
> +
> +	if (!devfreq_event_is_enabled(edev))
> +		return -EPERM;
> +
> +	mutex_lock(&edev->lock);
> +	if (edev->desc->ops && edev->desc->ops->reset)
> +		ret = edev->desc->ops->reset(edev);
> +	mutex_unlock(&edev->lock);

In the context of the get_event() handling "load",
aren't you supposed to set total_event = event = 0; here?

> +
> +	if (ret < 0)
> +		return -EINVAL;
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_reset_event);
> +
> +/**
> + * devfreq_event_get_drvdata() - Return driver-data of devfreq-event dev.
> + * @edev	: the devfreq-event device
> + *
> + * Note that this function return the driver-data of devfreq-event device.
> + */
> +void *devfreq_event_get_drvdata(struct devfreq_event_dev *edev)
> +{
> +	return edev->desc->driver_data;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_get_drvdata);

Looks like you can simply write this in the header file.
(either #define or static inline function)

[]

> +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle);
[]
> +EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count);
[]

> +/**
> + * devfreq_event_add_edev() - Add new devfreq-event device.
> + * @dev		: the device owning the devfreq-event device being created
> + * @desc	: the devfreq-event device's decriptor which include essential
> + *		  data for devfreq-event device.
> + *
> + * Note that this function add new devfreq-event device to devfreq-event class
> + * list and register the device of the devfreq-event device.
> + */
> +struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
> +						struct devfreq_event_desc *desc)
> +{
> +	struct devfreq_event_dev *edev;
> +	static atomic_t event_no = ATOMIC_INIT(0);
> +	int ret;
> +
> +	if (!dev || !desc)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!desc->name || !desc->ops)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!desc->ops->set_event || !desc->ops->get_event)
> +		return ERR_PTR(-EINVAL);
> +
> +	edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL);

devm_* here? (seeing no free)

> +	if (!edev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mutex_init(&edev->lock);
> +	edev->desc = desc;
> +	edev->dev.parent = dev;
> +	edev->dev.class = devfreq_event_class;
> +	edev->dev.release = devfreq_event_release_edev;
> +
> +	dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1);
> +	ret = device_register(&edev->dev);
> +	if (ret < 0) {
> +		put_device(&edev->dev);
> +		return ERR_PTR(ret);
> +	}
> +	dev_set_drvdata(&edev->dev, edev);
> +
> +	INIT_LIST_HEAD(&edev->node);
> +
> +	mutex_lock(&devfreq_event_list_lock);
> +	list_add(&edev->node, &devfreq_event_list);
> +	mutex_unlock(&devfreq_event_list_lock);
> +
> +	return edev;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_add_edev);
> +
> +/**
> + * devfreq_event_remove_edev() - Remove the devfreq-event device registered.
> + * @dev		: the devfreq-event device
> + *
> + * Note that this function remove the registered devfreq-event device.
> + */
> +int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
> +{
> +	if (!edev)
> +		return -EINVAL;
> +
> +	mutex_lock(&devfreq_event_list_lock);
> +	WARN_ON(edev->enable_count);

Let's WARN before mutex_lock();

> +	list_del(&edev->node);
> +	device_unregister(&edev->dev);

Let's unregister after mutex_unlock();

The two lines do not need to be protected by the mutex.

> +	mutex_unlock(&devfreq_event_list_lock);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(devfreq_event_remove_edev);
> +

[]

> diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig
> new file mode 100644
> index 0000000..1ced42c
> --- /dev/null
> +++ b/drivers/devfreq/event/Kconfig
> @@ -0,0 +1,16 @@
> +menuconfig PM_DEVFREQ_EVENT
> +	bool "DEVFREQ-Event device Support"
> +	help
> +	  The devfreq-event device provide the raw data and events which
> +	  indicate the current state of devfreq-event device. The provided
> +	  data from devfreq-event device is used to monitor the state of
> +	  device and determine the suitable size of resource to reduce the
> +	  wasted resource.
> +
> +	  The devfreq-event device can support the various type of events
> +	  (e.g., raw data, utilization, latency, bandwidth). The events
> +	  may be used by devfreq governor and other subsystem.
> +
> +if PM_DEVFREQ_EVENT
> +
> +endif # PM_DEVFREQ_EVENT
> diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile
> new file mode 100644
> index 0000000..dc56005
> --- /dev/null
> +++ b/drivers/devfreq/event/Makefile
> @@ -0,0 +1 @@
> +# Exynos DEVFREQ Event Drivers
> diff --git a/include/linux/devfreq-event.h b/include/linux/devfreq-event.h
> new file mode 100644
> index 0000000..b7363f5
> --- /dev/null
> +++ b/include/linux/devfreq-event.h
> @@ -0,0 +1,170 @@
> +/*
> + * devfreq-event: a framework to provide raw data and events of devfreq devices
> + *
> + * Copyright (C) 2014 Samsung Electronics
> + * Author: Chanwoo Choi <cw00.choi@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __LINUX_DEVFREQ_EVENT_H__
> +#define __LINUX_DEVFREQ_EVENT_H__
> +
> +#include <linux/device.h>
> +
> +/**
> + * struct devfreq_event_dev - the devfreq-event device
> + *
> + * @node	: Contain the devfreq-event device that have been registered.
> + * @dev		: the device registered by devfreq-event class. dev.parent is
> + *		  the device using devfreq-event.
> + * @lock	: a mutex to protect accessing devfreq-event.
> + * @enable_count: the number of enable function have been called.
> + * @desc	: the description for devfreq-event device.
> + *
> + * This structure contains devfreq-event device information.
> + */
> +struct devfreq_event_dev {
> +	struct list_head node;
> +
> +	struct device dev;
> +	struct mutex lock;
> +	u32 enable_count;
> +
> +	const struct devfreq_event_desc *desc;
> +};
> +
> +/**
> + * struct devfreq_event_data - the devfreq-event data
> + *
> + * @event	: the load of devfreq-event device for polling period
> + * @total_event	: the total load of devfreq-event device for polling period
> + *
> + * This structure contains the data of devfreq-event device for polling period.
> + */
> +struct devfreq_event_data {
> +	unsigned long event;
> +	unsigned long total_event;
> +};

I would like to rephrase and rename as follows:

+ * @load_count		: load count of devfreq-event device for the given period.
+ * @total_count	: total count of devfreq-event device for the given period.
+ *			each count may represent a clock cycle,
+ *			a time unit (ns/us/...), or anything the device driver wants.
+ *			Generally, utilization is load_count / total_count.

[]


You may already contact me with synchronous methods for more
prompt discussion. :) Your office is not that far from mine.
(Or during lunch, dinner, or beer sessions as well)


Cheers,
MyungJoo

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

end of thread, other threads:[~2015-01-20  7:25 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-12 12:34 [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor Chanwoo Choi
2015-01-19 10:12   ` Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 2/9] devfreq: event: Add resource-managed function for devfreq-event device Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 3/9] devfreq: event: Add exynos-ppmu devfreq-event driver Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 4/9] devfreq: event: Add documentation for " Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 5/9] ARM: dts: Add PPMU dt node for Exynos3250 SoC Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 6/9] ARM: dts: Add PPMU dt node for Exynos4 SoCs Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 7/9] ARM: dts: Add PPMU dt node for Exynos5260 SoC Chanwoo Choi
2015-01-19 10:01   ` Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 8/9] ARM: dts: exynos: Add PPMU node to Exynos3250-based Rinato/Monk board Chanwoo Choi
2015-01-12 12:34 ` [PATCHv8 9/9] ARM: dts: exynos: Add PPMU node for Exynos4412-based TRATS2 board Chanwoo Choi
2015-01-19  0:50 ` [PATCHv8 0/9] devfreq: Add devfreq-event class to provide raw data for devfreq device Chanwoo Choi
2015-01-20  4:34 [PATCHv8 1/9] devfreq: event: Add new devfreq_event class to provide basic data for devfreq governor MyungJoo Ham
2015-01-20  5:29 ` Chanwoo Choi
2015-01-20  6:59 MyungJoo Ham
2015-01-20  7:25 ` Chanwoo Choi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).