1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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
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
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**************************************/
44 * Interface to the Octeon extended error status.
46 * <hr>$Revision: 44252 $<hr>
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>
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"
67 #define MAX_TABLE_SIZE 1024 /* Max number of error status bits we can support */
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);
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;
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))
98 * Read a status or enable register from the hardware
100 * @param reg_type Register type to read
101 * @param addr Address to read
103 * @return Result of the read
105 static uint64_t __cvmx_error_read_hw(cvmx_error_register_t reg_type, uint64_t addr)
109 case __CVMX_ERROR_REGISTER_NONE:
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:
120 if (cvmx_srio_config_read32(addr>>32, 0, -1, 0, 0, addr&0xffffffffull, &r))
131 * Write a status or enable register to the hardware
133 * @param reg_type Register type to write
134 * @param addr Address to write
135 * @param value Value to write
137 static void __cvmx_error_write_hw(cvmx_error_register_t reg_type, uint64_t addr, uint64_t value)
141 case __CVMX_ERROR_REGISTER_NONE:
143 case CVMX_ERROR_REGISTER_IO64:
144 cvmx_write_csr(addr, value);
146 case CVMX_ERROR_REGISTER_IO32:
147 cvmx_write64_uint32(addr ^ 4, value);
149 case CVMX_ERROR_REGISTER_PCICONFIG:
150 cvmx_pcie_cfgx_write(addr>>32, addr&0xffffffffull, value);
152 case CVMX_ERROR_REGISTER_SRIOMAINT:
154 cvmx_srio_config_write32(addr>>32, 0, -1, 0, 0, addr&0xffffffffull, value);
162 * Function for processing non leaf error status registers. This function
163 * calls all handlers for this passed register and all children linked
166 * @param info Error register to check
168 * @return Number of error status bits found or zero if no bits were set.
170 int __cvmx_error_decode(const cvmx_error_info_t *info)
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);
184 for (i = 0; i < __cvmx_error_table_size; i++)
186 const cvmx_error_info_t *h = &__cvmx_error_table[i];
187 uint64_t masked_status = status;
189 /* If this is a child of the current register then recurse and process
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);
196 if ((h->reg_type != info->reg_type) || (h->status_addr != info->status_addr))
199 /* If the corresponding enable bit is not set then we have nothing to do */
200 if (h->enable_addr && h->enable_mask)
202 if (!(enable & h->enable_mask))
206 /* Apply the mask to eliminate irrelevant bits */
208 masked_status &= h->status_mask;
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);
214 /* Ths should be the total errors found */
220 * This error bit handler simply prints a message and clears the status bit
222 * @param info Error register to check
226 int __cvmx_error_display(const cvmx_error_info_t *info)
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);
233 /* Clear the source to reduce the chance for spurious interrupts. */
235 /* CN68XX has an CIU-15786 errata that accessing the ACK registers
236 * can stop interrupts from propagating
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()));
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.
252 * @param flags Optional flags.
254 * @return Zero on success, negative on failure.
256 int cvmx_error_initialize(cvmx_error_flags_t flags)
258 __cvmx_error_flags = flags;
259 if (OCTEON_IS_MODEL(OCTEON_CNF71XX))
261 if (cvmx_error_initialize_cnf71xx())
264 else if (OCTEON_IS_MODEL(OCTEON_CN68XX))
266 if (cvmx_error_initialize_cn68xx())
269 else if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X))
271 if (cvmx_error_initialize_cn68xxp1())
274 else if (OCTEON_IS_MODEL(OCTEON_CN66XX))
276 if (cvmx_error_initialize_cn66xx())
279 else if (OCTEON_IS_MODEL(OCTEON_CN63XX))
281 if (cvmx_error_initialize_cn63xx())
284 else if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
286 if (cvmx_error_initialize_cn63xxp1())
289 else if (OCTEON_IS_MODEL(OCTEON_CN61XX))
291 if (cvmx_error_initialize_cn61xx())
294 else if (OCTEON_IS_MODEL(OCTEON_CN58XX_PASS1_X))
296 if (cvmx_error_initialize_cn58xxp1())
299 else if (OCTEON_IS_MODEL(OCTEON_CN58XX))
301 if (cvmx_error_initialize_cn58xx())
304 else if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X))
306 if (cvmx_error_initialize_cn56xxp1())
309 else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
311 if (cvmx_error_initialize_cn56xx())
314 else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
316 if (cvmx_error_initialize_cn50xx())
319 else if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
321 if (cvmx_error_initialize_cn52xxp1())
324 else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
326 if (cvmx_error_initialize_cn52xx())
329 else if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2))
331 if (cvmx_error_initialize_cn38xxp2())
334 else if (OCTEON_IS_MODEL(OCTEON_CN38XX))
336 if (cvmx_error_initialize_cn38xx())
339 else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
341 if (cvmx_error_initialize_cn31xx())
344 else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
346 if (cvmx_error_initialize_cn30xx())
351 cvmx_warn("cvmx_error_initialize() needs update for this Octeon model\n");
355 if (__cvmx_error_custom_initialize())
358 /* Enable all of the purely internal error sources by default */
359 cvmx_error_enable_group(CVMX_ERROR_GROUP_INTERNAL, 0);
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);
366 /* Enable DDR error reporting based on the memory controllers */
367 if (OCTEON_IS_MODEL(OCTEON_CN56XX))
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);
377 cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, 0);
379 /* Enable error interrupts for other LMC only if it is
381 if (OCTEON_IS_MODEL(OCTEON_CN68XX))
384 for (i = 1; i < 4; i++)
386 cvmx_lmcx_dll_ctl2_t ctl2;
387 ctl2.u64 = cvmx_read_csr(CVMX_LMCX_DLL_CTL2(i));
389 cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, i);
393 /* Enable DFM error reporting based on feature availablility */
394 if (octeon_has_feature(OCTEON_FEATURE_DFM))
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)
401 cvmx_error_enable_group(CVMX_ERROR_GROUP_DFM, 0);
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);
412 /* Call poll once to clear out any pending interrupts */
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.
423 * @return Number of error handlers called. Zero means this call
424 * found no errors and was spurious.
426 int cvmx_error_poll(void)
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]);
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
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.
449 * @return Zero on success, negative on failure.
451 int cvmx_error_add(const cvmx_error_info_t *new_info)
453 if (__cvmx_error_table_size >= MAX_TABLE_SIZE)
455 cvmx_warn("cvmx-error table full\n");
458 __cvmx_error_table[__cvmx_error_table_size] = *new_info;
459 __cvmx_error_table_size++;
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
470 * @param reg_type Type of the status register to remove
472 * Status register to remove.
474 * All handlers for this status register with this mask will be
476 * @param old_info If not NULL, this is filled with information about the handler
479 * @return Zero on success, negative on failure (not found).
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)
487 for (i = 0; i < __cvmx_error_table_size; i++)
489 cvmx_error_info_t *h = &__cvmx_error_table[i];
490 if (!REG_MATCH(h, reg_type, status_addr, status_mask))
494 memset(h, 0, sizeof(*h));
501 cvmx_warn("cvmx-error remove couldn't find requested register\n");
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.
511 * @param reg_type Type of the status register to change
513 * Status register to change.
515 * All handlers for this status register with this mask will be
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
522 * @param old_user_info
523 * If not NULL, the old user info parameter.
525 * @return Zero on success, negative on failure
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)
534 for (i = 0; i < __cvmx_error_table_size; i++)
536 cvmx_error_info_t *h = &__cvmx_error_table[i];
537 if (!REG_MATCH(h, reg_type, status_addr, status_mask))
542 *old_user_info = h->user_info;
544 h->user_info = new_user_info;
551 cvmx_warn("cvmx-error change couldn't find requested register\n");
557 * Enable all error registers for a logical group. This should be
558 * called whenever a logical group is brought online.
560 * @param group Logical group to enable
562 * Index for the group as defined in the cvmx_error_group_t
565 * @return Zero on success, negative on failure.
567 int cvmx_error_enable_group(cvmx_error_group_t group, int group_index)
572 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
575 for (i = 0; i < __cvmx_error_table_size; i++)
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 */
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))
600 /* Skip entries that have flags that don't match the user's
602 if (h->flags && (h->flags != (h->flags & __cvmx_error_flags)))
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 */
609 enable |= h->enable_mask;
610 __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
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
621 * @param group Logical group to disable
623 * Index for the group as defined in the cvmx_error_group_t
626 * @return Zero on success, negative on failure.
628 int cvmx_error_disable_group(cvmx_error_group_t group, int group_index)
633 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
636 for (i = 0; i < __cvmx_error_table_size; i++)
638 const cvmx_error_info_t *h = &__cvmx_error_table[i];
640 /* SGMII and XAUI has different ipd_port, use the same group_index
641 for both the interfaces */
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))
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 */
666 enable &= ~h->enable_mask;
667 __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
673 * Enable all handlers for a specific status register mask.
675 * @param reg_type Type of the status register
677 * Status register address
679 * All handlers for this status register with this mask will be
682 * @return Zero on success, negative on failure.
684 int cvmx_error_enable(cvmx_error_register_t reg_type,
685 uint64_t status_addr, uint64_t status_mask)
690 for (i = 0; i < __cvmx_error_table_size; i++)
692 cvmx_error_info_t *h = &__cvmx_error_table[i];
693 if (!REG_MATCH(h, reg_type, status_addr, status_mask) || !h->enable_addr)
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 */
699 enable |= h->enable_mask;
700 __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
701 h->flags &= ~CVMX_ERROR_FLAGS_DISABLED;
708 cvmx_warn("cvmx-error enable couldn't find requested register\n");
714 * Disable all handlers for a specific status register and mask.
716 * @param reg_type Type of the status register
718 * Status register address
720 * All handlers for this status register with this mask will be
723 * @return Zero on success, negative on failure.
725 int cvmx_error_disable(cvmx_error_register_t reg_type,
726 uint64_t status_addr, uint64_t status_mask)
731 for (i = 0; i < __cvmx_error_table_size; i++)
733 cvmx_error_info_t *h = &__cvmx_error_table[i];
734 if (!REG_MATCH(h, reg_type, status_addr, status_mask) || !h->enable_addr)
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 */
740 enable &= ~h->enable_mask;
741 __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
742 h->flags |= CVMX_ERROR_FLAGS_DISABLED;
749 cvmx_warn("cvmx-error disable couldn't find requested register\n");
756 * Find the handler for a specific status register and mask
759 * Status register address
761 * @return Return the handler on success or null on failure.
763 cvmx_error_info_t *cvmx_error_get_index(uint64_t status_addr)
766 for (i = 0; i < __cvmx_error_table_size; i++)
768 if (__cvmx_error_table[i].status_addr == status_addr)
769 return &__cvmx_error_table[i];