aboutsummaryrefslogtreecommitdiffstats
path: root/arch/xtensa/mm
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2014-03-22 19:34:44 -0400
committerMax Filippov <jcmvbkbc@gmail.com>2014-04-01 17:35:52 -0400
commit9d4b52df4b1242e6ba9a00db5f8d62083a56709f (patch)
treed07dffe36aaeacda5b30472eaafb265100882861 /arch/xtensa/mm
parent9ba067f93f1eec0d241f002812806b873dd4f802 (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.c103
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
32struct sysmem_info sysmem __initdata; 33struct sysmem_info sysmem __initdata;
33 34
35/*
36 * Find bank with maximal .start such that bank.start <= start
37 */
38static 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 */
58static 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 */
34int __init add_sysmem_bank(unsigned long start, unsigned long end) 76int __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