diff mbox series

[05/15] cxl/acpi: Add probe function to detect restricted CXL hosts in RCD mode

Message ID 20220831081603.3415-6-rrichter@amd.com
State Superseded
Delegated to: Dan Williams
Headers show
Series cxl: Add support for Restricted CXL hosts (RCD mode) | expand

Commit Message

Robert Richter Aug. 31, 2022, 8:15 a.m. UTC
Restricted CXL device (RCD) mode (formerly CXL 1.1) uses a different
enumeration scheme other than CXL VH (formerly CXL 2.0). In RCD mode a
host/device (RCH-RCD) pair shows up as a legal PCIe hierarchy with an
ACPI host bridge ("PNP0A08" or "ACPI0016" HID) and RCiEP connected to
it with a description of the CXL device.

Add function cxl_restricted_host_probe() to probe RCD enumerated
devices. The function implements a loop that detects all CXL capable
ACPI PCI root bridges in the system (RCD mode only). The iterator
function cxl_find_next_rch() is introduced to walk through all of the
CXL hosts. The loop will then enable all CXL devices connected to the
host. For now, only implement an empty loop with an iterator that
returns all pci host bridges in the system.

The probe function is triggered by adding an own root device for RCHs.
This is different to CXL VH where an ACPI "ACPI0017" root device
exists. Its detection starts the CXL host detection. In RCD mode such
a device does not necessarily exists, so solve this by creating a
plain platform device that is not an ACPI device and is root only for
RCHs.

Signed-off-by: Robert Richter <rrichter@amd.com>
---
 drivers/cxl/acpi.c | 71 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 70 insertions(+), 1 deletion(-)

Comments

Jonathan Cameron Aug. 31, 2022, 10:08 a.m. UTC | #1
On Wed, 31 Aug 2022 10:15:53 +0200
Robert Richter <rrichter@amd.com> wrote:

> Restricted CXL device (RCD) mode (formerly CXL 1.1) uses a different
> enumeration scheme other than CXL VH (formerly CXL 2.0). In RCD mode a
> host/device (RCH-RCD) pair shows up as a legal PCIe hierarchy with an
> ACPI host bridge ("PNP0A08" or "ACPI0016" HID) and RCiEP connected to
> it with a description of the CXL device.
> 
> Add function cxl_restricted_host_probe() to probe RCD enumerated
> devices. The function implements a loop that detects all CXL capable
> ACPI PCI root bridges in the system (RCD mode only). The iterator
> function cxl_find_next_rch() is introduced to walk through all of the
> CXL hosts. The loop will then enable all CXL devices connected to the
> host. For now, only implement an empty loop with an iterator that
> returns all pci host bridges in the system.
> 
> The probe function is triggered by adding an own root device for RCHs.
> This is different to CXL VH where an ACPI "ACPI0017" root device
> exists. Its detection starts the CXL host detection. In RCD mode such
> a device does not necessarily exists, so solve this by creating a
> plain platform device that is not an ACPI device and is root only for
> RCHs.

If I read this correctly that platform device is created whether or not
there are any cxl devices in the system?

Can we create it only if we find some devices that will be placed
under it later?

Jonathan

> 
> Signed-off-by: Robert Richter <rrichter@amd.com>
> ---
>  drivers/cxl/acpi.c | 71 +++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 70 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
> index 31e104f0210f..a19e3154dd44 100644
> --- a/drivers/cxl/acpi.c
> +++ b/drivers/cxl/acpi.c
> @@ -312,6 +312,33 @@ static int add_root_nvdimm_bridge(struct device *match, void *data)
>  	return 1;
>  }
>  
> +struct pci_host_bridge *cxl_find_next_rch(struct pci_host_bridge *host)
> +{
> +	struct pci_bus *bus = host ? host->bus : NULL;
> +
> +	while ((bus = pci_find_next_bus(bus)) != NULL) {
> +		host = bus ? to_pci_host_bridge(bus->bridge) : NULL;
> +		if (!host)
> +			continue;
> +
> +		dev_dbg(&host->dev, "PCI bridge found\n");
> +
> +		return host;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int __init cxl_restricted_host_probe(struct platform_device *pdev)
> +{
> +	struct pci_host_bridge *host = NULL;
> +
> +	while ((host = cxl_find_next_rch(host)) != NULL) {
> +	}
> +
> +	return 0;
> +}
> +
>  static struct lock_class_key cxl_root_key;
>  
>  static void cxl_acpi_lock_reset_class(void *dev)
> @@ -445,6 +472,13 @@ static int cxl_acpi_probe(struct platform_device *pdev)
>  	struct acpi_device *adev = ACPI_COMPANION(host);
>  	struct cxl_cfmws_context ctx;
>  
> +	/*
> +	 * For RCH (CXL 1.1 hosts) the probe is triggered by a plain
> +	 * platform dev which does not have an acpi companion.
> +	 */
> +	if (!adev)
> +		return cxl_restricted_host_probe(pdev);
> +
>  	device_lock_set_class(&pdev->dev, &cxl_root_key);
>  	rc = devm_add_action_or_reset(&pdev->dev, cxl_acpi_lock_reset_class,
>  				      &pdev->dev);
> @@ -518,6 +552,7 @@ MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
>  
>  static const struct platform_device_id cxl_test_ids[] = {
>  	{ "cxl_acpi" },
> +	{ "cxl_root" },
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(platform, cxl_test_ids);
> @@ -531,7 +566,41 @@ static struct platform_driver cxl_acpi_driver = {
>  	.id_table = cxl_test_ids,
>  };
>  
> -module_platform_driver(cxl_acpi_driver);
> +static void cxl_acpi_device_release(struct device *dev) { }

Why the empty release?  Perhaps introduce this only when it
does something.

> +
> +static struct platform_device cxl_acpi_device = {
> +	.name = "cxl_root",
> +	.id = PLATFORM_DEVID_NONE,
> +	.dev = {
> +		.release = cxl_acpi_device_release,
> +	}
> +};
> +
> +static int __init cxl_host_init(void)
> +{
> +	int rc;
> +
> +	/* Kick off restricted host (CXL 1.1) detection */
> +	rc = platform_device_register(&cxl_acpi_device);
> +	if (rc) {
> +		platform_device_put(&cxl_acpi_device);
> +		return rc;
> +	}
> +	rc = platform_driver_register(&cxl_acpi_driver);
> +	if (rc)
> +		platform_device_unregister(&cxl_acpi_device);
> +	return rc;
> +}
> +
> +static void __exit cxl_host_exit(void)
> +{
> +	platform_driver_unregister(&cxl_acpi_driver);
> +	platform_device_unregister(&cxl_acpi_device);
> +}
> +
> +module_init(cxl_host_init);
> +module_exit(cxl_host_exit);
> +
>  MODULE_LICENSE("GPL v2");
>  MODULE_IMPORT_NS(CXL);
>  MODULE_IMPORT_NS(ACPI);
Robert Richter Sept. 1, 2022, 6:01 a.m. UTC | #2
On 31.08.22 11:08:04, Jonathan Cameron wrote:
> On Wed, 31 Aug 2022 10:15:53 +0200

> Robert Richter <rrichter@amd.com> wrote:
> 
> > Restricted CXL device (RCD) mode (formerly CXL 1.1) uses a different
> > enumeration scheme other than CXL VH (formerly CXL 2.0). In RCD mode a
> > host/device (RCH-RCD) pair shows up as a legal PCIe hierarchy with an
> > ACPI host bridge ("PNP0A08" or "ACPI0016" HID) and RCiEP connected to
> > it with a description of the CXL device.
> > 
> > Add function cxl_restricted_host_probe() to probe RCD enumerated
> > devices. The function implements a loop that detects all CXL capable
> > ACPI PCI root bridges in the system (RCD mode only). The iterator
> > function cxl_find_next_rch() is introduced to walk through all of the
> > CXL hosts. The loop will then enable all CXL devices connected to the
> > host. For now, only implement an empty loop with an iterator that
> > returns all pci host bridges in the system.
> > 
> > The probe function is triggered by adding an own root device for RCHs.
> > This is different to CXL VH where an ACPI "ACPI0017" root device
> > exists. Its detection starts the CXL host detection. In RCD mode such
> > a device does not necessarily exists, so solve this by creating a
> > plain platform device that is not an ACPI device and is root only for
> > RCHs.
> 
> If I read this correctly that platform device is created whether or not
> there are any cxl devices in the system?
> 
> Can we create it only if we find some devices that will be placed
> under it later?

This would move the host detection from probe to init which I wanted
to avoid to better control driver init order dependencies.

I could add a put_device() at the end of a probe so that it will be
released in case no other references use it. This implies the refcount
is maintained for parent devices. Or this needs to be added to. So if
there are no children (hosts) attached to the root device after probe,
it will disappear.

> > @@ -531,7 +566,41 @@ static struct platform_driver cxl_acpi_driver = {
> >  	.id_table = cxl_test_ids,
> >  };
> >  
> > -module_platform_driver(cxl_acpi_driver);
> > +static void cxl_acpi_device_release(struct device *dev) { }
> 
> Why the empty release?  Perhaps introduce this only when it
> does something.

The core device driver requires this in device_release() to be setup.

There is nothing to do as the device is kept in a static struct.
That's why it's empty.

-Robert
Jonathan Cameron Sept. 1, 2022, 10:10 a.m. UTC | #3
On Thu, 1 Sep 2022 08:01:05 +0200
Robert Richter <rrichter@amd.com> wrote:

> On 31.08.22 11:08:04, Jonathan Cameron wrote:
> > On Wed, 31 Aug 2022 10:15:53 +0200  
> 
> > Robert Richter <rrichter@amd.com> wrote:
> >   
> > > Restricted CXL device (RCD) mode (formerly CXL 1.1) uses a different
> > > enumeration scheme other than CXL VH (formerly CXL 2.0). In RCD mode a
> > > host/device (RCH-RCD) pair shows up as a legal PCIe hierarchy with an
> > > ACPI host bridge ("PNP0A08" or "ACPI0016" HID) and RCiEP connected to
> > > it with a description of the CXL device.
> > > 
> > > Add function cxl_restricted_host_probe() to probe RCD enumerated
> > > devices. The function implements a loop that detects all CXL capable
> > > ACPI PCI root bridges in the system (RCD mode only). The iterator
> > > function cxl_find_next_rch() is introduced to walk through all of the
> > > CXL hosts. The loop will then enable all CXL devices connected to the
> > > host. For now, only implement an empty loop with an iterator that
> > > returns all pci host bridges in the system.
> > > 
> > > The probe function is triggered by adding an own root device for RCHs.
> > > This is different to CXL VH where an ACPI "ACPI0017" root device
> > > exists. Its detection starts the CXL host detection. In RCD mode such
> > > a device does not necessarily exists, so solve this by creating a
> > > plain platform device that is not an ACPI device and is root only for
> > > RCHs.  
> > 
> > If I read this correctly that platform device is created whether or not
> > there are any cxl devices in the system?
> > 
> > Can we create it only if we find some devices that will be placed
> > under it later?  
> 
> This would move the host detection from probe to init which I wanted
> to avoid to better control driver init order dependencies.

It's a bit nasty either way.  I can see your reasoning, but
definitely not keen on it if there is a plausible way to avoid.
> 
> I could add a put_device() at the end of a probe so that it will be
> released in case no other references use it. This implies the refcount
> is maintained for parent devices. Or this needs to be added to. So if
> there are no children (hosts) attached to the root device after probe,
> it will disappear.

Unless there is precedence for that, it'll be weird enough to be
hard to maintain.  I guess I can live with the ugliness if we can't
add something new to ACPI to base this off.

> 
> > > @@ -531,7 +566,41 @@ static struct platform_driver cxl_acpi_driver = {
> > >  	.id_table = cxl_test_ids,
> > >  };
> > >  
> > > -module_platform_driver(cxl_acpi_driver);
> > > +static void cxl_acpi_device_release(struct device *dev) { }  
> > 
> > Why the empty release?  Perhaps introduce this only when it
> > does something.  
> 
> The core device driver requires this in device_release() to be setup.
> 
> There is nothing to do as the device is kept in a static struct.
> That's why it's empty.
Ah got it. I'd failed to register the static structure.

> 
> -Robert
Robert Richter Sept. 6, 2022, 7:19 a.m. UTC | #4
On 01.09.22 11:10:38, Jonathan Cameron wrote:
> On Thu, 1 Sep 2022 08:01:05 +0200
> Robert Richter <rrichter@amd.com> wrote:
> > On 31.08.22 11:08:04, Jonathan Cameron wrote:
> > > On Wed, 31 Aug 2022 10:15:53 +0200  
> > > Robert Richter <rrichter@amd.com> wrote:

> > > > The probe function is triggered by adding an own root device for RCHs.
> > > > This is different to CXL VH where an ACPI "ACPI0017" root device
> > > > exists. Its detection starts the CXL host detection. In RCD mode such
> > > > a device does not necessarily exists, so solve this by creating a
> > > > plain platform device that is not an ACPI device and is root only for
> > > > RCHs.  
> > > 
> > > If I read this correctly that platform device is created whether or not
> > > there are any cxl devices in the system?
> > > 
> > > Can we create it only if we find some devices that will be placed
> > > under it later?  
> > 
> > This would move the host detection from probe to init which I wanted
> > to avoid to better control driver init order dependencies.
> 
> It's a bit nasty either way.  I can see your reasoning, but
> definitely not keen on it if there is a plausible way to avoid.
> > 
> > I could add a put_device() at the end of a probe so that it will be
> > released in case no other references use it. This implies the refcount
> > is maintained for parent devices. Or this needs to be added to. So if
> > there are no children (hosts) attached to the root device after probe,
> > it will disappear.
> 
> Unless there is precedence for that, it'll be weird enough to be
> hard to maintain.  I guess I can live with the ugliness if we can't
> add something new to ACPI to base this off.

Let's stay with a put_device() for now. Then, we wont have a stale cxl
root device in the system in case there are no RCD children.

-Robert
Jonathan Cameron Sept. 6, 2022, 8:53 a.m. UTC | #5
On Tue, 6 Sep 2022 09:19:49 +0200
Robert Richter <rrichter@amd.com> wrote:

> On 01.09.22 11:10:38, Jonathan Cameron wrote:
> > On Thu, 1 Sep 2022 08:01:05 +0200
> > Robert Richter <rrichter@amd.com> wrote:  
> > > On 31.08.22 11:08:04, Jonathan Cameron wrote:  
> > > > On Wed, 31 Aug 2022 10:15:53 +0200  
> > > > Robert Richter <rrichter@amd.com> wrote:  
> 
> > > > > The probe function is triggered by adding an own root device for RCHs.
> > > > > This is different to CXL VH where an ACPI "ACPI0017" root device
> > > > > exists. Its detection starts the CXL host detection. In RCD mode such
> > > > > a device does not necessarily exists, so solve this by creating a
> > > > > plain platform device that is not an ACPI device and is root only for
> > > > > RCHs.    
> > > > 
> > > > If I read this correctly that platform device is created whether or not
> > > > there are any cxl devices in the system?
> > > > 
> > > > Can we create it only if we find some devices that will be placed
> > > > under it later?    
> > > 
> > > This would move the host detection from probe to init which I wanted
> > > to avoid to better control driver init order dependencies.  
> > 
> > It's a bit nasty either way.  I can see your reasoning, but
> > definitely not keen on it if there is a plausible way to avoid.  
> > > 
> > > I could add a put_device() at the end of a probe so that it will be
> > > released in case no other references use it. This implies the refcount
> > > is maintained for parent devices. Or this needs to be added to. So if
> > > there are no children (hosts) attached to the root device after probe,
> > > it will disappear.  
> > 
> > Unless there is precedence for that, it'll be weird enough to be
> > hard to maintain.  I guess I can live with the ugliness if we can't
> > add something new to ACPI to base this off.  
> 
> Let's stay with a put_device() for now. Then, we wont have a stale cxl
> root device in the system in case there are no RCD children.
> 
> -Robert
Kind of obvious, but...
Make sure to call that out as an unusual thing to do via cover letter / patch
description so we hopefully get more eyes on this detail..

Jonathan
Bjorn Helgaas Sept. 7, 2022, 6:22 p.m. UTC | #6
On Wed, Aug 31, 2022 at 10:15:53AM +0200, Robert Richter wrote:
> Restricted CXL device (RCD) mode (formerly CXL 1.1) uses a different
> enumeration scheme other than CXL VH (formerly CXL 2.0). In RCD mode a
> host/device (RCH-RCD) pair shows up as a legal PCIe hierarchy with an
> ACPI host bridge ("PNP0A08" or "ACPI0016" HID) and RCiEP connected to
> it with a description of the CXL device.
> 
> Add function cxl_restricted_host_probe() to probe RCD enumerated
> devices. The function implements a loop that detects all CXL capable
> ACPI PCI root bridges in the system (RCD mode only). The iterator
> function cxl_find_next_rch() is introduced to walk through all of the
> CXL hosts. The loop will then enable all CXL devices connected to the
> host. For now, only implement an empty loop with an iterator that
> returns all pci host bridges in the system.
> 
> The probe function is triggered by adding an own root device for RCHs.
> This is different to CXL VH where an ACPI "ACPI0017" root device
> exists. Its detection starts the CXL host detection. In RCD mode such
> a device does not necessarily exists, so solve this by creating a
> plain platform device that is not an ACPI device and is root only for
> RCHs.

Drive-by nitpicks: 
s/PCI root bridges/PCI host bridges/ to match other uses
s/pci host bridges/PCI host bridges/ to match other "PCI" uses
s/does not necessarily exists/does not necessarily exist/
Dan Williams Sept. 8, 2022, 6 a.m. UTC | #7
Robert Richter wrote:
> Restricted CXL device (RCD) mode (formerly CXL 1.1) uses a different
> enumeration scheme other than CXL VH (formerly CXL 2.0). In RCD mode a
> host/device (RCH-RCD) pair shows up as a legal PCIe hierarchy with an
> ACPI host bridge ("PNP0A08" or "ACPI0016" HID) and RCiEP connected to
> it with a description of the CXL device.
> 
> Add function cxl_restricted_host_probe() to probe RCD enumerated
> devices. The function implements a loop that detects all CXL capable
> ACPI PCI root bridges in the system (RCD mode only). The iterator
> function cxl_find_next_rch() is introduced to walk through all of the
> CXL hosts. The loop will then enable all CXL devices connected to the
> host. For now, only implement an empty loop with an iterator that
> returns all pci host bridges in the system.
> 
> The probe function is triggered by adding an own root device for RCHs.
> This is different to CXL VH where an ACPI "ACPI0017" root device
> exists. Its detection starts the CXL host detection. In RCD mode such
> a device does not necessarily exists, so solve this by creating a
> plain platform device that is not an ACPI device and is root only for
> RCHs.

As I mentioned in the cover letter a BIOS that does not provide an
ACPI0017 device is opting out of the possibility OS first error handling
and other OS CXL services. ACPI0017 is mandatory.

Otherwise, its odd to have a module create the device that its driver is
going to drive. That's a backwards driver model and why we proposed
ACPI0017 in the first instance.

> 
> Signed-off-by: Robert Richter <rrichter@amd.com>
> ---
>  drivers/cxl/acpi.c | 71 +++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 70 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
> index 31e104f0210f..a19e3154dd44 100644
> --- a/drivers/cxl/acpi.c
> +++ b/drivers/cxl/acpi.c
> @@ -312,6 +312,33 @@ static int add_root_nvdimm_bridge(struct device *match, void *data)
>  	return 1;
>  }
>  
> +struct pci_host_bridge *cxl_find_next_rch(struct pci_host_bridge *host)
> +{
> +	struct pci_bus *bus = host ? host->bus : NULL;
> +
> +	while ((bus = pci_find_next_bus(bus)) != NULL) {
> +		host = bus ? to_pci_host_bridge(bus->bridge) : NULL;
> +		if (!host)
> +			continue;
> +
> +		dev_dbg(&host->dev, "PCI bridge found\n");
> +
> +		return host;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int __init cxl_restricted_host_probe(struct platform_device *pdev)
> +{
> +	struct pci_host_bridge *host = NULL;
> +
> +	while ((host = cxl_find_next_rch(host)) != NULL) {
> +	}
> +
> +	return 0;
> +}
> +
>  static struct lock_class_key cxl_root_key;
>  
>  static void cxl_acpi_lock_reset_class(void *dev)
> @@ -445,6 +472,13 @@ static int cxl_acpi_probe(struct platform_device *pdev)
>  	struct acpi_device *adev = ACPI_COMPANION(host);
>  	struct cxl_cfmws_context ctx;
>  
> +	/*
> +	 * For RCH (CXL 1.1 hosts) the probe is triggered by a plain
> +	 * platform dev which does not have an acpi companion.
> +	 */
> +	if (!adev)
> +		return cxl_restricted_host_probe(pdev);
> +
>  	device_lock_set_class(&pdev->dev, &cxl_root_key);
>  	rc = devm_add_action_or_reset(&pdev->dev, cxl_acpi_lock_reset_class,
>  				      &pdev->dev);
> @@ -518,6 +552,7 @@ MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
>  
>  static const struct platform_device_id cxl_test_ids[] = {
>  	{ "cxl_acpi" },
> +	{ "cxl_root" },
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(platform, cxl_test_ids);
> @@ -531,7 +566,41 @@ static struct platform_driver cxl_acpi_driver = {
>  	.id_table = cxl_test_ids,
>  };
>  
> -module_platform_driver(cxl_acpi_driver);
> +static void cxl_acpi_device_release(struct device *dev) { }
> +
> +static struct platform_device cxl_acpi_device = {
> +	.name = "cxl_root",
> +	.id = PLATFORM_DEVID_NONE,
> +	.dev = {
> +		.release = cxl_acpi_device_release,
> +	}
> +};
> +
> +static int __init cxl_host_init(void)
> +{
> +	int rc;
> +
> +	/* Kick off restricted host (CXL 1.1) detection */
> +	rc = platform_device_register(&cxl_acpi_device);
> +	if (rc) {
> +		platform_device_put(&cxl_acpi_device);
> +		return rc;
> +	}
> +	rc = platform_driver_register(&cxl_acpi_driver);
> +	if (rc)
> +		platform_device_unregister(&cxl_acpi_device);
> +	return rc;
> +}
> +
> +static void __exit cxl_host_exit(void)
> +{
> +	platform_driver_unregister(&cxl_acpi_driver);
> +	platform_device_unregister(&cxl_acpi_device);
> +}
> +
> +module_init(cxl_host_init);
> +module_exit(cxl_host_exit);
> +
>  MODULE_LICENSE("GPL v2");
>  MODULE_IMPORT_NS(CXL);
>  MODULE_IMPORT_NS(ACPI);
> -- 
> 2.30.2
>
Dan Williams Sept. 8, 2022, 6:11 a.m. UTC | #8
Robert Richter wrote:
> Restricted CXL device (RCD) mode (formerly CXL 1.1) uses a different
> enumeration scheme other than CXL VH (formerly CXL 2.0). In RCD mode a
> host/device (RCH-RCD) pair shows up as a legal PCIe hierarchy with an
> ACPI host bridge ("PNP0A08" or "ACPI0016" HID) and RCiEP connected to
> it with a description of the CXL device.
> 
> Add function cxl_restricted_host_probe() to probe RCD enumerated
> devices. The function implements a loop that detects all CXL capable
> ACPI PCI root bridges in the system (RCD mode only). The iterator
> function cxl_find_next_rch() is introduced to walk through all of the
> CXL hosts. The loop will then enable all CXL devices connected to the
> host. For now, only implement an empty loop with an iterator that
> returns all pci host bridges in the system.
> 
> The probe function is triggered by adding an own root device for RCHs.
> This is different to CXL VH where an ACPI "ACPI0017" root device
> exists. Its detection starts the CXL host detection. In RCD mode such
> a device does not necessarily exists, so solve this by creating a
> plain platform device that is not an ACPI device and is root only for
> RCHs.

These host bridges should be discovered by add_host_bridge_dport(), no?
Unless the BIOS is failing to emit the expected CEDT along with
ACPI0017.
diff mbox series

Patch

diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 31e104f0210f..a19e3154dd44 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -312,6 +312,33 @@  static int add_root_nvdimm_bridge(struct device *match, void *data)
 	return 1;
 }
 
+struct pci_host_bridge *cxl_find_next_rch(struct pci_host_bridge *host)
+{
+	struct pci_bus *bus = host ? host->bus : NULL;
+
+	while ((bus = pci_find_next_bus(bus)) != NULL) {
+		host = bus ? to_pci_host_bridge(bus->bridge) : NULL;
+		if (!host)
+			continue;
+
+		dev_dbg(&host->dev, "PCI bridge found\n");
+
+		return host;
+	}
+
+	return NULL;
+}
+
+static int __init cxl_restricted_host_probe(struct platform_device *pdev)
+{
+	struct pci_host_bridge *host = NULL;
+
+	while ((host = cxl_find_next_rch(host)) != NULL) {
+	}
+
+	return 0;
+}
+
 static struct lock_class_key cxl_root_key;
 
 static void cxl_acpi_lock_reset_class(void *dev)
@@ -445,6 +472,13 @@  static int cxl_acpi_probe(struct platform_device *pdev)
 	struct acpi_device *adev = ACPI_COMPANION(host);
 	struct cxl_cfmws_context ctx;
 
+	/*
+	 * For RCH (CXL 1.1 hosts) the probe is triggered by a plain
+	 * platform dev which does not have an acpi companion.
+	 */
+	if (!adev)
+		return cxl_restricted_host_probe(pdev);
+
 	device_lock_set_class(&pdev->dev, &cxl_root_key);
 	rc = devm_add_action_or_reset(&pdev->dev, cxl_acpi_lock_reset_class,
 				      &pdev->dev);
@@ -518,6 +552,7 @@  MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
 
 static const struct platform_device_id cxl_test_ids[] = {
 	{ "cxl_acpi" },
+	{ "cxl_root" },
 	{ },
 };
 MODULE_DEVICE_TABLE(platform, cxl_test_ids);
@@ -531,7 +566,41 @@  static struct platform_driver cxl_acpi_driver = {
 	.id_table = cxl_test_ids,
 };
 
-module_platform_driver(cxl_acpi_driver);
+static void cxl_acpi_device_release(struct device *dev) { }
+
+static struct platform_device cxl_acpi_device = {
+	.name = "cxl_root",
+	.id = PLATFORM_DEVID_NONE,
+	.dev = {
+		.release = cxl_acpi_device_release,
+	}
+};
+
+static int __init cxl_host_init(void)
+{
+	int rc;
+
+	/* Kick off restricted host (CXL 1.1) detection */
+	rc = platform_device_register(&cxl_acpi_device);
+	if (rc) {
+		platform_device_put(&cxl_acpi_device);
+		return rc;
+	}
+	rc = platform_driver_register(&cxl_acpi_driver);
+	if (rc)
+		platform_device_unregister(&cxl_acpi_device);
+	return rc;
+}
+
+static void __exit cxl_host_exit(void)
+{
+	platform_driver_unregister(&cxl_acpi_driver);
+	platform_device_unregister(&cxl_acpi_device);
+}
+
+module_init(cxl_host_init);
+module_exit(cxl_host_exit);
+
 MODULE_LICENSE("GPL v2");
 MODULE_IMPORT_NS(CXL);
 MODULE_IMPORT_NS(ACPI);