diff options
Diffstat (limited to 'arch/powerpc/sysdev/fsl_pci.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 4ce547e00473..3b61e8cf3421 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c | |||
@@ -65,6 +65,30 @@ static int __init fsl_pcie_check_link(struct pci_controller *hose) | |||
65 | } | 65 | } |
66 | 66 | ||
67 | #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) | 67 | #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) |
68 | |||
69 | #define MAX_PHYS_ADDR_BITS 40 | ||
70 | static u64 pci64_dma_offset = 1ull << MAX_PHYS_ADDR_BITS; | ||
71 | |||
72 | static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask) | ||
73 | { | ||
74 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | ||
75 | return -EIO; | ||
76 | |||
77 | /* | ||
78 | * Fixup PCI devices that are able to DMA to above the physical | ||
79 | * address width of the SoC such that we can address any internal | ||
80 | * SoC address from across PCI if needed | ||
81 | */ | ||
82 | if ((dev->bus == &pci_bus_type) && | ||
83 | dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) { | ||
84 | set_dma_ops(dev, &dma_direct_ops); | ||
85 | set_dma_offset(dev, pci64_dma_offset); | ||
86 | } | ||
87 | |||
88 | *dev->dma_mask = dma_mask; | ||
89 | return 0; | ||
90 | } | ||
91 | |||
68 | static int __init setup_one_atmu(struct ccsr_pci __iomem *pci, | 92 | static int __init setup_one_atmu(struct ccsr_pci __iomem *pci, |
69 | unsigned int index, const struct resource *res, | 93 | unsigned int index, const struct resource *res, |
70 | resource_size_t offset) | 94 | resource_size_t offset) |
@@ -113,6 +137,8 @@ static void __init setup_pci_atmu(struct pci_controller *hose, | |||
113 | u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL | | 137 | u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL | |
114 | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; | 138 | PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; |
115 | char *name = hose->dn->full_name; | 139 | char *name = hose->dn->full_name; |
140 | const u64 *reg; | ||
141 | int len; | ||
116 | 142 | ||
117 | pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", | 143 | pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", |
118 | (u64)rsrc->start, (u64)resource_size(rsrc)); | 144 | (u64)rsrc->start, (u64)resource_size(rsrc)); |
@@ -205,6 +231,33 @@ static void __init setup_pci_atmu(struct pci_controller *hose, | |||
205 | 231 | ||
206 | /* Setup inbound mem window */ | 232 | /* Setup inbound mem window */ |
207 | mem = memblock_end_of_DRAM(); | 233 | mem = memblock_end_of_DRAM(); |
234 | |||
235 | /* | ||
236 | * The msi-address-64 property, if it exists, indicates the physical | ||
237 | * address of the MSIIR register. Normally, this register is located | ||
238 | * inside CCSR, so the ATMU that covers all of CCSR is used. But if | ||
239 | * this property exists, then we normally need to create a new ATMU | ||
240 | * for it. For now, however, we cheat. The only entity that creates | ||
241 | * this property is the Freescale hypervisor, and the address is | ||
242 | * specified in the partition configuration. Typically, the address | ||
243 | * is located in the page immediately after the end of DDR. If so, we | ||
244 | * can avoid allocating a new ATMU by extending the DDR ATMU by one | ||
245 | * page. | ||
246 | */ | ||
247 | reg = of_get_property(hose->dn, "msi-address-64", &len); | ||
248 | if (reg && (len == sizeof(u64))) { | ||
249 | u64 address = be64_to_cpup(reg); | ||
250 | |||
251 | if ((address >= mem) && (address < (mem + PAGE_SIZE))) { | ||
252 | pr_info("%s: extending DDR ATMU to cover MSIIR", name); | ||
253 | mem += PAGE_SIZE; | ||
254 | } else { | ||
255 | /* TODO: Create a new ATMU for MSIIR */ | ||
256 | pr_warn("%s: msi-address-64 address of %llx is " | ||
257 | "unsupported\n", name, address); | ||
258 | } | ||
259 | } | ||
260 | |||
208 | sz = min(mem, paddr_lo); | 261 | sz = min(mem, paddr_lo); |
209 | mem_log = __ilog2_u64(sz); | 262 | mem_log = __ilog2_u64(sz); |
210 | 263 | ||
@@ -228,6 +281,37 @@ static void __init setup_pci_atmu(struct pci_controller *hose, | |||
228 | 281 | ||
229 | hose->dma_window_base_cur = 0x00000000; | 282 | hose->dma_window_base_cur = 0x00000000; |
230 | hose->dma_window_size = (resource_size_t)sz; | 283 | hose->dma_window_size = (resource_size_t)sz; |
284 | |||
285 | /* | ||
286 | * if we have >4G of memory setup second PCI inbound window to | ||
287 | * let devices that are 64-bit address capable to work w/o | ||
288 | * SWIOTLB and access the full range of memory | ||
289 | */ | ||
290 | if (sz != mem) { | ||
291 | mem_log = __ilog2_u64(mem); | ||
292 | |||
293 | /* Size window up if we dont fit in exact power-of-2 */ | ||
294 | if ((1ull << mem_log) != mem) | ||
295 | mem_log++; | ||
296 | |||
297 | piwar = (piwar & ~PIWAR_SZ_MASK) | (mem_log - 1); | ||
298 | |||
299 | /* Setup inbound memory window */ | ||
300 | out_be32(&pci->piw[win_idx].pitar, 0x00000000); | ||
301 | out_be32(&pci->piw[win_idx].piwbear, | ||
302 | pci64_dma_offset >> 44); | ||
303 | out_be32(&pci->piw[win_idx].piwbar, | ||
304 | pci64_dma_offset >> 12); | ||
305 | out_be32(&pci->piw[win_idx].piwar, piwar); | ||
306 | |||
307 | /* | ||
308 | * install our own dma_set_mask handler to fixup dma_ops | ||
309 | * and dma_offset | ||
310 | */ | ||
311 | ppc_md.dma_set_mask = fsl_pci_dma_set_mask; | ||
312 | |||
313 | pr_info("%s: Setup 64-bit PCI DMA window\n", name); | ||
314 | } | ||
231 | } else { | 315 | } else { |
232 | u64 paddr = 0; | 316 | u64 paddr = 0; |
233 | 317 | ||