diff options
Diffstat (limited to 'arch/powerpc/sysdev/fsl_pci.c')
| -rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 138 | 
1 files changed, 118 insertions, 20 deletions
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 78021d8afc5..ae88b144801 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -23,6 +23,8 @@  #include <linux/string.h>  #include <linux/init.h>  #include <linux/bootmem.h> +#include <linux/lmb.h> +#include <linux/log2.h>  #include <asm/io.h>  #include <asm/prom.h> @@ -96,7 +98,13 @@ static void __init setup_pci_atmu(struct pci_controller *hose,  				  struct resource *rsrc)  {  	struct ccsr_pci __iomem *pci; -	int i, j, n; +	int i, j, n, mem_log, win_idx = 2; +	u64 mem, sz, paddr_hi = 0; +	u64 paddr_lo = ULLONG_MAX; +	u32 pcicsrbar = 0, pcicsrbar_sz; +	u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL | +			PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; +	char *name = hose->dn->full_name;  	pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",  		    (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); @@ -117,6 +125,9 @@ static void __init setup_pci_atmu(struct pci_controller *hose,  		if (!(hose->mem_resources[i].flags & IORESOURCE_MEM))  			continue; +		paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start); +		paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end); +  		n = setup_one_atmu(pci, j, &hose->mem_resources[i],  				   hose->pci_mem_offset); @@ -147,10 +158,105 @@ static void __init setup_pci_atmu(struct pci_controller *hose,  		}  	} -	/* Setup 2G inbound Memory Window @ 1 */ -	out_be32(&pci->piw[2].pitar, 0x00000000); -	out_be32(&pci->piw[2].piwbar,0x00000000); -	out_be32(&pci->piw[2].piwar, PIWAR_2G); +	/* convert to pci address space */ +	paddr_hi -= hose->pci_mem_offset; +	paddr_lo -= hose->pci_mem_offset; + +	if (paddr_hi == paddr_lo) { +		pr_err("%s: No outbound window space\n", name); +		return ; +	} + +	if (paddr_lo == 0) { +		pr_err("%s: No space for inbound window\n", name); +		return ; +	} + +	/* setup PCSRBAR/PEXCSRBAR */ +	early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff); +	early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz); +	pcicsrbar_sz = ~pcicsrbar_sz + 1; + +	if (paddr_hi < (0x100000000ull - pcicsrbar_sz) || +		(paddr_lo > 0x100000000ull)) +		pcicsrbar = 0x100000000ull - pcicsrbar_sz; +	else +		pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz; +	early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar); + +	paddr_lo = min(paddr_lo, (u64)pcicsrbar); + +	pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar); + +	/* Setup inbound mem window */ +	mem = lmb_end_of_DRAM(); +	sz = min(mem, paddr_lo); +	mem_log = __ilog2_u64(sz); + +	/* PCIe can overmap inbound & outbound since RX & TX are separated */ +	if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) { +		/* Size window to exact size if power-of-two or one size up */ +		if ((1ull << mem_log) != mem) { +			if ((1ull << mem_log) > mem) +				pr_info("%s: Setting PCI inbound window " +					"greater than memory size\n", name); +			mem_log++; +		} + +		piwar |= (mem_log - 1); + +		/* Setup inbound memory window */ +		out_be32(&pci->piw[win_idx].pitar,  0x00000000); +		out_be32(&pci->piw[win_idx].piwbar, 0x00000000); +		out_be32(&pci->piw[win_idx].piwar,  piwar); +		win_idx--; + +		hose->dma_window_base_cur = 0x00000000; +		hose->dma_window_size = (resource_size_t)sz; +	} else { +		u64 paddr = 0; + +		/* Setup inbound memory window */ +		out_be32(&pci->piw[win_idx].pitar,  paddr >> 12); +		out_be32(&pci->piw[win_idx].piwbar, paddr >> 12); +		out_be32(&pci->piw[win_idx].piwar,  (piwar | (mem_log - 1))); +		win_idx--; + +		paddr += 1ull << mem_log; +		sz -= 1ull << mem_log; + +		if (sz) { +			mem_log = __ilog2_u64(sz); +			piwar |= (mem_log - 1); + +			out_be32(&pci->piw[win_idx].pitar,  paddr >> 12); +			out_be32(&pci->piw[win_idx].piwbar, paddr >> 12); +			out_be32(&pci->piw[win_idx].piwar,  piwar); +			win_idx--; + +			paddr += 1ull << mem_log; +		} + +		hose->dma_window_base_cur = 0x00000000; +		hose->dma_window_size = (resource_size_t)paddr; +	} + +	if (hose->dma_window_size < mem) { +#ifndef CONFIG_SWIOTLB +		pr_err("%s: ERROR: Memory size exceeds PCI ATMU ability to " +			"map - enable CONFIG_SWIOTLB to avoid dma errors.\n", +			 name); +#endif +		/* adjusting outbound windows could reclaim space in mem map */ +		if (paddr_hi < 0xffffffffull) +			pr_warning("%s: WARNING: Outbound window cfg leaves " +				"gaps in memory map. Adjusting the memory map " +				"could reduce unnecessary bounce buffering.\n", +				name); + +		pr_info("%s: DMA window size is 0x%llx\n", name, +			(u64)hose->dma_window_size); +	}  	iounmap(pci);  } @@ -176,19 +282,9 @@ static void __init setup_pci_cmd(struct pci_controller *hose)  	}  } -static void __init setup_pci_pcsrbar(struct pci_controller *hose) -{ -#ifdef CONFIG_PCI_MSI -	phys_addr_t immr_base; - -	immr_base = get_immrbase(); -	early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, immr_base); -#endif -} -  void fsl_pcibios_fixup_bus(struct pci_bus *bus)  { -	struct pci_controller *hose = (struct pci_controller *) bus->sysdata; +	struct pci_controller *hose = pci_bus_to_host(bus);  	int i;  	if ((bus->parent == hose->bus) && @@ -269,8 +365,6 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary)  	/* Setup PEX window registers */  	setup_pci_atmu(hose, &rsrc); -	/* Setup PEXCSRBAR */ -	setup_pci_pcsrbar(hose);  	return 0;  } @@ -281,6 +375,8 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8543, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8547E, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8545E, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8545, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8569E, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8569, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8568E, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8568, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8567E, quirk_fsl_pcie_header); @@ -296,6 +392,8 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8536, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header);  DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header);  #endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */  #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) @@ -324,7 +422,7 @@ struct mpc83xx_pcie_priv {  static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn)  { -	struct pci_controller *hose = bus->sysdata; +	struct pci_controller *hose = pci_bus_to_host(bus);  	if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK)  		return PCIBIOS_DEVICE_NOT_FOUND; @@ -350,7 +448,7 @@ static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn)  static void __iomem *mpc83xx_pcie_remap_cfg(struct pci_bus *bus,  					    unsigned int devfn, int offset)  { -	struct pci_controller *hose = bus->sysdata; +	struct pci_controller *hose = pci_bus_to_host(bus);  	struct mpc83xx_pcie_priv *pcie = hose->dn->data;  	u8 bus_no = bus->number - hose->first_busno;  	u32 dev_base = bus_no << 24 | devfn << 16;  |