Linux CXL
 help / color / mirror / Atom feed
From: "Lucero Palau, Alejandro" <alejandro.lucero-palau@amd.com>
To: Richard Cheng <icheng@nvidia.com>
Cc: linux-cxl@vger.kernel.org, netdev@vger.kernel.org,
	edward.cree@amd.com, davem@davemloft.net, kuba@kernel.org,
	pabeni@redhat.com, edumazet@google.com, dave.jiang@intel.com,
	Alejandro Lucero <alucerop@amd.com>
Subject: Re: [RFC 1/2] cxl/memdev: add support for mutipf device
Date: Sat, 29 Aug 2026 08:06:46 +0100	[thread overview]
Message-ID: <173a8a29-2ea9-4231-815c-c6b0cca3ed80@amd.com> (raw)
In-Reply-To: <apErJUX77f4x02LH@MWDK4CY14F>


On 28/08/2026 09:15, Richard Cheng wrote:
> On Thu, Aug 27, 2026 at 06:44:42PM +0800, Lucero Palau, Alejandro wrote:
>> On 25/08/2026 08:37, Lucero Palau, Alejandro wrote:
>>> On 24/08/2026 09:33, Richard Cheng wrote:
>>>> On Fri, Aug 21, 2026 at 04:51:33PM
>>>> +0800,alejandro.lucero-palau@amd.com wrote:
>>>>> From: Alejandro Lucero<alucerop@amd.com>
>>>>>
>>>>> A PCI device can present multiple Physical Functions(PFs) but the CXL
>>>>> specs restrict to the first one, PF0, the discovery and management of
>>>>> CXL capabilities accessed through a PF0 BAR. Other non-PF0 PFs need to
>>>>> obtain the CXL.mem range to work with somehow.
>>>>>
>>>>> Although this could be handled internally by an accelerator/Type2
>>>>> driver, it requires to properly handle changes to the CXL mem device,
>>>>> mainly its release by the CXL core, but also potential CXL device
>>>>> resets. When this release happens, those other PFs need to be
>>>>> told about
>>>>> it.
>>>>>
>>>>> Implement a way for non-PF0 PFs to register/unregister to the memdev
>>>>> linked to the PF0 device. At memdev release, trigger the release of
>>>>> those non-PF0 PFs devices registered to such memdev from the
>>>>> driver they
>>>>> are bound to.
>>>>>
>> <snip>
>>
>>>> I suggest replacing cxl_get_pf0_memdev() and cxl_put_pf0_memdev()
>>>> with another
>>>> helper, e.g.:
>>>>
>>>> int cxl_memdev_link_consumer(struct device *pf0, struct device
>>>> *consumer, struct range *range);
>>>>    It should live in cxl/core/memdev.c , and the behavior is
>>>> something like
>>>>
>>>> 1. Find PF0's memdev and take a temp ref.
>>>> 2. Lock the memdev
>>>> 3. Verify that the memdev is still registered, driver-bound,
>>>> attached, and has a valid HPA range
>>>> 4. Create a managed devce link via device_link_add(consumer,
>>>> &cxlmd->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
>>>
>>> Interesting approach.
>>>
>>>
>>> Not sure this could do the proper thing though.
>>> DL_FLAG_AUTOREMOVE_CONSUMER seems to remove the link, cxlmd->dev in your
>>> case, when consume driver unbinds ... but it is the other way what we
>>> need. Maybe I do not understand well all the implications with this
>>> approach, so let me study it.
>>
>> I'm having problems just trying to implement the supposedly basic
>> functionality linking the cxlmd device with the non-PF0 device, I mean
>> without thinking about potential races with this approach (I think it has
>> less problems in this regard than my approach).
>>
>>
>> I can use DL_FLAG_AUTOREMOVE_SUPPLIER with the supplier being cxlmd->dev, so
>> at device unbinding it can trigger the non-PF0 device unbinding as well. But
>> it seems all this link code is quite related to PM, so some checks at link
>> creation fail. I have tried using DL_FLAGS_SYNC_STATE_ONLY along with the
>> previous one, but another check precludes the link creation if both are used
>> (See device_link_flag_is_sync_state_only() ).
>>
>>
>> Do you have any advice here?
>>
>>
> Hi Alejandro,
>
> Thanks for trying the device-link approach. I wonder what deivce-link eperiment you actually execute ?
> Though I don't have your HW, maybe we can discuss on the experiment method ?
>
>  From what I can know from the current driver-core behavior is
> - DL_FALG_SYNC_STATE_ONLY | DL_FLAG_AUTOREMOVE_SUPPLIER is rejected by design
> - a sync-state-only link won't enforce consumer unbind
> - DL_FLAG_AUTOREMOVE_SUPPLIER alone is a valid flag combination, so a NULL there depends on runtime state or
>    the specific device relationship
>
> You're right that DL_FLAG_AUTOREMOVE_CONSUMER means the link is removed when the consumer driver unbinds.
> Now we get it more clear that, the autoremove flag control the liftetime of the link, they don't control supplier-to-consumer unbind direction.
>
> For normal managed device link, driver core unbinds active consumers before unbinding the supplier.
> For this case I think DL_FLAG_AUTOREMOVE_CONSUMER is appropriate since the non-PF0 driver creates the dependency during probe and no longer
> needs it after that driver unbinds.


I was confused with the flags. A non-PF0 function should be able to 
delete the link without triggering the unbinding of the supplier, and 
the supplier unbinding should trigger the non-PF0 unbinding. The flag 
seems to do the first one, and the implicit functionality when unbinding 
the supplier does the second thing. So, I think this could do what we need.

However,  I can not (properly) test it, because the supplier is checked 
with device_pm_initialized() and it fails for the memdev device and I 
guess it will with the region device as well. If I remove the check, it 
all works, so maybe adding some support for this case and conditionally 
do such PM check could be the way to go, as it simplifies a lot the 
design. I will study this further and see the implications.


Thanks!


> But I rethink about linking consumer to cxlmd->dev, memdev is not the object whose lifetime defines whether the returned HPA range is valid.
> An open /dev/cxl/memX can keep the memdev object alive even after the EP and region have been torn down.
>
> I am not sure but cxl_region seems like a more accurate supplier, it provides vaid HPA to consumers.
>
> I let GPT sketched the implementation of the API I was thinking about, maybe something like the following.
>
> """
>    int cxl_memdev_link_region_consumer(struct cxl_memdev *cxlmd,
>    				    struct device *consumer,
>    				    struct range *range)
>    {
>    	struct device *decoder_dev __free(put_device) = NULL;
>    	struct device *region_dev __free(put_device) = NULL;
>    	struct cxl_endpoint_decoder *cxled;
>    	struct cxl_region_params *p;
>    	struct cxl_region *cxlr = NULL;
>    	struct cxl_port *endpoint;
>    	struct device_link *link;
>
>    	endpoint = cxlmd->endpoint;
>    	if (!endpoint)
>    		return -EPROBE_DEFER;
>
>    	/*
>    	 * Endpoint removal owns region teardown, so this prevents the
>    	 * endpoint and its decoder children from disappearing while the
>    	 * supplier is being resolved.
>    	 */
>    	guard(device)(&endpoint->dev);
>
>    	if (!endpoint->dev.driver)
>    		return -EPROBE_DEFER;
>
>    	decoder_dev = device_find_child(&endpoint->dev, NULL,
>    					first_mapped_decoder);
>    	if (!decoder_dev)
>    		return -EPROBE_DEFER;
>
>    	cxled = to_cxl_endpoint_decoder(decoder_dev);
>
>    	/*
>    	 * Take an independent region-device reference while the decoder to
>    	 * region association is protected. The association is revalidated
>    	 * below after taking the region device lock.
>    	 */
>    	scoped_guard(rwsem_read, &cxl_rwsem.region) {
>    		cxlr = cxled->cxld.region;
>    		if (!cxlr)
>    			return -EPROBE_DEFER;
>
>    		region_dev = get_device(&cxlr->dev);
>    	}
>
>    	/*
>    	 * Serialize link creation against region driver unbind. Without this,
>    	 * a link could be added after device_links_busy() has already marked
>    	 * the supplier as unbinding and walked its existing consumers.
>    	 */
>    	guard(device)(region_dev);
>    	guard(rwsem_read)(&cxl_rwsem.region);
>    	guard(rwsem_read)(&cxl_rwsem.dpa);
>
>    	p = &cxlr->params;
>
>    	if (!region_dev->driver ||
>    	    cxled->cxld.region != cxlr ||
>    	    p->state != CXL_CONFIG_COMMIT ||
>    	    !p->res ||
>    	    p->nr_targets != 1)
>    		return -EPROBE_DEFER;
>
>    	link = device_link_add(consumer, region_dev,
>    			       DL_FLAG_AUTOREMOVE_CONSUMER);
>    	if (!link)
>    		return -ENXIO;
>
>    	*range = (struct range) {
>    		.start = p->res->start,
>    		.end = p->res->end,
>    	};
>
>    	return 0;
>    }
> """
>
> I think it needs more tweaks, but hope it can give you some idea.
>
> The intended ordering is then,
>
> non-PF0 probe -> validate comitted region -> create (consumer, region) managed link -> copy HPA range -> map the PF slice
> region teardown -> driver core sees an active/probing consumer -> wait -> unbind the non-PF0 driver -> consumer unmaps its HPA slice -> AUTOREMOVE_CONSUMER removes the link -> region teardown removes the decoder
>
> driver core can manage the device references and drops the supplier lock before forcing consumer unbind.
>
> Does it match the behavior you need ?
>
> Best regards,
> Richard Cheng.

  reply	other threads:[~2026-08-29  7:06 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-21 15:51 [RFC 0/2] Type2 multipf support alejandro.lucero-palau
2026-08-21 15:51 ` [RFC 1/2] cxl/memdev: add support for mutipf device alejandro.lucero-palau
2026-08-22 14:43   ` sashiko-bot
2026-08-24  8:33   ` Richard Cheng
2026-08-25  7:37     ` Lucero Palau, Alejandro
2026-08-27 17:44       ` Lucero Palau, Alejandro
2026-08-28  8:15         ` Richard Cheng
2026-08-29  7:06           ` Lucero Palau, Alejandro [this message]
2026-08-21 15:51 ` [RFC 2/2] sfc: add multipf support alejandro.lucero-palau
2026-08-22 14:43   ` sashiko-bot

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=173a8a29-2ea9-4231-815c-c6b0cca3ed80@amd.com \
    --to=alejandro.lucero-palau@amd.com \
    --cc=alucerop@amd.com \
    --cc=dave.jiang@intel.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=edward.cree@amd.com \
    --cc=icheng@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=linux-cxl@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.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