]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-pow.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-pow.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are
8  *  met:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
12  *
13  *      * Redistributions in binary form must reproduce the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer in the documentation and/or other materials provided
16  *        with the distribution.
17  *
18  *      * Neither the name of Cavium Networks nor the names of
19  *        its contributors may be used to endorse or promote products
20  *        derived from this software without specific prior written
21  *        permission.
22  *
23  *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24  *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25  *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26  *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27  *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28  *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29  *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30  *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31  *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32  *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * Interface to the hardware Packet Order / Work unit.
48  *
49  * <hr>$Revision: 29727 $<hr>
50  */
51
52 #include "cvmx.h"
53 #include "cvmx-pow.h"
54
55 /**
56  * @INTERNAL
57  * This structure stores the internal POW state captured by
58  * cvmx_pow_capture(). It is purposely not exposed to the user
59  * since the format may change without notice.
60  */
61 typedef struct
62 {
63     cvmx_pow_tag_load_resp_t sstatus[16][8];
64     cvmx_pow_tag_load_resp_t smemload[2048][3];
65     cvmx_pow_tag_load_resp_t sindexload[16][4];
66 } __cvmx_pow_dump_t;
67
68 typedef enum
69 {
70     CVMX_POW_LIST_UNKNOWN=0,
71     CVMX_POW_LIST_FREE=1,
72     CVMX_POW_LIST_INPUT=2,
73     CVMX_POW_LIST_CORE=CVMX_POW_LIST_INPUT+8,
74     CVMX_POW_LIST_DESCHED=CVMX_POW_LIST_CORE+16,
75     CVMX_POW_LIST_NOSCHED=CVMX_POW_LIST_DESCHED+16,
76 } __cvmx_pow_list_types_t;
77
78 static const char *__cvmx_pow_list_names[] = {
79     "Unknown",
80     "Free List",
81     "Queue 0", "Queue 1", "Queue 2", "Queue 3",
82     "Queue 4", "Queue 5", "Queue 6", "Queue 7",
83     "Core 0", "Core 1", "Core 2", "Core 3",
84     "Core 4", "Core 5", "Core 6", "Core 7",
85     "Core 8", "Core 9", "Core 10", "Core 11",
86     "Core 12", "Core 13", "Core 14", "Core 15",
87     "Desched 0", "Desched 1", "Desched 2", "Desched 3",
88     "Desched 4", "Desched 5", "Desched 6", "Desched 7",
89     "Desched 8", "Desched 9", "Desched 10", "Desched 11",
90     "Desched 12", "Desched 13", "Desched 14", "Desched 15",
91     "Nosched 0", "Nosched 1", "Nosched 2", "Nosched 3",
92     "Nosched 4", "Nosched 5", "Nosched 6", "Nosched 7",
93     "Nosched 8", "Nosched 9", "Nosched 10", "Nosched 11",
94     "Nosched 12", "Nosched 13", "Nosched 14", "Nosched 15"
95 };
96
97
98 /**
99  * Return the number of POW entries supported by this chip
100  *
101  * @return Number of POW entries
102  */
103 int cvmx_pow_get_num_entries(void)
104 {
105     if (OCTEON_IS_MODEL(OCTEON_CN30XX))
106         return 64;
107     else if (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
108         return 256;
109     else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
110         return 512;
111     else
112         return 2048;
113 }
114
115
116 /**
117  * Store the current POW internal state into the supplied
118  * buffer. It is recommended that you pass a buffer of at least
119  * 128KB. The format of the capture may change based on SDK
120  * version and Octeon chip.
121  *
122  * @param buffer Buffer to store capture into
123  * @param buffer_size
124  *               The size of the supplied buffer
125  *
126  * @return Zero on sucess, negative on failure
127  */
128 int cvmx_pow_capture(void *buffer, int buffer_size)
129 {
130     __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
131     int num_cores;
132     int num_pow_entries = cvmx_pow_get_num_entries();
133     int core;
134     int index;
135     int bits;
136
137     if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
138     {
139         cvmx_dprintf("cvmx_pow_capture: Buffer too small\n");
140         return -1;
141     }
142
143     num_cores = cvmx_octeon_num_cores();
144
145     /* Read all core related state */
146     for (core=0; core<num_cores; core++)
147     {
148         cvmx_pow_load_addr_t load_addr;
149         load_addr.u64 = 0;
150         load_addr.sstatus.mem_region = CVMX_IO_SEG;
151         load_addr.sstatus.is_io = 1;
152         load_addr.sstatus.did = CVMX_OCT_DID_TAG_TAG1;
153         load_addr.sstatus.coreid = core;
154         for (bits=0; bits<8; bits++)
155         {
156             load_addr.sstatus.get_rev = (bits & 1) != 0;
157             load_addr.sstatus.get_cur = (bits & 2) != 0;
158             load_addr.sstatus.get_wqp = (bits & 4) != 0;
159             if ((load_addr.sstatus.get_cur == 0) && load_addr.sstatus.get_rev)
160                 dump->sstatus[core][bits].u64 = -1;
161             else
162                 dump->sstatus[core][bits].u64 = cvmx_read_csr(load_addr.u64);
163         }
164     }
165
166     /* Read all internal POW entries */
167     for (index=0; index<num_pow_entries; index++)
168     {
169         cvmx_pow_load_addr_t load_addr;
170         load_addr.u64 = 0;
171         load_addr.smemload.mem_region = CVMX_IO_SEG;
172         load_addr.smemload.is_io = 1;
173         load_addr.smemload.did = CVMX_OCT_DID_TAG_TAG2;
174         load_addr.smemload.index = index;
175         for (bits=0; bits<3; bits++)
176         {
177             load_addr.smemload.get_des = (bits & 1) != 0;
178             load_addr.smemload.get_wqp = (bits & 2) != 0;
179             dump->smemload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
180         }
181     }
182
183     /* Read all group and queue pointers */
184     for (index=0; index<16; index++)
185     {
186         cvmx_pow_load_addr_t load_addr;
187         load_addr.u64 = 0;
188         load_addr.sindexload.mem_region = CVMX_IO_SEG;
189         load_addr.sindexload.is_io = 1;
190         load_addr.sindexload.did = CVMX_OCT_DID_TAG_TAG3;
191         load_addr.sindexload.qosgrp = index;
192         for (bits=0; bits<4; bits++)
193         {
194             load_addr.sindexload.get_rmt =  (bits & 1) != 0;
195             load_addr.sindexload.get_des_get_tail =  (bits & 2) != 0;
196             /* The first pass only has 8 valid index values */
197             if ((load_addr.sindexload.get_rmt == 0) &&
198                 (load_addr.sindexload.get_des_get_tail == 0) &&
199                 (index >= 8))
200                 dump->sindexload[index][bits].u64 = -1;
201             else
202                 dump->sindexload[index][bits].u64 = cvmx_read_csr(load_addr.u64);
203         }
204     }
205     return 0;
206 }
207
208
209 /**
210  * Function to display a POW internal queue to the user
211  *
212  * @param name       User visible name for the queue
213  * @param name_param Parameter for printf in creating the name
214  * @param valid      Set if the queue contains any elements
215  * @param has_one    Set if the queue contains exactly one element
216  * @param head       The head pointer
217  * @param tail       The tail pointer
218  */
219 static void __cvmx_pow_display_list(const char *name, int name_param, int valid, int has_one, uint64_t head, uint64_t tail)
220 {
221     printf(name, name_param);
222     printf(": ");
223     if (valid)
224     {
225         if (has_one)
226             printf("One element index=%llu(0x%llx)\n", CAST64(head), CAST64(head));
227         else
228             printf("Multiple elements head=%llu(0x%llx) tail=%llu(0x%llx)\n", CAST64(head), CAST64(head), CAST64(tail), CAST64(tail));
229     }
230     else
231         printf("Empty\n");
232 }
233
234
235 /**
236  * Mark which list a POW entry is on. Print a warning message if the
237  * entry is already on a list. This happens if the POW changed while
238  * the capture was running.
239  *
240  * @param entry_num  Entry number to mark
241  * @param entry_type List type
242  * @param entry_list Array to store marks
243  *
244  * @return Zero on success, negative if already on a list
245  */
246 static int __cvmx_pow_entry_mark_list(int entry_num, __cvmx_pow_list_types_t entry_type, uint8_t entry_list[])
247 {
248     if (entry_list[entry_num] == 0)
249     {
250         entry_list[entry_num] = entry_type;
251         return 0;
252     }
253     else
254     {
255         printf("\nWARNING: Entry %d already on list %s, but we tried to add it to %s\n",
256                entry_num, __cvmx_pow_list_names[entry_list[entry_num]], __cvmx_pow_list_names[entry_type]);
257         return -1;
258     }
259 }
260
261
262 /**
263  * Display a list and mark all elements on the list as belonging to
264  * the list.
265  *
266  * @param entry_type Type of the list to display and mark
267  * @param dump       POW capture data
268  * @param entry_list Array to store marks in
269  * @param valid      Set if the queue contains any elements
270  * @param has_one    Set if the queue contains exactly one element
271  * @param head       The head pointer
272  * @param tail       The tail pointer
273  */
274 static void __cvmx_pow_display_list_and_walk(__cvmx_pow_list_types_t entry_type,
275                                              __cvmx_pow_dump_t *dump, uint8_t entry_list[],
276                                              int valid, int has_one, uint64_t head, uint64_t tail)
277 {
278     __cvmx_pow_display_list(__cvmx_pow_list_names[entry_type], 0, valid, has_one, head, tail);
279     if (valid)
280     {
281         if (has_one)
282             __cvmx_pow_entry_mark_list(head, entry_type, entry_list);
283         else
284         {
285             while (head != tail)
286             {
287                 if (__cvmx_pow_entry_mark_list(head, entry_type, entry_list))
288                     break;
289                 head = dump->smemload[head][0].s_smemload0.next_index;
290             }
291             __cvmx_pow_entry_mark_list(tail, entry_type, entry_list);
292         }
293     }
294 }
295
296
297 /**
298  * Dump a POW capture to the console in a human readable format.
299  *
300  * @param buffer POW capture from cvmx_pow_capture()
301  * @param buffer_size
302  *               Size of the buffer
303  */
304 void cvmx_pow_display(void *buffer, int buffer_size)
305 {
306     __cvmx_pow_dump_t *dump = (__cvmx_pow_dump_t*)buffer;
307     int num_pow_entries = cvmx_pow_get_num_entries();
308     int num_cores;
309     int core;
310     int index;
311     uint8_t entry_list[2048];
312
313     if (buffer_size < (int)sizeof(__cvmx_pow_dump_t))
314     {
315         cvmx_dprintf("cvmx_pow_dump: Buffer too small\n");
316         return;
317     }
318
319     memset(entry_list, 0, sizeof(entry_list));
320     num_cores = cvmx_octeon_num_cores();
321
322     printf("POW Display Start\n");
323
324     /* Print the free list info */
325     __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_FREE, dump, entry_list,
326                                      dump->sindexload[0][0].sindexload0.free_val,
327                                      dump->sindexload[0][0].sindexload0.free_one,
328                                      dump->sindexload[0][0].sindexload0.free_head,
329                                      dump->sindexload[0][0].sindexload0.free_tail);
330
331     /* Print the core state */
332     for (core=0; core<num_cores; core++)
333     {
334         const int bit_rev = 1;
335         const int bit_cur = 2;
336         const int bit_wqp = 4;
337         printf("Core %d State:  tag=%s,0x%08x", core,
338                OCT_TAG_TYPE_STRING(dump->sstatus[core][bit_cur].s_sstatus2.tag_type),
339                dump->sstatus[core][bit_cur].s_sstatus2.tag);
340         if (dump->sstatus[core][bit_cur].s_sstatus2.tag_type != CVMX_POW_TAG_TYPE_NULL_NULL)
341         {
342             __cvmx_pow_entry_mark_list(dump->sstatus[core][bit_cur].s_sstatus2.index, CVMX_POW_LIST_CORE + core, entry_list);
343             printf(" grp=%d",                   dump->sstatus[core][bit_cur].s_sstatus2.grp);
344             printf(" wqp=0x%016llx",            CAST64(dump->sstatus[core][bit_cur|bit_wqp].s_sstatus4.wqp));
345             printf(" index=%d",                 dump->sstatus[core][bit_cur].s_sstatus2.index);
346             if (dump->sstatus[core][bit_cur].s_sstatus2.head)
347                 printf(" head");
348             else
349                 printf(" prev=%d", dump->sstatus[core][bit_cur|bit_rev].s_sstatus3.revlink_index);
350             if (dump->sstatus[core][bit_cur].s_sstatus2.tail)
351                 printf(" tail");
352             else
353                 printf(" next=%d", dump->sstatus[core][bit_cur].s_sstatus2.link_index);
354         }
355
356         if (dump->sstatus[core][0].s_sstatus0.pend_switch)
357         {
358             printf(" pend_switch=%d",           dump->sstatus[core][0].s_sstatus0.pend_switch);
359             printf(" pend_switch_full=%d",      dump->sstatus[core][0].s_sstatus0.pend_switch_full);
360             printf(" pend_switch_null=%d",      dump->sstatus[core][0].s_sstatus0.pend_switch_null);
361         }
362
363         if (dump->sstatus[core][0].s_sstatus0.pend_desched)
364         {
365             printf(" pend_desched=%d",          dump->sstatus[core][0].s_sstatus0.pend_desched);
366             printf(" pend_desched_switch=%d",   dump->sstatus[core][0].s_sstatus0.pend_desched_switch);
367             printf(" pend_nosched=%d",          dump->sstatus[core][0].s_sstatus0.pend_nosched);
368             if (dump->sstatus[core][0].s_sstatus0.pend_desched_switch)
369                 printf(" pend_grp=%d",              dump->sstatus[core][0].s_sstatus0.pend_grp);
370         }
371
372         if (dump->sstatus[core][0].s_sstatus0.pend_new_work)
373         {
374             if (dump->sstatus[core][0].s_sstatus0.pend_new_work_wait)
375                 printf(" (Waiting for work)");
376             else
377                 printf(" (Getting work)");
378         }
379         if (dump->sstatus[core][0].s_sstatus0.pend_null_rd)
380             printf(" pend_null_rd=%d",          dump->sstatus[core][0].s_sstatus0.pend_null_rd);
381         if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
382         {
383             printf(" pend_nosched_clr=%d",      dump->sstatus[core][0].s_sstatus0.pend_nosched_clr);
384             printf(" pend_index=%d",            dump->sstatus[core][0].s_sstatus0.pend_index);
385         }
386         if (dump->sstatus[core][0].s_sstatus0.pend_switch ||
387             (dump->sstatus[core][0].s_sstatus0.pend_desched &&
388             dump->sstatus[core][0].s_sstatus0.pend_desched_switch))
389         {
390             printf(" pending tag=%s,0x%08x",
391                    OCT_TAG_TYPE_STRING(dump->sstatus[core][0].s_sstatus0.pend_type),
392                    dump->sstatus[core][0].s_sstatus0.pend_tag);
393         }
394         if (dump->sstatus[core][0].s_sstatus0.pend_nosched_clr)
395             printf(" pend_wqp=0x%016llx\n",     CAST64(dump->sstatus[core][bit_wqp].s_sstatus1.pend_wqp));
396         printf("\n");
397     }
398
399     /* Print out the state of the 16 deschedule lists. Each group has two
400         lists. One for entries marked noshed, the other for normal
401         deschedules */
402     for (index=0; index<16; index++)
403     {
404         __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_NOSCHED + index, dump, entry_list,
405                                 dump->sindexload[index][2].sindexload1.nosched_val,
406                                 dump->sindexload[index][2].sindexload1.nosched_one,
407                                 dump->sindexload[index][2].sindexload1.nosched_head,
408                                 dump->sindexload[index][2].sindexload1.nosched_tail);
409         __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_DESCHED + index, dump, entry_list,
410                                 dump->sindexload[index][2].sindexload1.des_val,
411                                 dump->sindexload[index][2].sindexload1.des_one,
412                                 dump->sindexload[index][2].sindexload1.des_head,
413                                 dump->sindexload[index][2].sindexload1.des_tail);
414     }
415
416     /* Print out the state of the 8 internal input queues */
417     for (index=0; index<8; index++)
418     {
419         __cvmx_pow_display_list_and_walk(CVMX_POW_LIST_INPUT + index, dump, entry_list,
420                                 dump->sindexload[index][0].sindexload0.loc_val,
421                                 dump->sindexload[index][0].sindexload0.loc_one,
422                                 dump->sindexload[index][0].sindexload0.loc_head,
423                                 dump->sindexload[index][0].sindexload0.loc_tail);
424     }
425
426     /* Print out the state of the 16 memory queues */
427     for (index=0; index<8; index++)
428     {
429         const char *name;
430         if (dump->sindexload[index][1].sindexload2.rmt_is_head)
431             name = "Queue %da Memory (is head)";
432         else
433             name = "Queue %da Memory";
434         __cvmx_pow_display_list(name, index,
435                                 dump->sindexload[index][1].sindexload2.rmt_val,
436                                 dump->sindexload[index][1].sindexload2.rmt_one,
437                                 dump->sindexload[index][1].sindexload2.rmt_head,
438                                 dump->sindexload[index][3].sindexload3.rmt_tail);
439         if (dump->sindexload[index+8][1].sindexload2.rmt_is_head)
440             name = "Queue %db Memory (is head)";
441         else
442             name = "Queue %db Memory";
443         __cvmx_pow_display_list(name, index,
444                                 dump->sindexload[index+8][1].sindexload2.rmt_val,
445                                 dump->sindexload[index+8][1].sindexload2.rmt_one,
446                                 dump->sindexload[index+8][1].sindexload2.rmt_head,
447                                 dump->sindexload[index+8][3].sindexload3.rmt_tail);
448     }
449
450     /* Print out each of the internal POW entries. Each entry has a tag, group,
451         wqe, and possibly a next pointer. The next pointer is only valid if this
452         entry isn't make as a tail */
453     for (index=0; index<num_pow_entries; index++)
454     {
455         printf("Entry %d(%-10s): tag=%s,0x%08x grp=%d wqp=0x%016llx", index,
456                __cvmx_pow_list_names[entry_list[index]],
457                OCT_TAG_TYPE_STRING(dump->smemload[index][0].s_smemload0.tag_type),
458                dump->smemload[index][0].s_smemload0.tag,
459                dump->smemload[index][0].s_smemload0.grp,
460                CAST64(dump->smemload[index][2].s_smemload1.wqp));
461         if (dump->smemload[index][0].s_smemload0.tail)
462             printf(" tail");
463         else
464             printf(" next=%d", dump->smemload[index][0].s_smemload0.next_index);
465         if (entry_list[index] >= CVMX_POW_LIST_DESCHED)
466         {
467             printf(" prev=%d", dump->smemload[index][1].s_smemload2.fwd_index);
468             printf(" nosched=%d", dump->smemload[index][1].s_smemload2.nosched);
469             if (dump->smemload[index][1].s_smemload2.pend_switch)
470             {
471                 printf(" pending tag=%s,0x%08x",
472                        OCT_TAG_TYPE_STRING(dump->smemload[index][1].s_smemload2.pend_type),
473                        dump->smemload[index][1].s_smemload2.pend_tag);
474             }
475         }
476         printf("\n");
477     }
478
479     printf("POW Display End\n");
480 }
481