All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-11 15:41 ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 15:41 UTC (permalink / raw)
  To: Philipp Zabel, Josh Triplett, Rashika Kheria, Stephen Warren,
	Maxime Ripard, Greg Kroah-Hartman
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai, Hans de Goede

Add reset_control_deassert_shared / reset_control_assert_shared
functions which are intended for use by drivers for hw blocks which
(may) share a reset line with another driver / hw block.

Unlike the regular reset_control_[de]assert functions these functions
keep track of how often deassert_shared / assert_shared have been called
and keep the line deasserted as long as deassert has been called more
times than assert.

Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
Changes in v2:
-This is a new patch in v2 of this patch-set
---
 drivers/reset/core.c             | 121 ++++++++++++++++++++++++++++++++++++---
 include/linux/reset-controller.h |   2 +
 include/linux/reset.h            |   2 +
 3 files changed, 116 insertions(+), 9 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 9ab9290..8c3436c 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_list_mutex);
 static LIST_HEAD(reset_controller_list);
 
 /**
+ * struct reset_line - a reset line
+ * @list:         list entry for the reset controllers reset line list
+ * @id:           ID of the reset line in the reset controller device
+ * @refcnt:       Number of reset_control structs referencing this device
+ * @deassert_cnt: Number of times this reset line has been deasserted
+ */
+struct reset_line {
+	struct list_head list;
+	unsigned int id;
+	unsigned int refcnt;
+	unsigned int deassert_cnt;
+};
+
+/**
  * struct reset_control - a reset control
  * @rcdev: a pointer to the reset controller device
  *         this reset control belongs to
- * @id: ID of the reset controller in the reset
- *      controller device
+ * @line:  reset line for this reset control
  */
 struct reset_control {
 	struct reset_controller_dev *rcdev;
+	struct reset_line *line;
 	struct device *dev;
-	unsigned int id;
 };
 
 /**
@@ -66,6 +79,8 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
 		rcdev->of_xlate = of_reset_simple_xlate;
 	}
 
+	INIT_LIST_HEAD(&rcdev->reset_line_head);
+
 	mutex_lock(&reset_controller_list_mutex);
 	list_add(&rcdev->list, &reset_controller_list);
 	mutex_unlock(&reset_controller_list_mutex);
@@ -93,7 +108,7 @@ EXPORT_SYMBOL_GPL(reset_controller_unregister);
 int reset_control_reset(struct reset_control *rstc)
 {
 	if (rstc->rcdev->ops->reset)
-		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
+		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->line->id);
 
 	return -ENOTSUPP;
 }
@@ -106,7 +121,7 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
 int reset_control_assert(struct reset_control *rstc)
 {
 	if (rstc->rcdev->ops->assert)
-		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
+		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
 
 	return -ENOTSUPP;
 }
@@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
 int reset_control_deassert(struct reset_control *rstc)
 {
 	if (rstc->rcdev->ops->deassert)
-		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
+		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
 
 	return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(reset_control_deassert);
 
 /**
+ * reset_control_assert_shared - asserts a shared reset line
+ * @rstc: reset controller
+ *
+ * Assert a shared reset line, this functions decreases the deassert count
+ * of the line by one and asserts it if, and only if, the deassert count
+ * reaches 0.
+ */
+int reset_control_assert_shared(struct reset_control *rstc)
+{
+	if (!rstc->rcdev->ops->assert)
+		return -ENOTSUPP;
+
+	rstc->line->deassert_cnt--;
+	if (rstc->line->deassert_cnt)
+		return 0;
+
+	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
+}
+EXPORT_SYMBOL_GPL(reset_control_assert_shared);
+
+/**
+ * reset_control_deassert_shared - deasserts a shared reset line
+ * @rstc: reset controller
+ *
+ * Assert a shared reset line, this functions increases the deassert count
+ * of the line by one and deasserts the reset line (if it was not already
+ * deasserted).
+ */
+int reset_control_deassert_shared(struct reset_control *rstc)
+{
+	if (!rstc->rcdev->ops->deassert)
+		return -ENOTSUPP;
+
+	rstc->line->deassert_cnt++;
+	if (rstc->line->deassert_cnt != 1)
+		return 0;
+
+	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
+}
+EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
+
+/**
  * reset_control_status - returns a negative errno if not supported, a
  * positive value if the reset line is asserted, or zero if the reset
  * line is not asserted.
@@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
 int reset_control_status(struct reset_control *rstc)
 {
 	if (rstc->rcdev->ops->status)
-		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
+		return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
 
 	return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(reset_control_status);
 
+static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
+					 unsigned int index)
+{
+	struct reset_line *line;
+
+	list_for_each_entry(line, &rcdev->reset_line_head, list) {
+		if (line->id == index) {
+			line->refcnt++;
+			return line;
+		}
+	}
+
+	line = kzalloc(sizeof(*line), GFP_KERNEL);
+	if (!line)
+		return NULL;
+
+	list_add(&line->list, &rcdev->reset_line_head);
+	line->id = index;
+	line->refcnt = 1;
+
+	return line;
+}
+
+static void reset_line_put(struct reset_line *line)
+{
+	if (!line)
+		return;
+
+	if (--line->refcnt)
+		return;
+
+	list_del(&line->list);
+	kfree(line);
+}
+
 /**
  * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
  * controller by index.
@@ -155,6 +247,7 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
 {
 	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
 	struct reset_controller_dev *r, *rcdev;
+	struct reset_line *line;
 	struct of_phandle_args args;
 	int rstc_id;
 	int ret;
@@ -186,16 +279,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
 	}
 
 	try_module_get(rcdev->owner);
+
+	/* reset_controller_list_mutex also protects the reset_line list */
+	line = reset_line_get(rcdev, rstc_id);
+
 	mutex_unlock(&reset_controller_list_mutex);
 
 	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
-	if (!rstc) {
+	if (!line || !rstc) {
+		kfree(rstc);
+		reset_line_put(line);
 		module_put(rcdev->owner);
 		return ERR_PTR(-ENOMEM);
 	}
 
 	rstc->rcdev = rcdev;
-	rstc->id = rstc_id;
+	rstc->line = line;
 
 	return rstc;
 }
@@ -259,6 +358,10 @@ void reset_control_put(struct reset_control *rstc)
 	if (IS_ERR(rstc))
 		return;
 
+	mutex_lock(&reset_controller_list_mutex);
+	reset_line_put(rstc->line);
+	mutex_unlock(&reset_controller_list_mutex);
+
 	module_put(rstc->rcdev->owner);
 	kfree(rstc);
 }
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index ce6b962..7f2cbd1 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -31,6 +31,7 @@ struct of_phandle_args;
  * @ops: a pointer to device specific struct reset_control_ops
  * @owner: kernel module of the reset controller driver
  * @list: internal list of reset controller devices
+ * @reset_line_head: head of internal list of reset lines
  * @of_node: corresponding device tree node as phandle target
  * @of_reset_n_cells: number of cells in reset line specifiers
  * @of_xlate: translation function to translate from specifier as found in the
@@ -41,6 +42,7 @@ struct reset_controller_dev {
 	struct reset_control_ops *ops;
 	struct module *owner;
 	struct list_head list;
+	struct list_head reset_line_head;
 	struct device_node *of_node;
 	int of_reset_n_cells;
 	int (*of_xlate)(struct reset_controller_dev *rcdev,
diff --git a/include/linux/reset.h b/include/linux/reset.h
index c4c097d..1cca8ce 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
 int reset_control_assert(struct reset_control *rstc);
 int reset_control_deassert(struct reset_control *rstc);
 int reset_control_status(struct reset_control *rstc);
+int reset_control_assert_shared(struct reset_control *rstc);
+int reset_control_deassert_shared(struct reset_control *rstc);
 
 struct reset_control *reset_control_get(struct device *dev, const char *id);
 void reset_control_put(struct reset_control *rstc);
-- 
2.5.0

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-11 15:41 ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

Add reset_control_deassert_shared / reset_control_assert_shared
functions which are intended for use by drivers for hw blocks which
(may) share a reset line with another driver / hw block.

Unlike the regular reset_control_[de]assert functions these functions
keep track of how often deassert_shared / assert_shared have been called
and keep the line deasserted as long as deassert has been called more
times than assert.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-This is a new patch in v2 of this patch-set
---
 drivers/reset/core.c             | 121 ++++++++++++++++++++++++++++++++++++---
 include/linux/reset-controller.h |   2 +
 include/linux/reset.h            |   2 +
 3 files changed, 116 insertions(+), 9 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 9ab9290..8c3436c 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_list_mutex);
 static LIST_HEAD(reset_controller_list);
 
 /**
+ * struct reset_line - a reset line
+ * @list:         list entry for the reset controllers reset line list
+ * @id:           ID of the reset line in the reset controller device
+ * @refcnt:       Number of reset_control structs referencing this device
+ * @deassert_cnt: Number of times this reset line has been deasserted
+ */
+struct reset_line {
+	struct list_head list;
+	unsigned int id;
+	unsigned int refcnt;
+	unsigned int deassert_cnt;
+};
+
+/**
  * struct reset_control - a reset control
  * @rcdev: a pointer to the reset controller device
  *         this reset control belongs to
- * @id: ID of the reset controller in the reset
- *      controller device
+ * @line:  reset line for this reset control
  */
 struct reset_control {
 	struct reset_controller_dev *rcdev;
+	struct reset_line *line;
 	struct device *dev;
-	unsigned int id;
 };
 
 /**
@@ -66,6 +79,8 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
 		rcdev->of_xlate = of_reset_simple_xlate;
 	}
 
+	INIT_LIST_HEAD(&rcdev->reset_line_head);
+
 	mutex_lock(&reset_controller_list_mutex);
 	list_add(&rcdev->list, &reset_controller_list);
 	mutex_unlock(&reset_controller_list_mutex);
@@ -93,7 +108,7 @@ EXPORT_SYMBOL_GPL(reset_controller_unregister);
 int reset_control_reset(struct reset_control *rstc)
 {
 	if (rstc->rcdev->ops->reset)
-		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
+		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->line->id);
 
 	return -ENOTSUPP;
 }
@@ -106,7 +121,7 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
 int reset_control_assert(struct reset_control *rstc)
 {
 	if (rstc->rcdev->ops->assert)
-		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
+		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
 
 	return -ENOTSUPP;
 }
@@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
 int reset_control_deassert(struct reset_control *rstc)
 {
 	if (rstc->rcdev->ops->deassert)
-		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
+		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
 
 	return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(reset_control_deassert);
 
 /**
+ * reset_control_assert_shared - asserts a shared reset line
+ * @rstc: reset controller
+ *
+ * Assert a shared reset line, this functions decreases the deassert count
+ * of the line by one and asserts it if, and only if, the deassert count
+ * reaches 0.
+ */
+int reset_control_assert_shared(struct reset_control *rstc)
+{
+	if (!rstc->rcdev->ops->assert)
+		return -ENOTSUPP;
+
+	rstc->line->deassert_cnt--;
+	if (rstc->line->deassert_cnt)
+		return 0;
+
+	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
+}
+EXPORT_SYMBOL_GPL(reset_control_assert_shared);
+
+/**
+ * reset_control_deassert_shared - deasserts a shared reset line
+ * @rstc: reset controller
+ *
+ * Assert a shared reset line, this functions increases the deassert count
+ * of the line by one and deasserts the reset line (if it was not already
+ * deasserted).
+ */
+int reset_control_deassert_shared(struct reset_control *rstc)
+{
+	if (!rstc->rcdev->ops->deassert)
+		return -ENOTSUPP;
+
+	rstc->line->deassert_cnt++;
+	if (rstc->line->deassert_cnt != 1)
+		return 0;
+
+	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
+}
+EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
+
+/**
  * reset_control_status - returns a negative errno if not supported, a
  * positive value if the reset line is asserted, or zero if the reset
  * line is not asserted.
@@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
 int reset_control_status(struct reset_control *rstc)
 {
 	if (rstc->rcdev->ops->status)
-		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
+		return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
 
 	return -ENOTSUPP;
 }
 EXPORT_SYMBOL_GPL(reset_control_status);
 
+static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
+					 unsigned int index)
+{
+	struct reset_line *line;
+
+	list_for_each_entry(line, &rcdev->reset_line_head, list) {
+		if (line->id == index) {
+			line->refcnt++;
+			return line;
+		}
+	}
+
+	line = kzalloc(sizeof(*line), GFP_KERNEL);
+	if (!line)
+		return NULL;
+
+	list_add(&line->list, &rcdev->reset_line_head);
+	line->id = index;
+	line->refcnt = 1;
+
+	return line;
+}
+
+static void reset_line_put(struct reset_line *line)
+{
+	if (!line)
+		return;
+
+	if (--line->refcnt)
+		return;
+
+	list_del(&line->list);
+	kfree(line);
+}
+
 /**
  * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
  * controller by index.
@@ -155,6 +247,7 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
 {
 	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
 	struct reset_controller_dev *r, *rcdev;
+	struct reset_line *line;
 	struct of_phandle_args args;
 	int rstc_id;
 	int ret;
@@ -186,16 +279,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
 	}
 
 	try_module_get(rcdev->owner);
+
+	/* reset_controller_list_mutex also protects the reset_line list */
+	line = reset_line_get(rcdev, rstc_id);
+
 	mutex_unlock(&reset_controller_list_mutex);
 
 	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
-	if (!rstc) {
+	if (!line || !rstc) {
+		kfree(rstc);
+		reset_line_put(line);
 		module_put(rcdev->owner);
 		return ERR_PTR(-ENOMEM);
 	}
 
 	rstc->rcdev = rcdev;
-	rstc->id = rstc_id;
+	rstc->line = line;
 
 	return rstc;
 }
@@ -259,6 +358,10 @@ void reset_control_put(struct reset_control *rstc)
 	if (IS_ERR(rstc))
 		return;
 
+	mutex_lock(&reset_controller_list_mutex);
+	reset_line_put(rstc->line);
+	mutex_unlock(&reset_controller_list_mutex);
+
 	module_put(rstc->rcdev->owner);
 	kfree(rstc);
 }
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index ce6b962..7f2cbd1 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -31,6 +31,7 @@ struct of_phandle_args;
  * @ops: a pointer to device specific struct reset_control_ops
  * @owner: kernel module of the reset controller driver
  * @list: internal list of reset controller devices
+ * @reset_line_head: head of internal list of reset lines
  * @of_node: corresponding device tree node as phandle target
  * @of_reset_n_cells: number of cells in reset line specifiers
  * @of_xlate: translation function to translate from specifier as found in the
@@ -41,6 +42,7 @@ struct reset_controller_dev {
 	struct reset_control_ops *ops;
 	struct module *owner;
 	struct list_head list;
+	struct list_head reset_line_head;
 	struct device_node *of_node;
 	int of_reset_n_cells;
 	int (*of_xlate)(struct reset_controller_dev *rcdev,
diff --git a/include/linux/reset.h b/include/linux/reset.h
index c4c097d..1cca8ce 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
 int reset_control_assert(struct reset_control *rstc);
 int reset_control_deassert(struct reset_control *rstc);
 int reset_control_status(struct reset_control *rstc);
+int reset_control_assert_shared(struct reset_control *rstc);
+int reset_control_deassert_shared(struct reset_control *rstc);
 
 struct reset_control *reset_control_get(struct device *dev, const char *id);
 void reset_control_put(struct reset_control *rstc);
-- 
2.5.0

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

* [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
  2015-12-11 15:41 ` Hans de Goede
@ 2015-12-11 15:41     ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 15:41 UTC (permalink / raw)
  To: Philipp Zabel, Josh Triplett, Rashika Kheria, Stephen Warren,
	Maxime Ripard, Greg Kroah-Hartman
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai, Reinder de Haan, Hans de Goede

From: Reinder de Haan <patchesrdh-I1/eAgTnXDYAvxtiuMwx3w@public.gmane.org>

At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
reset lines, the controller will not initialize while the reset for
its companion is still asserted, which means we need to de-assert
2 resets for the controller to work.

Signed-off-by: Reinder de Haan <patchesrdh-I1/eAgTnXDYAvxtiuMwx3w@public.gmane.org>
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
Changes in v2:
-Use the new reset_control_[de]assert_shared reset-controller functions
---
 Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
 drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
 2 files changed, 30 insertions(+), 19 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index a12d601..0701812 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -18,7 +18,7 @@ Optional properties:
  - clocks : a list of phandle + clock specifier pairs
  - phys : phandle + phy specifier pair
  - phy-names : "usb"
- - resets : phandle + reset specifier pair
+ - resets : a list of phandle + reset specifier pairs
 
 Example (Sequoia 440EPx):
     ehci@e0000300 {
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index bd7082f2..6fbf32a 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -39,11 +39,12 @@
 
 #define DRIVER_DESC "EHCI generic platform driver"
 #define EHCI_MAX_CLKS 3
+#define EHCI_MAX_RESETS 2
 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
 
 struct ehci_platform_priv {
 	struct clk *clks[EHCI_MAX_CLKS];
-	struct reset_control *rst;
+	struct reset_control *resets[EHCI_MAX_RESETS];
 	struct phy **phys;
 	int num_phys;
 	bool reset_on_resume;
@@ -149,7 +150,7 @@ static int ehci_platform_probe(struct platform_device *dev)
 	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ehci_platform_priv *priv;
 	struct ehci_hcd *ehci;
-	int err, irq, phy_num, clk = 0;
+	int err, irq, phy_num, clk = 0, rst = 0;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -232,18 +233,24 @@ static int ehci_platform_probe(struct platform_device *dev)
 				break;
 			}
 		}
-	}
 
-	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
-	if (IS_ERR(priv->rst)) {
-		err = PTR_ERR(priv->rst);
-		if (err == -EPROBE_DEFER)
-			goto err_put_clks;
-		priv->rst = NULL;
-	} else {
-		err = reset_control_deassert(priv->rst);
-		if (err)
-			goto err_put_clks;
+		for (rst = 0; rst < EHCI_MAX_RESETS; rst++) {
+			priv->resets[rst] =
+				of_reset_control_get_by_index(dev->dev.of_node,
+							      rst);
+			if (IS_ERR(priv->resets[rst])) {
+				err = PTR_ERR(priv->resets[rst]);
+				if (err == -EPROBE_DEFER)
+					goto err_reset;
+				priv->resets[rst] = NULL;
+				break;
+			}
+			err = reset_control_deassert_shared(priv->resets[rst]);
+			if (err) {
+				reset_control_put(priv->resets[rst]);
+				goto err_reset;
+			}
+		}
 	}
 
 	if (pdata->big_endian_desc)
@@ -300,8 +307,10 @@ err_power:
 	if (pdata->power_off)
 		pdata->power_off(dev);
 err_reset:
-	if (priv->rst)
-		reset_control_assert(priv->rst);
+	while (--rst >= 0) {
+		reset_control_assert_shared(priv->resets[rst]);
+		reset_control_put(priv->resets[rst]);
+	}
 err_put_clks:
 	while (--clk >= 0)
 		clk_put(priv->clks[clk]);
@@ -319,15 +328,17 @@ static int ehci_platform_remove(struct platform_device *dev)
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
-	int clk;
+	int clk, rst;
 
 	usb_remove_hcd(hcd);
 
 	if (pdata->power_off)
 		pdata->power_off(dev);
 
-	if (priv->rst)
-		reset_control_assert(priv->rst);
+	for (rst = 0; rst < EHCI_MAX_RESETS && priv->resets[rst]; rst++) {
+		reset_control_assert_shared(priv->resets[rst]);
+		reset_control_put(priv->resets[rst]);
+	}
 
 	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
 		clk_put(priv->clks[clk]);
-- 
2.5.0

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

* [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
@ 2015-12-11 15:41     ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

From: Reinder de Haan <patchesrdh@mveas.com>

At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
reset lines, the controller will not initialize while the reset for
its companion is still asserted, which means we need to de-assert
2 resets for the controller to work.

Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Use the new reset_control_[de]assert_shared reset-controller functions
---
 Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
 drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
 2 files changed, 30 insertions(+), 19 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index a12d601..0701812 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -18,7 +18,7 @@ Optional properties:
  - clocks : a list of phandle + clock specifier pairs
  - phys : phandle + phy specifier pair
  - phy-names : "usb"
- - resets : phandle + reset specifier pair
+ - resets : a list of phandle + reset specifier pairs
 
 Example (Sequoia 440EPx):
     ehci at e0000300 {
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index bd7082f2..6fbf32a 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -39,11 +39,12 @@
 
 #define DRIVER_DESC "EHCI generic platform driver"
 #define EHCI_MAX_CLKS 3
+#define EHCI_MAX_RESETS 2
 #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
 
 struct ehci_platform_priv {
 	struct clk *clks[EHCI_MAX_CLKS];
-	struct reset_control *rst;
+	struct reset_control *resets[EHCI_MAX_RESETS];
 	struct phy **phys;
 	int num_phys;
 	bool reset_on_resume;
@@ -149,7 +150,7 @@ static int ehci_platform_probe(struct platform_device *dev)
 	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ehci_platform_priv *priv;
 	struct ehci_hcd *ehci;
-	int err, irq, phy_num, clk = 0;
+	int err, irq, phy_num, clk = 0, rst = 0;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -232,18 +233,24 @@ static int ehci_platform_probe(struct platform_device *dev)
 				break;
 			}
 		}
-	}
 
-	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
-	if (IS_ERR(priv->rst)) {
-		err = PTR_ERR(priv->rst);
-		if (err == -EPROBE_DEFER)
-			goto err_put_clks;
-		priv->rst = NULL;
-	} else {
-		err = reset_control_deassert(priv->rst);
-		if (err)
-			goto err_put_clks;
+		for (rst = 0; rst < EHCI_MAX_RESETS; rst++) {
+			priv->resets[rst] =
+				of_reset_control_get_by_index(dev->dev.of_node,
+							      rst);
+			if (IS_ERR(priv->resets[rst])) {
+				err = PTR_ERR(priv->resets[rst]);
+				if (err == -EPROBE_DEFER)
+					goto err_reset;
+				priv->resets[rst] = NULL;
+				break;
+			}
+			err = reset_control_deassert_shared(priv->resets[rst]);
+			if (err) {
+				reset_control_put(priv->resets[rst]);
+				goto err_reset;
+			}
+		}
 	}
 
 	if (pdata->big_endian_desc)
@@ -300,8 +307,10 @@ err_power:
 	if (pdata->power_off)
 		pdata->power_off(dev);
 err_reset:
-	if (priv->rst)
-		reset_control_assert(priv->rst);
+	while (--rst >= 0) {
+		reset_control_assert_shared(priv->resets[rst]);
+		reset_control_put(priv->resets[rst]);
+	}
 err_put_clks:
 	while (--clk >= 0)
 		clk_put(priv->clks[clk]);
@@ -319,15 +328,17 @@ static int ehci_platform_remove(struct platform_device *dev)
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
-	int clk;
+	int clk, rst;
 
 	usb_remove_hcd(hcd);
 
 	if (pdata->power_off)
 		pdata->power_off(dev);
 
-	if (priv->rst)
-		reset_control_assert(priv->rst);
+	for (rst = 0; rst < EHCI_MAX_RESETS && priv->resets[rst]; rst++) {
+		reset_control_assert_shared(priv->resets[rst]);
+		reset_control_put(priv->resets[rst]);
+	}
 
 	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
 		clk_put(priv->clks[clk]);
-- 
2.5.0

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

* [PATCH v2 3/3] ohci-platform: Add support for controllers with multiple reset lines
  2015-12-11 15:41 ` Hans de Goede
@ 2015-12-11 15:42     ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 15:42 UTC (permalink / raw)
  To: Philipp Zabel, Josh Triplett, Rashika Kheria, Stephen Warren,
	Maxime Ripard, Greg Kroah-Hartman
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai, Hans de Goede

At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
reset lines, the controller will not initialize while the reset for
its companion is still asserted, which means we need to de-assert
2 resets for the controller to work.

Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
Changes in v2:
-New patch in v2 of this patch-set, to complement the identical patch for
 the ehci-platform code
---
 Documentation/devicetree/bindings/usb/usb-ohci.txt |  2 +-
 drivers/usb/host/ohci-platform.c                   | 49 +++++++++++++---------
 2 files changed, 30 insertions(+), 21 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
index 19233b7..9df4569 100644
--- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
@@ -14,7 +14,7 @@ Optional properties:
 - clocks : a list of phandle + clock specifier pairs
 - phys : phandle + phy specifier pair
 - phy-names : "usb"
-- resets : phandle + reset specifier pair
+- resets : a list of phandle + reset specifier pairs
 
 Example:
 
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index c2669f18..7d8bbc4 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -33,11 +33,12 @@
 
 #define DRIVER_DESC "OHCI generic platform driver"
 #define OHCI_MAX_CLKS 3
+#define OHCI_MAX_RESETS 2
 #define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
 
 struct ohci_platform_priv {
 	struct clk *clks[OHCI_MAX_CLKS];
-	struct reset_control *rst;
+	struct reset_control *resets[OHCI_MAX_RESETS];
 	struct phy **phys;
 	int num_phys;
 };
@@ -117,7 +118,7 @@ static int ohci_platform_probe(struct platform_device *dev)
 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ohci_platform_priv *priv;
 	struct ohci_hcd *ohci;
-	int err, irq, phy_num, clk = 0;
+	int err, irq, phy_num, clk = 0, rst = 0;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -195,19 +196,23 @@ static int ohci_platform_probe(struct platform_device *dev)
 				break;
 			}
 		}
-
-	}
-
-	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
-	if (IS_ERR(priv->rst)) {
-		err = PTR_ERR(priv->rst);
-		if (err == -EPROBE_DEFER)
-			goto err_put_clks;
-		priv->rst = NULL;
-	} else {
-		err = reset_control_deassert(priv->rst);
-		if (err)
-			goto err_put_clks;
+		for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
+			priv->resets[rst] =
+				of_reset_control_get_by_index(dev->dev.of_node,
+							      rst);
+			if (IS_ERR(priv->resets[rst])) {
+				err = PTR_ERR(priv->resets[rst]);
+				if (err == -EPROBE_DEFER)
+					goto err_reset;
+				priv->resets[rst] = NULL;
+				break;
+			}
+			err = reset_control_deassert_shared(priv->resets[rst]);
+			if (err) {
+				reset_control_put(priv->resets[rst]);
+				goto err_reset;
+			}
+		}
 	}
 
 	if (pdata->big_endian_desc)
@@ -265,8 +270,10 @@ err_power:
 	if (pdata->power_off)
 		pdata->power_off(dev);
 err_reset:
-	if (priv->rst)
-		reset_control_assert(priv->rst);
+	while (--rst >= 0) {
+		reset_control_assert_shared(priv->resets[rst]);
+		reset_control_put(priv->resets[rst]);
+	}
 err_put_clks:
 	while (--clk >= 0)
 		clk_put(priv->clks[clk]);
@@ -284,15 +291,17 @@ static int ohci_platform_remove(struct platform_device *dev)
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
-	int clk;
+	int clk, rst;
 
 	usb_remove_hcd(hcd);
 
 	if (pdata->power_off)
 		pdata->power_off(dev);
 
-	if (priv->rst)
-		reset_control_assert(priv->rst);
+	for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++) {
+		reset_control_assert_shared(priv->resets[rst]);
+		reset_control_put(priv->resets[rst]);
+	}
 
 	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
 		clk_put(priv->clks[clk]);
-- 
2.5.0

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

* [PATCH v2 3/3] ohci-platform: Add support for controllers with multiple reset lines
@ 2015-12-11 15:42     ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 15:42 UTC (permalink / raw)
  To: linux-arm-kernel

At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
reset lines, the controller will not initialize while the reset for
its companion is still asserted, which means we need to de-assert
2 resets for the controller to work.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-New patch in v2 of this patch-set, to complement the identical patch for
 the ehci-platform code
---
 Documentation/devicetree/bindings/usb/usb-ohci.txt |  2 +-
 drivers/usb/host/ohci-platform.c                   | 49 +++++++++++++---------
 2 files changed, 30 insertions(+), 21 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
index 19233b7..9df4569 100644
--- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
@@ -14,7 +14,7 @@ Optional properties:
 - clocks : a list of phandle + clock specifier pairs
 - phys : phandle + phy specifier pair
 - phy-names : "usb"
-- resets : phandle + reset specifier pair
+- resets : a list of phandle + reset specifier pairs
 
 Example:
 
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index c2669f18..7d8bbc4 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -33,11 +33,12 @@
 
 #define DRIVER_DESC "OHCI generic platform driver"
 #define OHCI_MAX_CLKS 3
+#define OHCI_MAX_RESETS 2
 #define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
 
 struct ohci_platform_priv {
 	struct clk *clks[OHCI_MAX_CLKS];
-	struct reset_control *rst;
+	struct reset_control *resets[OHCI_MAX_RESETS];
 	struct phy **phys;
 	int num_phys;
 };
@@ -117,7 +118,7 @@ static int ohci_platform_probe(struct platform_device *dev)
 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ohci_platform_priv *priv;
 	struct ohci_hcd *ohci;
-	int err, irq, phy_num, clk = 0;
+	int err, irq, phy_num, clk = 0, rst = 0;
 
 	if (usb_disabled())
 		return -ENODEV;
@@ -195,19 +196,23 @@ static int ohci_platform_probe(struct platform_device *dev)
 				break;
 			}
 		}
-
-	}
-
-	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
-	if (IS_ERR(priv->rst)) {
-		err = PTR_ERR(priv->rst);
-		if (err == -EPROBE_DEFER)
-			goto err_put_clks;
-		priv->rst = NULL;
-	} else {
-		err = reset_control_deassert(priv->rst);
-		if (err)
-			goto err_put_clks;
+		for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
+			priv->resets[rst] =
+				of_reset_control_get_by_index(dev->dev.of_node,
+							      rst);
+			if (IS_ERR(priv->resets[rst])) {
+				err = PTR_ERR(priv->resets[rst]);
+				if (err == -EPROBE_DEFER)
+					goto err_reset;
+				priv->resets[rst] = NULL;
+				break;
+			}
+			err = reset_control_deassert_shared(priv->resets[rst]);
+			if (err) {
+				reset_control_put(priv->resets[rst]);
+				goto err_reset;
+			}
+		}
 	}
 
 	if (pdata->big_endian_desc)
@@ -265,8 +270,10 @@ err_power:
 	if (pdata->power_off)
 		pdata->power_off(dev);
 err_reset:
-	if (priv->rst)
-		reset_control_assert(priv->rst);
+	while (--rst >= 0) {
+		reset_control_assert_shared(priv->resets[rst]);
+		reset_control_put(priv->resets[rst]);
+	}
 err_put_clks:
 	while (--clk >= 0)
 		clk_put(priv->clks[clk]);
@@ -284,15 +291,17 @@ static int ohci_platform_remove(struct platform_device *dev)
 	struct usb_hcd *hcd = platform_get_drvdata(dev);
 	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
 	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
-	int clk;
+	int clk, rst;
 
 	usb_remove_hcd(hcd);
 
 	if (pdata->power_off)
 		pdata->power_off(dev);
 
-	if (priv->rst)
-		reset_control_assert(priv->rst);
+	for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++) {
+		reset_control_assert_shared(priv->resets[rst]);
+		reset_control_put(priv->resets[rst]);
+	}
 
 	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
 		clk_put(priv->clks[clk]);
-- 
2.5.0

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

* Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-11 15:41 ` Hans de Goede
@ 2015-12-11 17:10     ` Philipp Zabel
  -1 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-11 17:10 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Josh Triplett, Rashika Kheria, Stephen Warren, Maxime Ripard,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

Hi Hans,

thanks for moving this forward.

Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
> Add reset_control_deassert_shared / reset_control_assert_shared
> functions which are intended for use by drivers for hw blocks which
> (may) share a reset line with another driver / hw block.
> 
> Unlike the regular reset_control_[de]assert functions these functions
> keep track of how often deassert_shared / assert_shared have been called
> and keep the line deasserted as long as deassert has been called more
> times than assert.
>
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> ---
> Changes in v2:
> -This is a new patch in v2 of this patch-set
> ---
>  drivers/reset/core.c             | 121 ++++++++++++++++++++++++++++++++++++---
>  include/linux/reset-controller.h |   2 +
>  include/linux/reset.h            |   2 +
>  3 files changed, 116 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 9ab9290..8c3436c 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_list_mutex);
>  static LIST_HEAD(reset_controller_list);
>  
>  /**
> + * struct reset_line - a reset line
> + * @list:         list entry for the reset controllers reset line list
> + * @id:           ID of the reset line in the reset controller device
> + * @refcnt:       Number of reset_control structs referencing this device
> + * @deassert_cnt: Number of times this reset line has been deasserted
> + */
> +struct reset_line {
> +	struct list_head list;
> +	unsigned int id;
> +	unsigned int refcnt;
> +	unsigned int deassert_cnt;
> +};

I'd move rcdev into reset_line, too. That way the description is
complete, and we don't duplicate rcdev when there are multiple
reset_controls pointing here.

> +/**
>   * struct reset_control - a reset control
>   * @rcdev: a pointer to the reset controller device
>   *         this reset control belongs to
> - * @id: ID of the reset controller in the reset
> - *      controller device
> + * @line:  reset line for this reset control
>   */
>  struct reset_control {
>  	struct reset_controller_dev *rcdev;
> +	struct reset_line *line;
>  	struct device *dev;
> -	unsigned int id;
>  };
>  
>  /**
[...]
> @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
>  int reset_control_deassert(struct reset_control *rstc)
>  {

Maybe WARN_ON(rstc->line->refcnt > 1) ?

>  	if (rstc->rcdev->ops->deassert)
> -		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
> +		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
>  
>  	return -ENOTSUPP;
>  }
>  EXPORT_SYMBOL_GPL(reset_control_deassert);
>  
>  /**
> + * reset_control_assert_shared - asserts a shared reset line
> + * @rstc: reset controller
> + *
> + * Assert a shared reset line, this functions decreases the deassert count
> + * of the line by one and asserts it if, and only if, the deassert count
> + * reaches 0.

"After calling this function the shared reset line may be asserted, or
 it may still be deasserted, as long as other users keep it so."

> + */
> +int reset_control_assert_shared(struct reset_control *rstc)
> +{
> +	if (!rstc->rcdev->ops->assert)
> +		return -ENOTSUPP;

WARN_ON(rstc->line->deassert_cnt == 0)

Actually, what to do in this case? Assume ops->assert was called, or do
it again to be sure? Certainly we don't want to wrap deassert_cnt, or
the next deassert_shared will do nothing.

> +	rstc->line->deassert_cnt--;
> +	if (rstc->line->deassert_cnt)

deassert_cnt isn't protected by any lock.

> +		return 0;
> +
> +	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
> +}
> +EXPORT_SYMBOL_GPL(reset_control_assert_shared);
> +
> +/**
> + * reset_control_deassert_shared - deasserts a shared reset line
> + * @rstc: reset controller
> + *
> + * Assert a shared reset line, this functions increases the deassert count

Deassert

> + * of the line by one and deasserts the reset line (if it was not already
> + * deasserted).

"After calling this function, the shared reset line is guaranteed to be
 deasserted."

> + */
> +int reset_control_deassert_shared(struct reset_control *rstc)
> +{
> +	if (!rstc->rcdev->ops->deassert)
> +		return -ENOTSUPP;
> +
> +	rstc->line->deassert_cnt++;
> +	if (rstc->line->deassert_cnt != 1)
> +		return 0;
> +
> +	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
> +}
> +EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
> +
> +/**
>   * reset_control_status - returns a negative errno if not supported, a
>   * positive value if the reset line is asserted, or zero if the reset
>   * line is not asserted.
> @@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
>  int reset_control_status(struct reset_control *rstc)
>  {
>  	if (rstc->rcdev->ops->status)
> -		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
> +		return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
>  
>  	return -ENOTSUPP;
>  }
>  EXPORT_SYMBOL_GPL(reset_control_status);
>  
> +static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
> +					 unsigned int index)
> +{
> +	struct reset_line *line;

lockdep_assert_held here and in reset_line_put would document that these
functions are called under reset_(controller_)list_mutex.

> +	list_for_each_entry(line, &rcdev->reset_line_head, list) {
> +		if (line->id == index) {
> +			line->refcnt++;
> +			return line;
> +		}
> +	}
> +
> +	line = kzalloc(sizeof(*line), GFP_KERNEL);
> +	if (!line)
> +		return NULL;
> +
> +	list_add(&line->list, &rcdev->reset_line_head);
> +	line->id = index;
> +	line->refcnt = 1;
> +
> +	return line;
> +}
> +
> +static void reset_line_put(struct reset_line *line)
> +{
> +	if (!line)
> +		return;
> +
> +	if (--line->refcnt)
> +		return;
> +
> +	list_del(&line->list);
> +	kfree(line);
> +}
> +
>  /**
>   * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
>   * controller by index.
> @@ -155,6 +247,7 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
>  {
>  	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
>  	struct reset_controller_dev *r, *rcdev;
> +	struct reset_line *line;
>  	struct of_phandle_args args;
>  	int rstc_id;
>  	int ret;
> @@ -186,16 +279,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
>  	}
>  
>  	try_module_get(rcdev->owner);
> +
> +	/* reset_controller_list_mutex also protects the reset_line list */

Let's rename it to reset_list_mutex, then.

> +	line = reset_line_get(rcdev, rstc_id);
> +
>  	mutex_unlock(&reset_controller_list_mutex);
>  
>  	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
> -	if (!rstc) {
> +	if (!line || !rstc) {
> +		kfree(rstc);
> +		reset_line_put(line);
>  		module_put(rcdev->owner);
>  		return ERR_PTR(-ENOMEM);
>  	}
>  
>  	rstc->rcdev = rcdev;
> -	rstc->id = rstc_id;
> +	rstc->line = line;
>  
>  	return rstc;
>  }
> @@ -259,6 +358,10 @@ void reset_control_put(struct reset_control *rstc)
>  	if (IS_ERR(rstc))
>  		return;
>  
> +	mutex_lock(&reset_controller_list_mutex);
> +	reset_line_put(rstc->line);
> +	mutex_unlock(&reset_controller_list_mutex);
> +
>  	module_put(rstc->rcdev->owner);
>  	kfree(rstc);
>  }
> diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
> index ce6b962..7f2cbd1 100644
> --- a/include/linux/reset-controller.h
> +++ b/include/linux/reset-controller.h
> @@ -31,6 +31,7 @@ struct of_phandle_args;
>   * @ops: a pointer to device specific struct reset_control_ops
>   * @owner: kernel module of the reset controller driver
>   * @list: internal list of reset controller devices
> + * @reset_line_head: head of internal list of reset lines

"list of requested reset lines" or "list of reset lines in use" to make
clear the list only contains entries for the requested controls?

>   * @of_node: corresponding device tree node as phandle target
>   * @of_reset_n_cells: number of cells in reset line specifiers
>   * @of_xlate: translation function to translate from specifier as found in the
[...]

best regards
Philipp

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-11 17:10     ` Philipp Zabel
  0 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-11 17:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Hans,

thanks for moving this forward.

Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
> Add reset_control_deassert_shared / reset_control_assert_shared
> functions which are intended for use by drivers for hw blocks which
> (may) share a reset line with another driver / hw block.
> 
> Unlike the regular reset_control_[de]assert functions these functions
> keep track of how often deassert_shared / assert_shared have been called
> and keep the line deasserted as long as deassert has been called more
> times than assert.
>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> -This is a new patch in v2 of this patch-set
> ---
>  drivers/reset/core.c             | 121 ++++++++++++++++++++++++++++++++++++---
>  include/linux/reset-controller.h |   2 +
>  include/linux/reset.h            |   2 +
>  3 files changed, 116 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 9ab9290..8c3436c 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_list_mutex);
>  static LIST_HEAD(reset_controller_list);
>  
>  /**
> + * struct reset_line - a reset line
> + * @list:         list entry for the reset controllers reset line list
> + * @id:           ID of the reset line in the reset controller device
> + * @refcnt:       Number of reset_control structs referencing this device
> + * @deassert_cnt: Number of times this reset line has been deasserted
> + */
> +struct reset_line {
> +	struct list_head list;
> +	unsigned int id;
> +	unsigned int refcnt;
> +	unsigned int deassert_cnt;
> +};

I'd move rcdev into reset_line, too. That way the description is
complete, and we don't duplicate rcdev when there are multiple
reset_controls pointing here.

> +/**
>   * struct reset_control - a reset control
>   * @rcdev: a pointer to the reset controller device
>   *         this reset control belongs to
> - * @id: ID of the reset controller in the reset
> - *      controller device
> + * @line:  reset line for this reset control
>   */
>  struct reset_control {
>  	struct reset_controller_dev *rcdev;
> +	struct reset_line *line;
>  	struct device *dev;
> -	unsigned int id;
>  };
>  
>  /**
[...]
> @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
>  int reset_control_deassert(struct reset_control *rstc)
>  {

Maybe WARN_ON(rstc->line->refcnt > 1) ?

>  	if (rstc->rcdev->ops->deassert)
> -		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
> +		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
>  
>  	return -ENOTSUPP;
>  }
>  EXPORT_SYMBOL_GPL(reset_control_deassert);
>  
>  /**
> + * reset_control_assert_shared - asserts a shared reset line
> + * @rstc: reset controller
> + *
> + * Assert a shared reset line, this functions decreases the deassert count
> + * of the line by one and asserts it if, and only if, the deassert count
> + * reaches 0.

"After calling this function the shared reset line may be asserted, or
 it may still be deasserted, as long as other users keep it so."

> + */
> +int reset_control_assert_shared(struct reset_control *rstc)
> +{
> +	if (!rstc->rcdev->ops->assert)
> +		return -ENOTSUPP;

WARN_ON(rstc->line->deassert_cnt == 0)

Actually, what to do in this case? Assume ops->assert was called, or do
it again to be sure? Certainly we don't want to wrap deassert_cnt, or
the next deassert_shared will do nothing.

> +	rstc->line->deassert_cnt--;
> +	if (rstc->line->deassert_cnt)

deassert_cnt isn't protected by any lock.

> +		return 0;
> +
> +	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
> +}
> +EXPORT_SYMBOL_GPL(reset_control_assert_shared);
> +
> +/**
> + * reset_control_deassert_shared - deasserts a shared reset line
> + * @rstc: reset controller
> + *
> + * Assert a shared reset line, this functions increases the deassert count

Deassert

> + * of the line by one and deasserts the reset line (if it was not already
> + * deasserted).

"After calling this function, the shared reset line is guaranteed to be
 deasserted."

> + */
> +int reset_control_deassert_shared(struct reset_control *rstc)
> +{
> +	if (!rstc->rcdev->ops->deassert)
> +		return -ENOTSUPP;
> +
> +	rstc->line->deassert_cnt++;
> +	if (rstc->line->deassert_cnt != 1)
> +		return 0;
> +
> +	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
> +}
> +EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
> +
> +/**
>   * reset_control_status - returns a negative errno if not supported, a
>   * positive value if the reset line is asserted, or zero if the reset
>   * line is not asserted.
> @@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
>  int reset_control_status(struct reset_control *rstc)
>  {
>  	if (rstc->rcdev->ops->status)
> -		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
> +		return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
>  
>  	return -ENOTSUPP;
>  }
>  EXPORT_SYMBOL_GPL(reset_control_status);
>  
> +static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
> +					 unsigned int index)
> +{
> +	struct reset_line *line;

lockdep_assert_held here and in reset_line_put would document that these
functions are called under reset_(controller_)list_mutex.

> +	list_for_each_entry(line, &rcdev->reset_line_head, list) {
> +		if (line->id == index) {
> +			line->refcnt++;
> +			return line;
> +		}
> +	}
> +
> +	line = kzalloc(sizeof(*line), GFP_KERNEL);
> +	if (!line)
> +		return NULL;
> +
> +	list_add(&line->list, &rcdev->reset_line_head);
> +	line->id = index;
> +	line->refcnt = 1;
> +
> +	return line;
> +}
> +
> +static void reset_line_put(struct reset_line *line)
> +{
> +	if (!line)
> +		return;
> +
> +	if (--line->refcnt)
> +		return;
> +
> +	list_del(&line->list);
> +	kfree(line);
> +}
> +
>  /**
>   * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
>   * controller by index.
> @@ -155,6 +247,7 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
>  {
>  	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
>  	struct reset_controller_dev *r, *rcdev;
> +	struct reset_line *line;
>  	struct of_phandle_args args;
>  	int rstc_id;
>  	int ret;
> @@ -186,16 +279,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
>  	}
>  
>  	try_module_get(rcdev->owner);
> +
> +	/* reset_controller_list_mutex also protects the reset_line list */

Let's rename it to reset_list_mutex, then.

> +	line = reset_line_get(rcdev, rstc_id);
> +
>  	mutex_unlock(&reset_controller_list_mutex);
>  
>  	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
> -	if (!rstc) {
> +	if (!line || !rstc) {
> +		kfree(rstc);
> +		reset_line_put(line);
>  		module_put(rcdev->owner);
>  		return ERR_PTR(-ENOMEM);
>  	}
>  
>  	rstc->rcdev = rcdev;
> -	rstc->id = rstc_id;
> +	rstc->line = line;
>  
>  	return rstc;
>  }
> @@ -259,6 +358,10 @@ void reset_control_put(struct reset_control *rstc)
>  	if (IS_ERR(rstc))
>  		return;
>  
> +	mutex_lock(&reset_controller_list_mutex);
> +	reset_line_put(rstc->line);
> +	mutex_unlock(&reset_controller_list_mutex);
> +
>  	module_put(rstc->rcdev->owner);
>  	kfree(rstc);
>  }
> diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
> index ce6b962..7f2cbd1 100644
> --- a/include/linux/reset-controller.h
> +++ b/include/linux/reset-controller.h
> @@ -31,6 +31,7 @@ struct of_phandle_args;
>   * @ops: a pointer to device specific struct reset_control_ops
>   * @owner: kernel module of the reset controller driver
>   * @list: internal list of reset controller devices
> + * @reset_line_head: head of internal list of reset lines

"list of requested reset lines" or "list of reset lines in use" to make
clear the list only contains entries for the requested controls?

>   * @of_node: corresponding device tree node as phandle target
>   * @of_reset_n_cells: number of cells in reset line specifiers
>   * @of_xlate: translation function to translate from specifier as found in the
[...]

best regards
Philipp

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

* Re: [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
  2015-12-11 15:41     ` Hans de Goede
@ 2015-12-11 17:13         ` Philipp Zabel
  -1 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-11 17:13 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Josh Triplett, Rashika Kheria, Stephen Warren, Maxime Ripard,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai, Reinder de Haan

Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
> From: Reinder de Haan <patchesrdh-I1/eAgTnXDYAvxtiuMwx3w@public.gmane.org>
> 
> At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
> reset lines, the controller will not initialize while the reset for
> its companion is still asserted, which means we need to de-assert
> 2 resets for the controller to work.
> 
> Signed-off-by: Reinder de Haan <patchesrdh-I1/eAgTnXDYAvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> ---
> Changes in v2:
> -Use the new reset_control_[de]assert_shared reset-controller functions
> ---
>  Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
>  drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
>  2 files changed, 30 insertions(+), 19 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> index a12d601..0701812 100644
> --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
> +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> @@ -18,7 +18,7 @@ Optional properties:
>   - clocks : a list of phandle + clock specifier pairs
>   - phys : phandle + phy specifier pair
>   - phy-names : "usb"
> - - resets : phandle + reset specifier pair
> + - resets : a list of phandle + reset specifier pairs

Are there documented names for these resets? Is the companion you
mention the Port Control?

regards
Philipp

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

* [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
@ 2015-12-11 17:13         ` Philipp Zabel
  0 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-11 17:13 UTC (permalink / raw)
  To: linux-arm-kernel

Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
> From: Reinder de Haan <patchesrdh@mveas.com>
> 
> At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
> reset lines, the controller will not initialize while the reset for
> its companion is still asserted, which means we need to de-assert
> 2 resets for the controller to work.
> 
> Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> Changes in v2:
> -Use the new reset_control_[de]assert_shared reset-controller functions
> ---
>  Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
>  drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
>  2 files changed, 30 insertions(+), 19 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> index a12d601..0701812 100644
> --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
> +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> @@ -18,7 +18,7 @@ Optional properties:
>   - clocks : a list of phandle + clock specifier pairs
>   - phys : phandle + phy specifier pair
>   - phy-names : "usb"
> - - resets : phandle + reset specifier pair
> + - resets : a list of phandle + reset specifier pairs

Are there documented names for these resets? Is the companion you
mention the Port Control?

regards
Philipp

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

* Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-11 17:10     ` Philipp Zabel
@ 2015-12-11 18:21         ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 18:21 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Josh Triplett, Rashika Kheria, Stephen Warren, Maxime Ripard,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

Hi,

On 11-12-15 18:10, Philipp Zabel wrote:
> Hi Hans,
>
> thanks for moving this forward.

Thanks for the quick review, I've a couple of (simple) questions
about your review remarks once those are cleared up I'll post a new version
(of just this patch).

> Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
>> Add reset_control_deassert_shared / reset_control_assert_shared
>> functions which are intended for use by drivers for hw blocks which
>> (may) share a reset line with another driver / hw block.
>>
>> Unlike the regular reset_control_[de]assert functions these functions
>> keep track of how often deassert_shared / assert_shared have been called
>> and keep the line deasserted as long as deassert has been called more
>> times than assert.
>>
>> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> ---
>> Changes in v2:
>> -This is a new patch in v2 of this patch-set
>> ---
>>   drivers/reset/core.c             | 121 ++++++++++++++++++++++++++++++++++++---
>>   include/linux/reset-controller.h |   2 +
>>   include/linux/reset.h            |   2 +
>>   3 files changed, 116 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
>> index 9ab9290..8c3436c 100644
>> --- a/drivers/reset/core.c
>> +++ b/drivers/reset/core.c
>> @@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_list_mutex);
>>   static LIST_HEAD(reset_controller_list);
>>
>>   /**
>> + * struct reset_line - a reset line
>> + * @list:         list entry for the reset controllers reset line list
>> + * @id:           ID of the reset line in the reset controller device
>> + * @refcnt:       Number of reset_control structs referencing this device
>> + * @deassert_cnt: Number of times this reset line has been deasserted
>> + */
>> +struct reset_line {
>> +	struct list_head list;
>> +	unsigned int id;
>> +	unsigned int refcnt;
>> +	unsigned int deassert_cnt;
>> +};
>
> I'd move rcdev into reset_line, too. That way the description is
> complete, and we don't duplicate rcdev when there are multiple
> reset_controls pointing here.

Ack.

>> +/**
>>    * struct reset_control - a reset control
>>    * @rcdev: a pointer to the reset controller device
>>    *         this reset control belongs to
>> - * @id: ID of the reset controller in the reset
>> - *      controller device
>> + * @line:  reset line for this reset control
>>    */
>>   struct reset_control {
>>   	struct reset_controller_dev *rcdev;
>> +	struct reset_line *line;
>>   	struct device *dev;
>> -	unsigned int id;
>>   };
>>
>>   /**
> [...]
>> @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
>>   int reset_control_deassert(struct reset_control *rstc)
>>   {
>
> Maybe WARN_ON(rstc->line->refcnt > 1) ?

I assume you mean deasser_cnt ? Seems reasonable with that change.

>>   	if (rstc->rcdev->ops->deassert)
>> -		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
>> +		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
>>
>>   	return -ENOTSUPP;
>>   }
>>   EXPORT_SYMBOL_GPL(reset_control_deassert);
>>
>>   /**
>> + * reset_control_assert_shared - asserts a shared reset line
>> + * @rstc: reset controller
>> + *
>> + * Assert a shared reset line, this functions decreases the deassert count
>> + * of the line by one and asserts it if, and only if, the deassert count
>> + * reaches 0.
>
> "After calling this function the shared reset line may be asserted, or
>   it may still be deasserted, as long as other users keep it so."

I take it this is to replace the text about "deassert count" ?

>> + */
>> +int reset_control_assert_shared(struct reset_control *rstc)
>> +{
>> +	if (!rstc->rcdev->ops->assert)
>> +		return -ENOTSUPP;
>
> WARN_ON(rstc->line->deassert_cnt == 0)
>
> Actually, what to do in this case? Assume ops->assert was called, or do
> it again to be sure? Certainly we don't want to wrap deassert_cnt, or
> the next deassert_shared will do nothing.
>
>> +	rstc->line->deassert_cnt--;
>> +	if (rstc->line->deassert_cnt)
>
> deassert_cnt isn't protected by any lock.

Right, good catch. I believe the best way to fix this is to change deassert_cnt
into an atomic_t and use atomic_dec_return / atomic_int_return,

Downside of using an atomic_t is that doing the WARN_ON you are asking for above
will not be race free, then, but since it is a should never happen scenario I
guess we do not care about the check not being 100% race free. Or we can even
just leave out the check ?


>
>> +		return 0;
>> +
>> +	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
>> +}
>> +EXPORT_SYMBOL_GPL(reset_control_assert_shared);
>> +
>> +/**
>> + * reset_control_deassert_shared - deasserts a shared reset line
>> + * @rstc: reset controller
>> + *
>> + * Assert a shared reset line, this functions increases the deassert count
>
> Deassert

Ack.

>> + * of the line by one and deasserts the reset line (if it was not already
>> + * deasserted).
>
> "After calling this function, the shared reset line is guaranteed to be
>   deasserted."

Same question as above.

>> + */
>> +int reset_control_deassert_shared(struct reset_control *rstc)
>> +{
>> +	if (!rstc->rcdev->ops->deassert)
>> +		return -ENOTSUPP;
>> +
>> +	rstc->line->deassert_cnt++;
>> +	if (rstc->line->deassert_cnt != 1)
>> +		return 0;
>> +
>> +	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
>> +}
>> +EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
>> +
>> +/**
>>    * reset_control_status - returns a negative errno if not supported, a
>>    * positive value if the reset line is asserted, or zero if the reset
>>    * line is not asserted.
>> @@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
>>   int reset_control_status(struct reset_control *rstc)
>>   {
>>   	if (rstc->rcdev->ops->status)
>> -		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
>> +		return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
>>
>>   	return -ENOTSUPP;
>>   }
>>   EXPORT_SYMBOL_GPL(reset_control_status);
>>
>> +static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
>> +					 unsigned int index)
>> +{
>> +	struct reset_line *line;
>
> lockdep_assert_held here and in reset_line_put would document that these
> functions are called under reset_(controller_)list_mutex.

Ok, I will add these.

>> +	list_for_each_entry(line, &rcdev->reset_line_head, list) {
>> +		if (line->id == index) {
>> +			line->refcnt++;
>> +			return line;
>> +		}
>> +	}
>> +
>> +	line = kzalloc(sizeof(*line), GFP_KERNEL);
>> +	if (!line)
>> +		return NULL;
>> +
>> +	list_add(&line->list, &rcdev->reset_line_head);
>> +	line->id = index;
>> +	line->refcnt = 1;
>> +
>> +	return line;
>> +}
>> +
>> +static void reset_line_put(struct reset_line *line)
>> +{
>> +	if (!line)
>> +		return;
>> +
>> +	if (--line->refcnt)
>> +		return;
>> +
>> +	list_del(&line->list);
>> +	kfree(line);
>> +}
>> +
>>   /**
>>    * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
>>    * controller by index.
>> @@ -155,6 +247,7 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
>>   {
>>   	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
>>   	struct reset_controller_dev *r, *rcdev;
>> +	struct reset_line *line;
>>   	struct of_phandle_args args;
>>   	int rstc_id;
>>   	int ret;
>> @@ -186,16 +279,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
>>   	}
>>
>>   	try_module_get(rcdev->owner);
>> +
>> +	/* reset_controller_list_mutex also protects the reset_line list */
>
> Let's rename it to reset_list_mutex, then.

Ack.

>> +	line = reset_line_get(rcdev, rstc_id);
>> +
>>   	mutex_unlock(&reset_controller_list_mutex);
>>
>>   	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
>> -	if (!rstc) {
>> +	if (!line || !rstc) {
>> +		kfree(rstc);
>> +		reset_line_put(line);
>>   		module_put(rcdev->owner);
>>   		return ERR_PTR(-ENOMEM);
>>   	}
>>
>>   	rstc->rcdev = rcdev;
>> -	rstc->id = rstc_id;
>> +	rstc->line = line;
>>
>>   	return rstc;
>>   }
>> @@ -259,6 +358,10 @@ void reset_control_put(struct reset_control *rstc)
>>   	if (IS_ERR(rstc))
>>   		return;
>>
>> +	mutex_lock(&reset_controller_list_mutex);
>> +	reset_line_put(rstc->line);
>> +	mutex_unlock(&reset_controller_list_mutex);
>> +
>>   	module_put(rstc->rcdev->owner);
>>   	kfree(rstc);
>>   }
>> diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
>> index ce6b962..7f2cbd1 100644
>> --- a/include/linux/reset-controller.h
>> +++ b/include/linux/reset-controller.h
>> @@ -31,6 +31,7 @@ struct of_phandle_args;
>>    * @ops: a pointer to device specific struct reset_control_ops
>>    * @owner: kernel module of the reset controller driver
>>    * @list: internal list of reset controller devices
>> + * @reset_line_head: head of internal list of reset lines
>
> "list of requested reset lines" or "list of reset lines in use" to make
> clear the list only contains entries for the requested controls?

Ok, will fix.

>>    * @of_node: corresponding device tree node as phandle target
>>    * @of_reset_n_cells: number of cells in reset line specifiers
>>    * @of_xlate: translation function to translate from specifier as found in the
> [...]
>
> best regards
> Philipp
>

Regards,

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

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-11 18:21         ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 18:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 11-12-15 18:10, Philipp Zabel wrote:
> Hi Hans,
>
> thanks for moving this forward.

Thanks for the quick review, I've a couple of (simple) questions
about your review remarks once those are cleared up I'll post a new version
(of just this patch).

> Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
>> Add reset_control_deassert_shared / reset_control_assert_shared
>> functions which are intended for use by drivers for hw blocks which
>> (may) share a reset line with another driver / hw block.
>>
>> Unlike the regular reset_control_[de]assert functions these functions
>> keep track of how often deassert_shared / assert_shared have been called
>> and keep the line deasserted as long as deassert has been called more
>> times than assert.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>> Changes in v2:
>> -This is a new patch in v2 of this patch-set
>> ---
>>   drivers/reset/core.c             | 121 ++++++++++++++++++++++++++++++++++++---
>>   include/linux/reset-controller.h |   2 +
>>   include/linux/reset.h            |   2 +
>>   3 files changed, 116 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
>> index 9ab9290..8c3436c 100644
>> --- a/drivers/reset/core.c
>> +++ b/drivers/reset/core.c
>> @@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_list_mutex);
>>   static LIST_HEAD(reset_controller_list);
>>
>>   /**
>> + * struct reset_line - a reset line
>> + * @list:         list entry for the reset controllers reset line list
>> + * @id:           ID of the reset line in the reset controller device
>> + * @refcnt:       Number of reset_control structs referencing this device
>> + * @deassert_cnt: Number of times this reset line has been deasserted
>> + */
>> +struct reset_line {
>> +	struct list_head list;
>> +	unsigned int id;
>> +	unsigned int refcnt;
>> +	unsigned int deassert_cnt;
>> +};
>
> I'd move rcdev into reset_line, too. That way the description is
> complete, and we don't duplicate rcdev when there are multiple
> reset_controls pointing here.

Ack.

>> +/**
>>    * struct reset_control - a reset control
>>    * @rcdev: a pointer to the reset controller device
>>    *         this reset control belongs to
>> - * @id: ID of the reset controller in the reset
>> - *      controller device
>> + * @line:  reset line for this reset control
>>    */
>>   struct reset_control {
>>   	struct reset_controller_dev *rcdev;
>> +	struct reset_line *line;
>>   	struct device *dev;
>> -	unsigned int id;
>>   };
>>
>>   /**
> [...]
>> @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
>>   int reset_control_deassert(struct reset_control *rstc)
>>   {
>
> Maybe WARN_ON(rstc->line->refcnt > 1) ?

I assume you mean deasser_cnt ? Seems reasonable with that change.

>>   	if (rstc->rcdev->ops->deassert)
>> -		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
>> +		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
>>
>>   	return -ENOTSUPP;
>>   }
>>   EXPORT_SYMBOL_GPL(reset_control_deassert);
>>
>>   /**
>> + * reset_control_assert_shared - asserts a shared reset line
>> + * @rstc: reset controller
>> + *
>> + * Assert a shared reset line, this functions decreases the deassert count
>> + * of the line by one and asserts it if, and only if, the deassert count
>> + * reaches 0.
>
> "After calling this function the shared reset line may be asserted, or
>   it may still be deasserted, as long as other users keep it so."

I take it this is to replace the text about "deassert count" ?

>> + */
>> +int reset_control_assert_shared(struct reset_control *rstc)
>> +{
>> +	if (!rstc->rcdev->ops->assert)
>> +		return -ENOTSUPP;
>
> WARN_ON(rstc->line->deassert_cnt == 0)
>
> Actually, what to do in this case? Assume ops->assert was called, or do
> it again to be sure? Certainly we don't want to wrap deassert_cnt, or
> the next deassert_shared will do nothing.
>
>> +	rstc->line->deassert_cnt--;
>> +	if (rstc->line->deassert_cnt)
>
> deassert_cnt isn't protected by any lock.

Right, good catch. I believe the best way to fix this is to change deassert_cnt
into an atomic_t and use atomic_dec_return / atomic_int_return,

Downside of using an atomic_t is that doing the WARN_ON you are asking for above
will not be race free, then, but since it is a should never happen scenario I
guess we do not care about the check not being 100% race free. Or we can even
just leave out the check ?


>
>> +		return 0;
>> +
>> +	return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
>> +}
>> +EXPORT_SYMBOL_GPL(reset_control_assert_shared);
>> +
>> +/**
>> + * reset_control_deassert_shared - deasserts a shared reset line
>> + * @rstc: reset controller
>> + *
>> + * Assert a shared reset line, this functions increases the deassert count
>
> Deassert

Ack.

>> + * of the line by one and deasserts the reset line (if it was not already
>> + * deasserted).
>
> "After calling this function, the shared reset line is guaranteed to be
>   deasserted."

Same question as above.

>> + */
>> +int reset_control_deassert_shared(struct reset_control *rstc)
>> +{
>> +	if (!rstc->rcdev->ops->deassert)
>> +		return -ENOTSUPP;
>> +
>> +	rstc->line->deassert_cnt++;
>> +	if (rstc->line->deassert_cnt != 1)
>> +		return 0;
>> +
>> +	return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
>> +}
>> +EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
>> +
>> +/**
>>    * reset_control_status - returns a negative errno if not supported, a
>>    * positive value if the reset line is asserted, or zero if the reset
>>    * line is not asserted.
>> @@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
>>   int reset_control_status(struct reset_control *rstc)
>>   {
>>   	if (rstc->rcdev->ops->status)
>> -		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
>> +		return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
>>
>>   	return -ENOTSUPP;
>>   }
>>   EXPORT_SYMBOL_GPL(reset_control_status);
>>
>> +static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
>> +					 unsigned int index)
>> +{
>> +	struct reset_line *line;
>
> lockdep_assert_held here and in reset_line_put would document that these
> functions are called under reset_(controller_)list_mutex.

Ok, I will add these.

>> +	list_for_each_entry(line, &rcdev->reset_line_head, list) {
>> +		if (line->id == index) {
>> +			line->refcnt++;
>> +			return line;
>> +		}
>> +	}
>> +
>> +	line = kzalloc(sizeof(*line), GFP_KERNEL);
>> +	if (!line)
>> +		return NULL;
>> +
>> +	list_add(&line->list, &rcdev->reset_line_head);
>> +	line->id = index;
>> +	line->refcnt = 1;
>> +
>> +	return line;
>> +}
>> +
>> +static void reset_line_put(struct reset_line *line)
>> +{
>> +	if (!line)
>> +		return;
>> +
>> +	if (--line->refcnt)
>> +		return;
>> +
>> +	list_del(&line->list);
>> +	kfree(line);
>> +}
>> +
>>   /**
>>    * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
>>    * controller by index.
>> @@ -155,6 +247,7 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
>>   {
>>   	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
>>   	struct reset_controller_dev *r, *rcdev;
>> +	struct reset_line *line;
>>   	struct of_phandle_args args;
>>   	int rstc_id;
>>   	int ret;
>> @@ -186,16 +279,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
>>   	}
>>
>>   	try_module_get(rcdev->owner);
>> +
>> +	/* reset_controller_list_mutex also protects the reset_line list */
>
> Let's rename it to reset_list_mutex, then.

Ack.

>> +	line = reset_line_get(rcdev, rstc_id);
>> +
>>   	mutex_unlock(&reset_controller_list_mutex);
>>
>>   	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
>> -	if (!rstc) {
>> +	if (!line || !rstc) {
>> +		kfree(rstc);
>> +		reset_line_put(line);
>>   		module_put(rcdev->owner);
>>   		return ERR_PTR(-ENOMEM);
>>   	}
>>
>>   	rstc->rcdev = rcdev;
>> -	rstc->id = rstc_id;
>> +	rstc->line = line;
>>
>>   	return rstc;
>>   }
>> @@ -259,6 +358,10 @@ void reset_control_put(struct reset_control *rstc)
>>   	if (IS_ERR(rstc))
>>   		return;
>>
>> +	mutex_lock(&reset_controller_list_mutex);
>> +	reset_line_put(rstc->line);
>> +	mutex_unlock(&reset_controller_list_mutex);
>> +
>>   	module_put(rstc->rcdev->owner);
>>   	kfree(rstc);
>>   }
>> diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
>> index ce6b962..7f2cbd1 100644
>> --- a/include/linux/reset-controller.h
>> +++ b/include/linux/reset-controller.h
>> @@ -31,6 +31,7 @@ struct of_phandle_args;
>>    * @ops: a pointer to device specific struct reset_control_ops
>>    * @owner: kernel module of the reset controller driver
>>    * @list: internal list of reset controller devices
>> + * @reset_line_head: head of internal list of reset lines
>
> "list of requested reset lines" or "list of reset lines in use" to make
> clear the list only contains entries for the requested controls?

Ok, will fix.

>>    * @of_node: corresponding device tree node as phandle target
>>    * @of_reset_n_cells: number of cells in reset line specifiers
>>    * @of_xlate: translation function to translate from specifier as found in the
> [...]
>
> best regards
> Philipp
>

Regards,

Hans

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

* Re: [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
  2015-12-11 17:13         ` Philipp Zabel
@ 2015-12-11 18:28             ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 18:28 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Josh Triplett, Rashika Kheria, Stephen Warren, Maxime Ripard,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai, Reinder de Haan

Hi,

On 11-12-15 18:13, Philipp Zabel wrote:
> Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
>> From: Reinder de Haan <patchesrdh-I1/eAgTnXDYAvxtiuMwx3w@public.gmane.org>
>>
>> At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
>> reset lines, the controller will not initialize while the reset for
>> its companion is still asserted, which means we need to de-assert
>> 2 resets for the controller to work.
>>
>> Signed-off-by: Reinder de Haan <patchesrdh-I1/eAgTnXDYAvxtiuMwx3w@public.gmane.org>
>> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> ---
>> Changes in v2:
>> -Use the new reset_control_[de]assert_shared reset-controller functions
>> ---
>>   Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
>>   drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
>>   2 files changed, 30 insertions(+), 19 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
>> index a12d601..0701812 100644
>> --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
>> +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
>> @@ -18,7 +18,7 @@ Optional properties:
>>    - clocks : a list of phandle + clock specifier pairs
>>    - phys : phandle + phy specifier pair
>>    - phy-names : "usb"
>> - - resets : phandle + reset specifier pair
>> + - resets : a list of phandle + reset specifier pairs
>
> Are there documented names for these resets?

This binding is a generic ehci controller binding, so even if
the names are documented for the allwinner SoC we should
not use names, just like the binding is deliberately not
using names for the clocks either to keep it generic, so
that we can reuse the binding + driver with many different SoCs.

> Is the companion you
> mention the Port Control?

Sort of, with USB-2, USB-1 compatibility is handled via a mux on the
datalines (controlled by the EHCI controller Port Control) which muxes
the lines to an USB-1 controller (typically either UHCI or OHCI) when the
device does not connect after USB-2 highspeed handshaking.

This USB-1 controller (or controller_S_ in some case since the
USB-1 companions may have less root-ports per controller then the EHCI
has root-ports) is called the companion controller.

The 2 controllers are supposed to be 100% independent but on the H3
Allwinner has done something (not documented) which requires one to
deassert reset on both before you can talk to either one.

Regards,

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

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

* [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
@ 2015-12-11 18:28             ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-11 18:28 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 11-12-15 18:13, Philipp Zabel wrote:
> Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
>> From: Reinder de Haan <patchesrdh@mveas.com>
>>
>> At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
>> reset lines, the controller will not initialize while the reset for
>> its companion is still asserted, which means we need to de-assert
>> 2 resets for the controller to work.
>>
>> Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>> Changes in v2:
>> -Use the new reset_control_[de]assert_shared reset-controller functions
>> ---
>>   Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
>>   drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
>>   2 files changed, 30 insertions(+), 19 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
>> index a12d601..0701812 100644
>> --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
>> +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
>> @@ -18,7 +18,7 @@ Optional properties:
>>    - clocks : a list of phandle + clock specifier pairs
>>    - phys : phandle + phy specifier pair
>>    - phy-names : "usb"
>> - - resets : phandle + reset specifier pair
>> + - resets : a list of phandle + reset specifier pairs
>
> Are there documented names for these resets?

This binding is a generic ehci controller binding, so even if
the names are documented for the allwinner SoC we should
not use names, just like the binding is deliberately not
using names for the clocks either to keep it generic, so
that we can reuse the binding + driver with many different SoCs.

> Is the companion you
> mention the Port Control?

Sort of, with USB-2, USB-1 compatibility is handled via a mux on the
datalines (controlled by the EHCI controller Port Control) which muxes
the lines to an USB-1 controller (typically either UHCI or OHCI) when the
device does not connect after USB-2 highspeed handshaking.

This USB-1 controller (or controller_S_ in some case since the
USB-1 companions may have less root-ports per controller then the EHCI
has root-ports) is called the companion controller.

The 2 controllers are supposed to be 100% independent but on the H3
Allwinner has done something (not documented) which requires one to
deassert reset on both before you can talk to either one.

Regards,

Hans

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

* Re: [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
  2015-12-11 15:41     ` Hans de Goede
@ 2015-12-14  1:09         ` Rob Herring
  -1 siblings, 0 replies; 38+ messages in thread
From: Rob Herring @ 2015-12-14  1:09 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Philipp Zabel, Josh Triplett, Rashika Kheria, Stephen Warren,
	Maxime Ripard, Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai, Reinder de Haan

On Fri, Dec 11, 2015 at 04:41:59PM +0100, Hans de Goede wrote:
> From: Reinder de Haan <patchesrdh-I1/eAgTnXDYAvxtiuMwx3w@public.gmane.org>
> 
> At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
> reset lines, the controller will not initialize while the reset for
> its companion is still asserted, which means we need to de-assert
> 2 resets for the controller to work.
> 
> Signed-off-by: Reinder de Haan <patchesrdh-I1/eAgTnXDYAvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

> ---
> Changes in v2:
> -Use the new reset_control_[de]assert_shared reset-controller functions
> ---
>  Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
>  drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
>  2 files changed, 30 insertions(+), 19 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> index a12d601..0701812 100644
> --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
> +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> @@ -18,7 +18,7 @@ Optional properties:
>   - clocks : a list of phandle + clock specifier pairs
>   - phys : phandle + phy specifier pair
>   - phy-names : "usb"
> - - resets : phandle + reset specifier pair
> + - resets : a list of phandle + reset specifier pairs
>  
>  Example (Sequoia 440EPx):
>      ehci@e0000300 {
> diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
> index bd7082f2..6fbf32a 100644
> --- a/drivers/usb/host/ehci-platform.c
> +++ b/drivers/usb/host/ehci-platform.c
> @@ -39,11 +39,12 @@
>  
>  #define DRIVER_DESC "EHCI generic platform driver"
>  #define EHCI_MAX_CLKS 3
> +#define EHCI_MAX_RESETS 2
>  #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
>  
>  struct ehci_platform_priv {
>  	struct clk *clks[EHCI_MAX_CLKS];
> -	struct reset_control *rst;
> +	struct reset_control *resets[EHCI_MAX_RESETS];
>  	struct phy **phys;
>  	int num_phys;
>  	bool reset_on_resume;
> @@ -149,7 +150,7 @@ static int ehci_platform_probe(struct platform_device *dev)
>  	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
>  	struct ehci_platform_priv *priv;
>  	struct ehci_hcd *ehci;
> -	int err, irq, phy_num, clk = 0;
> +	int err, irq, phy_num, clk = 0, rst = 0;
>  
>  	if (usb_disabled())
>  		return -ENODEV;
> @@ -232,18 +233,24 @@ static int ehci_platform_probe(struct platform_device *dev)
>  				break;
>  			}
>  		}
> -	}
>  
> -	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
> -	if (IS_ERR(priv->rst)) {
> -		err = PTR_ERR(priv->rst);
> -		if (err == -EPROBE_DEFER)
> -			goto err_put_clks;
> -		priv->rst = NULL;
> -	} else {
> -		err = reset_control_deassert(priv->rst);
> -		if (err)
> -			goto err_put_clks;
> +		for (rst = 0; rst < EHCI_MAX_RESETS; rst++) {
> +			priv->resets[rst] =
> +				of_reset_control_get_by_index(dev->dev.of_node,
> +							      rst);
> +			if (IS_ERR(priv->resets[rst])) {
> +				err = PTR_ERR(priv->resets[rst]);
> +				if (err == -EPROBE_DEFER)
> +					goto err_reset;
> +				priv->resets[rst] = NULL;
> +				break;
> +			}
> +			err = reset_control_deassert_shared(priv->resets[rst]);
> +			if (err) {
> +				reset_control_put(priv->resets[rst]);
> +				goto err_reset;
> +			}
> +		}
>  	}
>  
>  	if (pdata->big_endian_desc)
> @@ -300,8 +307,10 @@ err_power:
>  	if (pdata->power_off)
>  		pdata->power_off(dev);
>  err_reset:
> -	if (priv->rst)
> -		reset_control_assert(priv->rst);
> +	while (--rst >= 0) {
> +		reset_control_assert_shared(priv->resets[rst]);
> +		reset_control_put(priv->resets[rst]);
> +	}
>  err_put_clks:
>  	while (--clk >= 0)
>  		clk_put(priv->clks[clk]);
> @@ -319,15 +328,17 @@ static int ehci_platform_remove(struct platform_device *dev)
>  	struct usb_hcd *hcd = platform_get_drvdata(dev);
>  	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
>  	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
> -	int clk;
> +	int clk, rst;
>  
>  	usb_remove_hcd(hcd);
>  
>  	if (pdata->power_off)
>  		pdata->power_off(dev);
>  
> -	if (priv->rst)
> -		reset_control_assert(priv->rst);
> +	for (rst = 0; rst < EHCI_MAX_RESETS && priv->resets[rst]; rst++) {
> +		reset_control_assert_shared(priv->resets[rst]);
> +		reset_control_put(priv->resets[rst]);
> +	}
>  
>  	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
>  		clk_put(priv->clks[clk]);
> -- 
> 2.5.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
@ 2015-12-14  1:09         ` Rob Herring
  0 siblings, 0 replies; 38+ messages in thread
From: Rob Herring @ 2015-12-14  1:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Dec 11, 2015 at 04:41:59PM +0100, Hans de Goede wrote:
> From: Reinder de Haan <patchesrdh@mveas.com>
> 
> At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
> reset lines, the controller will not initialize while the reset for
> its companion is still asserted, which means we need to de-assert
> 2 resets for the controller to work.
> 
> Signed-off-by: Reinder de Haan <patchesrdh@mveas.com>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Acked-by: Rob Herring <robh@kernel.org>

> ---
> Changes in v2:
> -Use the new reset_control_[de]assert_shared reset-controller functions
> ---
>  Documentation/devicetree/bindings/usb/usb-ehci.txt |  2 +-
>  drivers/usb/host/ehci-platform.c                   | 47 +++++++++++++---------
>  2 files changed, 30 insertions(+), 19 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> index a12d601..0701812 100644
> --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
> +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> @@ -18,7 +18,7 @@ Optional properties:
>   - clocks : a list of phandle + clock specifier pairs
>   - phys : phandle + phy specifier pair
>   - phy-names : "usb"
> - - resets : phandle + reset specifier pair
> + - resets : a list of phandle + reset specifier pairs
>  
>  Example (Sequoia 440EPx):
>      ehci at e0000300 {
> diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
> index bd7082f2..6fbf32a 100644
> --- a/drivers/usb/host/ehci-platform.c
> +++ b/drivers/usb/host/ehci-platform.c
> @@ -39,11 +39,12 @@
>  
>  #define DRIVER_DESC "EHCI generic platform driver"
>  #define EHCI_MAX_CLKS 3
> +#define EHCI_MAX_RESETS 2
>  #define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
>  
>  struct ehci_platform_priv {
>  	struct clk *clks[EHCI_MAX_CLKS];
> -	struct reset_control *rst;
> +	struct reset_control *resets[EHCI_MAX_RESETS];
>  	struct phy **phys;
>  	int num_phys;
>  	bool reset_on_resume;
> @@ -149,7 +150,7 @@ static int ehci_platform_probe(struct platform_device *dev)
>  	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
>  	struct ehci_platform_priv *priv;
>  	struct ehci_hcd *ehci;
> -	int err, irq, phy_num, clk = 0;
> +	int err, irq, phy_num, clk = 0, rst = 0;
>  
>  	if (usb_disabled())
>  		return -ENODEV;
> @@ -232,18 +233,24 @@ static int ehci_platform_probe(struct platform_device *dev)
>  				break;
>  			}
>  		}
> -	}
>  
> -	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
> -	if (IS_ERR(priv->rst)) {
> -		err = PTR_ERR(priv->rst);
> -		if (err == -EPROBE_DEFER)
> -			goto err_put_clks;
> -		priv->rst = NULL;
> -	} else {
> -		err = reset_control_deassert(priv->rst);
> -		if (err)
> -			goto err_put_clks;
> +		for (rst = 0; rst < EHCI_MAX_RESETS; rst++) {
> +			priv->resets[rst] =
> +				of_reset_control_get_by_index(dev->dev.of_node,
> +							      rst);
> +			if (IS_ERR(priv->resets[rst])) {
> +				err = PTR_ERR(priv->resets[rst]);
> +				if (err == -EPROBE_DEFER)
> +					goto err_reset;
> +				priv->resets[rst] = NULL;
> +				break;
> +			}
> +			err = reset_control_deassert_shared(priv->resets[rst]);
> +			if (err) {
> +				reset_control_put(priv->resets[rst]);
> +				goto err_reset;
> +			}
> +		}
>  	}
>  
>  	if (pdata->big_endian_desc)
> @@ -300,8 +307,10 @@ err_power:
>  	if (pdata->power_off)
>  		pdata->power_off(dev);
>  err_reset:
> -	if (priv->rst)
> -		reset_control_assert(priv->rst);
> +	while (--rst >= 0) {
> +		reset_control_assert_shared(priv->resets[rst]);
> +		reset_control_put(priv->resets[rst]);
> +	}
>  err_put_clks:
>  	while (--clk >= 0)
>  		clk_put(priv->clks[clk]);
> @@ -319,15 +328,17 @@ static int ehci_platform_remove(struct platform_device *dev)
>  	struct usb_hcd *hcd = platform_get_drvdata(dev);
>  	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
>  	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
> -	int clk;
> +	int clk, rst;
>  
>  	usb_remove_hcd(hcd);
>  
>  	if (pdata->power_off)
>  		pdata->power_off(dev);
>  
> -	if (priv->rst)
> -		reset_control_assert(priv->rst);
> +	for (rst = 0; rst < EHCI_MAX_RESETS && priv->resets[rst]; rst++) {
> +		reset_control_assert_shared(priv->resets[rst]);
> +		reset_control_put(priv->resets[rst]);
> +	}
>  
>  	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
>  		clk_put(priv->clks[clk]);
> -- 
> 2.5.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v2 3/3] ohci-platform: Add support for controllers with multiple reset lines
  2015-12-11 15:42     ` Hans de Goede
@ 2015-12-14  1:10         ` Rob Herring
  -1 siblings, 0 replies; 38+ messages in thread
From: Rob Herring @ 2015-12-14  1:10 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Philipp Zabel, Josh Triplett, Rashika Kheria, Stephen Warren,
	Maxime Ripard, Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

On Fri, Dec 11, 2015 at 04:42:00PM +0100, Hans de Goede wrote:
> At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
> reset lines, the controller will not initialize while the reset for
> its companion is still asserted, which means we need to de-assert
> 2 resets for the controller to work.
> 
> Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

> ---
> Changes in v2:
> -New patch in v2 of this patch-set, to complement the identical patch for
>  the ehci-platform code
> ---
>  Documentation/devicetree/bindings/usb/usb-ohci.txt |  2 +-
>  drivers/usb/host/ohci-platform.c                   | 49 +++++++++++++---------
>  2 files changed, 30 insertions(+), 21 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
> index 19233b7..9df4569 100644
> --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
> +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
> @@ -14,7 +14,7 @@ Optional properties:
>  - clocks : a list of phandle + clock specifier pairs
>  - phys : phandle + phy specifier pair
>  - phy-names : "usb"
> -- resets : phandle + reset specifier pair
> +- resets : a list of phandle + reset specifier pairs
>  
>  Example:
>  
> diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
> index c2669f18..7d8bbc4 100644
> --- a/drivers/usb/host/ohci-platform.c
> +++ b/drivers/usb/host/ohci-platform.c
> @@ -33,11 +33,12 @@
>  
>  #define DRIVER_DESC "OHCI generic platform driver"
>  #define OHCI_MAX_CLKS 3
> +#define OHCI_MAX_RESETS 2
>  #define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
>  
>  struct ohci_platform_priv {
>  	struct clk *clks[OHCI_MAX_CLKS];
> -	struct reset_control *rst;
> +	struct reset_control *resets[OHCI_MAX_RESETS];
>  	struct phy **phys;
>  	int num_phys;
>  };
> @@ -117,7 +118,7 @@ static int ohci_platform_probe(struct platform_device *dev)
>  	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
>  	struct ohci_platform_priv *priv;
>  	struct ohci_hcd *ohci;
> -	int err, irq, phy_num, clk = 0;
> +	int err, irq, phy_num, clk = 0, rst = 0;
>  
>  	if (usb_disabled())
>  		return -ENODEV;
> @@ -195,19 +196,23 @@ static int ohci_platform_probe(struct platform_device *dev)
>  				break;
>  			}
>  		}
> -
> -	}
> -
> -	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
> -	if (IS_ERR(priv->rst)) {
> -		err = PTR_ERR(priv->rst);
> -		if (err == -EPROBE_DEFER)
> -			goto err_put_clks;
> -		priv->rst = NULL;
> -	} else {
> -		err = reset_control_deassert(priv->rst);
> -		if (err)
> -			goto err_put_clks;
> +		for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
> +			priv->resets[rst] =
> +				of_reset_control_get_by_index(dev->dev.of_node,
> +							      rst);
> +			if (IS_ERR(priv->resets[rst])) {
> +				err = PTR_ERR(priv->resets[rst]);
> +				if (err == -EPROBE_DEFER)
> +					goto err_reset;
> +				priv->resets[rst] = NULL;
> +				break;
> +			}
> +			err = reset_control_deassert_shared(priv->resets[rst]);
> +			if (err) {
> +				reset_control_put(priv->resets[rst]);
> +				goto err_reset;
> +			}
> +		}
>  	}
>  
>  	if (pdata->big_endian_desc)
> @@ -265,8 +270,10 @@ err_power:
>  	if (pdata->power_off)
>  		pdata->power_off(dev);
>  err_reset:
> -	if (priv->rst)
> -		reset_control_assert(priv->rst);
> +	while (--rst >= 0) {
> +		reset_control_assert_shared(priv->resets[rst]);
> +		reset_control_put(priv->resets[rst]);
> +	}
>  err_put_clks:
>  	while (--clk >= 0)
>  		clk_put(priv->clks[clk]);
> @@ -284,15 +291,17 @@ static int ohci_platform_remove(struct platform_device *dev)
>  	struct usb_hcd *hcd = platform_get_drvdata(dev);
>  	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
>  	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
> -	int clk;
> +	int clk, rst;
>  
>  	usb_remove_hcd(hcd);
>  
>  	if (pdata->power_off)
>  		pdata->power_off(dev);
>  
> -	if (priv->rst)
> -		reset_control_assert(priv->rst);
> +	for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++) {
> +		reset_control_assert_shared(priv->resets[rst]);
> +		reset_control_put(priv->resets[rst]);
> +	}
>  
>  	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
>  		clk_put(priv->clks[clk]);
> -- 
> 2.5.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v2 3/3] ohci-platform: Add support for controllers with multiple reset lines
@ 2015-12-14  1:10         ` Rob Herring
  0 siblings, 0 replies; 38+ messages in thread
From: Rob Herring @ 2015-12-14  1:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Dec 11, 2015 at 04:42:00PM +0100, Hans de Goede wrote:
> At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
> reset lines, the controller will not initialize while the reset for
> its companion is still asserted, which means we need to de-assert
> 2 resets for the controller to work.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Acked-by: Rob Herring <robh@kernel.org>

> ---
> Changes in v2:
> -New patch in v2 of this patch-set, to complement the identical patch for
>  the ehci-platform code
> ---
>  Documentation/devicetree/bindings/usb/usb-ohci.txt |  2 +-
>  drivers/usb/host/ohci-platform.c                   | 49 +++++++++++++---------
>  2 files changed, 30 insertions(+), 21 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
> index 19233b7..9df4569 100644
> --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
> +++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
> @@ -14,7 +14,7 @@ Optional properties:
>  - clocks : a list of phandle + clock specifier pairs
>  - phys : phandle + phy specifier pair
>  - phy-names : "usb"
> -- resets : phandle + reset specifier pair
> +- resets : a list of phandle + reset specifier pairs
>  
>  Example:
>  
> diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
> index c2669f18..7d8bbc4 100644
> --- a/drivers/usb/host/ohci-platform.c
> +++ b/drivers/usb/host/ohci-platform.c
> @@ -33,11 +33,12 @@
>  
>  #define DRIVER_DESC "OHCI generic platform driver"
>  #define OHCI_MAX_CLKS 3
> +#define OHCI_MAX_RESETS 2
>  #define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
>  
>  struct ohci_platform_priv {
>  	struct clk *clks[OHCI_MAX_CLKS];
> -	struct reset_control *rst;
> +	struct reset_control *resets[OHCI_MAX_RESETS];
>  	struct phy **phys;
>  	int num_phys;
>  };
> @@ -117,7 +118,7 @@ static int ohci_platform_probe(struct platform_device *dev)
>  	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
>  	struct ohci_platform_priv *priv;
>  	struct ohci_hcd *ohci;
> -	int err, irq, phy_num, clk = 0;
> +	int err, irq, phy_num, clk = 0, rst = 0;
>  
>  	if (usb_disabled())
>  		return -ENODEV;
> @@ -195,19 +196,23 @@ static int ohci_platform_probe(struct platform_device *dev)
>  				break;
>  			}
>  		}
> -
> -	}
> -
> -	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
> -	if (IS_ERR(priv->rst)) {
> -		err = PTR_ERR(priv->rst);
> -		if (err == -EPROBE_DEFER)
> -			goto err_put_clks;
> -		priv->rst = NULL;
> -	} else {
> -		err = reset_control_deassert(priv->rst);
> -		if (err)
> -			goto err_put_clks;
> +		for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
> +			priv->resets[rst] =
> +				of_reset_control_get_by_index(dev->dev.of_node,
> +							      rst);
> +			if (IS_ERR(priv->resets[rst])) {
> +				err = PTR_ERR(priv->resets[rst]);
> +				if (err == -EPROBE_DEFER)
> +					goto err_reset;
> +				priv->resets[rst] = NULL;
> +				break;
> +			}
> +			err = reset_control_deassert_shared(priv->resets[rst]);
> +			if (err) {
> +				reset_control_put(priv->resets[rst]);
> +				goto err_reset;
> +			}
> +		}
>  	}
>  
>  	if (pdata->big_endian_desc)
> @@ -265,8 +270,10 @@ err_power:
>  	if (pdata->power_off)
>  		pdata->power_off(dev);
>  err_reset:
> -	if (priv->rst)
> -		reset_control_assert(priv->rst);
> +	while (--rst >= 0) {
> +		reset_control_assert_shared(priv->resets[rst]);
> +		reset_control_put(priv->resets[rst]);
> +	}
>  err_put_clks:
>  	while (--clk >= 0)
>  		clk_put(priv->clks[clk]);
> @@ -284,15 +291,17 @@ static int ohci_platform_remove(struct platform_device *dev)
>  	struct usb_hcd *hcd = platform_get_drvdata(dev);
>  	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
>  	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
> -	int clk;
> +	int clk, rst;
>  
>  	usb_remove_hcd(hcd);
>  
>  	if (pdata->power_off)
>  		pdata->power_off(dev);
>  
> -	if (priv->rst)
> -		reset_control_assert(priv->rst);
> +	for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++) {
> +		reset_control_assert_shared(priv->resets[rst]);
> +		reset_control_put(priv->resets[rst]);
> +	}
>  
>  	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
>  		clk_put(priv->clks[clk]);
> -- 
> 2.5.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-11 18:21         ` Hans de Goede
@ 2015-12-14  9:12             ` Philipp Zabel
  -1 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-14  9:12 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Josh Triplett, Rashika Kheria, Stephen Warren, Maxime Ripard,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

Hi Hans,

Am Freitag, den 11.12.2015, 19:21 +0100 schrieb Hans de Goede:
[...]
> >> @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
> >>   int reset_control_deassert(struct reset_control *rstc)
> >>   {
> >
> > Maybe WARN_ON(rstc->line->refcnt > 1) ?
> 
> I assume you mean deasser_cnt ? Seems reasonable with that change.

I meant refcnt. Currently drivers sharing reset lines (refcnt > 1)
and then using the non-shared reset control functions are bound to cause
unexpected behaviour. Now we can detect this for the first time.

> >>   	if (rstc->rcdev->ops->deassert)
> >> -		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
> >> +		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
> >>
> >>   	return -ENOTSUPP;
> >>   }
> >>   EXPORT_SYMBOL_GPL(reset_control_deassert);
> >>
> >>   /**
> >> + * reset_control_assert_shared - asserts a shared reset line
> >> + * @rstc: reset controller
> >> + *
> >> + * Assert a shared reset line, this functions decreases the deassert count
> >> + * of the line by one and asserts it if, and only if, the deassert count
> >> + * reaches 0.
> >
> > "After calling this function the shared reset line may be asserted, or
> >   it may still be deasserted, as long as other users keep it so."
> 
> I take it this is to replace the text about "deassert count" ?

I thought you might append something like it. I just imagine that when
reading the documentation it might be helpful to also see the intended
effect described, especially given that a call to an _assert_ function
might leave the reset line in deasserted state, depending on the
refcount.

> >> + */
> >> +int reset_control_assert_shared(struct reset_control *rstc)
> >> +{
> >> +	if (!rstc->rcdev->ops->assert)
> >> +		return -ENOTSUPP;
> >
> > WARN_ON(rstc->line->deassert_cnt == 0)
> >
> > Actually, what to do in this case? Assume ops->assert was called, or do
> > it again to be sure? Certainly we don't want to wrap deassert_cnt, or
> > the next deassert_shared will do nothing.
> >
> >> +	rstc->line->deassert_cnt--;
> >> +	if (rstc->line->deassert_cnt)
> >
> > deassert_cnt isn't protected by any lock.
> 
> Right, good catch. I believe the best way to fix this is to change deassert_cnt
> into an atomic_t and use atomic_dec_return / atomic_int_return,

Yes, that would work.

> Downside of using an atomic_t is that doing the WARN_ON you are asking for above
> will not be race free, then, but since it is a should never happen scenario I
> guess we do not care about the check not being 100% race free. Or we can even
> just leave out the check ?

Since this is only a warning to notify driver developers we don't
support shared resets (apart from the clock-like use)

Not if we warn about refcnt instead of deassert_cnt above.

[...]
> >> + * of the line by one and deasserts the reset line (if it was not already
> >> + * deasserted).
> >
> > "After calling this function, the shared reset line is guaranteed to be
> >   deasserted."
> 
> Same question as above.

Same imprecise answer. I'd like to see the expected state after calling
this function in the description, in addition to the mechanism. This is
more important for the assert function. After calling deassert, the
reset line is deasserted, no reason to be surprised about that.

regards
Philipp

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-14  9:12             ` Philipp Zabel
  0 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-14  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Hans,

Am Freitag, den 11.12.2015, 19:21 +0100 schrieb Hans de Goede:
[...]
> >> @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
> >>   int reset_control_deassert(struct reset_control *rstc)
> >>   {
> >
> > Maybe WARN_ON(rstc->line->refcnt > 1) ?
> 
> I assume you mean deasser_cnt ? Seems reasonable with that change.

I meant refcnt. Currently drivers sharing reset lines (refcnt > 1)
and then using the non-shared reset control functions are bound to cause
unexpected behaviour. Now we can detect this for the first time.

> >>   	if (rstc->rcdev->ops->deassert)
> >> -		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
> >> +		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
> >>
> >>   	return -ENOTSUPP;
> >>   }
> >>   EXPORT_SYMBOL_GPL(reset_control_deassert);
> >>
> >>   /**
> >> + * reset_control_assert_shared - asserts a shared reset line
> >> + * @rstc: reset controller
> >> + *
> >> + * Assert a shared reset line, this functions decreases the deassert count
> >> + * of the line by one and asserts it if, and only if, the deassert count
> >> + * reaches 0.
> >
> > "After calling this function the shared reset line may be asserted, or
> >   it may still be deasserted, as long as other users keep it so."
> 
> I take it this is to replace the text about "deassert count" ?

I thought you might append something like it. I just imagine that when
reading the documentation it might be helpful to also see the intended
effect described, especially given that a call to an _assert_ function
might leave the reset line in deasserted state, depending on the
refcount.

> >> + */
> >> +int reset_control_assert_shared(struct reset_control *rstc)
> >> +{
> >> +	if (!rstc->rcdev->ops->assert)
> >> +		return -ENOTSUPP;
> >
> > WARN_ON(rstc->line->deassert_cnt == 0)
> >
> > Actually, what to do in this case? Assume ops->assert was called, or do
> > it again to be sure? Certainly we don't want to wrap deassert_cnt, or
> > the next deassert_shared will do nothing.
> >
> >> +	rstc->line->deassert_cnt--;
> >> +	if (rstc->line->deassert_cnt)
> >
> > deassert_cnt isn't protected by any lock.
> 
> Right, good catch. I believe the best way to fix this is to change deassert_cnt
> into an atomic_t and use atomic_dec_return / atomic_int_return,

Yes, that would work.

> Downside of using an atomic_t is that doing the WARN_ON you are asking for above
> will not be race free, then, but since it is a should never happen scenario I
> guess we do not care about the check not being 100% race free. Or we can even
> just leave out the check ?

Since this is only a warning to notify driver developers we don't
support shared resets (apart from the clock-like use)

Not if we warn about refcnt instead of deassert_cnt above.

[...]
> >> + * of the line by one and deasserts the reset line (if it was not already
> >> + * deasserted).
> >
> > "After calling this function, the shared reset line is guaranteed to be
> >   deasserted."
> 
> Same question as above.

Same imprecise answer. I'd like to see the expected state after calling
this function in the description, in addition to the mechanism. This is
more important for the assert function. After calling deassert, the
reset line is deasserted, no reason to be surprised about that.

regards
Philipp

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

* Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-11 15:41 ` Hans de Goede
@ 2015-12-14  9:36     ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2015-12-14  9:36 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Philipp Zabel, Josh Triplett, Rashika Kheria, Stephen Warren,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

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

Hi,

On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> diff --git a/include/linux/reset.h b/include/linux/reset.h
> index c4c097d..1cca8ce 100644
> --- a/include/linux/reset.h
> +++ b/include/linux/reset.h
> @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
>  int reset_control_assert(struct reset_control *rstc);
>  int reset_control_deassert(struct reset_control *rstc);
>  int reset_control_status(struct reset_control *rstc);
> +int reset_control_assert_shared(struct reset_control *rstc);
> +int reset_control_deassert_shared(struct reset_control *rstc);

Shouldn't that be handled in reset_control_get directly?

That would allow to share more code between the implementations, since
it would just be a flag to test in the get and not duplicate the
function definitions, and we could simply rely on the refcount to know
if we have to actually assert / deassert the device, in all the cases
(shared or not).

That would also allow us to catch easily if we're going to be able a
shared reset line or not, with the regular reset_control_get being
exclusive, and reset_control_get_shared or reset_control_get(..,
RESET_SHARED) being shared.

It would also avoid ending up with the shared variant used in every
generic driver eventually. We could just use the variant to see if we
have to use the shared get or not, and the rest of the driver is left
untouched, which is way less intrusive.

Moreover, it's also pretty much the pattern used everywhere else
(irqs, regulator, clocks, etc.), so it's going to be easier to review
as well.

Maxime

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

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-14  9:36     ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2015-12-14  9:36 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> diff --git a/include/linux/reset.h b/include/linux/reset.h
> index c4c097d..1cca8ce 100644
> --- a/include/linux/reset.h
> +++ b/include/linux/reset.h
> @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
>  int reset_control_assert(struct reset_control *rstc);
>  int reset_control_deassert(struct reset_control *rstc);
>  int reset_control_status(struct reset_control *rstc);
> +int reset_control_assert_shared(struct reset_control *rstc);
> +int reset_control_deassert_shared(struct reset_control *rstc);

Shouldn't that be handled in reset_control_get directly?

That would allow to share more code between the implementations, since
it would just be a flag to test in the get and not duplicate the
function definitions, and we could simply rely on the refcount to know
if we have to actually assert / deassert the device, in all the cases
(shared or not).

That would also allow us to catch easily if we're going to be able a
shared reset line or not, with the regular reset_control_get being
exclusive, and reset_control_get_shared or reset_control_get(..,
RESET_SHARED) being shared.

It would also avoid ending up with the shared variant used in every
generic driver eventually. We could just use the variant to see if we
have to use the shared get or not, and the rest of the driver is left
untouched, which is way less intrusive.

Moreover, it's also pretty much the pattern used everywhere else
(irqs, regulator, clocks, etc.), so it's going to be easier to review
as well.

Maxime

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

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

* Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-14  9:36     ` Maxime Ripard
@ 2015-12-14  9:50       ` Philipp Zabel
  -1 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-14  9:50 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Hans de Goede, Josh Triplett, Rashika Kheria, Stephen Warren,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
> Hi,
> 
> On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> > diff --git a/include/linux/reset.h b/include/linux/reset.h
> > index c4c097d..1cca8ce 100644
> > --- a/include/linux/reset.h
> > +++ b/include/linux/reset.h
> > @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
> >  int reset_control_assert(struct reset_control *rstc);
> >  int reset_control_deassert(struct reset_control *rstc);
> >  int reset_control_status(struct reset_control *rstc);
> > +int reset_control_assert_shared(struct reset_control *rstc);
> > +int reset_control_deassert_shared(struct reset_control *rstc);
> 
> Shouldn't that be handled in reset_control_get directly?

This is about different expectations of the caller.
A driver calling reset_control_assert expects the reset line to be
asserted after the call. A driver calling reset_control_assert_shared
just signals that it doesn't care about the state of the reset line
anymore.
We could just as well call the two new functions
reset_control_deassert_get and reset_control_deassert_put.

regards
Philipp

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-14  9:50       ` Philipp Zabel
  0 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-14  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
> Hi,
> 
> On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> > diff --git a/include/linux/reset.h b/include/linux/reset.h
> > index c4c097d..1cca8ce 100644
> > --- a/include/linux/reset.h
> > +++ b/include/linux/reset.h
> > @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
> >  int reset_control_assert(struct reset_control *rstc);
> >  int reset_control_deassert(struct reset_control *rstc);
> >  int reset_control_status(struct reset_control *rstc);
> > +int reset_control_assert_shared(struct reset_control *rstc);
> > +int reset_control_deassert_shared(struct reset_control *rstc);
> 
> Shouldn't that be handled in reset_control_get directly?

This is about different expectations of the caller.
A driver calling reset_control_assert expects the reset line to be
asserted after the call. A driver calling reset_control_assert_shared
just signals that it doesn't care about the state of the reset line
anymore.
We could just as well call the two new functions
reset_control_deassert_get and reset_control_deassert_put.

regards
Philipp

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

* Re: [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
  2015-12-11 18:28             ` Hans de Goede
@ 2015-12-14 20:11                 ` Philipp Zabel
  -1 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-14 20:11 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Josh Triplett, Rashika Kheria, Stephen Warren, Maxime Ripard,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai, Reinder de Haan

Am Freitag, den 11.12.2015, 19:28 +0100 schrieb Hans de Goede:
[...]
> >> diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> >> index a12d601..0701812 100644
> >> --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
> >> +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> >> @@ -18,7 +18,7 @@ Optional properties:
> >>    - clocks : a list of phandle + clock specifier pairs
> >>    - phys : phandle + phy specifier pair
> >>    - phy-names : "usb"
> >> - - resets : phandle + reset specifier pair
> >> + - resets : a list of phandle + reset specifier pairs
> >
> > Are there documented names for these resets?
> 
> This binding is a generic ehci controller binding, so even if
> the names are documented for the allwinner SoC we should
> not use names, just like the binding is deliberately not
> using names for the clocks either to keep it generic, so
> that we can reuse the binding + driver with many different SoCs.

I know, I'm just interested in understanding why this is necessary ...

> > Is the companion you
> > mention the Port Control?
> 
> Sort of, with USB-2, USB-1 compatibility is handled via a mux on the
> datalines (controlled by the EHCI controller Port Control) which muxes
> the lines to an USB-1 controller (typically either UHCI or OHCI) when the
> device does not connect after USB-2 highspeed handshaking.
> 
> This USB-1 controller (or controller_S_ in some case since the
> USB-1 companions may have less root-ports per controller then the EHCI
> has root-ports) is called the companion controller.
> 
> The 2 controllers are supposed to be 100% independent but on the H3
> Allwinner has done something (not documented) which requires one to
> deassert reset on both before you can talk to either one.

... so thank you for the explanation.

Acked-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

regards
Philipp

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

* [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines
@ 2015-12-14 20:11                 ` Philipp Zabel
  0 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-14 20:11 UTC (permalink / raw)
  To: linux-arm-kernel

Am Freitag, den 11.12.2015, 19:28 +0100 schrieb Hans de Goede:
[...]
> >> diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> >> index a12d601..0701812 100644
> >> --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
> >> +++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
> >> @@ -18,7 +18,7 @@ Optional properties:
> >>    - clocks : a list of phandle + clock specifier pairs
> >>    - phys : phandle + phy specifier pair
> >>    - phy-names : "usb"
> >> - - resets : phandle + reset specifier pair
> >> + - resets : a list of phandle + reset specifier pairs
> >
> > Are there documented names for these resets?
> 
> This binding is a generic ehci controller binding, so even if
> the names are documented for the allwinner SoC we should
> not use names, just like the binding is deliberately not
> using names for the clocks either to keep it generic, so
> that we can reuse the binding + driver with many different SoCs.

I know, I'm just interested in understanding why this is necessary ...

> > Is the companion you
> > mention the Port Control?
> 
> Sort of, with USB-2, USB-1 compatibility is handled via a mux on the
> datalines (controlled by the EHCI controller Port Control) which muxes
> the lines to an USB-1 controller (typically either UHCI or OHCI) when the
> device does not connect after USB-2 highspeed handshaking.
> 
> This USB-1 controller (or controller_S_ in some case since the
> USB-1 companions may have less root-ports per controller then the EHCI
> has root-ports) is called the companion controller.
> 
> The 2 controllers are supposed to be 100% independent but on the H3
> Allwinner has done something (not documented) which requires one to
> deassert reset on both before you can talk to either one.

... so thank you for the explanation.

Acked-by: Philipp Zabel <p.zabel@pengutronix.de>

regards
Philipp

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

* Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-14  9:50       ` Philipp Zabel
@ 2015-12-16 10:29           ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2015-12-16 10:29 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Hans de Goede, Josh Triplett, Rashika Kheria, Stephen Warren,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

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

On Mon, Dec 14, 2015 at 10:50:55AM +0100, Philipp Zabel wrote:
> Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
> > Hi,
> > 
> > On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> > > diff --git a/include/linux/reset.h b/include/linux/reset.h
> > > index c4c097d..1cca8ce 100644
> > > --- a/include/linux/reset.h
> > > +++ b/include/linux/reset.h
> > > @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
> > >  int reset_control_assert(struct reset_control *rstc);
> > >  int reset_control_deassert(struct reset_control *rstc);
> > >  int reset_control_status(struct reset_control *rstc);
> > > +int reset_control_assert_shared(struct reset_control *rstc);
> > > +int reset_control_deassert_shared(struct reset_control *rstc);
> > 
> > Shouldn't that be handled in reset_control_get directly?
> 
> This is about different expectations of the caller.
> A driver calling reset_control_assert expects the reset line to be
> asserted after the call.

Is that behaviour documented explicitly somewhere?

> A driver calling reset_control_assert_shared
> just signals that it doesn't care about the state of the reset line
> anymore.
> We could just as well call the two new functions
> reset_control_deassert_get and reset_control_deassert_put.

What happens if you mix them? What happens if you have several drivers
ignoring this API?

The current default API totally allows to have several drivers getting
the same reset line, and happily poking that reset line without any
way for the others to A) know they're not the single users B) let them
know their device has been reset.

And not being able to tell at the consumer level if and when our
device is going to be reset behind our back is a big issue. Because
then, we simply have to expect it can be reset at any point in time,
good luck writing a driver with that expectation.

The reset framework should make sure that the shared case is an
exception, and not the default case (and make sure that it cannot
happen in the default case). Just like for any other framework with
similar resources constraints.

Maxime

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

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

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-16 10:29           ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2015-12-16 10:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Dec 14, 2015 at 10:50:55AM +0100, Philipp Zabel wrote:
> Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
> > Hi,
> > 
> > On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> > > diff --git a/include/linux/reset.h b/include/linux/reset.h
> > > index c4c097d..1cca8ce 100644
> > > --- a/include/linux/reset.h
> > > +++ b/include/linux/reset.h
> > > @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
> > >  int reset_control_assert(struct reset_control *rstc);
> > >  int reset_control_deassert(struct reset_control *rstc);
> > >  int reset_control_status(struct reset_control *rstc);
> > > +int reset_control_assert_shared(struct reset_control *rstc);
> > > +int reset_control_deassert_shared(struct reset_control *rstc);
> > 
> > Shouldn't that be handled in reset_control_get directly?
> 
> This is about different expectations of the caller.
> A driver calling reset_control_assert expects the reset line to be
> asserted after the call.

Is that behaviour documented explicitly somewhere?

> A driver calling reset_control_assert_shared
> just signals that it doesn't care about the state of the reset line
> anymore.
> We could just as well call the two new functions
> reset_control_deassert_get and reset_control_deassert_put.

What happens if you mix them? What happens if you have several drivers
ignoring this API?

The current default API totally allows to have several drivers getting
the same reset line, and happily poking that reset line without any
way for the others to A) know they're not the single users B) let them
know their device has been reset.

And not being able to tell at the consumer level if and when our
device is going to be reset behind our back is a big issue. Because
then, we simply have to expect it can be reset at any point in time,
good luck writing a driver with that expectation.

The reset framework should make sure that the shared case is an
exception, and not the default case (and make sure that it cannot
happen in the default case). Just like for any other framework with
similar resources constraints.

Maxime

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

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

* Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-16 10:29           ` Maxime Ripard
@ 2015-12-16 11:21             ` Philipp Zabel
  -1 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-16 11:21 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Hans de Goede, Josh Triplett, Rashika Kheria, Stephen Warren,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

Hi Maxime,

Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
> On Mon, Dec 14, 2015 at 10:50:55AM +0100, Philipp Zabel wrote:
> > Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
> > > Hi,
> > > 
> > > On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> > > > diff --git a/include/linux/reset.h b/include/linux/reset.h
> > > > index c4c097d..1cca8ce 100644
> > > > --- a/include/linux/reset.h
> > > > +++ b/include/linux/reset.h
> > > > @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
> > > >  int reset_control_assert(struct reset_control *rstc);
> > > >  int reset_control_deassert(struct reset_control *rstc);
> > > >  int reset_control_status(struct reset_control *rstc);
> > > > +int reset_control_assert_shared(struct reset_control *rstc);
> > > > +int reset_control_deassert_shared(struct reset_control *rstc);
> > > 
> > > Shouldn't that be handled in reset_control_get directly?

I think I see your point now. Maybe we should add a flags parameter to
reset_control_get and/or wrap it in two versions,
reset_control_get_exclusive and reset_control_get_shared (or just add
the _shared variant). Then reset_control_get(_exclusive) could return
-EBUSY if a reset line is already in use.

> > This is about different expectations of the caller.
> > A driver calling reset_control_assert expects the reset line to be
> > asserted after the call.
> 
> Is that behaviour documented explicitly somewhere?

/**                                                                                                                                           
 * reset_control_assert - asserts the reset line
 * @rstc: reset controller
 */

Also, that expected behavior matches the function name, which I like.
So I still welcome adding new API calls for the shared/refcounting
variant.

> > A driver calling reset_control_assert_shared
> > just signals that it doesn't care about the state of the reset line
> > anymore.
> > We could just as well call the two new functions
> > reset_control_deassert_get and reset_control_deassert_put.
> 
> What happens if you mix them? What happens if you have several drivers
> ignoring this API?

The core should give useful error messages and disallow non-shared reset
calls on shared lines.

> The current default API totally allows to have several drivers getting
> the same reset line, and happily poking that reset line without any
> way for the others to A) know they're not the single users B) let them
> know their device has been reset.

That's why I'd like the WARN_ON and error return in reset_control_* when
the reset_line reference count is > 1.

> And not being able to tell at the consumer level if and when our
> device is going to be reset behind our back is a big issue. Because
> then, we simply have to expect it can be reset at any point in time,
> good luck writing a driver with that expectation.

Yes, that is unacceptable.

> The reset framework should make sure that the shared case is an
> exception, and not the default case (and make sure that it cannot
> happen in the default case). Just like for any other framework with
> similar resources constraints.

regards
Philipp

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-16 11:21             ` Philipp Zabel
  0 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2015-12-16 11:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Maxime,

Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
> On Mon, Dec 14, 2015 at 10:50:55AM +0100, Philipp Zabel wrote:
> > Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
> > > Hi,
> > > 
> > > On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> > > > diff --git a/include/linux/reset.h b/include/linux/reset.h
> > > > index c4c097d..1cca8ce 100644
> > > > --- a/include/linux/reset.h
> > > > +++ b/include/linux/reset.h
> > > > @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
> > > >  int reset_control_assert(struct reset_control *rstc);
> > > >  int reset_control_deassert(struct reset_control *rstc);
> > > >  int reset_control_status(struct reset_control *rstc);
> > > > +int reset_control_assert_shared(struct reset_control *rstc);
> > > > +int reset_control_deassert_shared(struct reset_control *rstc);
> > > 
> > > Shouldn't that be handled in reset_control_get directly?

I think I see your point now. Maybe we should add a flags parameter to
reset_control_get and/or wrap it in two versions,
reset_control_get_exclusive and reset_control_get_shared (or just add
the _shared variant). Then reset_control_get(_exclusive) could return
-EBUSY if a reset line is already in use.

> > This is about different expectations of the caller.
> > A driver calling reset_control_assert expects the reset line to be
> > asserted after the call.
> 
> Is that behaviour documented explicitly somewhere?

/**                                                                                                                                           
 * reset_control_assert - asserts the reset line
 * @rstc: reset controller
 */

Also, that expected behavior matches the function name, which I like.
So I still welcome adding new API calls for the shared/refcounting
variant.

> > A driver calling reset_control_assert_shared
> > just signals that it doesn't care about the state of the reset line
> > anymore.
> > We could just as well call the two new functions
> > reset_control_deassert_get and reset_control_deassert_put.
> 
> What happens if you mix them? What happens if you have several drivers
> ignoring this API?

The core should give useful error messages and disallow non-shared reset
calls on shared lines.

> The current default API totally allows to have several drivers getting
> the same reset line, and happily poking that reset line without any
> way for the others to A) know they're not the single users B) let them
> know their device has been reset.

That's why I'd like the WARN_ON and error return in reset_control_* when
the reset_line reference count is > 1.

> And not being able to tell at the consumer level if and when our
> device is going to be reset behind our back is a big issue. Because
> then, we simply have to expect it can be reset at any point in time,
> good luck writing a driver with that expectation.

Yes, that is unacceptable.

> The reset framework should make sure that the shared case is an
> exception, and not the default case (and make sure that it cannot
> happen in the default case). Just like for any other framework with
> similar resources constraints.

regards
Philipp

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

* Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-16 11:21             ` Philipp Zabel
@ 2015-12-18 11:08                 ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2015-12-18 11:08 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Hans de Goede, Josh Triplett, Rashika Kheria, Stephen Warren,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

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

On Wed, Dec 16, 2015 at 12:21:48PM +0100, Philipp Zabel wrote:
> Hi Maxime,
> 
> Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
> > On Mon, Dec 14, 2015 at 10:50:55AM +0100, Philipp Zabel wrote:
> > > Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
> > > > Hi,
> > > > 
> > > > On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> > > > > diff --git a/include/linux/reset.h b/include/linux/reset.h
> > > > > index c4c097d..1cca8ce 100644
> > > > > --- a/include/linux/reset.h
> > > > > +++ b/include/linux/reset.h
> > > > > @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
> > > > >  int reset_control_assert(struct reset_control *rstc);
> > > > >  int reset_control_deassert(struct reset_control *rstc);
> > > > >  int reset_control_status(struct reset_control *rstc);
> > > > > +int reset_control_assert_shared(struct reset_control *rstc);
> > > > > +int reset_control_deassert_shared(struct reset_control *rstc);
> > > > 
> > > > Shouldn't that be handled in reset_control_get directly?
> 
> I think I see your point now. Maybe we should add a flags parameter to
> reset_control_get and/or wrap it in two versions,
> reset_control_get_exclusive and reset_control_get_shared (or just add
> the _shared variant). Then reset_control_get(_exclusive) could return
> -EBUSY if a reset line is already in use.

I guess the current assumption was that reset_control_get was
exclusive.

So we could have something like:

reset_control_get (..) {
  return __reset_control_get(.., 0);
}

reset_control_get_shared (..) {
  return __reset_control_get(.., RESET_SHARED);
}

And all the logic shared between the two, without exposing any flag
(that would change the prototype and require to fix every callers).

> 
> > > This is about different expectations of the caller.
> > > A driver calling reset_control_assert expects the reset line to be
> > > asserted after the call.
> > 
> > Is that behaviour documented explicitly somewhere?
> 
> /**                                                                                                                                           
>  * reset_control_assert - asserts the reset line
>  * @rstc: reset controller
>  */

Yeah, but it's not said when it would happen, or if it happens
synchronously.

> Also, that expected behavior matches the function name, which I like.
> So I still welcome adding new API calls for the shared/refcounting
> variant.
> 
> > > A driver calling reset_control_assert_shared
> > > just signals that it doesn't care about the state of the reset line
> > > anymore.
> > > We could just as well call the two new functions
> > > reset_control_deassert_get and reset_control_deassert_put.
> > 
> > What happens if you mix them? What happens if you have several drivers
> > ignoring this API?
> 
> The core should give useful error messages and disallow non-shared reset
> calls on shared lines.

I guess we could also have something like this:

  * The driver gets the reference to the reset line using
    reset_control_get or its shared variant.

    - If you call reset_control_get on a free line, it succeeds, and
      marks the line in exclusive use.
    - If you call reset_control_get on a busy line, it fails with
      EBUSY

    - If you call the shared variant on a free line, it succeeds
    - If you call the shared variant on a busy exclusive line, it
      fails with EBUSY
    - If you call the shared variant on a busy !exclusive line, it
      succeeds.

  * The customer driver can then call reset_control_assert / deassert:

    - If the reset line is in exclusive use, the assertion happens
      right away, it succeeds and returns 0.

    - If the reset line is in a !exclusive use, but with a single
      user, the assertion happens right away, it succeeds and returns
      0.

    - If the reset line is in a !exclusive use with more than 1 user,
      the refcount is modified and an error is returned to notify that
      it didn't happen.

What do you think? That would work fine in both the case where you
care about the fact that the device has really been asserted (to
recover from an error for example) and the one when you don't really
care and you just want to give away your reset line (in a remove for
example).

I'd really like to avoid having shared variants of assert and
de-assert, since it will only spread out and end up being used in
drivers where most users don't have a shared reset line.

And if we want to avoid that, we'll end up in something like

if (struct->shared_reset)
	reset_control_assert_shared
else
	reset_control_assert

around *all* the calls in your driver.

Maxime

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

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

* [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-18 11:08                 ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2015-12-18 11:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Dec 16, 2015 at 12:21:48PM +0100, Philipp Zabel wrote:
> Hi Maxime,
> 
> Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
> > On Mon, Dec 14, 2015 at 10:50:55AM +0100, Philipp Zabel wrote:
> > > Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
> > > > Hi,
> > > > 
> > > > On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
> > > > > diff --git a/include/linux/reset.h b/include/linux/reset.h
> > > > > index c4c097d..1cca8ce 100644
> > > > > --- a/include/linux/reset.h
> > > > > +++ b/include/linux/reset.h
> > > > > @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
> > > > >  int reset_control_assert(struct reset_control *rstc);
> > > > >  int reset_control_deassert(struct reset_control *rstc);
> > > > >  int reset_control_status(struct reset_control *rstc);
> > > > > +int reset_control_assert_shared(struct reset_control *rstc);
> > > > > +int reset_control_deassert_shared(struct reset_control *rstc);
> > > > 
> > > > Shouldn't that be handled in reset_control_get directly?
> 
> I think I see your point now. Maybe we should add a flags parameter to
> reset_control_get and/or wrap it in two versions,
> reset_control_get_exclusive and reset_control_get_shared (or just add
> the _shared variant). Then reset_control_get(_exclusive) could return
> -EBUSY if a reset line is already in use.

I guess the current assumption was that reset_control_get was
exclusive.

So we could have something like:

reset_control_get (..) {
  return __reset_control_get(.., 0);
}

reset_control_get_shared (..) {
  return __reset_control_get(.., RESET_SHARED);
}

And all the logic shared between the two, without exposing any flag
(that would change the prototype and require to fix every callers).

> 
> > > This is about different expectations of the caller.
> > > A driver calling reset_control_assert expects the reset line to be
> > > asserted after the call.
> > 
> > Is that behaviour documented explicitly somewhere?
> 
> /**                                                                                                                                           
>  * reset_control_assert - asserts the reset line
>  * @rstc: reset controller
>  */

Yeah, but it's not said when it would happen, or if it happens
synchronously.

> Also, that expected behavior matches the function name, which I like.
> So I still welcome adding new API calls for the shared/refcounting
> variant.
> 
> > > A driver calling reset_control_assert_shared
> > > just signals that it doesn't care about the state of the reset line
> > > anymore.
> > > We could just as well call the two new functions
> > > reset_control_deassert_get and reset_control_deassert_put.
> > 
> > What happens if you mix them? What happens if you have several drivers
> > ignoring this API?
> 
> The core should give useful error messages and disallow non-shared reset
> calls on shared lines.

I guess we could also have something like this:

  * The driver gets the reference to the reset line using
    reset_control_get or its shared variant.

    - If you call reset_control_get on a free line, it succeeds, and
      marks the line in exclusive use.
    - If you call reset_control_get on a busy line, it fails with
      EBUSY

    - If you call the shared variant on a free line, it succeeds
    - If you call the shared variant on a busy exclusive line, it
      fails with EBUSY
    - If you call the shared variant on a busy !exclusive line, it
      succeeds.

  * The customer driver can then call reset_control_assert / deassert:

    - If the reset line is in exclusive use, the assertion happens
      right away, it succeeds and returns 0.

    - If the reset line is in a !exclusive use, but with a single
      user, the assertion happens right away, it succeeds and returns
      0.

    - If the reset line is in a !exclusive use with more than 1 user,
      the refcount is modified and an error is returned to notify that
      it didn't happen.

What do you think? That would work fine in both the case where you
care about the fact that the device has really been asserted (to
recover from an error for example) and the one when you don't really
care and you just want to give away your reset line (in a remove for
example).

I'd really like to avoid having shared variants of assert and
de-assert, since it will only spread out and end up being used in
drivers where most users don't have a shared reset line.

And if we want to avoid that, we'll end up in something like

if (struct->shared_reset)
	reset_control_assert_shared
else
	reset_control_assert

around *all* the calls in your driver.

Maxime

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

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

* Re: Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-18 11:08                 ` Maxime Ripard
@ 2015-12-19 10:55                   ` Hans de Goede
  -1 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-19 10:55 UTC (permalink / raw)
  To: Maxime Ripard, Philipp Zabel
  Cc: Josh Triplett, Rashika Kheria, Stephen Warren,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

Hi,

On 18-12-15 12:08, Maxime Ripard wrote:
> On Wed, Dec 16, 2015 at 12:21:48PM +0100, Philipp Zabel wrote:
>> Hi Maxime,
>>
>> Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
>>> On Mon, Dec 14, 2015 at 10:50:55AM +0100, Philipp Zabel wrote:
>>>> Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
>>>>> Hi,
>>>>>
>>>>> On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
>>>>>> diff --git a/include/linux/reset.h b/include/linux/reset.h
>>>>>> index c4c097d..1cca8ce 100644
>>>>>> --- a/include/linux/reset.h
>>>>>> +++ b/include/linux/reset.h
>>>>>> @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
>>>>>>   int reset_control_assert(struct reset_control *rstc);
>>>>>>   int reset_control_deassert(struct reset_control *rstc);
>>>>>>   int reset_control_status(struct reset_control *rstc);
>>>>>> +int reset_control_assert_shared(struct reset_control *rstc);
>>>>>> +int reset_control_deassert_shared(struct reset_control *rstc);
>>>>>
>>>>> Shouldn't that be handled in reset_control_get directly?
>>
>> I think I see your point now. Maybe we should add a flags parameter to
>> reset_control_get and/or wrap it in two versions,
>> reset_control_get_exclusive and reset_control_get_shared (or just add
>> the _shared variant). Then reset_control_get(_exclusive) could return
>> -EBUSY if a reset line is already in use.
>
> I guess the current assumption was that reset_control_get was
> exclusive.
>
> So we could have something like:
>
> reset_control_get (..) {
>    return __reset_control_get(.., 0);
> }
>
> reset_control_get_shared (..) {
>    return __reset_control_get(.., RESET_SHARED);
> }
>
> And all the logic shared between the two, without exposing any flag
> (that would change the prototype and require to fix every callers).
>
>>
>>>> This is about different expectations of the caller.
>>>> A driver calling reset_control_assert expects the reset line to be
>>>> asserted after the call.
>>>
>>> Is that behaviour documented explicitly somewhere?
>>
>> /**
>>   * reset_control_assert - asserts the reset line
>>   * @rstc: reset controller
>>   */
>
> Yeah, but it's not said when it would happen, or if it happens
> synchronously.
>
>> Also, that expected behavior matches the function name, which I like.
>> So I still welcome adding new API calls for the shared/refcounting
>> variant.
>>
>>>> A driver calling reset_control_assert_shared
>>>> just signals that it doesn't care about the state of the reset line
>>>> anymore.
>>>> We could just as well call the two new functions
>>>> reset_control_deassert_get and reset_control_deassert_put.
>>>
>>> What happens if you mix them? What happens if you have several drivers
>>> ignoring this API?
>>
>> The core should give useful error messages and disallow non-shared reset
>> calls on shared lines.
>
> I guess we could also have something like this:
>
>    * The driver gets the reference to the reset line using
>      reset_control_get or its shared variant.
>
>      - If you call reset_control_get on a free line, it succeeds, and
>        marks the line in exclusive use.
>      - If you call reset_control_get on a busy line, it fails with
>        EBUSY
>
>      - If you call the shared variant on a free line, it succeeds
>      - If you call the shared variant on a busy exclusive line, it
>        fails with EBUSY
>      - If you call the shared variant on a busy !exclusive line, it
>        succeeds.
>
>    * The customer driver can then call reset_control_assert / deassert:
>
>      - If the reset line is in exclusive use, the assertion happens
>        right away, it succeeds and returns 0.
>
>      - If the reset line is in a !exclusive use, but with a single
>        user, the assertion happens right away, it succeeds and returns
>        0.

Ack for all of the above, this is what I had in mind at first, but I started
with a more lightweight version as I'm lazy :)  If Philipp likes this
suggestion I can rework my patch-set into this.

>      - If the reset line is in a !exclusive use with more than 1 user,
>        the refcount is modified and an error is returned to notify that
>        it didn't happen.

Also ack, except for returning the error, if a driver has used
reset_control_get_shared, it should simply be aware that doing an assert
might not necessarily actually assert the line, just like doing a clk-disable
does not really necessary disable the clock, etc. If a driver is not prepared
to deal with this, it should simply not use reset_control_get_shared.

I see returning an error if the assert did not happen due to other users /
deassert_count != 0 as inconsistent compared to how clks, regulators and phys
handle this, these all simply return success in this case.

Regards,

Hans

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

* [linux-sunxi] Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2015-12-19 10:55                   ` Hans de Goede
  0 siblings, 0 replies; 38+ messages in thread
From: Hans de Goede @ 2015-12-19 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 18-12-15 12:08, Maxime Ripard wrote:
> On Wed, Dec 16, 2015 at 12:21:48PM +0100, Philipp Zabel wrote:
>> Hi Maxime,
>>
>> Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
>>> On Mon, Dec 14, 2015 at 10:50:55AM +0100, Philipp Zabel wrote:
>>>> Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
>>>>> Hi,
>>>>>
>>>>> On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
>>>>>> diff --git a/include/linux/reset.h b/include/linux/reset.h
>>>>>> index c4c097d..1cca8ce 100644
>>>>>> --- a/include/linux/reset.h
>>>>>> +++ b/include/linux/reset.h
>>>>>> @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
>>>>>>   int reset_control_assert(struct reset_control *rstc);
>>>>>>   int reset_control_deassert(struct reset_control *rstc);
>>>>>>   int reset_control_status(struct reset_control *rstc);
>>>>>> +int reset_control_assert_shared(struct reset_control *rstc);
>>>>>> +int reset_control_deassert_shared(struct reset_control *rstc);
>>>>>
>>>>> Shouldn't that be handled in reset_control_get directly?
>>
>> I think I see your point now. Maybe we should add a flags parameter to
>> reset_control_get and/or wrap it in two versions,
>> reset_control_get_exclusive and reset_control_get_shared (or just add
>> the _shared variant). Then reset_control_get(_exclusive) could return
>> -EBUSY if a reset line is already in use.
>
> I guess the current assumption was that reset_control_get was
> exclusive.
>
> So we could have something like:
>
> reset_control_get (..) {
>    return __reset_control_get(.., 0);
> }
>
> reset_control_get_shared (..) {
>    return __reset_control_get(.., RESET_SHARED);
> }
>
> And all the logic shared between the two, without exposing any flag
> (that would change the prototype and require to fix every callers).
>
>>
>>>> This is about different expectations of the caller.
>>>> A driver calling reset_control_assert expects the reset line to be
>>>> asserted after the call.
>>>
>>> Is that behaviour documented explicitly somewhere?
>>
>> /**
>>   * reset_control_assert - asserts the reset line
>>   * @rstc: reset controller
>>   */
>
> Yeah, but it's not said when it would happen, or if it happens
> synchronously.
>
>> Also, that expected behavior matches the function name, which I like.
>> So I still welcome adding new API calls for the shared/refcounting
>> variant.
>>
>>>> A driver calling reset_control_assert_shared
>>>> just signals that it doesn't care about the state of the reset line
>>>> anymore.
>>>> We could just as well call the two new functions
>>>> reset_control_deassert_get and reset_control_deassert_put.
>>>
>>> What happens if you mix them? What happens if you have several drivers
>>> ignoring this API?
>>
>> The core should give useful error messages and disallow non-shared reset
>> calls on shared lines.
>
> I guess we could also have something like this:
>
>    * The driver gets the reference to the reset line using
>      reset_control_get or its shared variant.
>
>      - If you call reset_control_get on a free line, it succeeds, and
>        marks the line in exclusive use.
>      - If you call reset_control_get on a busy line, it fails with
>        EBUSY
>
>      - If you call the shared variant on a free line, it succeeds
>      - If you call the shared variant on a busy exclusive line, it
>        fails with EBUSY
>      - If you call the shared variant on a busy !exclusive line, it
>        succeeds.
>
>    * The customer driver can then call reset_control_assert / deassert:
>
>      - If the reset line is in exclusive use, the assertion happens
>        right away, it succeeds and returns 0.
>
>      - If the reset line is in a !exclusive use, but with a single
>        user, the assertion happens right away, it succeeds and returns
>        0.

Ack for all of the above, this is what I had in mind at first, but I started
with a more lightweight version as I'm lazy :)  If Philipp likes this
suggestion I can rework my patch-set into this.

>      - If the reset line is in a !exclusive use with more than 1 user,
>        the refcount is modified and an error is returned to notify that
>        it didn't happen.

Also ack, except for returning the error, if a driver has used
reset_control_get_shared, it should simply be aware that doing an assert
might not necessarily actually assert the line, just like doing a clk-disable
does not really necessary disable the clock, etc. If a driver is not prepared
to deal with this, it should simply not use reset_control_get_shared.

I see returning an error if the assert did not happen due to other users /
deassert_count != 0 as inconsistent compared to how clks, regulators and phys
handle this, these all simply return success in this case.

Regards,

Hans

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

* Re: Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2015-12-19 10:55                   ` [linux-sunxi] " Hans de Goede
@ 2016-01-04 20:39                       ` Philipp Zabel
  -1 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2016-01-04 20:39 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Maxime Ripard, Josh Triplett, Rashika Kheria, Stephen Warren,
	Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Roger Quadros, Alan Stern,
	Tony Prisk, Florian Fainelli, linux-usb, devicetree,
	Chen-Yu Tsai

Am Samstag, den 19.12.2015, 11:55 +0100 schrieb Hans de Goede:
> On 18-12-15 12:08, Maxime Ripard wrote:
[...]
> > I guess we could also have something like this:
> >
> >    * The driver gets the reference to the reset line using
> >      reset_control_get or its shared variant.
> >
> >      - If you call reset_control_get on a free line, it succeeds, and
> >        marks the line in exclusive use.
> >      - If you call reset_control_get on a busy line, it fails with
> >        EBUSY
> >
> >      - If you call the shared variant on a free line, it succeeds
> >      - If you call the shared variant on a busy exclusive line, it
> >        fails with EBUSY
> >      - If you call the shared variant on a busy !exclusive line, it
> >        succeeds.
>>
> >    * The customer driver can then call reset_control_assert / deassert:
> >
> >      - If the reset line is in exclusive use, the assertion happens
> >        right away, it succeeds and returns 0.
> >
> >      - If the reset line is in a !exclusive use, but with a single
> >        user, the assertion happens right away, it succeeds and returns
> >        0.
>
> Ack for all of the above, this is what I had in mind at first, but I started
> with a more lightweight version as I'm lazy :)  If Philipp likes this
> suggestion I can rework my patch-set into this.

Seconded, this all sounds good to me.

> >      - If the reset line is in a !exclusive use with more than 1 user,
> >        the refcount is modified and an error is returned to notify that
> >        it didn't happen.
>
> Also ack, except for returning the error, if a driver has used
> reset_control_get_shared, it should simply be aware that doing an assert
> might not necessarily actually assert the line, just like doing a clk-disable
> does not really necessary disable the clock, etc. If a driver is not prepared
> to deal with this, it should simply not use reset_control_get_shared.
>
> I see returning an error if the assert did not happen due to other users /
> deassert_count != 0 as inconsistent compared to how clks, regulators and phys
> handle this, these all simply return success in this case.

I wouldn't want drivers to have to differentiate between relevant and
irrelevant error codes, so in the clock-like refcounting use case
reset_assert should not return an error if it just correctly decremented
the refcount. I'd still prefer to have separate API for the counted
must_deassert/may_assert vs the exclusive must_assert/must_deassert use
cases, but I just can't think of a good name.

regards
Philipp

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

* [linux-sunxi] Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2016-01-04 20:39                       ` Philipp Zabel
  0 siblings, 0 replies; 38+ messages in thread
From: Philipp Zabel @ 2016-01-04 20:39 UTC (permalink / raw)
  To: linux-arm-kernel

Am Samstag, den 19.12.2015, 11:55 +0100 schrieb Hans de Goede:
> On 18-12-15 12:08, Maxime Ripard wrote:
[...]
> > I guess we could also have something like this:
> >
> >    * The driver gets the reference to the reset line using
> >      reset_control_get or its shared variant.
> >
> >      - If you call reset_control_get on a free line, it succeeds, and
> >        marks the line in exclusive use.
> >      - If you call reset_control_get on a busy line, it fails with
> >        EBUSY
> >
> >      - If you call the shared variant on a free line, it succeeds
> >      - If you call the shared variant on a busy exclusive line, it
> >        fails with EBUSY
> >      - If you call the shared variant on a busy !exclusive line, it
> >        succeeds.
>>
> >    * The customer driver can then call reset_control_assert / deassert:
> >
> >      - If the reset line is in exclusive use, the assertion happens
> >        right away, it succeeds and returns 0.
> >
> >      - If the reset line is in a !exclusive use, but with a single
> >        user, the assertion happens right away, it succeeds and returns
> >        0.
>
> Ack for all of the above, this is what I had in mind at first, but I started
> with a more lightweight version as I'm lazy :)  If Philipp likes this
> suggestion I can rework my patch-set into this.

Seconded, this all sounds good to me.

> >      - If the reset line is in a !exclusive use with more than 1 user,
> >        the refcount is modified and an error is returned to notify that
> >        it didn't happen.
>
> Also ack, except for returning the error, if a driver has used
> reset_control_get_shared, it should simply be aware that doing an assert
> might not necessarily actually assert the line, just like doing a clk-disable
> does not really necessary disable the clock, etc. If a driver is not prepared
> to deal with this, it should simply not use reset_control_get_shared.
>
> I see returning an error if the assert did not happen due to other users /
> deassert_count != 0 as inconsistent compared to how clks, regulators and phys
> handle this, these all simply return success in this case.

I wouldn't want drivers to have to differentiate between relevant and
irrelevant error codes, so in the clock-like refcounting use case
reset_assert should not return an error if it just correctly decremented
the refcount. I'd still prefer to have separate API for the counted
must_deassert/may_assert vs the exclusive must_assert/must_deassert use
cases, but I just can't think of a good name.

regards
Philipp

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

* Re: Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
  2016-01-04 20:39                       ` [linux-sunxi] " Philipp Zabel
@ 2016-01-04 21:16                           ` Michal Suchanek
  -1 siblings, 0 replies; 38+ messages in thread
From: Michal Suchanek @ 2016-01-04 21:16 UTC (permalink / raw)
  To: p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ
  Cc: Hans de Goede, Maxime Ripard, Josh Triplett, Rashika Kheria,
	Stephen Warren, Greg Kroah-Hartman,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, linux-sunxi,
	Roger Quadros, Alan Stern, Tony Prisk, Florian Fainelli,
	linux-usb, devicetree, Chen-Yu Tsai

On 4 January 2016 at 21:39, Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> wrote:
> Am Samstag, den 19.12.2015, 11:55 +0100 schrieb Hans de Goede:
>> On 18-12-15 12:08, Maxime Ripard wrote:

>> >      - If the reset line is in a !exclusive use with more than 1 user,
>> >        the refcount is modified and an error is returned to notify that
>> >        it didn't happen.
>>
>> Also ack, except for returning the error, if a driver has used
>> reset_control_get_shared, it should simply be aware that doing an assert
>> might not necessarily actually assert the line, just like doing a clk-disable
>> does not really necessary disable the clock, etc. If a driver is not prepared
>> to deal with this, it should simply not use reset_control_get_shared.
>>
>> I see returning an error if the assert did not happen due to other users /
>> deassert_count != 0 as inconsistent compared to how clks, regulators and phys
>> handle this, these all simply return success in this case.
>
> I wouldn't want drivers to have to differentiate between relevant and
> irrelevant error codes, so in the clock-like refcounting use case
> reset_assert should not return an error if it just correctly decremented
> the refcount. I'd still prefer to have separate API for the counted
> must_deassert/may_assert vs the exclusive must_assert/must_deassert use
> cases, but I just can't think of a good name.
>

Maybe something along the lines of assert_now or assert_sync. It
should be possible to call on shared line and then get an error when
the operation is blocked by other user.

The driver may not really care. Depending on the hardware the line can
be shared on one device and exclusive on another. The driver may just
let the line go when the device is powered off. And it may require a
reset cycle when it detects the device is hosed and return an error
when the reset fails for whatever reason.

Thanks

Michal

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

* [linux-sunxi] Re: [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants
@ 2016-01-04 21:16                           ` Michal Suchanek
  0 siblings, 0 replies; 38+ messages in thread
From: Michal Suchanek @ 2016-01-04 21:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 4 January 2016 at 21:39, Philipp Zabel <p.zabel@pengutronix.de> wrote:
> Am Samstag, den 19.12.2015, 11:55 +0100 schrieb Hans de Goede:
>> On 18-12-15 12:08, Maxime Ripard wrote:

>> >      - If the reset line is in a !exclusive use with more than 1 user,
>> >        the refcount is modified and an error is returned to notify that
>> >        it didn't happen.
>>
>> Also ack, except for returning the error, if a driver has used
>> reset_control_get_shared, it should simply be aware that doing an assert
>> might not necessarily actually assert the line, just like doing a clk-disable
>> does not really necessary disable the clock, etc. If a driver is not prepared
>> to deal with this, it should simply not use reset_control_get_shared.
>>
>> I see returning an error if the assert did not happen due to other users /
>> deassert_count != 0 as inconsistent compared to how clks, regulators and phys
>> handle this, these all simply return success in this case.
>
> I wouldn't want drivers to have to differentiate between relevant and
> irrelevant error codes, so in the clock-like refcounting use case
> reset_assert should not return an error if it just correctly decremented
> the refcount. I'd still prefer to have separate API for the counted
> must_deassert/may_assert vs the exclusive must_assert/must_deassert use
> cases, but I just can't think of a good name.
>

Maybe something along the lines of assert_now or assert_sync. It
should be possible to call on shared line and then get an error when
the operation is blocked by other user.

The driver may not really care. Depending on the hardware the line can
be shared on one device and exclusive on another. The driver may just
let the line go when the device is powered off. And it may require a
reset cycle when it detects the device is hosed and return an error
when the reset fails for whatever reason.

Thanks

Michal

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

end of thread, other threads:[~2016-01-04 21:16 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-11 15:41 [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants Hans de Goede
2015-12-11 15:41 ` Hans de Goede
     [not found] ` <1449848520-27379-1-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2015-12-11 15:41   ` [PATCH v2 2/3] ehci-platform: Add support for controllers with multiple reset lines Hans de Goede
2015-12-11 15:41     ` Hans de Goede
     [not found]     ` <1449848520-27379-2-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2015-12-11 17:13       ` Philipp Zabel
2015-12-11 17:13         ` Philipp Zabel
     [not found]         ` <1449853984.3419.52.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2015-12-11 18:28           ` Hans de Goede
2015-12-11 18:28             ` Hans de Goede
     [not found]             ` <566B15B7.40703-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2015-12-14 20:11               ` Philipp Zabel
2015-12-14 20:11                 ` Philipp Zabel
2015-12-14  1:09       ` Rob Herring
2015-12-14  1:09         ` Rob Herring
2015-12-11 15:42   ` [PATCH v2 3/3] ohci-platform: " Hans de Goede
2015-12-11 15:42     ` Hans de Goede
     [not found]     ` <1449848520-27379-3-git-send-email-hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2015-12-14  1:10       ` Rob Herring
2015-12-14  1:10         ` Rob Herring
2015-12-11 17:10   ` [PATCH v2 1/3] reset: Add shared reset_control_[de]assert variants Philipp Zabel
2015-12-11 17:10     ` Philipp Zabel
     [not found]     ` <1449853825.3419.50.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2015-12-11 18:21       ` Hans de Goede
2015-12-11 18:21         ` Hans de Goede
     [not found]         ` <566B1424.2060700-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2015-12-14  9:12           ` Philipp Zabel
2015-12-14  9:12             ` Philipp Zabel
2015-12-14  9:36   ` Maxime Ripard
2015-12-14  9:36     ` Maxime Ripard
2015-12-14  9:50     ` Philipp Zabel
2015-12-14  9:50       ` Philipp Zabel
     [not found]       ` <1450086655.3407.23.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2015-12-16 10:29         ` Maxime Ripard
2015-12-16 10:29           ` Maxime Ripard
2015-12-16 11:21           ` Philipp Zabel
2015-12-16 11:21             ` Philipp Zabel
     [not found]             ` <1450264908.3421.36.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2015-12-18 11:08               ` Maxime Ripard
2015-12-18 11:08                 ` Maxime Ripard
2015-12-19 10:55                 ` Hans de Goede
2015-12-19 10:55                   ` [linux-sunxi] " Hans de Goede
     [not found]                   ` <5675378F.5010904-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2016-01-04 20:39                     ` Philipp Zabel
2016-01-04 20:39                       ` [linux-sunxi] " Philipp Zabel
     [not found]                       ` <1451939999.3884.89.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2016-01-04 21:16                         ` Michal Suchanek
2016-01-04 21:16                           ` [linux-sunxi] " Michal Suchanek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.