Aaron Williams | bec3f37 | 2021-05-06 09:40:43 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * Copyright (C) 2018-2022 Marvell International Ltd. |
| 4 | */ |
| 5 | |
| 6 | #include <log.h> |
| 7 | #include <time.h> |
| 8 | #include <linux/delay.h> |
| 9 | |
| 10 | #include <mach/cvmx-regs.h> |
| 11 | #include <mach/cvmx-csr.h> |
| 12 | #include <mach/cvmx-bootmem.h> |
| 13 | #include <mach/octeon-model.h> |
| 14 | #include <mach/cvmx-fuse.h> |
| 15 | #include <mach/octeon-feature.h> |
| 16 | #include <mach/cvmx-qlm.h> |
| 17 | #include <mach/octeon_qlm.h> |
| 18 | #include <mach/cvmx-pcie.h> |
| 19 | #include <mach/cvmx-coremask.h> |
| 20 | |
| 21 | #include <mach/cvmx-global-resources.h> |
| 22 | |
| 23 | #include <mach/cvmx-pki.h> |
| 24 | #include <mach/cvmx-helper.h> |
| 25 | #include <mach/cvmx-helper-board.h> |
| 26 | #include <mach/cvmx-helper-cfg.h> |
| 27 | |
| 28 | #include <mach/cvmx-range.h> |
| 29 | |
| 30 | #define CVMX_RANGE_AVAILABLE ((u64)-88) |
| 31 | #define addr_of_element(base, index) \ |
| 32 | (1ull << 63 | ((base) + sizeof(u64) + (index) * sizeof(u64))) |
| 33 | #define addr_of_size(base) (1ull << 63 | (base)) |
| 34 | |
| 35 | static const int debug; |
| 36 | |
| 37 | int cvmx_range_memory_size(int nelements) |
| 38 | { |
| 39 | return sizeof(u64) * (nelements + 1); |
| 40 | } |
| 41 | |
| 42 | int cvmx_range_init(u64 range_addr, int size) |
| 43 | { |
| 44 | u64 lsize = size; |
| 45 | u64 i; |
| 46 | |
| 47 | cvmx_write64_uint64(addr_of_size(range_addr), lsize); |
| 48 | for (i = 0; i < lsize; i++) { |
| 49 | cvmx_write64_uint64(addr_of_element(range_addr, i), |
| 50 | CVMX_RANGE_AVAILABLE); |
| 51 | } |
| 52 | return 0; |
| 53 | } |
| 54 | |
| 55 | static int64_t cvmx_range_find_next_available(u64 range_addr, u64 index, |
| 56 | int align) |
| 57 | { |
| 58 | u64 size = cvmx_read64_uint64(addr_of_size(range_addr)); |
| 59 | u64 i; |
| 60 | |
| 61 | while ((index % align) != 0) |
| 62 | index++; |
| 63 | |
| 64 | for (i = index; i < size; i += align) { |
| 65 | u64 r_owner = cvmx_read64_uint64(addr_of_element(range_addr, i)); |
| 66 | |
| 67 | if (debug) |
| 68 | debug("%s: index=%d owner=%llx\n", __func__, (int)i, |
| 69 | (unsigned long long)r_owner); |
| 70 | if (r_owner == CVMX_RANGE_AVAILABLE) |
| 71 | return i; |
| 72 | } |
| 73 | return -1; |
| 74 | } |
| 75 | |
| 76 | static int64_t cvmx_range_find_last_available(u64 range_addr, u64 index, |
| 77 | u64 align) |
| 78 | { |
| 79 | u64 size = cvmx_read64_uint64(addr_of_size(range_addr)); |
| 80 | u64 i; |
| 81 | |
| 82 | if (index == 0) |
| 83 | index = size - 1; |
| 84 | |
| 85 | while ((index % align) != 0) |
| 86 | index++; |
| 87 | |
| 88 | for (i = index; i > align; i -= align) { |
| 89 | u64 r_owner = cvmx_read64_uint64(addr_of_element(range_addr, i)); |
| 90 | |
| 91 | if (debug) |
| 92 | debug("%s: index=%d owner=%llx\n", __func__, (int)i, |
| 93 | (unsigned long long)r_owner); |
| 94 | if (r_owner == CVMX_RANGE_AVAILABLE) |
| 95 | return i; |
| 96 | } |
| 97 | return -1; |
| 98 | } |
| 99 | |
| 100 | int cvmx_range_alloc_ordered(u64 range_addr, u64 owner, u64 cnt, |
| 101 | int align, int reverse) |
| 102 | { |
| 103 | u64 i = 0, size; |
| 104 | s64 first_available; |
| 105 | |
| 106 | if (debug) |
| 107 | debug("%s: range_addr=%llx owner=%llx cnt=%d\n", __func__, |
| 108 | (unsigned long long)range_addr, |
| 109 | (unsigned long long)owner, (int)cnt); |
| 110 | |
| 111 | size = cvmx_read64_uint64(addr_of_size(range_addr)); |
| 112 | while (i < size) { |
| 113 | u64 available_cnt = 0; |
| 114 | |
| 115 | if (reverse) |
| 116 | first_available = cvmx_range_find_last_available(range_addr, i, align); |
| 117 | else |
| 118 | first_available = cvmx_range_find_next_available(range_addr, i, align); |
| 119 | if (first_available == -1) |
| 120 | return -1; |
| 121 | i = first_available; |
| 122 | |
| 123 | if (debug) |
| 124 | debug("%s: first_available=%d\n", __func__, (int)first_available); |
| 125 | while ((available_cnt != cnt) && (i < size)) { |
| 126 | u64 r_owner = cvmx_read64_uint64(addr_of_element(range_addr, i)); |
| 127 | |
| 128 | if (r_owner == CVMX_RANGE_AVAILABLE) |
| 129 | available_cnt++; |
| 130 | i++; |
| 131 | } |
| 132 | if (available_cnt == cnt) { |
| 133 | u64 j; |
| 134 | |
| 135 | if (debug) |
| 136 | debug("%s: first_available=%d available=%d\n", |
| 137 | __func__, |
| 138 | (int)first_available, (int)available_cnt); |
| 139 | |
| 140 | for (j = first_available; j < first_available + cnt; |
| 141 | j++) { |
| 142 | u64 a = addr_of_element(range_addr, j); |
| 143 | |
| 144 | cvmx_write64_uint64(a, owner); |
| 145 | } |
| 146 | return first_available; |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | if (debug) { |
| 151 | debug("ERROR: %s: failed to allocate range cnt=%d\n", |
| 152 | __func__, (int)cnt); |
| 153 | cvmx_range_show(range_addr); |
| 154 | } |
| 155 | |
| 156 | return -1; |
| 157 | } |
| 158 | |
| 159 | int cvmx_range_alloc(u64 range_addr, u64 owner, u64 cnt, int align) |
| 160 | { |
| 161 | return cvmx_range_alloc_ordered(range_addr, owner, cnt, align, 0); |
| 162 | } |
| 163 | |
| 164 | int cvmx_range_reserve(u64 range_addr, u64 owner, u64 base, |
| 165 | u64 cnt) |
| 166 | { |
| 167 | u64 i, size, r_owner; |
| 168 | u64 up = base + cnt; |
| 169 | |
| 170 | size = cvmx_read64_uint64(addr_of_size(range_addr)); |
| 171 | if (up > size) { |
| 172 | debug("ERROR: %s: invalid base or cnt. range_addr=0x%llx, owner=0x%llx, size=%d base+cnt=%d\n", |
| 173 | __func__, (unsigned long long)range_addr, |
| 174 | (unsigned long long)owner, |
| 175 | (int)size, (int)up); |
| 176 | return -1; |
| 177 | } |
| 178 | for (i = base; i < up; i++) { |
| 179 | r_owner = cvmx_read64_uint64(addr_of_element(range_addr, i)); |
| 180 | if (debug) |
| 181 | debug("%s: %d: %llx\n", |
| 182 | __func__, (int)i, (unsigned long long)r_owner); |
| 183 | if (r_owner != CVMX_RANGE_AVAILABLE) { |
| 184 | if (debug) { |
| 185 | debug("%s: resource already reserved base+cnt=%d %llu %llu %llx %llx %llx\n", |
| 186 | __func__, (int)i, (unsigned long long)cnt, |
| 187 | (unsigned long long)base, |
| 188 | (unsigned long long)r_owner, |
| 189 | (unsigned long long)range_addr, |
| 190 | (unsigned long long)owner); |
| 191 | } |
| 192 | return -1; |
| 193 | } |
| 194 | } |
| 195 | for (i = base; i < up; i++) |
| 196 | cvmx_write64_uint64(addr_of_element(range_addr, i), owner); |
| 197 | return base; |
| 198 | } |
| 199 | |
| 200 | int __cvmx_range_is_allocated(u64 range_addr, int bases[], int count) |
| 201 | { |
| 202 | u64 i, cnt, size; |
| 203 | u64 r_owner; |
| 204 | |
| 205 | cnt = count; |
| 206 | size = cvmx_read64_uint64(addr_of_size(range_addr)); |
| 207 | for (i = 0; i < cnt; i++) { |
| 208 | u64 base = bases[i]; |
| 209 | |
| 210 | if (base >= size) { |
| 211 | debug("ERROR: %s: invalid base or cnt size=%d base=%d\n", |
| 212 | __func__, (int)size, (int)base); |
| 213 | return 0; |
| 214 | } |
| 215 | r_owner = cvmx_read64_uint64(addr_of_element(range_addr, base)); |
| 216 | if (r_owner == CVMX_RANGE_AVAILABLE) { |
| 217 | if (debug) { |
| 218 | debug("%s: i=%d:base=%d is available\n", |
| 219 | __func__, (int)i, (int)base); |
| 220 | } |
| 221 | return 0; |
| 222 | } |
| 223 | } |
| 224 | return 1; |
| 225 | } |
| 226 | |
| 227 | int cvmx_range_free_mutiple(u64 range_addr, int bases[], int count) |
| 228 | { |
| 229 | u64 i, cnt; |
| 230 | |
| 231 | cnt = count; |
| 232 | if (__cvmx_range_is_allocated(range_addr, bases, count) != 1) |
| 233 | return -1; |
| 234 | for (i = 0; i < cnt; i++) { |
| 235 | u64 base = bases[i]; |
| 236 | |
| 237 | cvmx_write64_uint64(addr_of_element(range_addr, base), |
| 238 | CVMX_RANGE_AVAILABLE); |
| 239 | } |
| 240 | return 0; |
| 241 | } |
| 242 | |
| 243 | int cvmx_range_free_with_base(u64 range_addr, int base, int cnt) |
| 244 | { |
| 245 | u64 i, size; |
| 246 | u64 up = base + cnt; |
| 247 | |
| 248 | size = cvmx_read64_uint64(addr_of_size(range_addr)); |
| 249 | if (up > size) { |
| 250 | debug("ERROR: %s: invalid base or cnt size=%d base+cnt=%d\n", |
| 251 | __func__, (int)size, (int)up); |
| 252 | return -1; |
| 253 | } |
| 254 | for (i = base; i < up; i++) { |
| 255 | cvmx_write64_uint64(addr_of_element(range_addr, i), |
| 256 | CVMX_RANGE_AVAILABLE); |
| 257 | } |
| 258 | return 0; |
| 259 | } |