Thread (13 messages) 13 messages, 2 authors, 2026-02-02

Re: [PATCH 3/3] PCI: endpoint: Document pci_epc_set_bar() caller ownership and lifetime rules

From: Koichiro Den <hidden>
Date: 2026-02-02 15:04:14
Also in: linux-pci, lkml

On Mon, Feb 02, 2026 at 10:27:12AM +0100, Niklas Cassel wrote:
quoted hunk ↗ jump to hunk
On Mon, Feb 02, 2026 at 02:59:35PM +0900, Koichiro Den wrote:
quoted
quoted
Considering that struct pci_epf_bar lives in struct pci_epf, I think my
previous idea of doing a kmemdup, seems wrong...
I don't think it's inherently wrong. I think it really comes down to what
contract we want pci_epc_set_bar() to imply.

When I saw your earlier comment:
https://lore.kernel.org/all/aX019VTWjMlPX8qp@fedora/ (local)
I hastily assumed you were implicitly suggesting that there are some
outliers (such as epf-vntb), which led me to think we should document a
single "legit" way to use the API. In hindsight, I read too much into it,
there doesn't seem to be a clearly established contract today.

One subtlety if we decide to treat in-place updates as supported: the
existing dynamic update compatibility check in dwc [3] becomes officially
best-effort, because ep->epf_bar[bar] and the passed-in epf_bar may point
to the same object (so comparing against the previous state is not
reliable). In other words, changing barno/size/flags via in-place updates
would be caller misuse, but the driver cannot always detect it.
Yes, I agree, but I think that is fine.

If the caller does a fundamental change to an existing struct pci_epf_bar,
between two set_bar() calls... they have no one to blame but themselves.

At least the check will be able to detect when the second set_bar() call
is supplied a new struct which does not have the same size / flags as the
struct pci_epf_bar that is currently in use.

The same currently applies to clear_bar():
If you do a stupid in place update of the struct pci_epf_bar after calling
set_bar(), e.g. modifying epf_bar->barno, clear_bar() will absolutely do
"bad things".

Perhaps we should update the comment in dw_pcie_ep_set_bar():
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 7e7844ff0f7e..451ba8add157 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -518,6 +518,11 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
                /*
                 * We can only dynamically change a BAR if the new BAR size and
                 * BAR flags do not differ from the existing configuration.
+                *
+                * Note: this safety check only works when the caller uses a new
+                * struct pci_epf_bar in the second set_bar() call. If the same
+                * struct pci_epf_bar was supplied (i.e. being updated in place)
+                * then it is impossible to detect invalid changes to the BAR.
                 */
                if (ep_func->epf_bar[bar]->barno != bar ||
                    ep_func->epf_bar[bar]->size != size ||

To make it clear that this safety check is not always possible.

quoted
quoted
I'm sorry for making you waste time. I did miss that even though pci-epf-vntb
does not do in place updates of doorbell BAR, it does so for the other BARs.
No worries at all, and thanks for digging through the history with me.
At this point, I think there are still two reasonable options (to
summarize):

X). Treat the existing in-tree callers (including in-place update) as valid
    usage (i.e. apply [4]).

    [4] https://lore.kernel.org/linux-pci/q5e7ydmf4ra6x2mbxwifovgr6p6x5dfnz3hz5psq5ypyabtsvx@oq5ovi4o26yf/ (local)

    In this case, the downside noted in [4] remains: if a BAR reprogramming
    attempt fails (especially for the long-standing epf-vntb's BAR Match ->
    BAR Match transition case), the previously programmed inbound mapping
    will already have been torn down. This behavior change is inherent in
    making the teardown unconditional. I think this is acceptable because
    if the caller is passing incompatible/invalid parameters, things are
    already going off the rails anyway, and the call site that receives the
    error should never actively use the BAR for any real transactions.

    Separately, if we treat in-place updates as supported, some of the
    existing compatibility checks (e.g. barno/size/flags) become inherently
    best-effort, because the previous state may no longer be observable by
    the driver. Addressing that would require additional follow-up work
    (e.g. with doing a kmemdup and holding the snapshot), but this is a
    pre-existing issue, so there is no need to rush fixing this.

Y). Define a stricter API usage contract, document it, and then adjust all
    the caller sides later (i.e. apply this v2 series).

    The downside here is that struct pci_epf embeds the struct pci_epf_bar
    array, so tightening the contract and fixing existing users would
    likely be awkward.

Personally, I'm inclined towards (X) at the moment, mainly because there
doesn't seem to be a firm, shared understanding of the API contract today.
Later, we can do follow-up work for the existing behaviour, which is
already present on mainline.

If you still agree with (X), I'll send v2 with splitting [4] into two-patch
series, with an explanation above the unconditional
dw_pcie_ep_clear_ib_maps().
I did not change my mind a second time :)

So I still think X is the way to go.
I have just sent v2:
https://lore.kernel.org/linux-pci/20260202145407.503348-1-den@valinux.co.jp/ (local)
Thanks for the review.

Kind regards,
Koichiro

Kind regards,
Niklas
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help