| From 99aed9227073fb34ce2880cbc7063e04185a65e1 Mon Sep 17 00:00:00 2001 |
| From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Date: Thu, 22 Oct 2020 21:41:00 +0300 |
| Subject: device property: Don't clear secondary pointer for shared primary firmware node |
| |
| From: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| |
| commit 99aed9227073fb34ce2880cbc7063e04185a65e1 upstream. |
| |
| It appears that firmware nodes can be shared between devices. In such case |
| when a (child) device is about to be deleted, its firmware node may be shared |
| and ACPI_COMPANION_SET(..., NULL) call for it breaks the secondary link |
| of the shared primary firmware node. |
| |
| In order to prevent that, check, if the device has a parent and parent's |
| firmware node is shared with its child, and avoid crashing the link. |
| |
| Fixes: c15e1bdda436 ("device property: Fix the secondary firmware node handling in set_primary_fwnode()") |
| Reported-by: Ferry Toth <fntoth@gmail.com> |
| Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> |
| Tested-by: Ferry Toth <fntoth@gmail.com> |
| Cc: 5.9+ <stable@vger.kernel.org> # 5.9+ |
| Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/base/core.c | 4 +++- |
| 1 file changed, 3 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/base/core.c |
| +++ b/drivers/base/core.c |
| @@ -4260,6 +4260,7 @@ static inline bool fwnode_is_primary(str |
| */ |
| void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) |
| { |
| + struct device *parent = dev->parent; |
| struct fwnode_handle *fn = dev->fwnode; |
| |
| if (fwnode) { |
| @@ -4274,7 +4275,8 @@ void set_primary_fwnode(struct device *d |
| } else { |
| if (fwnode_is_primary(fn)) { |
| dev->fwnode = fn->secondary; |
| - fn->secondary = ERR_PTR(-ENODEV); |
| + if (!(parent && fn == parent->fwnode)) |
| + fn->secondary = ERR_PTR(-ENODEV); |
| } else { |
| dev->fwnode = NULL; |
| } |