@@ -487,28 +487,22 @@ static int decoder_populate_targets(struct cxl_decoder *cxld,
{
int rc = 0, i;
+ device_lock_assert(&port->dev);
+
if (!target_map)
return 0;
- device_lock(&port->dev);
- if (list_empty(&port->dports)) {
- rc = -EINVAL;
- goto out_unlock;
- }
+ if (list_empty(&port->dports))
+ return -EINVAL;
for (i = 0; i < cxld->nr_targets; i++) {
struct cxl_dport *dport = find_dport(port, target_map[i]);
- if (!dport) {
- rc = -ENXIO;
- goto out_unlock;
- }
+ if (!dport)
+ return -ENXIO;
cxld->target[i] = dport;
}
-out_unlock:
- device_unlock(&port->dev);
-
return rc;
}
@@ -621,7 +615,7 @@ struct cxl_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port)
EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, CXL);
/**
- * cxl_decoder_add - Add a decoder with targets
+ * cxl_decoder_add_locked - Add a decoder with targets
* @cxld: The cxl decoder allocated by cxl_decoder_alloc()
* @target_map: A list of downstream ports that this decoder can direct memory
* traffic to. These numbers should correspond with the port number
@@ -631,12 +625,15 @@ EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, CXL);
* is an endpoint device. A more awkward example is a hostbridge whose root
* ports get hot added (technically possible, though unlikely).
*
- * Context: Process context. Takes and releases the cxld's device lock.
+ * This is the locked variant of cxl_decoder_add().
+ *
+ * Context: Process context. Expects the device lock of the port that owns the
+ * @cxld to be held.
*
* Return: Negative error code if the decoder wasn't properly configured; else
* returns 0.
*/
-int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
+int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map)
{
struct cxl_port *port;
struct device *dev;
@@ -673,6 +670,40 @@ int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
return device_add(dev);
}
+EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, CXL);
+
+/**
+ * cxl_decoder_add - Add a decoder with targets
+ * @cxld: The cxl decoder allocated by cxl_decoder_alloc()
+ * @target_map: A list of downstream ports that this decoder can direct memory
+ * traffic to. These numbers should correspond with the port number
+ * in the PCIe Link Capabilities structure.
+ *
+ * This is the unlocked variant of cxl_decoder_add_locked().
+ * See cxl_decoder_add_locked().
+ *
+ * Context: Process context. Takes and releases the device lock of the port that
+ * owns the @cxld.
+ */
+int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
+{
+ struct cxl_port *port;
+ int rc;
+
+ if (WARN_ON_ONCE(!cxld))
+ return -EINVAL;
+
+ if (WARN_ON_ONCE(IS_ERR(cxld)))
+ return PTR_ERR(cxld);
+
+ port = to_cxl_port(cxld->dev.parent);
+
+ device_lock(&port->dev);
+ rc = cxl_decoder_add_locked(cxld, target_map);
+ device_unlock(&port->dev);
+
+ return rc;
+}
EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, CXL);
static void cxld_unregister(void *dev)
@@ -293,6 +293,7 @@ struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
unsigned int nr_targets);
struct cxl_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port);
+int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map);
int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map);
int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);