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 
cvmx_range_memory_size(int nelements)37 int cvmx_range_memory_size(int nelements)
38 {
39 	return sizeof(u64) * (nelements + 1);
40 }
41 
cvmx_range_init(u64 range_addr,int size)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 
cvmx_range_find_next_available(u64 range_addr,u64 index,int align)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 
cvmx_range_find_last_available(u64 range_addr,u64 index,u64 align)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 
cvmx_range_alloc_ordered(u64 range_addr,u64 owner,u64 cnt,int align,int reverse)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 
cvmx_range_alloc(u64 range_addr,u64 owner,u64 cnt,int align)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 
cvmx_range_reserve(u64 range_addr,u64 owner,u64 base,u64 cnt)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 
__cvmx_range_is_allocated(u64 range_addr,int bases[],int count)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 
cvmx_range_free_mutiple(u64 range_addr,int bases[],int count)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 
cvmx_range_free_with_base(u64 range_addr,int base,int cnt)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 }
260