diff mbox series

cxl/region: Remove soft reserve resource at region construction

Message ID 20240612205905.1209448-1-nathan.fontenot@amd.com
State New, archived
Headers show
Series cxl/region: Remove soft reserve resource at region construction | expand

Commit Message

Nathan Fontenot June 12, 2024, 8:59 p.m. UTC
Systems with a BIOS that creates soft reserve iomem resources
for memory ranges covered by CXL devices, the soft reserve resource
needs to be removed when hotplugging a CXL device. Without doing
so a new soft reserve for the memory range cannot be created
during hotplug add.

The previous approach from Alison [1] was to fix up the soft
reserve resource at region release so it longer covers the
memory range for the region being removed.

Instead of waiting for region removal, remove the soft reserve
resource when constructing a region. This is done by walking the
children of the region's parent's resources, finding a soft
reserve resource (if it exists) containing the memory range
for the region and removing the soft reserve prior to inserting
the resource for the region being constructed.

[1] https://lore.kernel.org/linux-cxl/cover.1692638817.git.alison.schofield@intel.com/

Signed-off-by: Nathan Fontenot <nathan.fontenot@amd.com>
---
 drivers/cxl/core/region.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

Comments

Alison Schofield June 13, 2024, 12:30 a.m. UTC | #1
On Wed, Jun 12, 2024 at 03:59:05PM -0500, Nathan Fontenot wrote:
> Systems with a BIOS that creates soft reserve iomem resources
> for memory ranges covered by CXL devices, the soft reserve resource
> needs to be removed when hotplugging a CXL device. Without doing
> so a new soft reserve for the memory range cannot be created
> during hotplug add.

Is a new soft reserved ever created?  I think the reason is to
free up the memory for the new region creation, period. If the
SR exists, userspace cannot 'replace' the region.

> 
> The previous approach from Alison [1] was to fix up the soft
> reserve resource at region release so it longer covers the
> memory range for the region being removed.
> 
> Instead of waiting for region removal, remove the soft reserve
> resource when constructing a region. This is done by walking the
> children of the region's parent's resources, finding a soft
> reserve resource (if it exists) containing the memory range
> for the region and removing the soft reserve prior to inserting
> the resource for the region being constructed.

Is it OK to remove the entire Soft Reserved when that first region
is constructed?  ie. in this setup that removes the soft reserved
before region1 is constructed.

100-600 : CXL Window 0
  100-600 : Soft Reserved
    100-200 : region0
    200-300 : region1


one bit below...


> 
> [1] https://lore.kernel.org/linux-cxl/cover.1692638817.git.alison.schofield@intel.com/
> 
> Signed-off-by: Nathan Fontenot <nathan.fontenot@amd.com>
> ---
>  drivers/cxl/core/region.c | 30 +++++++++++++++++++++++++++++-
>  1 file changed, 29 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index 00a9f0eef8dd..90e5c84230a5 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -3096,6 +3096,34 @@ static int match_region_by_range(struct device *dev, void *data)
>  	return rc;
>  }
>  
> +static int cxl_insert_resource(struct device *dev, struct resource *parent,
> +			       struct resource *res)
> +{
> +	struct resource *soft;
> +	int rc;
> +
> +	/*
> +	 * Find and attempt to remove the SOFT_RESERVED resource
> +	 * (if it exists) that includes the range of the new
> +	 * resource we're inserting.
> +	 */
> +	for (soft = parent->child; soft; soft = soft->sibling) {
> +		if (soft->desc != IORES_DESC_SOFT_RESERVED)
> +			continue;
> +
> +		if (soft->start <= res->start && soft->end >= res->end) {
> +			rc = remove_resource(soft);
> +			if (rc)
> +				dev_warn(dev,
> +					 "Couldn't remove %s resource %llx - %llx\n",

Use %pr format for struct resource.

> +					 soft->name, soft->start, soft->end);
> +			break;
> +		}
> +	}
> +
> +	return insert_resource(parent, res);
> +}
> +
>  /* Establish an empty region covering the given HPA range */
>  static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
>  					   struct cxl_endpoint_decoder *cxled)
> @@ -3142,7 +3170,7 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
>  
>  	*res = DEFINE_RES_MEM_NAMED(hpa->start, range_len(hpa),
>  				    dev_name(&cxlr->dev));
> -	rc = insert_resource(cxlrd->res, res);
> +	rc = cxl_insert_resource(cxlmd->dev.parent, cxlrd->res, res);
>  	if (rc) {
>  		/*
>  		 * Platform-firmware may not have split resources like "System
> -- 
> 2.34.1
>
Dan Williams June 13, 2024, 2:47 a.m. UTC | #2
Nathan Fontenot wrote:
> Systems with a BIOS that creates soft reserve iomem resources
> for memory ranges covered by CXL devices, the soft reserve resource
> needs to be removed when hotplugging a CXL device. Without doing
> so a new soft reserve for the memory range cannot be created
> during hotplug add.
> 
> The previous approach from Alison [1] was to fix up the soft
> reserve resource at region release so it longer covers the
> memory range for the region being removed.
> 
> Instead of waiting for region removal, remove the soft reserve
> resource when constructing a region. This is done by walking the
> children of the region's parent's resources, finding a soft
> reserve resource (if it exists) containing the memory range
> for the region and removing the soft reserve prior to inserting
> the resource for the region being constructed.
> 
> [1] https://lore.kernel.org/linux-cxl/cover.1692638817.git.alison.schofield@intel.com/

Somewhat disappointing that this changelog did not address anything from
this write-up:

http://lore.kernel.org/r/65e0fcae989d6_1138c7294c2@dwillia2-xfh.jf.intel.com.notmuch

> 
> Signed-off-by: Nathan Fontenot <nathan.fontenot@amd.com>
> ---
>  drivers/cxl/core/region.c | 30 +++++++++++++++++++++++++++++-
>  1 file changed, 29 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index 00a9f0eef8dd..90e5c84230a5 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -3096,6 +3096,34 @@ static int match_region_by_range(struct device *dev, void *data)
>  	return rc;
>  }
>  
> +static int cxl_insert_resource(struct device *dev, struct resource *parent,
> +			       struct resource *res)
> +{
> +	struct resource *soft;
> +	int rc;
> +
> +	/*
> +	 * Find and attempt to remove the SOFT_RESERVED resource
> +	 * (if it exists) that includes the range of the new
> +	 * resource we're inserting.
> +	 */

I wish it were this simple:

> +	for (soft = parent->child; soft; soft = soft->sibling) {

This list is protected by resource_lock, unlocked walks are racy.

You might say, "what about walk_iomem_res_desc()", but that does not
allow the callback routine to manipulate the resource tree.

> +		if (soft->desc != IORES_DESC_SOFT_RESERVED)
> +			continue;
> +
> +		if (soft->start <= res->start && soft->end >= res->end) {
> +			rc = remove_resource(soft);

The concern here is what happens if CXL region assembly eventually
fails? There is no fallback possible. Instead the approach I outlined in
65e0fcae989d6_1138c7294c2@dwillia2-xfh.jf.intel.com.notmuch is where I
would like to see this effort go.
Nathan Fontenot June 13, 2024, 6:58 p.m. UTC | #3
On 6/12/24 19:30, Alison Schofield wrote:
> On Wed, Jun 12, 2024 at 03:59:05PM -0500, Nathan Fontenot wrote:
>> Systems with a BIOS that creates soft reserve iomem resources
>> for memory ranges covered by CXL devices, the soft reserve resource
>> needs to be removed when hotplugging a CXL device. Without doing
>> so a new soft reserve for the memory range cannot be created
>> during hotplug add.
> 
> Is a new soft reserved ever created?  I think the reason is to
> free up the memory for the new region creation, period. If the
> SR exists, userspace cannot 'replace' the region.

You're correct. I had started from an bad assumption, there is no
new soft reserve created. If I now understand correctly the issue is
in alloc_hpa() when a user tries to set the size for the region. The call
to alloc_free_mem_region() ensures the address space is not claimed,
which in this case it is by the soft reserve.
  
> 
>>
>> The previous approach from Alison [1] was to fix up the soft
>> reserve resource at region release so it longer covers the
>> memory range for the region being removed.
>>
>> Instead of waiting for region removal, remove the soft reserve
>> resource when constructing a region. This is done by walking the
>> children of the region's parent's resources, finding a soft
>> reserve resource (if it exists) containing the memory range
>> for the region and removing the soft reserve prior to inserting
>> the resource for the region being constructed.
> 
> Is it OK to remove the entire Soft Reserved when that first region
> is constructed?  ie. in this setup that removes the soft reserved
> before region1 is constructed.
> 
> 100-600 : CXL Window 0
>   100-600 : Soft Reserved
>     100-200 : region0
>     200-300 : region1

My approach was thinking that it is ok to go ahead and remove the entire soft reserve.
I couldn't find a reason we needed to keep the soft reserve after this point. I could
be wrong on this.

One different approach I've been looking at is if it's possible to add the CFMWS resource
as a child of the soft reserve. Instead of starting with 

100 - 600 " CXL Window 0
  100 - 600 : Soft Reserved

We would have

100 - 600 : Soft Reserved
  100 - 600 : CXL Window 0

My thinking is that with the soft reserve above the CXL Window we no longer need to
manipulate the soft reserve range on hotplug remove. The alloc_hpa() call for user
set up uses the CXL Window as the base for alloc_free_mem_region() and the soft
reserve wouldn't come into play.

I haven't looked at acpi:add_cxl_resources() enough to know if this is something that
actually can be done safely.


> 
> 
> one bit below...
> 
> 
>>
>> [1] https://lore.kernel.org/linux-cxl/cover.1692638817.git.alison.schofield@intel.com/
>>
>> Signed-off-by: Nathan Fontenot <nathan.fontenot@amd.com>
>> ---
>>  drivers/cxl/core/region.c | 30 +++++++++++++++++++++++++++++-
>>  1 file changed, 29 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
>> index 00a9f0eef8dd..90e5c84230a5 100644
>> --- a/drivers/cxl/core/region.c
>> +++ b/drivers/cxl/core/region.c
>> @@ -3096,6 +3096,34 @@ static int match_region_by_range(struct device *dev, void *data)
>>  	return rc;
>>  }
>>  
>> +static int cxl_insert_resource(struct device *dev, struct resource *parent,
>> +			       struct resource *res)
>> +{
>> +	struct resource *soft;
>> +	int rc;
>> +
>> +	/*
>> +	 * Find and attempt to remove the SOFT_RESERVED resource
>> +	 * (if it exists) that includes the range of the new
>> +	 * resource we're inserting.
>> +	 */
>> +	for (soft = parent->child; soft; soft = soft->sibling) {
>> +		if (soft->desc != IORES_DESC_SOFT_RESERVED)
>> +			continue;
>> +
>> +		if (soft->start <= res->start && soft->end >= res->end) {
>> +			rc = remove_resource(soft);
>> +			if (rc)
>> +				dev_warn(dev,
>> +					 "Couldn't remove %s resource %llx - %llx\n",
> 
> Use %pr format for struct resource.

good catch, I'll update this locally but Dan's response let me know the resource
walk is not something I should be doing.

-Nathan

> 
>> +					 soft->name, soft->start, soft->end);
>> +			break;
>> +		}
>> +	}
>> +
>> +	return insert_resource(parent, res);
>> +}
>> +
>>  /* Establish an empty region covering the given HPA range */
>>  static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
>>  					   struct cxl_endpoint_decoder *cxled)
>> @@ -3142,7 +3170,7 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
>>  
>>  	*res = DEFINE_RES_MEM_NAMED(hpa->start, range_len(hpa),
>>  				    dev_name(&cxlr->dev));
>> -	rc = insert_resource(cxlrd->res, res);
>> +	rc = cxl_insert_resource(cxlmd->dev.parent, cxlrd->res, res);
>>  	if (rc) {
>>  		/*
>>  		 * Platform-firmware may not have split resources like "System
>> -- 
>> 2.34.1
>>
Dan Williams June 13, 2024, 7:31 p.m. UTC | #4
Nathan Fontenot wrote:
[..]
> > 
> > Is it OK to remove the entire Soft Reserved when that first region
> > is constructed?  ie. in this setup that removes the soft reserved
> > before region1 is constructed.
> > 
> > 100-600 : CXL Window 0
> >   100-600 : Soft Reserved
> >     100-200 : region0
> >     200-300 : region1
> 
> My approach was thinking that it is ok to go ahead and remove the entire soft reserve.
> I couldn't find a reason we needed to keep the soft reserve after this point. I could
> be wrong on this.
> 
> One different approach I've been looking at is if it's possible to add the CFMWS resource
> as a child of the soft reserve. Instead of starting with 
> 
> 100 - 600 " CXL Window 0
>   100 - 600 : Soft Reserved
> 
> We would have
> 
> 100 - 600 : Soft Reserved
>   100 - 600 : CXL Window 0
> 
> My thinking is that with the soft reserve above the CXL Window we no longer need to
> manipulate the soft reserve range on hotplug remove. The alloc_hpa() call for user
> set up uses the CXL Window as the base for alloc_free_mem_region() and the soft
> reserve wouldn't come into play.
> 
> I haven't looked at acpi:add_cxl_resources() enough to know if this is something that
> actually can be done safely.

Could you please stop trying to invent new approaches and respond to the
one on the table?
Nathan Fontenot June 13, 2024, 8:11 p.m. UTC | #5
On 6/13/24 14:31, Dan Williams wrote:
> Nathan Fontenot wrote:
> [..]
>>>
>>> Is it OK to remove the entire Soft Reserved when that first region
>>> is constructed?  ie. in this setup that removes the soft reserved
>>> before region1 is constructed.
>>>
>>> 100-600 : CXL Window 0
>>>   100-600 : Soft Reserved
>>>     100-200 : region0
>>>     200-300 : region1
>>
>> My approach was thinking that it is ok to go ahead and remove the entire soft reserve.
>> I couldn't find a reason we needed to keep the soft reserve after this point. I could
>> be wrong on this.
>>
>> One different approach I've been looking at is if it's possible to add the CFMWS resource
>> as a child of the soft reserve. Instead of starting with 
>>
>> 100 - 600 " CXL Window 0
>>   100 - 600 : Soft Reserved
>>
>> We would have
>>
>> 100 - 600 : Soft Reserved
>>   100 - 600 : CXL Window 0
>>
>> My thinking is that with the soft reserve above the CXL Window we no longer need to
>> manipulate the soft reserve range on hotplug remove. The alloc_hpa() call for user
>> set up uses the CXL Window as the base for alloc_free_mem_region() and the soft
>> reserve wouldn't come into play.
>>
>> I haven't looked at acpi:add_cxl_resources() enough to know if this is something that
>> actually can be done safely.
> 
> Could you please stop trying to invent new approaches and respond to the
> one on the table?

Going back through the previous conversation, I was just trying to explore different options.

-Nathan
diff mbox series

Patch

diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 00a9f0eef8dd..90e5c84230a5 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -3096,6 +3096,34 @@  static int match_region_by_range(struct device *dev, void *data)
 	return rc;
 }
 
+static int cxl_insert_resource(struct device *dev, struct resource *parent,
+			       struct resource *res)
+{
+	struct resource *soft;
+	int rc;
+
+	/*
+	 * Find and attempt to remove the SOFT_RESERVED resource
+	 * (if it exists) that includes the range of the new
+	 * resource we're inserting.
+	 */
+	for (soft = parent->child; soft; soft = soft->sibling) {
+		if (soft->desc != IORES_DESC_SOFT_RESERVED)
+			continue;
+
+		if (soft->start <= res->start && soft->end >= res->end) {
+			rc = remove_resource(soft);
+			if (rc)
+				dev_warn(dev,
+					 "Couldn't remove %s resource %llx - %llx\n",
+					 soft->name, soft->start, soft->end);
+			break;
+		}
+	}
+
+	return insert_resource(parent, res);
+}
+
 /* Establish an empty region covering the given HPA range */
 static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
 					   struct cxl_endpoint_decoder *cxled)
@@ -3142,7 +3170,7 @@  static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
 
 	*res = DEFINE_RES_MEM_NAMED(hpa->start, range_len(hpa),
 				    dev_name(&cxlr->dev));
-	rc = insert_resource(cxlrd->res, res);
+	rc = cxl_insert_resource(cxlmd->dev.parent, cxlrd->res, res);
 	if (rc) {
 		/*
 		 * Platform-firmware may not have split resources like "System