1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Networks (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 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
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 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**************************************/
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-pexp-defs.h>
57 #include "cvmx-error.h"
58 #include "cvmx-error-custom.h"
59 #include "cvmx-pcie.h"
60 #include "cvmx-srio.h"
61 #include "cvmx-interrupt.h"
64 #define MAX_TABLE_SIZE 1024 /* Max number of error status bits we can support */
66 extern int cvmx_error_initialize_cn63xx(void);
67 extern int cvmx_error_initialize_cn63xxp1(void);
68 extern int cvmx_error_initialize_cn58xxp1(void);
69 extern int cvmx_error_initialize_cn58xx(void);
70 extern int cvmx_error_initialize_cn56xxp1(void);
71 extern int cvmx_error_initialize_cn56xx(void);
72 extern int cvmx_error_initialize_cn50xx(void);
73 extern int cvmx_error_initialize_cn52xxp1(void);
74 extern int cvmx_error_initialize_cn52xx(void);
75 extern int cvmx_error_initialize_cn38xxp2(void);
76 extern int cvmx_error_initialize_cn38xx(void);
77 extern int cvmx_error_initialize_cn31xx(void);
78 extern int cvmx_error_initialize_cn30xx(void);
80 /* Each entry in this array represents a status bit function or chain */
81 static CVMX_SHARED cvmx_error_info_t __cvmx_error_table[MAX_TABLE_SIZE];
82 static CVMX_SHARED int __cvmx_error_table_size = 0;
83 static CVMX_SHARED cvmx_error_flags_t __cvmx_error_flags;
85 #define REG_MATCH(h, reg_type, status_addr, status_mask) \
86 ((h->reg_type == reg_type) && (h->status_addr == status_addr) && (h->status_mask == status_mask))
90 * Read a status or enable register from the hardware
92 * @param reg_type Register type to read
93 * @param addr Address to read
95 * @return Result of the read
97 static uint64_t __cvmx_error_read_hw(cvmx_error_register_t reg_type, uint64_t addr)
101 case __CVMX_ERROR_REGISTER_NONE:
103 case CVMX_ERROR_REGISTER_IO64:
104 return cvmx_read_csr(addr);
105 case CVMX_ERROR_REGISTER_IO32:
106 return cvmx_read64_uint32(addr ^ 4);
107 case CVMX_ERROR_REGISTER_PCICONFIG:
108 return cvmx_pcie_cfgx_read(addr>>32, addr&0xffffffffull);
109 case CVMX_ERROR_REGISTER_SRIOMAINT:
112 if (cvmx_srio_config_read32(addr>>32, 0, -1, 0, 0, addr&0xffffffffull, &r))
123 * Write a status or enable register to the hardware
125 * @param reg_type Register type to write
126 * @param addr Address to write
127 * @param value Value to write
129 static void __cvmx_error_write_hw(cvmx_error_register_t reg_type, uint64_t addr, uint64_t value)
133 case __CVMX_ERROR_REGISTER_NONE:
135 case CVMX_ERROR_REGISTER_IO64:
136 cvmx_write_csr(addr, value);
138 case CVMX_ERROR_REGISTER_IO32:
139 cvmx_write64_uint32(addr ^ 4, value);
141 case CVMX_ERROR_REGISTER_PCICONFIG:
142 cvmx_pcie_cfgx_write(addr>>32, addr&0xffffffffull, value);
144 case CVMX_ERROR_REGISTER_SRIOMAINT:
146 cvmx_srio_config_write32(addr>>32, 0, -1, 0, 0, addr&0xffffffffull, value);
154 * Function for processing non leaf error status registers. This function
155 * calls all handlers for this passed register and all children linked
158 * @param info Error register to check
160 * @return Number of error status bits found or zero if no bits were set.
162 int __cvmx_error_decode(const cvmx_error_info_t *info)
169 /* Read the status and enable state */
170 status = __cvmx_error_read_hw(info->reg_type, info->status_addr);
171 if (info->enable_addr)
172 enable = __cvmx_error_read_hw(info->reg_type, info->enable_addr);
176 for (i = 0; i < __cvmx_error_table_size; i++)
178 const cvmx_error_info_t *h = &__cvmx_error_table[i];
179 uint64_t masked_status = status;
181 /* If this is a child of the current register then recurse and process
183 if ((h->parent.reg_type == info->reg_type) &&
184 (h->parent.status_addr == info->status_addr) &&
185 (status & h->parent.status_mask))
186 handled += __cvmx_error_decode(h);
188 if ((h->reg_type != info->reg_type) || (h->status_addr != info->status_addr))
191 /* If the corresponding enable bit is not set then we have nothing to do */
192 if (h->enable_addr && h->enable_mask)
194 if (!(enable & h->enable_mask))
198 /* Apply the mask to eliminate irrelevant bits */
200 masked_status &= h->status_mask;
202 /* Finally call the handler function unless it is this function */
203 if (masked_status && h->func && (h->func != __cvmx_error_decode))
204 handled += h->func(h);
206 /* Ths should be the total errors found */
212 * This error bit handler simply prints a message and clears the status bit
214 * @param info Error register to check
218 int __cvmx_error_display(const cvmx_error_info_t *info)
220 const char *message = (const char *)(long)info->user_info;
221 /* This assumes that all bits in the status register are RO or R/W1C */
222 __cvmx_error_write_hw(info->reg_type, info->status_addr, info->status_mask);
223 cvmx_safe_printf("%s", message);
228 * Initalize the error status system. This should be called once
229 * before any other functions are called. This function adds default
230 * handlers for most all error events but does not enable them. Later
231 * calls to cvmx_error_enable() are needed.
233 * @param flags Optional flags.
235 * @return Zero on success, negative on failure.
237 int cvmx_error_initialize(cvmx_error_flags_t flags)
239 __cvmx_error_flags = flags;
240 if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS2_X))
242 if (cvmx_error_initialize_cn63xx())
245 else if (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))
247 if (cvmx_error_initialize_cn63xxp1())
250 else if (OCTEON_IS_MODEL(OCTEON_CN58XX_PASS1_X))
252 if (cvmx_error_initialize_cn58xxp1())
255 else if (OCTEON_IS_MODEL(OCTEON_CN58XX))
257 if (cvmx_error_initialize_cn58xx())
260 else if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X))
262 if (cvmx_error_initialize_cn56xxp1())
265 else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
267 if (cvmx_error_initialize_cn56xx())
270 else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
272 if (cvmx_error_initialize_cn50xx())
275 else if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
277 if (cvmx_error_initialize_cn52xxp1())
280 else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
282 if (cvmx_error_initialize_cn52xx())
285 else if (OCTEON_IS_MODEL(OCTEON_CN38XX_PASS2))
287 if (cvmx_error_initialize_cn38xxp2())
290 else if (OCTEON_IS_MODEL(OCTEON_CN38XX))
292 if (cvmx_error_initialize_cn38xx())
295 else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
297 if (cvmx_error_initialize_cn31xx())
300 else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
302 if (cvmx_error_initialize_cn30xx())
307 cvmx_warn("cvmx_error_initialize() needs update for this Octeon model\n");
311 if (__cvmx_error_custom_initialize())
314 /* Enable all of the purely internal error sources by default */
315 cvmx_error_enable_group(CVMX_ERROR_GROUP_INTERNAL, 0);
317 /* Enable DDR error reporting based on the memory controllers */
318 if (OCTEON_IS_MODEL(OCTEON_CN56XX))
320 cvmx_l2c_cfg_t l2c_cfg;
321 l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
322 if (l2c_cfg.s.dpres0)
323 cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, 0);
324 if (l2c_cfg.s.dpres1)
325 cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, 1);
328 cvmx_error_enable_group(CVMX_ERROR_GROUP_LMC, 0);
330 /* Old PCI parts don't have a common PCI init, so enable error
331 reporting if the bootloader told us we are a PCI host. PCIe
332 is handled when cvmx_pcie_rc_initialize is called */
333 if (!octeon_has_feature(OCTEON_FEATURE_PCIE) &&
334 (cvmx_sysinfo_get()->bootloader_config_flags & CVMX_BOOTINFO_CFG_FLAG_PCI_HOST))
335 cvmx_error_enable_group(CVMX_ERROR_GROUP_PCI, 0);
337 /* FIXME: Why is this needed for CN63XX? */
338 if (OCTEON_IS_MODEL(OCTEON_CN63XX))
339 cvmx_write_csr(CVMX_PEXP_SLI_INT_SUM, 1);
345 * Poll the error status registers and call the appropriate error
346 * handlers. This should be called in the RSL interrupt handler
347 * for your application or operating system.
349 * @return Number of error handlers called. Zero means this call
350 * found no errors and was spurious.
352 int cvmx_error_poll(void)
356 /* Call all handlers that don't have a parent */
357 for (i = 0; i < __cvmx_error_table_size; i++)
358 if (__cvmx_error_table[i].parent.reg_type == __CVMX_ERROR_REGISTER_NONE)
359 count += __cvmx_error_decode(&__cvmx_error_table[i]);
364 * Register to be called when an error status bit is set. Most users
365 * will not need to call this function as cvmx_error_initialize()
366 * registers default handlers for most error conditions. This function
367 * is normally used to add more handlers without changing the existing
370 * @param new_info Information about the handler for a error register. The
371 * structure passed is copied and can be destroyed after the
372 * call. All members of the structure must be populated, even the
373 * parent information.
375 * @return Zero on success, negative on failure.
377 int cvmx_error_add(const cvmx_error_info_t *new_info)
379 if (__cvmx_error_table_size >= MAX_TABLE_SIZE)
381 cvmx_warn("cvmx-error table full\n");
384 __cvmx_error_table[__cvmx_error_table_size] = *new_info;
385 __cvmx_error_table_size++;
390 * Remove all handlers for a status register and mask. Normally
391 * this function should not be called. Instead a new handler should be
392 * installed to replace the existing handler. In the even that all
393 * reporting of a error bit should be removed, then use this
396 * @param reg_type Type of the status register to remove
398 * Status register to remove.
400 * All handlers for this status register with this mask will be
402 * @param old_info If not NULL, this is filled with information about the handler
405 * @return Zero on success, negative on failure (not found).
407 int cvmx_error_remove(cvmx_error_register_t reg_type,
408 uint64_t status_addr, uint64_t status_mask,
409 cvmx_error_info_t *old_info)
413 for (i = 0; i < __cvmx_error_table_size; i++)
415 cvmx_error_info_t *h = &__cvmx_error_table[i];
416 if (!REG_MATCH(h, reg_type, status_addr, status_mask))
420 memset(h, 0, sizeof(*h));
427 cvmx_warn("cvmx-error remove couldn't find requested register\n");
433 * Change the function and user_info for an existing error status
434 * register. This function should be used to replace the default
435 * handler with an application specific version as needed.
437 * @param reg_type Type of the status register to change
439 * Status register to change.
441 * All handlers for this status register with this mask will be
443 * @param new_func New function to use to handle the error status
444 * @param new_user_info
445 * New user info parameter for the function
446 * @param old_func If not NULL, the old function is returned. Useful for restoring
448 * @param old_user_info
449 * If not NULL, the old user info parameter.
451 * @return Zero on success, negative on failure
453 int cvmx_error_change_handler(cvmx_error_register_t reg_type,
454 uint64_t status_addr, uint64_t status_mask,
455 cvmx_error_func_t new_func, uint64_t new_user_info,
456 cvmx_error_func_t *old_func, uint64_t *old_user_info)
460 for (i = 0; i < __cvmx_error_table_size; i++)
462 cvmx_error_info_t *h = &__cvmx_error_table[i];
463 if (!REG_MATCH(h, reg_type, status_addr, status_mask))
468 *old_user_info = h->user_info;
470 h->user_info = new_user_info;
477 cvmx_warn("cvmx-error change couldn't find requested register\n");
483 * Enable all error registers for a logical group. This should be
484 * called whenever a logical group is brought online.
486 * @param group Logical group to enable
488 * Index for the group as defined in the cvmx_error_group_t
491 * @return Zero on success, negative on failure.
493 int cvmx_error_enable_group(cvmx_error_group_t group, int group_index)
498 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
501 for (i = 0; i < __cvmx_error_table_size; i++)
503 const cvmx_error_info_t *h = &__cvmx_error_table[i];
504 /* Skip entries that have a different group or group index. We
505 also skip entries that don't have an enable */
506 if ((h->group != group) || (h->group_index != group_index) || (!h->enable_addr))
508 /* Skip entries that have flags that don't match the user's
510 if (h->flags && (h->flags != (h->flags & __cvmx_error_flags)))
512 /* Update the enables for this entry */
513 enable = __cvmx_error_read_hw(h->reg_type, h->enable_addr);
514 if (h->reg_type == CVMX_ERROR_REGISTER_PCICONFIG)
515 enable &= ~h->enable_mask; /* PCI bits have reversed polarity */
517 enable |= h->enable_mask;
518 __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
524 * Disable all error registers for a logical group. This should be
525 * called whenever a logical group is brought offline. Many blocks
526 * will report spurious errors when offline unless this function
529 * @param group Logical group to disable
531 * Index for the group as defined in the cvmx_error_group_t
534 * @return Zero on success, negative on failure.
536 int cvmx_error_disable_group(cvmx_error_group_t group, int group_index)
541 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
544 for (i = 0; i < __cvmx_error_table_size; i++)
546 const cvmx_error_info_t *h = &__cvmx_error_table[i];
547 /* Skip entries that have a different group or group index. We
548 also skip entries that don't have an enable */
549 if ((h->group != group) || (h->group_index != group_index) || (!h->enable_addr))
551 /* Update the enables for this entry */
552 enable = __cvmx_error_read_hw(h->reg_type, h->enable_addr);
553 if (h->reg_type == CVMX_ERROR_REGISTER_PCICONFIG)
554 enable |= h->enable_mask; /* PCI bits have reversed polarity */
556 enable &= ~h->enable_mask;
557 __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
563 * Enable all handlers for a specific status register mask.
565 * @param reg_type Type of the status register
567 * Status register address
569 * All handlers for this status register with this mask will be
572 * @return Zero on success, negative on failure.
574 int cvmx_error_enable(cvmx_error_register_t reg_type,
575 uint64_t status_addr, uint64_t status_mask)
580 for (i = 0; i < __cvmx_error_table_size; i++)
582 cvmx_error_info_t *h = &__cvmx_error_table[i];
583 if (!REG_MATCH(h, reg_type, status_addr, status_mask) || !h->enable_addr)
585 enable = __cvmx_error_read_hw(h->reg_type, h->enable_addr);
586 if (h->reg_type == CVMX_ERROR_REGISTER_PCICONFIG)
587 enable &= ~h->enable_mask; /* PCI bits have reversed polarity */
589 enable |= h->enable_mask;
590 __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
591 h->flags &= ~CVMX_ERROR_FLAGS_DISABLED;
598 cvmx_warn("cvmx-error enable couldn't find requested register\n");
604 * Disable all handlers for a specific status register and mask.
606 * @param reg_type Type of the status register
608 * Status register address
610 * All handlers for this status register with this mask will be
613 * @return Zero on success, negative on failure.
615 int cvmx_error_disable(cvmx_error_register_t reg_type,
616 uint64_t status_addr, uint64_t status_mask)
621 for (i = 0; i < __cvmx_error_table_size; i++)
623 cvmx_error_info_t *h = &__cvmx_error_table[i];
624 if (!REG_MATCH(h, reg_type, status_addr, status_mask) || !h->enable_addr)
626 enable = __cvmx_error_read_hw(h->reg_type, h->enable_addr);
627 if (h->reg_type == CVMX_ERROR_REGISTER_PCICONFIG)
628 enable |= h->enable_mask; /* PCI bits have reversed polarity */
630 enable &= ~h->enable_mask;
631 __cvmx_error_write_hw(h->reg_type, h->enable_addr, enable);
632 h->flags |= CVMX_ERROR_FLAGS_DISABLED;
639 cvmx_warn("cvmx-error disable couldn't find requested register\n");