aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorKumar Gala <galak@kernel.crashing.org>2009-05-08 16:05:23 -0400
committerKumar Gala <galak@kernel.crashing.org>2009-05-19 01:50:44 -0400
commit54c181935d2a2d46a1b2f00cbb25acc35e4f5ee2 (patch)
treebc2dfbf4f9199d8735fcca96c5d3cb2c6aea56cb /arch
parent01af9507ff36578dad89b1cc88ff37ac18e719cb (diff)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c130
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h6
2 files changed, 115 insertions, 21 deletions
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index b20171d9df0c..0de91c62e3d2 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -23,6 +23,8 @@
23#include <linux/string.h> 23#include <linux/string.h>
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/bootmem.h> 25#include <linux/bootmem.h>
26#include <linux/lmb.h>
27#include <linux/log2.h>
26 28
27#include <asm/io.h> 29#include <asm/io.h>
28#include <asm/prom.h> 30#include <asm/prom.h>
@@ -96,7 +98,13 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
96 struct resource *rsrc) 98 struct resource *rsrc)
97{ 99{
98 struct ccsr_pci __iomem *pci; 100 struct ccsr_pci __iomem *pci;
99 int i, j, n; 101 int i, j, n, mem_log, win_idx = 2;
102 u64 mem, sz, paddr_hi = 0;
103 u64 paddr_lo = ULLONG_MAX;
104 u32 pcicsrbar = 0, pcicsrbar_sz;
105 u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
106 PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
107 char *name = hose->dn->full_name;
100 108
101 pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", 109 pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
102 (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); 110 (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1);
@@ -117,6 +125,9 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
117 if (!(hose->mem_resources[i].flags & IORESOURCE_MEM)) 125 if (!(hose->mem_resources[i].flags & IORESOURCE_MEM))
118 continue; 126 continue;
119 127
128 paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start);
129 paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end);
130
120 n = setup_one_atmu(pci, j, &hose->mem_resources[i], 131 n = setup_one_atmu(pci, j, &hose->mem_resources[i],
121 hose->pci_mem_offset); 132 hose->pci_mem_offset);
122 133
@@ -147,14 +158,105 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
147 } 158 }
148 } 159 }
149 160
150 /* Setup 2G inbound Memory Window @ 1 */ 161 /* convert to pci address space */
151 out_be32(&pci->piw[2].pitar, 0x00000000); 162 paddr_hi -= hose->pci_mem_offset;
152 out_be32(&pci->piw[2].piwbar,0x00000000); 163 paddr_lo -= hose->pci_mem_offset;
153 out_be32(&pci->piw[2].piwar, PIWAR_2G); 164
165 if (paddr_hi == paddr_lo) {
166 pr_err("%s: No outbound window space\n", name);
167 return ;
168 }
169
170 if (paddr_lo == 0) {
171 pr_err("%s: No space for inbound window\n", name);
172 return ;
173 }
174
175 /* setup PCSRBAR/PEXCSRBAR */
176 early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff);
177 early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
178 pcicsrbar_sz = ~pcicsrbar_sz + 1;
179
180 if (paddr_hi < (0x100000000ull - pcicsrbar_sz) ||
181 (paddr_lo > 0x100000000ull))
182 pcicsrbar = 0x100000000ull - pcicsrbar_sz;
183 else
184 pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz;
185 early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar);
186
187 paddr_lo = min(paddr_lo, (u64)pcicsrbar);
154 188
155 /* Save the base address and size covered by inbound window mappings */ 189 pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar);
156 hose->dma_window_base_cur = 0x00000000; 190
157 hose->dma_window_size = 0x80000000; 191 /* Setup inbound mem window */
192 mem = lmb_end_of_DRAM();
193 sz = min(mem, paddr_lo);
194 mem_log = __ilog2_u64(sz);
195
196 /* PCIe can overmap inbound & outbound since RX & TX are separated */
197 if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
198 /* Size window to exact size if power-of-two or one size up */
199 if ((1ull << mem_log) != mem) {
200 if ((1ull << mem_log) > mem)
201 pr_info("%s: Setting PCI inbound window "
202 "greater than memory size\n", name);
203 mem_log++;
204 }
205
206 piwar |= (mem_log - 1);
207
208 /* Setup inbound memory window */
209 out_be32(&pci->piw[win_idx].pitar, 0x00000000);
210 out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
211 out_be32(&pci->piw[win_idx].piwar, piwar);
212 win_idx--;
213
214 hose->dma_window_base_cur = 0x00000000;
215 hose->dma_window_size = (resource_size_t)sz;
216 } else {
217 u64 paddr = 0;
218
219 /* Setup inbound memory window */
220 out_be32(&pci->piw[win_idx].pitar, paddr >> 12);
221 out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
222 out_be32(&pci->piw[win_idx].piwar, (piwar | (mem_log - 1)));
223 win_idx--;
224
225 paddr += 1ull << mem_log;
226 sz -= 1ull << mem_log;
227
228 if (sz) {
229 mem_log = __ilog2_u64(sz);
230 piwar |= (mem_log - 1);
231
232 out_be32(&pci->piw[win_idx].pitar, paddr >> 12);
233 out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
234 out_be32(&pci->piw[win_idx].piwar, piwar);
235 win_idx--;
236
237 paddr += 1ull << mem_log;
238 }
239
240 hose->dma_window_base_cur = 0x00000000;
241 hose->dma_window_size = (resource_size_t)paddr;
242 }
243
244 if (hose->dma_window_size < mem) {
245#ifndef CONFIG_SWIOTLB
246 pr_err("%s: ERROR: Memory size exceeds PCI ATMU ability to "
247 "map - enable CONFIG_SWIOTLB to avoid dma errors.\n",
248 name);
249#endif
250 /* adjusting outbound windows could reclaim space in mem map */
251 if (paddr_hi < 0xffffffffull)
252 pr_warning("%s: WARNING: Outbound window cfg leaves "
253 "gaps in memory map. Adjusting the memory map "
254 "could reduce unnecessary bounce buffering.\n",
255 name);
256
257 pr_info("%s: DMA window size is 0x%llx\n", name,
258 (u64)hose->dma_window_size);
259 }
158 260
159 iounmap(pci); 261 iounmap(pci);
160} 262}
@@ -180,16 +282,6 @@ static void __init setup_pci_cmd(struct pci_controller *hose)
180 } 282 }
181} 283}
182 284
183static void __init setup_pci_pcsrbar(struct pci_controller *hose)
184{
185#ifdef CONFIG_PCI_MSI
186 phys_addr_t immr_base;
187
188 immr_base = get_immrbase();
189 early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, immr_base);
190#endif
191}
192
193void fsl_pcibios_fixup_bus(struct pci_bus *bus) 285void fsl_pcibios_fixup_bus(struct pci_bus *bus)
194{ 286{
195 struct pci_controller *hose = (struct pci_controller *) bus->sysdata; 287 struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
@@ -273,8 +365,6 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary)
273 /* Setup PEX window registers */ 365 /* Setup PEX window registers */
274 setup_pci_atmu(hose, &rsrc); 366 setup_pci_atmu(hose, &rsrc);
275 367
276 /* Setup PEXCSRBAR */
277 setup_pci_pcsrbar(hose);
278 return 0; 368 return 0;
279} 369}
280 370
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index 13f30c2a61e7..a9d8bbebed80 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -16,7 +16,11 @@
16 16
17#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */ 17#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */
18#define PCIE_LTSSM_L0 0x16 /* L0 state */ 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/* PCI/PCI Express outbound window reg */ 25/* PCI/PCI Express outbound window reg */
22struct pci_outbound_window_regs { 26struct pci_outbound_window_regs {