Commit 0c0df631 authored by Dan Williams's avatar Dan Williams
Browse files

Merge branch 'for-6.5/cxl-rch-eh' into for-6.5/cxl

Pick up the first half of the RCH error handling series. The back half
needs some fixups for test regressions. Small conflicts with the PMU
work around register enumeration and setup helpers.
parents d2f9fe69 5d2ffbe4
Loading
Loading
Loading
Loading
+116 −90
Original line number Diff line number Diff line
@@ -327,66 +327,21 @@ __mock struct acpi_device *to_cxl_host_bridge(struct device *host,
	return NULL;
}

/*
 * A host bridge is a dport to a CFMWS decode and it is a uport to the
 * dport (PCIe Root Ports) in the host bridge.
 */
static int add_host_bridge_uport(struct device *match, void *arg)
{
	struct cxl_port *root_port = arg;
	struct device *host = root_port->dev.parent;
	struct acpi_device *hb = to_cxl_host_bridge(host, match);
	struct acpi_pci_root *pci_root;
	struct cxl_dport *dport;
	struct cxl_port *port;
	struct device *bridge;
	int rc;

	if (!hb)
		return 0;

	pci_root = acpi_pci_find_root(hb->handle);
	bridge = pci_root->bus->bridge;
	dport = cxl_find_dport_by_dev(root_port, bridge);
	if (!dport) {
		dev_dbg(host, "host bridge expected and not found\n");
		return 0;
	}

	if (dport->rch) {
		dev_info(bridge, "host supports CXL (restricted)\n");
		return 0;
	}

	rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus);
	if (rc)
		return rc;

	port = devm_cxl_add_port(host, bridge, dport->component_reg_phys,
				 dport);
	if (IS_ERR(port))
		return PTR_ERR(port);

	dev_info(bridge, "host supports CXL\n");

	return 0;
}

/* Note, @dev is used by mock_acpi_table_parse_cedt() */
struct cxl_chbs_context {
	struct device *dev;
	unsigned long long uid;
	resource_size_t rcrb;
	resource_size_t chbcr;
	resource_size_t base;
	u32 cxl_version;
};

static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
static int cxl_get_chbs_iter(union acpi_subtable_headers *header, void *arg,
			     const unsigned long end)
{
	struct cxl_chbs_context *ctx = arg;
	struct acpi_cedt_chbs *chbs;

	if (ctx->chbcr)
	if (ctx->base != CXL_RESOURCE_NONE)
		return 0;

	chbs = (struct acpi_cedt_chbs *) header;
@@ -395,23 +350,39 @@ static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
		return 0;

	ctx->cxl_version = chbs->cxl_version;
	ctx->rcrb = CXL_RESOURCE_NONE;
	ctx->chbcr = CXL_RESOURCE_NONE;

	if (!chbs->base)
		return 0;

	if (chbs->cxl_version != ACPI_CEDT_CHBS_VERSION_CXL11) {
		ctx->chbcr = chbs->base;
	if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11 &&
	    chbs->length != CXL_RCRB_SIZE)
		return 0;
	}

	if (chbs->length != CXL_RCRB_SIZE)
	ctx->base = chbs->base;

	return 0;
}

	ctx->rcrb = chbs->base;
	ctx->chbcr = cxl_rcrb_to_component(ctx->dev, chbs->base,
					   CXL_RCRB_DOWNSTREAM);
static int cxl_get_chbs(struct device *dev, struct acpi_device *hb,
			struct cxl_chbs_context *ctx)
{
	unsigned long long uid;
	int rc;

	rc = acpi_evaluate_integer(hb->handle, METHOD_NAME__UID, NULL, &uid);
	if (rc != AE_OK) {
		dev_err(dev, "unable to retrieve _UID\n");
		return -ENOENT;
	}

	dev_dbg(dev, "UID found: %lld\n", uid);
	*ctx = (struct cxl_chbs_context) {
		.dev = dev,
		.uid = uid,
		.base = CXL_RESOURCE_NONE,
		.cxl_version = UINT_MAX,
	};

	acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbs_iter, ctx);

	return 0;
}
@@ -420,7 +391,6 @@ static int add_host_bridge_dport(struct device *match, void *arg)
{
	acpi_status rc;
	struct device *bridge;
	unsigned long long uid;
	struct cxl_dport *dport;
	struct cxl_chbs_context ctx;
	struct acpi_pci_root *pci_root;
@@ -431,47 +401,103 @@ static int add_host_bridge_dport(struct device *match, void *arg)
	if (!hb)
		return 0;

	rc = acpi_evaluate_integer(hb->handle, METHOD_NAME__UID, NULL, &uid);
	if (rc != AE_OK) {
		dev_err(match, "unable to retrieve _UID\n");
		return -ENODEV;
	rc = cxl_get_chbs(match, hb, &ctx);
	if (rc)
		return rc;

	if (ctx.cxl_version == UINT_MAX) {
		dev_warn(match, "No CHBS found for Host Bridge (UID %lld)\n",
			 ctx.uid);
		return 0;
	}

	dev_dbg(match, "UID found: %lld\n", uid);
	if (ctx.base == CXL_RESOURCE_NONE) {
		dev_warn(match, "CHBS invalid for Host Bridge (UID %lld)\n",
			 ctx.uid);
		return 0;
	}

	ctx = (struct cxl_chbs_context) {
		.dev = match,
		.uid = uid,
	};
	acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbcr, &ctx);
	pci_root = acpi_pci_find_root(hb->handle);
	bridge = pci_root->bus->bridge;

	if (!ctx.chbcr) {
		dev_warn(match, "No CHBS found for Host Bridge (UID %lld)\n",
			 uid);
		return 0;
	/*
	 * In RCH mode, bind the component regs base to the dport. In
	 * VH mode it will be bound to the CXL host bridge's port
	 * object later in add_host_bridge_uport().
	 */
	if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) {
		dev_dbg(match, "RCRB found for UID %lld: %pa\n", ctx.uid,
			&ctx.base);
		dport = devm_cxl_add_rch_dport(root_port, bridge, ctx.uid,
					       ctx.base);
	} else {
		dport = devm_cxl_add_dport(root_port, bridge, ctx.uid,
					   CXL_RESOURCE_NONE);
	}

	if (ctx.rcrb != CXL_RESOURCE_NONE)
		dev_dbg(match, "RCRB found for UID %lld: %pa\n", uid, &ctx.rcrb);
	if (IS_ERR(dport))
		return PTR_ERR(dport);

	if (ctx.chbcr == CXL_RESOURCE_NONE) {
		dev_warn(match, "CHBCR invalid for Host Bridge (UID %lld)\n",
			 uid);
	return 0;
}

	dev_dbg(match, "CHBCR found: %pa\n", &ctx.chbcr);
/*
 * A host bridge is a dport to a CFMWS decode and it is a uport to the
 * dport (PCIe Root Ports) in the host bridge.
 */
static int add_host_bridge_uport(struct device *match, void *arg)
{
	struct cxl_port *root_port = arg;
	struct device *host = root_port->dev.parent;
	struct acpi_device *hb = to_cxl_host_bridge(host, match);
	struct acpi_pci_root *pci_root;
	struct cxl_dport *dport;
	struct cxl_port *port;
	struct device *bridge;
	struct cxl_chbs_context ctx;
	resource_size_t component_reg_phys;
	int rc;

	if (!hb)
		return 0;

	pci_root = acpi_pci_find_root(hb->handle);
	bridge = pci_root->bus->bridge;
	if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11)
		dport = devm_cxl_add_rch_dport(root_port, bridge, uid,
					       ctx.chbcr, ctx.rcrb);
	else
		dport = devm_cxl_add_dport(root_port, bridge, uid,
					   ctx.chbcr);
	if (IS_ERR(dport))
		return PTR_ERR(dport);
	dport = cxl_find_dport_by_dev(root_port, bridge);
	if (!dport) {
		dev_dbg(host, "host bridge expected and not found\n");
		return 0;
	}

	if (dport->rch) {
		dev_info(bridge, "host supports CXL (restricted)\n");
		return 0;
	}

	rc = cxl_get_chbs(match, hb, &ctx);
	if (rc)
		return rc;

	if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) {
		dev_warn(bridge,
			 "CXL CHBS version mismatch, skip port registration\n");
		return 0;
	}

	component_reg_phys = ctx.base;
	if (component_reg_phys != CXL_RESOURCE_NONE)
		dev_dbg(match, "CHBCR found for UID %lld: %pa\n",
			ctx.uid, &component_reg_phys);

	rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus);
	if (rc)
		return rc;

	port = devm_cxl_add_port(host, bridge, component_reg_phys, dport);
	if (IS_ERR(port))
		return PTR_ERR(port);

	dev_info(bridge, "host supports CXL\n");

	return 0;
}
+10 −0
Original line number Diff line number Diff line
@@ -64,6 +64,16 @@ int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size);
int cxl_dpa_free(struct cxl_endpoint_decoder *cxled);
resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled);
resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled);

enum cxl_rcrb {
	CXL_RCRB_DOWNSTREAM,
	CXL_RCRB_UPSTREAM,
};
struct cxl_rcrb_info;
resource_size_t __rcrb_to_component(struct device *dev,
				    struct cxl_rcrb_info *ri,
				    enum cxl_rcrb which);

extern struct rw_semaphore cxl_dpa_rwsem;

int cxl_memdev_init(void);
+2 −2
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
				struct cxl_component_regs *regs)
{
	struct cxl_register_map map = {
		.dev = &port->dev,
		.resource = port->component_reg_phys,
		.base = crb,
		.max_size = CXL_COMPONENT_REG_BLOCK_SIZE,
@@ -97,8 +98,7 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
		return -ENODEV;
	}

	return cxl_map_component_regs(&port->dev, regs, &map,
				      BIT(CXL_CM_CAP_CAP_ID_HDM));
	return cxl_map_component_regs(&map, regs, BIT(CXL_CM_CAP_CAP_ID_HDM));
}

static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
+2 −2
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ static int match_add_dports(struct pci_dev *pdev, void *data)

/**
 * devm_cxl_port_enumerate_dports - enumerate downstream ports of the upstream port
 * @port: cxl_port whose ->uport is the upstream of dports to be enumerated
 * @port: cxl_port whose ->uport_dev is the upstream of dports to be enumerated
 *
 * Returns a positive number of dports enumerated or a negative error
 * code.
@@ -603,7 +603,7 @@ static int cxl_cdat_read_table(struct device *dev,
 */
void read_cdat_data(struct cxl_port *port)
{
	struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport);
	struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
	struct device *host = cxlmd->dev.parent;
	struct device *dev = &port->dev;
	struct pci_doe_mb *cdat_doe;
+105 −45
Original line number Diff line number Diff line
@@ -563,9 +563,9 @@ static void unregister_port(void *_port)
	 * unregistered while holding their parent port lock.
	 */
	if (!parent)
		lock_dev = port->uport;
		lock_dev = port->uport_dev;
	else if (is_cxl_root(parent))
		lock_dev = parent->uport;
		lock_dev = parent->uport_dev;
	else
		lock_dev = &parent->dev;

@@ -585,7 +585,8 @@ static int devm_cxl_link_uport(struct device *host, struct cxl_port *port)
{
	int rc;

	rc = sysfs_create_link(&port->dev.kobj, &port->uport->kobj, "uport");
	rc = sysfs_create_link(&port->dev.kobj, &port->uport_dev->kobj,
			       "uport");
	if (rc)
		return rc;
	return devm_add_action_or_reset(host, cxl_unlink_uport, port);
@@ -607,7 +608,7 @@ static int devm_cxl_link_parent_dport(struct device *host,
	if (!parent_dport)
		return 0;

	rc = sysfs_create_link(&port->dev.kobj, &parent_dport->dport->kobj,
	rc = sysfs_create_link(&port->dev.kobj, &parent_dport->dport_dev->kobj,
			       "parent_dport");
	if (rc)
		return rc;
@@ -616,7 +617,7 @@ static int devm_cxl_link_parent_dport(struct device *host,

static struct lock_class_key cxl_port_key;

static struct cxl_port *cxl_port_alloc(struct device *uport,
static struct cxl_port *cxl_port_alloc(struct device *uport_dev,
				       resource_size_t component_reg_phys,
				       struct cxl_dport *parent_dport)
{
@@ -632,7 +633,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport,
	if (rc < 0)
		goto err;
	port->id = rc;
	port->uport = uport;
	port->uport_dev = uport_dev;

	/*
	 * The top-level cxl_port "cxl_root" does not have a cxl_port as
@@ -660,12 +661,13 @@ static struct cxl_port *cxl_port_alloc(struct device *uport,
		if (iter->host_bridge)
			port->host_bridge = iter->host_bridge;
		else if (parent_dport->rch)
			port->host_bridge = parent_dport->dport;
			port->host_bridge = parent_dport->dport_dev;
		else
			port->host_bridge = iter->uport;
		dev_dbg(uport, "host-bridge: %s\n", dev_name(port->host_bridge));
			port->host_bridge = iter->uport_dev;
		dev_dbg(uport_dev, "host-bridge: %s\n",
			dev_name(port->host_bridge));
	} else
		dev->parent = uport;
		dev->parent = uport_dev;

	port->component_reg_phys = component_reg_phys;
	ida_init(&port->decoder_ida);
@@ -688,8 +690,38 @@ static struct cxl_port *cxl_port_alloc(struct device *uport,
	return ERR_PTR(rc);
}

static int cxl_setup_comp_regs(struct device *dev, struct cxl_register_map *map,
			       resource_size_t component_reg_phys)
{
	if (component_reg_phys == CXL_RESOURCE_NONE)
		return 0;

	*map = (struct cxl_register_map) {
		.dev = dev,
		.reg_type = CXL_REGLOC_RBI_COMPONENT,
		.resource = component_reg_phys,
		.max_size = CXL_COMPONENT_REG_BLOCK_SIZE,
	};

	return cxl_setup_regs(map);
}

static inline int cxl_port_setup_regs(struct cxl_port *port,
				      resource_size_t component_reg_phys)
{
	return cxl_setup_comp_regs(&port->dev, &port->comp_map,
				   component_reg_phys);
}

static inline int cxl_dport_setup_regs(struct cxl_dport *dport,
				       resource_size_t component_reg_phys)
{
	return cxl_setup_comp_regs(dport->dport_dev, &dport->comp_map,
				   component_reg_phys);
}

static struct cxl_port *__devm_cxl_add_port(struct device *host,
					    struct device *uport,
					    struct device *uport_dev,
					    resource_size_t component_reg_phys,
					    struct cxl_dport *parent_dport)
{
@@ -697,12 +729,12 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
	struct device *dev;
	int rc;

	port = cxl_port_alloc(uport, component_reg_phys, parent_dport);
	port = cxl_port_alloc(uport_dev, component_reg_phys, parent_dport);
	if (IS_ERR(port))
		return port;

	dev = &port->dev;
	if (is_cxl_memdev(uport))
	if (is_cxl_memdev(uport_dev))
		rc = dev_set_name(dev, "endpoint%d", port->id);
	else if (parent_dport)
		rc = dev_set_name(dev, "port%d", port->id);
@@ -711,6 +743,10 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
	if (rc)
		goto err;

	rc = cxl_port_setup_regs(port, component_reg_phys);
	if (rc)
		goto err;

	rc = device_add(dev);
	if (rc)
		goto err;
@@ -737,28 +773,29 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
/**
 * devm_cxl_add_port - register a cxl_port in CXL memory decode hierarchy
 * @host: host device for devm operations
 * @uport: "physical" device implementing this upstream port
 * @uport_dev: "physical" device implementing this upstream port
 * @component_reg_phys: (optional) for configurable cxl_port instances
 * @parent_dport: next hop up in the CXL memory decode hierarchy
 */
struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
struct cxl_port *devm_cxl_add_port(struct device *host,
				   struct device *uport_dev,
				   resource_size_t component_reg_phys,
				   struct cxl_dport *parent_dport)
{
	struct cxl_port *port, *parent_port;

	port = __devm_cxl_add_port(host, uport, component_reg_phys,
	port = __devm_cxl_add_port(host, uport_dev, component_reg_phys,
				   parent_dport);

	parent_port = parent_dport ? parent_dport->port : NULL;
	if (IS_ERR(port)) {
		dev_dbg(uport, "Failed to add%s%s%s: %ld\n",
		dev_dbg(uport_dev, "Failed to add%s%s%s: %ld\n",
			parent_port ? " port to " : "",
			parent_port ? dev_name(&parent_port->dev) : "",
			parent_port ? "" : " root port",
			PTR_ERR(port));
	} else {
		dev_dbg(uport, "%s added%s%s%s\n",
		dev_dbg(uport_dev, "%s added%s%s%s\n",
			dev_name(&port->dev),
			parent_port ? " to " : "",
			parent_port ? dev_name(&parent_port->dev) : "",
@@ -775,33 +812,34 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port)
	if (is_cxl_root(port))
		return NULL;

	if (dev_is_pci(port->uport)) {
		struct pci_dev *pdev = to_pci_dev(port->uport);
	if (dev_is_pci(port->uport_dev)) {
		struct pci_dev *pdev = to_pci_dev(port->uport_dev);

		return pdev->subordinate;
	}

	return xa_load(&cxl_root_buses, (unsigned long)port->uport);
	return xa_load(&cxl_root_buses, (unsigned long)port->uport_dev);
}
EXPORT_SYMBOL_NS_GPL(cxl_port_to_pci_bus, CXL);

static void unregister_pci_bus(void *uport)
static void unregister_pci_bus(void *uport_dev)
{
	xa_erase(&cxl_root_buses, (unsigned long)uport);
	xa_erase(&cxl_root_buses, (unsigned long)uport_dev);
}

int devm_cxl_register_pci_bus(struct device *host, struct device *uport,
int devm_cxl_register_pci_bus(struct device *host, struct device *uport_dev,
			      struct pci_bus *bus)
{
	int rc;

	if (dev_is_pci(uport))
	if (dev_is_pci(uport_dev))
		return -EINVAL;

	rc = xa_insert(&cxl_root_buses, (unsigned long)uport, bus, GFP_KERNEL);
	rc = xa_insert(&cxl_root_buses, (unsigned long)uport_dev, bus,
		       GFP_KERNEL);
	if (rc)
		return rc;
	return devm_add_action_or_reset(host, unregister_pci_bus, uport);
	return devm_add_action_or_reset(host, unregister_pci_bus, uport_dev);
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_register_pci_bus, CXL);

@@ -849,22 +887,22 @@ static struct cxl_dport *find_dport(struct cxl_port *port, int id)
	return NULL;
}

static int add_dport(struct cxl_port *port, struct cxl_dport *new)
static int add_dport(struct cxl_port *port, struct cxl_dport *dport)
{
	struct cxl_dport *dup;
	int rc;

	device_lock_assert(&port->dev);
	dup = find_dport(port, new->port_id);
	dup = find_dport(port, dport->port_id);
	if (dup) {
		dev_err(&port->dev,
			"unable to add dport%d-%s non-unique port id (%s)\n",
			new->port_id, dev_name(new->dport),
			dev_name(dup->dport));
			dport->port_id, dev_name(dport->dport_dev),
			dev_name(dup->dport_dev));
		return -EBUSY;
	}

	rc = xa_insert(&port->dports, (unsigned long)new->dport, new,
	rc = xa_insert(&port->dports, (unsigned long)dport->dport_dev, dport,
		       GFP_KERNEL);
	if (rc)
		return rc;
@@ -897,8 +935,8 @@ static void cxl_dport_remove(void *data)
	struct cxl_dport *dport = data;
	struct cxl_port *port = dport->port;

	xa_erase(&port->dports, (unsigned long) dport->dport);
	put_device(dport->dport);
	xa_erase(&port->dports, (unsigned long) dport->dport_dev);
	put_device(dport->dport_dev);
}

static void cxl_dport_unlink(void *data)
@@ -922,7 +960,7 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
	int rc;

	if (is_cxl_root(port))
		host = port->uport;
		host = port->uport_dev;
	else
		host = &port->dev;

@@ -940,13 +978,29 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
	if (!dport)
		return ERR_PTR(-ENOMEM);

	dport->dport = dport_dev;
	if (rcrb != CXL_RESOURCE_NONE) {
		dport->rcrb.base = rcrb;
		component_reg_phys = __rcrb_to_component(dport_dev, &dport->rcrb,
							 CXL_RCRB_DOWNSTREAM);
		if (component_reg_phys == CXL_RESOURCE_NONE) {
			dev_warn(dport_dev, "Invalid Component Registers in RCRB");
			return ERR_PTR(-ENXIO);
		}

		dport->rch = true;
	}

	if (component_reg_phys != CXL_RESOURCE_NONE)
		dev_dbg(dport_dev, "Component Registers found for dport: %pa\n",
			&component_reg_phys);

	dport->dport_dev = dport_dev;
	dport->port_id = port_id;
	dport->component_reg_phys = component_reg_phys;
	dport->port = port;
	if (rcrb != CXL_RESOURCE_NONE)
		dport->rch = true;
	dport->rcrb = rcrb;

	rc = cxl_dport_setup_regs(dport, component_reg_phys);
	if (rc)
		return ERR_PTR(rc);

	cond_cxl_root_lock(port);
	rc = add_dport(port, dport);
@@ -1006,14 +1060,12 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport, CXL);
 * @port: the cxl_port that references this dport
 * @dport_dev: firmware or PCI device representing the dport
 * @port_id: identifier for this dport in a decoder's target list
 * @component_reg_phys: optional location of CXL component registers
 * @rcrb: mandatory location of a Root Complex Register Block
 *
 * See CXL 3.0 9.11.8 CXL Devices Attached to an RCH
 */
struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
					 struct device *dport_dev, int port_id,
					 resource_size_t component_reg_phys,
					 resource_size_t rcrb)
{
	struct cxl_dport *dport;
@@ -1024,7 +1076,7 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
	}

	dport = __devm_cxl_add_dport(port, dport_dev, port_id,
				     component_reg_phys, rcrb);
				     CXL_RESOURCE_NONE, rcrb);
	if (IS_ERR(dport)) {
		dev_dbg(dport_dev, "failed to add RCH dport to %s: %ld\n",
			dev_name(&port->dev), PTR_ERR(dport));
@@ -1366,7 +1418,7 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd,
		rc = PTR_ERR(port);
	else {
		dev_dbg(&cxlmd->dev, "add to new port %s:%s\n",
			dev_name(&port->dev), dev_name(port->uport));
			dev_name(&port->dev), dev_name(port->uport_dev));
		rc = cxl_add_ep(dport, &cxlmd->dev);
		if (rc == -EBUSY) {
			/*
@@ -1428,7 +1480,8 @@ int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd)
		if (port) {
			dev_dbg(&cxlmd->dev,
				"found already registered port %s:%s\n",
				dev_name(&port->dev), dev_name(port->uport));
				dev_name(&port->dev),
				dev_name(port->uport_dev));
			rc = cxl_add_ep(dport, &cxlmd->dev);

			/*
@@ -1468,6 +1521,13 @@ int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd)
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, CXL);

struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev,
				   struct cxl_dport **dport)
{
	return find_cxl_port(pdev->dev.parent, dport);
}
EXPORT_SYMBOL_NS_GPL(cxl_pci_find_port, CXL);

struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
				   struct cxl_dport **dport)
{
Loading