Skip to content

Commit

Permalink
powerpc/fsl: Setup PCI inbound window based on actual amount of memory
Browse files Browse the repository at this point in the history
Previouslly we just always set the inbound window to 2G.  This was
broken for systems with >2G.  If a system has >=4G we will need
SWIOTLB support to handle that case.

We now allocate PCICSRBAR/PEXCSRBAR right below the lowest PCI outbound
address for MMIO or the 4G boundary (if the lowest PCI address is above
4G).

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
  • Loading branch information
Kumar Gala committed May 19, 2009
1 parent 01af950 commit 54c1819
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 21 deletions.
130 changes: 110 additions & 20 deletions arch/powerpc/sysdev/fsl_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -147,14 +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);

/* Save the base address and size covered by inbound window mappings */
hose->dma_window_base_cur = 0x00000000;
hose->dma_window_size = 0x80000000;
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);
}
Expand All @@ -180,16 +282,6 @@ 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;
Expand Down Expand Up @@ -273,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;
}

Expand Down
6 changes: 5 additions & 1 deletion arch/powerpc/sysdev/fsl_pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@

#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */
#define PCIE_LTSSM_L0 0x16 /* L0 state */
#define PIWAR_2G 0xa0f5501e /* Enable, Prefetch, Local Mem, Snoop R/W, 2G */
#define PIWAR_EN 0x80000000 /* Enable */
#define PIWAR_PF 0x20000000 /* prefetch */
#define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */
#define PIWAR_READ_SNOOP 0x00050000
#define PIWAR_WRITE_SNOOP 0x00005000

/* PCI/PCI Express outbound window reg */
struct pci_outbound_window_regs {
Expand Down

0 comments on commit 54c1819

Please sign in to comment.