forked from mirrors/linux
		
	PCI: dwc: Fix dw_pcie_ep_raise_msix_irq() to get correct MSI-X table address
commitbeb4641a78("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:beb4641a78("PCI: dwc: Add MSI-X callbacks handler") Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
This commit is contained in:
		
							parent
							
								
									83153d9f36
								
							
						
					
					
						commit
						6f5e193bfb
					
				
					 4 changed files with 35 additions and 29 deletions
				
			
		| 
						 | 
				
			
			@ -134,6 +134,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
 | 
			
		|||
 | 
			
		||||
	dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
 | 
			
		||||
	clear_bit(atu_index, ep->ib_window_map);
 | 
			
		||||
	ep->epf_bar[bar] = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		|||
		dw_pcie_writel_dbi(pci, reg + 4, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ep->epf_bar[bar] = epf_bar;
 | 
			
		||||
	dw_pcie_dbi_ro_wr_dis(pci);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -429,55 +431,41 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
 | 
			
		|||
			     u16 interrupt_num)
 | 
			
		||||
{
 | 
			
		||||
	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 | 
			
		||||
	struct pci_epf_msix_tbl *msix_tbl;
 | 
			
		||||
	struct pci_epc *epc = ep->epc;
 | 
			
		||||
	u16 tbl_offset, bir;
 | 
			
		||||
	u32 bar_addr_upper, bar_addr_lower;
 | 
			
		||||
	u32 msg_addr_upper, msg_addr_lower;
 | 
			
		||||
	struct pci_epf_bar *epf_bar;
 | 
			
		||||
	u32 reg, msg_data, vec_ctrl;
 | 
			
		||||
	u64 tbl_addr, msg_addr, reg_u64;
 | 
			
		||||
	void __iomem *msix_tbl;
 | 
			
		||||
	unsigned int aligned_offset;
 | 
			
		||||
	u32 tbl_offset;
 | 
			
		||||
	u64 msg_addr;
 | 
			
		||||
	int ret;
 | 
			
		||||
	u8 bir;
 | 
			
		||||
 | 
			
		||||
	reg = ep->msix_cap + PCI_MSIX_TABLE;
 | 
			
		||||
	tbl_offset = dw_pcie_readl_dbi(pci, reg);
 | 
			
		||||
	bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
 | 
			
		||||
	tbl_offset &= PCI_MSIX_TABLE_OFFSET;
 | 
			
		||||
 | 
			
		||||
	reg = PCI_BASE_ADDRESS_0 + (4 * bir);
 | 
			
		||||
	bar_addr_upper = 0;
 | 
			
		||||
	bar_addr_lower = dw_pcie_readl_dbi(pci, reg);
 | 
			
		||||
	reg_u64 = (bar_addr_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK);
 | 
			
		||||
	if (reg_u64 == PCI_BASE_ADDRESS_MEM_TYPE_64)
 | 
			
		||||
		bar_addr_upper = dw_pcie_readl_dbi(pci, reg + 4);
 | 
			
		||||
	epf_bar = ep->epf_bar[bir];
 | 
			
		||||
	msix_tbl = epf_bar->addr;
 | 
			
		||||
	msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
 | 
			
		||||
 | 
			
		||||
	tbl_addr = ((u64) bar_addr_upper) << 32 | bar_addr_lower;
 | 
			
		||||
	tbl_addr += (tbl_offset + ((interrupt_num - 1) * PCI_MSIX_ENTRY_SIZE));
 | 
			
		||||
	tbl_addr &= PCI_BASE_ADDRESS_MEM_MASK;
 | 
			
		||||
 | 
			
		||||
	msix_tbl = ioremap(ep->phys_base + tbl_addr,
 | 
			
		||||
				   PCI_MSIX_ENTRY_SIZE);
 | 
			
		||||
	if (!msix_tbl)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	msg_addr_lower = readl(msix_tbl + PCI_MSIX_ENTRY_LOWER_ADDR);
 | 
			
		||||
	msg_addr_upper = readl(msix_tbl + PCI_MSIX_ENTRY_UPPER_ADDR);
 | 
			
		||||
	msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
 | 
			
		||||
	msg_data = readl(msix_tbl + PCI_MSIX_ENTRY_DATA);
 | 
			
		||||
	vec_ctrl = readl(msix_tbl + PCI_MSIX_ENTRY_VECTOR_CTRL);
 | 
			
		||||
 | 
			
		||||
	iounmap(msix_tbl);
 | 
			
		||||
	msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
 | 
			
		||||
	msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
 | 
			
		||||
	vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
 | 
			
		||||
 | 
			
		||||
	if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) {
 | 
			
		||||
		dev_dbg(pci->dev, "MSI-X entry ctrl set\n");
 | 
			
		||||
		return -EPERM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
 | 
			
		||||
	aligned_offset = msg_addr & (epc->mem->page_size - 1);
 | 
			
		||||
	ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys,  msg_addr,
 | 
			
		||||
				  epc->mem->page_size);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	writel(msg_data, ep->msi_mem);
 | 
			
		||||
	writel(msg_data, ep->msi_mem + aligned_offset);
 | 
			
		||||
 | 
			
		||||
	dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -233,6 +233,7 @@ struct dw_pcie_ep {
 | 
			
		|||
	phys_addr_t		msi_mem_phys;
 | 
			
		||||
	u8			msi_cap;	/* MSI capability offset */
 | 
			
		||||
	u8			msix_cap;	/* MSI-X capability offset */
 | 
			
		||||
	struct pci_epf_bar	*epf_bar[PCI_STD_NUM_BARS];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct dw_pcie_ops {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,6 +87,7 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar)
 | 
			
		|||
			  epf->bar[bar].phys_addr);
 | 
			
		||||
 | 
			
		||||
	epf->bar[bar].phys_addr = 0;
 | 
			
		||||
	epf->bar[bar].addr = NULL;
 | 
			
		||||
	epf->bar[bar].size = 0;
 | 
			
		||||
	epf->bar[bar].barno = 0;
 | 
			
		||||
	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,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	epf->bar[bar].phys_addr = phys_addr;
 | 
			
		||||
	epf->bar[bar].addr = space;
 | 
			
		||||
	epf->bar[bar].size = size;
 | 
			
		||||
	epf->bar[bar].barno = bar;
 | 
			
		||||
	epf->bar[bar].flags |= upper_32_bits(size) ?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,10 +94,12 @@ struct pci_epf_driver {
 | 
			
		|||
/**
 | 
			
		||||
 * struct pci_epf_bar - represents the BAR of EPF device
 | 
			
		||||
 * @phys_addr: physical address that should be mapped to the BAR
 | 
			
		||||
 * @addr: virtual address corresponding to the @phys_addr
 | 
			
		||||
 * @size: the size of the address space present in BAR
 | 
			
		||||
 */
 | 
			
		||||
struct pci_epf_bar {
 | 
			
		||||
	dma_addr_t	phys_addr;
 | 
			
		||||
	void		*addr;
 | 
			
		||||
	size_t		size;
 | 
			
		||||
	enum pci_barno	barno;
 | 
			
		||||
	int		flags;
 | 
			
		||||
| 
						 | 
				
			
			@ -134,6 +136,19 @@ struct pci_epf {
 | 
			
		|||
	struct mutex		lock;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct pci_epf_msix_tbl - represents the MSIX table entry structure
 | 
			
		||||
 * @msg_addr: Writes to this address will trigger MSIX interrupt in host
 | 
			
		||||
 * @msg_data: Data that should be written to @msg_addr to trigger MSIX interrupt
 | 
			
		||||
 * @vector_ctrl: Identifies if the function is prohibited from sending a message
 | 
			
		||||
 * using this MSIX table entry
 | 
			
		||||
 */
 | 
			
		||||
struct pci_epf_msix_tbl {
 | 
			
		||||
	u64 msg_addr;
 | 
			
		||||
	u32 msg_data;
 | 
			
		||||
	u32 vector_ctrl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define to_pci_epf(epf_dev) container_of((epf_dev), struct pci_epf, dev)
 | 
			
		||||
 | 
			
		||||
#define pci_epf_register_driver(driver)    \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue