static int etm_starting_cpu(unsigned int cpu) { if (!etmdrvdata[cpu]) return 0; spin_lock(&etmdrvdata[cpu]->spinlock); if (!etmdrvdata[cpu]->os_unlock) { etm_os_unlock(etmdrvdata[cpu]); etmdrvdata[cpu]->os_unlock = true; } if (local_read(&etmdrvdata[cpu]->mode)) etm_enable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); return 0; }
static void etm_init_arch_data(void *info) { u32 etmidr; u32 etmccr; struct etm_drvdata *drvdata = info; /* Make sure all registers are accessible */ etm_os_unlock(drvdata); CS_UNLOCK(drvdata->base); /* First dummy read */ (void)etm_readl(drvdata, ETMPDSR); /* Provide power to ETM: ETMPDCR[3] == 1 */ etm_set_pwrup(drvdata); /* * Clear power down bit since when this bit is set writes to * certain registers might be ignored. */ etm_clr_pwrdwn(drvdata); /* * Set prog bit. It will be set from reset but this is included to * ensure it is set */ etm_set_prog(drvdata); /* Find all capabilities */ etmidr = etm_readl(drvdata, ETMIDR); drvdata->arch = BMVAL(etmidr, 4, 11); drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK; drvdata->etmccer = etm_readl(drvdata, ETMCCER); etmccr = etm_readl(drvdata, ETMCCR); drvdata->etmccr = etmccr; drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2; drvdata->nr_cntr = BMVAL(etmccr, 13, 15); drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19); drvdata->nr_ext_out = BMVAL(etmccr, 20, 22); drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25); etm_set_pwrdwn(drvdata); etm_clr_pwrup(drvdata); CS_LOCK(drvdata->base); }
static void coresight_etm_restore(void) { struct etm_info *p_etm_info; void __iomem *p_etm_base = ETM_BASE(raw_smp_processor_id()); /* unlock software lock */ etm_unlock(); /* Fix me, normally, lock OS lock can disable trace unit and external access, * but found OS lock can't lock/unlock issue when doing MBTF test, so replace * with TRC_PRGCTLR to disabel trace unit */ #if USE_OSLOCK etm_os_lock(); #else writel_relaxed(0x0, p_etm_base + TRC_PRGCTLR); #endif /* restore registers */ p_etm_info = this_cpu_ptr(&cpu_etm_info); writel_relaxed(p_etm_info->trc_config, p_etm_base + TRC_CONFIGR); writel_relaxed(p_etm_info->trc_eventctl0, p_etm_base + TRC_EVENTCTL0R); writel_relaxed(p_etm_info->trc_eventctl1, p_etm_base + TRC_EVENTCTL1R); writel_relaxed(p_etm_info->trc_stallctl, p_etm_base + TRC_STALLCTLR); writel_relaxed(p_etm_info->trc_tsctlr, p_etm_base + TRC_TSCTLR); writel_relaxed(p_etm_info->trc_syncpr, p_etm_base + TRC_SYNCPR); writel_relaxed(p_etm_info->trc_bbctl, p_etm_base + TRC_BBCTLR); writel_relaxed(p_etm_info->trc_traceid, p_etm_base + TRC_TRACEIDR); writel_relaxed(p_etm_info->trc_victlr, p_etm_base + TRC_VICTLR); writel_relaxed(p_etm_info->trc_viiectl, p_etm_base + TRC_VIIECTLR); writel_relaxed(p_etm_info->trc_vissctl, p_etm_base + TRC_VISSCTLR); #if USE_OSLOCK writel_relaxed(p_etm_info->trc_prgctl, p_etm_base + TRC_PRGCTLR); #else writel_relaxed(0x1, p_etm_base + TRC_PRGCTLR); #endif /* unlock os lock */ etm_os_unlock(); /* lock software lock */ etm_lock(); }
static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; if (!etmdrvdata[cpu]) goto out; switch (action & (~CPU_TASKS_FROZEN)) { case CPU_STARTING: spin_lock(&etmdrvdata[cpu]->spinlock); if (!etmdrvdata[cpu]->os_unlock) { etm_os_unlock(etmdrvdata[cpu]); etmdrvdata[cpu]->os_unlock = true; } if (etmdrvdata[cpu]->enable) etm_enable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); break; case CPU_ONLINE: if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable) coresight_enable(etmdrvdata[cpu]->csdev); break; case CPU_DYING: spin_lock(&etmdrvdata[cpu]->spinlock); if (etmdrvdata[cpu]->enable) etm_disable_hw(etmdrvdata[cpu]); spin_unlock(&etmdrvdata[cpu]->spinlock); break; } out: return NOTIFY_OK; }
static void etm_enable_hw(void *info) { int i; u32 etmcr; struct etm_drvdata *drvdata = info; CS_UNLOCK(drvdata->base); /* Turn engine on */ etm_clr_pwrdwn(drvdata); /* Apply power to trace registers */ etm_set_pwrup(drvdata); /* Make sure all registers are accessible */ etm_os_unlock(drvdata); etm_set_prog(drvdata); etmcr = etm_readl(drvdata, ETMCR); etmcr &= (ETMCR_PWD_DWN | ETMCR_ETM_PRG); etmcr |= drvdata->port_size; etm_writel(drvdata, drvdata->ctrl | etmcr, ETMCR); etm_writel(drvdata, drvdata->trigger_event, ETMTRIGGER); etm_writel(drvdata, drvdata->startstop_ctrl, ETMTSSCR); etm_writel(drvdata, drvdata->enable_event, ETMTEEVR); etm_writel(drvdata, drvdata->enable_ctrl1, ETMTECR1); etm_writel(drvdata, drvdata->fifofull_level, ETMFFLR); for (i = 0; i < drvdata->nr_addr_cmp; i++) { etm_writel(drvdata, drvdata->addr_val[i], ETMACVRn(i)); etm_writel(drvdata, drvdata->addr_acctype[i], ETMACTRn(i)); } for (i = 0; i < drvdata->nr_cntr; i++) { etm_writel(drvdata, drvdata->cntr_rld_val[i], ETMCNTRLDVRn(i)); etm_writel(drvdata, drvdata->cntr_event[i], ETMCNTENRn(i)); etm_writel(drvdata, drvdata->cntr_rld_event[i], ETMCNTRLDEVRn(i)); etm_writel(drvdata, drvdata->cntr_val[i], ETMCNTVRn(i)); } etm_writel(drvdata, drvdata->seq_12_event, ETMSQ12EVR); etm_writel(drvdata, drvdata->seq_21_event, ETMSQ21EVR); etm_writel(drvdata, drvdata->seq_23_event, ETMSQ23EVR); etm_writel(drvdata, drvdata->seq_31_event, ETMSQ31EVR); etm_writel(drvdata, drvdata->seq_32_event, ETMSQ32EVR); etm_writel(drvdata, drvdata->seq_13_event, ETMSQ13EVR); etm_writel(drvdata, drvdata->seq_curr_state, ETMSQR); for (i = 0; i < drvdata->nr_ext_out; i++) etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i)); for (i = 0; i < drvdata->nr_ctxid_cmp; i++) etm_writel(drvdata, drvdata->ctxid_pid[i], ETMCIDCVRn(i)); etm_writel(drvdata, drvdata->ctxid_mask, ETMCIDCMR); etm_writel(drvdata, drvdata->sync_freq, ETMSYNCFR); /* No external input selected */ etm_writel(drvdata, 0x0, ETMEXTINSELR); etm_writel(drvdata, drvdata->timestamp_event, ETMTSEVR); /* No auxiliary control selected */ etm_writel(drvdata, 0x0, ETMAUXCR); etm_writel(drvdata, drvdata->traceid, ETMTRACEIDR); /* No VMID comparator value selected */ etm_writel(drvdata, 0x0, ETMVMIDCVR); /* Ensures trace output is enabled from this ETM */ etm_writel(drvdata, drvdata->ctrl | ETMCR_ETM_EN | etmcr, ETMCR); etm_clr_prog(drvdata); CS_LOCK(drvdata->base); dev_dbg(drvdata->dev, "cpu: %d enable smp call done\n", drvdata->cpu); }
static inline void etm_restore_state(struct etm_ctx *etmdata) { int i, j; i = 0; ETM_UNLOCK(etmdata); switch (etmdata->arch) { case ETM_ARCH_V4: atomic_notifier_call_chain(&etm_restore_notifier_list, 0, NULL); /* check OS lock is locked */ if (BVAL(etm_readl(etmdata, TRCOSLSR), 1) != 1) { pr_err_ratelimited("OS lock is unlocked\n"); etm_os_lock(etmdata); } /* main control and configuration registers */ etm_writel(etmdata, etmdata->state[i++], TRCPROCSELR); etm_writel(etmdata, etmdata->state[i++], TRCCONFIGR); etm_writel(etmdata, etmdata->state[i++], TRCAUXCTLR); etm_writel(etmdata, etmdata->state[i++], TRCEVENTCTL0R); etm_writel(etmdata, etmdata->state[i++], TRCEVENTCTL1R); etm_writel(etmdata, etmdata->state[i++], TRCSTALLCTLR); etm_writel(etmdata, etmdata->state[i++], TRCTSCTLR); etm_writel(etmdata, etmdata->state[i++], TRCSYNCPR); etm_writel(etmdata, etmdata->state[i++], TRCCCCTLR); etm_writel(etmdata, etmdata->state[i++], TRCBBCTLR); etm_writel(etmdata, etmdata->state[i++], TRCTRACEIDR); etm_writel(etmdata, etmdata->state[i++], TRCQCTLR); /* filtering control registers */ etm_writel(etmdata, etmdata->state[i++], TRCVICTLR); etm_writel(etmdata, etmdata->state[i++], TRCVIIECTLR); etm_writel(etmdata, etmdata->state[i++], TRCVISSCTLR); etm_writel(etmdata, etmdata->state[i++], TRCVIPCSSCTLR); etm_writel(etmdata, etmdata->state[i++], TRCVDCTLR); etm_writel(etmdata, etmdata->state[i++], TRCVDSACCTLR); etm_writel(etmdata, etmdata->state[i++], TRCVDARCCTLR); /* derived resources registers */ for (j = 0; j < etmdata->nr_seq_state-1; j++) etm_writel(etmdata, etmdata->state[i++], TRCSEQEVRn(j)); etm_writel(etmdata, etmdata->state[i++], TRCSEQRSTEVR); etm_writel(etmdata, etmdata->state[i++], TRCSEQSTR); etm_writel(etmdata, etmdata->state[i++], TRCEXTINSELR); for (j = 0; j < etmdata->nr_cntr; j++) { etm_writel(etmdata, etmdata->state[i++], TRCCNTRLDVRn(j)); etm_writel(etmdata, etmdata->state[i++], TRCCNTCTLRn(j)); etm_writel(etmdata, etmdata->state[i++], TRCCNTVRn(j)); } /* resource selection registers */ for (j = 0; j < etmdata->nr_resource; j++) etm_writel(etmdata, etmdata->state[i++], TRCRSCTLRn(j)); /* comparator registers */ for (j = 0; j < etmdata->nr_addr_cmp * 2; j++) { etm_writeq(etmdata, etmdata->state[i++], TRCACVRn(j)); etm_writeq(etmdata, etmdata->state[i++], TRCACATRn(j)); } for (j = 0; j < etmdata->nr_data_cmp; j++) { etm_writeq(etmdata, etmdata->state[i++], TRCDVCVRn(j)); etm_writeq(etmdata, etmdata->state[i++], TRCDVCMRn(j)); } for (j = 0; j < etmdata->nr_ctxid_cmp; j++) etm_writeq(etmdata, etmdata->state[i++], TRCCIDCVRn(j)); etm_writel(etmdata, etmdata->state[i++], TRCCIDCCTLR0); etm_writel(etmdata, etmdata->state[i++], TRCCIDCCTLR1); for (j = 0; j < etmdata->nr_vmid_cmp; j++) etm_writeq(etmdata, etmdata->state[i++], TRCVMIDCVRn(j)); etm_writel(etmdata, etmdata->state[i++], TRCVMIDCCTLR0); etm_writel(etmdata, etmdata->state[i++], TRCVMIDCCTLR1); /* e-shot comparator registers */ for (j = 0; j < etmdata->nr_ss_cmp; j++) { etm_writel(etmdata, etmdata->state[i++], TRCSSCCRn(j)); etm_writel(etmdata, etmdata->state[i++], TRCSSCSRn(j)); etm_writel(etmdata, etmdata->state[i++], TRCSSPCICRn(j)); } /* claim tag registers */ etm_writel(etmdata, etmdata->state[i++], TRCCLAIMSET); /* program ctrl register */ etm_writel(etmdata, etmdata->state[i++], TRCPRGCTLR); etm_os_unlock(etmdata); break; default: pr_err_ratelimited("unsupported etm arch %d in %s\n", etmdata->arch, __func__); } ETM_LOCK(etmdata); }
static int etm_enable_hw(struct etm_drvdata *drvdata) { int i, rc; u32 etmcr; struct etm_config *config = &drvdata->config; CS_UNLOCK(drvdata->base); rc = coresight_claim_device_unlocked(drvdata->base); if (rc) goto done; /* Turn engine on */ etm_clr_pwrdwn(drvdata); /* Apply power to trace registers */ etm_set_pwrup(drvdata); /* Make sure all registers are accessible */ etm_os_unlock(drvdata); etm_set_prog(drvdata); etmcr = etm_readl(drvdata, ETMCR); /* Clear setting from a previous run if need be */ etmcr &= ~ETM3X_SUPPORTED_OPTIONS; etmcr |= drvdata->port_size; etmcr |= ETMCR_ETM_EN; etm_writel(drvdata, config->ctrl | etmcr, ETMCR); etm_writel(drvdata, config->trigger_event, ETMTRIGGER); etm_writel(drvdata, config->startstop_ctrl, ETMTSSCR); etm_writel(drvdata, config->enable_event, ETMTEEVR); etm_writel(drvdata, config->enable_ctrl1, ETMTECR1); etm_writel(drvdata, config->fifofull_level, ETMFFLR); for (i = 0; i < drvdata->nr_addr_cmp; i++) { etm_writel(drvdata, config->addr_val[i], ETMACVRn(i)); etm_writel(drvdata, config->addr_acctype[i], ETMACTRn(i)); } for (i = 0; i < drvdata->nr_cntr; i++) { etm_writel(drvdata, config->cntr_rld_val[i], ETMCNTRLDVRn(i)); etm_writel(drvdata, config->cntr_event[i], ETMCNTENRn(i)); etm_writel(drvdata, config->cntr_rld_event[i], ETMCNTRLDEVRn(i)); etm_writel(drvdata, config->cntr_val[i], ETMCNTVRn(i)); } etm_writel(drvdata, config->seq_12_event, ETMSQ12EVR); etm_writel(drvdata, config->seq_21_event, ETMSQ21EVR); etm_writel(drvdata, config->seq_23_event, ETMSQ23EVR); etm_writel(drvdata, config->seq_31_event, ETMSQ31EVR); etm_writel(drvdata, config->seq_32_event, ETMSQ32EVR); etm_writel(drvdata, config->seq_13_event, ETMSQ13EVR); etm_writel(drvdata, config->seq_curr_state, ETMSQR); for (i = 0; i < drvdata->nr_ext_out; i++) etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i)); for (i = 0; i < drvdata->nr_ctxid_cmp; i++) etm_writel(drvdata, config->ctxid_pid[i], ETMCIDCVRn(i)); etm_writel(drvdata, config->ctxid_mask, ETMCIDCMR); etm_writel(drvdata, config->sync_freq, ETMSYNCFR); /* No external input selected */ etm_writel(drvdata, 0x0, ETMEXTINSELR); etm_writel(drvdata, config->timestamp_event, ETMTSEVR); /* No auxiliary control selected */ etm_writel(drvdata, 0x0, ETMAUXCR); etm_writel(drvdata, drvdata->traceid, ETMTRACEIDR); /* No VMID comparator value selected */ etm_writel(drvdata, 0x0, ETMVMIDCVR); etm_clr_prog(drvdata); done: CS_LOCK(drvdata->base); dev_dbg(&drvdata->csdev->dev, "cpu: %d enable smp call done: %d\n", drvdata->cpu, rc); return rc; }