Commit 5c3c067b authored by Dan Williams's avatar Dan Williams
Browse files

cxl/core/port: Fix unregister_port() lock assertion



The device_lock_assert() in unregister_port() fails to pick the right
device leading to splats like the following from:

echo "ACPI0017:00" > /sys/bus/platform/drivers/cxl_acpi/unbind

 WARNING: CPU: 32 PID: 1147 at include/linux/device.h:787 unregister_port+0x49/0x50 [cxl_c
 [..]
 RIP: 0010:unregister_port+0x49/0x50 [cxl_core]
 [..]
 Call Trace:
  <TASK>
  release_nodes+0x63/0x80
  devres_release_all+0x8b/0xc0
  __device_release_driver+0x190/0x240
  device_driver_detach+0x3e/0xa0
  unbind_store+0x113/0x130

Fix it up to assert on the device_lock() for ACPI0017 for root and 1st
level ports, and parent ports for all the rest.

Fixes: 54cdbf84 ("cxl/port: Add a driver for 'struct cxl_port' objects")
Reported-by: default avatarBen Widawsky <ben.widawsky@intel.com>
Reviewed-by: default avatarBen Widawsky <ben.widawsky@intel.com>
Link: https://lore.kernel.org/r/164439224893.2941117.18331456248117887720.stgit@dwillia2-desk3.amr.corp.intel.com


Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 74b0fe80
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -348,12 +348,28 @@ EXPORT_SYMBOL_NS_GPL(to_cxl_port, CXL);
static void unregister_port(void *_port)
{
	struct cxl_port *port = _port;
	struct cxl_port *parent;
	struct device *lock_dev;

	if (!is_cxl_root(port)) {
		device_lock_assert(port->dev.parent);
		port->uport = NULL;
	}
	if (is_cxl_root(port))
		parent = NULL;
	else
		parent = to_cxl_port(port->dev.parent);

	/*
	 * CXL root port's and the first level of ports are unregistered
	 * under the platform firmware device lock, all other ports are
	 * unregistered while holding their parent port lock.
	 */
	if (!parent)
		lock_dev = port->uport;
	else if (is_cxl_root(parent))
		lock_dev = parent->uport;
	else
		lock_dev = &parent->dev;

	device_lock_assert(lock_dev);
	port->uport = NULL;
	device_unregister(&port->dev);
}