Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

PCI: dwc: ep: Always clear IB maps on BAR update

dw_pcie_ep_set_bar() currently tears down existing inbound mappings only
when either the previous or the new struct pci_epf_bar uses submaps
(num_submap != 0). If both the old and new mappings are BAR Match Mode,
reprogramming the same ATU index is sufficient, so no explicit teardown
was needed.

However, some callers may reuse the same struct pci_epf_bar instance and
update it in place before calling set_bar() again. In that case
ep_func->epf_bar[bar] and the passed-in epf_bar can point to the same
object, so we cannot reliably distinguish BAR Match Mode -> BAR Match Mode
from Address Match Mode -> BAR Match Mode. As a result, the conditional
teardown based on num_submap becomes unreliable and existing inbound maps
may be left active.

Call dw_pcie_ep_clear_ib_maps() unconditionally before reprogramming the
BAR so that in-place updates are handled correctly.

This introduces a behavioral change in a corner case: if a BAR
reprogramming attempt fails (especially for the long-standing BAR Match
Mode -> BAR Match Mode update case), the previously programmed inbound
mapping will already have been torn down. This should be acceptable, since
the caller observes the error and should not use the BAR for any real
transactions in that case.

While at it, document that the existing update parameter check is
best-effort for in-place updates.

Fixes: cc839bef7727 ("PCI: dwc: ep: Support BAR subrange inbound mapping via Address Match Mode iATU")
Signed-off-by: Koichiro Den <den@valinux.co.jp>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Niklas Cassel <cassel@kernel.org>
Link: https://patch.msgid.link/20260202145407.503348-3-den@valinux.co.jp

authored by

Koichiro Den and committed by
Bjorn Helgaas
8c746e22 88a71941

+11 -3
+11 -3
drivers/pci/controller/dwc/pcie-designware-ep.c
··· 519 519 /* 520 520 * We can only dynamically change a BAR if the new BAR size and 521 521 * BAR flags do not differ from the existing configuration. 522 + * 523 + * Note: this safety check only works when the caller uses 524 + * a new struct pci_epf_bar in the second set_bar() call. 525 + * If the same instance is updated in place and passed in, 526 + * we cannot reliably detect invalid barno/size/flags 527 + * changes here. 522 528 */ 523 529 if (ep_func->epf_bar[bar]->barno != bar || 524 530 ep_func->epf_bar[bar]->size != size || ··· 533 527 534 528 /* 535 529 * When dynamically changing a BAR, tear down any existing 536 - * mappings before re-programming. 530 + * mappings before re-programming. This is redundant when 531 + * both the old and new mappings are BAR Match Mode, but 532 + * required to handle in-place updates and match-mode 533 + * changes reliably. 537 534 */ 538 - if (ep_func->epf_bar[bar]->num_submap || epf_bar->num_submap) 539 - dw_pcie_ep_clear_ib_maps(ep, func_no, bar); 535 + dw_pcie_ep_clear_ib_maps(ep, func_no, bar); 540 536 541 537 /* 542 538 * When dynamically changing a BAR, skip writing the BAR reg, as