diff options
Diffstat (limited to 'drivers/pci/controller/dwc/pcie-designware-ep.c')
| -rw-r--r-- | drivers/pci/controller/dwc/pcie-designware-ep.c | 55 | 
1 files changed, 44 insertions, 11 deletions
| diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 24f5a775ad34..2bf5a35c0570 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -46,16 +46,19 @@ static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie *pci, u8 cap_ptr,  	u8 cap_id, next_cap_ptr;  	u16 reg; +	if (!cap_ptr) +		return 0; +  	reg = dw_pcie_readw_dbi(pci, cap_ptr); -	next_cap_ptr = (reg & 0xff00) >> 8;  	cap_id = (reg & 0x00ff); -	if (!next_cap_ptr || cap_id > PCI_CAP_ID_MAX) +	if (cap_id > PCI_CAP_ID_MAX)  		return 0;  	if (cap_id == cap)  		return cap_ptr; +	next_cap_ptr = (reg & 0xff00) >> 8;  	return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);  } @@ -67,9 +70,6 @@ static u8 dw_pcie_ep_find_capability(struct dw_pcie *pci, u8 cap)  	reg = dw_pcie_readw_dbi(pci, PCI_CAPABILITY_LIST);  	next_cap_ptr = (reg & 0x00ff); -	if (!next_cap_ptr) -		return 0; -  	return __dw_pcie_ep_find_next_cap(pci, next_cap_ptr, cap);  } @@ -397,6 +397,7 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,  {  	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);  	struct pci_epc *epc = ep->epc; +	unsigned int aligned_offset;  	u16 msg_ctrl, msg_data;  	u32 msg_addr_lower, msg_addr_upper, reg;  	u64 msg_addr; @@ -422,13 +423,15 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,  		reg = ep->msi_cap + PCI_MSI_DATA_32;  		msg_data = dw_pcie_readw_dbi(pci, reg);  	} -	msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower; +	aligned_offset = msg_addr_lower & (epc->mem->page_size - 1); +	msg_addr = ((u64)msg_addr_upper) << 32 | +			(msg_addr_lower & ~aligned_offset);  	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 | (interrupt_num - 1), ep->msi_mem); +	writel(msg_data | (interrupt_num - 1), ep->msi_mem + aligned_offset);  	dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys); @@ -504,10 +507,32 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)  	pci_epc_mem_exit(epc);  } +static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap) +{ +	u32 header; +	int pos = PCI_CFG_SPACE_SIZE; + +	while (pos) { +		header = dw_pcie_readl_dbi(pci, pos); +		if (PCI_EXT_CAP_ID(header) == cap) +			return pos; + +		pos = PCI_EXT_CAP_NEXT(header); +		if (!pos) +			break; +	} + +	return 0; +} +  int dw_pcie_ep_init(struct dw_pcie_ep *ep)  { +	int i;  	int ret; +	u32 reg;  	void *addr; +	unsigned int nbars; +	unsigned int offset;  	struct pci_epc *epc;  	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);  	struct device *dev = pci->dev; @@ -517,10 +542,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)  		dev_err(dev, "dbi_base/dbi_base2 is not populated\n");  		return -EINVAL;  	} -	if (pci->iatu_unroll_enabled && !pci->atu_base) { -		dev_err(dev, "atu_base is not populated\n"); -		return -EINVAL; -	}  	ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);  	if (ret < 0) { @@ -595,6 +616,18 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)  	ep->msix_cap = dw_pcie_ep_find_capability(pci, PCI_CAP_ID_MSIX); +	offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR); +	if (offset) { +		reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL); +		nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >> +			PCI_REBAR_CTRL_NBAR_SHIFT; + +		dw_pcie_dbi_ro_wr_en(pci); +		for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL) +			dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0); +		dw_pcie_dbi_ro_wr_dis(pci); +	} +  	dw_pcie_setup(pci);  	return 0; |