cregit-Linux how code gets into the kernel

Release 4.14 drivers/hwtracing/coresight/coresight-tmc-etr.c

/*
 * Copyright(C) 2016 Linaro Limited. All rights reserved.
 * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/coresight.h>
#include <linux/dma-mapping.h>
#include "coresight-priv.h"
#include "coresight-tmc.h"


static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) { u32 axictl, sts; /* Zero out the memory to help with debug */ memset(drvdata->vaddr, 0, drvdata->size); CS_UNLOCK(drvdata->base); /* Wait for TMCSReady bit to be set */ tmc_wait_for_tmcready(drvdata); writel_relaxed(drvdata->size / 4, drvdata->base + TMC_RSZ); writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); axictl = readl_relaxed(drvdata->base + TMC_AXICTL); axictl &= ~TMC_AXICTL_CLEAR_MASK; axictl |= (TMC_AXICTL_PROT_CTL_B1 | TMC_AXICTL_WR_BURST_16); axictl |= TMC_AXICTL_AXCACHE_OS; if (tmc_etr_has_cap(drvdata, TMC_ETR_AXI_ARCACHE)) { axictl &= ~TMC_AXICTL_ARCACHE_MASK; axictl |= TMC_AXICTL_ARCACHE_OS; } writel_relaxed(axictl, drvdata->base + TMC_AXICTL); tmc_write_dba(drvdata, drvdata->paddr); /* * If the TMC pointers must be programmed before the session, * we have to set it properly (i.e, RRP/RWP to base address and * STS to "not full"). */ if (tmc_etr_has_cap(drvdata, TMC_ETR_SAVE_RESTORE)) { tmc_write_rrp(drvdata, drvdata->paddr); tmc_write_rwp(drvdata, drvdata->paddr); sts = readl_relaxed(drvdata->base + TMC_STS) & ~TMC_STS_FULL; writel_relaxed(sts, drvdata->base + TMC_STS); } writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT | TMC_FFCR_TRIGON_TRIGIN, drvdata->base + TMC_FFCR); writel_relaxed(drvdata->trigger_cntr, drvdata->base + TMC_TRG); tmc_enable_hw(drvdata); CS_LOCK(drvdata->base); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier14862.71%116.67%
Suzuki K. Poulose8736.86%466.67%
Baoyou Xie10.42%116.67%
Total236100.00%6100.00%


static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) { const u32 *barrier; u32 val; u32 *temp; u64 rwp; rwp = tmc_read_rwp(drvdata); val = readl_relaxed(drvdata->base + TMC_STS); /* * Adjust the buffer to point to the beginning of the trace data * and update the available trace data. */ if (val & TMC_STS_FULL) { drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; drvdata->len = drvdata->size; barrier = barrier_pkt; temp = (u32 *)drvdata->buf; while (*barrier) { *temp = *barrier; temp++; barrier++; } } else { drvdata->buf = drvdata->vaddr; drvdata->len = rwp - drvdata->paddr; } }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier10077.52%240.00%
Suzuki K. Poulose2922.48%360.00%
Total129100.00%5100.00%


static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata) { CS_UNLOCK(drvdata->base); tmc_flush_and_stop(drvdata); /* * When operating in sysFS mode the content of the buffer needs to be * read before the TMC is disabled. */ if (drvdata->mode == CS_MODE_SYSFS) tmc_etr_dump_hw(drvdata); tmc_disable_hw(drvdata); CS_LOCK(drvdata->base); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier49100.00%3100.00%
Total49100.00%3100.00%


static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) { int ret = 0; bool used = false; unsigned long flags; void __iomem *vaddr = NULL; dma_addr_t paddr; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); /* * If we don't have a buffer release the lock and allocate memory. * Otherwise keep the lock and move along. */ spin_lock_irqsave(&drvdata->spinlock, flags); if (!drvdata->vaddr) { spin_unlock_irqrestore(&drvdata->spinlock, flags); /* * Contiguous memory can't be allocated while a spinlock is * held. As such allocate memory here and free it if a buffer * has already been allocated (from a previous session). */ vaddr = dma_alloc_coherent(drvdata->dev, drvdata->size, &paddr, GFP_KERNEL); if (!vaddr) return -ENOMEM; /* Let's try again */ spin_lock_irqsave(&drvdata->spinlock, flags); } if (drvdata->reading) { ret = -EBUSY; goto out; } /* * In sysFS mode we can have multiple writers per sink. Since this * sink is already enabled no memory is needed and the HW need not be * touched. */ if (drvdata->mode == CS_MODE_SYSFS) goto out; /* * If drvdata::buf == NULL, use the memory allocated above. * Otherwise a buffer still exists from a previous session, so * simply use that. */ if (drvdata->buf == NULL) { used = true; drvdata->vaddr = vaddr; drvdata->paddr = paddr; drvdata->buf = drvdata->vaddr; } drvdata->mode = CS_MODE_SYSFS; tmc_etr_enable_hw(drvdata); out: spin_unlock_irqrestore(&drvdata->spinlock, flags); /* Free memory outside the spinlock if need be */ if (!used && vaddr) dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr); if (!ret) dev_info(drvdata->dev, "TMC-ETR enabled\n"); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier23596.31%480.00%
Suzuki K. Poulose93.69%120.00%
Total244100.00%5100.00%


static int tmc_enable_etr_sink_perf(struct coresight_device *csdev) { int ret = 0; unsigned long flags; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { ret = -EINVAL; goto out; } /* * In Perf mode there can be only one writer per sink. There * is also no need to continue if the ETR is already operated * from sysFS. */ if (drvdata->mode != CS_MODE_DISABLED) { ret = -EINVAL; goto out; } drvdata->mode = CS_MODE_PERF; tmc_etr_enable_hw(drvdata); out: spin_unlock_irqrestore(&drvdata->spinlock, flags); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier9691.43%150.00%
Suzuki K. Poulose98.57%150.00%
Total105100.00%2100.00%


static int tmc_enable_etr_sink(struct coresight_device *csdev, u32 mode) { switch (mode) { case CS_MODE_SYSFS: return tmc_enable_etr_sink_sysfs(csdev); case CS_MODE_PERF: return tmc_enable_etr_sink_perf(csdev); } /* We shouldn't be here */ return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier43100.00%1100.00%
Total43100.00%1100.00%


static void tmc_disable_etr_sink(struct coresight_device *csdev) { unsigned long flags; struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { spin_unlock_irqrestore(&drvdata->spinlock, flags); return; } /* Disable the TMC only if it needs to */ if (drvdata->mode != CS_MODE_DISABLED) { tmc_etr_disable_hw(drvdata); drvdata->mode = CS_MODE_DISABLED; } spin_unlock_irqrestore(&drvdata->spinlock, flags); dev_info(drvdata->dev, "TMC-ETR disabled\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier8888.89%266.67%
Suzuki K. Poulose1111.11%133.33%
Total99100.00%3100.00%

static const struct coresight_ops_sink tmc_etr_sink_ops = { .enable = tmc_enable_etr_sink, .disable = tmc_disable_etr_sink, }; const struct coresight_ops tmc_etr_cs_ops = { .sink_ops = &tmc_etr_sink_ops, };
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) { int ret = 0; unsigned long flags; /* config types are set a boot time and never change */ if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) return -EINVAL; spin_lock_irqsave(&drvdata->spinlock, flags); if (drvdata->reading) { ret = -EBUSY; goto out; } /* Don't interfere if operated from Perf */ if (drvdata->mode == CS_MODE_PERF) { ret = -EINVAL; goto out; } /* If drvdata::buf is NULL the trace data has been read already */ if (drvdata->buf == NULL) { ret = -EINVAL; goto out; } /* Disable the TMC if need be */ if (drvdata->mode == CS_MODE_SYSFS) tmc_etr_disable_hw(drvdata); drvdata->reading = true; out: spin_unlock_irqrestore(&drvdata->spinlock, flags); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier12895.52%583.33%
Suzuki K. Poulose64.48%116.67%
Total134100.00%6100.00%


int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata) { unsigned long flags; dma_addr_t paddr; void __iomem *vaddr = NULL; /* config types are set a boot time and never change */ if (WARN_ON_ONCE(drvdata->config_type != TMC_CONFIG_TYPE_ETR)) return -EINVAL; spin_lock_irqsave(&drvdata->spinlock, flags); /* RE-enable the TMC if need be */ if (drvdata->mode == CS_MODE_SYSFS) { /* * The trace run will continue with the same allocated trace * buffer. The trace buffer is cleared in tmc_etr_enable_hw(), * so we don't have to explicitly clear it. Also, since the * tracer is still enabled drvdata::buf can't be NULL. */ tmc_etr_enable_hw(drvdata); } else { /* * The ETR is not tracing and the buffer was just read. * As such prepare to free the trace buffer. */ vaddr = drvdata->vaddr; paddr = drvdata->paddr; drvdata->buf = drvdata->vaddr = NULL; } drvdata->reading = false; spin_unlock_irqrestore(&drvdata->spinlock, flags); /* Free allocated memory out side of the spinlock */ if (vaddr) dma_free_coherent(drvdata->dev, drvdata->size, vaddr, paddr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier12796.21%360.00%
Suzuki K. Poulose53.79%240.00%
Total132100.00%5100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Mathieu J. Poirier105887.08%844.44%
Suzuki K. Poulose15612.84%950.00%
Baoyou Xie10.08%15.56%
Total1215100.00%18100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.