Linux PCI subsystem development
 help / color / mirror / Atom feed
From: Alison Schofield <alison.schofield@intel.com>
To: Srirangan Madhavan <smadhavan@nvidia.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>,
	Dave Jiang <dave.jiang@intel.com>,
	Davidlohr Bueso <dave@stgolabs.net>,
	Ira Weiny <ira.weiny@intel.com>,
	Jonathan Cameron <jic23@kernel.org>,
	Vishal Verma <vishal.l.verma@intel.com>,
	<linux-cxl@vger.kernel.org>, <linux-pci@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>,
	Alex Williamson <alex.williamson@redhat.com>, <vsethi@nvidia.com>,
	<alwilliamson@nvidia.com>,
	Sai Yashwanth Reddy Kancherla <skancherla@nvidia.com>,
	Vishal Aslot <vaslot@nvidia.com>,
	Manish Honap <mhonap@nvidia.com>, Jiandi An <jan@nvidia.com>,
	Richard Cheng <icheng@nvidia.com>, <linux-tegra@vger.kernel.org>
Subject: Re: [PATCH v15 09/16] PCI/CXL: Cache endpoint HDM state during PCI enumeration
Date: Wed, 28 Oct 2026 20:19:15 -0700	[thread overview]
Message-ID: <auK7MxeCI2fsUNZC@aschofie-mobl2.lan> (raw)
In-Reply-To: <20261011021422.3428136-10-smadhavan@nvidia.com>

On Sun, Oct 11, 2026 at 02:14:15AM +0000, Srirangan Madhavan wrote:
> Cache HDM state in pci_dev->hdm after BAR resource setup and before driver
> binding, so reset can restore it without a bound CXL driver.
> 
> Save the HDM register location, decoder settings, and Device DVSEC state.
> Validate capability reads and decoder counts, and restore PCI_COMMAND
> after temporary MMIO access, reporting restoration failures.
> 
> Keep PCI discovery separate from shared HDM helpers. Move cxl_rwsem into
> built-in state code and protect cache publication with its DPA lock, so
> the cache remains usable when cxl_core is modular.

Hi Srirangan,

I felt the large-ness of this patch, so I'm coming back to the top
here to add this comment after doing the inline review below.

The commit message doesn't mention much of the preparation work that's
included. Could that prep be presented first in prep patches, and then
add the new code?  Something like:

cxl: Build register block helpers into the kernel
- regs.o moves from cxl_core into the built-in objects
- devm_cxl_iomap_block(), cxl_rcrb_to_aer(), __rcrb_to_component()
  and cxl_rcd_component_reg_phys() gain exports
- cxl_find_regblock() and cxl_setup_regs() move to include/cxl/pci.h
- struct cxl_register_map gains bar and bar_offset

cxl: Move cxl_rwsem into built-in code
- a new hdm_state.c holds cxl_rwsem and its export, and hdm.c drops it


More feedback inline below -

> 
> Link: https://git.kernel.org/pub/scm/linux/kernel/git/djiang/linux.git/commit/?id=b12baa1105f33cc1a10f9c9c0c6376194397d9f3
> Suggested-by: Dave Jiang <dave.jiang@intel.com>
> Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
> Assisted-by: LLM
> ---
>  MAINTAINERS                  |   1 +
>  drivers/cxl/core/Makefile    |   3 +-
>  drivers/cxl/core/hdm.c       |   5 -
>  drivers/cxl/core/hdm_regs.c  |  99 ++++++++++++++++
>  drivers/cxl/core/hdm_state.c |  64 ++++++++++
>  drivers/cxl/core/pci.c       |  17 ++-
>  drivers/cxl/core/regs.c      |   9 ++
>  drivers/cxl/cxl.h            |   3 -
>  drivers/pci/Makefile         |   1 +
>  drivers/pci/bus.c            |   1 +
>  drivers/pci/cxl.c            | 223 +++++++++++++++++++++++++++++++++++
>  drivers/pci/pci.h            |   8 ++
>  drivers/pci/probe.c          |   1 +
>  include/cxl/cxl.h            |   6 +
>  include/cxl/hdm.h            |  12 ++
>  include/cxl/pci.h            |  13 ++
>  tools/testing/cxl/Kbuild     |   1 -
>  17 files changed, 454 insertions(+), 13 deletions(-)
>  create mode 100644 drivers/cxl/core/hdm_state.c
>  create mode 100644 drivers/pci/cxl.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c2414447892c..b874340b0265 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6572,6 +6572,7 @@ S:	Maintained
>  F:	Documentation/driver-api/cxl
>  F:	Documentation/userspace-api/fwctl/fwctl-cxl.rst
>  F:	drivers/cxl/
> +F:	drivers/pci/cxl.c
>  F:	include/cxl/
>  F:	include/uapi/linux/cxl_mem.h
>  F:	tools/testing/cxl/
> diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
> index 6703c1729396..9a77e68d44ce 100644
> --- a/drivers/cxl/core/Makefile
> +++ b/drivers/cxl/core/Makefile
> @@ -1,6 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0
>  obj-$(CONFIG_CXL_BUS) += cxl_core.o
> -obj-$(subst m,y,$(CONFIG_CXL_BUS)) += hdm_regs.o
> +obj-$(subst m,y,$(CONFIG_CXL_BUS)) += hdm_regs.o hdm_state.o regs.o
>  obj-$(CONFIG_CXL_SUSPEND) += suspend.o
>  
>  ccflags-y += -I$(srctree)/drivers/cxl
> @@ -8,7 +8,6 @@ CFLAGS_trace.o = -DTRACE_INCLUDE_PATH=. -I$(src)
>  
>  cxl_core-y := port.o
>  cxl_core-y += pmem.o
> -cxl_core-y += regs.o

Does all of reg.c need to be built in? I'm implying that that you'd
only build in the part that PCI core needs and leave the rest in
cxl_core. Maybe moving more code around is not worth it. Just noticing.


snip


> +static int cxl_hdm_read_decoder_settings(struct device *dev,
> +					 struct cxl_endpoint_decoder_settings *settings,
> +					 void __iomem *hdm, int id)
> +{
> +	u64 base, size;
> +	u32 ctrl;
> +	int rc;
> +
> +	ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
> +	base = ((u64)readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id)) << 32) |
> +	       readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id));
> +	size = ((u64)readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(id)) << 32) |
> +	       readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id));
> +	rc = cxl_hdm_unpack_decoder(&settings->config, id, ctrl, base, size);


This duplicates work of init_hdm_decoder().
Could the new shared helper _unpack_decoder() grow to do the register
reads also, so the code is shared. Also, then you could do the reads
in low then high order, like init_hdm_decoder() does and like the
rest of the CXL code reads its Low/High register pairs.

snip

> +/* A published cache is usable only if its HDM register block was mapped. */
> +bool cxl_hdm_cache_present(struct cxl_hdm_info *const *slot)
> +{
> +	guard(rwsem_read)(&cxl_rwsem.dpa);
> +	return *slot && (*slot)->hdm_size;
> +}

Add a blank line before the final return please. (subsystem style)

snip

>  
> +static void cxl_hdm_cache_dvsec_ctrl(struct pci_dev *pdev, u16 ctrl)
> +{
> +	guard(rwsem_write)(&cxl_rwsem.dpa);
> +	if (!pdev->hdm)
> +		return;
> +
> +	pdev->hdm->dvsec_ctrl = ctrl;
> +	pdev->hdm->dvsec_ctrl_valid = true;



Could hdm_state.c add accessors for this, like the existing
cxl_hdm_cache_present() and cxl_hdm_cache_publish()? That way cxl_core
doesn't write pdev->hdm directly and the dpa locking stays in one place.
The same could be done for cxl_hdm_get_cached_info() and
cxl_hdm_check_decoder_count() added in Patch 8/16.


> +}
> +
>  static int cxl_set_mem_enable(struct cxl_dev_state *cxlds, u16 val)
>  {
>  	struct pci_dev *pdev = to_pci_dev(cxlds->dev);
> @@ -261,8 +271,10 @@ static int cxl_set_mem_enable(struct cxl_dev_state *cxlds, u16 val)
>  	if (rc)
>  		return pcibios_err_to_errno(rc);
>  
> -	if ((ctrl & PCI_DVSEC_CXL_MEM_ENABLE) == val)
> +	if ((ctrl & PCI_DVSEC_CXL_MEM_ENABLE) == val) {
> +		cxl_hdm_cache_dvsec_ctrl(pdev, ctrl);
>  		return 1;
> +	}
>  	ctrl &= ~PCI_DVSEC_CXL_MEM_ENABLE;
>  	ctrl |= val;
>  
> @@ -270,6 +282,7 @@ static int cxl_set_mem_enable(struct cxl_dev_state *cxlds, u16 val)
>  	if (rc)
>  		return pcibios_err_to_errno(rc);
>  
> +	cxl_hdm_cache_dvsec_ctrl(pdev, ctrl);
>  	return 0;


Can this function end in a single return, with the 0 or 1 result
in a variable, so that the cache is updated in one place?

snip

> @@ -200,6 +200,7 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr,
>  
>  	return ret_val;
>  }
> +EXPORT_SYMBOL_NS_GPL(devm_cxl_iomap_block, "CXL");


Why not EXPORT_SYMBOL_FOR_MODULES(..., "cxl_core") here, like the hdm_regs.c
helpers?

snip

> +static struct cxl_hdm_info *__cxl_pci_hdm_read_info(struct pci_dev *pdev,
> +						    struct cxl_register_map *map,
> +						    int dvsec)
> +{
> +	struct cxl_reg_map *hdm_map = &map->component_map.hdm_decoder;
> +	resource_size_t hdm_offset;
> +	void __iomem *hdm;
> +	int decoder_count;
> +	u16 dvsec_ctrl;
> +	int rc;
> +
> +	hdm = cxl_pci_hdm_map_regs(pdev, map, &hdm_offset, &decoder_count);
> +	if (IS_ERR(hdm))
> +		return ERR_CAST(hdm);
> +
> +	rc = pci_read_config_word(pdev, dvsec + PCI_DVSEC_CXL_CTRL,
> +				  &dvsec_ctrl);
> +	if (rc) {
> +		rc = pcibios_err_to_errno(rc);
> +		goto out_unmap;
> +	}
> +
> +	struct cxl_hdm_info *info =
> +		kzalloc_flex(*info, settings, decoder_count, GFP_KERNEL);

Move declaration to top of func.
checkpatch should be complaining about mixing statement & declarations.


> +	if (!info) {
> +		rc = -ENOMEM;
> +		goto out_unmap;
> +	}
> +
> +	info->decoder_count = decoder_count;
> +	info->hdm_bar = map->bar;
> +	info->hdm_offset = hdm_offset;
> +	info->hdm_size = hdm_map->size;
> +	info->dvsec = dvsec;
> +	info->dvsec_ctrl = dvsec_ctrl;
> +	info->dvsec_ctrl_valid = true;
> +
> +	rc = cxl_hdm_read_state(&pdev->dev, hdm, info);
> +	if (rc)
> +		goto out_free;
> +
> +	iounmap(hdm);
> +	return info;
> +
> +out_free:
> +	kfree(info);
> +out_unmap:
> +	iounmap(hdm);
> +	return ERR_PTR(rc);
> +}
> +
> +static struct cxl_hdm_info *cxl_pci_hdm_read_info(struct pci_dev *pdev,
> +						  struct cxl_register_map *map,
> +						  int dvsec)
> +{
> +	struct cxl_hdm_info *info;
> +	u16 command;
> +	int rc;
> +
> +	guard(pci_dev)(pdev);
> +
> +	rc = pci_read_config_word(pdev, PCI_COMMAND, &command);
> +	if (rc)
> +		return ERR_PTR(pcibios_err_to_errno(rc));
> +
> +	if (command & PCI_COMMAND_MEMORY)
> +		return __cxl_pci_hdm_read_info(pdev, map, dvsec);
> +
> +	rc = pci_write_config_word(pdev, PCI_COMMAND,
> +				   command | PCI_COMMAND_MEMORY);
> +	if (rc)
> +		return ERR_PTR(pcibios_err_to_errno(rc));
> +
> +	info = __cxl_pci_hdm_read_info(pdev, map, dvsec);
> +	rc = pci_write_config_word(pdev, PCI_COMMAND, command);
> +	if (!rc)
> +		return info;
> +
> +	pci_err(pdev,
> +		"failed to restore PCI_COMMAND after CXL HDM cache init: %d\n",
> +		pcibios_err_to_errno(rc));
> +	if (IS_ERR(info))
> +		return info;
> +
> +	kfree(info);
> +	return ERR_PTR(pcibios_err_to_errno(rc));


This returns the __cxl_pci_hdm_read_info() result from two places, and then
has three more returns after a failed PCI_COMMAND restore. Try to end in a
single return. Li Ming's suggestion to warn and keep the info on a failed
restore would also reduce the tail to one return info


> +}
> +
> +static int __pci_cxl_hdm_cache_init(struct pci_dev *pdev)
> +{
> +	struct cxl_register_map map = { };
> +	u16 dvsec, cap;
> +	int rc;
> +
> +	/* Avoid duplicate MMIO reads when the cache is already present. */
> +	if (cxl_hdm_cache_present(&pdev->hdm))
> +		return 0;
> +
> +	rc = cxl_pci_device_dvsec(pdev, &dvsec, &cap);
> +	if (rc == -ENOTTY)
> +		return 0;
> +	if (rc)
> +		return rc;
> +	if (!(cap & PCI_DVSEC_CXL_MEM_CAPABLE) ||
> +	    !cxl_dvsec_hdm_count_valid(FIELD_GET(PCI_DVSEC_CXL_HDM_COUNT, cap)))
> +		return 0;
> +

This cache is built for every function w CXL.mem, not just type2.
So I believe we are needlessly reading Type decoders at PCI enumeration.

Can this check the capability bits like cxl_reset_function() does 
and limit this work to type2 devices that can use it?

snip to end...

-- Alison

  parent reply	other threads:[~2026-10-29  3:19 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-11  2:14 [PATCH v15 00/16] PCI/CXL: Add CXL reset support for Type 2 devices Srirangan Madhavan
2026-10-11  2:14 ` [PATCH v15 01/16] cxl: Drop stale decoder interleave limit comment Srirangan Madhavan
2026-10-11  2:16   ` sashiko-bot
2026-10-27  4:13   ` Alison Schofield
2026-10-11  2:14 ` [PATCH v15 02/16] cxl: Share CXL port upstream PCI device lookup Srirangan Madhavan
2026-10-11  2:25   ` sashiko-bot
2026-10-11  2:14 ` [PATCH v15 03/16] cxl: Move decoder declarations to shared header Srirangan Madhavan
2026-10-11  2:19   ` sashiko-bot
2026-10-11  2:14 ` [PATCH v15 04/16] cxl: Embed decoder configuration in a standalone structure Srirangan Madhavan
2026-10-11  2:25   ` sashiko-bot
2026-10-11  2:14 ` [PATCH v15 05/16] cxl: Introduce endpoint HDM decoder settings Srirangan Madhavan
2026-10-11  2:22   ` sashiko-bot
2026-10-26 22:20   ` Dave Jiang
2026-10-27  6:23   ` Li Ming
2026-10-11  2:14 ` [PATCH v15 06/16] cxl: Move HDM decoder helpers to built-in code Srirangan Madhavan
2026-10-11  2:21   ` sashiko-bot
2026-10-26 22:32   ` Dave Jiang
2026-10-27  6:24   ` Li Ming
2026-10-11  2:14 ` [PATCH v15 07/16] cxl: Share HDM decoder register unpacking Srirangan Madhavan
2026-10-11  2:25   ` sashiko-bot
2026-10-26 22:41   ` Dave Jiang
2026-10-27  6:31   ` Li Ming
2026-10-11  2:14 ` [PATCH v15 08/16] cxl: Refresh cached PCI HDM decoder settings Srirangan Madhavan
2026-10-11  2:23   ` sashiko-bot
2026-10-26 22:56   ` Dave Jiang
2026-10-27  6:50   ` Li Ming
2026-10-11  2:14 ` [PATCH v15 09/16] PCI/CXL: Cache endpoint HDM state during PCI enumeration Srirangan Madhavan
2026-10-11  2:25   ` sashiko-bot
2026-10-27  8:07   ` Li Ming
2026-10-29  3:19   ` Alison Schofield [this message]
2026-10-29  7:02   ` Li Ming
2026-10-11  2:14 ` [PATCH v15 10/16] PCI/CXL: Add CXL Device Reset sequencing Srirangan Madhavan
2026-10-11  2:25   ` sashiko-bot
2026-10-28  3:01   ` Li Ming
2026-10-11  2:14 ` [PATCH v15 11/16] cxl: Validate and synchronize HDM ranges around reset Srirangan Madhavan
2026-10-11  2:21   ` sashiko-bot
2026-10-27  3:25   ` Alison Schofield
2026-10-27  4:32   ` Alison Schofield
2026-10-11  2:14 ` [PATCH v15 12/16] PCI/CXL: Reject reset with unsafe function scope Srirangan Madhavan
2026-10-11  2:28   ` sashiko-bot
2026-10-11  2:14 ` [PATCH v15 13/16] PCI/CXL: Restore CXL state after PCI reset Srirangan Madhavan
2026-10-11  2:25   ` sashiko-bot
2026-10-27  3:56   ` Alison Schofield
2026-10-11  2:14 ` [PATCH v15 14/16] PCI/CXL: Expose CXL Reset as a PCI reset method Srirangan Madhavan
2026-10-11  2:34   ` sashiko-bot
2026-10-11  2:14 ` [PATCH v15 15/16] PCI/CXL: Restore CXL state after CXL bus reset Srirangan Madhavan
2026-10-11  2:24   ` sashiko-bot
2026-10-11  2:14 ` [PATCH v15 16/16] tools/testing/cxl: Add HDM decoder range checks Srirangan Madhavan
2026-10-11  2:22   ` sashiko-bot
2026-10-27  2:41   ` Alison Schofield

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=auK7MxeCI2fsUNZC@aschofie-mobl2.lan \
    --to=alison.schofield@intel.com \
    --cc=alex.williamson@redhat.com \
    --cc=alwilliamson@nvidia.com \
    --cc=bhelgaas@google.com \
    --cc=dave.jiang@intel.com \
    --cc=dave@stgolabs.net \
    --cc=icheng@nvidia.com \
    --cc=ira.weiny@intel.com \
    --cc=jan@nvidia.com \
    --cc=jic23@kernel.org \
    --cc=linux-cxl@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=mhonap@nvidia.com \
    --cc=skancherla@nvidia.com \
    --cc=smadhavan@nvidia.com \
    --cc=vaslot@nvidia.com \
    --cc=vishal.l.verma@intel.com \
    --cc=vsethi@nvidia.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