aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2010-08-04 17:53:57 -0400
committerRalf Baechle <ralf@linux-mips.org>2010-08-05 08:26:31 -0400
commit2b5987abaf2dd6c3934e0376b7d9f64411cdcf03 (patch)
tree1d3609613faed623728eed98a83565f781201420 /arch/mips
parent70dc6f045fce6907b5d10377850a78ada6837ffb (diff)
MIPS: Octeon: Allow more than 3.75GB of memory with PCIe
We reserve the 3.75GB - 4GB region of PCIe address space for device to device transfers, making the corresponding physical memory under direct mapping unavailable for DMA. To allow for PCIe DMA to all physical memory we map this chunk of physical memory with BAR1. Because of the resulting discontinuity in the mapping function, we remove a page of memory at each end of the range so multi-page DMA buffers can never be allocated that span the range. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1535/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/cavium-octeon/dma-octeon.c17
-rw-r--r--arch/mips/cavium-octeon/setup.c34
-rw-r--r--arch/mips/include/asm/octeon/pci-octeon.h13
-rw-r--r--arch/mips/pci/pcie-octeon.c37
4 files changed, 87 insertions, 14 deletions
diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c
index be531ec1f206..d22b5a2d64f4 100644
--- a/arch/mips/cavium-octeon/dma-octeon.c
+++ b/arch/mips/cavium-octeon/dma-octeon.c
@@ -99,13 +99,16 @@ dma_addr_t octeon_map_dma_mem(struct device *dev, void *ptr, size_t size)
99 panic("dma_map_single: " 99 panic("dma_map_single: "
100 "Attempt to map illegal memory address 0x%llx\n", 100 "Attempt to map illegal memory address 0x%llx\n",
101 physical); 101 physical);
102 else if ((physical + size >= 102 else if (physical >= CVMX_PCIE_BAR1_PHYS_BASE &&
103 (4ull<<30) - (OCTEON_PCI_BAR1_HOLE_SIZE<<20)) 103 physical + size < (CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_PHYS_SIZE)) {
104 && physical < (4ull<<30)) 104 result = physical - CVMX_PCIE_BAR1_PHYS_BASE + CVMX_PCIE_BAR1_RC_BASE;
105 pr_warning("dma_map_single: Warning: " 105
106 "Mapping memory address that might " 106 if (((result+size-1) & dma_mask) != result+size-1)
107 "conflict with devices 0x%llx-0x%llx\n", 107 panic("dma_map_single: Attempt to map address 0x%llx-0x%llx, which can't be accessed according to the dma mask 0x%llx\n",
108 physical, physical+size-1); 108 physical, physical+size-1, dma_mask);
109 goto done;
110 }
111
109 /* The 2nd 256MB is mapped at 256<<20 instead of 0x410000000 */ 112 /* The 2nd 256MB is mapped at 256<<20 instead of 0x410000000 */
110 if ((physical >= 0x410000000ull) && physical < 0x420000000ull) 113 if ((physical >= 0x410000000ull) && physical < 0x420000000ull)
111 result = physical - 0x400000000ull; 114 result = physical - 0x400000000ull;
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index 041326e34f4d..69197cb6c7ea 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -32,6 +32,7 @@
32#include <asm/time.h> 32#include <asm/time.h>
33 33
34#include <asm/octeon/octeon.h> 34#include <asm/octeon/octeon.h>
35#include <asm/octeon/pci-octeon.h>
35 36
36#ifdef CONFIG_CAVIUM_DECODE_RSL 37#ifdef CONFIG_CAVIUM_DECODE_RSL
37extern void cvmx_interrupt_rsl_decode(void); 38extern void cvmx_interrupt_rsl_decode(void);
@@ -609,6 +610,22 @@ void __init prom_init(void)
609 register_smp_ops(&octeon_smp_ops); 610 register_smp_ops(&octeon_smp_ops);
610} 611}
611 612
613/* Exclude a single page from the regions obtained in plat_mem_setup. */
614static __init void memory_exclude_page(u64 addr, u64 *mem, u64 *size)
615{
616 if (addr > *mem && addr < *mem + *size) {
617 u64 inc = addr - *mem;
618 add_memory_region(*mem, inc, BOOT_MEM_RAM);
619 *mem += inc;
620 *size -= inc;
621 }
622
623 if (addr == *mem && *size > PAGE_SIZE) {
624 *mem += PAGE_SIZE;
625 *size -= PAGE_SIZE;
626 }
627}
628
612void __init plat_mem_setup(void) 629void __init plat_mem_setup(void)
613{ 630{
614 uint64_t mem_alloc_size; 631 uint64_t mem_alloc_size;
@@ -659,12 +676,27 @@ void __init plat_mem_setup(void)
659 CVMX_BOOTMEM_FLAG_NO_LOCKING); 676 CVMX_BOOTMEM_FLAG_NO_LOCKING);
660#endif 677#endif
661 if (memory >= 0) { 678 if (memory >= 0) {
679 u64 size = mem_alloc_size;
680
681 /*
682 * exclude a page at the beginning and end of
683 * the 256MB PCIe 'hole' so the kernel will not
684 * try to allocate multi-page buffers that
685 * span the discontinuity.
686 */
687 memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE,
688 &memory, &size);
689 memory_exclude_page(CVMX_PCIE_BAR1_PHYS_BASE +
690 CVMX_PCIE_BAR1_PHYS_SIZE,
691 &memory, &size);
692
662 /* 693 /*
663 * This function automatically merges address 694 * This function automatically merges address
664 * regions next to each other if they are 695 * regions next to each other if they are
665 * received in incrementing order. 696 * received in incrementing order.
666 */ 697 */
667 add_memory_region(memory, mem_alloc_size, BOOT_MEM_RAM); 698 if (size)
699 add_memory_region(memory, size, BOOT_MEM_RAM);
668 total += mem_alloc_size; 700 total += mem_alloc_size;
669 } else { 701 } else {
670 break; 702 break;
diff --git a/arch/mips/include/asm/octeon/pci-octeon.h b/arch/mips/include/asm/octeon/pci-octeon.h
index 6ac5d3e3398e..ece78043acf6 100644
--- a/arch/mips/include/asm/octeon/pci-octeon.h
+++ b/arch/mips/include/asm/octeon/pci-octeon.h
@@ -15,6 +15,19 @@
15#define PCI_CONFIG_SPACE_DELAY 10000 15#define PCI_CONFIG_SPACE_DELAY 10000
16 16
17/* 17/*
18 * The physical memory base mapped by BAR1. 256MB at the end of the
19 * first 4GB.
20 */
21#define CVMX_PCIE_BAR1_PHYS_BASE ((1ull << 32) - (1ull << 28))
22#define CVMX_PCIE_BAR1_PHYS_SIZE (1ull << 28)
23
24/*
25 * The RC base of BAR1. gen1 has a 39-bit BAR2, gen2 has 41-bit BAR2,
26 * place BAR1 so it is the same for both.
27 */
28#define CVMX_PCIE_BAR1_RC_BASE (1ull << 41)
29
30/*
18 * pcibios_map_irq() is defined inside pci-octeon.c. All it does is 31 * pcibios_map_irq() is defined inside pci-octeon.c. All it does is
19 * call the Octeon specific version pointed to by this variable. This 32 * call the Octeon specific version pointed to by this variable. This
20 * function needs to change for PCI or PCIe based hosts. 33 * function needs to change for PCI or PCIe based hosts.
diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c
index 6aa5c542d52d..861361e0c9af 100644
--- a/arch/mips/pci/pcie-octeon.c
+++ b/arch/mips/pci/pcie-octeon.c
@@ -402,6 +402,10 @@ static void __cvmx_pcie_rc_initialize_config_space(int pcie_port)
402 npei_ctl_status2.s.mps = 0; 402 npei_ctl_status2.s.mps = 0;
403 /* Max read request size = 128 bytes for best Octeon DMA performance */ 403 /* Max read request size = 128 bytes for best Octeon DMA performance */
404 npei_ctl_status2.s.mrrs = 0; 404 npei_ctl_status2.s.mrrs = 0;
405 if (pcie_port)
406 npei_ctl_status2.s.c1_b1_s = 3; /* Port1 BAR1 Size 256MB */
407 else
408 npei_ctl_status2.s.c0_b1_s = 3; /* Port0 BAR1 Size 256MB */
405 cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64); 409 cvmx_write_csr(CVMX_PEXP_NPEI_CTL_STATUS2, npei_ctl_status2.u64);
406 410
407 /* ECRC Generation (PCIE*_CFG070[GE,CE]) */ 411 /* ECRC Generation (PCIE*_CFG070[GE,CE]) */
@@ -666,6 +670,8 @@ static int __cvmx_pcie_rc_initialize_link(int pcie_port)
666static int cvmx_pcie_rc_initialize(int pcie_port) 670static int cvmx_pcie_rc_initialize(int pcie_port)
667{ 671{
668 int i; 672 int i;
673 int base;
674 u64 addr_swizzle;
669 union cvmx_ciu_soft_prst ciu_soft_prst; 675 union cvmx_ciu_soft_prst ciu_soft_prst;
670 union cvmx_pescx_bist_status pescx_bist_status; 676 union cvmx_pescx_bist_status pescx_bist_status;
671 union cvmx_pescx_bist_status2 pescx_bist_status2; 677 union cvmx_pescx_bist_status2 pescx_bist_status2;
@@ -674,6 +680,7 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
674 union cvmx_npei_mem_access_subidx mem_access_subid; 680 union cvmx_npei_mem_access_subidx mem_access_subid;
675 union cvmx_npei_dbg_data npei_dbg_data; 681 union cvmx_npei_dbg_data npei_dbg_data;
676 union cvmx_pescx_ctl_status2 pescx_ctl_status2; 682 union cvmx_pescx_ctl_status2 pescx_ctl_status2;
683 union cvmx_npei_bar1_indexx bar1_index;
677 684
678 /* 685 /*
679 * Make sure we aren't trying to setup a target mode interface 686 * Make sure we aren't trying to setup a target mode interface
@@ -918,12 +925,30 @@ static int cvmx_pcie_rc_initialize(int pcie_port)
918 /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */ 925 /* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */
919 cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0); 926 cvmx_write_csr(CVMX_PESCX_P2N_BAR0_START(pcie_port), 0);
920 927
921 /* 928 /* BAR1 follows BAR2 with a gap. */
922 * Disable Octeon's BAR1. It isn't needed in RC mode since 929 cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), CVMX_PCIE_BAR1_RC_BASE);
923 * BAR2 maps all of memory. BAR2 also maps 256MB-512MB into 930
924 * the 2nd 256MB of memory. 931 bar1_index.u32 = 0;
925 */ 932 bar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22);
926 cvmx_write_csr(CVMX_PESCX_P2N_BAR1_START(pcie_port), -1); 933 bar1_index.s.ca = 1; /* Not Cached */
934 bar1_index.s.end_swp = 1; /* Endian Swap mode */
935 bar1_index.s.addr_v = 1; /* Valid entry */
936
937 base = pcie_port ? 16 : 0;
938
939 /* Big endian swizzle for 32-bit PEXP_NCB register. */
940#ifdef __MIPSEB__
941 addr_swizzle = 4;
942#else
943 addr_swizzle = 0;
944#endif
945 for (i = 0; i < 16; i++) {
946 cvmx_write64_uint32((CVMX_PEXP_NPEI_BAR1_INDEXX(base) ^ addr_swizzle),
947 bar1_index.u32);
948 base++;
949 /* 256MB / 16 >> 22 == 4 */
950 bar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22);
951 }
927 952
928 /* 953 /*
929 * Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take 954 * Set Octeon's BAR2 to decode 0-2^39. Bar0 and Bar1 take