From: Ramiro Oliveira Ramiro.Oliveira@synopsys.com
commit bb475230b8e59a547ab66ac3b02572df21a580e9 upstream.
The *_get_optional_* functions weren't really optional so this patch makes them really optional.
These *_get_optional_* functions will now return NULL instead of an error if no matching reset phandle is found in the DT, and all the reset_control_* functions now accept NULL rstc pointers.
Signed-off-by: Ramiro Oliveira Ramiro.Oliveira@synopsys.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de --- Please apply to v4.9.y stable tree. --- drivers/reset/core.c | 48 +++++++++++++++++++++++++++++++++---------- include/linux/reset.h | 45 +++++++++++++++++++++++----------------- 2 files changed, 63 insertions(+), 30 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c index b8ae1dbd4c17..75821417b799 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -135,11 +135,16 @@ EXPORT_SYMBOL_GPL(devm_reset_controller_register); * @rstc: reset controller * * Calling this on a shared reset controller is an error. + * + * If rstc is NULL it is an optional reset and the function will just + * return 0. */ int reset_control_reset(struct reset_control *rstc) { - if (WARN_ON(IS_ERR_OR_NULL(rstc)) || - WARN_ON(rstc->shared)) + if (!rstc) + return 0; + + if (WARN_ON(IS_ERR(rstc))) return -EINVAL;
if (rstc->rcdev->ops->reset) @@ -159,10 +164,16 @@ EXPORT_SYMBOL_GPL(reset_control_reset); * * For shared reset controls a driver cannot expect the hw's registers and * internal state to be reset, but must be prepared for this to happen. + * + * If rstc is NULL it is an optional reset and the function will just + * return 0. */ int reset_control_assert(struct reset_control *rstc) { - if (WARN_ON(IS_ERR_OR_NULL(rstc))) + if (!rstc) + return 0; + + if (WARN_ON(IS_ERR(rstc))) return -EINVAL;
if (!rstc->rcdev->ops->assert) @@ -185,10 +196,16 @@ EXPORT_SYMBOL_GPL(reset_control_assert); * @rstc: reset controller * * After calling this function, the reset is guaranteed to be deasserted. + * + * If rstc is NULL it is an optional reset and the function will just + * return 0. */ int reset_control_deassert(struct reset_control *rstc) { - if (WARN_ON(IS_ERR_OR_NULL(rstc))) + if (!rstc) + return 0; + + if (WARN_ON(IS_ERR(rstc))) return -EINVAL;
if (!rstc->rcdev->ops->deassert) @@ -206,12 +223,15 @@ EXPORT_SYMBOL_GPL(reset_control_deassert); /** * 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. + * line is not asserted or if the desc is NULL (optional reset). * @rstc: reset controller */ int reset_control_status(struct reset_control *rstc) { - if (WARN_ON(IS_ERR_OR_NULL(rstc))) + if (!rstc) + return 0; + + if (WARN_ON(IS_ERR(rstc))) return -EINVAL;
if (rstc->rcdev->ops->status) @@ -268,7 +288,8 @@ static void __reset_control_put(struct reset_control *rstc) }
struct reset_control *__of_reset_control_get(struct device_node *node, - const char *id, int index, int shared) + const char *id, int index, bool shared, + bool optional) { struct reset_control *rstc; struct reset_controller_dev *r, *rcdev; @@ -282,14 +303,18 @@ struct reset_control *__of_reset_control_get(struct device_node *node, if (id) { index = of_property_match_string(node, "reset-names", id); + if (index == -EILSEQ) + return ERR_PTR(index); if (index < 0) - return ERR_PTR(-ENOENT); + return optional ? NULL : ERR_PTR(-ENOENT); }
ret = of_parse_phandle_with_args(node, "resets", "#reset-cells", index, &args); - if (ret) + if (ret == -EINVAL) return ERR_PTR(ret); + if (ret) + return optional ? NULL : ERR_PTR(ret);
mutex_lock(&reset_list_mutex); rcdev = NULL; @@ -348,7 +373,8 @@ static void devm_reset_control_release(struct device *dev, void *res) }
struct reset_control *__devm_reset_control_get(struct device *dev, - const char *id, int index, int shared) + const char *id, int index, bool shared, + bool optional) { struct reset_control **ptr, *rstc;
@@ -358,7 +384,7 @@ struct reset_control *__devm_reset_control_get(struct device *dev, return ERR_PTR(-ENOMEM);
rstc = __of_reset_control_get(dev ? dev->of_node : NULL, - id, index, shared); + id, index, shared, optional); if (!IS_ERR(rstc)) { *ptr = rstc; devres_add(dev, ptr); diff --git a/include/linux/reset.h b/include/linux/reset.h index 5daff15722d3..86b4ed75359e 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -13,10 +13,12 @@ int reset_control_deassert(struct reset_control *rstc); int reset_control_status(struct reset_control *rstc);
struct reset_control *__of_reset_control_get(struct device_node *node, - const char *id, int index, int shared); + const char *id, int index, bool shared, + bool optional); void reset_control_put(struct reset_control *rstc); struct reset_control *__devm_reset_control_get(struct device *dev, - const char *id, int index, int shared); + const char *id, int index, bool shared, + bool optional);
int __must_check device_reset(struct device *dev);
@@ -69,14 +71,15 @@ static inline int device_reset_optional(struct device *dev)
static inline struct reset_control *__of_reset_control_get( struct device_node *node, - const char *id, int index, int shared) + const char *id, int index, bool shared, + bool optional) { return ERR_PTR(-ENOTSUPP); }
static inline struct reset_control *__devm_reset_control_get( - struct device *dev, - const char *id, int index, int shared) + struct device *dev, const char *id, + int index, bool shared, bool optional) { return ERR_PTR(-ENOTSUPP); } @@ -104,7 +107,8 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id) #ifndef CONFIG_RESET_CONTROLLER WARN_ON(1); #endif - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0); + return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, false, + false); }
/** @@ -132,19 +136,22 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id) static inline struct reset_control *reset_control_get_shared( struct device *dev, const char *id) { - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 1); + return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, true, + false); }
static inline struct reset_control *reset_control_get_optional_exclusive( struct device *dev, const char *id) { - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 0); + return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, false, + true); }
static inline struct reset_control *reset_control_get_optional_shared( struct device *dev, const char *id) { - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, 1); + return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, true, + true); }
/** @@ -160,7 +167,7 @@ static inline struct reset_control *reset_control_get_optional_shared( static inline struct reset_control *of_reset_control_get_exclusive( struct device_node *node, const char *id) { - return __of_reset_control_get(node, id, 0, 0); + return __of_reset_control_get(node, id, 0, false, false); }
/** @@ -185,7 +192,7 @@ static inline struct reset_control *of_reset_control_get_exclusive( static inline struct reset_control *of_reset_control_get_shared( struct device_node *node, const char *id) { - return __of_reset_control_get(node, id, 0, 1); + return __of_reset_control_get(node, id, 0, true, false); }
/** @@ -202,7 +209,7 @@ static inline struct reset_control *of_reset_control_get_shared( static inline struct reset_control *of_reset_control_get_exclusive_by_index( struct device_node *node, int index) { - return __of_reset_control_get(node, NULL, index, 0); + return __of_reset_control_get(node, NULL, index, false, false); }
/** @@ -230,7 +237,7 @@ static inline struct reset_control *of_reset_control_get_exclusive_by_index( static inline struct reset_control *of_reset_control_get_shared_by_index( struct device_node *node, int index) { - return __of_reset_control_get(node, NULL, index, 1); + return __of_reset_control_get(node, NULL, index, true, false); }
/** @@ -252,7 +259,7 @@ __must_check devm_reset_control_get_exclusive(struct device *dev, #ifndef CONFIG_RESET_CONTROLLER WARN_ON(1); #endif - return __devm_reset_control_get(dev, id, 0, 0); + return __devm_reset_control_get(dev, id, 0, false, false); }
/** @@ -267,19 +274,19 @@ __must_check devm_reset_control_get_exclusive(struct device *dev, static inline struct reset_control *devm_reset_control_get_shared( struct device *dev, const char *id) { - return __devm_reset_control_get(dev, id, 0, 1); + return __devm_reset_control_get(dev, id, 0, true, false); }
static inline struct reset_control *devm_reset_control_get_optional_exclusive( struct device *dev, const char *id) { - return __devm_reset_control_get(dev, id, 0, 0); + return __devm_reset_control_get(dev, id, 0, false, true); }
static inline struct reset_control *devm_reset_control_get_optional_shared( struct device *dev, const char *id) { - return __devm_reset_control_get(dev, id, 0, 1); + return __devm_reset_control_get(dev, id, 0, true, true); }
/** @@ -297,7 +304,7 @@ static inline struct reset_control *devm_reset_control_get_optional_shared( static inline struct reset_control * devm_reset_control_get_exclusive_by_index(struct device *dev, int index) { - return __devm_reset_control_get(dev, NULL, index, 0); + return __devm_reset_control_get(dev, NULL, index, false, false); }
/** @@ -313,7 +320,7 @@ devm_reset_control_get_exclusive_by_index(struct device *dev, int index) static inline struct reset_control * devm_reset_control_get_shared_by_index(struct device *dev, int index) { - return __devm_reset_control_get(dev, NULL, index, 1); + return __devm_reset_control_get(dev, NULL, index, true, false); }
/*
From: Heiner Kallweit hkallweit1@gmail.com
commit 4891486fb2c80eaf3bb0f9eb065d15ecd357702f upstream.
Commit "reset: make optional functions really optional" missed to adjust one check in reset_control_put, causing a NULL pointer access for optional resets.
Fixes: bb475230b8e5 "reset: make optional functions really optional" Signed-off-by: Heiner Kallweit hkallweit1@gmail.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de --- drivers/reset/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 75821417b799..f62f57ebc45a 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -358,7 +358,7 @@ EXPORT_SYMBOL_GPL(__of_reset_control_get);
void reset_control_put(struct reset_control *rstc) { - if (IS_ERR(rstc)) + if (IS_ERR_OR_NULL(rstc)) return;
mutex_lock(&reset_list_mutex);
From: Philipp Zabel p.zabel@pengutronix.de
commit 0ca10b60ceeb5372da01798ca68c116ae45a6eb6 upstream.
When RESET_CONTROLLER is not enabled, the optional reset_control_get stubs should now also return NULL.
Since it is now valid for reset_control_assert/deassert/reset/status/put to be called unconditionally, with NULL as an argument for optional resets, the stubs are not allowed to warn anymore.
Fixes: bb475230b8e5 ("reset: make optional functions really optional") Reported-by: Andrzej Hajda a.hajda@samsung.com Tested-by: Andrzej Hajda a.hajda@samsung.com Reviewed-by: Andrzej Hajda a.hajda@samsung.com Cc: Ramiro Oliveira Ramiro.Oliveira@synopsys.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de --- include/linux/reset.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/include/linux/reset.h b/include/linux/reset.h index 86b4ed75359e..96fb139bdd08 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -31,31 +31,26 @@ static inline int device_reset_optional(struct device *dev)
static inline int reset_control_reset(struct reset_control *rstc) { - WARN_ON(1); return 0; }
static inline int reset_control_assert(struct reset_control *rstc) { - WARN_ON(1); return 0; }
static inline int reset_control_deassert(struct reset_control *rstc) { - WARN_ON(1); return 0; }
static inline int reset_control_status(struct reset_control *rstc) { - WARN_ON(1); return 0; }
static inline void reset_control_put(struct reset_control *rstc) { - WARN_ON(1); }
static inline int __must_check device_reset(struct device *dev) @@ -74,14 +69,14 @@ static inline struct reset_control *__of_reset_control_get( const char *id, int index, bool shared, bool optional) { - return ERR_PTR(-ENOTSUPP); + return optional ? NULL : ERR_PTR(-ENOTSUPP); }
static inline struct reset_control *__devm_reset_control_get( struct device *dev, const char *id, int index, bool shared, bool optional) { - return ERR_PTR(-ENOTSUPP); + return optional ? NULL : ERR_PTR(-ENOTSUPP); }
#endif /* CONFIG_RESET_CONTROLLER */
From: Philipp Zabel p.zabel@pengutronix.de
commit 62e24c5775ecb387a3eb33701378ccfa6dbc98ee upstream.
Rename the internal __reset_control_get/put functions to __reset_control_get/put_internal and add an exported __reset_control_get equivalent to __of_reset_control_get that takes a struct device parameter. This avoids the confusing call to __of_reset_control_get in the non-DT case and fixes the devm_reset_control_get_optional function to return NULL if RESET_CONTROLLER is enabled but dev->of_node == NULL.
Fixes: bb475230b8e5 ("reset: make optional functions really optional") Reported-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Tested-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Cc: Ramiro Oliveira Ramiro.Oliveira@synopsys.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de --- drivers/reset/core.c | 22 ++++++++++++++++------ include/linux/reset.h | 22 ++++++++++++++-------- 2 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c index f62f57ebc45a..e8cb31616c3e 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -241,7 +241,7 @@ int reset_control_status(struct reset_control *rstc) } EXPORT_SYMBOL_GPL(reset_control_status);
-static struct reset_control *__reset_control_get( +static struct reset_control *__reset_control_get_internal( struct reset_controller_dev *rcdev, unsigned int index, int shared) { @@ -274,7 +274,7 @@ static struct reset_control *__reset_control_get( return rstc; }
-static void __reset_control_put(struct reset_control *rstc) +static void __reset_control_put_internal(struct reset_control *rstc) { lockdep_assert_held(&reset_list_mutex);
@@ -343,7 +343,7 @@ struct reset_control *__of_reset_control_get(struct device_node *node, }
/* reset_list_mutex also protects the rcdev's reset_control list */ - rstc = __reset_control_get(rcdev, rstc_id, shared); + rstc = __reset_control_get_internal(rcdev, rstc_id, shared);
mutex_unlock(&reset_list_mutex);
@@ -351,6 +351,17 @@ struct reset_control *__of_reset_control_get(struct device_node *node, } EXPORT_SYMBOL_GPL(__of_reset_control_get);
+struct reset_control *__reset_control_get(struct device *dev, const char *id, + int index, bool shared, bool optional) +{ + if (dev->of_node) + return __of_reset_control_get(dev->of_node, id, index, shared, + optional); + + return optional ? NULL : ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(__reset_control_get); + /** * reset_control_put - free the reset controller * @rstc: reset controller @@ -362,7 +373,7 @@ void reset_control_put(struct reset_control *rstc) return;
mutex_lock(&reset_list_mutex); - __reset_control_put(rstc); + __reset_control_put_internal(rstc); mutex_unlock(&reset_list_mutex); } EXPORT_SYMBOL_GPL(reset_control_put); @@ -383,8 +394,7 @@ struct reset_control *__devm_reset_control_get(struct device *dev, if (!ptr) return ERR_PTR(-ENOMEM);
- rstc = __of_reset_control_get(dev ? dev->of_node : NULL, - id, index, shared, optional); + rstc = __reset_control_get(dev, id, index, shared, optional); if (!IS_ERR(rstc)) { *ptr = rstc; devres_add(dev, ptr); diff --git a/include/linux/reset.h b/include/linux/reset.h index 96fb139bdd08..13d8681210d5 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -15,6 +15,9 @@ int reset_control_status(struct reset_control *rstc); struct reset_control *__of_reset_control_get(struct device_node *node, const char *id, int index, bool shared, bool optional); +struct reset_control *__reset_control_get(struct device *dev, const char *id, + int index, bool shared, + bool optional); void reset_control_put(struct reset_control *rstc); struct reset_control *__devm_reset_control_get(struct device *dev, const char *id, int index, bool shared, @@ -72,6 +75,13 @@ static inline struct reset_control *__of_reset_control_get( return optional ? NULL : ERR_PTR(-ENOTSUPP); }
+static inline struct reset_control *__reset_control_get( + struct device *dev, const char *id, + int index, bool shared, bool optional) +{ + return optional ? NULL : ERR_PTR(-ENOTSUPP); +} + static inline struct reset_control *__devm_reset_control_get( struct device *dev, const char *id, int index, bool shared, bool optional) @@ -102,8 +112,7 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id) #ifndef CONFIG_RESET_CONTROLLER WARN_ON(1); #endif - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, false, - false); + return __reset_control_get(dev, id, 0, false, false); }
/** @@ -131,22 +140,19 @@ __must_check reset_control_get_exclusive(struct device *dev, const char *id) static inline struct reset_control *reset_control_get_shared( struct device *dev, const char *id) { - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, true, - false); + return __reset_control_get(dev, id, 0, true, false); }
static inline struct reset_control *reset_control_get_optional_exclusive( struct device *dev, const char *id) { - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, false, - true); + return __reset_control_get(dev, id, 0, false, true); }
static inline struct reset_control *reset_control_get_optional_shared( struct device *dev, const char *id) { - return __of_reset_control_get(dev ? dev->of_node : NULL, id, 0, true, - true); + return __reset_control_get(dev, id, 0, true, true); }
/**
From: Masahiro Yamada yamada.masahiro@socionext.com
commit 1554bbd4ad401b7f0f916c0891874111c10befe5 upstream.
Commit bb475230b8e5 ("reset: make optional functions really optional") converted *_get_optional* functions, but device_reset_optional() was left behind. Convert it in the same way.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de --- drivers/reset/core.c | 9 +++++---- include/linux/reset.h | 28 +++++++++++++--------------- 2 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/drivers/reset/core.c b/drivers/reset/core.c index e8cb31616c3e..188205a55261 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -410,17 +410,18 @@ EXPORT_SYMBOL_GPL(__devm_reset_control_get); * device_reset - find reset controller associated with the device * and perform reset * @dev: device to be reset by the controller + * @optional: whether it is optional to reset the device * - * Convenience wrapper for reset_control_get() and reset_control_reset(). + * Convenience wrapper for __reset_control_get() and reset_control_reset(). * This is useful for the common case of devices with single, dedicated reset * lines. */ -int device_reset(struct device *dev) +int __device_reset(struct device *dev, bool optional) { struct reset_control *rstc; int ret;
- rstc = reset_control_get(dev, NULL); + rstc = __reset_control_get(dev, NULL, 0, 0, optional); if (IS_ERR(rstc)) return PTR_ERR(rstc);
@@ -430,4 +431,4 @@ int device_reset(struct device *dev)
return ret; } -EXPORT_SYMBOL_GPL(device_reset); +EXPORT_SYMBOL_GPL(__device_reset); diff --git a/include/linux/reset.h b/include/linux/reset.h index 13d8681210d5..61a0dda3f981 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -19,17 +19,11 @@ struct reset_control *__reset_control_get(struct device *dev, const char *id, int index, bool shared, bool optional); void reset_control_put(struct reset_control *rstc); +int __device_reset(struct device *dev, bool optional); struct reset_control *__devm_reset_control_get(struct device *dev, const char *id, int index, bool shared, bool optional);
-int __must_check device_reset(struct device *dev); - -static inline int device_reset_optional(struct device *dev) -{ - return device_reset(dev); -} - #else
static inline int reset_control_reset(struct reset_control *rstc) @@ -56,15 +50,9 @@ static inline void reset_control_put(struct reset_control *rstc) { }
-static inline int __must_check device_reset(struct device *dev) +static inline int __device_reset(struct device *dev, bool optional) { - WARN_ON(1); - return -ENOTSUPP; -} - -static inline int device_reset_optional(struct device *dev) -{ - return -ENOTSUPP; + return optional ? 0 : -ENOTSUPP; }
static inline struct reset_control *__of_reset_control_get( @@ -91,6 +79,16 @@ static inline struct reset_control *__devm_reset_control_get(
#endif /* CONFIG_RESET_CONTROLLER */
+static inline int __must_check device_reset(struct device *dev) +{ + return __device_reset(dev, false); +} + +static inline int device_reset_optional(struct device *dev) +{ + return __device_reset(dev, true); +} + /** * reset_control_get_exclusive - Lookup and obtain an exclusive reference * to a reset controller.
From: Masahiro Yamada yamada.masahiro@socionext.com
commit bb6c7768385b200063a14d6615cc1246c3d00760 upstream.
Commit bb475230b8e5 ("reset: make optional functions really optional") gave a new meaning to _get_optional variants.
The differentiation by WARN_ON() is not needed any more. We already have inconsistency about this; (devm_)reset_control_get_exclusive() has WARN_ON() check, but of_reset_control_get_exclusive() does not.
Signed-off-by: Masahiro Yamada yamada.masahiro@socionext.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de --- include/linux/reset.h | 6 ------ 1 file changed, 6 deletions(-)
diff --git a/include/linux/reset.h b/include/linux/reset.h index 61a0dda3f981..7e99690dbc81 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -107,9 +107,6 @@ static inline int device_reset_optional(struct device *dev) static inline struct reset_control * __must_check reset_control_get_exclusive(struct device *dev, const char *id) { -#ifndef CONFIG_RESET_CONTROLLER - WARN_ON(1); -#endif return __reset_control_get(dev, id, 0, false, false); }
@@ -255,9 +252,6 @@ static inline struct reset_control * __must_check devm_reset_control_get_exclusive(struct device *dev, const char *id) { -#ifndef CONFIG_RESET_CONTROLLER - WARN_ON(1); -#endif return __devm_reset_control_get(dev, id, 0, false, false); }
On Mon, Dec 03, 2018 at 03:42:09PM -0600, Dinh Nguyen wrote:
From: Ramiro Oliveira Ramiro.Oliveira@synopsys.com
commit bb475230b8e59a547ab66ac3b02572df21a580e9 upstream.
The *_get_optional_* functions weren't really optional so this patch makes them really optional.
These *_get_optional_* functions will now return NULL instead of an error if no matching reset phandle is found in the DT, and all the reset_control_* functions now accept NULL rstc pointers.
Signed-off-by: Ramiro Oliveira Ramiro.Oliveira@synopsys.com Signed-off-by: Philipp Zabel p.zabel@pengutronix.de
Please apply to v4.9.y stable tree.
Why is this patch series needed in 4.9? You haven't provided any justification here :(
thanks,
greg k-h
linux-stable-mirror@lists.linaro.org