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