123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /*
- * Copyright (c) 2021-2022, NVIDIA Corporation. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- /*
- * Driver for GIC-600AE Fault Management Unit
- */
- #include <assert.h>
- #include <inttypes.h>
- #include <arch_helpers.h>
- #include <common/debug.h>
- #include <drivers/arm/gic600ae_fmu.h>
- #include <drivers/arm/gicv3.h>
- /* GIC-600 AE FMU specific register offsets */
- /* GIC-600 AE FMU specific macros */
- #define FMU_ERRIDR_NUM U(44)
- #define FMU_ERRIDR_NUM_MASK U(0xFFFF)
- /* Safety mechanisms for GICD block */
- static char *gicd_sm_info[] = {
- "Reserved",
- "GICD dual lockstep error",
- "GICD AXI4 slave interface error",
- "GICD-PPI AXI4-Stream interface error",
- "GICD-ITS AXI4-Stream interface error",
- "GICD-SPI-Collator AXI4-Stream interface error",
- "GICD AXI4 master interface error",
- "SPI RAM DED error",
- "SGI RAM DED error",
- "Reserved",
- "LPI RAM DED error",
- "GICD-remote-GICD AXI4-Stream interface error",
- "GICD Q-Channel interface error",
- "GICD P-Channel interface error",
- "SPI RAM address decode error",
- "SGI RAM address decode error",
- "Reserved",
- "LPI RAM address decode error",
- "FMU dual lockstep error",
- "FMU ping ACK error",
- "FMU APB parity error",
- "GICD-Wake AXI4-Stream interface error",
- "GICD PageOffset or Chip ID error",
- "MBIST REQ error",
- "SPI RAM SEC error",
- "SGI RAM SEC error",
- "Reserved",
- "LPI RAM SEC error",
- "User custom SM0 error",
- "User custom SM1 error",
- "GICD-ITS Monolithic switch error",
- "GICD-ITS Q-Channel interface error",
- "GICD-ITS Monolithic interface error",
- "GICD FMU ClkGate override"
- };
- /* Safety mechanisms for PPI block */
- static char *ppi_sm_info[] = {
- "Reserved",
- "PPI dual lockstep error",
- "PPI-GICD AXI4-Stream interface error",
- "PPI-CPU-IF AXI4-Stream interface error",
- "PPI Q-Channel interface error",
- "PPI RAM DED error",
- "PPI RAM address decode error",
- "PPI RAM SEC error",
- "PPI User0 SM",
- "PPI User1 SM",
- "MBIST REQ error",
- "PPI interrupt parity protection error",
- "PPI FMU ClkGate override"
- };
- /* Safety mechanisms for ITS block */
- static char *its_sm_info[] = {
- "Reserved",
- "ITS dual lockstep error",
- "ITS-GICD AXI4-Stream interface error",
- "ITS AXI4 slave interface error",
- "ITS AXI4 master interface error",
- "ITS Q-Channel interface error",
- "ITS RAM DED error",
- "ITS RAM address decode error",
- "Bypass ACE switch error",
- "ITS RAM SEC error",
- "ITS User0 SM",
- "ITS User1 SM",
- "ITS-GICD Monolithic interface error",
- "MBIST REQ error",
- "ITS FMU ClkGate override"
- };
- /* Safety mechanisms for SPI Collator block */
- static char *spicol_sm_info[] = {
- "Reserved",
- "SPI Collator dual lockstep error",
- "SPI-Collator-GICD AXI4-Stream interface error",
- "SPI Collator Q-Channel interface error",
- "SPI Collator Q-Channel clock error",
- "SPI interrupt parity error"
- };
- /* Safety mechanisms for Wake Request block */
- static char *wkrqst_sm_info[] = {
- "Reserved",
- "Wake dual lockstep error",
- "Wake-GICD AXI4-Stream interface error"
- };
- /* Helper function to find detailed information for a specific IERR */
- static char __unused *ras_ierr_to_str(unsigned int blkid, unsigned int ierr)
- {
- char *str = NULL;
- /* Find the correct record */
- switch (blkid) {
- case FMU_BLK_GICD:
- assert(ierr < ARRAY_SIZE(gicd_sm_info));
- str = gicd_sm_info[ierr];
- break;
- case FMU_BLK_SPICOL:
- assert(ierr < ARRAY_SIZE(spicol_sm_info));
- str = spicol_sm_info[ierr];
- break;
- case FMU_BLK_WAKERQ:
- assert(ierr < ARRAY_SIZE(wkrqst_sm_info));
- str = wkrqst_sm_info[ierr];
- break;
- case FMU_BLK_ITS0...FMU_BLK_ITS7:
- assert(ierr < ARRAY_SIZE(its_sm_info));
- str = its_sm_info[ierr];
- break;
- case FMU_BLK_PPI0...FMU_BLK_PPI31:
- assert(ierr < ARRAY_SIZE(ppi_sm_info));
- str = ppi_sm_info[ierr];
- break;
- default:
- assert(false);
- break;
- }
- return str;
- }
- /*
- * Probe for error in memory-mapped registers containing error records.
- * Upon detecting an error, set probe data to the index of the record
- * in error, and return 1; otherwise, return 0.
- */
- int gic600_fmu_probe(uint64_t base, int *probe_data)
- {
- uint64_t gsr;
- assert(base != 0UL);
- /*
- * Read ERR_GSR to find the error record 'M'
- */
- gsr = gic_fmu_read_errgsr(base);
- if (gsr == U(0)) {
- return 0;
- }
- /* Return the index of the record in error */
- if (probe_data != NULL) {
- *probe_data = (int)__builtin_ctzll(gsr);
- }
- return 1;
- }
- /*
- * The handler function to read RAS records and find the safety
- * mechanism with the error.
- */
- int gic600_fmu_ras_handler(uint64_t base, int probe_data)
- {
- uint64_t errstatus;
- unsigned int blkid = (unsigned int)probe_data, ierr, serr;
- assert(base != 0UL);
- /*
- * FMU_ERRGSR indicates the ID of the GIC
- * block that faulted.
- */
- assert(blkid <= FMU_BLK_PPI31);
- /*
- * Find more information by reading FMU_ERR<M>STATUS
- * register
- */
- errstatus = gic_fmu_read_errstatus(base, blkid);
- /*
- * If FMU_ERR<M>STATUS.V is set to 0, no RAS records
- * need to be scanned.
- */
- if ((errstatus & FMU_ERRSTATUS_V_BIT) == U(0)) {
- return 0;
- }
- /*
- * FMU_ERR<M>STATUS.IERR indicates which Safety Mechanism
- * reported the error.
- */
- ierr = (errstatus >> FMU_ERRSTATUS_IERR_SHIFT) &
- FMU_ERRSTATUS_IERR_MASK;
- /*
- * FMU_ERR<M>STATUS.SERR indicates architecturally
- * defined primary error code.
- */
- serr = errstatus & FMU_ERRSTATUS_SERR_MASK;
- ERROR("**************************************\n");
- ERROR("RAS %s Error detected by GIC600 AE FMU\n",
- ((errstatus & FMU_ERRSTATUS_UE_BIT) != 0U) ?
- "Uncorrectable" : "Corrected");
- ERROR("\tStatus = 0x%lx \n", errstatus);
- ERROR("\tBlock ID = 0x%x\n", blkid);
- ERROR("\tSafety Mechanism ID = 0x%x (%s)\n", ierr,
- ras_ierr_to_str(blkid, ierr));
- ERROR("\tArchitecturally defined primary error code = 0x%x\n",
- serr);
- ERROR("**************************************\n");
- /* Clear FMU_ERR<M>STATUS */
- gic_fmu_write_errstatus(base, probe_data, errstatus);
- return 0;
- }
- /*
- * Initialization sequence for the FMU
- *
- * 1. enable error detection for error records that are passed in the blk_present_mask
- * 2. enable MBIST REQ and FMU Clk Gate override safety mechanisms for error records
- * that are present on the platform
- *
- * The platforms are expected to pass `errctlr_ce_en` and `errctlr_ue_en`.
- */
- void gic600_fmu_init(uint64_t base, uint64_t blk_present_mask,
- bool errctlr_ce_en, bool errctlr_ue_en)
- {
- unsigned int num_blk = gic_fmu_read_erridr(base) & FMU_ERRIDR_NUM_MASK;
- uint64_t errctlr;
- uint32_t smen;
- INFO("GIC600-AE FMU supports %d error records\n", num_blk);
- assert(num_blk == FMU_ERRIDR_NUM);
- /* sanitize block present mask */
- blk_present_mask &= FMU_BLK_PRESENT_MASK;
- /* Enable error detection for all error records */
- for (unsigned int i = 0U; i < num_blk; i++) {
- /*
- * Disable all safety mechanisms for blocks that are not
- * present and skip the next steps.
- */
- if ((blk_present_mask & BIT(i)) == 0U) {
- gic_fmu_disable_all_sm_blkid(base, i);
- continue;
- }
- /* Read the error record control register */
- errctlr = gic_fmu_read_errctlr(base, i);
- /* Enable error reporting and logging, if it is disabled */
- if ((errctlr & FMU_ERRCTLR_ED_BIT) == 0U) {
- errctlr |= FMU_ERRCTLR_ED_BIT;
- }
- /* Enable client provided ERRCTLR settings */
- errctlr |= (errctlr_ce_en ? (FMU_ERRCTLR_CI_BIT | FMU_ERRCTLR_CE_EN_BIT) : 0);
- errctlr |= (errctlr_ue_en ? FMU_ERRCTLR_UI_BIT : 0U);
- gic_fmu_write_errctlr(base, i, errctlr);
- }
- /*
- * Enable MBIST REQ error and FMU CLK gate override safety mechanisms for
- * all blocks
- *
- * GICD, SMID 23 and SMID 33
- * PPI, SMID 10 and SMID 12
- * ITS, SMID 13 and SMID 14
- */
- if ((blk_present_mask & BIT(FMU_BLK_GICD)) != 0U) {
- smen = (GICD_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
- (FMU_BLK_GICD << FMU_SMEN_BLK_SHIFT) |
- FMU_SMEN_EN_BIT;
- gic_fmu_write_smen(base, smen);
- smen = (GICD_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
- (FMU_BLK_GICD << FMU_SMEN_BLK_SHIFT) |
- FMU_SMEN_EN_BIT;
- gic_fmu_write_smen(base, smen);
- }
- for (unsigned int i = FMU_BLK_PPI0; i < FMU_BLK_PPI31; i++) {
- if ((blk_present_mask & BIT(i)) != 0U) {
- smen = (PPI_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
- (i << FMU_SMEN_BLK_SHIFT) |
- FMU_SMEN_EN_BIT;
- gic_fmu_write_smen(base, smen);
- smen = (PPI_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
- (i << FMU_SMEN_BLK_SHIFT) |
- FMU_SMEN_EN_BIT;
- gic_fmu_write_smen(base, smen);
- }
- }
- for (unsigned int i = FMU_BLK_ITS0; i < FMU_BLK_ITS7; i++) {
- if ((blk_present_mask & BIT(i)) != 0U) {
- smen = (ITS_MBIST_REQ_ERROR << FMU_SMEN_SMID_SHIFT) |
- (i << FMU_SMEN_BLK_SHIFT) |
- FMU_SMEN_EN_BIT;
- gic_fmu_write_smen(base, smen);
- smen = (ITS_FMU_CLKGATE_ERROR << FMU_SMEN_SMID_SHIFT) |
- (i << FMU_SMEN_BLK_SHIFT) |
- FMU_SMEN_EN_BIT;
- gic_fmu_write_smen(base, smen);
- }
- }
- }
- /*
- * This function enable the GICD background ping engine. The GICD sends ping
- * messages to each remote GIC block, and expects a PING_ACK back within the
- * specified timeout. Pings need to be enabled after programming the timeout
- * value.
- */
- void gic600_fmu_enable_ping(uint64_t base, uint64_t blk_present_mask,
- unsigned int timeout_val, unsigned int interval_diff)
- {
- /*
- * Populate the PING Mask to skip a specific block while generating
- * background ping messages and enable the ping mechanism.
- */
- gic_fmu_write_pingmask(base, ~blk_present_mask);
- gic_fmu_write_pingctlr(base, (interval_diff << FMU_PINGCTLR_INTDIFF_SHIFT) |
- (timeout_val << FMU_PINGCTLR_TIMEOUTVAL_SHIFT) | FMU_PINGCTLR_EN_BIT);
- }
- /* Print the safety mechanism description for a given block */
- void gic600_fmu_print_sm_info(uint64_t base, unsigned int blk, unsigned int smid)
- {
- if (blk == FMU_BLK_GICD && smid <= FMU_SMID_GICD_MAX) {
- INFO("GICD, SMID %d: %s\n", smid, gicd_sm_info[smid]);
- }
- if (blk == FMU_BLK_SPICOL && smid <= FMU_SMID_SPICOL_MAX) {
- INFO("SPI Collator, SMID %d: %s\n", smid, spicol_sm_info[smid]);
- }
- if (blk == FMU_BLK_WAKERQ && (smid <= FMU_SMID_WAKERQ_MAX)) {
- INFO("Wake Request, SMID %d: %s\n", smid, wkrqst_sm_info[smid]);
- }
- if (((blk >= FMU_BLK_ITS0) && (blk <= FMU_BLK_ITS7)) && (smid <= FMU_SMID_ITS_MAX)) {
- INFO("ITS, SMID %d: %s\n", smid, its_sm_info[smid]);
- }
- if (((blk >= FMU_BLK_PPI0) && (blk <= FMU_BLK_PPI31)) && (smid <= FMU_SMID_PPI_MAX)) {
- INFO("PPI, SMID %d: %s\n", smid, ppi_sm_info[smid]);
- }
- }
|