Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/fsl: Setup PCI inbound window based on actual amount of memory

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>

+115 -21
+110 -20
arch/powerpc/sysdev/fsl_pci.c
··· 23 23 #include <linux/string.h> 24 24 #include <linux/init.h> 25 25 #include <linux/bootmem.h> 26 + #include <linux/lmb.h> 27 + #include <linux/log2.h> 26 28 27 29 #include <asm/io.h> 28 30 #include <asm/prom.h> ··· 98 96 struct resource *rsrc) 99 97 { 100 98 struct ccsr_pci __iomem *pci; 101 - int i, j, n; 99 + int i, j, n, mem_log, win_idx = 2; 100 + u64 mem, sz, paddr_hi = 0; 101 + u64 paddr_lo = ULLONG_MAX; 102 + u32 pcicsrbar = 0, pcicsrbar_sz; 103 + u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL | 104 + PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; 105 + char *name = hose->dn->full_name; 102 106 103 107 pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", 104 108 (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); ··· 124 116 for(i = 0, j = 1; i < 3; i++) { 125 117 if (!(hose->mem_resources[i].flags & IORESOURCE_MEM)) 126 118 continue; 119 + 120 + paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start); 121 + paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end); 127 122 128 123 n = setup_one_atmu(pci, j, &hose->mem_resources[i], 129 124 hose->pci_mem_offset); ··· 158 147 } 159 148 } 160 149 161 - /* Setup 2G inbound Memory Window @ 1 */ 162 - out_be32(&pci->piw[2].pitar, 0x00000000); 163 - out_be32(&pci->piw[2].piwbar,0x00000000); 164 - out_be32(&pci->piw[2].piwar, PIWAR_2G); 150 + /* convert to pci address space */ 151 + paddr_hi -= hose->pci_mem_offset; 152 + paddr_lo -= hose->pci_mem_offset; 165 153 166 - /* Save the base address and size covered by inbound window mappings */ 167 - hose->dma_window_base_cur = 0x00000000; 168 - hose->dma_window_size = 0x80000000; 154 + if (paddr_hi == paddr_lo) { 155 + pr_err("%s: No outbound window space\n", name); 156 + return ; 157 + } 158 + 159 + if (paddr_lo == 0) { 160 + pr_err("%s: No space for inbound window\n", name); 161 + return ; 162 + } 163 + 164 + /* setup PCSRBAR/PEXCSRBAR */ 165 + early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff); 166 + early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz); 167 + pcicsrbar_sz = ~pcicsrbar_sz + 1; 168 + 169 + if (paddr_hi < (0x100000000ull - pcicsrbar_sz) || 170 + (paddr_lo > 0x100000000ull)) 171 + pcicsrbar = 0x100000000ull - pcicsrbar_sz; 172 + else 173 + pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz; 174 + early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar); 175 + 176 + paddr_lo = min(paddr_lo, (u64)pcicsrbar); 177 + 178 + pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar); 179 + 180 + /* Setup inbound mem window */ 181 + mem = lmb_end_of_DRAM(); 182 + sz = min(mem, paddr_lo); 183 + mem_log = __ilog2_u64(sz); 184 + 185 + /* PCIe can overmap inbound & outbound since RX & TX are separated */ 186 + if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) { 187 + /* Size window to exact size if power-of-two or one size up */ 188 + if ((1ull << mem_log) != mem) { 189 + if ((1ull << mem_log) > mem) 190 + pr_info("%s: Setting PCI inbound window " 191 + "greater than memory size\n", name); 192 + mem_log++; 193 + } 194 + 195 + piwar |= (mem_log - 1); 196 + 197 + /* Setup inbound memory window */ 198 + out_be32(&pci->piw[win_idx].pitar, 0x00000000); 199 + out_be32(&pci->piw[win_idx].piwbar, 0x00000000); 200 + out_be32(&pci->piw[win_idx].piwar, piwar); 201 + win_idx--; 202 + 203 + hose->dma_window_base_cur = 0x00000000; 204 + hose->dma_window_size = (resource_size_t)sz; 205 + } else { 206 + u64 paddr = 0; 207 + 208 + /* Setup inbound memory window */ 209 + out_be32(&pci->piw[win_idx].pitar, paddr >> 12); 210 + out_be32(&pci->piw[win_idx].piwbar, paddr >> 12); 211 + out_be32(&pci->piw[win_idx].piwar, (piwar | (mem_log - 1))); 212 + win_idx--; 213 + 214 + paddr += 1ull << mem_log; 215 + sz -= 1ull << mem_log; 216 + 217 + if (sz) { 218 + mem_log = __ilog2_u64(sz); 219 + piwar |= (mem_log - 1); 220 + 221 + out_be32(&pci->piw[win_idx].pitar, paddr >> 12); 222 + out_be32(&pci->piw[win_idx].piwbar, paddr >> 12); 223 + out_be32(&pci->piw[win_idx].piwar, piwar); 224 + win_idx--; 225 + 226 + paddr += 1ull << mem_log; 227 + } 228 + 229 + hose->dma_window_base_cur = 0x00000000; 230 + hose->dma_window_size = (resource_size_t)paddr; 231 + } 232 + 233 + if (hose->dma_window_size < mem) { 234 + #ifndef CONFIG_SWIOTLB 235 + pr_err("%s: ERROR: Memory size exceeds PCI ATMU ability to " 236 + "map - enable CONFIG_SWIOTLB to avoid dma errors.\n", 237 + name); 238 + #endif 239 + /* adjusting outbound windows could reclaim space in mem map */ 240 + if (paddr_hi < 0xffffffffull) 241 + pr_warning("%s: WARNING: Outbound window cfg leaves " 242 + "gaps in memory map. Adjusting the memory map " 243 + "could reduce unnecessary bounce buffering.\n", 244 + name); 245 + 246 + pr_info("%s: DMA window size is 0x%llx\n", name, 247 + (u64)hose->dma_window_size); 248 + } 169 249 170 250 iounmap(pci); 171 251 } ··· 280 178 } else { 281 179 early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80); 282 180 } 283 - } 284 - 285 - static void __init setup_pci_pcsrbar(struct pci_controller *hose) 286 - { 287 - #ifdef CONFIG_PCI_MSI 288 - phys_addr_t immr_base; 289 - 290 - immr_base = get_immrbase(); 291 - early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, immr_base); 292 - #endif 293 181 } 294 182 295 183 void fsl_pcibios_fixup_bus(struct pci_bus *bus) ··· 365 273 /* Setup PEX window registers */ 366 274 setup_pci_atmu(hose, &rsrc); 367 275 368 - /* Setup PEXCSRBAR */ 369 - setup_pci_pcsrbar(hose); 370 276 return 0; 371 277 } 372 278
+5 -1
arch/powerpc/sysdev/fsl_pci.h
··· 16 16 17 17 #define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */ 18 18 #define PCIE_LTSSM_L0 0x16 /* L0 state */ 19 - #define PIWAR_2G 0xa0f5501e /* Enable, Prefetch, Local Mem, Snoop R/W, 2G */ 19 + #define PIWAR_EN 0x80000000 /* Enable */ 20 + #define PIWAR_PF 0x20000000 /* prefetch */ 21 + #define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */ 22 + #define PIWAR_READ_SNOOP 0x00050000 23 + #define PIWAR_WRITE_SNOOP 0x00005000 20 24 21 25 /* PCI/PCI Express outbound window reg */ 22 26 struct pci_outbound_window_regs {