From: sashiko-bot@kernel.org
To: "Davidlohr Bueso" <dave@stgolabs.net>
Cc: linux-cxl@vger.kernel.org
Subject: Re: [PATCH v7 2/8] cxl/pci: Add BI topology enable/disable
Date: Tue, 28 Jul 2026 15:16:28 +0000 [thread overview]
Message-ID: <20260728151629.20F0D1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260728144136.709882-3-dave@stgolabs.net>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Topology walk loop exits early, completely skipping CXL Root Ports and breaking BI enablement.
- [High] Missing explicit hardware commit for Endpoints and Root Ports.
- [High] Premature BI disablement on shared Switch DSPs due to missing `nr_bi` reference counting.
- [Medium] Hardware register state is leaked (left enabled) when a downstream port fails to commit.
- [Medium] Writing to the BI_COMMIT control bit without waiting for the BI_COMMITTED status bit to clear introduces a race condition.
--
--- Patch [2]: [PATCH v7 2/8] cxl/pci: Add BI topology enable/disable ---
commit 60c6baf3b8f67e918530663c4dbf82d8c044cc21
Author: Davidlohr Bueso <dave@stgolabs.net>
cxl/pci: Add BI topology enable/disable
This commit implements cxl_bi_setup() to enable Back-Invalidate (BI) flows
on a device and every component in its path. It also implements the teardown
counterpart cxl_bi_dealloc(). The setup runs during endpoint port probe and
walks the topology to enable BI capabilities.
> diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
> index f82559d8a8c5a..a87c2ad9ac533 100644
> --- a/drivers/cxl/core/pci.c
> +++ b/drivers/cxl/core/pci.c
[ ... ]
> @@ -964,3 +966,380 @@ void devm_cxl_dport_bi_setup(struct cxl_dport *dport)
[ ... ]
> +static int __cxl_bi_commit_decoder(struct device *dev, void __iomem *bi)
> +{
> + u32 status, ctrl;
> + unsigned int scale, base;
> +
> + if (!FIELD_GET(CXL_BI_DECODER_CAPS_EXPLICIT_COMMIT_REQ,
> + readl(bi + CXL_BI_DECODER_CAPS_OFFSET)))
> + return 0;
> +
> + ctrl = readl(bi + CXL_BI_DECODER_CTRL_OFFSET);
> + writel(ctrl & ~CXL_BI_DECODER_CTRL_BI_COMMIT,
> + bi + CXL_BI_DECODER_CTRL_OFFSET);
> + writel(ctrl | CXL_BI_DECODER_CTRL_BI_COMMIT,
> + bi + CXL_BI_DECODER_CTRL_OFFSET);
[Severity: Medium]
Will this sequence cause a race condition with the subsequent polling loop?
If the hardware was previously in a committed state, the status bit might
still be set when the polling starts.
Could this allow the polling loop to succeed instantly before the hardware has
processed the new commit request?
[ ... ]
> +static int __cxl_bi_ctrl_dport(struct cxl_dport *dport, bool enable)
> +{
> + struct pci_dev *pdev = to_pci_dev(dport->dport_dev);
> + void __iomem *bi = dport->regs.bi_decoder;
> + struct cxl_port *port = dport->port;
> + u32 ctrl, value;
> + int rc;
> +
> + guard(mutex)(&port->bi_lock);
> + if (!bi)
> + return -EINVAL;
> +
> + ctrl = readl(bi + CXL_BI_DECODER_CTRL_OFFSET);
> +
> + switch (pci_pcie_type(pdev)) {
> + case PCI_EXP_TYPE_ROOT_PORT:
> + if (enable) {
> + /*
> + * There is no point of failure from here on,
> + * BI will be enabled on the endpoint device.
> + */
> + dport->nr_bi++;
> +
> + if (FIELD_GET(CXL_BI_DECODER_CTRL_BI_FW, ctrl) &&
> + !FIELD_GET(CXL_BI_DECODER_CTRL_BI_ENABLE, ctrl))
> + return 0;
> +
> + value = ctrl | CXL_BI_DECODER_CTRL_BI_FW;
> + value &= ~CXL_BI_DECODER_CTRL_BI_ENABLE;
> + } else {
> + if (WARN_ON_ONCE(dport->nr_bi == 0))
> + return -EINVAL;
> + if (--dport->nr_bi > 0)
> + return 0;
> +
> + value = ctrl & ~(CXL_BI_DECODER_CTRL_BI_FW |
> + CXL_BI_DECODER_CTRL_BI_ENABLE);
> + }
> +
> + writel(value, bi + CXL_BI_DECODER_CTRL_OFFSET);
> + return 0;
[Severity: High]
Does this code need to explicitly commit the BI Decoder for Root Ports?
The control register is updated, but a hardware commit is never performed.
Will this fail to enable BI on Root Ports that require an explicit commit?
> + case PCI_EXP_TYPE_DOWNSTREAM:
> + if (enable) {
> + value = ctrl & ~CXL_BI_DECODER_CTRL_BI_FW;
> + value |= CXL_BI_DECODER_CTRL_BI_ENABLE;
> + } else {
> + if (!FIELD_GET(CXL_BI_DECODER_CTRL_BI_ENABLE, ctrl))
> + return 0;
> + value = ctrl & ~(CXL_BI_DECODER_CTRL_BI_FW |
> + CXL_BI_DECODER_CTRL_BI_ENABLE);
> + }
> +
> + writel(value, bi + CXL_BI_DECODER_CTRL_OFFSET);
[Severity: High]
Is there a missing reference count for Downstream Ports here?
Unlike Root Ports which check dport->nr_bi, this unconditionally clears the
CXL_BI_DECODER_CTRL_BI_ENABLE bit when disabling.
If this is a shared Switch DSP in a cascaded switch topology, will unbinding
one endpoint instantly break BI functionality for all other active endpoints
below the same upstream switch?
[ ... ]
> +static int __cxl_bi_ctrl_endpoint(struct cxl_dev_state *cxlds, bool enable)
> +{
> + struct cxl_port *endpoint = cxlds->cxlmd->endpoint;
> + void __iomem *bi = endpoint->regs.bi_decoder;
> + u32 ctrl, val;
[ ... ]
> + writel(val, bi + CXL_BI_DECODER_CTRL_OFFSET);
> + cxlds->bi = enable;
> +
> + dev_dbg(cxlds->dev, "BI requests %s\n",
> + str_enabled_disabled(enable));
> +
> + return 0;
> +}
[Severity: High]
Does the endpoint need an explicit hardware commit here?
Similar to the Root Port case, this modifies the CXL_BI_DECODER_CTRL_BI_ENABLE
bit but never calls __cxl_bi_commit_decoder() to commit the change to
hardware.
[ ... ]
> +static void cxl_bi_dealloc(void *data)
> +{
> + struct cxl_port *endpoint = data;
> + struct cxl_memdev *cxlmd = to_cxl_memdev(endpoint->uport_dev);
> + struct cxl_dev_state *cxlds = cxlmd->cxlds;
> + struct cxl_dport *dport_iter;
> + struct cxl_port *port_iter;
> +
> + if (!cxlds->bi)
> + return;
> +
> + scoped_guard(rwsem_read, &cxl_rwsem.region)
> + cxl_bi_ctrl_endpoint_disable(cxlds);
> +
> + /*
> + * Walk the same parent_dport chain that enabled the path. A bus
> + * lookup cannot stand in for it: an ancestor-driven teardown
> + * delists the parent port before this devres action runs.
> + */
> + dport_iter = endpoint->parent_dport;
> + port_iter = dport_iter->port;
> + while (!is_cxl_root(port_iter)) {
> + int rc = cxl_bi_ctrl_dport_disable(dport_iter);
[Severity: High]
Does this loop terminate before processing the Root Port?
When port_iter reaches the top, its owning port is cxl_root. Since
is_cxl_root(cxl_root) evaluates to true, it looks like the loop exits
immediately before executing the disable body for the Root Port.
[ ... ]
> +static int cxl_bi_enable_path(struct cxl_dev_state *cxlds,
> + struct cxl_port *port, struct cxl_dport *dport)
> +{
> + struct cxl_dport *dport_iter, *failed;
> + struct cxl_port *port_iter;
> + int rc;
> +
> + port_iter = port;
> + dport_iter = dport;
> + while (!is_cxl_root(port_iter)) {
> + rc = cxl_bi_ctrl_dport_enable(dport_iter);
> + if (rc)
> + goto err_rollback;
> +
> + dport_iter = port_iter->parent_dport;
> + port_iter = dport_iter->port;
> + }
[Severity: High]
Does this also skip enabling the Root Port?
Using the same !is_cxl_root() condition as cxl_bi_dealloc(), this loop will
exit before calling cxl_bi_ctrl_dport_enable() for the Root Port, leaving the
host path incomplete.
[ ... ]
> +err_rollback:
> + failed = dport_iter;
> + dport_iter = dport;
> + port_iter = port;
> + while (!is_cxl_root(port_iter) && dport_iter != failed) {
> + cxl_bi_ctrl_dport_disable(dport_iter);
> + dport_iter = port_iter->parent_dport;
> + port_iter = dport_iter->port;
> + }
> + return rc;
> +}
[Severity: Medium]
Should the failed dport be included in the rollback loop?
If cxl_bi_ctrl_dport_enable() writes the enable bit but the hardware commit
fails, the control register has still been modified.
By stopping the rollback when dport_iter != failed,
cxl_bi_ctrl_dport_disable() is never called for it, potentially leaking the
hardware register state as left enabled.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260728144136.709882-1-dave@stgolabs.net?part=2
next prev parent reply other threads:[~2026-07-28 15:16 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-28 14:41 [PATCH v7 0/8] cxl: Support Back-Invalidate Davidlohr Bueso
2026-07-28 14:41 ` [PATCH v7 1/8] cxl: Add BI register probing and port initialization Davidlohr Bueso
2026-07-28 14:41 ` [PATCH v7 2/8] cxl/pci: Add BI topology enable/disable Davidlohr Bueso
2026-07-28 15:16 ` sashiko-bot [this message]
2026-07-28 14:41 ` [PATCH v7 3/8] cxl/hdm: Add BI coherency support for endpoint decoders Davidlohr Bueso
2026-07-28 15:26 ` sashiko-bot
2026-07-28 18:44 ` Davidlohr Bueso
2026-07-28 14:41 ` [PATCH v7 4/8] cxl: Add HDM-DB region creation Davidlohr Bueso
2026-07-28 14:41 ` [PATCH v7 5/8] cxl/hdm: Rename decoder coherency flags Davidlohr Bueso
2026-07-28 14:41 ` [PATCH v7 6/8] cxl/region: Log the coherency model at region creation Davidlohr Bueso
2026-07-28 14:41 ` [PATCH v7 7/8] cxl/pci: Split BI capability probe from setup Davidlohr Bueso
2026-07-28 14:41 ` [PATCH v7 8/8] cxl: Allow auto-committed BI hdm decoders Davidlohr Bueso
2026-07-28 15:46 ` 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=20260728151629.20F0D1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dave@stgolabs.net \
--cc=linux-cxl@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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