]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/octeon-sdk/cvmx-error.c
Fix link status handling on if_arge upon system boot to allow bootp/NFS to
[FreeBSD/FreeBSD.git] / sys / contrib / octeon-sdk / cvmx-error.c
1 /***********************license start***************
2  * Copyright (c) 2003-2010  Cavium Inc. (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 Inc. 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 INC. 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  * @file
43  *
44  * Interface to the Octeon extended error status.
45  *
46  * <hr>$Revision: 44252 $<hr>
47  */
48 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
49 #include <asm/octeon/cvmx.h>
50 #include <asm/octeon/cvmx-error.h>
51 #include <asm/octeon/cvmx-error-custom.h>
52 #include <asm/octeon/cvmx-pcie.h>
53 #include <asm/octeon/cvmx-srio.h>
54 #include <asm/octeon/cvmx-ciu2-defs.h>
55 #include <asm/octeon/cvmx-dfm-defs.h>
56 #include <asm/octeon/cvmx-lmcx-defs.h>
57 #include <asm/octeon/cvmx-pexp-defs.h>
58 #else
59 #include "cvmx.h"
60 #include "cvmx-error.h"
61 #include "cvmx-error-custom.h"
62 #include "cvmx-pcie.h"
63 #include "cvmx-srio.h"
64 #include "cvmx-interrupt.h"
65 #endif
66
67 #define MAX_TABLE_SIZE 1024   /* Max number of error status bits we can support */
68
69 extern int cvmx_error_initialize_cnf71xx(void);
70 extern int cvmx_error_initialize_cn68xx(void);
71 extern int cvmx_error_initialize_cn68xxp1(void);
72 extern int cvmx_error_initialize_cn66xx(void);
73 extern int cvmx_error_initialize_cn63xx(void);
74 extern int cvmx_error_initialize_cn63xxp1(void);
75 extern int cvmx_error_initialize_cn61xx(void);
76 extern int cvmx_error_initialize_cn58xxp1(void);
77 extern int cvmx_error_initialize_cn58xx(void);
78 extern int cvmx_error_initialize_cn56xxp1(void);
79 extern int cvmx_error_initialize_cn56xx(void);
80 extern int cvmx_error_initialize_cn50xx(void);
81 extern int cvmx_error_initialize_cn52xxp1(void);
82 extern int cvmx_error_initialize_cn52xx(void);
83 extern int cvmx_error_initialize_cn38xxp2(void);
84 extern int cvmx_error_initialize_cn38xx(void);
85 extern int cvmx_error_initialize_cn31xx(void);
86 extern int cvmx_error_initialize_cn30xx(void);
87
88 /* Each entry in this array represents a status bit function or chain */
89 static CVMX_SHARED cvmx_error_info_t __cvmx_error_table[MAX_TABLE_SIZE];
90 static CVMX_SHARED int __cvmx_error_table_size = 0;
91 static CVMX_SHARED cvmx_error_flags_t __cvmx_error_flags;
92
93 #define REG_MATCH(h, reg_type, status_addr, status_mask) \
94     ((h->reg_type == reg_type) && (h->status_addr == status_addr) && (h->status_mask == status_mask))
95
96 /**
97  * @INTERNAL
98  * Read a status or enable register from the hardware
99  *
100  * @param reg_type Register type to read
101  * @param addr     Address to read
102  *
103  * @return Result of the read
104  */
105 static uint64_t __cvmx_error_read_hw(cvmx_error_register_t reg_type, uint64_t addr)
106 {
107     switch (reg_type)
108     {
109         case __CVMX_ERROR_REGISTER_NONE:
110             return 0;
111         case CVMX_ERROR_REGISTER_IO64:
112             return cvmx_read_csr(addr);
113         case CVMX_ERROR_REGISTER_IO32:
114             return cvmx_read64_uint32(addr ^ 4);
115         case CVMX_ERROR_REGISTER_PCICONFIG:
116             return cvmx_pcie_cfgx_read(addr>>32, addr&0xffffffffull);
117         case CVMX_ERROR_REGISTER_SRIOMAINT:
118         {
119             uint32_t r;
120             if (cvmx_srio_config_read32(addr>>32, 0, -1, 0, 0, addr&0xffffffffull, &r))
121                 return 0;
122             else
123                 return r;
124         }
125     }
126     return 0;
127 }
128
129 /**
130  * @INTERNAL
131  * Write a status or enable register to the hardware
132  *
133  * @param reg_type Register type to write
134  * @param addr     Address to write
135  * @param value    Value to write
136  */
137 static void __cvmx_error_write_hw(cvmx_error_register_t reg_type, uint64_t addr, uint64_t value)
138 {
139     switch (reg_type)
140     {
141         case __CVMX_ERROR_REGISTER_NONE:
142             return;
143         case CVMX_ERROR_REGISTER_IO64:
144             cvmx_write_csr(addr, value);
145             return;
146         case CVMX_ERROR_REGISTER_IO32:
147             cvmx_write64_uint32(addr ^ 4, value);
148             return;
149         case CVMX_ERROR_REGISTER_PCICONFIG:
150             cvmx_pcie_cfgx_write(addr>>32, addr&0xffffffffull, value);
151             return;
152         case CVMX_ERROR_REGISTER_SRIOMAINT:
153         {
154             cvmx_srio_config_write32(addr>>32, 0, -1, 0, 0, addr&0xffffffffull, value);
155             return;
156         }
157     }
158 }
159
160 /**
161  * @INTERNAL
162  * Function for processing non leaf error status registers. This function
163  * calls all handlers for this passed register and all children linked
164  * to it.
165  *
166  * @param info   Error register to check
167  *
168  * @return Number of error status bits found or zero if no bits were set.
169  */
170 int __cvmx_error_decode(const cvmx_error_info_t *info)
171 {
172     uint64_t status;
173     uint64_t enable;
174     int i;
175     int handled = 0;
176
177     /* Read the status and enable state */
178     status = __cvmx_error_read_hw(info->reg_type, info->status_addr);
179     if (info->enable_addr)
180         enable = __cvmx_error_read_hw(info->reg_type, info->enable_addr);
181     else
182         enable = 0;
183
184     for (i = 0; i < __cvmx_error_table_size; i++)
185     {
186         const cvmx_error_info_t *h = &__cvmx_error_table[i];
187         uint64_t masked_status = status;
188
189         /* If this is a child of the current register then recurse and process
190             the child */
191         if ((h->parent.reg_type == info->reg_type) &&
192             (h->parent.status_addr == info->status_addr) &&
193             (status & h->parent.status_mask))
194             handled += __cvmx_error_decode(h);
195
196         if ((h->reg_type != info->reg_type) || (h->status_addr != info->status_addr))
197             continue;
198
199         /* If the corresponding enable bit is not set then we have nothing to do */
200         if (h->enable_addr && h->enable_mask)
201         {
202             if (!(enable & h->enable_mask))
203                 continue;
204         }
205
206         /* Apply the mask to eliminate irrelevant bits */
207         if (h->status_mask)
208             masked_status &= h->status_mask;
209
210         /* Finally call the handler function unless it is this function */
211         if (masked_status && h->func && (h->func != __cvmx_error_decode))
212             handled += h->func(h);
213     }
214     /* Ths should be the total errors found */
215     return handled;
216 }
217
218 /**
219  * @INTERNAL
220  * This error bit handler simply prints a message and clears the status bit
221  *
222  * @param info   Error register to check
223  *
224  * @return
225  */
226 int __cvmx_error_display(const cvmx_error_info_t *info)
227 {
228     const char *message = (const char *)(long)info->user_info;
229     /* This assumes that all bits in the status register are RO or R/W1C */
230     __cvmx_error_write_hw(info->reg_type, info->status_addr, info->status_mask);
231     cvmx_safe_printf("%s", message);
232
233     /* Clear the source to reduce the chance for spurious interrupts.  */
234                                                                                 
235     /* CN68XX has an CIU-15786 errata that accessing the ACK registers
236      * can stop interrupts from propagating
237      */
238     if (OCTEON_IS_MODEL(OCTEON_CN68XX))
239         cvmx_read_csr(CVMX_CIU2_INTR_CIU_READY);
240     else if (OCTEON_IS_MODEL(OCTEON_CN68XX))
241         cvmx_read_csr(CVMX_CIU2_ACK_PPX_IP4(cvmx_get_core_num()));
242
243     return 1;
244 }
245
246 /**
247  * Initalize the error status system. This should be called once
248  * before any other functions are called. This function adds default
249  * handlers for most all error events but does not enable them. Later
250  * calls to cvmx_error_enable() are needed.
251  *
252  * @param flags  Optional flags.
253  *
254  * @return Zero on success, negative on failure.
255  */
256 int cvmx_error_initialize(cvmx_error_flags_t flags)
257 {
258     __cvmx_error_flags = flags;
259     if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
260     {
261         if (cvmx_error_initialize_cnf71xx())
262             return -1;
263     }
264     else if (OCTEON_IS_MODEL(OCTEON_CN68XX))
265     {
266         if (cvmx_error_initialize_cn68xx())
267             return -1;
268     }
269     else if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X))
270     {
271         if (cvmx_error_initialize_cn68xxp1())
272             return -1;
273     }
274     else if (OCTEON_IS_MODEL(OCTEON_CN66XX))
275     {
276         if (cvmx_error_initialize_cn66xx())
277             return -1;
278     }
279     else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
280     {
281         if (cvmx_error_initialize_cn63xx())
282             return -1;
283     }
284     else if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
285     {
286         if (cvmx_error_initialize_cn63xxp1())
287             return -1;
288     }
289     else if (OCTEON_IS_MODEL(OCTEON_CN61XX))
290     {
291         if (cvmx_error_initialize_cn61xx())
292             return -1;
293     }
294     else if (OCTEON_IS_MODEL(OCTEON_CN58XX_PASS1_X))
295     {
296         if (cvmx_error_initialize_cn58xxp1())
297             return -1;
298     }
299     else if (OCTEON_IS_MODEL(OCTEON_CN58XX))
300     {
301         if (cvmx_error_initialize_cn58xx())
302             return -1;
303     }
304     else if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X))
305     {
306         if (cvmx_error_initialize_cn56xxp1())
307             return -1;
308     }
309     else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
310     {
311         if (cvmx_error_initialize_cn56xx())
312             return -1;
313     }
314     else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
315     {
316         if (cvmx_error_initialize_cn50xx())
317             return -1;
318     }
319     else if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
320     {
321         if (cvmx_error_initialize_cn52xxp1())
322             return -1;
323     }
324     else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
325     {
326         if (cvmx_error_initialize_cn52xx())
327             return -1;
328     }
329     else if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2))
330     {
331         if (cvmx_error_initialize_cn38xxp2())
332             return -1;
333     }
334     else if (OCTEON_IS_MODEL(OCTEON_CN38XX))
335     {
336         if (cvmx_error_initialize_cn38xx())
337             return -1;
338     }
339     else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
340     {
341         if (cvmx_error_initialize_cn31xx())
342             return -1;
343     }
344     else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
345     {
346         if (cvmx_error_initialize_cn30xx())
347             return -1;
348     }
349     else
350     {
351         cvmx_warn("cvmx_error_initialize() needs update for this Octeon model\n");
352         return -1;
353     }
354
355     if (__cvmx_error_custom_initialize())
356         return -1;
357
358     /* Enable all of the purely internal error sources by default */
359     cvmx_error_enable_group(CVMX_ERROR_GROUP_INTERNAL, 0);
360
361     /* According to workaround for errata KEY-14814 in cn63xx, clearing 
362        SLI_INT_SUM[RML_TO] after enabling KEY interrupts */
363     if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
364         cvmx_write_csr(CVMX_PEXP_SLI_INT_SUM, 1);
365
366     /* Enable DDR error reporting based on the memory controllers */
367     if (OCTEON_IS_MODEL(OCTEON_CN56XX))
368     {
369         cvmx_l2c_cfg_t l2c_cfg;
370         l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
371         if (l2c_cfg.s.dpres0)
372             cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, 0);
373         if (l2c_cfg.s.dpres1)
374             cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, 1);
375     }
376     else
377         cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, 0);
378
379     /* Enable error interrupts for other LMC only if it is
380        available. */
381     if (OCTEON_IS_MODEL(OCTEON_CN68XX))
382     {
383         int i;
384         for (i = 1; i < 4; i++)
385         {
386             cvmx_lmcx_dll_ctl2_t ctl2;
387             ctl2.u64 = cvmx_read_csr(CVMX_LMCX_DLL_CTL2(i));
388             if (ctl2.s.intf_en)
389                 cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, i);
390         } 
391     }
392
393     /* Enable DFM error reporting based on feature availablility */
394     if (octeon_has_feature(OCTEON_FEATURE_DFM))
395     {
396         /* Only configure interrupts if DFM clock is enabled. */
397         cvmx_dfm_fnt_sclk_t dfm_fnt_sclk;
398         dfm_fnt_sclk.u64 = cvmx_read_csr(CVMX_DFM_FNT_SCLK);
399         if (!dfm_fnt_sclk.s.sclkdis)
400         {
401             cvmx_error_enable_group(CVMX_ERROR_GROUP_DFM, 0);
402         }
403     }
404
405     /* Old PCI parts don't have a common PCI init, so enable error
406         reporting if the bootloader told us we are a PCI host. PCIe
407         is handled when cvmx_pcie_rc_initialize is called */
408     if (!octeon_has_feature(OCTEON_FEATURE_PCIE) &&
409         (cvmx_sysinfo_get()->bootloader_config_flags & CVMX_BOOTINFO_CFG_FLAG_PCI_HOST))
410         cvmx_error_enable_group(CVMX_ERROR_GROUP_PCI, 0);
411
412     /* Call poll once to clear out any pending interrupts */
413     cvmx_error_poll();
414
415     return 0;
416 }
417
418 /**
419  * Poll the error status registers and call the appropriate error
420  * handlers. This should be called in the RSL interrupt handler
421  * for your application or operating system.
422  *
423  * @return Number of error handlers called. Zero means this call
424  *         found no errors and was spurious.
425  */
426 int cvmx_error_poll(void)
427 {
428     int i;
429     int count = 0;
430     /* Call all handlers that don't have a parent */
431     for (i = 0; i < __cvmx_error_table_size; i++)
432         if (__cvmx_error_table[i].parent.reg_type == __CVMX_ERROR_REGISTER_NONE)
433             count += __cvmx_error_decode(&__cvmx_error_table[i]);
434     return count;
435 }
436
437 /**
438  * Register to be called when an error status bit is set. Most users
439  * will not need to call this function as cvmx_error_initialize()
440  * registers default handlers for most error conditions. This function
441  * is normally used to add more handlers without changing the existing
442  * handlers.
443  *
444  * @param new_info Information about the handler for a error register. The
445  *                 structure passed is copied and can be destroyed after the
446  *                 call. All members of the structure must be populated, even the
447  *                 parent information.
448  *
449  * @return Zero on success, negative on failure.
450  */
451 int cvmx_error_add(const cvmx_error_info_t *new_info)
452 {
453     if (__cvmx_error_table_size >= MAX_TABLE_SIZE)
454     {
455         cvmx_warn("cvmx-error table full\n");
456         return -1;
457     }
458     __cvmx_error_table[__cvmx_error_table_size] = *new_info;
459     __cvmx_error_table_size++;
460     return 0;
461 }
462
463 /**
464  * Remove all handlers for a status register and mask. Normally
465  * this function should not be called. Instead a new handler should be
466  * installed to replace the existing handler. In the even that all
467  * reporting of a error bit should be removed, then use this
468  * function.
469  *
470  * @param reg_type Type of the status register to remove
471  * @param status_addr
472  *                 Status register to remove.
473  * @param status_mask
474  *                 All handlers for this status register with this mask will be
475  *                 removed.
476  * @param old_info If not NULL, this is filled with information about the handler
477  *                 that was removed.
478  *
479  * @return Zero on success, negative on failure (not found).
480  */
481 int cvmx_error_remove(cvmx_error_register_t reg_type,
482                         uint64_t status_addr, uint64_t status_mask,
483                         cvmx_error_info_t *old_info)
484 {
485     int found = 0;
486     int i;
487     for (i = 0; i < __cvmx_error_table_size; i++)
488     {
489         cvmx_error_info_t *h = &__cvmx_error_table[i];
490         if (!REG_MATCH(h, reg_type, status_addr, status_mask))
491             continue;
492         if (old_info)
493             *old_info = *h;
494         memset(h, 0, sizeof(*h));
495         found = 1;
496     }
497     if (found)
498         return 0;
499     else
500     {
501         cvmx_warn("cvmx-error remove couldn't find requested register\n");
502         return -1;
503     }
504 }
505
506 /**
507  * Change the function and user_info for an existing error status
508  * register. This function should be used to replace the default
509  * handler with an application specific version as needed.
510  *
511  * @param reg_type Type of the status register to change
512  * @param status_addr
513  *                 Status register to change.
514  * @param status_mask
515  *                 All handlers for this status register with this mask will be
516  *                 changed.
517  * @param new_func New function to use to handle the error status
518  * @param new_user_info
519  *                 New user info parameter for the function
520  * @param old_func If not NULL, the old function is returned. Useful for restoring
521  *                 the old handler.
522  * @param old_user_info
523  *                 If not NULL, the old user info parameter.
524  *
525  * @return Zero on success, negative on failure
526  */
527 int cvmx_error_change_handler(cvmx_error_register_t reg_type,
528                         uint64_t status_addr, uint64_t status_mask,
529                         cvmx_error_func_t new_func, uint64_t new_user_info,
530                         cvmx_error_func_t *old_func, uint64_t *old_user_info)
531 {
532     int found = 0;
533     int i;
534     for (i = 0; i < __cvmx_error_table_size; i++)
535     {
536         cvmx_error_info_t *h = &__cvmx_error_table[i];
537         if (!REG_MATCH(h, reg_type, status_addr, status_mask))
538             continue;
539         if (old_func)
540             *old_func = h->func;
541         if (old_user_info)
542             *old_user_info = h->user_info;
543         h->func = new_func;
544         h->user_info = new_user_info;
545         found = 1;
546     }
547     if (found)
548         return 0;
549     else
550     {
551         cvmx_warn("cvmx-error change couldn't find requested register\n");
552         return -1;
553     }
554 }
555
556 /**
557  * Enable all error registers for a logical group. This should be
558  * called whenever a logical group is brought online.
559  *
560  * @param group  Logical group to enable
561  * @param group_index
562  *               Index for the group as defined in the cvmx_error_group_t
563  *               comments.
564  *
565  * @return Zero on success, negative on failure.
566  */
567 int cvmx_error_enable_group(cvmx_error_group_t group, int group_index)
568 {
569     int i;
570     uint64_t enable;
571
572     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
573         return 0;
574
575     for (i = 0; i < __cvmx_error_table_size; i++)
576     {
577         const cvmx_error_info_t *h = &__cvmx_error_table[i];
578         /* SGMII and XAUI has different ipd_port, use the same group_index
579            for both the interfaces */
580         switch(group_index)
581         {
582             case 0x840:
583                 group_index = 0x800;
584                 break;
585             case 0xa40:
586                 group_index = 0xa00;
587                 break;
588             case 0xb40:
589                 group_index = 0xb00;
590                 break;
591             case 0xc40:
592                 group_index = 0xc00;
593                 break;
594         }
595             
596         /* Skip entries that have a different group or group index. We
597             also skip entries that don't have an enable */
598         if ((h->group != group) || (h->group_index != group_index) || (!h->enable_addr))
599             continue;
600         /* Skip entries that have flags that don't match the user's
601             selected flags */
602         if (h->flags && (h->flags != (h->flags & __cvmx_error_flags)))
603             continue;
604         /* Update the enables for this entry */
605         enable = __cvmx_error_read_hw(h->reg_type, h->enable_addr);
606         if (h->reg_type == CVMX_ERROR_REGISTER_PCICONFIG)
607             enable &= ~h->enable_mask; /* PCI bits have reversed polarity */
608         else
609             enable |= h->enable_mask;
610         __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
611     }
612     return 0;
613 }
614
615 /**
616  * Disable all error registers for a logical group. This should be
617  * called whenever a logical group is brought offline. Many blocks
618  * will report spurious errors when offline unless this function
619  * is called.
620  *
621  * @param group  Logical group to disable
622  * @param group_index
623  *               Index for the group as defined in the cvmx_error_group_t
624  *               comments.
625  *
626  * @return Zero on success, negative on failure.
627  */
628 int cvmx_error_disable_group(cvmx_error_group_t group, int group_index)
629 {
630     int i;
631     uint64_t enable;
632
633     if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
634         return 0;
635
636     for (i = 0; i < __cvmx_error_table_size; i++)
637     {
638         const cvmx_error_info_t *h = &__cvmx_error_table[i];
639
640         /* SGMII and XAUI has different ipd_port, use the same group_index
641            for both the interfaces */
642         switch(group_index)
643         {
644             case 0x840:
645                 group_index = 0x800;
646                 break;
647             case 0xa40:
648                 group_index = 0xa00;
649                 break;
650             case 0xb40:
651                 group_index = 0xb00;
652                 break;
653             case 0xc40:
654                 group_index = 0xc00;
655                 break;
656         }
657         /* Skip entries that have a different group or group index. We
658             also skip entries that don't have an enable */
659         if ((h->group != group) || (h->group_index != group_index) || (!h->enable_addr))
660             continue;
661         /* Update the enables for this entry */
662         enable = __cvmx_error_read_hw(h->reg_type, h->enable_addr);
663         if (h->reg_type == CVMX_ERROR_REGISTER_PCICONFIG)
664             enable |= h->enable_mask; /* PCI bits have reversed polarity */
665         else
666             enable &= ~h->enable_mask;
667         __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
668     }
669     return 0;
670 }
671
672 /**
673  * Enable all handlers for a specific status register mask.
674  *
675  * @param reg_type Type of the status register
676  * @param status_addr
677  *                 Status register address
678  * @param status_mask
679  *                 All handlers for this status register with this mask will be
680  *                 enabled.
681  *
682  * @return Zero on success, negative on failure.
683  */
684 int cvmx_error_enable(cvmx_error_register_t reg_type,
685                         uint64_t status_addr, uint64_t status_mask)
686 {
687     int found = 0;
688     int i;
689     uint64_t enable;
690     for (i = 0; i < __cvmx_error_table_size; i++)
691     {
692         cvmx_error_info_t *h = &__cvmx_error_table[i];
693         if (!REG_MATCH(h, reg_type, status_addr, status_mask) || !h->enable_addr)
694             continue;
695         enable = __cvmx_error_read_hw(h->reg_type, h->enable_addr);
696         if (h->reg_type == CVMX_ERROR_REGISTER_PCICONFIG)
697             enable &= ~h->enable_mask; /* PCI bits have reversed polarity */
698         else
699             enable |= h->enable_mask;
700         __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
701         h->flags &= ~CVMX_ERROR_FLAGS_DISABLED;
702         found = 1;
703     }
704     if (found)
705         return 0;
706     else
707     {
708         cvmx_warn("cvmx-error enable couldn't find requested register\n");
709         return -1;
710     }
711 }
712
713 /**
714  * Disable all handlers for a specific status register and mask.
715  *
716  * @param reg_type Type of the status register
717  * @param status_addr
718  *                 Status register address
719  * @param status_mask
720  *                 All handlers for this status register with this mask will be
721  *                 disabled.
722  *
723  * @return Zero on success, negative on failure.
724  */
725 int cvmx_error_disable(cvmx_error_register_t reg_type,
726                         uint64_t status_addr, uint64_t status_mask)
727 {
728     int found = 0;
729     int i;
730     uint64_t enable;
731     for (i = 0; i < __cvmx_error_table_size; i++)
732     {
733         cvmx_error_info_t *h = &__cvmx_error_table[i];
734         if (!REG_MATCH(h, reg_type, status_addr, status_mask) || !h->enable_addr)
735             continue;
736         enable = __cvmx_error_read_hw(h->reg_type, h->enable_addr);
737         if (h->reg_type == CVMX_ERROR_REGISTER_PCICONFIG)
738             enable |= h->enable_mask; /* PCI bits have reversed polarity */
739         else
740             enable &= ~h->enable_mask;
741         __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
742         h->flags |= CVMX_ERROR_FLAGS_DISABLED;
743         found = 1;
744     }
745     if (found)
746         return 0;
747     else
748     {
749         cvmx_warn("cvmx-error disable couldn't find requested register\n");
750         return -1;
751     }
752 }
753
754
755 /**
756  * Find the handler for a specific status register and mask
757  *
758  * @param status_addr
759  *                Status register address
760  *
761  * @return  Return the handler on success or null on failure.
762  */
763 cvmx_error_info_t *cvmx_error_get_index(uint64_t status_addr)
764 {
765     int i;
766     for (i = 0; i < __cvmx_error_table_size; i++)
767     {
768         if (__cvmx_error_table[i].status_addr == status_addr)
769             return &__cvmx_error_table[i];
770     }
771
772     return NULL;
773 }