diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index 42e411457494..0691e6d9c1e4 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -26,14 +26,20 @@ #include "omap_l3_noc.h" -/* - * Interrupt Handler for L3 error detection. - * 1) Identify the L3 clockdomain partition to which the error belongs to. - * 2) Identify the slave where the error information is logged - * 3) Print the logged information. - * 4) Add dump stack to provide kernel trace. +/** + * l3_handle_target() - Handle Target specific parse and reporting + * @l3: pointer to l3 struct + * @base: base address of clkdm + * @flag_mux: flagmux corresponding to the event + * @err_src: error source index of the slave (target) * - * Two Types of errors : + * This does the second part of the error interrupt handling: + * 3) Parse in the slave information + * 4) Print the logged information. + * 5) Add dump stack to provide kernel trace. + * 6) Clear the source if known. + * + * This handles two types of errors: * 1) Custom errors in L3 : * Target like DMM/FW/EMIF generates SRESP=ERR error * 2) Standard L3 error: @@ -49,22 +55,107 @@ * can be trapped as well. But the trapping is implemented as part * secure software and hence need not be implemented here. */ -static irqreturn_t l3_interrupt_handler(int irq, void *_l3) +static int l3_handle_target(struct omap_l3 *l3, void __iomem *base, + struct l3_flagmux_data *flag_mux, int err_src) { - - struct omap_l3 *l3 = _l3; - int inttype, i, k; - int err_src = 0; - u32 std_err_main, err_reg, clear, masterid; - void __iomem *base, *l3_targ_base; + int k; + u32 std_err_main, clear, masterid; + void __iomem *l3_targ_base; void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr; - char *target_name, *master_name = "UN IDENTIFIED"; struct l3_target_data *l3_targ_inst; - struct l3_flagmux_data *flag_mux; struct l3_masters_data *master; + char *target_name, *master_name = "UN IDENTIFIED"; char *err_description; char err_string[30] = { 0 }; + /* We DONOT expect err_src to go out of bounds */ + BUG_ON(err_src > MAX_CLKDM_TARGETS); + + if (err_src < flag_mux->num_targ_data) { + l3_targ_inst = &flag_mux->l3_targ[err_src]; + target_name = l3_targ_inst->name; + l3_targ_base = base + l3_targ_inst->offset; + } else { + target_name = L3_TARGET_NOT_SUPPORTED; + } + + if (target_name == L3_TARGET_NOT_SUPPORTED) + return -ENODEV; + + /* Read the stderrlog_main_source from clk domain */ + l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; + l3_targ_slvofslsb = l3_targ_base + L3_TARG_STDERRLOG_SLVOFSLSB; + + std_err_main = readl_relaxed(l3_targ_stderr); + + switch (std_err_main & CUSTOM_ERROR) { + case STANDARD_ERROR: + err_description = "Standard"; + snprintf(err_string, sizeof(err_string), + ": At Address: 0x%08X ", + readl_relaxed(l3_targ_slvofslsb)); + + l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_MSTADDR; + break; + + case CUSTOM_ERROR: + err_description = "Custom"; + + l3_targ_mstaddr = l3_targ_base + + L3_TARG_STDERRLOG_CINFO_MSTADDR; + break; + + default: + /* Nothing to be handled here as of now */ + return 0; + } + + /* STDERRLOG_MSTADDR Stores the NTTP master address. */ + masterid = (readl_relaxed(l3_targ_mstaddr) & + l3->mst_addr_mask) >> __ffs(l3->mst_addr_mask); + + for (k = 0, master = l3->l3_masters; k < l3->num_masters; + k++, master++) { + if (masterid == master->id) { + master_name = master->name; + break; + } + } + + WARN(true, + "%s:L3 %s Error: MASTER %s TARGET %s%s\n", + dev_name(l3->dev), + err_description, + master_name, target_name, + err_string); + + /* clear the std error log*/ + clear = std_err_main | CLEAR_STDERR_LOG; + writel_relaxed(clear, l3_targ_stderr); + + return 0; +} + +/** + * l3_interrupt_handler() - interrupt handler for l3 events + * @irq: irq number + * @_l3: pointer to l3 structure + * + * Interrupt Handler for L3 error detection. + * 1) Identify the L3 clockdomain partition to which the error belongs to. + * 2) Identify the slave where the error information is logged + * ... handle the slave event.. + * 7) if the slave is unknown, mask out the slave. + */ +static irqreturn_t l3_interrupt_handler(int irq, void *_l3) +{ + struct omap_l3 *l3 = _l3; + int inttype, i, ret; + int err_src = 0; + u32 err_reg, mask_val; + void __iomem *base, *mask_reg; + struct l3_flagmux_data *flag_mux; + /* Get the Type of interrupt */ inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; @@ -80,35 +171,18 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) /* Get the corresponding error and analyse */ if (err_reg) { - bool std_err = true; - /* Identify the source from control status register */ err_src = __ffs(err_reg); - /* We DONOT expect err_src to go out of bounds */ - BUG_ON(err_src > MAX_CLKDM_TARGETS); - - if (err_src < flag_mux->num_targ_data) { - l3_targ_inst = &flag_mux->l3_targ[err_src]; - target_name = l3_targ_inst->name; - l3_targ_base = base + l3_targ_inst->offset; - } else { - target_name = L3_TARGET_NOT_SUPPORTED; - } + ret = l3_handle_target(l3, base, flag_mux, err_src); /* - * If we do not know of a register offset to decode - * and clear, then mask. + * Certain plaforms may have "undocumented" status + * pending on boot. So dont generate a severe warning + * here. Just mask it off to prevent the error from + * reoccuring and locking up the system. */ - if (target_name == L3_TARGET_NOT_SUPPORTED) { - u32 mask_val; - void __iomem *mask_reg; - - /* - * Certain plaforms may have "undocumented" - * status pending on boot.. So dont generate - * a severe warning here. - */ + if (ret) { dev_err(l3->dev, "L3 %s error: target %d mod:%d %s\n", inttype ? "debug" : "application", @@ -119,67 +193,8 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3) mask_val = readl_relaxed(mask_reg); mask_val &= ~(1 << err_src); writel_relaxed(mask_val, mask_reg); - - break; } - /* Read the stderrlog_main_source from clk domain */ - l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN; - l3_targ_slvofslsb = l3_targ_base + - L3_TARG_STDERRLOG_SLVOFSLSB; - - std_err_main = readl_relaxed(l3_targ_stderr); - - switch (std_err_main & CUSTOM_ERROR) { - case STANDARD_ERROR: - err_description = "Standard"; - snprintf(err_string, sizeof(err_string), - ": At Address: 0x%08X ", - readl_relaxed(l3_targ_slvofslsb)); - - l3_targ_mstaddr = l3_targ_base + - L3_TARG_STDERRLOG_MSTADDR; - break; - - case CUSTOM_ERROR: - err_description = "Custom"; - - l3_targ_mstaddr = l3_targ_base + - L3_TARG_STDERRLOG_CINFO_MSTADDR; - break; - - default: - std_err = false; - /* Nothing to be handled here as of now */ - break; - } - - if (!std_err) - break; - - /* STDERRLOG_MSTADDR Stores the NTTP master address. */ - masterid = (readl_relaxed(l3_targ_mstaddr) & - l3->mst_addr_mask) >> - __ffs(l3->mst_addr_mask); - - for (k = 0, master = l3->l3_masters; - k < l3->num_masters; k++, master++) { - if (masterid == master->id) { - master_name = master->name; - break; - } - } - - WARN(true, - "%s:L3 %s Error: MASTER %s TARGET %s%s\n", - dev_name(l3->dev), - err_description, - master_name, target_name, - err_string); - /* clear the std error log*/ - clear = std_err_main | CLEAR_STDERR_LOG; - writel_relaxed(clear, l3_targ_stderr); - /* Error found so break the for loop */ break; }