Skip to content

Commit 6f5e193

Browse files
kishonLorenzo Pieralisi
authored andcommitted
PCI: dwc: Fix dw_pcie_ep_raise_msix_irq() to get correct MSI-X table address
commit beb4641 ("PCI: dwc: Add MSI-X callbacks handler"), in order to raise MSI-X interrupt, obtained MSIX table address from Base Address Register (BAR). However BAR only holds PCI address programmed by the host whereas the MSI-X table should be in the local memory. Store the MSI-X table address (virtual address) as part of ->set_bar() callback and use that to get the message address and message data here. Fixes: beb4641 ("PCI: dwc: Add MSI-X callbacks handler") Signed-off-by: Kishon Vijay Abraham I <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]>
1 parent 83153d9 commit 6f5e193

File tree

4 files changed

+35
-29
lines changed

4 files changed

+35
-29
lines changed

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

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
134134

135135
dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
136136
clear_bit(atu_index, ep->ib_window_map);
137+
ep->epf_bar[bar] = NULL;
137138
}
138139

139140
static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
@@ -167,6 +168,7 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
167168
dw_pcie_writel_dbi(pci, reg + 4, 0);
168169
}
169170

171+
ep->epf_bar[bar] = epf_bar;
170172
dw_pcie_dbi_ro_wr_dis(pci);
171173

172174
return 0;
@@ -429,55 +431,41 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
429431
u16 interrupt_num)
430432
{
431433
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
434+
struct pci_epf_msix_tbl *msix_tbl;
432435
struct pci_epc *epc = ep->epc;
433-
u16 tbl_offset, bir;
434-
u32 bar_addr_upper, bar_addr_lower;
435-
u32 msg_addr_upper, msg_addr_lower;
436+
struct pci_epf_bar *epf_bar;
436437
u32 reg, msg_data, vec_ctrl;
437-
u64 tbl_addr, msg_addr, reg_u64;
438-
void __iomem *msix_tbl;
438+
unsigned int aligned_offset;
439+
u32 tbl_offset;
440+
u64 msg_addr;
439441
int ret;
442+
u8 bir;
440443

441444
reg = ep->msix_cap + PCI_MSIX_TABLE;
442445
tbl_offset = dw_pcie_readl_dbi(pci, reg);
443446
bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
444447
tbl_offset &= PCI_MSIX_TABLE_OFFSET;
445448

446-
reg = PCI_BASE_ADDRESS_0 + (4 * bir);
447-
bar_addr_upper = 0;
448-
bar_addr_lower = dw_pcie_readl_dbi(pci, reg);
449-
reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK);
450-
if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64)
451-
bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4);
449+
epf_bar = ep->epf_bar[bir];
450+
msix_tbl = epf_bar->addr;
451+
msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
452452

453-
tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower;
454-
tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE));
455-
tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK;
456-
457-
msix_tbl = ioremap(ep->phys_base + tbl_addr,
458-
PCI_MSIX_ENTRY_SIZE);
459-
if (!msix_tbl)
460-
return -EINVAL;
461-
462-
msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR);
463-
msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR);
464-
msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
465-
msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA);
466-
vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL);
467-
468-
iounmap(msix_tbl);
453+
msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
454+
msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
455+
vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
469456

470457
if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) {
471458
dev_dbg(pci->dev, "MSI-X entry ctrl set\n");
472459
return -EPERM;
473460
}
474461

475-
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
462+
aligned_offset = msg_addr & (epc->mem->page_size - 1);
463+
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
476464
epc->mem->page_size);
477465
if (ret)
478466
return ret;
479467

480-
writel(msg_data, ep->msi_mem);
468+
writel(msg_data, ep->msi_mem + aligned_offset);
481469

482470
dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
483471

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ struct dw_pcie_ep {
233233
phys_addr_t msi_mem_phys;
234234
u8 msi_cap; /* MSI capability offset */
235235
u8 msix_cap; /* MSI-X capability offset */
236+
struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
236237
};
237238

238239
struct dw_pcie_ops {

drivers/pci/endpoint/pci-epf-core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar)
8787
epf->bar[bar].phys_addr);
8888

8989
epf->bar[bar].phys_addr = 0;
90+
epf->bar[bar].addr = NULL;
9091
epf->bar[bar].size = 0;
9192
epf->bar[bar].barno = 0;
9293
epf->bar[bar].flags = 0;
@@ -123,6 +124,7 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
123124
}
124125

125126
epf->bar[bar].phys_addr = phys_addr;
127+
epf->bar[bar].addr = space;
126128
epf->bar[bar].size = size;
127129
epf->bar[bar].barno = bar;
128130
epf->bar[bar].flags |= upper_32_bits(size) ?

include/linux/pci-epf.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,12 @@ struct pci_epf_driver {
9494
/**
9595
* struct pci_epf_bar - represents the BAR of EPF device
9696
* @phys_addr: physical address that should be mapped to the BAR
97+
* @addr: virtual address corresponding to the @phys_addr
9798
* @size: the size of the address space present in BAR
9899
*/
99100
struct pci_epf_bar {
100101
dma_addr_t phys_addr;
102+
void *addr;
101103
size_t size;
102104
enum pci_barno barno;
103105
int flags;
@@ -134,6 +136,19 @@ struct pci_epf {
134136
struct mutex lock;
135137
};
136138

139+
/**
140+
* struct pci_epf_msix_tbl - represents the MSIX table entry structure
141+
* @msg_addr: Writes to this address will trigger MSIX interrupt in host
142+
* @msg_data: Data that should be written to @msg_addr to trigger MSIX interrupt
143+
* @vector_ctrl: Identifies if the function is prohibited from sending a message
144+
* using this MSIX table entry
145+
*/
146+
struct pci_epf_msix_tbl {
147+
u64 msg_addr;
148+
u32 msg_data;
149+
u32 vector_ctrl;
150+
};
151+
137152
#define to_pci_epf(epf_dev) container_of((epf_dev), struct pci_epf, dev)
138153

139154
#define pci_epf_register_driver(driver) \

0 commit comments

Comments
 (0)