Skip to content

Commit 72cb5ed

Browse files
AkshGarg-19bjorn-helgaas
authored andcommitted
PCI: dwc: ep: Add per-PF BAR and inbound ATU mapping support
The commit 24ede43 ("PCI: designware-ep: Add multiple PFs support for DWC") added support for multiple PFs in the DWC driver, but the implementation was incomplete. It did not properly support MSI/MSI-X, as well as BAR and inbound ATU mapping for multiple PFs. The MSI/MSI-X issue was later fixed by commit 47a0626 ("PCI: designware-ep: Modify MSI and MSIX CAP way of finding") by introducing a per-PF struct dw_pcie_ep_func. However, even with both commits, the multiple PF support in the driver remains broken because BAR configuration and ATU mappings are managed globally in struct dw_pcie_ep, meaning all PFs share the same BAR-to-ATU mapping table. This causes one PF's EPF to overwrite the address translation of another PF's EPF in the internal ATU region, creating conflicts when multiple physical functions attempt to configure their BARs independently. The commit cfbc98d ("PCI: dwc: ep: Support BAR subrange inbound mapping via Address Match Mode iATU") later introduced Address Match Mode support, which suffers from the same multi-PF conflict issue. Fix this by moving the required members from struct dw_pcie_ep to struct dw_pcie_ep_func, similar to what commit 47a0626 ("PCI: designware-ep: Modify MSI and MSIX CAP way of finding") did for MSI/MSI-X capability support, to allow proper multi-function endpoint operation, where each PF can configure its BARs and corresponding internal ATU region without interfering with other PFs. Fixes: 24ede43 ("PCI: designware-ep: Add multiple PFs support for DWC") Fixes: cc839be ("PCI: dwc: ep: Support BAR subrange inbound mapping via Address Match Mode iATU") Signed-off-by: Aksh Garg <a-garg7@ti.com> Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Niklas Cassel <cassel@kernel.org> Link: https://patch.msgid.link/20260130115516.515082-3-a-garg7@ti.com
1 parent 43d67ec commit 72cb5ed

2 files changed

Lines changed: 54 additions & 37 deletions

File tree

drivers/pci/controller/dwc/pcie-designware-ep.c

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,15 @@ static int dw_pcie_ep_ib_atu_bar(struct dw_pcie_ep *ep, u8 func_no, int type,
115115
int ret;
116116
u32 free_win;
117117
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
118+
struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
118119

119-
if (!ep->bar_to_atu[bar])
120+
if (!ep_func)
121+
return -EINVAL;
122+
123+
if (!ep_func->bar_to_atu[bar])
120124
free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows);
121125
else
122-
free_win = ep->bar_to_atu[bar] - 1;
126+
free_win = ep_func->bar_to_atu[bar] - 1;
123127

124128
if (free_win >= pci->num_ib_windows) {
125129
dev_err(pci->dev, "No free inbound window\n");
@@ -137,33 +141,37 @@ static int dw_pcie_ep_ib_atu_bar(struct dw_pcie_ep *ep, u8 func_no, int type,
137141
* Always increment free_win before assignment, since value 0 is used to identify
138142
* unallocated mapping.
139143
*/
140-
ep->bar_to_atu[bar] = free_win + 1;
144+
ep_func->bar_to_atu[bar] = free_win + 1;
141145
set_bit(free_win, ep->ib_window_map);
142146

143147
return 0;
144148
}
145149

146-
static void dw_pcie_ep_clear_ib_maps(struct dw_pcie_ep *ep, enum pci_barno bar)
150+
static void dw_pcie_ep_clear_ib_maps(struct dw_pcie_ep *ep, u8 func_no, enum pci_barno bar)
147151
{
152+
struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
148153
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
149154
struct device *dev = pci->dev;
150155
unsigned int i, num;
151156
u32 atu_index;
152157
u32 *indexes;
153158

159+
if (!ep_func)
160+
return;
161+
154162
/* Tear down the BAR Match Mode mapping, if any. */
155-
if (ep->bar_to_atu[bar]) {
156-
atu_index = ep->bar_to_atu[bar] - 1;
163+
if (ep_func->bar_to_atu[bar]) {
164+
atu_index = ep_func->bar_to_atu[bar] - 1;
157165
dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index);
158166
clear_bit(atu_index, ep->ib_window_map);
159-
ep->bar_to_atu[bar] = 0;
167+
ep_func->bar_to_atu[bar] = 0;
160168
}
161169

162170
/* Tear down all Address Match Mode mappings, if any. */
163-
indexes = ep->ib_atu_indexes[bar];
164-
num = ep->num_ib_atu_indexes[bar];
165-
ep->ib_atu_indexes[bar] = NULL;
166-
ep->num_ib_atu_indexes[bar] = 0;
171+
indexes = ep_func->ib_atu_indexes[bar];
172+
num = ep_func->num_ib_atu_indexes[bar];
173+
ep_func->ib_atu_indexes[bar] = NULL;
174+
ep_func->num_ib_atu_indexes[bar] = 0;
167175
if (!indexes)
168176
return;
169177
for (i = 0; i < num; i++) {
@@ -248,6 +256,7 @@ static int dw_pcie_ep_validate_submap(struct dw_pcie_ep *ep,
248256
static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type,
249257
const struct pci_epf_bar *epf_bar)
250258
{
259+
struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
251260
const struct pci_epf_bar_submap *submap = epf_bar->submap;
252261
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
253262
enum pci_barno bar = epf_bar->barno;
@@ -258,7 +267,7 @@ static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type,
258267
unsigned int i;
259268
u32 *indexes;
260269

261-
if (!epf_bar->num_submap || !submap || !epf_bar->size)
270+
if (!ep_func || !epf_bar->num_submap || !submap || !epf_bar->size)
262271
return -EINVAL;
263272

264273
ret = dw_pcie_ep_validate_submap(ep, submap, epf_bar->num_submap,
@@ -279,8 +288,8 @@ static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type,
279288
if (!indexes)
280289
return -ENOMEM;
281290

282-
ep->ib_atu_indexes[bar] = indexes;
283-
ep->num_ib_atu_indexes[bar] = 0;
291+
ep_func->ib_atu_indexes[bar] = indexes;
292+
ep_func->num_ib_atu_indexes[bar] = 0;
284293

285294
for (i = 0; i < epf_bar->num_submap; i++) {
286295
size = submap[i].size;
@@ -308,11 +317,11 @@ static int dw_pcie_ep_ib_atu_addr(struct dw_pcie_ep *ep, u8 func_no, int type,
308317

309318
set_bit(free_win, ep->ib_window_map);
310319
indexes[i] = free_win;
311-
ep->num_ib_atu_indexes[bar] = i + 1;
320+
ep_func->num_ib_atu_indexes[bar] = i + 1;
312321
}
313322
return 0;
314323
err:
315-
dw_pcie_ep_clear_ib_maps(ep, bar);
324+
dw_pcie_ep_clear_ib_maps(ep, func_no, bar);
316325
return ret;
317326
}
318327

@@ -346,15 +355,16 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
346355
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
347356
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
348357
enum pci_barno bar = epf_bar->barno;
358+
struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
349359

350-
if (!ep->epf_bar[bar])
360+
if (!ep_func || !ep_func->epf_bar[bar])
351361
return;
352362

353363
__dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags);
354364

355-
dw_pcie_ep_clear_ib_maps(ep, bar);
365+
dw_pcie_ep_clear_ib_maps(ep, func_no, bar);
356366

357-
ep->epf_bar[bar] = NULL;
367+
ep_func->epf_bar[bar] = NULL;
358368
}
359369

360370
static unsigned int dw_pcie_ep_get_rebar_offset(struct dw_pcie_ep *ep, u8 func_no,
@@ -481,12 +491,16 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
481491
{
482492
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
483493
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
494+
struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
484495
enum pci_barno bar = epf_bar->barno;
485496
size_t size = epf_bar->size;
486497
enum pci_epc_bar_type bar_type;
487498
int flags = epf_bar->flags;
488499
int ret, type;
489500

501+
if (!ep_func)
502+
return -EINVAL;
503+
490504
/*
491505
* DWC does not allow BAR pairs to overlap, e.g. you cannot combine BARs
492506
* 1 and 2 to form a 64-bit BAR.
@@ -500,22 +514,22 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
500514
* calling clear_bar() would clear the BAR's PCI address assigned by the
501515
* host).
502516
*/
503-
if (ep->epf_bar[bar]) {
517+
if (ep_func->epf_bar[bar]) {
504518
/*
505519
* We can only dynamically change a BAR if the new BAR size and
506520
* BAR flags do not differ from the existing configuration.
507521
*/
508-
if (ep->epf_bar[bar]->barno != bar ||
509-
ep->epf_bar[bar]->size != size ||
510-
ep->epf_bar[bar]->flags != flags)
522+
if (ep_func->epf_bar[bar]->barno != bar ||
523+
ep_func->epf_bar[bar]->size != size ||
524+
ep_func->epf_bar[bar]->flags != flags)
511525
return -EINVAL;
512526

513527
/*
514528
* When dynamically changing a BAR, tear down any existing
515529
* mappings before re-programming.
516530
*/
517-
if (ep->epf_bar[bar]->num_submap || epf_bar->num_submap)
518-
dw_pcie_ep_clear_ib_maps(ep, bar);
531+
if (ep_func->epf_bar[bar]->num_submap || epf_bar->num_submap)
532+
dw_pcie_ep_clear_ib_maps(ep, func_no, bar);
519533

520534
/*
521535
* When dynamically changing a BAR, skip writing the BAR reg, as
@@ -574,7 +588,7 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
574588
if (ret)
575589
return ret;
576590

577-
ep->epf_bar[bar] = epf_bar;
591+
ep_func->epf_bar[bar] = epf_bar;
578592

579593
return 0;
580594
}
@@ -969,7 +983,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
969983
bir = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset);
970984
tbl_offset &= PCI_MSIX_TABLE_OFFSET;
971985

972-
msix_tbl = ep->epf_bar[bir]->addr + tbl_offset;
986+
msix_tbl = ep_func->epf_bar[bir]->addr + tbl_offset;
973987
msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
974988
msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
975989
vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
@@ -1032,11 +1046,14 @@ EXPORT_SYMBOL_GPL(dw_pcie_ep_deinit);
10321046

10331047
static void dw_pcie_ep_init_rebar_registers(struct dw_pcie_ep *ep, u8 func_no)
10341048
{
1035-
unsigned int offset;
1036-
unsigned int nbars;
1049+
struct dw_pcie_ep_func *ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
1050+
unsigned int offset, nbars;
10371051
enum pci_barno bar;
10381052
u32 reg, i, val;
10391053

1054+
if (!ep_func)
1055+
return;
1056+
10401057
offset = dw_pcie_ep_find_ext_capability(ep, func_no, PCI_EXT_CAP_ID_REBAR);
10411058

10421059
if (offset) {
@@ -1063,8 +1080,8 @@ static void dw_pcie_ep_init_rebar_registers(struct dw_pcie_ep *ep, u8 func_no)
10631080
*/
10641081
val = dw_pcie_ep_readl_dbi(ep, func_no, offset + PCI_REBAR_CTRL);
10651082
bar = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, val);
1066-
if (ep->epf_bar[bar])
1067-
pci_epc_bar_size_to_rebar_cap(ep->epf_bar[bar]->size, &val);
1083+
if (ep_func->epf_bar[bar])
1084+
pci_epc_bar_size_to_rebar_cap(ep_func->epf_bar[bar]->size, &val);
10681085
else
10691086
val = BIT(4);
10701087

drivers/pci/controller/dwc/pcie-designware.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,12 @@ struct dw_pcie_ep_func {
471471
u8 func_no;
472472
u8 msi_cap; /* MSI capability offset */
473473
u8 msix_cap; /* MSI-X capability offset */
474+
u8 bar_to_atu[PCI_STD_NUM_BARS];
475+
struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
476+
477+
/* Only for Address Match Mode inbound iATU */
478+
u32 *ib_atu_indexes[PCI_STD_NUM_BARS];
479+
unsigned int num_ib_atu_indexes[PCI_STD_NUM_BARS];
474480
};
475481

476482
struct dw_pcie_ep {
@@ -480,17 +486,11 @@ struct dw_pcie_ep {
480486
phys_addr_t phys_base;
481487
size_t addr_size;
482488
size_t page_size;
483-
u8 bar_to_atu[PCI_STD_NUM_BARS];
484489
phys_addr_t *outbound_addr;
485490
unsigned long *ib_window_map;
486491
unsigned long *ob_window_map;
487492
void __iomem *msi_mem;
488493
phys_addr_t msi_mem_phys;
489-
struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
490-
491-
/* Only for Address Match Mode inbound iATU */
492-
u32 *ib_atu_indexes[PCI_STD_NUM_BARS];
493-
unsigned int num_ib_atu_indexes[PCI_STD_NUM_BARS];
494494

495495
/* MSI outbound iATU state */
496496
bool msi_iatu_mapped;

0 commit comments

Comments
 (0)