Linux CXL
 help / color / mirror / Atom feed
From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
To: Dave Jiang <dave.jiang@intel.com>
Cc: <linux-cxl@vger.kernel.org>, <dave@stgolabs.net>,
	<alison.schofield@intel.com>, <vishal.l.verma@intel.com>,
	<ira.weiny@intel.com>, <dan.j.williams@intel.com>,
	<rrichter@amd.com>
Subject: Re: [PATCH v4 4/9] cxl: Defer dport allocation for switch ports
Date: Wed, 2 Jul 2025 11:18:37 +0100	[thread overview]
Message-ID: <20250702111837.000032c5@huawei.com> (raw)
In-Reply-To: <69efff01-1fff-488c-8bea-496a56cb057d@intel.com>

On Tue, 1 Jul 2025 13:18:16 -0700
Dave Jiang <dave.jiang@intel.com> wrote:

> On 7/1/25 4:10 AM, Jonathan Cameron wrote:
> > On Tue, 24 Jun 2025 14:39:11 -0700
> > Dave Jiang <dave.jiang@intel.com> wrote:
> >   
> >> The current implementation enumerates the dports during the cxl_port
> >> driver probe. Without an endpoint connected, the dport may not be
> >> active during port probe. This scheme may prevent a valid hardware
> >> dport id to be retrieved and MMIO registers to be read when an endpoint
> >> is hot-plugged. Move the dport allocation and setup to behind memdev
> >> probe so the endpoint is guaranteed to be connected.
> >>
> >> In the original enumeration behavior, there are 3 phases (or 2 if no CXL
> >> switches) for port creation. cxl_acpi() creates a Root Port (RP) from the
> >> ACPI0017.N device. Through that it enumerate downstream ports composed
> >> of ACPI0016.N devices through add_host_bridge_dport(). Once done, it
> >> use add_host_bridge_uport() to create the ports that enumerates the PCI
> >> RPs as the dports of these ports. Every time a port is created, the port
> >> driver is attached and drv->probe() is called and
> >> devm_cxl_port_enumerate_dports() is envoked to enumerate and probe
> >> the dports.
> >>
> >> The second phase is if there are any CXL switches. When the pci endpoint
> >> device driver (cxl_pci) calls probe, it will add a mem device and triggers
> >> the cxl_mem->probe(). cxl_mem->probe() calls devm_cxl_enumerate_ports()
> >> and attempts to discovery and create all the ports represent CXL switches.
> >> During this phase, a port is created per switch and the attached dports
> >> are also enumerated and probed.
> >>
> >> The last phase is creating endpoint port which happens for all endpoint
> >> devices.
> >>
> >> In this commit, the port create and its dport probing in cxl_acpi is not
> >> changed. That will be handled in a different patch later on. The behavior
> >> change is only for CXL switch ports. Only the dport that is part of the
> >> path for an endpoint device to the RP will be probed. This happens
> >> naturally by the code walking up the device hierarchy and identifying the
> >> upstream device and the downstream device.
> >>
> >> There are two points where the interception of dport creation happens
> >> during the devm_cxl_enumerate_ports() path. The first location is right
> >> before the function calls add_port_attch_ep() where it does the dport  
> > 
> > attach_ep()
> >   
> >> allocation for the RP. Once the dport is allocated, the iteration path
> >> is reset to the beginning to try again. The second location happens
> >> in add_port_attach_ep() after the location where either the port is
> >> discovered or allocated new if it does not exist.
> >>
> >> Locking of port device during __cxl_port_add_dport() protects modifications
> >> against the port and its dports while multiple endpoints can be probing at
> >> the same time and the same port is being modified concurrently.
> >>
> >> While the decoders are allocated during the port driver probe,
> >> The decoders must also be updated since previously it's all done when all
> >> the dports are setup and now every time a dport is setup per endpoint, the
> >> switch target listing need to be updated with new dport. A
> >> guard(rwsem_write) is used to update decoder targets. This is similar to
> >> when decoder_populate_target() is called and the decoder programming
> >> must be protected.
> >>
> >> Link: https://lore.kernel.org/linux-cxl/20250305100123.3077031-1-rrichter@amd.com/
> >> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> >> ---
> >> v4:
> >> - Allocate dport when they are found via endpoint probe. (Robert)  
> > 
> > A few comments inline. 
> >   
> >> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> >> index b50551601c2e..6e9b5ab69de0 100644
> >> --- a/drivers/cxl/core/pci.c
> >> +++ b/drivers/cxl/core/pci.c
> >> @@ -24,6 +24,44 @@ static unsigned short media_ready_timeout = 60;
> >>  module_param(media_ready_timeout, ushort, 0644);
> >>  MODULE_PARM_DESC(media_ready_timeout, "seconds to wait for media ready");  
> >   
> >>  struct cxl_walk_context {
> >>  	struct pci_bus *bus;
> >>  	struct cxl_port *port;
> >> @@ -1169,3 +1207,53 @@ int cxl_gpf_port_setup(struct cxl_dport *dport)
> >>  
> >>  	return 0;
> >>  }
> >> +
> >> +static int match_dport(struct pci_dev *pdev, void *data)
> >> +{
> >> +	struct cxl_walk_context *ctx = data;
> >> +	int type = pci_pcie_type(pdev);
> >> +
> >> +	if (pdev->bus != ctx->bus)
> >> +		return 0;
> >> +	if (!pci_is_pcie(pdev))
> >> +		return 0;
> >> +	if (type != ctx->type)  
> > 
> > I'm lost.  How would bus have matched, but type not?
> > Add a comment.  
> 
> I don't follow. It could be PCI bus but not the right device type (i.e. not a downstream port or root port). Or do you mean explain that? Sure. 

Miss read. I'd confused bus and subordinate though
even that would not be enough as might be a usp.

So this is fine, ignore me :)




> 
> >   
> >> +		return 0;
> >> +
> >> +	ctx->count++;
> >> +	return 0;
> >> +}
> >> +
> >> +int cxl_port_get_total_dports(struct cxl_port *port)  
> > 
> > See comment below on renaming this given it doesn't return
> > the number.
> >   
> >> +{
> >> +	struct pci_bus *bus = cxl_port_to_pci_bus(port);
> >> +	struct cxl_walk_context ctx;
> >> +	int type;
> >> +
> >> +	if (!bus) {
> >> +		dev_err(&port->dev, "No PCI bus found for port %s\n",
> >> +			dev_name(&port->dev));
> >> +		return -ENXIO;
> >> +	}
> >> +
> >> +	if (pci_is_root_bus(bus))
> >> +		type = PCI_EXP_TYPE_ROOT_PORT;
> >> +	else
> >> +		type = PCI_EXP_TYPE_DOWNSTREAM;
> >> +
> >> +	ctx = (struct cxl_walk_context) {
> >> +		.bus = bus,
> >> +		.type = type,
> >> +	};
> >> +	pci_walk_bus(bus, match_dport, &ctx);
> >> +
> >> +	port->total_dports = ctx.count;
> >> +	if (port->total_dports == 0) {
> >> +		dev_warn(&port->dev, "No dports found for port %s on bus %s\n",
> >> +			 dev_name(&port->dev), bus->name);
> >> +		return -ENXIO;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +EXPORT_SYMBOL_NS_GPL(cxl_port_get_total_dports, "CXL");
> >> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> >> index 9691da831224..3872638c439b 100644
> >> --- a/drivers/cxl/core/port.c
> >> +++ b/drivers/cxl/core/port.c
> >> @@ -1551,6 +1551,134 @@ static resource_size_t find_component_registers(struct device *dev)
> >>  	return map.resource;
> >>  }  
> > 
> > 
> >   
> >> +
> >> +static int devm_cxl_add_dport_by_uport(struct device *uport_dev,
> >> +				       struct device *dport_dev,
> >> +				       struct cxl_dport **dport)
> >> +{
> >> +	*dport = NULL;
> >> +	struct cxl_port *port __free(put_cxl_port) =
> >> +		find_cxl_port_by_uport(uport_dev);
> >> +	if (!port)
> >> +		return -ENODEV;
> >> +
> >> +	guard(device)(&port->dev);
> >> +	return devm_cxl_port_add_dport(port, dport_dev, dport);
> >> +}
> >> +
> >> +static int devm_cxl_add_dport_for_rp(struct device *uport_dev,
> >> +				     struct device *dport_dev,
> >> +				     struct cxl_dport **dport)  
> > 
> > That this sets *dport = NULL lead me to get confused at the caller.
> > Perhaps instead these could return a dport *, NULL or ERR_PTR()
> > instead?  
> 
> Yeah I went back and forth a bit on this one. I needed a way to
distinguish between returning an existing dport vs a newly allocated dport.
I suppose I could return PTR_ERR(-EEXIST) and then try to retrieve that dport again. Thoughts?

Using assignment or not after reporting success on something called 'add' is a rather non intuitive.
I was thinking NULL but -EEXIST is more explicit so agreed that
would work and doesn't look like the handling will be too bad

	dport = devm_cxl_add_dport_for_rp(uport_dev, dport_dev);
	if (!IS_ERR(dport)) /* Added dport so restart enumeration */
		goto retry;
	if (PTR_ERR(dport != -EEXIST))
		return PTR_ERR(dport);

or something along those lines.




  reply	other threads:[~2025-07-02 10:18 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-24 21:39 [PATCH v4 0/9] cxl: Delay HB port and switch dport probing until endpoint dev probe Dave Jiang
2025-06-24 21:39 ` [PATCH v4 1/9] cxl/region: Add decoder check to check_commit_order() Dave Jiang
2025-06-24 21:39 ` [PATCH v4 2/9] cxl: Add helper to detect top of CXL device topology Dave Jiang
2025-06-24 21:39 ` [PATCH v4 3/9] cxl: Add helper to reap dport Dave Jiang
2025-07-01 10:31   ` Jonathan Cameron
2025-06-24 21:39 ` [PATCH v4 4/9] cxl: Defer dport allocation for switch ports Dave Jiang
2025-07-01 11:10   ` Jonathan Cameron
2025-07-01 20:18     ` Dave Jiang
2025-07-02 10:18       ` Jonathan Cameron [this message]
2025-06-24 21:39 ` [PATCH v4 5/9] cxl/test: Add cxl_test support for new dport allocation scheme Dave Jiang
2025-07-01 11:12   ` Jonathan Cameron
2025-06-24 21:39 ` [PATCH v4 6/9] cxl/test: Add mock version of devm_cxl_add_dport_by_dev() Dave Jiang
2025-07-01 11:17   ` Jonathan Cameron
2025-06-24 21:39 ` [PATCH v4 7/9] cxl: Change sslbis handler to only handle single dport Dave Jiang
2025-06-24 21:39 ` [PATCH v4 8/9] cxl: Create an xarray to tie a host bridge to the cxl_root Dave Jiang
2025-07-01 11:20   ` Jonathan Cameron
2025-06-24 21:39 ` [PATCH v4 9/9] cxl: Move enumeration of hostbridge ports to the memdev probe path Dave Jiang
2025-07-01 11:32   ` Jonathan Cameron
2025-07-03 23:22     ` Dave Jiang
2025-07-04  9:39       ` Jonathan Cameron
2025-07-07 18:35         ` Dave Jiang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250702111837.000032c5@huawei.com \
    --to=jonathan.cameron@huawei.com \
    --cc=alison.schofield@intel.com \
    --cc=dan.j.williams@intel.com \
    --cc=dave.jiang@intel.com \
    --cc=dave@stgolabs.net \
    --cc=ira.weiny@intel.com \
    --cc=linux-cxl@vger.kernel.org \
    --cc=rrichter@amd.com \
    --cc=vishal.l.verma@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox