reset: Add shared reset_control_[de]assert variants
Subsystems (5)
PATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
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.
---
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(-)
drivers/reset/core.c +112 -9
@@ -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); }
include/linux/reset-controller.h +2 -0
@@ -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,
include/linux/reset.h +2 -0
@@ -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);
Signature · 1 line
2.5.0
PATCH v2 2/3 ehci-platform: Add support for controllers with multiple reset lines
From: Reinder de Haan <[email protected]>
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.
---
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(-)
Documentation/devicetree/bindings/usb/usb-ehci.txt +1 -1
@@ -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 {
drivers/usb/host/ehci-platform.c +29 -18
88 lines not on this page · raw message
Signature · 1 line
2.5.0
Philipp Zabel
maintainerPATCH v2 2/3 ehci-platform: Add support for controllers with multiple reset lines
Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
Quoted 22 lines
From: Reinder de Haan <[email protected]>
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 <[email protected]>Signed-off-by Hans de Goede <[email protected]>---
Changes in v2:(quoted diff) +0
-2-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(-)Documentation/devicetree/bindings/usb/usb-ehci.txt +0
-0
Documentation/devicetree/bindings/usb/usb-ehci.txt Optional properties: · line 21
Quoted 5 lines
Documentation/devicetree/bindings/usb/usb-ehci.txt +1
-1@@ -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
PATCH v2 2/3 ehci-platform: Add support for controllers with multiple reset lines
Hi,
Quoted 18 lines · Philipp Zabel
Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
Quoted 17 lines
From: Reinder de Haan <[email protected]>
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 <[email protected]>Signed-off-by Hans de Goede <[email protected]>---
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(-)
Quoted 12 lines
Documentation/devicetree/bindings/usb/usb-ehci.txt Optional properties: · line 21
Quoted 10 lines
Documentation/devicetree/bindings/usb/usb-ehci.txt +1
-1@@ -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 pairsAre 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.
Quoted 2 lines
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
Philipp Zabel
maintainerPATCH v2 2/3 ehci-platform: Add support for controllers with multiple reset lines
Am Freitag, den 11.12.2015, 19:28 +0100 schrieb Hans de Goede:
[...]
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
Documentation/devicetree/bindings/usb/usb-ehci.txt +0
-0Quoted 8 lines
Documentation/devicetree/bindings/usb/usb-ehci.txt Optional properties: · line 21
Quoted 6 lines
Documentation/devicetree/bindings/usb/usb-ehci.txt +1
-1@@ -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 pairsAre there documented names for these resets?
Quoted 5 lines
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 ...
Quoted 8 lines
Quoted 2 lines
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.
Quoted 7 lines
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.
regards
Philipp
Rob Herring
maintainerPATCH v2 2/3 ehci-platform: Add support for controllers with multiple reset lines
In reply to Hans de GoedeQuoted 9 lines · Hans de Goede
From: Reinder de Haan <[email protected]>
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 <[email protected]>Signed-off-by Hans de Goede <[email protected]>
Quoted 125 lines
---
Changes in v2:(quoted diff) +0
-2-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(-)Documentation/devicetree/bindings/usb/usb-ehci.txt +1
-1@@ -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 {drivers/usb/host/ehci-platform.c +29
-18@@ -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]);Signature · 6 lines
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
PATCH v2 3/3 ohci-platform: Add support for controllers with multiple reset lines
In reply to Hans de GoedeAt 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.
---
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(-)
Documentation/devicetree/bindings/usb/usb-ohci.txt +1 -1
@@ -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:
drivers/usb/host/ohci-platform.c +29 -20
89 lines not on this page · raw message
Signature · 1 line
2.5.0
Rob Herring
maintainerPATCH v2 3/3 ohci-platform: Add support for controllers with multiple reset lines
Quoted 6 lines · 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 <[email protected]>
Quoted 127 lines
---
Changes in v2:(quoted diff) +0
-2-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(-)Documentation/devicetree/bindings/usb/usb-ohci.txt +1
-1@@ -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:drivers/usb/host/ohci-platform.c +29
-20@@ -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]);Signature · 6 lines
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
Philipp Zabel
maintainerPATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
In reply to Hans de GoedeHi Hans,
thanks for moving this forward.
Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
Quoted 29 lines
Add
reset_control_deassert_shared/reset_control_assert_sharedfunctions 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_sharedhave been called and keep the line deasserted as long as deassert has been called more times than assert.Signed-off-by Hans de Goede <[email protected]>---
Changes in v2:(quoted diff) +0
-2-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(-)drivers/reset/core.c +2
-0@@ -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
drivers/reset/core.c static DEFINE_MUTEX(reset_controller_list_mutex); · line 36
Quoted 10 lines
drivers/reset/core.c +10
-0+* @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.
Quoted 16 lines
drivers/reset/core.c +3
-3+/** * 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; };/**
[...]
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 135
Quoted 3 lines
drivers/reset/core.c +0
-0@@ -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) ?
Quoted 5 lines
drivers/reset/core.c +1
-1if (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 ;
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 149
Quoted 10 lines
drivers/reset/core.c +6
-0}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."
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 154
Quoted 5 lines
drivers/reset/core.c +5
-0+*/ +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.
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 157
Quoted 2 lines
drivers/reset/core.c +2
-0+ rstc->line->deassert_cnt--; +if (rstc->line->deassert_cnt)
deassert_cnt isn't protected by any lock.
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 168
Quoted 11 lines
drivers/reset/core.c +11
-0+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
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 170
Quoted 2 lines
drivers/reset/core.c +2
-0+* 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."
Quoted 23 lines
drivers/reset/core.c +15
-1+*/ +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);
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_deassert); · line 203
Quoted 10 lines
drivers/reset/core.c +5
-0+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.
Quoted 42 lines
drivers/reset/core.c +31
-0+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;
drivers/reset/core.c struct reset_control *of_reset_control_get_by_index(struct device_node *node, · line 283
Quoted 5 lines
drivers/reset/core.c +2
-0@@ -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.
Quoted 35 lines
drivers/reset/core.c +10
-2+ 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); }include/linux/reset-controller.h +0
-0
include/linux/reset-controller.h struct of_phandle_args; · line 34
Quoted 4 lines
include/linux/reset-controller.h +1
-0@@ -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?
include/linux/reset-controller.h struct of_phandle_args; · line 37
Quoted 3 lines
include/linux/reset-controller.h +0
-0* @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
PATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
Hi,
Quoted 3 lines · Philipp Zabel
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).
Quoted 36 lines
Am Freitag, den 11.12.2015, 16:41 +0100 schrieb Hans de Goede:
Quoted 35 lines
Add
reset_control_deassert_shared/reset_control_assert_sharedfunctions 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_sharedhave been called and keep the line deasserted as long as deassert has been called more times than assert.Signed-off-by Hans de Goede <[email protected]>---
Changes in v2:(quoted diff) +0
-2-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(-)drivers/reset/core.c +8
-0@@ -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;
Quoted 8 lines
drivers/reset/core.c static DEFINE_MUTEX(reset_controller_list_mutex); · line 36
Quoted 4 lines
drivers/reset/core.c +4
-0+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 multiplereset_controlspointing here.
Ack.
Quoted 15 lines
Quoted 15 lines
drivers/reset/core.c +3
-3+/** * 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; };
Quoted 7 lines
Quoted 1 line
drivers/reset/core.c +0
-0/** [...]
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 135
Quoted 3 lines
drivers/reset/core.c +0
-0@@ -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.
Quoted 8 lines
Quoted 8 lines
drivers/reset/core.c +1
-1if (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);
Quoted 10 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 149
Quoted 7 lines
drivers/reset/core.c +6
-0/** +* 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" ?
Quoted 8 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 154
Quoted 5 lines
drivers/reset/core.c +5
-0+*/ +int reset_control_assert_shared (struct reset_control *rstc) +{ +if (!rstc->rcdev->ops->assert) +return -ENOTSUPP ;
WARN_ON(rstc->line->deassert_cnt == 0)
Quoted 8 lines
Actually, what to do in this case? Assume
ops->assertwas called, or do it again to be sure? Certainly we don't want to wrapdeassert_cnt, or the nextdeassert_sharedwill do nothing.drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 157
Quoted 2 lines
drivers/reset/core.c +2
-0+ rstc->line->deassert_cnt--; +if (rstc->line->deassert_cnt)
deassert_cntisn'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 ?
Quoted 14 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 168
Quoted 12 lines
drivers/reset/core.c +11
-0+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.
Quoted 5 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 170
Quoted 2 lines
drivers/reset/core.c +2
-0+* 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.
Quoted 29 lines
Quoted 29 lines
drivers/reset/core.c +16
-1+*/ +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);
Quoted 7 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_deassert); · line 203
Quoted 4 lines
drivers/reset/core.c +4
-0+static struct reset_line *reset_line_get (struct reset_controller_dev *rcdev, +unsigned int index) +{ +struct reset_line *line;
lockdep_assert_heldhere and inreset_line_putwould document that these functions are called under reset_(controller_)list_mutex.
Ok, I will add these.
Quoted 44 lines
Quoted 44 lines
drivers/reset/core.c +31
-0+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, }
Quoted 5 lines
drivers/reset/core.c struct reset_control *of_reset_control_get_by_index(struct device_node *node, · line 283
Quoted 3 lines
drivers/reset/core.c +2
-0try_module_get (rcdev->owner); + +/* reset_controller_list_mutex also protects the reset_line list */ Let's rename it to
reset_list_mutex, then.
Ack.
Quoted 34 lines
Quoted 34 lines
drivers/reset/core.c +10
-2+ 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); }include/linux/reset-controller.h +0
-0
Quoted 8 lines
include/linux/reset-controller.h struct of_phandle_args; · line 34
Quoted 5 lines
include/linux/reset-controller.h +1
-0@@ -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.
Quoted 8 lines
include/linux/reset-controller.h struct of_phandle_args; · line 37
Quoted 3 lines
include/linux/reset-controller.h +0
-0* @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
Philipp Zabel
maintainerPATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
Hi Hans,
Am Freitag, den 11.12.2015, 19:21 +0100 schrieb Hans de Goede:
[...]
Quoted 7 lines
Quoted 5 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 135
Quoted 3 lines
drivers/reset/core.c +0
-0@@ -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.
Quoted 19 lines
Quoted 8 lines
Quoted 8 lines
drivers/reset/core.c +1
-1if (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);Quoted 10 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 149
Quoted 7 lines
drivers/reset/core.c +6
-0/** +* 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."
Quoted 1 line
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.
Quoted 12 lines
Quoted 12 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 154
Quoted 5 lines
drivers/reset/core.c +5
-0+*/ +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->assertwas called, or do it again to be sure? Certainly we don't want to wrapdeassert_cnt, or the nextdeassert_sharedwill do nothing.
Quoted 7 lines
Quoted 4 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 157
Quoted 2 lines
drivers/reset/core.c +2
-0+ rstc->line->deassert_cnt--; +if (rstc->line->deassert_cnt)
deassert_cntisn't protected by any lock.Right, good catch. I believe the best way to fix this is to change
deassert_cntinto anatomic_tand useatomic_dec_return/atomic_int_return,
Yes, that would work.
Quoted 4 lines
Downside of using an
atomic_tis that doing theWARN_ONyou 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.
[...]
Quoted 7 lines
Quoted 5 lines
drivers/reset/core.c EXPORT_SYMBOL_GPL(reset_control_assert); · line 170
Quoted 2 lines
drivers/reset/core.c +2
-0+* 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
PATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
In reply to Hans de GoedeHi,
include/linux/reset.h int reset_control_reset(struct reset_control *rstc); · line 15
Quoted 10 lines · Hans de Goede
include/linux/reset.h +2
-0@@ -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
Signature · 10 lines
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>
Philipp Zabel
maintainerPATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
Quoted 15 lines
Hi,
include/linux/reset.h int reset_control_reset(struct reset_control *rstc); · line 15
Quoted 10 lines · Hans de Goede
include/linux/reset.h +2
-0@@ -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_getdirectly?
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
PATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
Quoted 17 lines · Philipp Zabel
Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
Quoted 15 lines
Hi,
include/linux/reset.h int reset_control_reset(struct reset_control *rstc); · line 15
Quoted 10 lines · Hans de Goede
include/linux/reset.h +2
-0@@ -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_getdirectly?
Quoted 3 lines
This is about different expectations of the caller.
A driver callingreset_control_assertexpects the reset line to be asserted after the call.
Is that behaviour documented explicitly somewhere?
Quoted 5 lines
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 functionsreset_control_deassert_getandreset_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
Signature · 10 lines
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>
Philipp Zabel
maintainerPATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
Hi Maxime,
Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
Quoted 5 lines · Philipp Zabel
Quoted 4 lines
Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
Quoted 3 lines
Hi,
On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/linux/reset.h +0
-0Quoted 8 lines
Quoted 8 lines
include/linux/reset.h int reset_control_reset(struct reset_control *rstc); · line 15
Quoted 6 lines
include/linux/reset.h +2
-0@@ -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_getdirectly?
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.
Quoted 5 lines
Quoted 3 lines
This is about different expectations of the caller.
A driver callingreset_control_assertexpects 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.
Quoted 8 lines
Quoted 5 lines
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 functionsreset_control_deassert_getandreset_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.
Quoted 4 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.
Quoted 4 lines
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.
Quoted 4 lines
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
PATCH v2 1/3 reset: Add shared reset_control_[de]assert variants
Quoted 21 lines · Philipp Zabel
Hi Maxime,
Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
Quoted 5 lines · Philipp Zabel
Quoted 4 lines
Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
Quoted 3 lines
Hi,
On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/linux/reset.h +0
-0Quoted 8 lines
Quoted 8 lines
include/linux/reset.h int reset_control_reset(struct reset_control *rstc); · line 15
Quoted 6 lines
include/linux/reset.h +2
-0@@ -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_getdirectly?
Quoted 5 lines
I think I see your point now. Maybe we should add a flags parameter to
reset_control_getand/or wrap it in two versions,reset_control_get_exclusiveandreset_control_get_shared(or just add the_sharedvariant). Thenreset_control_get(_exclusive)could return-EBUSYif 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).
Quoted 11 lines
Quoted 6 lines
Quoted 4 lines
This is about different expectations of the caller.
A driver callingreset_control_assertexpects 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.
Quoted 10 lines
Also, that expected behavior matches the function name, which I like. So I still welcome adding new API calls for the shared/refcounting variant.
Quoted 6 lines
Quoted 5 lines
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 functionsreset_control_deassert_getandreset_control_deassert_put.
Quoted 5 lines
Quoted 2 lines
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
Signature · 10 lines
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>
Hi,
Quoted 91 lines · Maxime Ripard
Quoted 21 lines · Philipp Zabel
Hi Maxime,
Am Mittwoch, den 16.12.2015, 11:29 +0100 schrieb Maxime Ripard:
Quoted 5 lines · Philipp Zabel
Quoted 4 lines
Am Montag, den 14.12.2015, 10:36 +0100 schrieb Maxime Ripard:
Quoted 3 lines
Hi,
On Fri, Dec 11, 2015 at 04:41:58PM +0100, Hans de Goede wrote:
Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
include/linux/reset.h +0
-0Quoted 8 lines
Quoted 8 lines
include/linux/reset.h int reset_control_reset(struct reset_control *rstc); · line 15
Quoted 6 lines
include/linux/reset.h +2
-0@@ -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_getdirectly?Quoted 5 lines
I think I see your point now. Maybe we should add a flags parameter to
reset_control_getand/or wrap it in two versions,reset_control_get_exclusiveandreset_control_get_shared(or just add the_sharedvariant). Thenreset_control_get(_exclusive)could return-EBUSYif a reset line is already in use.I guess the current assumption was that
reset_control_getwas 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).
Quoted 11 lines
Quoted 6 lines
Quoted 4 lines
This is about different expectations of the caller.
A driver callingreset_control_assertexpects 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.
Quoted 10 lines
Also, that expected behavior matches the function name, which I like. So I still welcome adding new API calls for the shared/refcounting variant.
Quoted 6 lines
Quoted 5 lines
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 functionsreset_control_deassert_getandreset_control_deassert_put.Quoted 5 lines
Quoted 2 lines
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_getor its shared variant.- If you call
reset_control_geton a free line, it succeeds, and marks the line in exclusive use.
- If you callreset_control_geton 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.
Quoted 8 lines
* 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.
Quoted 3 lines
- 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
Philipp Zabel
maintainerAm Samstag, den 19.12.2015, 11:55 +0100 schrieb Hans de Goede:
Quoted 1 line · Maxime Ripard
[...]
Quoted 21 lines
Quoted 21 lines
I guess we could also have something like this:
* The driver gets the reference to the reset line using
reset_control_getor its shared variant.- If you call
reset_control_geton a free line, it succeeds, and marks the line in exclusive use.
- If you callreset_control_geton 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.
Quoted 7 lines
Quoted 3 lines
- 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.
Quoted 10 lines
Quoted 3 lines
- 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 usereset_control_get_shared.
Quoted 3 lines
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
Quoted 17 lines · Philipp Zabel
Am Samstag, den 19.12.2015, 11:55 +0100 schrieb Hans de Goede:
Quoted 12 lines · Maxime Ripard
Quoted 4 lines
- 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 usereset_control_get_shared.Quoted 3 lines
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.
Quoted 7 lines
I wouldn't want drivers to have to differentiate between relevant and irrelevant error codes, so in the clock-like refcounting use case
reset_assertshould 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