summaryrefslogtreecommitdiff
path: root/drivers/cxl/core
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2022-01-31 11:50:09 -0800
committerDan Williams <dan.j.williams@intel.com>2022-02-08 22:57:29 -0800
commit3c5b903955251ea464fca383a42d981e33004df6 (patch)
treec4ff8665db9ad785d73be3a5ec462964e2148b86 /drivers/cxl/core
parent53fa1bff3426344d466d91e81f076eab677d0ece (diff)
cxl: Prove CXL locking
When CONFIG_PROVE_LOCKING is enabled the 'struct device' definition gets an additional mutex that is not clobbered by lockdep_set_novalidate_class() like the typical device_lock(). This allows for local annotation of subsystem locks with mutex_lock_nested() per the subsystem's object/lock hierarchy. For CXL, this primarily needs the ability to lock ports by depth and child objects of ports by their parent parent-port lock. Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Ben Widawsky <ben.widawsky@intel.com> Link: https://lore.kernel.org/r/164365853422.99383.1052399160445197427.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/cxl/core')
-rw-r--r--drivers/cxl/core/pmem.c4
-rw-r--r--drivers/cxl/core/port.c47
2 files changed, 38 insertions, 13 deletions
diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c
index b5fca97b0a07..40b3f5030496 100644
--- a/drivers/cxl/core/pmem.c
+++ b/drivers/cxl/core/pmem.c
@@ -115,10 +115,10 @@ static void unregister_nvb(void *_cxl_nvb)
* work to flush. Once the state has been changed to 'dead' then no new
* work can be queued by user-triggered bind.
*/
- device_lock(&cxl_nvb->dev);
+ cxl_device_lock(&cxl_nvb->dev);
flush = cxl_nvb->state != CXL_NVB_NEW;
cxl_nvb->state = CXL_NVB_DEAD;
- device_unlock(&cxl_nvb->dev);
+ cxl_device_unlock(&cxl_nvb->dev);
/*
* Even though the device core will trigger device_release_driver()
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index f287d87da6d6..9285cdb734b2 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -111,7 +111,7 @@ static ssize_t target_list_show(struct device *dev,
ssize_t offset = 0;
int i, rc = 0;
- device_lock(dev);
+ cxl_device_lock(dev);
for (i = 0; i < cxld->interleave_ways; i++) {
struct cxl_dport *dport = cxld->target[i];
struct cxl_dport *next = NULL;
@@ -127,7 +127,7 @@ static ssize_t target_list_show(struct device *dev,
break;
offset += rc;
}
- device_unlock(dev);
+ cxl_device_unlock(dev);
if (rc < 0)
return rc;
@@ -214,6 +214,12 @@ bool is_root_decoder(struct device *dev)
}
EXPORT_SYMBOL_NS_GPL(is_root_decoder, CXL);
+bool is_cxl_decoder(struct device *dev)
+{
+ return dev->type->release == cxl_decoder_release;
+}
+EXPORT_SYMBOL_NS_GPL(is_cxl_decoder, CXL);
+
struct cxl_decoder *to_cxl_decoder(struct device *dev)
{
if (dev_WARN_ONCE(dev, dev->type->release != cxl_decoder_release,
@@ -235,10 +241,10 @@ static void cxl_port_release(struct device *dev)
struct cxl_port *port = to_cxl_port(dev);
struct cxl_dport *dport, *_d;
- device_lock(dev);
+ cxl_device_lock(dev);
list_for_each_entry_safe(dport, _d, &port->dports, list)
cxl_dport_release(dport);
- device_unlock(dev);
+ cxl_device_unlock(dev);
ida_free(&cxl_port_ida, port->id);
kfree(port);
}
@@ -254,6 +260,12 @@ static const struct device_type cxl_port_type = {
.groups = cxl_port_attribute_groups,
};
+bool is_cxl_port(struct device *dev)
+{
+ return dev->type == &cxl_port_type;
+}
+EXPORT_SYMBOL_NS_GPL(is_cxl_port, CXL);
+
struct cxl_port *to_cxl_port(struct device *dev)
{
if (dev_WARN_ONCE(dev, dev->type != &cxl_port_type,
@@ -261,13 +273,14 @@ struct cxl_port *to_cxl_port(struct device *dev)
return NULL;
return container_of(dev, struct cxl_port, dev);
}
+EXPORT_SYMBOL_NS_GPL(to_cxl_port, CXL);
static void unregister_port(void *_port)
{
struct cxl_port *port = _port;
struct cxl_dport *dport;
- device_lock(&port->dev);
+ cxl_device_lock(&port->dev);
list_for_each_entry(dport, &port->dports, list) {
char link_name[CXL_TARGET_STRLEN];
@@ -276,7 +289,7 @@ static void unregister_port(void *_port)
continue;
sysfs_remove_link(&port->dev.kobj, link_name);
}
- device_unlock(&port->dev);
+ cxl_device_unlock(&port->dev);
device_unregister(&port->dev);
}
@@ -407,7 +420,7 @@ static int add_dport(struct cxl_port *port, struct cxl_dport *new)
{
struct cxl_dport *dup;
- device_lock(&port->dev);
+ cxl_device_lock(&port->dev);
dup = find_dport(port, new->port_id);
if (dup)
dev_err(&port->dev,
@@ -416,7 +429,7 @@ static int add_dport(struct cxl_port *port, struct cxl_dport *new)
dev_name(dup->dport));
else
list_add_tail(&new->list, &port->dports);
- device_unlock(&port->dev);
+ cxl_device_unlock(&port->dev);
return dup ? -EEXIST : 0;
}
@@ -475,7 +488,7 @@ static int decoder_populate_targets(struct cxl_decoder *cxld,
if (!target_map)
return 0;
- device_lock(&port->dev);
+ cxl_device_lock(&port->dev);
if (list_empty(&port->dports)) {
rc = -EINVAL;
goto out_unlock;
@@ -492,7 +505,7 @@ static int decoder_populate_targets(struct cxl_decoder *cxld,
}
out_unlock:
- device_unlock(&port->dev);
+ cxl_device_unlock(&port->dev);
return rc;
}
@@ -717,15 +730,27 @@ static int cxl_bus_match(struct device *dev, struct device_driver *drv)
static int cxl_bus_probe(struct device *dev)
{
- return to_cxl_drv(dev->driver)->probe(dev);
+ int rc;
+
+ /*
+ * Take the CXL nested lock since the driver core only holds
+ * @dev->mutex and not @dev->lockdep_mutex.
+ */
+ cxl_nested_lock(dev);
+ rc = to_cxl_drv(dev->driver)->probe(dev);
+ cxl_nested_unlock(dev);
+
+ return rc;
}
static void cxl_bus_remove(struct device *dev)
{
struct cxl_driver *cxl_drv = to_cxl_drv(dev->driver);
+ cxl_nested_lock(dev);
if (cxl_drv->remove)
cxl_drv->remove(dev);
+ cxl_nested_unlock(dev);
}
struct bus_type cxl_bus_type = {