diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/cavium-octeon/executive/Makefile | 13 | ||||
-rw-r--r-- | arch/mips/cavium-octeon/executive/cvmx-bootmem.c | 586 | ||||
-rw-r--r-- | arch/mips/cavium-octeon/executive/cvmx-l2c.c | 734 | ||||
-rw-r--r-- | arch/mips/cavium-octeon/executive/cvmx-sysinfo.c | 116 | ||||
-rw-r--r-- | arch/mips/cavium-octeon/executive/octeon-model.c | 358 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/cvmx-asm.h | 128 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/cvmx-bootinfo.h | 262 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/cvmx-bootmem.h | 288 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/cvmx-l2c.h | 325 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/cvmx-packet.h | 61 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/cvmx-spinlock.h | 232 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/cvmx-sysinfo.h | 152 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/cvmx.h | 505 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/octeon-feature.h | 119 | ||||
-rw-r--r-- | arch/mips/include/asm/octeon/octeon-model.h | 321 |
15 files changed, 4200 insertions, 0 deletions
diff --git a/arch/mips/cavium-octeon/executive/Makefile b/arch/mips/cavium-octeon/executive/Makefile new file mode 100644 index 000000000000..80d6cb26766b --- /dev/null +++ b/arch/mips/cavium-octeon/executive/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # | ||
2 | # Makefile for the Cavium Octeon specific kernel interface routines | ||
3 | # under Linux. | ||
4 | # | ||
5 | # This file is subject to the terms and conditions of the GNU General Public | ||
6 | # License. See the file "COPYING" in the main directory of this archive | ||
7 | # for more details. | ||
8 | # | ||
9 | # Copyright (C) 2005-2008 Cavium Networks | ||
10 | # | ||
11 | |||
12 | obj-y += cvmx-bootmem.o cvmx-l2c.o cvmx-sysinfo.o octeon-model.o | ||
13 | |||
diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c new file mode 100644 index 000000000000..4f5a08b37ccd --- /dev/null +++ b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c | |||
@@ -0,0 +1,586 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * Simple allocate only memory allocator. Used to allocate memory at | ||
30 | * application start time. | ||
31 | */ | ||
32 | |||
33 | #include <linux/kernel.h> | ||
34 | |||
35 | #include <asm/octeon/cvmx.h> | ||
36 | #include <asm/octeon/cvmx-spinlock.h> | ||
37 | #include <asm/octeon/cvmx-bootmem.h> | ||
38 | |||
39 | /*#define DEBUG */ | ||
40 | |||
41 | |||
42 | static struct cvmx_bootmem_desc *cvmx_bootmem_desc; | ||
43 | |||
44 | /* See header file for descriptions of functions */ | ||
45 | |||
46 | /* | ||
47 | * Wrapper functions are provided for reading/writing the size and | ||
48 | * next block values as these may not be directly addressible (in 32 | ||
49 | * bit applications, for instance.) Offsets of data elements in | ||
50 | * bootmem list, must match cvmx_bootmem_block_header_t. | ||
51 | */ | ||
52 | #define NEXT_OFFSET 0 | ||
53 | #define SIZE_OFFSET 8 | ||
54 | |||
55 | static void cvmx_bootmem_phy_set_size(uint64_t addr, uint64_t size) | ||
56 | { | ||
57 | cvmx_write64_uint64((addr + SIZE_OFFSET) | (1ull << 63), size); | ||
58 | } | ||
59 | |||
60 | static void cvmx_bootmem_phy_set_next(uint64_t addr, uint64_t next) | ||
61 | { | ||
62 | cvmx_write64_uint64((addr + NEXT_OFFSET) | (1ull << 63), next); | ||
63 | } | ||
64 | |||
65 | static uint64_t cvmx_bootmem_phy_get_size(uint64_t addr) | ||
66 | { | ||
67 | return cvmx_read64_uint64((addr + SIZE_OFFSET) | (1ull << 63)); | ||
68 | } | ||
69 | |||
70 | static uint64_t cvmx_bootmem_phy_get_next(uint64_t addr) | ||
71 | { | ||
72 | return cvmx_read64_uint64((addr + NEXT_OFFSET) | (1ull << 63)); | ||
73 | } | ||
74 | |||
75 | void *cvmx_bootmem_alloc_range(uint64_t size, uint64_t alignment, | ||
76 | uint64_t min_addr, uint64_t max_addr) | ||
77 | { | ||
78 | int64_t address; | ||
79 | address = | ||
80 | cvmx_bootmem_phy_alloc(size, min_addr, max_addr, alignment, 0); | ||
81 | |||
82 | if (address > 0) | ||
83 | return cvmx_phys_to_ptr(address); | ||
84 | else | ||
85 | return NULL; | ||
86 | } | ||
87 | |||
88 | void *cvmx_bootmem_alloc_address(uint64_t size, uint64_t address, | ||
89 | uint64_t alignment) | ||
90 | { | ||
91 | return cvmx_bootmem_alloc_range(size, alignment, address, | ||
92 | address + size); | ||
93 | } | ||
94 | |||
95 | void *cvmx_bootmem_alloc(uint64_t size, uint64_t alignment) | ||
96 | { | ||
97 | return cvmx_bootmem_alloc_range(size, alignment, 0, 0); | ||
98 | } | ||
99 | |||
100 | int cvmx_bootmem_free_named(char *name) | ||
101 | { | ||
102 | return cvmx_bootmem_phy_named_block_free(name, 0); | ||
103 | } | ||
104 | |||
105 | struct cvmx_bootmem_named_block_desc *cvmx_bootmem_find_named_block(char *name) | ||
106 | { | ||
107 | return cvmx_bootmem_phy_named_block_find(name, 0); | ||
108 | } | ||
109 | |||
110 | void cvmx_bootmem_lock(void) | ||
111 | { | ||
112 | cvmx_spinlock_lock((cvmx_spinlock_t *) &(cvmx_bootmem_desc->lock)); | ||
113 | } | ||
114 | |||
115 | void cvmx_bootmem_unlock(void) | ||
116 | { | ||
117 | cvmx_spinlock_unlock((cvmx_spinlock_t *) &(cvmx_bootmem_desc->lock)); | ||
118 | } | ||
119 | |||
120 | int cvmx_bootmem_init(void *mem_desc_ptr) | ||
121 | { | ||
122 | /* Here we set the global pointer to the bootmem descriptor | ||
123 | * block. This pointer will be used directly, so we will set | ||
124 | * it up to be directly usable by the application. It is set | ||
125 | * up as follows for the various runtime/ABI combinations: | ||
126 | * | ||
127 | * Linux 64 bit: Set XKPHYS bit | ||
128 | * Linux 32 bit: use mmap to create mapping, use virtual address | ||
129 | * CVMX 64 bit: use physical address directly | ||
130 | * CVMX 32 bit: use physical address directly | ||
131 | * | ||
132 | * Note that the CVMX environment assumes the use of 1-1 TLB | ||
133 | * mappings so that the physical addresses can be used | ||
134 | * directly | ||
135 | */ | ||
136 | if (!cvmx_bootmem_desc) { | ||
137 | #if defined(CVMX_ABI_64) | ||
138 | /* Set XKPHYS bit */ | ||
139 | cvmx_bootmem_desc = cvmx_phys_to_ptr(CAST64(mem_desc_ptr)); | ||
140 | #else | ||
141 | cvmx_bootmem_desc = (struct cvmx_bootmem_desc *) mem_desc_ptr; | ||
142 | #endif | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * The cvmx_bootmem_phy* functions below return 64 bit physical | ||
150 | * addresses, and expose more features that the cvmx_bootmem_functions | ||
151 | * above. These are required for full memory space access in 32 bit | ||
152 | * applications, as well as for using some advance features. Most | ||
153 | * applications should not need to use these. | ||
154 | */ | ||
155 | |||
156 | int64_t cvmx_bootmem_phy_alloc(uint64_t req_size, uint64_t address_min, | ||
157 | uint64_t address_max, uint64_t alignment, | ||
158 | uint32_t flags) | ||
159 | { | ||
160 | |||
161 | uint64_t head_addr; | ||
162 | uint64_t ent_addr; | ||
163 | /* points to previous list entry, NULL current entry is head of list */ | ||
164 | uint64_t prev_addr = 0; | ||
165 | uint64_t new_ent_addr = 0; | ||
166 | uint64_t desired_min_addr; | ||
167 | |||
168 | #ifdef DEBUG | ||
169 | cvmx_dprintf("cvmx_bootmem_phy_alloc: req_size: 0x%llx, " | ||
170 | "min_addr: 0x%llx, max_addr: 0x%llx, align: 0x%llx\n", | ||
171 | (unsigned long long)req_size, | ||
172 | (unsigned long long)address_min, | ||
173 | (unsigned long long)address_max, | ||
174 | (unsigned long long)alignment); | ||
175 | #endif | ||
176 | |||
177 | if (cvmx_bootmem_desc->major_version > 3) { | ||
178 | cvmx_dprintf("ERROR: Incompatible bootmem descriptor " | ||
179 | "version: %d.%d at addr: %p\n", | ||
180 | (int)cvmx_bootmem_desc->major_version, | ||
181 | (int)cvmx_bootmem_desc->minor_version, | ||
182 | cvmx_bootmem_desc); | ||
183 | goto error_out; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Do a variety of checks to validate the arguments. The | ||
188 | * allocator code will later assume that these checks have | ||
189 | * been made. We validate that the requested constraints are | ||
190 | * not self-contradictory before we look through the list of | ||
191 | * available memory. | ||
192 | */ | ||
193 | |||
194 | /* 0 is not a valid req_size for this allocator */ | ||
195 | if (!req_size) | ||
196 | goto error_out; | ||
197 | |||
198 | /* Round req_size up to mult of minimum alignment bytes */ | ||
199 | req_size = (req_size + (CVMX_BOOTMEM_ALIGNMENT_SIZE - 1)) & | ||
200 | ~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1); | ||
201 | |||
202 | /* | ||
203 | * Convert !0 address_min and 0 address_max to special case of | ||
204 | * range that specifies an exact memory block to allocate. Do | ||
205 | * this before other checks and adjustments so that this | ||
206 | * tranformation will be validated. | ||
207 | */ | ||
208 | if (address_min && !address_max) | ||
209 | address_max = address_min + req_size; | ||
210 | else if (!address_min && !address_max) | ||
211 | address_max = ~0ull; /* If no limits given, use max limits */ | ||
212 | |||
213 | |||
214 | /* | ||
215 | * Enforce minimum alignment (this also keeps the minimum free block | ||
216 | * req_size the same as the alignment req_size. | ||
217 | */ | ||
218 | if (alignment < CVMX_BOOTMEM_ALIGNMENT_SIZE) | ||
219 | alignment = CVMX_BOOTMEM_ALIGNMENT_SIZE; | ||
220 | |||
221 | /* | ||
222 | * Adjust address minimum based on requested alignment (round | ||
223 | * up to meet alignment). Do this here so we can reject | ||
224 | * impossible requests up front. (NOP for address_min == 0) | ||
225 | */ | ||
226 | if (alignment) | ||
227 | address_min = __ALIGN_MASK(address_min, (alignment - 1)); | ||
228 | |||
229 | /* | ||
230 | * Reject inconsistent args. We have adjusted these, so this | ||
231 | * may fail due to our internal changes even if this check | ||
232 | * would pass for the values the user supplied. | ||
233 | */ | ||
234 | if (req_size > address_max - address_min) | ||
235 | goto error_out; | ||
236 | |||
237 | /* Walk through the list entries - first fit found is returned */ | ||
238 | |||
239 | if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) | ||
240 | cvmx_bootmem_lock(); | ||
241 | head_addr = cvmx_bootmem_desc->head_addr; | ||
242 | ent_addr = head_addr; | ||
243 | for (; ent_addr; | ||
244 | prev_addr = ent_addr, | ||
245 | ent_addr = cvmx_bootmem_phy_get_next(ent_addr)) { | ||
246 | uint64_t usable_base, usable_max; | ||
247 | uint64_t ent_size = cvmx_bootmem_phy_get_size(ent_addr); | ||
248 | |||
249 | if (cvmx_bootmem_phy_get_next(ent_addr) | ||
250 | && ent_addr > cvmx_bootmem_phy_get_next(ent_addr)) { | ||
251 | cvmx_dprintf("Internal bootmem_alloc() error: ent: " | ||
252 | "0x%llx, next: 0x%llx\n", | ||
253 | (unsigned long long)ent_addr, | ||
254 | (unsigned long long) | ||
255 | cvmx_bootmem_phy_get_next(ent_addr)); | ||
256 | goto error_out; | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Determine if this is an entry that can satisify the | ||
261 | * request Check to make sure entry is large enough to | ||
262 | * satisfy request. | ||
263 | */ | ||
264 | usable_base = | ||
265 | __ALIGN_MASK(max(address_min, ent_addr), alignment - 1); | ||
266 | usable_max = min(address_max, ent_addr + ent_size); | ||
267 | /* | ||
268 | * We should be able to allocate block at address | ||
269 | * usable_base. | ||
270 | */ | ||
271 | |||
272 | desired_min_addr = usable_base; | ||
273 | /* | ||
274 | * Determine if request can be satisfied from the | ||
275 | * current entry. | ||
276 | */ | ||
277 | if (!((ent_addr + ent_size) > usable_base | ||
278 | && ent_addr < address_max | ||
279 | && req_size <= usable_max - usable_base)) | ||
280 | continue; | ||
281 | /* | ||
282 | * We have found an entry that has room to satisfy the | ||
283 | * request, so allocate it from this entry. If end | ||
284 | * CVMX_BOOTMEM_FLAG_END_ALLOC set, then allocate from | ||
285 | * the end of this block rather than the beginning. | ||
286 | */ | ||
287 | if (flags & CVMX_BOOTMEM_FLAG_END_ALLOC) { | ||
288 | desired_min_addr = usable_max - req_size; | ||
289 | /* | ||
290 | * Align desired address down to required | ||
291 | * alignment. | ||
292 | */ | ||
293 | desired_min_addr &= ~(alignment - 1); | ||
294 | } | ||
295 | |||
296 | /* Match at start of entry */ | ||
297 | if (desired_min_addr == ent_addr) { | ||
298 | if (req_size < ent_size) { | ||
299 | /* | ||
300 | * big enough to create a new block | ||
301 | * from top portion of block. | ||
302 | */ | ||
303 | new_ent_addr = ent_addr + req_size; | ||
304 | cvmx_bootmem_phy_set_next(new_ent_addr, | ||
305 | cvmx_bootmem_phy_get_next(ent_addr)); | ||
306 | cvmx_bootmem_phy_set_size(new_ent_addr, | ||
307 | ent_size - | ||
308 | req_size); | ||
309 | |||
310 | /* | ||
311 | * Adjust next pointer as following | ||
312 | * code uses this. | ||
313 | */ | ||
314 | cvmx_bootmem_phy_set_next(ent_addr, | ||
315 | new_ent_addr); | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * adjust prev ptr or head to remove this | ||
320 | * entry from list. | ||
321 | */ | ||
322 | if (prev_addr) | ||
323 | cvmx_bootmem_phy_set_next(prev_addr, | ||
324 | cvmx_bootmem_phy_get_next(ent_addr)); | ||
325 | else | ||
326 | /* | ||
327 | * head of list being returned, so | ||
328 | * update head ptr. | ||
329 | */ | ||
330 | cvmx_bootmem_desc->head_addr = | ||
331 | cvmx_bootmem_phy_get_next(ent_addr); | ||
332 | |||
333 | if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) | ||
334 | cvmx_bootmem_unlock(); | ||
335 | return desired_min_addr; | ||
336 | } | ||
337 | /* | ||
338 | * block returned doesn't start at beginning of entry, | ||
339 | * so we know that we will be splitting a block off | ||
340 | * the front of this one. Create a new block from the | ||
341 | * beginning, add to list, and go to top of loop | ||
342 | * again. | ||
343 | * | ||
344 | * create new block from high portion of | ||
345 | * block, so that top block starts at desired | ||
346 | * addr. | ||
347 | */ | ||
348 | new_ent_addr = desired_min_addr; | ||
349 | cvmx_bootmem_phy_set_next(new_ent_addr, | ||
350 | cvmx_bootmem_phy_get_next | ||
351 | (ent_addr)); | ||
352 | cvmx_bootmem_phy_set_size(new_ent_addr, | ||
353 | cvmx_bootmem_phy_get_size | ||
354 | (ent_addr) - | ||
355 | (desired_min_addr - | ||
356 | ent_addr)); | ||
357 | cvmx_bootmem_phy_set_size(ent_addr, | ||
358 | desired_min_addr - ent_addr); | ||
359 | cvmx_bootmem_phy_set_next(ent_addr, new_ent_addr); | ||
360 | /* Loop again to handle actual alloc from new block */ | ||
361 | } | ||
362 | error_out: | ||
363 | /* We didn't find anything, so return error */ | ||
364 | if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) | ||
365 | cvmx_bootmem_unlock(); | ||
366 | return -1; | ||
367 | } | ||
368 | |||
369 | int __cvmx_bootmem_phy_free(uint64_t phy_addr, uint64_t size, uint32_t flags) | ||
370 | { | ||
371 | uint64_t cur_addr; | ||
372 | uint64_t prev_addr = 0; /* zero is invalid */ | ||
373 | int retval = 0; | ||
374 | |||
375 | #ifdef DEBUG | ||
376 | cvmx_dprintf("__cvmx_bootmem_phy_free addr: 0x%llx, size: 0x%llx\n", | ||
377 | (unsigned long long)phy_addr, (unsigned long long)size); | ||
378 | #endif | ||
379 | if (cvmx_bootmem_desc->major_version > 3) { | ||
380 | cvmx_dprintf("ERROR: Incompatible bootmem descriptor " | ||
381 | "version: %d.%d at addr: %p\n", | ||
382 | (int)cvmx_bootmem_desc->major_version, | ||
383 | (int)cvmx_bootmem_desc->minor_version, | ||
384 | cvmx_bootmem_desc); | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | /* 0 is not a valid size for this allocator */ | ||
389 | if (!size) | ||
390 | return 0; | ||
391 | |||
392 | if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) | ||
393 | cvmx_bootmem_lock(); | ||
394 | cur_addr = cvmx_bootmem_desc->head_addr; | ||
395 | if (cur_addr == 0 || phy_addr < cur_addr) { | ||
396 | /* add at front of list - special case with changing head ptr */ | ||
397 | if (cur_addr && phy_addr + size > cur_addr) | ||
398 | goto bootmem_free_done; /* error, overlapping section */ | ||
399 | else if (phy_addr + size == cur_addr) { | ||
400 | /* Add to front of existing first block */ | ||
401 | cvmx_bootmem_phy_set_next(phy_addr, | ||
402 | cvmx_bootmem_phy_get_next | ||
403 | (cur_addr)); | ||
404 | cvmx_bootmem_phy_set_size(phy_addr, | ||
405 | cvmx_bootmem_phy_get_size | ||
406 | (cur_addr) + size); | ||
407 | cvmx_bootmem_desc->head_addr = phy_addr; | ||
408 | |||
409 | } else { | ||
410 | /* New block before first block. OK if cur_addr is 0 */ | ||
411 | cvmx_bootmem_phy_set_next(phy_addr, cur_addr); | ||
412 | cvmx_bootmem_phy_set_size(phy_addr, size); | ||
413 | cvmx_bootmem_desc->head_addr = phy_addr; | ||
414 | } | ||
415 | retval = 1; | ||
416 | goto bootmem_free_done; | ||
417 | } | ||
418 | |||
419 | /* Find place in list to add block */ | ||
420 | while (cur_addr && phy_addr > cur_addr) { | ||
421 | prev_addr = cur_addr; | ||
422 | cur_addr = cvmx_bootmem_phy_get_next(cur_addr); | ||
423 | } | ||
424 | |||
425 | if (!cur_addr) { | ||
426 | /* | ||
427 | * We have reached the end of the list, add on to end, | ||
428 | * checking to see if we need to combine with last | ||
429 | * block | ||
430 | */ | ||
431 | if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) == | ||
432 | phy_addr) { | ||
433 | cvmx_bootmem_phy_set_size(prev_addr, | ||
434 | cvmx_bootmem_phy_get_size | ||
435 | (prev_addr) + size); | ||
436 | } else { | ||
437 | cvmx_bootmem_phy_set_next(prev_addr, phy_addr); | ||
438 | cvmx_bootmem_phy_set_size(phy_addr, size); | ||
439 | cvmx_bootmem_phy_set_next(phy_addr, 0); | ||
440 | } | ||
441 | retval = 1; | ||
442 | goto bootmem_free_done; | ||
443 | } else { | ||
444 | /* | ||
445 | * insert between prev and cur nodes, checking for | ||
446 | * merge with either/both. | ||
447 | */ | ||
448 | if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) == | ||
449 | phy_addr) { | ||
450 | /* Merge with previous */ | ||
451 | cvmx_bootmem_phy_set_size(prev_addr, | ||
452 | cvmx_bootmem_phy_get_size | ||
453 | (prev_addr) + size); | ||
454 | if (phy_addr + size == cur_addr) { | ||
455 | /* Also merge with current */ | ||
456 | cvmx_bootmem_phy_set_size(prev_addr, | ||
457 | cvmx_bootmem_phy_get_size(cur_addr) + | ||
458 | cvmx_bootmem_phy_get_size(prev_addr)); | ||
459 | cvmx_bootmem_phy_set_next(prev_addr, | ||
460 | cvmx_bootmem_phy_get_next(cur_addr)); | ||
461 | } | ||
462 | retval = 1; | ||
463 | goto bootmem_free_done; | ||
464 | } else if (phy_addr + size == cur_addr) { | ||
465 | /* Merge with current */ | ||
466 | cvmx_bootmem_phy_set_size(phy_addr, | ||
467 | cvmx_bootmem_phy_get_size | ||
468 | (cur_addr) + size); | ||
469 | cvmx_bootmem_phy_set_next(phy_addr, | ||
470 | cvmx_bootmem_phy_get_next | ||
471 | (cur_addr)); | ||
472 | cvmx_bootmem_phy_set_next(prev_addr, phy_addr); | ||
473 | retval = 1; | ||
474 | goto bootmem_free_done; | ||
475 | } | ||
476 | |||
477 | /* It is a standalone block, add in between prev and cur */ | ||
478 | cvmx_bootmem_phy_set_size(phy_addr, size); | ||
479 | cvmx_bootmem_phy_set_next(phy_addr, cur_addr); | ||
480 | cvmx_bootmem_phy_set_next(prev_addr, phy_addr); | ||
481 | |||
482 | } | ||
483 | retval = 1; | ||
484 | |||
485 | bootmem_free_done: | ||
486 | if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) | ||
487 | cvmx_bootmem_unlock(); | ||
488 | return retval; | ||
489 | |||
490 | } | ||
491 | |||
492 | struct cvmx_bootmem_named_block_desc * | ||
493 | cvmx_bootmem_phy_named_block_find(char *name, uint32_t flags) | ||
494 | { | ||
495 | unsigned int i; | ||
496 | struct cvmx_bootmem_named_block_desc *named_block_array_ptr; | ||
497 | |||
498 | #ifdef DEBUG | ||
499 | cvmx_dprintf("cvmx_bootmem_phy_named_block_find: %s\n", name); | ||
500 | #endif | ||
501 | /* | ||
502 | * Lock the structure to make sure that it is not being | ||
503 | * changed while we are examining it. | ||
504 | */ | ||
505 | if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) | ||
506 | cvmx_bootmem_lock(); | ||
507 | |||
508 | /* Use XKPHYS for 64 bit linux */ | ||
509 | named_block_array_ptr = (struct cvmx_bootmem_named_block_desc *) | ||
510 | cvmx_phys_to_ptr(cvmx_bootmem_desc->named_block_array_addr); | ||
511 | |||
512 | #ifdef DEBUG | ||
513 | cvmx_dprintf | ||
514 | ("cvmx_bootmem_phy_named_block_find: named_block_array_ptr: %p\n", | ||
515 | named_block_array_ptr); | ||
516 | #endif | ||
517 | if (cvmx_bootmem_desc->major_version == 3) { | ||
518 | for (i = 0; | ||
519 | i < cvmx_bootmem_desc->named_block_num_blocks; i++) { | ||
520 | if ((name && named_block_array_ptr[i].size | ||
521 | && !strncmp(name, named_block_array_ptr[i].name, | ||
522 | cvmx_bootmem_desc->named_block_name_len | ||
523 | - 1)) | ||
524 | || (!name && !named_block_array_ptr[i].size)) { | ||
525 | if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) | ||
526 | cvmx_bootmem_unlock(); | ||
527 | |||
528 | return &(named_block_array_ptr[i]); | ||
529 | } | ||
530 | } | ||
531 | } else { | ||
532 | cvmx_dprintf("ERROR: Incompatible bootmem descriptor " | ||
533 | "version: %d.%d at addr: %p\n", | ||
534 | (int)cvmx_bootmem_desc->major_version, | ||
535 | (int)cvmx_bootmem_desc->minor_version, | ||
536 | cvmx_bootmem_desc); | ||
537 | } | ||
538 | if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING)) | ||
539 | cvmx_bootmem_unlock(); | ||
540 | |||
541 | return NULL; | ||
542 | } | ||
543 | |||
544 | int cvmx_bootmem_phy_named_block_free(char *name, uint32_t flags) | ||
545 | { | ||
546 | struct cvmx_bootmem_named_block_desc *named_block_ptr; | ||
547 | |||
548 | if (cvmx_bootmem_desc->major_version != 3) { | ||
549 | cvmx_dprintf("ERROR: Incompatible bootmem descriptor version: " | ||
550 | "%d.%d at addr: %p\n", | ||
551 | (int)cvmx_bootmem_desc->major_version, | ||
552 | (int)cvmx_bootmem_desc->minor_version, | ||
553 | cvmx_bootmem_desc); | ||
554 | return 0; | ||
555 | } | ||
556 | #ifdef DEBUG | ||
557 | cvmx_dprintf("cvmx_bootmem_phy_named_block_free: %s\n", name); | ||
558 | #endif | ||
559 | |||
560 | /* | ||
561 | * Take lock here, as name lookup/block free/name free need to | ||
562 | * be atomic. | ||
563 | */ | ||
564 | cvmx_bootmem_lock(); | ||
565 | |||
566 | named_block_ptr = | ||
567 | cvmx_bootmem_phy_named_block_find(name, | ||
568 | CVMX_BOOTMEM_FLAG_NO_LOCKING); | ||
569 | if (named_block_ptr) { | ||
570 | #ifdef DEBUG | ||
571 | cvmx_dprintf("cvmx_bootmem_phy_named_block_free: " | ||
572 | "%s, base: 0x%llx, size: 0x%llx\n", | ||
573 | name, | ||
574 | (unsigned long long)named_block_ptr->base_addr, | ||
575 | (unsigned long long)named_block_ptr->size); | ||
576 | #endif | ||
577 | __cvmx_bootmem_phy_free(named_block_ptr->base_addr, | ||
578 | named_block_ptr->size, | ||
579 | CVMX_BOOTMEM_FLAG_NO_LOCKING); | ||
580 | named_block_ptr->size = 0; | ||
581 | /* Set size to zero to indicate block not used. */ | ||
582 | } | ||
583 | |||
584 | cvmx_bootmem_unlock(); | ||
585 | return named_block_ptr != NULL; /* 0 on failure, 1 on success */ | ||
586 | } | ||
diff --git a/arch/mips/cavium-octeon/executive/cvmx-l2c.c b/arch/mips/cavium-octeon/executive/cvmx-l2c.c new file mode 100644 index 000000000000..6abe56f1e097 --- /dev/null +++ b/arch/mips/cavium-octeon/executive/cvmx-l2c.c | |||
@@ -0,0 +1,734 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * Implementation of the Level 2 Cache (L2C) control, measurement, and | ||
30 | * debugging facilities. | ||
31 | */ | ||
32 | |||
33 | #include <asm/octeon/cvmx.h> | ||
34 | #include <asm/octeon/cvmx-l2c.h> | ||
35 | #include <asm/octeon/cvmx-spinlock.h> | ||
36 | |||
37 | /* | ||
38 | * This spinlock is used internally to ensure that only one core is | ||
39 | * performing certain L2 operations at a time. | ||
40 | * | ||
41 | * NOTE: This only protects calls from within a single application - | ||
42 | * if multiple applications or operating systems are running, then it | ||
43 | * is up to the user program to coordinate between them. | ||
44 | */ | ||
45 | static cvmx_spinlock_t cvmx_l2c_spinlock; | ||
46 | |||
47 | static inline int l2_size_half(void) | ||
48 | { | ||
49 | uint64_t val = cvmx_read_csr(CVMX_L2D_FUS3); | ||
50 | return !!(val & (1ull << 34)); | ||
51 | } | ||
52 | |||
53 | int cvmx_l2c_get_core_way_partition(uint32_t core) | ||
54 | { | ||
55 | uint32_t field; | ||
56 | |||
57 | /* Validate the core number */ | ||
58 | if (core >= cvmx_octeon_num_cores()) | ||
59 | return -1; | ||
60 | |||
61 | /* | ||
62 | * Use the lower two bits of the coreNumber to determine the | ||
63 | * bit offset of the UMSK[] field in the L2C_SPAR register. | ||
64 | */ | ||
65 | field = (core & 0x3) * 8; | ||
66 | |||
67 | /* | ||
68 | * Return the UMSK[] field from the appropriate L2C_SPAR | ||
69 | * register based on the coreNumber. | ||
70 | */ | ||
71 | |||
72 | switch (core & 0xC) { | ||
73 | case 0x0: | ||
74 | return (cvmx_read_csr(CVMX_L2C_SPAR0) & (0xFF << field)) >> | ||
75 | field; | ||
76 | case 0x4: | ||
77 | return (cvmx_read_csr(CVMX_L2C_SPAR1) & (0xFF << field)) >> | ||
78 | field; | ||
79 | case 0x8: | ||
80 | return (cvmx_read_csr(CVMX_L2C_SPAR2) & (0xFF << field)) >> | ||
81 | field; | ||
82 | case 0xC: | ||
83 | return (cvmx_read_csr(CVMX_L2C_SPAR3) & (0xFF << field)) >> | ||
84 | field; | ||
85 | } | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | int cvmx_l2c_set_core_way_partition(uint32_t core, uint32_t mask) | ||
90 | { | ||
91 | uint32_t field; | ||
92 | uint32_t valid_mask; | ||
93 | |||
94 | valid_mask = (0x1 << cvmx_l2c_get_num_assoc()) - 1; | ||
95 | |||
96 | mask &= valid_mask; | ||
97 | |||
98 | /* A UMSK setting which blocks all L2C Ways is an error. */ | ||
99 | if (mask == valid_mask) | ||
100 | return -1; | ||
101 | |||
102 | /* Validate the core number */ | ||
103 | if (core >= cvmx_octeon_num_cores()) | ||
104 | return -1; | ||
105 | |||
106 | /* Check to make sure current mask & new mask don't block all ways */ | ||
107 | if (((mask | cvmx_l2c_get_core_way_partition(core)) & valid_mask) == | ||
108 | valid_mask) | ||
109 | return -1; | ||
110 | |||
111 | /* Use the lower two bits of core to determine the bit offset of the | ||
112 | * UMSK[] field in the L2C_SPAR register. | ||
113 | */ | ||
114 | field = (core & 0x3) * 8; | ||
115 | |||
116 | /* Assign the new mask setting to the UMSK[] field in the appropriate | ||
117 | * L2C_SPAR register based on the core_num. | ||
118 | * | ||
119 | */ | ||
120 | switch (core & 0xC) { | ||
121 | case 0x0: | ||
122 | cvmx_write_csr(CVMX_L2C_SPAR0, | ||
123 | (cvmx_read_csr(CVMX_L2C_SPAR0) & | ||
124 | ~(0xFF << field)) | mask << field); | ||
125 | break; | ||
126 | case 0x4: | ||
127 | cvmx_write_csr(CVMX_L2C_SPAR1, | ||
128 | (cvmx_read_csr(CVMX_L2C_SPAR1) & | ||
129 | ~(0xFF << field)) | mask << field); | ||
130 | break; | ||
131 | case 0x8: | ||
132 | cvmx_write_csr(CVMX_L2C_SPAR2, | ||
133 | (cvmx_read_csr(CVMX_L2C_SPAR2) & | ||
134 | ~(0xFF << field)) | mask << field); | ||
135 | break; | ||
136 | case 0xC: | ||
137 | cvmx_write_csr(CVMX_L2C_SPAR3, | ||
138 | (cvmx_read_csr(CVMX_L2C_SPAR3) & | ||
139 | ~(0xFF << field)) | mask << field); | ||
140 | break; | ||
141 | } | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | int cvmx_l2c_set_hw_way_partition(uint32_t mask) | ||
146 | { | ||
147 | uint32_t valid_mask; | ||
148 | |||
149 | valid_mask = 0xff; | ||
150 | |||
151 | if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN38XX)) { | ||
152 | if (l2_size_half()) | ||
153 | valid_mask = 0xf; | ||
154 | } else if (l2_size_half()) | ||
155 | valid_mask = 0x3; | ||
156 | |||
157 | mask &= valid_mask; | ||
158 | |||
159 | /* A UMSK setting which blocks all L2C Ways is an error. */ | ||
160 | if (mask == valid_mask) | ||
161 | return -1; | ||
162 | /* Check to make sure current mask & new mask don't block all ways */ | ||
163 | if (((mask | cvmx_l2c_get_hw_way_partition()) & valid_mask) == | ||
164 | valid_mask) | ||
165 | return -1; | ||
166 | |||
167 | cvmx_write_csr(CVMX_L2C_SPAR4, | ||
168 | (cvmx_read_csr(CVMX_L2C_SPAR4) & ~0xFF) | mask); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | int cvmx_l2c_get_hw_way_partition(void) | ||
173 | { | ||
174 | return cvmx_read_csr(CVMX_L2C_SPAR4) & (0xFF); | ||
175 | } | ||
176 | |||
177 | void cvmx_l2c_config_perf(uint32_t counter, enum cvmx_l2c_event event, | ||
178 | uint32_t clear_on_read) | ||
179 | { | ||
180 | union cvmx_l2c_pfctl pfctl; | ||
181 | |||
182 | pfctl.u64 = cvmx_read_csr(CVMX_L2C_PFCTL); | ||
183 | |||
184 | switch (counter) { | ||
185 | case 0: | ||
186 | pfctl.s.cnt0sel = event; | ||
187 | pfctl.s.cnt0ena = 1; | ||
188 | if (!cvmx_octeon_is_pass1()) | ||
189 | pfctl.s.cnt0rdclr = clear_on_read; | ||
190 | break; | ||
191 | case 1: | ||
192 | pfctl.s.cnt1sel = event; | ||
193 | pfctl.s.cnt1ena = 1; | ||
194 | if (!cvmx_octeon_is_pass1()) | ||
195 | pfctl.s.cnt1rdclr = clear_on_read; | ||
196 | break; | ||
197 | case 2: | ||
198 | pfctl.s.cnt2sel = event; | ||
199 | pfctl.s.cnt2ena = 1; | ||
200 | if (!cvmx_octeon_is_pass1()) | ||
201 | pfctl.s.cnt2rdclr = clear_on_read; | ||
202 | break; | ||
203 | case 3: | ||
204 | default: | ||
205 | pfctl.s.cnt3sel = event; | ||
206 | pfctl.s.cnt3ena = 1; | ||
207 | if (!cvmx_octeon_is_pass1()) | ||
208 | pfctl.s.cnt3rdclr = clear_on_read; | ||
209 | break; | ||
210 | } | ||
211 | |||
212 | cvmx_write_csr(CVMX_L2C_PFCTL, pfctl.u64); | ||
213 | } | ||
214 | |||
215 | uint64_t cvmx_l2c_read_perf(uint32_t counter) | ||
216 | { | ||
217 | switch (counter) { | ||
218 | case 0: | ||
219 | return cvmx_read_csr(CVMX_L2C_PFC0); | ||
220 | case 1: | ||
221 | return cvmx_read_csr(CVMX_L2C_PFC1); | ||
222 | case 2: | ||
223 | return cvmx_read_csr(CVMX_L2C_PFC2); | ||
224 | case 3: | ||
225 | default: | ||
226 | return cvmx_read_csr(CVMX_L2C_PFC3); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | /** | ||
231 | * @INTERNAL | ||
232 | * Helper function use to fault in cache lines for L2 cache locking | ||
233 | * | ||
234 | * @addr: Address of base of memory region to read into L2 cache | ||
235 | * @len: Length (in bytes) of region to fault in | ||
236 | */ | ||
237 | static void fault_in(uint64_t addr, int len) | ||
238 | { | ||
239 | volatile char *ptr; | ||
240 | volatile char dummy; | ||
241 | /* | ||
242 | * Adjust addr and length so we get all cache lines even for | ||
243 | * small ranges spanning two cache lines | ||
244 | */ | ||
245 | len += addr & CVMX_CACHE_LINE_MASK; | ||
246 | addr &= ~CVMX_CACHE_LINE_MASK; | ||
247 | ptr = (volatile char *)cvmx_phys_to_ptr(addr); | ||
248 | /* | ||
249 | * Invalidate L1 cache to make sure all loads result in data | ||
250 | * being in L2. | ||
251 | */ | ||
252 | CVMX_DCACHE_INVALIDATE; | ||
253 | while (len > 0) { | ||
254 | dummy += *ptr; | ||
255 | len -= CVMX_CACHE_LINE_SIZE; | ||
256 | ptr += CVMX_CACHE_LINE_SIZE; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | int cvmx_l2c_lock_line(uint64_t addr) | ||
261 | { | ||
262 | int retval = 0; | ||
263 | union cvmx_l2c_dbg l2cdbg; | ||
264 | union cvmx_l2c_lckbase lckbase; | ||
265 | union cvmx_l2c_lckoff lckoff; | ||
266 | union cvmx_l2t_err l2t_err; | ||
267 | l2cdbg.u64 = 0; | ||
268 | lckbase.u64 = 0; | ||
269 | lckoff.u64 = 0; | ||
270 | |||
271 | cvmx_spinlock_lock(&cvmx_l2c_spinlock); | ||
272 | |||
273 | /* Clear l2t error bits if set */ | ||
274 | l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); | ||
275 | l2t_err.s.lckerr = 1; | ||
276 | l2t_err.s.lckerr2 = 1; | ||
277 | cvmx_write_csr(CVMX_L2T_ERR, l2t_err.u64); | ||
278 | |||
279 | addr &= ~CVMX_CACHE_LINE_MASK; | ||
280 | |||
281 | /* Set this core as debug core */ | ||
282 | l2cdbg.s.ppnum = cvmx_get_core_num(); | ||
283 | CVMX_SYNC; | ||
284 | cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); | ||
285 | cvmx_read_csr(CVMX_L2C_DBG); | ||
286 | |||
287 | lckoff.s.lck_offset = 0; /* Only lock 1 line at a time */ | ||
288 | cvmx_write_csr(CVMX_L2C_LCKOFF, lckoff.u64); | ||
289 | cvmx_read_csr(CVMX_L2C_LCKOFF); | ||
290 | |||
291 | if (((union cvmx_l2c_cfg) (cvmx_read_csr(CVMX_L2C_CFG))).s.idxalias) { | ||
292 | int alias_shift = | ||
293 | CVMX_L2C_IDX_ADDR_SHIFT + 2 * CVMX_L2_SET_BITS - 1; | ||
294 | uint64_t addr_tmp = | ||
295 | addr ^ (addr & ((1 << alias_shift) - 1)) >> | ||
296 | CVMX_L2_SET_BITS; | ||
297 | lckbase.s.lck_base = addr_tmp >> 7; | ||
298 | } else { | ||
299 | lckbase.s.lck_base = addr >> 7; | ||
300 | } | ||
301 | |||
302 | lckbase.s.lck_ena = 1; | ||
303 | cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); | ||
304 | cvmx_read_csr(CVMX_L2C_LCKBASE); /* Make sure it gets there */ | ||
305 | |||
306 | fault_in(addr, CVMX_CACHE_LINE_SIZE); | ||
307 | |||
308 | lckbase.s.lck_ena = 0; | ||
309 | cvmx_write_csr(CVMX_L2C_LCKBASE, lckbase.u64); | ||
310 | cvmx_read_csr(CVMX_L2C_LCKBASE); /* Make sure it gets there */ | ||
311 | |||
312 | /* Stop being debug core */ | ||
313 | cvmx_write_csr(CVMX_L2C_DBG, 0); | ||
314 | cvmx_read_csr(CVMX_L2C_DBG); | ||
315 | |||
316 | l2t_err.u64 = cvmx_read_csr(CVMX_L2T_ERR); | ||
317 | if (l2t_err.s.lckerr || l2t_err.s.lckerr2) | ||
318 | retval = 1; /* We were unable to lock the line */ | ||
319 | |||
320 | cvmx_spinlock_unlock(&cvmx_l2c_spinlock); | ||
321 | |||
322 | return retval; | ||
323 | } | ||
324 | |||
325 | int cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len) | ||
326 | { | ||
327 | int retval = 0; | ||
328 | |||
329 | /* Round start/end to cache line boundaries */ | ||
330 | len += start & CVMX_CACHE_LINE_MASK; | ||
331 | start &= ~CVMX_CACHE_LINE_MASK; | ||
332 | len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK; | ||
333 | |||
334 | while (len) { | ||
335 | retval += cvmx_l2c_lock_line(start); | ||
336 | start += CVMX_CACHE_LINE_SIZE; | ||
337 | len -= CVMX_CACHE_LINE_SIZE; | ||
338 | } | ||
339 | |||
340 | return retval; | ||
341 | } | ||
342 | |||
343 | void cvmx_l2c_flush(void) | ||
344 | { | ||
345 | uint64_t assoc, set; | ||
346 | uint64_t n_assoc, n_set; | ||
347 | union cvmx_l2c_dbg l2cdbg; | ||
348 | |||
349 | cvmx_spinlock_lock(&cvmx_l2c_spinlock); | ||
350 | |||
351 | l2cdbg.u64 = 0; | ||
352 | if (!OCTEON_IS_MODEL(OCTEON_CN30XX)) | ||
353 | l2cdbg.s.ppnum = cvmx_get_core_num(); | ||
354 | l2cdbg.s.finv = 1; | ||
355 | n_set = CVMX_L2_SETS; | ||
356 | n_assoc = l2_size_half() ? (CVMX_L2_ASSOC / 2) : CVMX_L2_ASSOC; | ||
357 | for (set = 0; set < n_set; set++) { | ||
358 | for (assoc = 0; assoc < n_assoc; assoc++) { | ||
359 | l2cdbg.s.set = assoc; | ||
360 | /* Enter debug mode, and make sure all other | ||
361 | ** writes complete before we enter debug | ||
362 | ** mode */ | ||
363 | CVMX_SYNCW; | ||
364 | cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); | ||
365 | cvmx_read_csr(CVMX_L2C_DBG); | ||
366 | |||
367 | CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG | ||
368 | (CVMX_MIPS_SPACE_XKPHYS, | ||
369 | set * CVMX_CACHE_LINE_SIZE), 0); | ||
370 | CVMX_SYNCW; /* Push STF out to L2 */ | ||
371 | /* Exit debug mode */ | ||
372 | CVMX_SYNC; | ||
373 | cvmx_write_csr(CVMX_L2C_DBG, 0); | ||
374 | cvmx_read_csr(CVMX_L2C_DBG); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | cvmx_spinlock_unlock(&cvmx_l2c_spinlock); | ||
379 | } | ||
380 | |||
381 | int cvmx_l2c_unlock_line(uint64_t address) | ||
382 | { | ||
383 | int assoc; | ||
384 | union cvmx_l2c_tag tag; | ||
385 | union cvmx_l2c_dbg l2cdbg; | ||
386 | uint32_t tag_addr; | ||
387 | |||
388 | uint32_t index = cvmx_l2c_address_to_index(address); | ||
389 | |||
390 | cvmx_spinlock_lock(&cvmx_l2c_spinlock); | ||
391 | /* Compute portion of address that is stored in tag */ | ||
392 | tag_addr = | ||
393 | ((address >> CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) & | ||
394 | ((1 << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) - 1)); | ||
395 | for (assoc = 0; assoc < CVMX_L2_ASSOC; assoc++) { | ||
396 | tag = cvmx_get_l2c_tag(assoc, index); | ||
397 | |||
398 | if (tag.s.V && (tag.s.addr == tag_addr)) { | ||
399 | l2cdbg.u64 = 0; | ||
400 | l2cdbg.s.ppnum = cvmx_get_core_num(); | ||
401 | l2cdbg.s.set = assoc; | ||
402 | l2cdbg.s.finv = 1; | ||
403 | |||
404 | CVMX_SYNC; | ||
405 | /* Enter debug mode */ | ||
406 | cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); | ||
407 | cvmx_read_csr(CVMX_L2C_DBG); | ||
408 | |||
409 | CVMX_PREPARE_FOR_STORE(CVMX_ADD_SEG | ||
410 | (CVMX_MIPS_SPACE_XKPHYS, | ||
411 | address), 0); | ||
412 | CVMX_SYNC; | ||
413 | /* Exit debug mode */ | ||
414 | cvmx_write_csr(CVMX_L2C_DBG, 0); | ||
415 | cvmx_read_csr(CVMX_L2C_DBG); | ||
416 | cvmx_spinlock_unlock(&cvmx_l2c_spinlock); | ||
417 | return tag.s.L; | ||
418 | } | ||
419 | } | ||
420 | cvmx_spinlock_unlock(&cvmx_l2c_spinlock); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | int cvmx_l2c_unlock_mem_region(uint64_t start, uint64_t len) | ||
425 | { | ||
426 | int num_unlocked = 0; | ||
427 | /* Round start/end to cache line boundaries */ | ||
428 | len += start & CVMX_CACHE_LINE_MASK; | ||
429 | start &= ~CVMX_CACHE_LINE_MASK; | ||
430 | len = (len + CVMX_CACHE_LINE_MASK) & ~CVMX_CACHE_LINE_MASK; | ||
431 | while (len > 0) { | ||
432 | num_unlocked += cvmx_l2c_unlock_line(start); | ||
433 | start += CVMX_CACHE_LINE_SIZE; | ||
434 | len -= CVMX_CACHE_LINE_SIZE; | ||
435 | } | ||
436 | |||
437 | return num_unlocked; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * Internal l2c tag types. These are converted to a generic structure | ||
442 | * that can be used on all chips. | ||
443 | */ | ||
444 | union __cvmx_l2c_tag { | ||
445 | uint64_t u64; | ||
446 | struct cvmx_l2c_tag_cn50xx { | ||
447 | uint64_t reserved:40; | ||
448 | uint64_t V:1; /* Line valid */ | ||
449 | uint64_t D:1; /* Line dirty */ | ||
450 | uint64_t L:1; /* Line locked */ | ||
451 | uint64_t U:1; /* Use, LRU eviction */ | ||
452 | uint64_t addr:20; /* Phys mem addr (33..14) */ | ||
453 | } cn50xx; | ||
454 | struct cvmx_l2c_tag_cn30xx { | ||
455 | uint64_t reserved:41; | ||
456 | uint64_t V:1; /* Line valid */ | ||
457 | uint64_t D:1; /* Line dirty */ | ||
458 | uint64_t L:1; /* Line locked */ | ||
459 | uint64_t U:1; /* Use, LRU eviction */ | ||
460 | uint64_t addr:19; /* Phys mem addr (33..15) */ | ||
461 | } cn30xx; | ||
462 | struct cvmx_l2c_tag_cn31xx { | ||
463 | uint64_t reserved:42; | ||
464 | uint64_t V:1; /* Line valid */ | ||
465 | uint64_t D:1; /* Line dirty */ | ||
466 | uint64_t L:1; /* Line locked */ | ||
467 | uint64_t U:1; /* Use, LRU eviction */ | ||
468 | uint64_t addr:18; /* Phys mem addr (33..16) */ | ||
469 | } cn31xx; | ||
470 | struct cvmx_l2c_tag_cn38xx { | ||
471 | uint64_t reserved:43; | ||
472 | uint64_t V:1; /* Line valid */ | ||
473 | uint64_t D:1; /* Line dirty */ | ||
474 | uint64_t L:1; /* Line locked */ | ||
475 | uint64_t U:1; /* Use, LRU eviction */ | ||
476 | uint64_t addr:17; /* Phys mem addr (33..17) */ | ||
477 | } cn38xx; | ||
478 | struct cvmx_l2c_tag_cn58xx { | ||
479 | uint64_t reserved:44; | ||
480 | uint64_t V:1; /* Line valid */ | ||
481 | uint64_t D:1; /* Line dirty */ | ||
482 | uint64_t L:1; /* Line locked */ | ||
483 | uint64_t U:1; /* Use, LRU eviction */ | ||
484 | uint64_t addr:16; /* Phys mem addr (33..18) */ | ||
485 | } cn58xx; | ||
486 | struct cvmx_l2c_tag_cn58xx cn56xx; /* 2048 sets */ | ||
487 | struct cvmx_l2c_tag_cn31xx cn52xx; /* 512 sets */ | ||
488 | }; | ||
489 | |||
490 | /** | ||
491 | * @INTERNAL | ||
492 | * Function to read a L2C tag. This code make the current core | ||
493 | * the 'debug core' for the L2. This code must only be executed by | ||
494 | * 1 core at a time. | ||
495 | * | ||
496 | * @assoc: Association (way) of the tag to dump | ||
497 | * @index: Index of the cacheline | ||
498 | * | ||
499 | * Returns The Octeon model specific tag structure. This is | ||
500 | * translated by a wrapper function to a generic form that is | ||
501 | * easier for applications to use. | ||
502 | */ | ||
503 | static union __cvmx_l2c_tag __read_l2_tag(uint64_t assoc, uint64_t index) | ||
504 | { | ||
505 | |||
506 | uint64_t debug_tag_addr = (((1ULL << 63) | (index << 7)) + 96); | ||
507 | uint64_t core = cvmx_get_core_num(); | ||
508 | union __cvmx_l2c_tag tag_val; | ||
509 | uint64_t dbg_addr = CVMX_L2C_DBG; | ||
510 | unsigned long flags; | ||
511 | |||
512 | union cvmx_l2c_dbg debug_val; | ||
513 | debug_val.u64 = 0; | ||
514 | /* | ||
515 | * For low core count parts, the core number is always small enough | ||
516 | * to stay in the correct field and not set any reserved bits. | ||
517 | */ | ||
518 | debug_val.s.ppnum = core; | ||
519 | debug_val.s.l2t = 1; | ||
520 | debug_val.s.set = assoc; | ||
521 | /* | ||
522 | * Make sure core is quiet (no prefetches, etc.) before | ||
523 | * entering debug mode. | ||
524 | */ | ||
525 | CVMX_SYNC; | ||
526 | /* Flush L1 to make sure debug load misses L1 */ | ||
527 | CVMX_DCACHE_INVALIDATE; | ||
528 | |||
529 | local_irq_save(flags); | ||
530 | |||
531 | /* | ||
532 | * The following must be done in assembly as when in debug | ||
533 | * mode all data loads from L2 return special debug data, not | ||
534 | * normal memory contents. Also, interrupts must be | ||
535 | * disabled, since if an interrupt occurs while in debug mode | ||
536 | * the ISR will get debug data from all its memory reads | ||
537 | * instead of the contents of memory | ||
538 | */ | ||
539 | |||
540 | asm volatile (".set push \n" | ||
541 | " .set mips64 \n" | ||
542 | " .set noreorder \n" | ||
543 | /* Enter debug mode, wait for store */ | ||
544 | " sd %[dbg_val], 0(%[dbg_addr]) \n" | ||
545 | " ld $0, 0(%[dbg_addr]) \n" | ||
546 | /* Read L2C tag data */ | ||
547 | " ld %[tag_val], 0(%[tag_addr]) \n" | ||
548 | /* Exit debug mode, wait for store */ | ||
549 | " sd $0, 0(%[dbg_addr]) \n" | ||
550 | " ld $0, 0(%[dbg_addr]) \n" | ||
551 | /* Invalidate dcache to discard debug data */ | ||
552 | " cache 9, 0($0) \n" | ||
553 | " .set pop" : | ||
554 | [tag_val] "=r"(tag_val.u64) : [dbg_addr] "r"(dbg_addr), | ||
555 | [dbg_val] "r"(debug_val.u64), | ||
556 | [tag_addr] "r"(debug_tag_addr) : "memory"); | ||
557 | |||
558 | local_irq_restore(flags); | ||
559 | return tag_val; | ||
560 | |||
561 | } | ||
562 | |||
563 | union cvmx_l2c_tag cvmx_l2c_get_tag(uint32_t association, uint32_t index) | ||
564 | { | ||
565 | union __cvmx_l2c_tag tmp_tag; | ||
566 | union cvmx_l2c_tag tag; | ||
567 | tag.u64 = 0; | ||
568 | |||
569 | if ((int)association >= cvmx_l2c_get_num_assoc()) { | ||
570 | cvmx_dprintf | ||
571 | ("ERROR: cvmx_get_l2c_tag association out of range\n"); | ||
572 | return tag; | ||
573 | } | ||
574 | if ((int)index >= cvmx_l2c_get_num_sets()) { | ||
575 | cvmx_dprintf("ERROR: cvmx_get_l2c_tag " | ||
576 | "index out of range (arg: %d, max: %d\n", | ||
577 | index, cvmx_l2c_get_num_sets()); | ||
578 | return tag; | ||
579 | } | ||
580 | /* __read_l2_tag is intended for internal use only */ | ||
581 | tmp_tag = __read_l2_tag(association, index); | ||
582 | |||
583 | /* | ||
584 | * Convert all tag structure types to generic version, as it | ||
585 | * can represent all models. | ||
586 | */ | ||
587 | if (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) { | ||
588 | tag.s.V = tmp_tag.cn58xx.V; | ||
589 | tag.s.D = tmp_tag.cn58xx.D; | ||
590 | tag.s.L = tmp_tag.cn58xx.L; | ||
591 | tag.s.U = tmp_tag.cn58xx.U; | ||
592 | tag.s.addr = tmp_tag.cn58xx.addr; | ||
593 | } else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) { | ||
594 | tag.s.V = tmp_tag.cn38xx.V; | ||
595 | tag.s.D = tmp_tag.cn38xx.D; | ||
596 | tag.s.L = tmp_tag.cn38xx.L; | ||
597 | tag.s.U = tmp_tag.cn38xx.U; | ||
598 | tag.s.addr = tmp_tag.cn38xx.addr; | ||
599 | } else if (OCTEON_IS_MODEL(OCTEON_CN31XX) | ||
600 | || OCTEON_IS_MODEL(OCTEON_CN52XX)) { | ||
601 | tag.s.V = tmp_tag.cn31xx.V; | ||
602 | tag.s.D = tmp_tag.cn31xx.D; | ||
603 | tag.s.L = tmp_tag.cn31xx.L; | ||
604 | tag.s.U = tmp_tag.cn31xx.U; | ||
605 | tag.s.addr = tmp_tag.cn31xx.addr; | ||
606 | } else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) { | ||
607 | tag.s.V = tmp_tag.cn30xx.V; | ||
608 | tag.s.D = tmp_tag.cn30xx.D; | ||
609 | tag.s.L = tmp_tag.cn30xx.L; | ||
610 | tag.s.U = tmp_tag.cn30xx.U; | ||
611 | tag.s.addr = tmp_tag.cn30xx.addr; | ||
612 | } else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) { | ||
613 | tag.s.V = tmp_tag.cn50xx.V; | ||
614 | tag.s.D = tmp_tag.cn50xx.D; | ||
615 | tag.s.L = tmp_tag.cn50xx.L; | ||
616 | tag.s.U = tmp_tag.cn50xx.U; | ||
617 | tag.s.addr = tmp_tag.cn50xx.addr; | ||
618 | } else { | ||
619 | cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); | ||
620 | } | ||
621 | |||
622 | return tag; | ||
623 | } | ||
624 | |||
625 | uint32_t cvmx_l2c_address_to_index(uint64_t addr) | ||
626 | { | ||
627 | uint64_t idx = addr >> CVMX_L2C_IDX_ADDR_SHIFT; | ||
628 | union cvmx_l2c_cfg l2c_cfg; | ||
629 | l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG); | ||
630 | |||
631 | if (l2c_cfg.s.idxalias) { | ||
632 | idx ^= | ||
633 | ((addr & CVMX_L2C_ALIAS_MASK) >> | ||
634 | CVMX_L2C_TAG_ADDR_ALIAS_SHIFT); | ||
635 | } | ||
636 | idx &= CVMX_L2C_IDX_MASK; | ||
637 | return idx; | ||
638 | } | ||
639 | |||
640 | int cvmx_l2c_get_cache_size_bytes(void) | ||
641 | { | ||
642 | return cvmx_l2c_get_num_sets() * cvmx_l2c_get_num_assoc() * | ||
643 | CVMX_CACHE_LINE_SIZE; | ||
644 | } | ||
645 | |||
646 | /** | ||
647 | * Return log base 2 of the number of sets in the L2 cache | ||
648 | * Returns | ||
649 | */ | ||
650 | int cvmx_l2c_get_set_bits(void) | ||
651 | { | ||
652 | int l2_set_bits; | ||
653 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) | ||
654 | l2_set_bits = 11; /* 2048 sets */ | ||
655 | else if (OCTEON_IS_MODEL(OCTEON_CN38XX)) | ||
656 | l2_set_bits = 10; /* 1024 sets */ | ||
657 | else if (OCTEON_IS_MODEL(OCTEON_CN31XX) | ||
658 | || OCTEON_IS_MODEL(OCTEON_CN52XX)) | ||
659 | l2_set_bits = 9; /* 512 sets */ | ||
660 | else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) | ||
661 | l2_set_bits = 8; /* 256 sets */ | ||
662 | else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) | ||
663 | l2_set_bits = 7; /* 128 sets */ | ||
664 | else { | ||
665 | cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); | ||
666 | l2_set_bits = 11; /* 2048 sets */ | ||
667 | } | ||
668 | return l2_set_bits; | ||
669 | |||
670 | } | ||
671 | |||
672 | /* Return the number of sets in the L2 Cache */ | ||
673 | int cvmx_l2c_get_num_sets(void) | ||
674 | { | ||
675 | return 1 << cvmx_l2c_get_set_bits(); | ||
676 | } | ||
677 | |||
678 | /* Return the number of associations in the L2 Cache */ | ||
679 | int cvmx_l2c_get_num_assoc(void) | ||
680 | { | ||
681 | int l2_assoc; | ||
682 | if (OCTEON_IS_MODEL(OCTEON_CN56XX) || | ||
683 | OCTEON_IS_MODEL(OCTEON_CN52XX) || | ||
684 | OCTEON_IS_MODEL(OCTEON_CN58XX) || | ||
685 | OCTEON_IS_MODEL(OCTEON_CN50XX) || OCTEON_IS_MODEL(OCTEON_CN38XX)) | ||
686 | l2_assoc = 8; | ||
687 | else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || | ||
688 | OCTEON_IS_MODEL(OCTEON_CN30XX)) | ||
689 | l2_assoc = 4; | ||
690 | else { | ||
691 | cvmx_dprintf("Unsupported OCTEON Model in %s\n", __func__); | ||
692 | l2_assoc = 8; | ||
693 | } | ||
694 | |||
695 | /* Check to see if part of the cache is disabled */ | ||
696 | if (cvmx_fuse_read(265)) | ||
697 | l2_assoc = l2_assoc >> 2; | ||
698 | else if (cvmx_fuse_read(264)) | ||
699 | l2_assoc = l2_assoc >> 1; | ||
700 | |||
701 | return l2_assoc; | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * Flush a line from the L2 cache | ||
706 | * This should only be called from one core at a time, as this routine | ||
707 | * sets the core to the 'debug' core in order to flush the line. | ||
708 | * | ||
709 | * @assoc: Association (or way) to flush | ||
710 | * @index: Index to flush | ||
711 | */ | ||
712 | void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index) | ||
713 | { | ||
714 | union cvmx_l2c_dbg l2cdbg; | ||
715 | |||
716 | l2cdbg.u64 = 0; | ||
717 | l2cdbg.s.ppnum = cvmx_get_core_num(); | ||
718 | l2cdbg.s.finv = 1; | ||
719 | |||
720 | l2cdbg.s.set = assoc; | ||
721 | /* | ||
722 | * Enter debug mode, and make sure all other writes complete | ||
723 | * before we enter debug mode. | ||
724 | */ | ||
725 | asm volatile ("sync" : : : "memory"); | ||
726 | cvmx_write_csr(CVMX_L2C_DBG, l2cdbg.u64); | ||
727 | cvmx_read_csr(CVMX_L2C_DBG); | ||
728 | |||
729 | CVMX_PREPARE_FOR_STORE(((1ULL << 63) + (index) * 128), 0); | ||
730 | /* Exit debug mode */ | ||
731 | asm volatile ("sync" : : : "memory"); | ||
732 | cvmx_write_csr(CVMX_L2C_DBG, 0); | ||
733 | cvmx_read_csr(CVMX_L2C_DBG); | ||
734 | } | ||
diff --git a/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c b/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c new file mode 100644 index 000000000000..4812370706a1 --- /dev/null +++ b/arch/mips/cavium-octeon/executive/cvmx-sysinfo.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * This module provides system/board/application information obtained | ||
30 | * by the bootloader. | ||
31 | */ | ||
32 | |||
33 | #include <asm/octeon/cvmx.h> | ||
34 | #include <asm/octeon/cvmx-spinlock.h> | ||
35 | #include <asm/octeon/cvmx-sysinfo.h> | ||
36 | |||
37 | /** | ||
38 | * This structure defines the private state maintained by sysinfo module. | ||
39 | * | ||
40 | */ | ||
41 | static struct { | ||
42 | struct cvmx_sysinfo sysinfo; /* system information */ | ||
43 | cvmx_spinlock_t lock; /* mutex spinlock */ | ||
44 | |||
45 | } state = { | ||
46 | .lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER | ||
47 | }; | ||
48 | |||
49 | |||
50 | /* | ||
51 | * Global variables that define the min/max of the memory region set | ||
52 | * up for 32 bit userspace access. | ||
53 | */ | ||
54 | uint64_t linux_mem32_min; | ||
55 | uint64_t linux_mem32_max; | ||
56 | uint64_t linux_mem32_wired; | ||
57 | uint64_t linux_mem32_offset; | ||
58 | |||
59 | /** | ||
60 | * This function returns the application information as obtained | ||
61 | * by the bootloader. This provides the core mask of the cores | ||
62 | * running the same application image, as well as the physical | ||
63 | * memory regions available to the core. | ||
64 | * | ||
65 | * Returns Pointer to the boot information structure | ||
66 | * | ||
67 | */ | ||
68 | struct cvmx_sysinfo *cvmx_sysinfo_get(void) | ||
69 | { | ||
70 | return &(state.sysinfo); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * This function is used in non-simple executive environments (such as | ||
75 | * Linux kernel, u-boot, etc.) to configure the minimal fields that | ||
76 | * are required to use simple executive files directly. | ||
77 | * | ||
78 | * Locking (if required) must be handled outside of this | ||
79 | * function | ||
80 | * | ||
81 | * @phy_mem_desc_ptr: | ||
82 | * Pointer to global physical memory descriptor | ||
83 | * (bootmem descriptor) @board_type: Octeon board | ||
84 | * type enumeration | ||
85 | * | ||
86 | * @board_rev_major: | ||
87 | * Board major revision | ||
88 | * @board_rev_minor: | ||
89 | * Board minor revision | ||
90 | * @cpu_clock_hz: | ||
91 | * CPU clock freqency in hertz | ||
92 | * | ||
93 | * Returns 0: Failure | ||
94 | * 1: success | ||
95 | */ | ||
96 | int cvmx_sysinfo_minimal_initialize(void *phy_mem_desc_ptr, | ||
97 | uint16_t board_type, | ||
98 | uint8_t board_rev_major, | ||
99 | uint8_t board_rev_minor, | ||
100 | uint32_t cpu_clock_hz) | ||
101 | { | ||
102 | |||
103 | /* The sysinfo structure was already initialized */ | ||
104 | if (state.sysinfo.board_type) | ||
105 | return 0; | ||
106 | |||
107 | memset(&(state.sysinfo), 0x0, sizeof(state.sysinfo)); | ||
108 | state.sysinfo.phy_mem_desc_ptr = phy_mem_desc_ptr; | ||
109 | state.sysinfo.board_type = board_type; | ||
110 | state.sysinfo.board_rev_major = board_rev_major; | ||
111 | state.sysinfo.board_rev_minor = board_rev_minor; | ||
112 | state.sysinfo.cpu_clock_hz = cpu_clock_hz; | ||
113 | |||
114 | return 1; | ||
115 | } | ||
116 | |||
diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c new file mode 100644 index 000000000000..9afc3794ed1b --- /dev/null +++ b/arch/mips/cavium-octeon/executive/octeon-model.c | |||
@@ -0,0 +1,358 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * File defining functions for working with different Octeon | ||
30 | * models. | ||
31 | */ | ||
32 | #include <asm/octeon/octeon.h> | ||
33 | |||
34 | /** | ||
35 | * Given the chip processor ID from COP0, this function returns a | ||
36 | * string representing the chip model number. The string is of the | ||
37 | * form CNXXXXpX.X-FREQ-SUFFIX. | ||
38 | * - XXXX = The chip model number | ||
39 | * - X.X = Chip pass number | ||
40 | * - FREQ = Current frequency in Mhz | ||
41 | * - SUFFIX = NSP, EXP, SCP, SSP, or CP | ||
42 | * | ||
43 | * @chip_id: Chip ID | ||
44 | * | ||
45 | * Returns Model string | ||
46 | */ | ||
47 | const char *octeon_model_get_string(uint32_t chip_id) | ||
48 | { | ||
49 | static char buffer[32]; | ||
50 | return octeon_model_get_string_buffer(chip_id, buffer); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Version of octeon_model_get_string() that takes buffer as argument, | ||
55 | * as running early in u-boot static/global variables don't work when | ||
56 | * running from flash. | ||
57 | */ | ||
58 | const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer) | ||
59 | { | ||
60 | const char *family; | ||
61 | const char *core_model; | ||
62 | char pass[4]; | ||
63 | int clock_mhz; | ||
64 | const char *suffix; | ||
65 | union cvmx_l2d_fus3 fus3; | ||
66 | int num_cores; | ||
67 | union cvmx_mio_fus_dat2 fus_dat2; | ||
68 | union cvmx_mio_fus_dat3 fus_dat3; | ||
69 | char fuse_model[10]; | ||
70 | uint32_t fuse_data = 0; | ||
71 | |||
72 | fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); | ||
73 | fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); | ||
74 | fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); | ||
75 | |||
76 | num_cores = cvmx_octeon_num_cores(); | ||
77 | |||
78 | /* Make sure the non existant devices look disabled */ | ||
79 | switch ((chip_id >> 8) & 0xff) { | ||
80 | case 6: /* CN50XX */ | ||
81 | case 2: /* CN30XX */ | ||
82 | fus_dat3.s.nodfa_dte = 1; | ||
83 | fus_dat3.s.nozip = 1; | ||
84 | break; | ||
85 | case 4: /* CN57XX or CN56XX */ | ||
86 | fus_dat3.s.nodfa_dte = 1; | ||
87 | break; | ||
88 | default: | ||
89 | break; | ||
90 | } | ||
91 | |||
92 | /* Make a guess at the suffix */ | ||
93 | /* NSP = everything */ | ||
94 | /* EXP = No crypto */ | ||
95 | /* SCP = No DFA, No zip */ | ||
96 | /* CP = No DFA, No crypto, No zip */ | ||
97 | if (fus_dat3.s.nodfa_dte) { | ||
98 | if (fus_dat2.s.nocrypto) | ||
99 | suffix = "CP"; | ||
100 | else | ||
101 | suffix = "SCP"; | ||
102 | } else if (fus_dat2.s.nocrypto) | ||
103 | suffix = "EXP"; | ||
104 | else | ||
105 | suffix = "NSP"; | ||
106 | |||
107 | /* | ||
108 | * Assume pass number is encoded using <5:3><2:0>. Exceptions | ||
109 | * will be fixed later. | ||
110 | */ | ||
111 | sprintf(pass, "%u.%u", ((chip_id >> 3) & 7) + 1, chip_id & 7); | ||
112 | |||
113 | /* | ||
114 | * Use the number of cores to determine the last 2 digits of | ||
115 | * the model number. There are some exceptions that are fixed | ||
116 | * later. | ||
117 | */ | ||
118 | switch (num_cores) { | ||
119 | case 16: | ||
120 | core_model = "60"; | ||
121 | break; | ||
122 | case 15: | ||
123 | core_model = "58"; | ||
124 | break; | ||
125 | case 14: | ||
126 | core_model = "55"; | ||
127 | break; | ||
128 | case 13: | ||
129 | core_model = "52"; | ||
130 | break; | ||
131 | case 12: | ||
132 | core_model = "50"; | ||
133 | break; | ||
134 | case 11: | ||
135 | core_model = "48"; | ||
136 | break; | ||
137 | case 10: | ||
138 | core_model = "45"; | ||
139 | break; | ||
140 | case 9: | ||
141 | core_model = "42"; | ||
142 | break; | ||
143 | case 8: | ||
144 | core_model = "40"; | ||
145 | break; | ||
146 | case 7: | ||
147 | core_model = "38"; | ||
148 | break; | ||
149 | case 6: | ||
150 | core_model = "34"; | ||
151 | break; | ||
152 | case 5: | ||
153 | core_model = "32"; | ||
154 | break; | ||
155 | case 4: | ||
156 | core_model = "30"; | ||
157 | break; | ||
158 | case 3: | ||
159 | core_model = "25"; | ||
160 | break; | ||
161 | case 2: | ||
162 | core_model = "20"; | ||
163 | break; | ||
164 | case 1: | ||
165 | core_model = "10"; | ||
166 | break; | ||
167 | default: | ||
168 | core_model = "XX"; | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | /* Now figure out the family, the first two digits */ | ||
173 | switch ((chip_id >> 8) & 0xff) { | ||
174 | case 0: /* CN38XX, CN37XX or CN36XX */ | ||
175 | if (fus3.cn38xx.crip_512k) { | ||
176 | /* | ||
177 | * For some unknown reason, the 16 core one is | ||
178 | * called 37 instead of 36. | ||
179 | */ | ||
180 | if (num_cores >= 16) | ||
181 | family = "37"; | ||
182 | else | ||
183 | family = "36"; | ||
184 | } else | ||
185 | family = "38"; | ||
186 | /* | ||
187 | * This series of chips didn't follow the standard | ||
188 | * pass numbering. | ||
189 | */ | ||
190 | switch (chip_id & 0xf) { | ||
191 | case 0: | ||
192 | strcpy(pass, "1.X"); | ||
193 | break; | ||
194 | case 1: | ||
195 | strcpy(pass, "2.X"); | ||
196 | break; | ||
197 | case 3: | ||
198 | strcpy(pass, "3.X"); | ||
199 | break; | ||
200 | default: | ||
201 | strcpy(pass, "X.X"); | ||
202 | break; | ||
203 | } | ||
204 | break; | ||
205 | case 1: /* CN31XX or CN3020 */ | ||
206 | if ((chip_id & 0x10) || fus3.cn31xx.crip_128k) | ||
207 | family = "30"; | ||
208 | else | ||
209 | family = "31"; | ||
210 | /* | ||
211 | * This series of chips didn't follow the standard | ||
212 | * pass numbering. | ||
213 | */ | ||
214 | switch (chip_id & 0xf) { | ||
215 | case 0: | ||
216 | strcpy(pass, "1.0"); | ||
217 | break; | ||
218 | case 2: | ||
219 | strcpy(pass, "1.1"); | ||
220 | break; | ||
221 | default: | ||
222 | strcpy(pass, "X.X"); | ||
223 | break; | ||
224 | } | ||
225 | break; | ||
226 | case 2: /* CN3010 or CN3005 */ | ||
227 | family = "30"; | ||
228 | /* A chip with half cache is an 05 */ | ||
229 | if (fus3.cn30xx.crip_64k) | ||
230 | core_model = "05"; | ||
231 | /* | ||
232 | * This series of chips didn't follow the standard | ||
233 | * pass numbering. | ||
234 | */ | ||
235 | switch (chip_id & 0xf) { | ||
236 | case 0: | ||
237 | strcpy(pass, "1.0"); | ||
238 | break; | ||
239 | case 2: | ||
240 | strcpy(pass, "1.1"); | ||
241 | break; | ||
242 | default: | ||
243 | strcpy(pass, "X.X"); | ||
244 | break; | ||
245 | } | ||
246 | break; | ||
247 | case 3: /* CN58XX */ | ||
248 | family = "58"; | ||
249 | /* Special case. 4 core, no crypto */ | ||
250 | if ((num_cores == 4) && fus_dat2.cn38xx.nocrypto) | ||
251 | core_model = "29"; | ||
252 | |||
253 | /* Pass 1 uses different encodings for pass numbers */ | ||
254 | if ((chip_id & 0xFF) < 0x8) { | ||
255 | switch (chip_id & 0x3) { | ||
256 | case 0: | ||
257 | strcpy(pass, "1.0"); | ||
258 | break; | ||
259 | case 1: | ||
260 | strcpy(pass, "1.1"); | ||
261 | break; | ||
262 | case 3: | ||
263 | strcpy(pass, "1.2"); | ||
264 | break; | ||
265 | default: | ||
266 | strcpy(pass, "1.X"); | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | break; | ||
271 | case 4: /* CN57XX, CN56XX, CN55XX, CN54XX */ | ||
272 | if (fus_dat2.cn56xx.raid_en) { | ||
273 | if (fus3.cn56xx.crip_1024k) | ||
274 | family = "55"; | ||
275 | else | ||
276 | family = "57"; | ||
277 | if (fus_dat2.cn56xx.nocrypto) | ||
278 | suffix = "SP"; | ||
279 | else | ||
280 | suffix = "SSP"; | ||
281 | } else { | ||
282 | if (fus_dat2.cn56xx.nocrypto) | ||
283 | suffix = "CP"; | ||
284 | else { | ||
285 | suffix = "NSP"; | ||
286 | if (fus_dat3.s.nozip) | ||
287 | suffix = "SCP"; | ||
288 | } | ||
289 | if (fus3.cn56xx.crip_1024k) | ||
290 | family = "54"; | ||
291 | else | ||
292 | family = "56"; | ||
293 | } | ||
294 | break; | ||
295 | case 6: /* CN50XX */ | ||
296 | family = "50"; | ||
297 | break; | ||
298 | case 7: /* CN52XX */ | ||
299 | if (fus3.cn52xx.crip_256k) | ||
300 | family = "51"; | ||
301 | else | ||
302 | family = "52"; | ||
303 | break; | ||
304 | default: | ||
305 | family = "XX"; | ||
306 | core_model = "XX"; | ||
307 | strcpy(pass, "X.X"); | ||
308 | suffix = "XXX"; | ||
309 | break; | ||
310 | } | ||
311 | |||
312 | clock_mhz = octeon_get_clock_rate() / 1000000; | ||
313 | |||
314 | if (family[0] != '3') { | ||
315 | /* Check for model in fuses, overrides normal decode */ | ||
316 | /* This is _not_ valid for Octeon CN3XXX models */ | ||
317 | fuse_data |= cvmx_fuse_read_byte(51); | ||
318 | fuse_data = fuse_data << 8; | ||
319 | fuse_data |= cvmx_fuse_read_byte(50); | ||
320 | fuse_data = fuse_data << 8; | ||
321 | fuse_data |= cvmx_fuse_read_byte(49); | ||
322 | fuse_data = fuse_data << 8; | ||
323 | fuse_data |= cvmx_fuse_read_byte(48); | ||
324 | if (fuse_data & 0x7ffff) { | ||
325 | int model = fuse_data & 0x3fff; | ||
326 | int suffix = (fuse_data >> 14) & 0x1f; | ||
327 | if (suffix && model) { | ||
328 | /* | ||
329 | * Have both number and suffix in | ||
330 | * fuses, so both | ||
331 | */ | ||
332 | sprintf(fuse_model, "%d%c", | ||
333 | model, 'A' + suffix - 1); | ||
334 | core_model = ""; | ||
335 | family = fuse_model; | ||
336 | } else if (suffix && !model) { | ||
337 | /* | ||
338 | * Only have suffix, so add suffix to | ||
339 | * 'normal' model number. | ||
340 | */ | ||
341 | sprintf(fuse_model, "%s%c", core_model, | ||
342 | 'A' + suffix - 1); | ||
343 | core_model = fuse_model; | ||
344 | } else { | ||
345 | /* | ||
346 | * Don't have suffix, so just use | ||
347 | * model from fuses. | ||
348 | */ | ||
349 | sprintf(fuse_model, "%d", model); | ||
350 | core_model = ""; | ||
351 | family = fuse_model; | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | sprintf(buffer, "CN%s%sp%s-%d-%s", | ||
356 | family, core_model, pass, clock_mhz, suffix); | ||
357 | return buffer; | ||
358 | } | ||
diff --git a/arch/mips/include/asm/octeon/cvmx-asm.h b/arch/mips/include/asm/octeon/cvmx-asm.h new file mode 100644 index 000000000000..b21d3fc1ef91 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-asm.h | |||
@@ -0,0 +1,128 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * | ||
30 | * This is file defines ASM primitives for the executive. | ||
31 | */ | ||
32 | #ifndef __CVMX_ASM_H__ | ||
33 | #define __CVMX_ASM_H__ | ||
34 | |||
35 | #include "octeon-model.h" | ||
36 | |||
37 | /* other useful stuff */ | ||
38 | #define CVMX_SYNC asm volatile ("sync" : : : "memory") | ||
39 | /* String version of SYNCW macro for using in inline asm constructs */ | ||
40 | #define CVMX_SYNCW_STR "syncw\nsyncw\n" | ||
41 | #ifdef __OCTEON__ | ||
42 | |||
43 | /* Deprecated, will be removed in future release */ | ||
44 | #define CVMX_SYNCIO asm volatile ("nop") | ||
45 | |||
46 | #define CVMX_SYNCIOBDMA asm volatile ("synciobdma" : : : "memory") | ||
47 | |||
48 | /* Deprecated, will be removed in future release */ | ||
49 | #define CVMX_SYNCIOALL asm volatile ("nop") | ||
50 | |||
51 | /* | ||
52 | * We actually use two syncw instructions in a row when we need a write | ||
53 | * memory barrier. This is because the CN3XXX series of Octeons have | ||
54 | * errata Core-401. This can cause a single syncw to not enforce | ||
55 | * ordering under very rare conditions. Even if it is rare, better safe | ||
56 | * than sorry. | ||
57 | */ | ||
58 | #define CVMX_SYNCW asm volatile ("syncw\n\tsyncw" : : : "memory") | ||
59 | |||
60 | /* | ||
61 | * Define new sync instructions to be normal SYNC instructions for | ||
62 | * operating systems that use threads. | ||
63 | */ | ||
64 | #define CVMX_SYNCWS CVMX_SYNCW | ||
65 | #define CVMX_SYNCS CVMX_SYNC | ||
66 | #define CVMX_SYNCWS_STR CVMX_SYNCW_STR | ||
67 | #else | ||
68 | /* | ||
69 | * Not using a Cavium compiler, always use the slower sync so the | ||
70 | * assembler stays happy. | ||
71 | */ | ||
72 | /* Deprecated, will be removed in future release */ | ||
73 | #define CVMX_SYNCIO asm volatile ("nop") | ||
74 | |||
75 | #define CVMX_SYNCIOBDMA asm volatile ("sync" : : : "memory") | ||
76 | |||
77 | /* Deprecated, will be removed in future release */ | ||
78 | #define CVMX_SYNCIOALL asm volatile ("nop") | ||
79 | |||
80 | #define CVMX_SYNCW asm volatile ("sync" : : : "memory") | ||
81 | #define CVMX_SYNCWS CVMX_SYNCW | ||
82 | #define CVMX_SYNCS CVMX_SYNC | ||
83 | #define CVMX_SYNCWS_STR CVMX_SYNCW_STR | ||
84 | #endif | ||
85 | |||
86 | /* | ||
87 | * CVMX_PREPARE_FOR_STORE makes each byte of the block unpredictable | ||
88 | * (actually old value or zero) until that byte is stored to (by this or | ||
89 | * another processor. Note that the value of each byte is not only | ||
90 | * unpredictable, but may also change again - up until the point when one | ||
91 | * of the cores stores to the byte. | ||
92 | */ | ||
93 | #define CVMX_PREPARE_FOR_STORE(address, offset) \ | ||
94 | asm volatile ("pref 30, " CVMX_TMP_STR(offset) "(%[rbase])" : : \ | ||
95 | [rbase] "d" (address)) | ||
96 | /* | ||
97 | * This is a command headed to the L2 controller to tell it to clear | ||
98 | * its dirty bit for a block. Basically, SW is telling HW that the | ||
99 | * current version of the block will not be used. | ||
100 | */ | ||
101 | #define CVMX_DONT_WRITE_BACK(address, offset) \ | ||
102 | asm volatile ("pref 29, " CVMX_TMP_STR(offset) "(%[rbase])" : : \ | ||
103 | [rbase] "d" (address)) | ||
104 | |||
105 | /* flush stores, invalidate entire icache */ | ||
106 | #define CVMX_ICACHE_INVALIDATE \ | ||
107 | { CVMX_SYNC; asm volatile ("synci 0($0)" : : ); } | ||
108 | |||
109 | /* flush stores, invalidate entire icache */ | ||
110 | #define CVMX_ICACHE_INVALIDATE2 \ | ||
111 | { CVMX_SYNC; asm volatile ("cache 0, 0($0)" : : ); } | ||
112 | |||
113 | /* complete prefetches, invalidate entire dcache */ | ||
114 | #define CVMX_DCACHE_INVALIDATE \ | ||
115 | { CVMX_SYNC; asm volatile ("cache 9, 0($0)" : : ); } | ||
116 | |||
117 | |||
118 | #define CVMX_POP(result, input) \ | ||
119 | asm ("pop %[rd],%[rs]" : [rd] "=d" (result) : [rs] "d" (input)) | ||
120 | #define CVMX_DPOP(result, input) \ | ||
121 | asm ("dpop %[rd],%[rs]" : [rd] "=d" (result) : [rs] "d" (input)) | ||
122 | |||
123 | /* some new cop0-like stuff */ | ||
124 | #define CVMX_RDHWR(result, regstr) \ | ||
125 | asm volatile ("rdhwr %[rt],$" CVMX_TMP_STR(regstr) : [rt] "=d" (result)) | ||
126 | #define CVMX_RDHWRNV(result, regstr) \ | ||
127 | asm ("rdhwr %[rt],$" CVMX_TMP_STR(regstr) : [rt] "=d" (result)) | ||
128 | #endif /* __CVMX_ASM_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h new file mode 100644 index 000000000000..692989acd8a9 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h | |||
@@ -0,0 +1,262 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * Header file containing the ABI with the bootloader. | ||
30 | */ | ||
31 | |||
32 | #ifndef __CVMX_BOOTINFO_H__ | ||
33 | #define __CVMX_BOOTINFO_H__ | ||
34 | |||
35 | /* | ||
36 | * Current major and minor versions of the CVMX bootinfo block that is | ||
37 | * passed from the bootloader to the application. This is versioned | ||
38 | * so that applications can properly handle multiple bootloader | ||
39 | * versions. | ||
40 | */ | ||
41 | #define CVMX_BOOTINFO_MAJ_VER 1 | ||
42 | #define CVMX_BOOTINFO_MIN_VER 2 | ||
43 | |||
44 | #if (CVMX_BOOTINFO_MAJ_VER == 1) | ||
45 | #define CVMX_BOOTINFO_OCTEON_SERIAL_LEN 20 | ||
46 | /* | ||
47 | * This structure is populated by the bootloader. For binary | ||
48 | * compatibility the only changes that should be made are | ||
49 | * adding members to the end of the structure, and the minor | ||
50 | * version should be incremented at that time. | ||
51 | * If an incompatible change is made, the major version | ||
52 | * must be incremented, and the minor version should be reset | ||
53 | * to 0. | ||
54 | */ | ||
55 | struct cvmx_bootinfo { | ||
56 | uint32_t major_version; | ||
57 | uint32_t minor_version; | ||
58 | |||
59 | uint64_t stack_top; | ||
60 | uint64_t heap_base; | ||
61 | uint64_t heap_end; | ||
62 | uint64_t desc_vaddr; | ||
63 | |||
64 | uint32_t exception_base_addr; | ||
65 | uint32_t stack_size; | ||
66 | uint32_t flags; | ||
67 | uint32_t core_mask; | ||
68 | /* DRAM size in megabytes */ | ||
69 | uint32_t dram_size; | ||
70 | /* physical address of free memory descriptor block*/ | ||
71 | uint32_t phy_mem_desc_addr; | ||
72 | /* used to pass flags from app to debugger */ | ||
73 | uint32_t debugger_flags_base_addr; | ||
74 | |||
75 | /* CPU clock speed, in hz */ | ||
76 | uint32_t eclock_hz; | ||
77 | |||
78 | /* DRAM clock speed, in hz */ | ||
79 | uint32_t dclock_hz; | ||
80 | |||
81 | uint32_t reserved0; | ||
82 | uint16_t board_type; | ||
83 | uint8_t board_rev_major; | ||
84 | uint8_t board_rev_minor; | ||
85 | uint16_t reserved1; | ||
86 | uint8_t reserved2; | ||
87 | uint8_t reserved3; | ||
88 | char board_serial_number[CVMX_BOOTINFO_OCTEON_SERIAL_LEN]; | ||
89 | uint8_t mac_addr_base[6]; | ||
90 | uint8_t mac_addr_count; | ||
91 | #if (CVMX_BOOTINFO_MIN_VER >= 1) | ||
92 | /* | ||
93 | * Several boards support compact flash on the Octeon boot | ||
94 | * bus. The CF memory spaces may be mapped to different | ||
95 | * addresses on different boards. These are the physical | ||
96 | * addresses, so care must be taken to use the correct | ||
97 | * XKPHYS/KSEG0 addressing depending on the application's | ||
98 | * ABI. These values will be 0 if CF is not present. | ||
99 | */ | ||
100 | uint64_t compact_flash_common_base_addr; | ||
101 | uint64_t compact_flash_attribute_base_addr; | ||
102 | /* | ||
103 | * Base address of the LED display (as on EBT3000 board) | ||
104 | * This will be 0 if LED display not present. | ||
105 | */ | ||
106 | uint64_t led_display_base_addr; | ||
107 | #endif | ||
108 | #if (CVMX_BOOTINFO_MIN_VER >= 2) | ||
109 | /* DFA reference clock in hz (if applicable)*/ | ||
110 | uint32_t dfa_ref_clock_hz; | ||
111 | |||
112 | /* | ||
113 | * flags indicating various configuration options. These | ||
114 | * flags supercede the 'flags' variable and should be used | ||
115 | * instead if available. | ||
116 | */ | ||
117 | uint32_t config_flags; | ||
118 | #endif | ||
119 | |||
120 | }; | ||
121 | |||
122 | #define CVMX_BOOTINFO_CFG_FLAG_PCI_HOST (1ull << 0) | ||
123 | #define CVMX_BOOTINFO_CFG_FLAG_PCI_TARGET (1ull << 1) | ||
124 | #define CVMX_BOOTINFO_CFG_FLAG_DEBUG (1ull << 2) | ||
125 | #define CVMX_BOOTINFO_CFG_FLAG_NO_MAGIC (1ull << 3) | ||
126 | /* This flag is set if the TLB mappings are not contained in the | ||
127 | * 0x10000000 - 0x20000000 boot bus region. */ | ||
128 | #define CVMX_BOOTINFO_CFG_FLAG_OVERSIZE_TLB_MAPPING (1ull << 4) | ||
129 | #define CVMX_BOOTINFO_CFG_FLAG_BREAK (1ull << 5) | ||
130 | |||
131 | #endif /* (CVMX_BOOTINFO_MAJ_VER == 1) */ | ||
132 | |||
133 | /* Type defines for board and chip types */ | ||
134 | enum cvmx_board_types_enum { | ||
135 | CVMX_BOARD_TYPE_NULL = 0, | ||
136 | CVMX_BOARD_TYPE_SIM = 1, | ||
137 | CVMX_BOARD_TYPE_EBT3000 = 2, | ||
138 | CVMX_BOARD_TYPE_KODAMA = 3, | ||
139 | CVMX_BOARD_TYPE_NIAGARA = 4, | ||
140 | CVMX_BOARD_TYPE_NAC38 = 5, /* formerly NAO38 */ | ||
141 | CVMX_BOARD_TYPE_THUNDER = 6, | ||
142 | CVMX_BOARD_TYPE_TRANTOR = 7, | ||
143 | CVMX_BOARD_TYPE_EBH3000 = 8, | ||
144 | CVMX_BOARD_TYPE_EBH3100 = 9, | ||
145 | CVMX_BOARD_TYPE_HIKARI = 10, | ||
146 | CVMX_BOARD_TYPE_CN3010_EVB_HS5 = 11, | ||
147 | CVMX_BOARD_TYPE_CN3005_EVB_HS5 = 12, | ||
148 | CVMX_BOARD_TYPE_KBP = 13, | ||
149 | /* Deprecated, CVMX_BOARD_TYPE_CN3010_EVB_HS5 supports the CN3020 */ | ||
150 | CVMX_BOARD_TYPE_CN3020_EVB_HS5 = 14, | ||
151 | CVMX_BOARD_TYPE_EBT5800 = 15, | ||
152 | CVMX_BOARD_TYPE_NICPRO2 = 16, | ||
153 | CVMX_BOARD_TYPE_EBH5600 = 17, | ||
154 | CVMX_BOARD_TYPE_EBH5601 = 18, | ||
155 | CVMX_BOARD_TYPE_EBH5200 = 19, | ||
156 | CVMX_BOARD_TYPE_BBGW_REF = 20, | ||
157 | CVMX_BOARD_TYPE_NIC_XLE_4G = 21, | ||
158 | CVMX_BOARD_TYPE_EBT5600 = 22, | ||
159 | CVMX_BOARD_TYPE_EBH5201 = 23, | ||
160 | CVMX_BOARD_TYPE_MAX, | ||
161 | |||
162 | /* | ||
163 | * The range from CVMX_BOARD_TYPE_MAX to | ||
164 | * CVMX_BOARD_TYPE_CUST_DEFINED_MIN is reserved for future | ||
165 | * SDK use. | ||
166 | */ | ||
167 | |||
168 | /* | ||
169 | * Set aside a range for customer boards. These numbers are managed | ||
170 | * by Cavium. | ||
171 | */ | ||
172 | CVMX_BOARD_TYPE_CUST_DEFINED_MIN = 10000, | ||
173 | CVMX_BOARD_TYPE_CUST_WSX16 = 10001, | ||
174 | CVMX_BOARD_TYPE_CUST_NS0216 = 10002, | ||
175 | CVMX_BOARD_TYPE_CUST_NB5 = 10003, | ||
176 | CVMX_BOARD_TYPE_CUST_WMR500 = 10004, | ||
177 | CVMX_BOARD_TYPE_CUST_DEFINED_MAX = 20000, | ||
178 | |||
179 | /* | ||
180 | * Set aside a range for customer private use. The SDK won't | ||
181 | * use any numbers in this range. | ||
182 | */ | ||
183 | CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, | ||
184 | CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, | ||
185 | |||
186 | /* The remaining range is reserved for future use. */ | ||
187 | }; | ||
188 | |||
189 | enum cvmx_chip_types_enum { | ||
190 | CVMX_CHIP_TYPE_NULL = 0, | ||
191 | CVMX_CHIP_SIM_TYPE_DEPRECATED = 1, | ||
192 | CVMX_CHIP_TYPE_OCTEON_SAMPLE = 2, | ||
193 | CVMX_CHIP_TYPE_MAX, | ||
194 | }; | ||
195 | |||
196 | /* Compatability alias for NAC38 name change, planned to be removed | ||
197 | * from SDK 1.7 */ | ||
198 | #define CVMX_BOARD_TYPE_NAO38 CVMX_BOARD_TYPE_NAC38 | ||
199 | |||
200 | /* Functions to return string based on type */ | ||
201 | #define ENUM_BRD_TYPE_CASE(x) \ | ||
202 | case x: return(#x + 16); /* Skip CVMX_BOARD_TYPE_ */ | ||
203 | static inline const char *cvmx_board_type_to_string(enum | ||
204 | cvmx_board_types_enum type) | ||
205 | { | ||
206 | switch (type) { | ||
207 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NULL) | ||
208 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_SIM) | ||
209 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT3000) | ||
210 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KODAMA) | ||
211 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIAGARA) | ||
212 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NAC38) | ||
213 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_THUNDER) | ||
214 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_TRANTOR) | ||
215 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH3000) | ||
216 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH3100) | ||
217 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_HIKARI) | ||
218 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3010_EVB_HS5) | ||
219 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3005_EVB_HS5) | ||
220 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KBP) | ||
221 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3020_EVB_HS5) | ||
222 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5800) | ||
223 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NICPRO2) | ||
224 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5600) | ||
225 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5601) | ||
226 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5200) | ||
227 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_BBGW_REF) | ||
228 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_4G) | ||
229 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5600) | ||
230 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5201) | ||
231 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX) | ||
232 | |||
233 | /* Customer boards listed here */ | ||
234 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MIN) | ||
235 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WSX16) | ||
236 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NS0216) | ||
237 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NB5) | ||
238 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WMR500) | ||
239 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MAX) | ||
240 | |||
241 | /* Customer private range */ | ||
242 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN) | ||
243 | ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX) | ||
244 | } | ||
245 | return "Unsupported Board"; | ||
246 | } | ||
247 | |||
248 | #define ENUM_CHIP_TYPE_CASE(x) \ | ||
249 | case x: return(#x + 15); /* Skip CVMX_CHIP_TYPE */ | ||
250 | static inline const char *cvmx_chip_type_to_string(enum | ||
251 | cvmx_chip_types_enum type) | ||
252 | { | ||
253 | switch (type) { | ||
254 | ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_NULL) | ||
255 | ENUM_CHIP_TYPE_CASE(CVMX_CHIP_SIM_TYPE_DEPRECATED) | ||
256 | ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_OCTEON_SAMPLE) | ||
257 | ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_MAX) | ||
258 | } | ||
259 | return "Unsupported Chip"; | ||
260 | } | ||
261 | |||
262 | #endif /* __CVMX_BOOTINFO_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/cvmx-bootmem.h b/arch/mips/include/asm/octeon/cvmx-bootmem.h new file mode 100644 index 000000000000..1cbe4b55889d --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-bootmem.h | |||
@@ -0,0 +1,288 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * Simple allocate only memory allocator. Used to allocate memory at | ||
30 | * application start time. | ||
31 | */ | ||
32 | |||
33 | #ifndef __CVMX_BOOTMEM_H__ | ||
34 | #define __CVMX_BOOTMEM_H__ | ||
35 | /* Must be multiple of 8, changing breaks ABI */ | ||
36 | #define CVMX_BOOTMEM_NAME_LEN 128 | ||
37 | |||
38 | /* Can change without breaking ABI */ | ||
39 | #define CVMX_BOOTMEM_NUM_NAMED_BLOCKS 64 | ||
40 | |||
41 | /* minimum alignment of bootmem alloced blocks */ | ||
42 | #define CVMX_BOOTMEM_ALIGNMENT_SIZE (16ull) | ||
43 | |||
44 | /* Flags for cvmx_bootmem_phy_mem* functions */ | ||
45 | /* Allocate from end of block instead of beginning */ | ||
46 | #define CVMX_BOOTMEM_FLAG_END_ALLOC (1 << 0) | ||
47 | |||
48 | /* Don't do any locking. */ | ||
49 | #define CVMX_BOOTMEM_FLAG_NO_LOCKING (1 << 1) | ||
50 | |||
51 | /* First bytes of each free physical block of memory contain this structure, | ||
52 | * which is used to maintain the free memory list. Since the bootloader is | ||
53 | * only 32 bits, there is a union providing 64 and 32 bit versions. The | ||
54 | * application init code converts addresses to 64 bit addresses before the | ||
55 | * application starts. | ||
56 | */ | ||
57 | struct cvmx_bootmem_block_header { | ||
58 | /* | ||
59 | * Note: these are referenced from assembly routines in the | ||
60 | * bootloader, so this structure should not be changed | ||
61 | * without changing those routines as well. | ||
62 | */ | ||
63 | uint64_t next_block_addr; | ||
64 | uint64_t size; | ||
65 | |||
66 | }; | ||
67 | |||
68 | /* | ||
69 | * Structure for named memory blocks. Number of descriptors available | ||
70 | * can be changed without affecting compatiblity, but name length | ||
71 | * changes require a bump in the bootmem descriptor version Note: This | ||
72 | * structure must be naturally 64 bit aligned, as a single memory | ||
73 | * image will be used by both 32 and 64 bit programs. | ||
74 | */ | ||
75 | struct cvmx_bootmem_named_block_desc { | ||
76 | /* Base address of named block */ | ||
77 | uint64_t base_addr; | ||
78 | /* | ||
79 | * Size actually allocated for named block (may differ from | ||
80 | * requested). | ||
81 | */ | ||
82 | uint64_t size; | ||
83 | /* name of named block */ | ||
84 | char name[CVMX_BOOTMEM_NAME_LEN]; | ||
85 | }; | ||
86 | |||
87 | /* Current descriptor versions */ | ||
88 | /* CVMX bootmem descriptor major version */ | ||
89 | #define CVMX_BOOTMEM_DESC_MAJ_VER 3 | ||
90 | |||
91 | /* CVMX bootmem descriptor minor version */ | ||
92 | #define CVMX_BOOTMEM_DESC_MIN_VER 0 | ||
93 | |||
94 | /* First three members of cvmx_bootmem_desc_t are left in original | ||
95 | * positions for backwards compatibility. | ||
96 | */ | ||
97 | struct cvmx_bootmem_desc { | ||
98 | /* spinlock to control access to list */ | ||
99 | uint32_t lock; | ||
100 | /* flags for indicating various conditions */ | ||
101 | uint32_t flags; | ||
102 | uint64_t head_addr; | ||
103 | |||
104 | /* Incremented when incompatible changes made */ | ||
105 | uint32_t major_version; | ||
106 | |||
107 | /* | ||
108 | * Incremented changed when compatible changes made, reset to | ||
109 | * zero when major incremented. | ||
110 | */ | ||
111 | uint32_t minor_version; | ||
112 | |||
113 | uint64_t app_data_addr; | ||
114 | uint64_t app_data_size; | ||
115 | |||
116 | /* number of elements in named blocks array */ | ||
117 | uint32_t named_block_num_blocks; | ||
118 | |||
119 | /* length of name array in bootmem blocks */ | ||
120 | uint32_t named_block_name_len; | ||
121 | /* address of named memory block descriptors */ | ||
122 | uint64_t named_block_array_addr; | ||
123 | |||
124 | }; | ||
125 | |||
126 | /** | ||
127 | * Initialize the boot alloc memory structures. This is | ||
128 | * normally called inside of cvmx_user_app_init() | ||
129 | * | ||
130 | * @mem_desc_ptr: Address of the free memory list | ||
131 | */ | ||
132 | extern int cvmx_bootmem_init(void *mem_desc_ptr); | ||
133 | |||
134 | /** | ||
135 | * Allocate a block of memory from the free list that was passed | ||
136 | * to the application by the bootloader. | ||
137 | * This is an allocate-only algorithm, so freeing memory is not possible. | ||
138 | * | ||
139 | * @size: Size in bytes of block to allocate | ||
140 | * @alignment: Alignment required - must be power of 2 | ||
141 | * | ||
142 | * Returns pointer to block of memory, NULL on error | ||
143 | */ | ||
144 | extern void *cvmx_bootmem_alloc(uint64_t size, uint64_t alignment); | ||
145 | |||
146 | /** | ||
147 | * Allocate a block of memory from the free list that was | ||
148 | * passed to the application by the bootloader at a specific | ||
149 | * address. This is an allocate-only algorithm, so | ||
150 | * freeing memory is not possible. Allocation will fail if | ||
151 | * memory cannot be allocated at the specified address. | ||
152 | * | ||
153 | * @size: Size in bytes of block to allocate | ||
154 | * @address: Physical address to allocate memory at. If this memory is not | ||
155 | * available, the allocation fails. | ||
156 | * @alignment: Alignment required - must be power of 2 | ||
157 | * Returns pointer to block of memory, NULL on error | ||
158 | */ | ||
159 | extern void *cvmx_bootmem_alloc_address(uint64_t size, uint64_t address, | ||
160 | uint64_t alignment); | ||
161 | |||
162 | /** | ||
163 | * Allocate a block of memory from the free list that was | ||
164 | * passed to the application by the bootloader within a specified | ||
165 | * address range. This is an allocate-only algorithm, so | ||
166 | * freeing memory is not possible. Allocation will fail if | ||
167 | * memory cannot be allocated in the requested range. | ||
168 | * | ||
169 | * @size: Size in bytes of block to allocate | ||
170 | * @min_addr: defines the minimum address of the range | ||
171 | * @max_addr: defines the maximum address of the range | ||
172 | * @alignment: Alignment required - must be power of 2 | ||
173 | * Returns pointer to block of memory, NULL on error | ||
174 | */ | ||
175 | extern void *cvmx_bootmem_alloc_range(uint64_t size, uint64_t alignment, | ||
176 | uint64_t min_addr, uint64_t max_addr); | ||
177 | |||
178 | /** | ||
179 | * Frees a previously allocated named bootmem block. | ||
180 | * | ||
181 | * @name: name of block to free | ||
182 | * | ||
183 | * Returns 0 on failure, | ||
184 | * !0 on success | ||
185 | */ | ||
186 | extern int cvmx_bootmem_free_named(char *name); | ||
187 | |||
188 | /** | ||
189 | * Finds a named bootmem block by name. | ||
190 | * | ||
191 | * @name: name of block to free | ||
192 | * | ||
193 | * Returns pointer to named block descriptor on success | ||
194 | * 0 on failure | ||
195 | */ | ||
196 | struct cvmx_bootmem_named_block_desc *cvmx_bootmem_find_named_block(char *name); | ||
197 | |||
198 | /** | ||
199 | * Allocates a block of physical memory from the free list, at | ||
200 | * (optional) requested address and alignment. | ||
201 | * | ||
202 | * @req_size: size of region to allocate. All requests are rounded up | ||
203 | * to be a multiple CVMX_BOOTMEM_ALIGNMENT_SIZE bytes size | ||
204 | * | ||
205 | * @address_min: Minimum address that block can occupy. | ||
206 | * | ||
207 | * @address_max: Specifies the maximum address_min (inclusive) that | ||
208 | * the allocation can use. | ||
209 | * | ||
210 | * @alignment: Requested alignment of the block. If this alignment | ||
211 | * cannot be met, the allocation fails. This must be a | ||
212 | * power of 2. (Note: Alignment of | ||
213 | * CVMX_BOOTMEM_ALIGNMENT_SIZE bytes is required, and | ||
214 | * internally enforced. Requested alignments of less than | ||
215 | * CVMX_BOOTMEM_ALIGNMENT_SIZE are set to | ||
216 | * CVMX_BOOTMEM_ALIGNMENT_SIZE.) | ||
217 | * | ||
218 | * @flags: Flags to control options for the allocation. | ||
219 | * | ||
220 | * Returns physical address of block allocated, or -1 on failure | ||
221 | */ | ||
222 | int64_t cvmx_bootmem_phy_alloc(uint64_t req_size, uint64_t address_min, | ||
223 | uint64_t address_max, uint64_t alignment, | ||
224 | uint32_t flags); | ||
225 | |||
226 | /** | ||
227 | * Finds a named memory block by name. | ||
228 | * Also used for finding an unused entry in the named block table. | ||
229 | * | ||
230 | * @name: Name of memory block to find. If NULL pointer given, then | ||
231 | * finds unused descriptor, if available. | ||
232 | * | ||
233 | * @flags: Flags to control options for the allocation. | ||
234 | * | ||
235 | * Returns Pointer to memory block descriptor, NULL if not found. | ||
236 | * If NULL returned when name parameter is NULL, then no memory | ||
237 | * block descriptors are available. | ||
238 | */ | ||
239 | struct cvmx_bootmem_named_block_desc * | ||
240 | cvmx_bootmem_phy_named_block_find(char *name, uint32_t flags); | ||
241 | |||
242 | /** | ||
243 | * Frees a named block. | ||
244 | * | ||
245 | * @name: name of block to free | ||
246 | * @flags: flags for passing options | ||
247 | * | ||
248 | * Returns 0 on failure | ||
249 | * 1 on success | ||
250 | */ | ||
251 | int cvmx_bootmem_phy_named_block_free(char *name, uint32_t flags); | ||
252 | |||
253 | /** | ||
254 | * Frees a block to the bootmem allocator list. This must | ||
255 | * be used with care, as the size provided must match the size | ||
256 | * of the block that was allocated, or the list will become | ||
257 | * corrupted. | ||
258 | * | ||
259 | * IMPORTANT: This is only intended to be used as part of named block | ||
260 | * frees and initial population of the free memory list. | ||
261 | * * | ||
262 | * | ||
263 | * @phy_addr: physical address of block | ||
264 | * @size: size of block in bytes. | ||
265 | * @flags: flags for passing options | ||
266 | * | ||
267 | * Returns 1 on success, | ||
268 | * 0 on failure | ||
269 | */ | ||
270 | int __cvmx_bootmem_phy_free(uint64_t phy_addr, uint64_t size, uint32_t flags); | ||
271 | |||
272 | /** | ||
273 | * Locks the bootmem allocator. This is useful in certain situations | ||
274 | * where multiple allocations must be made without being interrupted. | ||
275 | * This should be used with the CVMX_BOOTMEM_FLAG_NO_LOCKING flag. | ||
276 | * | ||
277 | */ | ||
278 | void cvmx_bootmem_lock(void); | ||
279 | |||
280 | /** | ||
281 | * Unlocks the bootmem allocator. This is useful in certain situations | ||
282 | * where multiple allocations must be made without being interrupted. | ||
283 | * This should be used with the CVMX_BOOTMEM_FLAG_NO_LOCKING flag. | ||
284 | * | ||
285 | */ | ||
286 | void cvmx_bootmem_unlock(void); | ||
287 | |||
288 | #endif /* __CVMX_BOOTMEM_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/cvmx-l2c.h b/arch/mips/include/asm/octeon/cvmx-l2c.h new file mode 100644 index 000000000000..2a8c0902ea50 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-l2c.h | |||
@@ -0,0 +1,325 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * | ||
30 | * Interface to the Level 2 Cache (L2C) control, measurement, and debugging | ||
31 | * facilities. | ||
32 | */ | ||
33 | |||
34 | #ifndef __CVMX_L2C_H__ | ||
35 | #define __CVMX_L2C_H__ | ||
36 | |||
37 | /* Deprecated macro, use function */ | ||
38 | #define CVMX_L2_ASSOC cvmx_l2c_get_num_assoc() | ||
39 | |||
40 | /* Deprecated macro, use function */ | ||
41 | #define CVMX_L2_SET_BITS cvmx_l2c_get_set_bits() | ||
42 | |||
43 | /* Deprecated macro, use function */ | ||
44 | #define CVMX_L2_SETS cvmx_l2c_get_num_sets() | ||
45 | |||
46 | #define CVMX_L2C_IDX_ADDR_SHIFT 7 /* based on 128 byte cache line size */ | ||
47 | #define CVMX_L2C_IDX_MASK (cvmx_l2c_get_num_sets() - 1) | ||
48 | |||
49 | /* Defines for index aliasing computations */ | ||
50 | #define CVMX_L2C_TAG_ADDR_ALIAS_SHIFT \ | ||
51 | (CVMX_L2C_IDX_ADDR_SHIFT + cvmx_l2c_get_set_bits()) | ||
52 | |||
53 | #define CVMX_L2C_ALIAS_MASK \ | ||
54 | (CVMX_L2C_IDX_MASK << CVMX_L2C_TAG_ADDR_ALIAS_SHIFT) | ||
55 | |||
56 | union cvmx_l2c_tag { | ||
57 | uint64_t u64; | ||
58 | struct { | ||
59 | uint64_t reserved:28; | ||
60 | uint64_t V:1; /* Line valid */ | ||
61 | uint64_t D:1; /* Line dirty */ | ||
62 | uint64_t L:1; /* Line locked */ | ||
63 | uint64_t U:1; /* Use, LRU eviction */ | ||
64 | uint64_t addr:32; /* Phys mem (not all bits valid) */ | ||
65 | } s; | ||
66 | }; | ||
67 | |||
68 | /* L2C Performance Counter events. */ | ||
69 | enum cvmx_l2c_event { | ||
70 | CVMX_L2C_EVENT_CYCLES = 0, | ||
71 | CVMX_L2C_EVENT_INSTRUCTION_MISS = 1, | ||
72 | CVMX_L2C_EVENT_INSTRUCTION_HIT = 2, | ||
73 | CVMX_L2C_EVENT_DATA_MISS = 3, | ||
74 | CVMX_L2C_EVENT_DATA_HIT = 4, | ||
75 | CVMX_L2C_EVENT_MISS = 5, | ||
76 | CVMX_L2C_EVENT_HIT = 6, | ||
77 | CVMX_L2C_EVENT_VICTIM_HIT = 7, | ||
78 | CVMX_L2C_EVENT_INDEX_CONFLICT = 8, | ||
79 | CVMX_L2C_EVENT_TAG_PROBE = 9, | ||
80 | CVMX_L2C_EVENT_TAG_UPDATE = 10, | ||
81 | CVMX_L2C_EVENT_TAG_COMPLETE = 11, | ||
82 | CVMX_L2C_EVENT_TAG_DIRTY = 12, | ||
83 | CVMX_L2C_EVENT_DATA_STORE_NOP = 13, | ||
84 | CVMX_L2C_EVENT_DATA_STORE_READ = 14, | ||
85 | CVMX_L2C_EVENT_DATA_STORE_WRITE = 15, | ||
86 | CVMX_L2C_EVENT_FILL_DATA_VALID = 16, | ||
87 | CVMX_L2C_EVENT_WRITE_REQUEST = 17, | ||
88 | CVMX_L2C_EVENT_READ_REQUEST = 18, | ||
89 | CVMX_L2C_EVENT_WRITE_DATA_VALID = 19, | ||
90 | CVMX_L2C_EVENT_XMC_NOP = 20, | ||
91 | CVMX_L2C_EVENT_XMC_LDT = 21, | ||
92 | CVMX_L2C_EVENT_XMC_LDI = 22, | ||
93 | CVMX_L2C_EVENT_XMC_LDD = 23, | ||
94 | CVMX_L2C_EVENT_XMC_STF = 24, | ||
95 | CVMX_L2C_EVENT_XMC_STT = 25, | ||
96 | CVMX_L2C_EVENT_XMC_STP = 26, | ||
97 | CVMX_L2C_EVENT_XMC_STC = 27, | ||
98 | CVMX_L2C_EVENT_XMC_DWB = 28, | ||
99 | CVMX_L2C_EVENT_XMC_PL2 = 29, | ||
100 | CVMX_L2C_EVENT_XMC_PSL1 = 30, | ||
101 | CVMX_L2C_EVENT_XMC_IOBLD = 31, | ||
102 | CVMX_L2C_EVENT_XMC_IOBST = 32, | ||
103 | CVMX_L2C_EVENT_XMC_IOBDMA = 33, | ||
104 | CVMX_L2C_EVENT_XMC_IOBRSP = 34, | ||
105 | CVMX_L2C_EVENT_XMC_BUS_VALID = 35, | ||
106 | CVMX_L2C_EVENT_XMC_MEM_DATA = 36, | ||
107 | CVMX_L2C_EVENT_XMC_REFL_DATA = 37, | ||
108 | CVMX_L2C_EVENT_XMC_IOBRSP_DATA = 38, | ||
109 | CVMX_L2C_EVENT_RSC_NOP = 39, | ||
110 | CVMX_L2C_EVENT_RSC_STDN = 40, | ||
111 | CVMX_L2C_EVENT_RSC_FILL = 41, | ||
112 | CVMX_L2C_EVENT_RSC_REFL = 42, | ||
113 | CVMX_L2C_EVENT_RSC_STIN = 43, | ||
114 | CVMX_L2C_EVENT_RSC_SCIN = 44, | ||
115 | CVMX_L2C_EVENT_RSC_SCFL = 45, | ||
116 | CVMX_L2C_EVENT_RSC_SCDN = 46, | ||
117 | CVMX_L2C_EVENT_RSC_DATA_VALID = 47, | ||
118 | CVMX_L2C_EVENT_RSC_VALID_FILL = 48, | ||
119 | CVMX_L2C_EVENT_RSC_VALID_STRSP = 49, | ||
120 | CVMX_L2C_EVENT_RSC_VALID_REFL = 50, | ||
121 | CVMX_L2C_EVENT_LRF_REQ = 51, | ||
122 | CVMX_L2C_EVENT_DT_RD_ALLOC = 52, | ||
123 | CVMX_L2C_EVENT_DT_WR_INVAL = 53 | ||
124 | }; | ||
125 | |||
126 | /** | ||
127 | * Configure one of the four L2 Cache performance counters to capture event | ||
128 | * occurences. | ||
129 | * | ||
130 | * @counter: The counter to configure. Range 0..3. | ||
131 | * @event: The type of L2 Cache event occurrence to count. | ||
132 | * @clear_on_read: When asserted, any read of the performance counter | ||
133 | * clears the counter. | ||
134 | * | ||
135 | * The routine does not clear the counter. | ||
136 | */ | ||
137 | void cvmx_l2c_config_perf(uint32_t counter, | ||
138 | enum cvmx_l2c_event event, uint32_t clear_on_read); | ||
139 | /** | ||
140 | * Read the given L2 Cache performance counter. The counter must be configured | ||
141 | * before reading, but this routine does not enforce this requirement. | ||
142 | * | ||
143 | * @counter: The counter to configure. Range 0..3. | ||
144 | * | ||
145 | * Returns The current counter value. | ||
146 | */ | ||
147 | uint64_t cvmx_l2c_read_perf(uint32_t counter); | ||
148 | |||
149 | /** | ||
150 | * Return the L2 Cache way partitioning for a given core. | ||
151 | * | ||
152 | * @core: The core processor of interest. | ||
153 | * | ||
154 | * Returns The mask specifying the partitioning. 0 bits in mask indicates | ||
155 | * the cache 'ways' that a core can evict from. | ||
156 | * -1 on error | ||
157 | */ | ||
158 | int cvmx_l2c_get_core_way_partition(uint32_t core); | ||
159 | |||
160 | /** | ||
161 | * Partitions the L2 cache for a core | ||
162 | * | ||
163 | * @core: The core that the partitioning applies to. | ||
164 | * | ||
165 | * @mask: The partitioning of the ways expressed as a binary mask. A 0 | ||
166 | * bit allows the core to evict cache lines from a way, while a | ||
167 | * 1 bit blocks the core from evicting any lines from that | ||
168 | * way. There must be at least one allowed way (0 bit) in the | ||
169 | * mask. | ||
170 | * | ||
171 | * If any ways are blocked for all cores and the HW blocks, then those | ||
172 | * ways will never have any cache lines evicted from them. All cores | ||
173 | * and the hardware blocks are free to read from all ways regardless | ||
174 | * of the partitioning. | ||
175 | */ | ||
176 | int cvmx_l2c_set_core_way_partition(uint32_t core, uint32_t mask); | ||
177 | |||
178 | /** | ||
179 | * Return the L2 Cache way partitioning for the hw blocks. | ||
180 | * | ||
181 | * Returns The mask specifying the reserved way. 0 bits in mask indicates | ||
182 | * the cache 'ways' that a core can evict from. | ||
183 | * -1 on error | ||
184 | */ | ||
185 | int cvmx_l2c_get_hw_way_partition(void); | ||
186 | |||
187 | /** | ||
188 | * Partitions the L2 cache for the hardware blocks. | ||
189 | * | ||
190 | * @mask: The partitioning of the ways expressed as a binary mask. A 0 | ||
191 | * bit allows the core to evict cache lines from a way, while a | ||
192 | * 1 bit blocks the core from evicting any lines from that | ||
193 | * way. There must be at least one allowed way (0 bit) in the | ||
194 | * mask. | ||
195 | * | ||
196 | * If any ways are blocked for all cores and the HW blocks, then those | ||
197 | * ways will never have any cache lines evicted from them. All cores | ||
198 | * and the hardware blocks are free to read from all ways regardless | ||
199 | * of the partitioning. | ||
200 | */ | ||
201 | int cvmx_l2c_set_hw_way_partition(uint32_t mask); | ||
202 | |||
203 | /** | ||
204 | * Locks a line in the L2 cache at the specified physical address | ||
205 | * | ||
206 | * @addr: physical address of line to lock | ||
207 | * | ||
208 | * Returns 0 on success, | ||
209 | * 1 if line not locked. | ||
210 | */ | ||
211 | int cvmx_l2c_lock_line(uint64_t addr); | ||
212 | |||
213 | /** | ||
214 | * Locks a specified memory region in the L2 cache. | ||
215 | * | ||
216 | * Note that if not all lines can be locked, that means that all | ||
217 | * but one of the ways (associations) available to the locking | ||
218 | * core are locked. Having only 1 association available for | ||
219 | * normal caching may have a significant adverse affect on performance. | ||
220 | * Care should be taken to ensure that enough of the L2 cache is left | ||
221 | * unlocked to allow for normal caching of DRAM. | ||
222 | * | ||
223 | * @start: Physical address of the start of the region to lock | ||
224 | * @len: Length (in bytes) of region to lock | ||
225 | * | ||
226 | * Returns Number of requested lines that where not locked. | ||
227 | * 0 on success (all locked) | ||
228 | */ | ||
229 | int cvmx_l2c_lock_mem_region(uint64_t start, uint64_t len); | ||
230 | |||
231 | /** | ||
232 | * Unlock and flush a cache line from the L2 cache. | ||
233 | * IMPORTANT: Must only be run by one core at a time due to use | ||
234 | * of L2C debug features. | ||
235 | * Note that this function will flush a matching but unlocked cache line. | ||
236 | * (If address is not in L2, no lines are flushed.) | ||
237 | * | ||
238 | * @address: Physical address to unlock | ||
239 | * | ||
240 | * Returns 0: line not unlocked | ||
241 | * 1: line unlocked | ||
242 | */ | ||
243 | int cvmx_l2c_unlock_line(uint64_t address); | ||
244 | |||
245 | /** | ||
246 | * Unlocks a region of memory that is locked in the L2 cache | ||
247 | * | ||
248 | * @start: start physical address | ||
249 | * @len: length (in bytes) to unlock | ||
250 | * | ||
251 | * Returns Number of locked lines that the call unlocked | ||
252 | */ | ||
253 | int cvmx_l2c_unlock_mem_region(uint64_t start, uint64_t len); | ||
254 | |||
255 | /** | ||
256 | * Read the L2 controller tag for a given location in L2 | ||
257 | * | ||
258 | * @association: | ||
259 | * Which association to read line from | ||
260 | * @index: Which way to read from. | ||
261 | * | ||
262 | * Returns l2c tag structure for line requested. | ||
263 | */ | ||
264 | union cvmx_l2c_tag cvmx_l2c_get_tag(uint32_t association, uint32_t index); | ||
265 | |||
266 | /* Wrapper around deprecated old function name */ | ||
267 | static inline union cvmx_l2c_tag cvmx_get_l2c_tag(uint32_t association, | ||
268 | uint32_t index) | ||
269 | { | ||
270 | return cvmx_l2c_get_tag(association, index); | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * Returns the cache index for a given physical address | ||
275 | * | ||
276 | * @addr: physical address | ||
277 | * | ||
278 | * Returns L2 cache index | ||
279 | */ | ||
280 | uint32_t cvmx_l2c_address_to_index(uint64_t addr); | ||
281 | |||
282 | /** | ||
283 | * Flushes (and unlocks) the entire L2 cache. | ||
284 | * IMPORTANT: Must only be run by one core at a time due to use | ||
285 | * of L2C debug features. | ||
286 | */ | ||
287 | void cvmx_l2c_flush(void); | ||
288 | |||
289 | /** | ||
290 | * | ||
291 | * Returns Returns the size of the L2 cache in bytes, | ||
292 | * -1 on error (unrecognized model) | ||
293 | */ | ||
294 | int cvmx_l2c_get_cache_size_bytes(void); | ||
295 | |||
296 | /** | ||
297 | * Return the number of sets in the L2 Cache | ||
298 | * | ||
299 | * Returns | ||
300 | */ | ||
301 | int cvmx_l2c_get_num_sets(void); | ||
302 | |||
303 | /** | ||
304 | * Return log base 2 of the number of sets in the L2 cache | ||
305 | * Returns | ||
306 | */ | ||
307 | int cvmx_l2c_get_set_bits(void); | ||
308 | /** | ||
309 | * Return the number of associations in the L2 Cache | ||
310 | * | ||
311 | * Returns | ||
312 | */ | ||
313 | int cvmx_l2c_get_num_assoc(void); | ||
314 | |||
315 | /** | ||
316 | * Flush a line from the L2 cache | ||
317 | * This should only be called from one core at a time, as this routine | ||
318 | * sets the core to the 'debug' core in order to flush the line. | ||
319 | * | ||
320 | * @assoc: Association (or way) to flush | ||
321 | * @index: Index to flush | ||
322 | */ | ||
323 | void cvmx_l2c_flush_line(uint32_t assoc, uint32_t index); | ||
324 | |||
325 | #endif /* __CVMX_L2C_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/cvmx-packet.h b/arch/mips/include/asm/octeon/cvmx-packet.h new file mode 100644 index 000000000000..38aefa1bab9d --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-packet.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * Packet buffer defines. | ||
30 | */ | ||
31 | |||
32 | #ifndef __CVMX_PACKET_H__ | ||
33 | #define __CVMX_PACKET_H__ | ||
34 | |||
35 | /** | ||
36 | * This structure defines a buffer pointer on Octeon | ||
37 | */ | ||
38 | union cvmx_buf_ptr { | ||
39 | void *ptr; | ||
40 | uint64_t u64; | ||
41 | struct { | ||
42 | /* if set, invert the "free" pick of the overall | ||
43 | * packet. HW always sets this bit to 0 on inbound | ||
44 | * packet */ | ||
45 | uint64_t i:1; | ||
46 | |||
47 | /* Indicates the amount to back up to get to the | ||
48 | * buffer start in cache lines. In most cases this is | ||
49 | * less than one complete cache line, so the value is | ||
50 | * zero */ | ||
51 | uint64_t back:4; | ||
52 | /* The pool that the buffer came from / goes to */ | ||
53 | uint64_t pool:3; | ||
54 | /* The size of the segment pointed to by addr (in bytes) */ | ||
55 | uint64_t size:16; | ||
56 | /* Pointer to the first byte of the data, NOT buffer */ | ||
57 | uint64_t addr:40; | ||
58 | } s; | ||
59 | }; | ||
60 | |||
61 | #endif /* __CVMX_PACKET_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/cvmx-spinlock.h b/arch/mips/include/asm/octeon/cvmx-spinlock.h new file mode 100644 index 000000000000..2fbf0871df11 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-spinlock.h | |||
@@ -0,0 +1,232 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /** | ||
29 | * Implementation of spinlocks for Octeon CVMX. Although similar in | ||
30 | * function to Linux kernel spinlocks, they are not compatible. | ||
31 | * Octeon CVMX spinlocks are only used to synchronize with the boot | ||
32 | * monitor and other non-Linux programs running in the system. | ||
33 | */ | ||
34 | |||
35 | #ifndef __CVMX_SPINLOCK_H__ | ||
36 | #define __CVMX_SPINLOCK_H__ | ||
37 | |||
38 | #include "cvmx-asm.h" | ||
39 | |||
40 | /* Spinlocks for Octeon */ | ||
41 | |||
42 | /* define these to enable recursive spinlock debugging */ | ||
43 | /*#define CVMX_SPINLOCK_DEBUG */ | ||
44 | |||
45 | /** | ||
46 | * Spinlocks for Octeon CVMX | ||
47 | */ | ||
48 | typedef struct { | ||
49 | volatile uint32_t value; | ||
50 | } cvmx_spinlock_t; | ||
51 | |||
52 | /* note - macros not expanded in inline ASM, so values hardcoded */ | ||
53 | #define CVMX_SPINLOCK_UNLOCKED_VAL 0 | ||
54 | #define CVMX_SPINLOCK_LOCKED_VAL 1 | ||
55 | |||
56 | #define CVMX_SPINLOCK_UNLOCKED_INITIALIZER {CVMX_SPINLOCK_UNLOCKED_VAL} | ||
57 | |||
58 | /** | ||
59 | * Initialize a spinlock | ||
60 | * | ||
61 | * @lock: Lock to initialize | ||
62 | */ | ||
63 | static inline void cvmx_spinlock_init(cvmx_spinlock_t *lock) | ||
64 | { | ||
65 | lock->value = CVMX_SPINLOCK_UNLOCKED_VAL; | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * Return non-zero if the spinlock is currently locked | ||
70 | * | ||
71 | * @lock: Lock to check | ||
72 | * Returns Non-zero if locked | ||
73 | */ | ||
74 | static inline int cvmx_spinlock_locked(cvmx_spinlock_t *lock) | ||
75 | { | ||
76 | return lock->value != CVMX_SPINLOCK_UNLOCKED_VAL; | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * Releases lock | ||
81 | * | ||
82 | * @lock: pointer to lock structure | ||
83 | */ | ||
84 | static inline void cvmx_spinlock_unlock(cvmx_spinlock_t *lock) | ||
85 | { | ||
86 | CVMX_SYNCWS; | ||
87 | lock->value = 0; | ||
88 | CVMX_SYNCWS; | ||
89 | } | ||
90 | |||
91 | /** | ||
92 | * Attempts to take the lock, but does not spin if lock is not available. | ||
93 | * May take some time to acquire the lock even if it is available | ||
94 | * due to the ll/sc not succeeding. | ||
95 | * | ||
96 | * @lock: pointer to lock structure | ||
97 | * | ||
98 | * Returns 0: lock successfully taken | ||
99 | * 1: lock not taken, held by someone else | ||
100 | * These return values match the Linux semantics. | ||
101 | */ | ||
102 | |||
103 | static inline unsigned int cvmx_spinlock_trylock(cvmx_spinlock_t *lock) | ||
104 | { | ||
105 | unsigned int tmp; | ||
106 | |||
107 | __asm__ __volatile__(".set noreorder \n" | ||
108 | "1: ll %[tmp], %[val] \n" | ||
109 | /* if lock held, fail immediately */ | ||
110 | " bnez %[tmp], 2f \n" | ||
111 | " li %[tmp], 1 \n" | ||
112 | " sc %[tmp], %[val] \n" | ||
113 | " beqz %[tmp], 1b \n" | ||
114 | " li %[tmp], 0 \n" | ||
115 | "2: \n" | ||
116 | ".set reorder \n" : | ||
117 | [val] "+m"(lock->value), [tmp] "=&r"(tmp) | ||
118 | : : "memory"); | ||
119 | |||
120 | return tmp != 0; /* normalize to 0 or 1 */ | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * Gets lock, spins until lock is taken | ||
125 | * | ||
126 | * @lock: pointer to lock structure | ||
127 | */ | ||
128 | static inline void cvmx_spinlock_lock(cvmx_spinlock_t *lock) | ||
129 | { | ||
130 | unsigned int tmp; | ||
131 | |||
132 | __asm__ __volatile__(".set noreorder \n" | ||
133 | "1: ll %[tmp], %[val] \n" | ||
134 | " bnez %[tmp], 1b \n" | ||
135 | " li %[tmp], 1 \n" | ||
136 | " sc %[tmp], %[val] \n" | ||
137 | " beqz %[tmp], 1b \n" | ||
138 | " nop \n" | ||
139 | ".set reorder \n" : | ||
140 | [val] "+m"(lock->value), [tmp] "=&r"(tmp) | ||
141 | : : "memory"); | ||
142 | |||
143 | } | ||
144 | |||
145 | /** ******************************************************************** | ||
146 | * Bit spinlocks | ||
147 | * These spinlocks use a single bit (bit 31) of a 32 bit word for locking. | ||
148 | * The rest of the bits in the word are left undisturbed. This enables more | ||
149 | * compact data structures as only 1 bit is consumed for the lock. | ||
150 | * | ||
151 | */ | ||
152 | |||
153 | /** | ||
154 | * Gets lock, spins until lock is taken | ||
155 | * Preserves the low 31 bits of the 32 bit | ||
156 | * word used for the lock. | ||
157 | * | ||
158 | * | ||
159 | * @word: word to lock bit 31 of | ||
160 | */ | ||
161 | static inline void cvmx_spinlock_bit_lock(uint32_t *word) | ||
162 | { | ||
163 | unsigned int tmp; | ||
164 | unsigned int sav; | ||
165 | |||
166 | __asm__ __volatile__(".set noreorder \n" | ||
167 | ".set noat \n" | ||
168 | "1: ll %[tmp], %[val] \n" | ||
169 | " bbit1 %[tmp], 31, 1b \n" | ||
170 | " li $at, 1 \n" | ||
171 | " ins %[tmp], $at, 31, 1 \n" | ||
172 | " sc %[tmp], %[val] \n" | ||
173 | " beqz %[tmp], 1b \n" | ||
174 | " nop \n" | ||
175 | ".set at \n" | ||
176 | ".set reorder \n" : | ||
177 | [val] "+m"(*word), [tmp] "=&r"(tmp), [sav] "=&r"(sav) | ||
178 | : : "memory"); | ||
179 | |||
180 | } | ||
181 | |||
182 | /** | ||
183 | * Attempts to get lock, returns immediately with success/failure | ||
184 | * Preserves the low 31 bits of the 32 bit | ||
185 | * word used for the lock. | ||
186 | * | ||
187 | * | ||
188 | * @word: word to lock bit 31 of | ||
189 | * Returns 0: lock successfully taken | ||
190 | * 1: lock not taken, held by someone else | ||
191 | * These return values match the Linux semantics. | ||
192 | */ | ||
193 | static inline unsigned int cvmx_spinlock_bit_trylock(uint32_t *word) | ||
194 | { | ||
195 | unsigned int tmp; | ||
196 | |||
197 | __asm__ __volatile__(".set noreorder\n\t" | ||
198 | ".set noat\n" | ||
199 | "1: ll %[tmp], %[val] \n" | ||
200 | /* if lock held, fail immediately */ | ||
201 | " bbit1 %[tmp], 31, 2f \n" | ||
202 | " li $at, 1 \n" | ||
203 | " ins %[tmp], $at, 31, 1 \n" | ||
204 | " sc %[tmp], %[val] \n" | ||
205 | " beqz %[tmp], 1b \n" | ||
206 | " li %[tmp], 0 \n" | ||
207 | "2: \n" | ||
208 | ".set at \n" | ||
209 | ".set reorder \n" : | ||
210 | [val] "+m"(*word), [tmp] "=&r"(tmp) | ||
211 | : : "memory"); | ||
212 | |||
213 | return tmp != 0; /* normalize to 0 or 1 */ | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * Releases bit lock | ||
218 | * | ||
219 | * Unconditionally clears bit 31 of the lock word. Note that this is | ||
220 | * done non-atomically, as this implementation assumes that the rest | ||
221 | * of the bits in the word are protected by the lock. | ||
222 | * | ||
223 | * @word: word to unlock bit 31 in | ||
224 | */ | ||
225 | static inline void cvmx_spinlock_bit_unlock(uint32_t *word) | ||
226 | { | ||
227 | CVMX_SYNCWS; | ||
228 | *word &= ~(1UL << 31); | ||
229 | CVMX_SYNCWS; | ||
230 | } | ||
231 | |||
232 | #endif /* __CVMX_SPINLOCK_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/cvmx-sysinfo.h b/arch/mips/include/asm/octeon/cvmx-sysinfo.h new file mode 100644 index 000000000000..61dd5741afe4 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx-sysinfo.h | |||
@@ -0,0 +1,152 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * This module provides system/board information obtained by the bootloader. | ||
30 | */ | ||
31 | |||
32 | #ifndef __CVMX_SYSINFO_H__ | ||
33 | #define __CVMX_SYSINFO_H__ | ||
34 | |||
35 | #define OCTEON_SERIAL_LEN 20 | ||
36 | /** | ||
37 | * Structure describing application specific information. | ||
38 | * __cvmx_app_init() populates this from the cvmx boot descriptor. | ||
39 | * This structure is private to simple executive applications, so | ||
40 | * no versioning is required. | ||
41 | * | ||
42 | * This structure must be provided with some fields set in order to | ||
43 | * use simple executive functions in other applications (Linux kernel, | ||
44 | * u-boot, etc.) The cvmx_sysinfo_minimal_initialize() function is | ||
45 | * provided to set the required values in these cases. | ||
46 | */ | ||
47 | struct cvmx_sysinfo { | ||
48 | /* System wide variables */ | ||
49 | /* installed DRAM in system, in bytes */ | ||
50 | uint64_t system_dram_size; | ||
51 | |||
52 | /* ptr to memory descriptor block */ | ||
53 | void *phy_mem_desc_ptr; | ||
54 | |||
55 | |||
56 | /* Application image specific variables */ | ||
57 | /* stack top address (virtual) */ | ||
58 | uint64_t stack_top; | ||
59 | /* heap base address (virtual) */ | ||
60 | uint64_t heap_base; | ||
61 | /* stack size in bytes */ | ||
62 | uint32_t stack_size; | ||
63 | /* heap size in bytes */ | ||
64 | uint32_t heap_size; | ||
65 | /* coremask defining cores running application */ | ||
66 | uint32_t core_mask; | ||
67 | /* Deprecated, use cvmx_coremask_first_core() to select init core */ | ||
68 | uint32_t init_core; | ||
69 | |||
70 | /* exception base address, as set by bootloader */ | ||
71 | uint64_t exception_base_addr; | ||
72 | |||
73 | /* cpu clock speed in hz */ | ||
74 | uint32_t cpu_clock_hz; | ||
75 | |||
76 | /* dram data rate in hz (data rate = 2 * clock rate */ | ||
77 | uint32_t dram_data_rate_hz; | ||
78 | |||
79 | |||
80 | uint16_t board_type; | ||
81 | uint8_t board_rev_major; | ||
82 | uint8_t board_rev_minor; | ||
83 | uint8_t mac_addr_base[6]; | ||
84 | uint8_t mac_addr_count; | ||
85 | char board_serial_number[OCTEON_SERIAL_LEN]; | ||
86 | /* | ||
87 | * Several boards support compact flash on the Octeon boot | ||
88 | * bus. The CF memory spaces may be mapped to different | ||
89 | * addresses on different boards. These values will be 0 if | ||
90 | * CF is not present. Note that these addresses are physical | ||
91 | * addresses, and it is up to the application to use the | ||
92 | * proper addressing mode (XKPHYS, KSEG0, etc.) | ||
93 | */ | ||
94 | uint64_t compact_flash_common_base_addr; | ||
95 | uint64_t compact_flash_attribute_base_addr; | ||
96 | /* | ||
97 | * Base address of the LED display (as on EBT3000 board) This | ||
98 | * will be 0 if LED display not present. Note that this | ||
99 | * address is a physical address, and it is up to the | ||
100 | * application to use the proper addressing mode (XKPHYS, | ||
101 | * KSEG0, etc.) | ||
102 | */ | ||
103 | uint64_t led_display_base_addr; | ||
104 | /* DFA reference clock in hz (if applicable)*/ | ||
105 | uint32_t dfa_ref_clock_hz; | ||
106 | /* configuration flags from bootloader */ | ||
107 | uint32_t bootloader_config_flags; | ||
108 | |||
109 | /* Uart number used for console */ | ||
110 | uint8_t console_uart_num; | ||
111 | }; | ||
112 | |||
113 | /** | ||
114 | * This function returns the system/board information as obtained | ||
115 | * by the bootloader. | ||
116 | * | ||
117 | * | ||
118 | * Returns Pointer to the boot information structure | ||
119 | * | ||
120 | */ | ||
121 | |||
122 | extern struct cvmx_sysinfo *cvmx_sysinfo_get(void); | ||
123 | |||
124 | /** | ||
125 | * This function is used in non-simple executive environments (such as | ||
126 | * Linux kernel, u-boot, etc.) to configure the minimal fields that | ||
127 | * are required to use simple executive files directly. | ||
128 | * | ||
129 | * Locking (if required) must be handled outside of this | ||
130 | * function | ||
131 | * | ||
132 | * @phy_mem_desc_ptr: Pointer to global physical memory descriptor | ||
133 | * (bootmem descriptor) @board_type: Octeon board | ||
134 | * type enumeration | ||
135 | * | ||
136 | * @board_rev_major: | ||
137 | * Board major revision | ||
138 | * @board_rev_minor: | ||
139 | * Board minor revision | ||
140 | * @cpu_clock_hz: | ||
141 | * CPU clock freqency in hertz | ||
142 | * | ||
143 | * Returns 0: Failure | ||
144 | * 1: success | ||
145 | */ | ||
146 | extern int cvmx_sysinfo_minimal_initialize(void *phy_mem_desc_ptr, | ||
147 | uint16_t board_type, | ||
148 | uint8_t board_rev_major, | ||
149 | uint8_t board_rev_minor, | ||
150 | uint32_t cpu_clock_hz); | ||
151 | |||
152 | #endif /* __CVMX_SYSINFO_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/cvmx.h b/arch/mips/include/asm/octeon/cvmx.h new file mode 100644 index 000000000000..03fddfa3e928 --- /dev/null +++ b/arch/mips/include/asm/octeon/cvmx.h | |||
@@ -0,0 +1,505 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | #ifndef __CVMX_H__ | ||
29 | #define __CVMX_H__ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/string.h> | ||
33 | |||
34 | #include "cvmx-asm.h" | ||
35 | #include "cvmx-packet.h" | ||
36 | #include "cvmx-sysinfo.h" | ||
37 | |||
38 | #include "cvmx-ciu-defs.h" | ||
39 | #include "cvmx-gpio-defs.h" | ||
40 | #include "cvmx-iob-defs.h" | ||
41 | #include "cvmx-ipd-defs.h" | ||
42 | #include "cvmx-l2c-defs.h" | ||
43 | #include "cvmx-l2d-defs.h" | ||
44 | #include "cvmx-l2t-defs.h" | ||
45 | #include "cvmx-led-defs.h" | ||
46 | #include "cvmx-mio-defs.h" | ||
47 | #include "cvmx-pow-defs.h" | ||
48 | |||
49 | #include "cvmx-bootinfo.h" | ||
50 | #include "cvmx-bootmem.h" | ||
51 | #include "cvmx-l2c.h" | ||
52 | |||
53 | #ifndef CVMX_ENABLE_DEBUG_PRINTS | ||
54 | #define CVMX_ENABLE_DEBUG_PRINTS 1 | ||
55 | #endif | ||
56 | |||
57 | #if CVMX_ENABLE_DEBUG_PRINTS | ||
58 | #define cvmx_dprintf printk | ||
59 | #else | ||
60 | #define cvmx_dprintf(...) {} | ||
61 | #endif | ||
62 | |||
63 | #define CVMX_MAX_CORES (16) | ||
64 | #define CVMX_CACHE_LINE_SIZE (128) /* In bytes */ | ||
65 | #define CVMX_CACHE_LINE_MASK (CVMX_CACHE_LINE_SIZE - 1) /* In bytes */ | ||
66 | #define CVMX_CACHE_LINE_ALIGNED __attribute__ ((aligned(CVMX_CACHE_LINE_SIZE))) | ||
67 | #define CAST64(v) ((long long)(long)(v)) | ||
68 | #define CASTPTR(type, v) ((type *)(long)(v)) | ||
69 | |||
70 | /* | ||
71 | * Returns processor ID, different Linux and simple exec versions | ||
72 | * provided in the cvmx-app-init*.c files. | ||
73 | */ | ||
74 | static inline uint32_t cvmx_get_proc_id(void) __attribute__ ((pure)); | ||
75 | static inline uint32_t cvmx_get_proc_id(void) | ||
76 | { | ||
77 | uint32_t id; | ||
78 | asm("mfc0 %0, $15,0" : "=r"(id)); | ||
79 | return id; | ||
80 | } | ||
81 | |||
82 | /* turn the variable name into a string */ | ||
83 | #define CVMX_TMP_STR(x) CVMX_TMP_STR2(x) | ||
84 | #define CVMX_TMP_STR2(x) #x | ||
85 | |||
86 | /** | ||
87 | * Builds a bit mask given the required size in bits. | ||
88 | * | ||
89 | * @bits: Number of bits in the mask | ||
90 | * Returns The mask | ||
91 | */ static inline uint64_t cvmx_build_mask(uint64_t bits) | ||
92 | { | ||
93 | return ~((~0x0ull) << bits); | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * Builds a memory address for I/O based on the Major and Sub DID. | ||
98 | * | ||
99 | * @major_did: 5 bit major did | ||
100 | * @sub_did: 3 bit sub did | ||
101 | * Returns I/O base address | ||
102 | */ | ||
103 | static inline uint64_t cvmx_build_io_address(uint64_t major_did, | ||
104 | uint64_t sub_did) | ||
105 | { | ||
106 | return (0x1ull << 48) | (major_did << 43) | (sub_did << 40); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * Perform mask and shift to place the supplied value into | ||
111 | * the supplied bit rage. | ||
112 | * | ||
113 | * Example: cvmx_build_bits(39,24,value) | ||
114 | * <pre> | ||
115 | * 6 5 4 3 3 2 1 | ||
116 | * 3 5 7 9 1 3 5 7 0 | ||
117 | * +-------+-------+-------+-------+-------+-------+-------+------+ | ||
118 | * 000000000000000000000000___________value000000000000000000000000 | ||
119 | * </pre> | ||
120 | * | ||
121 | * @high_bit: Highest bit value can occupy (inclusive) 0-63 | ||
122 | * @low_bit: Lowest bit value can occupy inclusive 0-high_bit | ||
123 | * @value: Value to use | ||
124 | * Returns Value masked and shifted | ||
125 | */ | ||
126 | static inline uint64_t cvmx_build_bits(uint64_t high_bit, | ||
127 | uint64_t low_bit, uint64_t value) | ||
128 | { | ||
129 | return (value & cvmx_build_mask(high_bit - low_bit + 1)) << low_bit; | ||
130 | } | ||
131 | |||
132 | enum cvmx_mips_space { | ||
133 | CVMX_MIPS_SPACE_XKSEG = 3LL, | ||
134 | CVMX_MIPS_SPACE_XKPHYS = 2LL, | ||
135 | CVMX_MIPS_SPACE_XSSEG = 1LL, | ||
136 | CVMX_MIPS_SPACE_XUSEG = 0LL | ||
137 | }; | ||
138 | |||
139 | /* These macros for use when using 32 bit pointers. */ | ||
140 | #define CVMX_MIPS32_SPACE_KSEG0 1l | ||
141 | #define CVMX_ADD_SEG32(segment, add) \ | ||
142 | (((int32_t)segment << 31) | (int32_t)(add)) | ||
143 | |||
144 | #define CVMX_IO_SEG CVMX_MIPS_SPACE_XKPHYS | ||
145 | |||
146 | /* These macros simplify the process of creating common IO addresses */ | ||
147 | #define CVMX_ADD_SEG(segment, add) \ | ||
148 | ((((uint64_t)segment) << 62) | (add)) | ||
149 | #ifndef CVMX_ADD_IO_SEG | ||
150 | #define CVMX_ADD_IO_SEG(add) CVMX_ADD_SEG(CVMX_IO_SEG, (add)) | ||
151 | #endif | ||
152 | |||
153 | /** | ||
154 | * Convert a memory pointer (void*) into a hardware compatable | ||
155 | * memory address (uint64_t). Octeon hardware widgets don't | ||
156 | * understand logical addresses. | ||
157 | * | ||
158 | * @ptr: C style memory pointer | ||
159 | * Returns Hardware physical address | ||
160 | */ | ||
161 | static inline uint64_t cvmx_ptr_to_phys(void *ptr) | ||
162 | { | ||
163 | if (sizeof(void *) == 8) { | ||
164 | /* | ||
165 | * We're running in 64 bit mode. Normally this means | ||
166 | * that we can use 40 bits of address space (the | ||
167 | * hardware limit). Unfortunately there is one case | ||
168 | * were we need to limit this to 30 bits, sign | ||
169 | * extended 32 bit. Although these are 64 bits wide, | ||
170 | * only 30 bits can be used. | ||
171 | */ | ||
172 | if ((CAST64(ptr) >> 62) == 3) | ||
173 | return CAST64(ptr) & cvmx_build_mask(30); | ||
174 | else | ||
175 | return CAST64(ptr) & cvmx_build_mask(40); | ||
176 | } else { | ||
177 | return (long)(ptr) & 0x1fffffff; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /** | ||
182 | * Convert a hardware physical address (uint64_t) into a | ||
183 | * memory pointer (void *). | ||
184 | * | ||
185 | * @physical_address: | ||
186 | * Hardware physical address to memory | ||
187 | * Returns Pointer to memory | ||
188 | */ | ||
189 | static inline void *cvmx_phys_to_ptr(uint64_t physical_address) | ||
190 | { | ||
191 | if (sizeof(void *) == 8) { | ||
192 | /* Just set the top bit, avoiding any TLB uglyness */ | ||
193 | return CASTPTR(void, | ||
194 | CVMX_ADD_SEG(CVMX_MIPS_SPACE_XKPHYS, | ||
195 | physical_address)); | ||
196 | } else { | ||
197 | return CASTPTR(void, | ||
198 | CVMX_ADD_SEG32(CVMX_MIPS32_SPACE_KSEG0, | ||
199 | physical_address)); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /* The following #if controls the definition of the macro | ||
204 | CVMX_BUILD_WRITE64. This macro is used to build a store operation to | ||
205 | a full 64bit address. With a 64bit ABI, this can be done with a simple | ||
206 | pointer access. 32bit ABIs require more complicated assembly */ | ||
207 | |||
208 | /* We have a full 64bit ABI. Writing to a 64bit address can be done with | ||
209 | a simple volatile pointer */ | ||
210 | #define CVMX_BUILD_WRITE64(TYPE, ST) \ | ||
211 | static inline void cvmx_write64_##TYPE(uint64_t addr, TYPE##_t val) \ | ||
212 | { \ | ||
213 | *CASTPTR(volatile TYPE##_t, addr) = val; \ | ||
214 | } | ||
215 | |||
216 | |||
217 | /* The following #if controls the definition of the macro | ||
218 | CVMX_BUILD_READ64. This macro is used to build a load operation from | ||
219 | a full 64bit address. With a 64bit ABI, this can be done with a simple | ||
220 | pointer access. 32bit ABIs require more complicated assembly */ | ||
221 | |||
222 | /* We have a full 64bit ABI. Writing to a 64bit address can be done with | ||
223 | a simple volatile pointer */ | ||
224 | #define CVMX_BUILD_READ64(TYPE, LT) \ | ||
225 | static inline TYPE##_t cvmx_read64_##TYPE(uint64_t addr) \ | ||
226 | { \ | ||
227 | return *CASTPTR(volatile TYPE##_t, addr); \ | ||
228 | } | ||
229 | |||
230 | |||
231 | /* The following defines 8 functions for writing to a 64bit address. Each | ||
232 | takes two arguments, the address and the value to write. | ||
233 | cvmx_write64_int64 cvmx_write64_uint64 | ||
234 | cvmx_write64_int32 cvmx_write64_uint32 | ||
235 | cvmx_write64_int16 cvmx_write64_uint16 | ||
236 | cvmx_write64_int8 cvmx_write64_uint8 */ | ||
237 | CVMX_BUILD_WRITE64(int64, "sd"); | ||
238 | CVMX_BUILD_WRITE64(int32, "sw"); | ||
239 | CVMX_BUILD_WRITE64(int16, "sh"); | ||
240 | CVMX_BUILD_WRITE64(int8, "sb"); | ||
241 | CVMX_BUILD_WRITE64(uint64, "sd"); | ||
242 | CVMX_BUILD_WRITE64(uint32, "sw"); | ||
243 | CVMX_BUILD_WRITE64(uint16, "sh"); | ||
244 | CVMX_BUILD_WRITE64(uint8, "sb"); | ||
245 | #define cvmx_write64 cvmx_write64_uint64 | ||
246 | |||
247 | /* The following defines 8 functions for reading from a 64bit address. Each | ||
248 | takes the address as the only argument | ||
249 | cvmx_read64_int64 cvmx_read64_uint64 | ||
250 | cvmx_read64_int32 cvmx_read64_uint32 | ||
251 | cvmx_read64_int16 cvmx_read64_uint16 | ||
252 | cvmx_read64_int8 cvmx_read64_uint8 */ | ||
253 | CVMX_BUILD_READ64(int64, "ld"); | ||
254 | CVMX_BUILD_READ64(int32, "lw"); | ||
255 | CVMX_BUILD_READ64(int16, "lh"); | ||
256 | CVMX_BUILD_READ64(int8, "lb"); | ||
257 | CVMX_BUILD_READ64(uint64, "ld"); | ||
258 | CVMX_BUILD_READ64(uint32, "lw"); | ||
259 | CVMX_BUILD_READ64(uint16, "lhu"); | ||
260 | CVMX_BUILD_READ64(uint8, "lbu"); | ||
261 | #define cvmx_read64 cvmx_read64_uint64 | ||
262 | |||
263 | |||
264 | static inline void cvmx_write_csr(uint64_t csr_addr, uint64_t val) | ||
265 | { | ||
266 | cvmx_write64(csr_addr, val); | ||
267 | |||
268 | /* | ||
269 | * Perform an immediate read after every write to an RSL | ||
270 | * register to force the write to complete. It doesn't matter | ||
271 | * what RSL read we do, so we choose CVMX_MIO_BOOT_BIST_STAT | ||
272 | * because it is fast and harmless. | ||
273 | */ | ||
274 | if ((csr_addr >> 40) == (0x800118)) | ||
275 | cvmx_read64(CVMX_MIO_BOOT_BIST_STAT); | ||
276 | } | ||
277 | |||
278 | static inline void cvmx_write_io(uint64_t io_addr, uint64_t val) | ||
279 | { | ||
280 | cvmx_write64(io_addr, val); | ||
281 | |||
282 | } | ||
283 | |||
284 | static inline uint64_t cvmx_read_csr(uint64_t csr_addr) | ||
285 | { | ||
286 | uint64_t val = cvmx_read64(csr_addr); | ||
287 | return val; | ||
288 | } | ||
289 | |||
290 | |||
291 | static inline void cvmx_send_single(uint64_t data) | ||
292 | { | ||
293 | const uint64_t CVMX_IOBDMA_SENDSINGLE = 0xffffffffffffa200ull; | ||
294 | cvmx_write64(CVMX_IOBDMA_SENDSINGLE, data); | ||
295 | } | ||
296 | |||
297 | static inline void cvmx_read_csr_async(uint64_t scraddr, uint64_t csr_addr) | ||
298 | { | ||
299 | union { | ||
300 | uint64_t u64; | ||
301 | struct { | ||
302 | uint64_t scraddr:8; | ||
303 | uint64_t len:8; | ||
304 | uint64_t addr:48; | ||
305 | } s; | ||
306 | } addr; | ||
307 | addr.u64 = csr_addr; | ||
308 | addr.s.scraddr = scraddr >> 3; | ||
309 | addr.s.len = 1; | ||
310 | cvmx_send_single(addr.u64); | ||
311 | } | ||
312 | |||
313 | /* Return true if Octeon is CN38XX pass 1 */ | ||
314 | static inline int cvmx_octeon_is_pass1(void) | ||
315 | { | ||
316 | #if OCTEON_IS_COMMON_BINARY() | ||
317 | return 0; /* Pass 1 isn't supported for common binaries */ | ||
318 | #else | ||
319 | /* Now that we know we're built for a specific model, only check CN38XX */ | ||
320 | #if OCTEON_IS_MODEL(OCTEON_CN38XX) | ||
321 | return cvmx_get_proc_id() == OCTEON_CN38XX_PASS1; | ||
322 | #else | ||
323 | return 0; /* Built for non CN38XX chip, we're not CN38XX pass1 */ | ||
324 | #endif | ||
325 | #endif | ||
326 | } | ||
327 | |||
328 | static inline unsigned int cvmx_get_core_num(void) | ||
329 | { | ||
330 | unsigned int core_num; | ||
331 | CVMX_RDHWRNV(core_num, 0); | ||
332 | return core_num; | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * Returns the number of bits set in the provided value. | ||
337 | * Simple wrapper for POP instruction. | ||
338 | * | ||
339 | * @val: 32 bit value to count set bits in | ||
340 | * | ||
341 | * Returns Number of bits set | ||
342 | */ | ||
343 | static inline uint32_t cvmx_pop(uint32_t val) | ||
344 | { | ||
345 | uint32_t pop; | ||
346 | CVMX_POP(pop, val); | ||
347 | return pop; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * Returns the number of bits set in the provided value. | ||
352 | * Simple wrapper for DPOP instruction. | ||
353 | * | ||
354 | * @val: 64 bit value to count set bits in | ||
355 | * | ||
356 | * Returns Number of bits set | ||
357 | */ | ||
358 | static inline int cvmx_dpop(uint64_t val) | ||
359 | { | ||
360 | int pop; | ||
361 | CVMX_DPOP(pop, val); | ||
362 | return pop; | ||
363 | } | ||
364 | |||
365 | /** | ||
366 | * Provide current cycle counter as a return value | ||
367 | * | ||
368 | * Returns current cycle counter | ||
369 | */ | ||
370 | |||
371 | static inline uint64_t cvmx_get_cycle(void) | ||
372 | { | ||
373 | uint64_t cycle; | ||
374 | CVMX_RDHWR(cycle, 31); | ||
375 | return cycle; | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * Reads a chip global cycle counter. This counts CPU cycles since | ||
380 | * chip reset. The counter is 64 bit. | ||
381 | * This register does not exist on CN38XX pass 1 silicion | ||
382 | * | ||
383 | * Returns Global chip cycle count since chip reset. | ||
384 | */ | ||
385 | static inline uint64_t cvmx_get_cycle_global(void) | ||
386 | { | ||
387 | if (cvmx_octeon_is_pass1()) | ||
388 | return 0; | ||
389 | else | ||
390 | return cvmx_read64(CVMX_IPD_CLK_COUNT); | ||
391 | } | ||
392 | |||
393 | /** | ||
394 | * This macro spins on a field waiting for it to reach a value. It | ||
395 | * is common in code to need to wait for a specific field in a CSR | ||
396 | * to match a specific value. Conceptually this macro expands to: | ||
397 | * | ||
398 | * 1) read csr at "address" with a csr typedef of "type" | ||
399 | * 2) Check if ("type".s."field" "op" "value") | ||
400 | * 3) If #2 isn't true loop to #1 unless too much time has passed. | ||
401 | */ | ||
402 | #define CVMX_WAIT_FOR_FIELD64(address, type, field, op, value, timeout_usec)\ | ||
403 | ( \ | ||
404 | { \ | ||
405 | int result; \ | ||
406 | do { \ | ||
407 | uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \ | ||
408 | cvmx_sysinfo_get()->cpu_clock_hz / 1000000; \ | ||
409 | type c; \ | ||
410 | while (1) { \ | ||
411 | c.u64 = cvmx_read_csr(address); \ | ||
412 | if ((c.s.field) op(value)) { \ | ||
413 | result = 0; \ | ||
414 | break; \ | ||
415 | } else if (cvmx_get_cycle() > done) { \ | ||
416 | result = -1; \ | ||
417 | break; \ | ||
418 | } else \ | ||
419 | cvmx_wait(100); \ | ||
420 | } \ | ||
421 | } while (0); \ | ||
422 | result; \ | ||
423 | }) | ||
424 | |||
425 | /***************************************************************************/ | ||
426 | |||
427 | static inline void cvmx_reset_octeon(void) | ||
428 | { | ||
429 | union cvmx_ciu_soft_rst ciu_soft_rst; | ||
430 | ciu_soft_rst.u64 = 0; | ||
431 | ciu_soft_rst.s.soft_rst = 1; | ||
432 | cvmx_write_csr(CVMX_CIU_SOFT_RST, ciu_soft_rst.u64); | ||
433 | } | ||
434 | |||
435 | /* Return the number of cores available in the chip */ | ||
436 | static inline uint32_t cvmx_octeon_num_cores(void) | ||
437 | { | ||
438 | uint32_t ciu_fuse = (uint32_t) cvmx_read_csr(CVMX_CIU_FUSE) & 0xffff; | ||
439 | return cvmx_pop(ciu_fuse); | ||
440 | } | ||
441 | |||
442 | /** | ||
443 | * Read a byte of fuse data | ||
444 | * @byte_addr: address to read | ||
445 | * | ||
446 | * Returns fuse value: 0 or 1 | ||
447 | */ | ||
448 | static uint8_t cvmx_fuse_read_byte(int byte_addr) | ||
449 | { | ||
450 | union cvmx_mio_fus_rcmd read_cmd; | ||
451 | |||
452 | read_cmd.u64 = 0; | ||
453 | read_cmd.s.addr = byte_addr; | ||
454 | read_cmd.s.pend = 1; | ||
455 | cvmx_write_csr(CVMX_MIO_FUS_RCMD, read_cmd.u64); | ||
456 | while ((read_cmd.u64 = cvmx_read_csr(CVMX_MIO_FUS_RCMD)) | ||
457 | && read_cmd.s.pend) | ||
458 | ; | ||
459 | return read_cmd.s.dat; | ||
460 | } | ||
461 | |||
462 | /** | ||
463 | * Read a single fuse bit | ||
464 | * | ||
465 | * @fuse: Fuse number (0-1024) | ||
466 | * | ||
467 | * Returns fuse value: 0 or 1 | ||
468 | */ | ||
469 | static inline int cvmx_fuse_read(int fuse) | ||
470 | { | ||
471 | return (cvmx_fuse_read_byte(fuse >> 3) >> (fuse & 0x7)) & 1; | ||
472 | } | ||
473 | |||
474 | static inline int cvmx_octeon_model_CN36XX(void) | ||
475 | { | ||
476 | return OCTEON_IS_MODEL(OCTEON_CN38XX) | ||
477 | && !cvmx_octeon_is_pass1() | ||
478 | && cvmx_fuse_read(264); | ||
479 | } | ||
480 | |||
481 | static inline int cvmx_octeon_zip_present(void) | ||
482 | { | ||
483 | return octeon_has_feature(OCTEON_FEATURE_ZIP); | ||
484 | } | ||
485 | |||
486 | static inline int cvmx_octeon_dfa_present(void) | ||
487 | { | ||
488 | if (!OCTEON_IS_MODEL(OCTEON_CN38XX) | ||
489 | && !OCTEON_IS_MODEL(OCTEON_CN31XX) | ||
490 | && !OCTEON_IS_MODEL(OCTEON_CN58XX)) | ||
491 | return 0; | ||
492 | else if (OCTEON_IS_MODEL(OCTEON_CN3020)) | ||
493 | return 0; | ||
494 | else if (cvmx_octeon_is_pass1()) | ||
495 | return 1; | ||
496 | else | ||
497 | return !cvmx_fuse_read(120); | ||
498 | } | ||
499 | |||
500 | static inline int cvmx_octeon_crypto_present(void) | ||
501 | { | ||
502 | return octeon_has_feature(OCTEON_FEATURE_CRYPTO); | ||
503 | } | ||
504 | |||
505 | #endif /* __CVMX_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/octeon-feature.h b/arch/mips/include/asm/octeon/octeon-feature.h new file mode 100644 index 000000000000..04fac684069c --- /dev/null +++ b/arch/mips/include/asm/octeon/octeon-feature.h | |||
@@ -0,0 +1,119 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * File defining checks for different Octeon features. | ||
30 | */ | ||
31 | |||
32 | #ifndef __OCTEON_FEATURE_H__ | ||
33 | #define __OCTEON_FEATURE_H__ | ||
34 | |||
35 | enum octeon_feature { | ||
36 | /* | ||
37 | * Octeon models in the CN5XXX family and higher support | ||
38 | * atomic add instructions to memory (saa/saad). | ||
39 | */ | ||
40 | OCTEON_FEATURE_SAAD, | ||
41 | /* Does this Octeon support the ZIP offload engine? */ | ||
42 | OCTEON_FEATURE_ZIP, | ||
43 | /* Does this Octeon support crypto acceleration using COP2? */ | ||
44 | OCTEON_FEATURE_CRYPTO, | ||
45 | /* Does this Octeon support PCI express? */ | ||
46 | OCTEON_FEATURE_PCIE, | ||
47 | /* Some Octeon models support internal memory for storing | ||
48 | * cryptographic keys */ | ||
49 | OCTEON_FEATURE_KEY_MEMORY, | ||
50 | /* Octeon has a LED controller for banks of external LEDs */ | ||
51 | OCTEON_FEATURE_LED_CONTROLLER, | ||
52 | /* Octeon has a trace buffer */ | ||
53 | OCTEON_FEATURE_TRA, | ||
54 | /* Octeon has a management port */ | ||
55 | OCTEON_FEATURE_MGMT_PORT, | ||
56 | /* Octeon has a raid unit */ | ||
57 | OCTEON_FEATURE_RAID, | ||
58 | /* Octeon has a builtin USB */ | ||
59 | OCTEON_FEATURE_USB, | ||
60 | }; | ||
61 | |||
62 | static inline int cvmx_fuse_read(int fuse); | ||
63 | |||
64 | /** | ||
65 | * Determine if the current Octeon supports a specific feature. These | ||
66 | * checks have been optimized to be fairly quick, but they should still | ||
67 | * be kept out of fast path code. | ||
68 | * | ||
69 | * @feature: Feature to check for. This should always be a constant so the | ||
70 | * compiler can remove the switch statement through optimization. | ||
71 | * | ||
72 | * Returns Non zero if the feature exists. Zero if the feature does not | ||
73 | * exist. | ||
74 | */ | ||
75 | static inline int octeon_has_feature(enum octeon_feature feature) | ||
76 | { | ||
77 | switch (feature) { | ||
78 | case OCTEON_FEATURE_SAAD: | ||
79 | return !OCTEON_IS_MODEL(OCTEON_CN3XXX); | ||
80 | |||
81 | case OCTEON_FEATURE_ZIP: | ||
82 | if (OCTEON_IS_MODEL(OCTEON_CN30XX) | ||
83 | || OCTEON_IS_MODEL(OCTEON_CN50XX) | ||
84 | || OCTEON_IS_MODEL(OCTEON_CN52XX)) | ||
85 | return 0; | ||
86 | else if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS1)) | ||
87 | return 1; | ||
88 | else | ||
89 | return !cvmx_fuse_read(121); | ||
90 | |||
91 | case OCTEON_FEATURE_CRYPTO: | ||
92 | return !cvmx_fuse_read(90); | ||
93 | |||
94 | case OCTEON_FEATURE_PCIE: | ||
95 | return OCTEON_IS_MODEL(OCTEON_CN56XX) | ||
96 | || OCTEON_IS_MODEL(OCTEON_CN52XX); | ||
97 | |||
98 | case OCTEON_FEATURE_KEY_MEMORY: | ||
99 | case OCTEON_FEATURE_LED_CONTROLLER: | ||
100 | return OCTEON_IS_MODEL(OCTEON_CN38XX) | ||
101 | || OCTEON_IS_MODEL(OCTEON_CN58XX) | ||
102 | || OCTEON_IS_MODEL(OCTEON_CN56XX); | ||
103 | case OCTEON_FEATURE_TRA: | ||
104 | return !(OCTEON_IS_MODEL(OCTEON_CN30XX) | ||
105 | || OCTEON_IS_MODEL(OCTEON_CN50XX)); | ||
106 | case OCTEON_FEATURE_MGMT_PORT: | ||
107 | return OCTEON_IS_MODEL(OCTEON_CN56XX) | ||
108 | || OCTEON_IS_MODEL(OCTEON_CN52XX); | ||
109 | case OCTEON_FEATURE_RAID: | ||
110 | return OCTEON_IS_MODEL(OCTEON_CN56XX) | ||
111 | || OCTEON_IS_MODEL(OCTEON_CN52XX); | ||
112 | case OCTEON_FEATURE_USB: | ||
113 | return !(OCTEON_IS_MODEL(OCTEON_CN38XX) | ||
114 | || OCTEON_IS_MODEL(OCTEON_CN58XX)); | ||
115 | } | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | #endif /* __OCTEON_FEATURE_H__ */ | ||
diff --git a/arch/mips/include/asm/octeon/octeon-model.h b/arch/mips/include/asm/octeon/octeon-model.h new file mode 100644 index 000000000000..cf50336eca2e --- /dev/null +++ b/arch/mips/include/asm/octeon/octeon-model.h | |||
@@ -0,0 +1,321 @@ | |||
1 | /***********************license start*************** | ||
2 | * Author: Cavium Networks | ||
3 | * | ||
4 | * Contact: support@caviumnetworks.com | ||
5 | * This file is part of the OCTEON SDK | ||
6 | * | ||
7 | * Copyright (c) 2003-2008 Cavium Networks | ||
8 | * | ||
9 | * This file is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License, Version 2, as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This file is distributed in the hope that it will be useful, but | ||
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | ||
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | ||
16 | * NONINFRINGEMENT. See the GNU General Public License for more | ||
17 | * details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this file; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * or visit http://www.gnu.org/licenses/. | ||
23 | * | ||
24 | * This file may also be available under a different license from Cavium. | ||
25 | * Contact Cavium Networks for more information | ||
26 | ***********************license end**************************************/ | ||
27 | |||
28 | /* | ||
29 | * | ||
30 | * File defining different Octeon model IDs and macros to | ||
31 | * compare them. | ||
32 | * | ||
33 | */ | ||
34 | |||
35 | #ifndef __OCTEON_MODEL_H__ | ||
36 | #define __OCTEON_MODEL_H__ | ||
37 | |||
38 | /* NOTE: These must match what is checked in common-config.mk */ | ||
39 | /* Defines to represent the different versions of Octeon. */ | ||
40 | |||
41 | /* | ||
42 | * IMPORTANT: When the default pass is updated for an Octeon Model, | ||
43 | * the corresponding change must also be made in the oct-sim script. | ||
44 | */ | ||
45 | |||
46 | /* | ||
47 | * The defines below should be used with the OCTEON_IS_MODEL() macro | ||
48 | * to determine what model of chip the software is running on. Models | ||
49 | * ending in 'XX' match multiple models (families), while specific | ||
50 | * models match only that model. If a pass (revision) is specified, | ||
51 | * then only that revision will be matched. Care should be taken when | ||
52 | * checking for both specific models and families that the specific | ||
53 | * models are checked for first. While these defines are similar to | ||
54 | * the processor ID, they are not intended to be used by anything | ||
55 | * other that the OCTEON_IS_MODEL framework, and the values are | ||
56 | * subject to change at anytime without notice. | ||
57 | * | ||
58 | * NOTE: only the OCTEON_IS_MODEL() macro/function and the OCTEON_CN* | ||
59 | * macros should be used outside of this file. All other macros are | ||
60 | * for internal use only, and may change without notice. | ||
61 | */ | ||
62 | |||
63 | /* Flag bits in top byte */ | ||
64 | /* Ignores revision in model checks */ | ||
65 | #define OM_IGNORE_REVISION 0x01000000 | ||
66 | /* Check submodels */ | ||
67 | #define OM_CHECK_SUBMODEL 0x02000000 | ||
68 | /* Match all models previous than the one specified */ | ||
69 | #define OM_MATCH_PREVIOUS_MODELS 0x04000000 | ||
70 | /* Ignores the minor revison on newer parts */ | ||
71 | #define OM_IGNORE_MINOR_REVISION 0x08000000 | ||
72 | #define OM_FLAG_MASK 0xff000000 | ||
73 | |||
74 | /* | ||
75 | * CN5XXX models with new revision encoding | ||
76 | */ | ||
77 | #define OCTEON_CN58XX_PASS1_0 0x000d0300 | ||
78 | #define OCTEON_CN58XX_PASS1_1 0x000d0301 | ||
79 | #define OCTEON_CN58XX_PASS1_2 0x000d0303 | ||
80 | #define OCTEON_CN58XX_PASS2_0 0x000d0308 | ||
81 | #define OCTEON_CN58XX_PASS2_1 0x000d0309 | ||
82 | #define OCTEON_CN58XX_PASS2_2 0x000d030a | ||
83 | #define OCTEON_CN58XX_PASS2_3 0x000d030b | ||
84 | |||
85 | #define OCTEON_CN58XX (OCTEON_CN58XX_PASS1_0 | OM_IGNORE_REVISION) | ||
86 | #define OCTEON_CN58XX_PASS1_X (OCTEON_CN58XX_PASS1_0 \ | ||
87 | | OM_IGNORE_MINOR_REVISION) | ||
88 | #define OCTEON_CN58XX_PASS2_X (OCTEON_CN58XX_PASS2_0 \ | ||
89 | | OM_IGNORE_MINOR_REVISION) | ||
90 | #define OCTEON_CN58XX_PASS1 OCTEON_CN58XX_PASS1_X | ||
91 | #define OCTEON_CN58XX_PASS2 OCTEON_CN58XX_PASS2_X | ||
92 | |||
93 | #define OCTEON_CN56XX_PASS1_0 0x000d0400 | ||
94 | #define OCTEON_CN56XX_PASS1_1 0x000d0401 | ||
95 | #define OCTEON_CN56XX_PASS2_0 0x000d0408 | ||
96 | #define OCTEON_CN56XX_PASS2_1 0x000d0409 | ||
97 | |||
98 | #define OCTEON_CN56XX (OCTEON_CN56XX_PASS2_0 | OM_IGNORE_REVISION) | ||
99 | #define OCTEON_CN56XX_PASS1_X (OCTEON_CN56XX_PASS1_0 \ | ||
100 | | OM_IGNORE_MINOR_REVISION) | ||
101 | #define OCTEON_CN56XX_PASS2_X (OCTEON_CN56XX_PASS2_0 \ | ||
102 | | OM_IGNORE_MINOR_REVISION) | ||
103 | #define OCTEON_CN56XX_PASS1 OCTEON_CN56XX_PASS1_X | ||
104 | #define OCTEON_CN56XX_PASS2 OCTEON_CN56XX_PASS2_X | ||
105 | |||
106 | #define OCTEON_CN57XX OCTEON_CN56XX | ||
107 | #define OCTEON_CN57XX_PASS1 OCTEON_CN56XX_PASS1 | ||
108 | #define OCTEON_CN57XX_PASS2 OCTEON_CN56XX_PASS2 | ||
109 | |||
110 | #define OCTEON_CN55XX OCTEON_CN56XX | ||
111 | #define OCTEON_CN55XX_PASS1 OCTEON_CN56XX_PASS1 | ||
112 | #define OCTEON_CN55XX_PASS2 OCTEON_CN56XX_PASS2 | ||
113 | |||
114 | #define OCTEON_CN54XX OCTEON_CN56XX | ||
115 | #define OCTEON_CN54XX_PASS1 OCTEON_CN56XX_PASS1 | ||
116 | #define OCTEON_CN54XX_PASS2 OCTEON_CN56XX_PASS2 | ||
117 | |||
118 | #define OCTEON_CN50XX_PASS1_0 0x000d0600 | ||
119 | |||
120 | #define OCTEON_CN50XX (OCTEON_CN50XX_PASS1_0 | OM_IGNORE_REVISION) | ||
121 | #define OCTEON_CN50XX_PASS1_X (OCTEON_CN50XX_PASS1_0 \ | ||
122 | | OM_IGNORE_MINOR_REVISION) | ||
123 | #define OCTEON_CN50XX_PASS1 OCTEON_CN50XX_PASS1_X | ||
124 | |||
125 | /* | ||
126 | * NOTE: Octeon CN5000F model is not identifiable using the | ||
127 | * OCTEON_IS_MODEL() functions, but are treated as CN50XX. | ||
128 | */ | ||
129 | |||
130 | #define OCTEON_CN52XX_PASS1_0 0x000d0700 | ||
131 | #define OCTEON_CN52XX_PASS2_0 0x000d0708 | ||
132 | |||
133 | #define OCTEON_CN52XX (OCTEON_CN52XX_PASS2_0 | OM_IGNORE_REVISION) | ||
134 | #define OCTEON_CN52XX_PASS1_X (OCTEON_CN52XX_PASS1_0 \ | ||
135 | | OM_IGNORE_MINOR_REVISION) | ||
136 | #define OCTEON_CN52XX_PASS2_X (OCTEON_CN52XX_PASS2_0 \ | ||
137 | | OM_IGNORE_MINOR_REVISION) | ||
138 | #define OCTEON_CN52XX_PASS1 OCTEON_CN52XX_PASS1_X | ||
139 | #define OCTEON_CN52XX_PASS2 OCTEON_CN52XX_PASS2_X | ||
140 | |||
141 | /* | ||
142 | * CN3XXX models with old revision enconding | ||
143 | */ | ||
144 | #define OCTEON_CN38XX_PASS1 0x000d0000 | ||
145 | #define OCTEON_CN38XX_PASS2 0x000d0001 | ||
146 | #define OCTEON_CN38XX_PASS3 0x000d0003 | ||
147 | #define OCTEON_CN38XX (OCTEON_CN38XX_PASS3 | OM_IGNORE_REVISION) | ||
148 | |||
149 | #define OCTEON_CN36XX OCTEON_CN38XX | ||
150 | #define OCTEON_CN36XX_PASS2 OCTEON_CN38XX_PASS2 | ||
151 | #define OCTEON_CN36XX_PASS3 OCTEON_CN38XX_PASS3 | ||
152 | |||
153 | /* The OCTEON_CN31XX matches CN31XX models and the CN3020 */ | ||
154 | #define OCTEON_CN31XX_PASS1 0x000d0100 | ||
155 | #define OCTEON_CN31XX_PASS1_1 0x000d0102 | ||
156 | #define OCTEON_CN31XX (OCTEON_CN31XX_PASS1 | OM_IGNORE_REVISION) | ||
157 | |||
158 | /* | ||
159 | * This model is only used for internal checks, it is not a valid | ||
160 | * model for the OCTEON_MODEL environment variable. This matches the | ||
161 | * CN3010 and CN3005 but NOT the CN3020. | ||
162 | */ | ||
163 | #define OCTEON_CN30XX_PASS1 0x000d0200 | ||
164 | #define OCTEON_CN30XX_PASS1_1 0x000d0202 | ||
165 | #define OCTEON_CN30XX (OCTEON_CN30XX_PASS1 | OM_IGNORE_REVISION) | ||
166 | |||
167 | #define OCTEON_CN3005_PASS1 (0x000d0210 | OM_CHECK_SUBMODEL) | ||
168 | #define OCTEON_CN3005_PASS1_0 (0x000d0210 | OM_CHECK_SUBMODEL) | ||
169 | #define OCTEON_CN3005_PASS1_1 (0x000d0212 | OM_CHECK_SUBMODEL) | ||
170 | #define OCTEON_CN3005 (OCTEON_CN3005_PASS1 | OM_IGNORE_REVISION \ | ||
171 | | OM_CHECK_SUBMODEL) | ||
172 | |||
173 | #define OCTEON_CN3010_PASS1 (0x000d0200 | OM_CHECK_SUBMODEL) | ||
174 | #define OCTEON_CN3010_PASS1_0 (0x000d0200 | OM_CHECK_SUBMODEL) | ||
175 | #define OCTEON_CN3010_PASS1_1 (0x000d0202 | OM_CHECK_SUBMODEL) | ||
176 | #define OCTEON_CN3010 (OCTEON_CN3010_PASS1 | OM_IGNORE_REVISION \ | ||
177 | | OM_CHECK_SUBMODEL) | ||
178 | |||
179 | #define OCTEON_CN3020_PASS1 (0x000d0110 | OM_CHECK_SUBMODEL) | ||
180 | #define OCTEON_CN3020_PASS1_0 (0x000d0110 | OM_CHECK_SUBMODEL) | ||
181 | #define OCTEON_CN3020_PASS1_1 (0x000d0112 | OM_CHECK_SUBMODEL) | ||
182 | #define OCTEON_CN3020 (OCTEON_CN3020_PASS1 | OM_IGNORE_REVISION \ | ||
183 | | OM_CHECK_SUBMODEL) | ||
184 | |||
185 | |||
186 | |||
187 | /* This matches the complete family of CN3xxx CPUs, and not subsequent models */ | ||
188 | #define OCTEON_CN3XXX (OCTEON_CN58XX_PASS1_0 \ | ||
189 | | OM_MATCH_PREVIOUS_MODELS \ | ||
190 | | OM_IGNORE_REVISION) | ||
191 | |||
192 | /* The revision byte (low byte) has two different encodings. | ||
193 | * CN3XXX: | ||
194 | * | ||
195 | * bits | ||
196 | * <7:5>: reserved (0) | ||
197 | * <4>: alternate package | ||
198 | * <3:0>: revision | ||
199 | * | ||
200 | * CN5XXX: | ||
201 | * | ||
202 | * bits | ||
203 | * <7>: reserved (0) | ||
204 | * <6>: alternate package | ||
205 | * <5:3>: major revision | ||
206 | * <2:0>: minor revision | ||
207 | * | ||
208 | */ | ||
209 | |||
210 | /* Masks used for the various types of model/family/revision matching */ | ||
211 | #define OCTEON_38XX_FAMILY_MASK 0x00ffff00 | ||
212 | #define OCTEON_38XX_FAMILY_REV_MASK 0x00ffff0f | ||
213 | #define OCTEON_38XX_MODEL_MASK 0x00ffff10 | ||
214 | #define OCTEON_38XX_MODEL_REV_MASK (OCTEON_38XX_FAMILY_REV_MASK \ | ||
215 | | OCTEON_38XX_MODEL_MASK) | ||
216 | |||
217 | /* CN5XXX and later use different layout of bits in the revision ID field */ | ||
218 | #define OCTEON_58XX_FAMILY_MASK OCTEON_38XX_FAMILY_MASK | ||
219 | #define OCTEON_58XX_FAMILY_REV_MASK 0x00ffff3f | ||
220 | #define OCTEON_58XX_MODEL_MASK 0x00ffffc0 | ||
221 | #define OCTEON_58XX_MODEL_REV_MASK (OCTEON_58XX_FAMILY_REV_MASK \ | ||
222 | | OCTEON_58XX_MODEL_MASK) | ||
223 | #define OCTEON_58XX_MODEL_MINOR_REV_MASK (OCTEON_58XX_MODEL_REV_MASK \ | ||
224 | & 0x00fffff8) | ||
225 | |||
226 | #define __OCTEON_MATCH_MASK__(x, y, z) (((x) & (z)) == ((y) & (z))) | ||
227 | |||
228 | /* NOTE: This is for internal (to this file) use only. */ | ||
229 | static inline int __OCTEON_IS_MODEL_COMPILE__(uint32_t arg_model, | ||
230 | uint32_t chip_model) | ||
231 | { | ||
232 | uint32_t rev_and_sub = OM_IGNORE_REVISION | OM_CHECK_SUBMODEL; | ||
233 | |||
234 | if ((arg_model & OCTEON_38XX_FAMILY_MASK) < OCTEON_CN58XX_PASS1_0) { | ||
235 | if (((arg_model & OM_FLAG_MASK) == rev_and_sub) && | ||
236 | __OCTEON_MATCH_MASK__(chip_model, arg_model, | ||
237 | OCTEON_38XX_MODEL_MASK)) | ||
238 | return 1; | ||
239 | if (((arg_model & OM_FLAG_MASK) == 0) && | ||
240 | __OCTEON_MATCH_MASK__(chip_model, arg_model, | ||
241 | OCTEON_38XX_FAMILY_REV_MASK)) | ||
242 | return 1; | ||
243 | if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_REVISION) && | ||
244 | __OCTEON_MATCH_MASK__(chip_model, arg_model, | ||
245 | OCTEON_38XX_FAMILY_MASK)) | ||
246 | return 1; | ||
247 | if (((arg_model & OM_FLAG_MASK) == OM_CHECK_SUBMODEL) && | ||
248 | __OCTEON_MATCH_MASK__((chip_model), (arg_model), | ||
249 | OCTEON_38XX_MODEL_REV_MASK)) | ||
250 | return 1; | ||
251 | if ((arg_model & OM_MATCH_PREVIOUS_MODELS) && | ||
252 | ((chip_model & OCTEON_38XX_MODEL_MASK) < | ||
253 | (arg_model & OCTEON_38XX_MODEL_MASK))) | ||
254 | return 1; | ||
255 | } else { | ||
256 | if (((arg_model & OM_FLAG_MASK) == rev_and_sub) && | ||
257 | __OCTEON_MATCH_MASK__((chip_model), (arg_model), | ||
258 | OCTEON_58XX_MODEL_MASK)) | ||
259 | return 1; | ||
260 | if (((arg_model & OM_FLAG_MASK) == 0) && | ||
261 | __OCTEON_MATCH_MASK__((chip_model), (arg_model), | ||
262 | OCTEON_58XX_FAMILY_REV_MASK)) | ||
263 | return 1; | ||
264 | if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_MINOR_REVISION) && | ||
265 | __OCTEON_MATCH_MASK__((chip_model), (arg_model), | ||
266 | OCTEON_58XX_MODEL_MINOR_REV_MASK)) | ||
267 | return 1; | ||
268 | if (((arg_model & OM_FLAG_MASK) == OM_IGNORE_REVISION) && | ||
269 | __OCTEON_MATCH_MASK__((chip_model), (arg_model), | ||
270 | OCTEON_58XX_FAMILY_MASK)) | ||
271 | return 1; | ||
272 | if (((arg_model & OM_FLAG_MASK) == OM_CHECK_SUBMODEL) && | ||
273 | __OCTEON_MATCH_MASK__((chip_model), (arg_model), | ||
274 | OCTEON_58XX_MODEL_REV_MASK)) | ||
275 | return 1; | ||
276 | if ((arg_model & OM_MATCH_PREVIOUS_MODELS) && | ||
277 | ((chip_model & OCTEON_58XX_MODEL_MASK) < | ||
278 | (arg_model & OCTEON_58XX_MODEL_MASK))) | ||
279 | return 1; | ||
280 | } | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* forward declarations */ | ||
285 | static inline uint32_t cvmx_get_proc_id(void) __attribute__ ((pure)); | ||
286 | static inline uint64_t cvmx_read_csr(uint64_t csr_addr); | ||
287 | |||
288 | /* NOTE: This for internal use only!!!!! */ | ||
289 | static inline int __octeon_is_model_runtime__(uint32_t model) | ||
290 | { | ||
291 | uint32_t cpuid = cvmx_get_proc_id(); | ||
292 | |||
293 | /* | ||
294 | * Check for special case of mismarked 3005 samples. We only | ||
295 | * need to check if the sub model isn't being ignored. | ||
296 | */ | ||
297 | if ((model & OM_CHECK_SUBMODEL) == OM_CHECK_SUBMODEL) { | ||
298 | if (cpuid == OCTEON_CN3010_PASS1 \ | ||
299 | && (cvmx_read_csr(0x80011800800007B8ull) & (1ull << 34))) | ||
300 | cpuid |= 0x10; | ||
301 | } | ||
302 | return __OCTEON_IS_MODEL_COMPILE__(model, cpuid); | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | * The OCTEON_IS_MODEL macro should be used for all Octeon model | ||
307 | * checking done in a program. This should be kept runtime if at all | ||
308 | * possible. Any compile time (#if OCTEON_IS_MODEL) usage must be | ||
309 | * condtionalized with OCTEON_IS_COMMON_BINARY() if runtime checking | ||
310 | * support is required. | ||
311 | */ | ||
312 | #define OCTEON_IS_MODEL(x) __octeon_is_model_runtime__(x) | ||
313 | #define OCTEON_IS_COMMON_BINARY() 1 | ||
314 | #undef OCTEON_MODEL | ||
315 | |||
316 | const char *octeon_model_get_string(uint32_t chip_id); | ||
317 | const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer); | ||
318 | |||
319 | #include "octeon-feature.h" | ||
320 | |||
321 | #endif /* __OCTEON_MODEL_H__ */ | ||