diff options
author | David VomLehn <dvomlehn@cisco.com> | 2010-05-21 14:25:36 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2010-08-05 08:25:40 -0400 |
commit | ca36c36b7821b573fe06ce6bc34db03b557f3ce4 (patch) | |
tree | 28fe24b5080e29ca62ff4d1b4bbf5afc83084792 /arch | |
parent | 36f217d9df3e6bf8e6ae7647827b485b79dbaf8e (diff) |
MIPS: PowerTV: Use O(1) algorthm for phys_to_dma/dma_to_phys
Replace phys_to_dma()/dma_to_phys() looping algorithm with an O(1) algorithm
The approach taken is inspired by the sparse memory implementation: take a
certain number of high-order bits off the address them, use this as an
index into a table containing an offset to the desired address and add
it to the original value. There is a table for mapping physical addresses
to DMA addresses and another one for the reverse mapping. The table sizes
depend on how fine-grained the mappings need to be; Coarser granularity
less to smaller tables. On a processor with 32-bit physical and DMA
addresses, with 4 MIB granularity, memory usage is two 2048-byte arrays.
Each 32-byte cache line thus covers 64 MiB of address space.
Also, renames phys_to_bus() to phys_to_dma() and bus_to_phys() to
dma_to_phys() to align with kernel usage.
[Ralf: Fixed silly build breakage due to stackoverflow warning caused by
huge array on stack.]
Signed-off-by: David VomLehn <dvomlehn@cisco.com>
To: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/1257/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/include/asm/mach-powertv/dma-coherence.h | 8 | ||||
-rw-r--r-- | arch/mips/include/asm/mach-powertv/ioremap.h | 165 | ||||
-rw-r--r-- | arch/mips/powertv/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/powertv/asic/asic_devices.c | 18 | ||||
-rw-r--r-- | arch/mips/powertv/ioremap.c | 136 | ||||
-rw-r--r-- | arch/mips/powertv/memory.c | 341 |
6 files changed, 529 insertions, 142 deletions
diff --git a/arch/mips/include/asm/mach-powertv/dma-coherence.h b/arch/mips/include/asm/mach-powertv/dma-coherence.h index 5b8d5ebeb838..f76029c2406e 100644 --- a/arch/mips/include/asm/mach-powertv/dma-coherence.h +++ b/arch/mips/include/asm/mach-powertv/dma-coherence.h | |||
@@ -65,21 +65,21 @@ static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr, | |||
65 | size_t size) | 65 | size_t size) |
66 | { | 66 | { |
67 | if (is_kseg2(addr)) | 67 | if (is_kseg2(addr)) |
68 | return phys_to_bus(virt_to_phys_from_pte(addr)); | 68 | return phys_to_dma(virt_to_phys_from_pte(addr)); |
69 | else | 69 | else |
70 | return phys_to_bus(virt_to_phys(addr)); | 70 | return phys_to_dma(virt_to_phys(addr)); |
71 | } | 71 | } |
72 | 72 | ||
73 | static inline dma_addr_t plat_map_dma_mem_page(struct device *dev, | 73 | static inline dma_addr_t plat_map_dma_mem_page(struct device *dev, |
74 | struct page *page) | 74 | struct page *page) |
75 | { | 75 | { |
76 | return phys_to_bus(page_to_phys(page)); | 76 | return phys_to_dma(page_to_phys(page)); |
77 | } | 77 | } |
78 | 78 | ||
79 | static inline unsigned long plat_dma_addr_to_phys(struct device *dev, | 79 | static inline unsigned long plat_dma_addr_to_phys(struct device *dev, |
80 | dma_addr_t dma_addr) | 80 | dma_addr_t dma_addr) |
81 | { | 81 | { |
82 | return bus_to_phys(dma_addr); | 82 | return dma_to_phys(dma_addr); |
83 | } | 83 | } |
84 | 84 | ||
85 | static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr, | 85 | static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr, |
diff --git a/arch/mips/include/asm/mach-powertv/ioremap.h b/arch/mips/include/asm/mach-powertv/ioremap.h index e6276d5146e8..076f2eeaa575 100644 --- a/arch/mips/include/asm/mach-powertv/ioremap.h +++ b/arch/mips/include/asm/mach-powertv/ioremap.h | |||
@@ -10,64 +10,101 @@ | |||
10 | #define __ASM_MACH_POWERTV_IOREMAP_H | 10 | #define __ASM_MACH_POWERTV_IOREMAP_H |
11 | 11 | ||
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/log2.h> | ||
14 | #include <linux/compiler.h> | ||
13 | 15 | ||
14 | #define LOW_MEM_BOUNDARY_PHYS 0x20000000 | 16 | #include <asm/pgtable-bits.h> |
15 | #define LOW_MEM_BOUNDARY_MASK (~(LOW_MEM_BOUNDARY_PHYS - 1)) | 17 | #include <asm/addrspace.h> |
18 | |||
19 | /* We're going to mess with bits, so get sizes */ | ||
20 | #define IOR_BPC 8 /* Bits per char */ | ||
21 | #define IOR_PHYS_BITS (IOR_BPC * sizeof(phys_addr_t)) | ||
22 | #define IOR_DMA_BITS (IOR_BPC * sizeof(dma_addr_t)) | ||
16 | 23 | ||
17 | /* | 24 | /* |
18 | * The bus addresses are different than the physical addresses that | 25 | * Define the granularity of physical/DMA mapping in terms of the number |
19 | * the processor sees by an offset. This offset varies by ASIC | 26 | * of bits that defines the offset within a grain. These will be the |
20 | * version. Define a variable to hold the offset and some macros to | 27 | * least significant bits of the address. The rest of a physical or DMA |
21 | * make the conversion simpler. */ | 28 | * address will be used to index into an appropriate table to find the |
22 | extern unsigned long phys_to_bus_offset; | 29 | * offset to add to the address to yield the corresponding DMA or physical |
23 | 30 | * address, respectively. | |
24 | #ifdef CONFIG_HIGHMEM | 31 | */ |
25 | #define MEM_GAP_PHYS 0x60000000 | 32 | #define IOR_LSBITS 22 /* Bits in a grain */ |
33 | |||
26 | /* | 34 | /* |
27 | * TODO: We will use the hard code for conversion between physical and | 35 | * Compute the number of most significant address bits after removing those |
28 | * bus until the bootloader releases their device tree to us. | 36 | * used for the offset within a grain and then compute the number of table |
37 | * entries for the conversion. | ||
29 | */ | 38 | */ |
30 | #define phys_to_bus(x) (((x) < LOW_MEM_BOUNDARY_PHYS) ? \ | 39 | #define IOR_PHYS_MSBITS (IOR_PHYS_BITS - IOR_LSBITS) |
31 | ((x) + phys_to_bus_offset) : (x)) | 40 | #define IOR_NUM_PHYS_TO_DMA ((phys_addr_t) 1 << IOR_PHYS_MSBITS) |
32 | #define bus_to_phys(x) (((x) < MEM_GAP_PHYS_ADDR) ? \ | 41 | |
33 | ((x) - phys_to_bus_offset) : (x)) | 42 | #define IOR_DMA_MSBITS (IOR_DMA_BITS - IOR_LSBITS) |
34 | #else | 43 | #define IOR_NUM_DMA_TO_PHYS ((dma_addr_t) 1 << IOR_DMA_MSBITS) |
35 | #define phys_to_bus(x) ((x) + phys_to_bus_offset) | ||
36 | #define bus_to_phys(x) ((x) - phys_to_bus_offset) | ||
37 | #endif | ||
38 | 44 | ||
39 | /* | 45 | /* |
40 | * Determine whether the address we are given is for an ASIC device | 46 | * Define data structures used as elements in the arrays for the conversion |
41 | * Params: addr Address to check | 47 | * between physical and DMA addresses. We do some slightly fancy math to |
42 | * Returns: Zero if the address is not for ASIC devices, non-zero | 48 | * compute the width of the offset element of the conversion tables so |
43 | * if it is. | 49 | * that we can have the smallest conversion tables. Next, round up the |
50 | * sizes to the next higher power of two, i.e. the offset element will have | ||
51 | * 8, 16, 32, 64, etc. bits. This eliminates the need to mask off any | ||
52 | * bits. Finally, we compute a shift value that puts the most significant | ||
53 | * bits of the offset into the most significant bits of the offset element. | ||
54 | * This makes it more efficient on processors without barrel shifters and | ||
55 | * easier to see the values if the conversion table is dumped in binary. | ||
44 | */ | 56 | */ |
45 | static inline int asic_is_device_addr(phys_t addr) | 57 | #define _IOR_OFFSET_WIDTH(n) (1 << order_base_2(n)) |
58 | #define IOR_OFFSET_WIDTH(n) \ | ||
59 | (_IOR_OFFSET_WIDTH(n) < 8 ? 8 : _IOR_OFFSET_WIDTH(n)) | ||
60 | |||
61 | #define IOR_PHYS_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_PHYS_MSBITS) | ||
62 | #define IOR_PHYS_SHIFT (IOR_PHYS_BITS - IOR_PHYS_OFFSET_BITS) | ||
63 | |||
64 | #define IOR_DMA_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_DMA_MSBITS) | ||
65 | #define IOR_DMA_SHIFT (IOR_DMA_BITS - IOR_DMA_OFFSET_BITS) | ||
66 | |||
67 | struct ior_phys_to_dma { | ||
68 | dma_addr_t offset:IOR_DMA_OFFSET_BITS __packed | ||
69 | __aligned((IOR_DMA_OFFSET_BITS / IOR_BPC)); | ||
70 | }; | ||
71 | |||
72 | struct ior_dma_to_phys { | ||
73 | dma_addr_t offset:IOR_PHYS_OFFSET_BITS __packed | ||
74 | __aligned((IOR_PHYS_OFFSET_BITS / IOR_BPC)); | ||
75 | }; | ||
76 | |||
77 | extern struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA]; | ||
78 | extern struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS]; | ||
79 | |||
80 | static inline dma_addr_t _phys_to_dma_offset_raw(phys_addr_t phys) | ||
46 | { | 81 | { |
47 | return !((phys_t)addr & (phys_t) LOW_MEM_BOUNDARY_MASK); | 82 | return (dma_addr_t)_ior_phys_to_dma[phys >> IOR_LSBITS].offset; |
48 | } | 83 | } |
49 | 84 | ||
50 | /* | 85 | static inline dma_addr_t _dma_to_phys_offset_raw(dma_addr_t dma) |
51 | * Determine whether the address we are given is external RAM mappable | ||
52 | * into KSEG1. | ||
53 | * Params: addr Address to check | ||
54 | * Returns: Zero if the address is not for external RAM and | ||
55 | */ | ||
56 | static inline int asic_is_lowmem_ram_addr(phys_t addr) | ||
57 | { | 86 | { |
58 | /* | 87 | return (dma_addr_t)_ior_dma_to_phys[dma >> IOR_LSBITS].offset; |
59 | * The RAM always starts at the following address in the processor's | 88 | } |
60 | * physical address space | ||
61 | */ | ||
62 | static const phys_t phys_ram_base = 0x10000000; | ||
63 | phys_t bus_ram_base; | ||
64 | 89 | ||
65 | bus_ram_base = phys_to_bus_offset + phys_ram_base; | 90 | /* These are not portable and should not be used in drivers. Drivers should |
91 | * be using ioremap() and friends to map physical addreses to virtual | ||
92 | * addresses and dma_map*() and friends to map virtual addresses into DMA | ||
93 | * addresses and back. | ||
94 | */ | ||
95 | static inline dma_addr_t phys_to_dma(phys_addr_t phys) | ||
96 | { | ||
97 | return phys + (_phys_to_dma_offset_raw(phys) << IOR_PHYS_SHIFT); | ||
98 | } | ||
66 | 99 | ||
67 | return addr >= bus_ram_base && | 100 | static inline phys_addr_t dma_to_phys(dma_addr_t dma) |
68 | addr < (bus_ram_base + (LOW_MEM_BOUNDARY_PHYS - phys_ram_base)); | 101 | { |
102 | return dma + (_dma_to_phys_offset_raw(dma) << IOR_DMA_SHIFT); | ||
69 | } | 103 | } |
70 | 104 | ||
105 | extern void ioremap_add_map(dma_addr_t phys, phys_addr_t alias, | ||
106 | dma_addr_t size); | ||
107 | |||
71 | /* | 108 | /* |
72 | * Allow physical addresses to be fixed up to help peripherals located | 109 | * Allow physical addresses to be fixed up to help peripherals located |
73 | * outside the low 32-bit range -- generic pass-through version. | 110 | * outside the low 32-bit range -- generic pass-through version. |
@@ -77,10 +114,50 @@ static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) | |||
77 | return phys_addr; | 114 | return phys_addr; |
78 | } | 115 | } |
79 | 116 | ||
80 | static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size, | 117 | /* |
118 | * Handle the special case of addresses the area aliased into the first | ||
119 | * 512 MiB of the processor's physical address space. These turn into either | ||
120 | * kseg0 or kseg1 addresses, depending on flags. | ||
121 | */ | ||
122 | static inline void __iomem *plat_ioremap(phys_t start, unsigned long size, | ||
81 | unsigned long flags) | 123 | unsigned long flags) |
82 | { | 124 | { |
83 | return NULL; | 125 | phys_addr_t start_offset; |
126 | void __iomem *result = NULL; | ||
127 | |||
128 | /* Start by checking to see whether this is an aliased address */ | ||
129 | start_offset = _dma_to_phys_offset_raw(start); | ||
130 | |||
131 | /* | ||
132 | * If: | ||
133 | * o the memory is aliased into the first 512 MiB, and | ||
134 | * o the start and end are in the same RAM bank, and | ||
135 | * o we don't have a zero size or wrap around, and | ||
136 | * o we are supposed to create an uncached mapping, | ||
137 | * handle this is a kseg0 or kseg1 address | ||
138 | */ | ||
139 | if (start_offset != 0) { | ||
140 | phys_addr_t last; | ||
141 | dma_addr_t dma_to_phys_offset; | ||
142 | |||
143 | last = start + size - 1; | ||
144 | dma_to_phys_offset = | ||
145 | _dma_to_phys_offset_raw(last) << IOR_DMA_SHIFT; | ||
146 | |||
147 | if (dma_to_phys_offset == start_offset && | ||
148 | size != 0 && start <= last) { | ||
149 | phys_t adjusted_start; | ||
150 | adjusted_start = start + start_offset; | ||
151 | if (flags == _CACHE_UNCACHED) | ||
152 | result = (void __iomem *) (unsigned long) | ||
153 | CKSEG1ADDR(adjusted_start); | ||
154 | else | ||
155 | result = (void __iomem *) (unsigned long) | ||
156 | CKSEG0ADDR(adjusted_start); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | return result; | ||
84 | } | 161 | } |
85 | 162 | ||
86 | static inline int plat_iounmap(const volatile void __iomem *addr) | 163 | static inline int plat_iounmap(const volatile void __iomem *addr) |
diff --git a/arch/mips/powertv/Makefile b/arch/mips/powertv/Makefile index 0a0d73c0564f..e9fe1c6efe16 100644 --- a/arch/mips/powertv/Makefile +++ b/arch/mips/powertv/Makefile | |||
@@ -23,6 +23,7 @@ | |||
23 | # under Linux. | 23 | # under Linux. |
24 | # | 24 | # |
25 | 25 | ||
26 | obj-y += init.o memory.o reset.o time.o powertv_setup.o asic/ pci/ | 26 | obj-y += init.o ioremap.o memory.o powertv_setup.o reset.o time.o \ |
27 | asic/ pci/ | ||
27 | 28 | ||
28 | EXTRA_CFLAGS += -Wall -Werror | 29 | EXTRA_CFLAGS += -Wall -Werror |
diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c index 9ec523e4dd06..c81dd497ed7b 100644 --- a/arch/mips/powertv/asic/asic_devices.c +++ b/arch/mips/powertv/asic/asic_devices.c | |||
@@ -80,8 +80,8 @@ static bool usb_configured; | |||
80 | * Don't recommend to use it directly, it is usually used by kernel internally. | 80 | * Don't recommend to use it directly, it is usually used by kernel internally. |
81 | * Portable code should be using interfaces such as ioremp, dma_map_single, etc. | 81 | * Portable code should be using interfaces such as ioremp, dma_map_single, etc. |
82 | */ | 82 | */ |
83 | unsigned long phys_to_bus_offset; | 83 | unsigned long phys_to_dma_offset; |
84 | EXPORT_SYMBOL(phys_to_bus_offset); | 84 | EXPORT_SYMBOL(phys_to_dma_offset); |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * | 87 | * |
@@ -533,10 +533,10 @@ void __init configure_platform(void) | |||
533 | 533 | ||
534 | switch (asic) { | 534 | switch (asic) { |
535 | case ASIC_ZEUS: | 535 | case ASIC_ZEUS: |
536 | phys_to_bus_offset = 0x30000000; | 536 | phys_to_dma_offset = 0x30000000; |
537 | break; | 537 | break; |
538 | case ASIC_CALLIOPE: | 538 | case ASIC_CALLIOPE: |
539 | phys_to_bus_offset = 0x10000000; | 539 | phys_to_dma_offset = 0x10000000; |
540 | break; | 540 | break; |
541 | case ASIC_CRONUSLITE: | 541 | case ASIC_CRONUSLITE: |
542 | /* Fall through */ | 542 | /* Fall through */ |
@@ -546,10 +546,10 @@ void __init configure_platform(void) | |||
546 | * 0x2XXXXXXX. If 0x10000000 aliases into 0x60000000- | 546 | * 0x2XXXXXXX. If 0x10000000 aliases into 0x60000000- |
547 | * 0x6XXXXXXX, the offset should be 0x50000000, not 0x10000000. | 547 | * 0x6XXXXXXX, the offset should be 0x50000000, not 0x10000000. |
548 | */ | 548 | */ |
549 | phys_to_bus_offset = 0x10000000; | 549 | phys_to_dma_offset = 0x10000000; |
550 | break; | 550 | break; |
551 | default: | 551 | default: |
552 | phys_to_bus_offset = 0x00000000; | 552 | phys_to_dma_offset = 0x00000000; |
553 | break; | 553 | break; |
554 | } | 554 | } |
555 | } | 555 | } |
@@ -603,7 +603,7 @@ void __init platform_alloc_bootmem(void) | |||
603 | int size = gp_resources[i].end - gp_resources[i].start + 1; | 603 | int size = gp_resources[i].end - gp_resources[i].start + 1; |
604 | if ((gp_resources[i].start != 0) && | 604 | if ((gp_resources[i].start != 0) && |
605 | ((gp_resources[i].flags & IORESOURCE_MEM) != 0)) { | 605 | ((gp_resources[i].flags & IORESOURCE_MEM) != 0)) { |
606 | reserve_bootmem(bus_to_phys(gp_resources[i].start), | 606 | reserve_bootmem(dma_to_phys(gp_resources[i].start), |
607 | size, 0); | 607 | size, 0); |
608 | total += gp_resources[i].end - | 608 | total += gp_resources[i].end - |
609 | gp_resources[i].start + 1; | 609 | gp_resources[i].start + 1; |
@@ -627,7 +627,7 @@ void __init platform_alloc_bootmem(void) | |||
627 | 627 | ||
628 | else { | 628 | else { |
629 | gp_resources[i].start = | 629 | gp_resources[i].start = |
630 | phys_to_bus(virt_to_phys(mem)); | 630 | phys_to_dma(virt_to_phys(mem)); |
631 | gp_resources[i].end = | 631 | gp_resources[i].end = |
632 | gp_resources[i].start + size - 1; | 632 | gp_resources[i].start + size - 1; |
633 | total += size; | 633 | total += size; |
@@ -691,7 +691,7 @@ static void __init pmem_setup_resource(void) | |||
691 | if (resource && pmemaddr && pmemlen) { | 691 | if (resource && pmemaddr && pmemlen) { |
692 | /* The address provided by bootloader is in kseg0. Convert to | 692 | /* The address provided by bootloader is in kseg0. Convert to |
693 | * a bus address. */ | 693 | * a bus address. */ |
694 | resource->start = phys_to_bus(pmemaddr - 0x80000000); | 694 | resource->start = phys_to_dma(pmemaddr - 0x80000000); |
695 | resource->end = resource->start + pmemlen - 1; | 695 | resource->end = resource->start + pmemlen - 1; |
696 | 696 | ||
697 | pr_info("persistent memory: start=0x%x end=0x%x\n", | 697 | pr_info("persistent memory: start=0x%x end=0x%x\n", |
diff --git a/arch/mips/powertv/ioremap.c b/arch/mips/powertv/ioremap.c new file mode 100644 index 000000000000..a77c6f62fe23 --- /dev/null +++ b/arch/mips/powertv/ioremap.c | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * ioremap.c | ||
3 | * | ||
4 | * Support for mapping between dma_addr_t values a phys_addr_t values. | ||
5 | * | ||
6 | * Copyright (C) 2005-2009 Scientific-Atlanta, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | * | ||
22 | * Author: David VomLehn <dvomlehn@cisco.com> | ||
23 | * | ||
24 | * Description: Defines the platform resources for the SA settop. | ||
25 | * | ||
26 | * NOTE: The bootloader allocates persistent memory at an address which is | ||
27 | * 16 MiB below the end of the highest address in KSEG0. All fixed | ||
28 | * address memory reservations must avoid this region. | ||
29 | */ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/module.h> | ||
33 | |||
34 | #include <asm/mach-powertv/ioremap.h> | ||
35 | |||
36 | /* | ||
37 | * Define the sizes of and masks for grains in physical and DMA space. The | ||
38 | * values are the same but the types are not. | ||
39 | */ | ||
40 | #define IOR_PHYS_GRAIN ((phys_addr_t) 1 << IOR_LSBITS) | ||
41 | #define IOR_PHYS_GRAIN_MASK (IOR_PHYS_GRAIN - 1) | ||
42 | |||
43 | #define IOR_DMA_GRAIN ((dma_addr_t) 1 << IOR_LSBITS) | ||
44 | #define IOR_DMA_GRAIN_MASK (IOR_DMA_GRAIN - 1) | ||
45 | |||
46 | /* | ||
47 | * Values that, when accessed by an index derived from a phys_addr_t and | ||
48 | * added to phys_addr_t value, yield a DMA address | ||
49 | */ | ||
50 | struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA]; | ||
51 | EXPORT_SYMBOL(_ior_phys_to_dma); | ||
52 | |||
53 | /* | ||
54 | * Values that, when accessed by an index derived from a dma_addr_t and | ||
55 | * added to that dma_addr_t value, yield a physical address | ||
56 | */ | ||
57 | struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS]; | ||
58 | EXPORT_SYMBOL(_ior_dma_to_phys); | ||
59 | |||
60 | /** | ||
61 | * setup_dma_to_phys - set up conversion from DMA to physical addresses | ||
62 | * @dma_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index | ||
63 | * into the array _dma_to_phys. | ||
64 | * @delta: Value that, when added to the DMA address, will yield the | ||
65 | * physical address | ||
66 | * @s: Number of bytes in the section of memory with the given delta | ||
67 | * between DMA and physical addresses. | ||
68 | */ | ||
69 | static void setup_dma_to_phys(dma_addr_t dma, phys_addr_t delta, dma_addr_t s) | ||
70 | { | ||
71 | int dma_idx, first_idx, last_idx; | ||
72 | phys_addr_t first, last; | ||
73 | |||
74 | /* | ||
75 | * Calculate the first and last indices, rounding the first up and | ||
76 | * the second down. | ||
77 | */ | ||
78 | first = dma & ~IOR_DMA_GRAIN_MASK; | ||
79 | last = (dma + s - 1) & ~IOR_DMA_GRAIN_MASK; | ||
80 | first_idx = first >> IOR_LSBITS; /* Convert to indices */ | ||
81 | last_idx = last >> IOR_LSBITS; | ||
82 | |||
83 | for (dma_idx = first_idx; dma_idx <= last_idx; dma_idx++) | ||
84 | _ior_dma_to_phys[dma_idx].offset = delta >> IOR_DMA_SHIFT; | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * setup_phys_to_dma - set up conversion from DMA to physical addresses | ||
89 | * @phys_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index | ||
90 | * into the array _phys_to_dma. | ||
91 | * @delta: Value that, when added to the DMA address, will yield the | ||
92 | * physical address | ||
93 | * @s: Number of bytes in the section of memory with the given delta | ||
94 | * between DMA and physical addresses. | ||
95 | */ | ||
96 | static void setup_phys_to_dma(phys_addr_t phys, dma_addr_t delta, phys_addr_t s) | ||
97 | { | ||
98 | int phys_idx, first_idx, last_idx; | ||
99 | phys_addr_t first, last; | ||
100 | |||
101 | /* | ||
102 | * Calculate the first and last indices, rounding the first up and | ||
103 | * the second down. | ||
104 | */ | ||
105 | first = phys & ~IOR_PHYS_GRAIN_MASK; | ||
106 | last = (phys + s - 1) & ~IOR_PHYS_GRAIN_MASK; | ||
107 | first_idx = first >> IOR_LSBITS; /* Convert to indices */ | ||
108 | last_idx = last >> IOR_LSBITS; | ||
109 | |||
110 | for (phys_idx = first_idx; phys_idx <= last_idx; phys_idx++) | ||
111 | _ior_phys_to_dma[phys_idx].offset = delta >> IOR_PHYS_SHIFT; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * ioremap_add_map - add to the physical and DMA address conversion arrays | ||
116 | * @phys: Process's view of the address of the start of the memory chunk | ||
117 | * @dma: DMA address of the start of the memory chunk | ||
118 | * @size: Size, in bytes, of the chunk of memory | ||
119 | * | ||
120 | * NOTE: It might be obvious, but the assumption is that all @size bytes have | ||
121 | * the same offset between the physical address and the DMA address. | ||
122 | */ | ||
123 | void ioremap_add_map(phys_addr_t phys, phys_addr_t dma, phys_addr_t size) | ||
124 | { | ||
125 | if (size == 0) | ||
126 | return; | ||
127 | |||
128 | if ((dma & IOR_DMA_GRAIN_MASK) != 0 || | ||
129 | (phys & IOR_PHYS_GRAIN_MASK) != 0 || | ||
130 | (size & IOR_PHYS_GRAIN_MASK) != 0) | ||
131 | pr_crit("Memory allocation must be in chunks of 0x%x bytes\n", | ||
132 | IOR_PHYS_GRAIN); | ||
133 | |||
134 | setup_dma_to_phys(dma, phys - dma, size); | ||
135 | setup_phys_to_dma(phys, dma - phys, size); | ||
136 | } | ||
diff --git a/arch/mips/powertv/memory.c b/arch/mips/powertv/memory.c index f49eb3d0358b..73880ad29bc2 100644 --- a/arch/mips/powertv/memory.c +++ b/arch/mips/powertv/memory.c | |||
@@ -30,28 +30,141 @@ | |||
30 | #include <asm/sections.h> | 30 | #include <asm/sections.h> |
31 | 31 | ||
32 | #include <asm/mips-boards/prom.h> | 32 | #include <asm/mips-boards/prom.h> |
33 | #include <asm/mach-powertv/asic.h> | ||
34 | #include <asm/mach-powertv/ioremap.h> | ||
33 | 35 | ||
34 | #include "init.h" | 36 | #include "init.h" |
35 | 37 | ||
36 | /* Memory constants */ | 38 | /* Memory constants */ |
37 | #define KIBIBYTE(n) ((n) * 1024) /* Number of kibibytes */ | 39 | #define KIBIBYTE(n) ((n) * 1024) /* Number of kibibytes */ |
38 | #define MEBIBYTE(n) ((n) * KIBIBYTE(1024)) /* Number of mebibytes */ | 40 | #define MEBIBYTE(n) ((n) * KIBIBYTE(1024)) /* Number of mebibytes */ |
39 | #define DEFAULT_MEMSIZE MEBIBYTE(256) /* If no memsize provided */ | 41 | #define DEFAULT_MEMSIZE MEBIBYTE(128) /* If no memsize provided */ |
40 | #define LOW_MEM_MAX MEBIBYTE(252) /* Max usable low mem */ | ||
41 | #define RES_BOOTLDR_MEMSIZE MEBIBYTE(1) /* Memory reserved for bldr */ | ||
42 | #define BOOT_MEM_SIZE KIBIBYTE(256) /* Memory reserved for bldr */ | ||
43 | #define PHYS_MEM_START 0x10000000 /* Start of physical memory */ | ||
44 | 42 | ||
45 | char __initdata cmdline[COMMAND_LINE_SIZE]; | 43 | #define BLDR_SIZE KIBIBYTE(256) /* Memory reserved for bldr */ |
44 | #define RV_SIZE MEBIBYTE(4) /* Size of reset vector */ | ||
46 | 45 | ||
47 | void __init prom_meminit(void) | 46 | #define LOW_MEM_END 0x20000000 /* Highest low memory address */ |
47 | #define BLDR_ALIAS 0x10000000 /* Bootloader address */ | ||
48 | #define RV_PHYS 0x1fc00000 /* Reset vector address */ | ||
49 | #define LOW_RAM_END RV_PHYS /* End of real RAM in low mem */ | ||
50 | |||
51 | /* | ||
52 | * Very low-level conversion from processor physical address to device | ||
53 | * DMA address for the first bank of memory. | ||
54 | */ | ||
55 | #define PHYS_TO_DMA(paddr) ((paddr) + (CONFIG_LOW_RAM_DMA - LOW_RAM_ALIAS)) | ||
56 | |||
57 | unsigned long ptv_memsize; | ||
58 | |||
59 | /* | ||
60 | * struct low_mem_reserved - Items in low memmory that are reserved | ||
61 | * @start: Physical address of item | ||
62 | * @size: Size, in bytes, of this item | ||
63 | * @is_aliased: True if this is RAM aliased from another location. If false, | ||
64 | * it is something other than aliased RAM and the RAM in the | ||
65 | * unaliased address is still visible outside of low memory. | ||
66 | */ | ||
67 | struct low_mem_reserved { | ||
68 | phys_addr_t start; | ||
69 | phys_addr_t size; | ||
70 | bool is_aliased; | ||
71 | }; | ||
72 | |||
73 | /* | ||
74 | * Must be in ascending address order | ||
75 | */ | ||
76 | struct low_mem_reserved low_mem_reserved[] = { | ||
77 | {BLDR_ALIAS, BLDR_SIZE, true}, /* Bootloader RAM */ | ||
78 | {RV_PHYS, RV_SIZE, false}, /* Reset vector */ | ||
79 | }; | ||
80 | |||
81 | /* | ||
82 | * struct mem_layout - layout of a piece of the system RAM | ||
83 | * @phys: Physical address of the start of this piece of RAM. This is the | ||
84 | * address at which both the processor and I/O devices see the | ||
85 | * RAM. | ||
86 | * @alias: Alias of this piece of memory in order to make it appear in | ||
87 | * the low memory part of the processor's address space. I/O | ||
88 | * devices don't see anything here. | ||
89 | * @size: Size, in bytes, of this piece of RAM | ||
90 | */ | ||
91 | struct mem_layout { | ||
92 | phys_addr_t phys; | ||
93 | phys_addr_t alias; | ||
94 | phys_addr_t size; | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * struct mem_layout_list - list descriptor for layouts of system RAM pieces | ||
99 | * @family: Specifies the family being described | ||
100 | * @n: Number of &struct mem_layout elements | ||
101 | * @layout: Pointer to the list of &mem_layout structures | ||
102 | */ | ||
103 | struct mem_layout_list { | ||
104 | enum family_type family; | ||
105 | size_t n; | ||
106 | struct mem_layout *layout; | ||
107 | }; | ||
108 | |||
109 | static struct mem_layout f1500_layout[] = { | ||
110 | {0x20000000, 0x10000000, MEBIBYTE(256)}, | ||
111 | }; | ||
112 | |||
113 | static struct mem_layout f4500_layout[] = { | ||
114 | {0x40000000, 0x10000000, MEBIBYTE(256)}, | ||
115 | {0x20000000, 0x20000000, MEBIBYTE(32)}, | ||
116 | }; | ||
117 | |||
118 | static struct mem_layout f8500_layout[] = { | ||
119 | {0x40000000, 0x10000000, MEBIBYTE(256)}, | ||
120 | {0x20000000, 0x20000000, MEBIBYTE(32)}, | ||
121 | {0x30000000, 0x30000000, MEBIBYTE(32)}, | ||
122 | }; | ||
123 | |||
124 | static struct mem_layout fx600_layout[] = { | ||
125 | {0x20000000, 0x10000000, MEBIBYTE(256)}, | ||
126 | {0x60000000, 0x60000000, MEBIBYTE(128)}, | ||
127 | }; | ||
128 | |||
129 | static struct mem_layout_list layout_list[] = { | ||
130 | {FAMILY_1500, ARRAY_SIZE(f1500_layout), f1500_layout}, | ||
131 | {FAMILY_1500VZE, ARRAY_SIZE(f1500_layout), f1500_layout}, | ||
132 | {FAMILY_1500VZF, ARRAY_SIZE(f1500_layout), f1500_layout}, | ||
133 | {FAMILY_4500, ARRAY_SIZE(f4500_layout), f4500_layout}, | ||
134 | {FAMILY_8500, ARRAY_SIZE(f8500_layout), f8500_layout}, | ||
135 | {FAMILY_8500RNG, ARRAY_SIZE(f8500_layout), f8500_layout}, | ||
136 | {FAMILY_4600, ARRAY_SIZE(fx600_layout), fx600_layout}, | ||
137 | {FAMILY_4600VZA, ARRAY_SIZE(fx600_layout), fx600_layout}, | ||
138 | {FAMILY_8600, ARRAY_SIZE(fx600_layout), fx600_layout}, | ||
139 | {FAMILY_8600VZB, ARRAY_SIZE(fx600_layout), fx600_layout}, | ||
140 | }; | ||
141 | |||
142 | /* If we can't determine the layout, use this */ | ||
143 | static struct mem_layout default_layout[] = { | ||
144 | {0x20000000, 0x10000000, MEBIBYTE(128)}, | ||
145 | }; | ||
146 | |||
147 | /** | ||
148 | * register_non_ram - register low memory not available for RAM usage | ||
149 | */ | ||
150 | static __init void register_non_ram(void) | ||
151 | { | ||
152 | int i; | ||
153 | |||
154 | for (i = 0; i < ARRAY_SIZE(low_mem_reserved); i++) | ||
155 | add_memory_region(low_mem_reserved[i].start, | ||
156 | low_mem_reserved[i].size, BOOT_MEM_RESERVED); | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * get_memsize - get the size of memory as a single bank | ||
161 | */ | ||
162 | static phys_addr_t get_memsize(void) | ||
48 | { | 163 | { |
164 | static char cmdline[COMMAND_LINE_SIZE] __initdata; | ||
165 | phys_addr_t memsize = 0; | ||
49 | char *memsize_str; | 166 | char *memsize_str; |
50 | unsigned long memsize = 0; | ||
51 | unsigned int physend; | ||
52 | char *ptr; | 167 | char *ptr; |
53 | int low_mem; | ||
54 | int high_mem; | ||
55 | 168 | ||
56 | /* Check the command line first for a memsize directive */ | 169 | /* Check the command line first for a memsize directive */ |
57 | strcpy(cmdline, arcs_cmdline); | 170 | strcpy(cmdline, arcs_cmdline); |
@@ -73,96 +186,156 @@ void __init prom_meminit(void) | |||
73 | if (memsize == 0) { | 186 | if (memsize == 0) { |
74 | if (_prom_memsize != 0) { | 187 | if (_prom_memsize != 0) { |
75 | memsize = _prom_memsize; | 188 | memsize = _prom_memsize; |
76 | pr_info("_prom_memsize = 0x%lx\n", memsize); | 189 | pr_info("_prom_memsize = 0x%x\n", memsize); |
77 | /* add in memory that the bootloader doesn't | 190 | /* add in memory that the bootloader doesn't |
78 | * report */ | 191 | * report */ |
79 | memsize += BOOT_MEM_SIZE; | 192 | memsize += BLDR_SIZE; |
80 | } else { | 193 | } else { |
81 | memsize = DEFAULT_MEMSIZE; | 194 | memsize = DEFAULT_MEMSIZE; |
82 | pr_info("Memsize not passed by bootloader, " | 195 | pr_info("Memsize not passed by bootloader, " |
83 | "defaulting to 0x%lx\n", memsize); | 196 | "defaulting to 0x%x\n", memsize); |
84 | } | 197 | } |
85 | } | 198 | } |
86 | } | 199 | } |
87 | 200 | ||
88 | physend = PFN_ALIGN(&_end) - 0x80000000; | 201 | return memsize; |
89 | if (memsize > LOW_MEM_MAX) { | 202 | } |
90 | low_mem = LOW_MEM_MAX; | 203 | |
91 | high_mem = memsize - low_mem; | 204 | /** |
92 | } else { | 205 | * register_low_ram - register an aliased section of RAM |
93 | low_mem = memsize; | 206 | * @p: Alias address of memory |
94 | high_mem = 0; | 207 | * @n: Number of bytes in this section of memory |
208 | * | ||
209 | * Returns the number of bytes registered | ||
210 | * | ||
211 | */ | ||
212 | static __init phys_addr_t register_low_ram(phys_addr_t p, phys_addr_t n) | ||
213 | { | ||
214 | phys_addr_t s; | ||
215 | int i; | ||
216 | phys_addr_t orig_n; | ||
217 | |||
218 | orig_n = n; | ||
219 | |||
220 | BUG_ON(p + n > RV_PHYS); | ||
221 | |||
222 | for (i = 0; n != 0 && i < ARRAY_SIZE(low_mem_reserved); i++) { | ||
223 | phys_addr_t start; | ||
224 | phys_addr_t size; | ||
225 | |||
226 | start = low_mem_reserved[i].start; | ||
227 | size = low_mem_reserved[i].size; | ||
228 | |||
229 | /* Handle memory before this low memory section */ | ||
230 | if (p < start) { | ||
231 | phys_addr_t s; | ||
232 | s = min(n, start - p); | ||
233 | add_memory_region(p, s, BOOT_MEM_RAM); | ||
234 | p += s; | ||
235 | n -= s; | ||
236 | } | ||
237 | |||
238 | /* Handle the low memory section itself. If it's aliased, | ||
239 | * we reduce the number of byes left, but if not, the RAM | ||
240 | * is available elsewhere and we don't reduce the number of | ||
241 | * bytes remaining. */ | ||
242 | if (p == start) { | ||
243 | if (low_mem_reserved[i].is_aliased) { | ||
244 | s = min(n, size); | ||
245 | n -= s; | ||
246 | p += s; | ||
247 | } else | ||
248 | p += n; | ||
249 | } | ||
95 | } | 250 | } |
96 | 251 | ||
252 | return orig_n - n; | ||
253 | } | ||
254 | |||
97 | /* | 255 | /* |
98 | * TODO: We will use the hard code for memory configuration until | 256 | * register_ram - register real RAM |
99 | * the bootloader releases their device tree to us. | 257 | * @p: Address of memory as seen by devices |
258 | * @alias: If the memory is seen at an additional address by the processor, | ||
259 | * this will be the address, otherwise it is the same as @p. | ||
260 | * @n: Number of bytes in this section of memory | ||
100 | */ | 261 | */ |
262 | static __init void register_ram(phys_addr_t p, phys_addr_t alias, | ||
263 | phys_addr_t n) | ||
264 | { | ||
101 | /* | 265 | /* |
102 | * Add the memory reserved for use by the bootloader to the | 266 | * If some or all of this memory has an alias, break it into the |
103 | * memory map. | 267 | * aliased and non-aliased portion. |
104 | */ | ||
105 | add_memory_region(PHYS_MEM_START, RES_BOOTLDR_MEMSIZE, | ||
106 | BOOT_MEM_RESERVED); | ||
107 | #ifdef CONFIG_HIGHMEM_256_128 | ||
108 | /* | ||
109 | * Add memory in low for general use by the kernel and its friends | ||
110 | * (like drivers, applications, etc). | ||
111 | */ | ||
112 | add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE, | ||
113 | LOW_MEM_MAX - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM); | ||
114 | /* | ||
115 | * Add the memory reserved for reset vector. | ||
116 | */ | ||
117 | add_memory_region(0x1fc00000, MEBIBYTE(4), BOOT_MEM_RESERVED); | ||
118 | /* | ||
119 | * Add the memory reserved. | ||
120 | */ | ||
121 | add_memory_region(0x20000000, MEBIBYTE(1024 + 75), BOOT_MEM_RESERVED); | ||
122 | /* | ||
123 | * Add memory in high for general use by the kernel and its friends | ||
124 | * (like drivers, applications, etc). | ||
125 | * | ||
126 | * 75MB is reserved for devices which are using the memory in high. | ||
127 | */ | ||
128 | add_memory_region(0x60000000 + MEBIBYTE(75), MEBIBYTE(128 - 75), | ||
129 | BOOT_MEM_RAM); | ||
130 | #elif defined CONFIG_HIGHMEM_128_128 | ||
131 | /* | ||
132 | * Add memory in low for general use by the kernel and its friends | ||
133 | * (like drivers, applications, etc). | ||
134 | */ | ||
135 | add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE, | ||
136 | MEBIBYTE(128) - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM); | ||
137 | /* | ||
138 | * Add the memory reserved. | ||
139 | */ | ||
140 | add_memory_region(PHYS_MEM_START + MEBIBYTE(128), | ||
141 | MEBIBYTE(128 + 1024 + 75), BOOT_MEM_RESERVED); | ||
142 | /* | ||
143 | * Add memory in high for general use by the kernel and its friends | ||
144 | * (like drivers, applications, etc). | ||
145 | * | ||
146 | * 75MB is reserved for devices which are using the memory in high. | ||
147 | */ | ||
148 | add_memory_region(0x60000000 + MEBIBYTE(75), MEBIBYTE(128 - 75), | ||
149 | BOOT_MEM_RAM); | ||
150 | #else | ||
151 | /* Add low memory regions for either: | ||
152 | * - no-highmemory configuration case -OR- | ||
153 | * - highmemory "HIGHMEM_LOWBANK_ONLY" case | ||
154 | */ | ||
155 | /* | ||
156 | * Add memory for general use by the kernel and its friends | ||
157 | * (like drivers, applications, etc). | ||
158 | */ | 268 | */ |
159 | add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE, | 269 | if (p != alias) { |
160 | low_mem - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM); | 270 | phys_addr_t alias_size; |
271 | phys_addr_t registered; | ||
272 | |||
273 | alias_size = min(n, LOW_RAM_END - alias); | ||
274 | registered = register_low_ram(alias, alias_size); | ||
275 | ioremap_add_map(alias, p, n); | ||
276 | n -= registered; | ||
277 | p += registered; | ||
278 | } | ||
279 | |||
280 | #ifdef CONFIG_HIGHMEM | ||
281 | if (n != 0) { | ||
282 | add_memory_region(p, n, BOOT_MEM_RAM); | ||
283 | ioremap_add_map(p, p, n); | ||
284 | } | ||
285 | #endif | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * register_address_space - register things in the address space | ||
290 | * @memsize: Number of bytes of RAM installed | ||
291 | * | ||
292 | * Takes the given number of bytes of RAM and registers as many of the regions, | ||
293 | * or partial regions, as it can. So, the default configuration might have | ||
294 | * two regions with 256 MiB each. If the memsize passed in on the command line | ||
295 | * is 384 MiB, it will register the first region with 256 MiB and the second | ||
296 | * with 128 MiB. | ||
297 | */ | ||
298 | static __init void register_address_space(phys_addr_t memsize) | ||
299 | { | ||
300 | int i; | ||
301 | phys_addr_t size; | ||
302 | size_t n; | ||
303 | struct mem_layout *layout; | ||
304 | enum family_type family; | ||
305 | |||
161 | /* | 306 | /* |
162 | * Add the memory reserved for reset vector. | 307 | * Register all of the things that aren't available to the kernel as |
308 | * memory. | ||
163 | */ | 309 | */ |
164 | add_memory_region(0x1fc00000, MEBIBYTE(4), BOOT_MEM_RESERVED); | 310 | register_non_ram(); |
165 | #endif | 311 | |
312 | /* Find the appropriate memory description */ | ||
313 | family = platform_get_family(); | ||
314 | |||
315 | for (i = 0; i < ARRAY_SIZE(layout_list); i++) { | ||
316 | if (layout_list[i].family == family) | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | if (i == ARRAY_SIZE(layout_list)) { | ||
321 | n = ARRAY_SIZE(default_layout); | ||
322 | layout = default_layout; | ||
323 | } else { | ||
324 | n = layout_list[i].n; | ||
325 | layout = layout_list[i].layout; | ||
326 | } | ||
327 | |||
328 | for (i = 0; memsize != 0 && i < n; i++) { | ||
329 | size = min(memsize, layout[i].size); | ||
330 | register_ram(layout[i].phys, layout[i].alias, size); | ||
331 | memsize -= size; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | void __init prom_meminit(void) | ||
336 | { | ||
337 | ptv_memsize = get_memsize(); | ||
338 | register_address_space(ptv_memsize); | ||
166 | } | 339 | } |
167 | 340 | ||
168 | void __init prom_free_prom_memory(void) | 341 | void __init prom_free_prom_memory(void) |