summaryrefslogtreecommitdiff
path: root/drivers/cxl/cxl.h
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2022-01-31 22:50:09 +0300
committerDan Williams <dan.j.williams@intel.com>2022-02-09 09:57:29 +0300
commit3c5b903955251ea464fca383a42d981e33004df6 (patch)
treec4ff8665db9ad785d73be3a5ec462964e2148b86 /drivers/cxl/cxl.h
parent53fa1bff3426344d466d91e81f076eab677d0ece (diff)
downloadlinux-3c5b903955251ea464fca383a42d981e33004df6.tar.xz
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/cxl.h')
-rw-r--r--drivers/cxl/cxl.h81
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 7ade555076bc..6a38d2e1f3dd 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -291,6 +291,7 @@ static inline bool is_cxl_root(struct cxl_port *port)
return port->uport == port->dev.parent;
}
+bool is_cxl_port(struct device *dev);
struct cxl_port *to_cxl_port(struct device *dev);
struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
resource_size_t component_reg_phys,
@@ -301,6 +302,7 @@ int cxl_add_dport(struct cxl_port *port, struct device *dport, int port_id,
struct cxl_decoder *to_cxl_decoder(struct device *dev);
bool is_root_decoder(struct device *dev);
+bool is_cxl_decoder(struct device *dev);
struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
unsigned int nr_targets);
struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
@@ -353,4 +355,83 @@ struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd);
#ifndef __mock
#define __mock static
#endif
+
+#ifdef CONFIG_PROVE_CXL_LOCKING
+enum cxl_lock_class {
+ CXL_ANON_LOCK,
+ CXL_NVDIMM_LOCK,
+ CXL_NVDIMM_BRIDGE_LOCK,
+ CXL_PORT_LOCK,
+ /*
+ * Be careful to add new lock classes here, CXL_PORT_LOCK is
+ * extended by the port depth, so a maximum CXL port topology
+ * depth would need to be defined first.
+ */
+};
+
+static inline void cxl_nested_lock(struct device *dev)
+{
+ if (is_cxl_port(dev)) {
+ struct cxl_port *port = to_cxl_port(dev);
+
+ mutex_lock_nested(&dev->lockdep_mutex,
+ CXL_PORT_LOCK + port->depth);
+ } else if (is_cxl_decoder(dev)) {
+ struct cxl_port *port = to_cxl_port(dev->parent);
+
+ /*
+ * A decoder is the immediate child of a port, so set
+ * its lock class equal to other child device siblings.
+ */
+ mutex_lock_nested(&dev->lockdep_mutex,
+ CXL_PORT_LOCK + port->depth + 1);
+ } else if (is_cxl_nvdimm_bridge(dev))
+ mutex_lock_nested(&dev->lockdep_mutex, CXL_NVDIMM_BRIDGE_LOCK);
+ else if (is_cxl_nvdimm(dev))
+ mutex_lock_nested(&dev->lockdep_mutex, CXL_NVDIMM_LOCK);
+ else
+ mutex_lock_nested(&dev->lockdep_mutex, CXL_ANON_LOCK);
+}
+
+static inline void cxl_nested_unlock(struct device *dev)
+{
+ mutex_unlock(&dev->lockdep_mutex);
+}
+
+static inline void cxl_device_lock(struct device *dev)
+{
+ /*
+ * For double lock errors the lockup will happen before lockdep
+ * warns at cxl_nested_lock(), so assert explicitly.
+ */
+ lockdep_assert_not_held(&dev->lockdep_mutex);
+
+ device_lock(dev);
+ cxl_nested_lock(dev);
+}
+
+static inline void cxl_device_unlock(struct device *dev)
+{
+ cxl_nested_unlock(dev);
+ device_unlock(dev);
+}
+#else
+static inline void cxl_nested_lock(struct device *dev)
+{
+}
+
+static inline void cxl_nested_unlock(struct device *dev)
+{
+}
+
+static inline void cxl_device_lock(struct device *dev)
+{
+ device_lock(dev);
+}
+
+static inline void cxl_device_unlock(struct device *dev)
+{
+ device_unlock(dev);
+}
+#endif
#endif /* __CXL_H__ */