diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2014-03-22 19:34:44 -0400 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2014-04-01 17:35:52 -0400 |
commit | 9d4b52df4b1242e6ba9a00db5f8d62083a56709f (patch) | |
tree | d07dffe36aaeacda5b30472eaafb265100882861 /arch/xtensa/mm | |
parent | 9ba067f93f1eec0d241f002812806b873dd4f802 (diff) |
xtensa: keep sysmem banks ordered in add_sysmem_bank
Rewrite add_sysmem_bank so that it keeps bank order and merges
adjacent/overlapping banks.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa/mm')
-rw-r--r-- | arch/xtensa/mm/init.c | 103 |
1 files changed, 98 insertions, 5 deletions
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index 4f78264e8bd8..79c0c3d52ae3 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * for more details. | 8 | * for more details. |
9 | * | 9 | * |
10 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 10 | * Copyright (C) 2001 - 2005 Tensilica Inc. |
11 | * Copyright (C) 2014 Cadence Design Systems Inc. | ||
11 | * | 12 | * |
12 | * Chris Zankel <chris@zankel.net> | 13 | * Chris Zankel <chris@zankel.net> |
13 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> | 14 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com> |
@@ -31,17 +32,109 @@ | |||
31 | 32 | ||
32 | struct sysmem_info sysmem __initdata; | 33 | struct sysmem_info sysmem __initdata; |
33 | 34 | ||
35 | /* | ||
36 | * Find bank with maximal .start such that bank.start <= start | ||
37 | */ | ||
38 | static inline struct meminfo * __init find_bank(unsigned long start) | ||
39 | { | ||
40 | unsigned i; | ||
41 | struct meminfo *it = NULL; | ||
42 | |||
43 | for (i = 0; i < sysmem.nr_banks; ++i) | ||
44 | if (sysmem.bank[i].start <= start) | ||
45 | it = sysmem.bank + i; | ||
46 | else | ||
47 | break; | ||
48 | return it; | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * Move all memory banks starting at 'from' to a new place at 'to', | ||
53 | * adjust nr_banks accordingly. | ||
54 | * Both 'from' and 'to' must be inside the sysmem.bank. | ||
55 | * | ||
56 | * Returns: 0 (success), -ENOMEM (not enough space in the sysmem.bank). | ||
57 | */ | ||
58 | static int __init move_banks(struct meminfo *to, struct meminfo *from) | ||
59 | { | ||
60 | unsigned n = sysmem.nr_banks - (from - sysmem.bank); | ||
61 | |||
62 | if (to > from && to - from + sysmem.nr_banks > SYSMEM_BANKS_MAX) | ||
63 | return -ENOMEM; | ||
64 | if (to != from) | ||
65 | memmove(to, from, n * sizeof(struct meminfo)); | ||
66 | sysmem.nr_banks += to - from; | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * Add new bank to sysmem. Resulting sysmem is the union of bytes of the | ||
72 | * original sysmem and the new bank. | ||
73 | * | ||
74 | * Returns: 0 (success), < 0 (error) | ||
75 | */ | ||
34 | int __init add_sysmem_bank(unsigned long start, unsigned long end) | 76 | int __init add_sysmem_bank(unsigned long start, unsigned long end) |
35 | { | 77 | { |
36 | if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) { | 78 | unsigned i; |
37 | pr_warn("Ignoring memory bank 0x%08lx size %ldKB\n", | 79 | struct meminfo *it = NULL; |
80 | unsigned long sz; | ||
81 | unsigned long bank_sz = 0; | ||
82 | |||
83 | if (start == end || | ||
84 | (start < end) != (PAGE_ALIGN(start) < (end & PAGE_MASK))) { | ||
85 | pr_warn("Ignoring small memory bank 0x%08lx size: %ld bytes\n", | ||
38 | start, end - start); | 86 | start, end - start); |
39 | return -EINVAL; | 87 | return -EINVAL; |
40 | } | 88 | } |
41 | sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(start); | ||
42 | sysmem.bank[sysmem.nr_banks].end = end & PAGE_MASK; | ||
43 | sysmem.nr_banks++; | ||
44 | 89 | ||
90 | start = PAGE_ALIGN(start); | ||
91 | end &= PAGE_MASK; | ||
92 | sz = end - start; | ||
93 | |||
94 | it = find_bank(start); | ||
95 | |||
96 | if (it) | ||
97 | bank_sz = it->end - it->start; | ||
98 | |||
99 | if (it && bank_sz >= start - it->start) { | ||
100 | if (end - it->start > bank_sz) | ||
101 | it->end = end; | ||
102 | else | ||
103 | return 0; | ||
104 | } else { | ||
105 | if (!it) | ||
106 | it = sysmem.bank; | ||
107 | else | ||
108 | ++it; | ||
109 | |||
110 | if (it - sysmem.bank < sysmem.nr_banks && | ||
111 | it->start - start <= sz) { | ||
112 | it->start = start; | ||
113 | if (it->end - it->start < sz) | ||
114 | it->end = end; | ||
115 | else | ||
116 | return 0; | ||
117 | } else { | ||
118 | if (move_banks(it + 1, it) < 0) { | ||
119 | pr_warn("Ignoring memory bank 0x%08lx size %ld bytes\n", | ||
120 | start, end - start); | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | it->start = start; | ||
124 | it->end = end; | ||
125 | return 0; | ||
126 | } | ||
127 | } | ||
128 | sz = it->end - it->start; | ||
129 | for (i = it + 1 - sysmem.bank; i < sysmem.nr_banks; ++i) | ||
130 | if (sysmem.bank[i].start - it->start <= sz) { | ||
131 | if (sz < sysmem.bank[i].end - it->start) | ||
132 | it->end = sysmem.bank[i].end; | ||
133 | } else { | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | move_banks(it + 1, sysmem.bank + i); | ||
45 | return 0; | 138 | return 0; |
46 | } | 139 | } |
47 | 140 | ||