Skip to content

Commit

Permalink
intel_th: msu-sink: An example msu buffer "sink"
Browse files Browse the repository at this point in the history
This patch adds an example MSU buffer "sink", which consumes trace
data from MSC buffers.

Functionally, it acts similarly to "multi" mode with automatic window
switching.

Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20190705141425.19894-3-alexander.shishkin@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Alexander Shishkin authored and Greg Kroah-Hartman committed Jul 25, 2019
1 parent 615c164 commit f220df6
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
3 changes: 3 additions & 0 deletions drivers/hwtracing/intel_th/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ intel_th_msu-y := msu.o

obj-$(CONFIG_INTEL_TH_PTI) += intel_th_pti.o
intel_th_pti-y := pti.o

obj-$(CONFIG_INTEL_TH_MSU) += intel_th_msu_sink.o
intel_th_msu_sink-y := msu-sink.o
116 changes: 116 additions & 0 deletions drivers/hwtracing/intel_th/msu-sink.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// SPDX-License-Identifier: GPL-2.0
/*
* An example software sink buffer for Intel TH MSU.
*
* Copyright (C) 2019 Intel Corporation.
*/

#include <linux/intel_th.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>

#define MAX_SGTS 16

struct msu_sink_private {
struct device *dev;
struct sg_table **sgts;
unsigned int nr_sgts;
};

static void *msu_sink_assign(struct device *dev, int *mode)
{
struct msu_sink_private *priv;

priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return NULL;

priv->sgts = kcalloc(MAX_SGTS, sizeof(void *), GFP_KERNEL);
if (!priv->sgts) {
kfree(priv);
return NULL;
}

priv->dev = dev;
*mode = MSC_MODE_MULTI;

return priv;
}

static void msu_sink_unassign(void *data)
{
struct msu_sink_private *priv = data;

kfree(priv->sgts);
kfree(priv);
}

/* See also: msc.c: __msc_buffer_win_alloc() */
static int msu_sink_alloc_window(void *data, struct sg_table **sgt, size_t size)
{
struct msu_sink_private *priv = data;
unsigned int nents;
struct scatterlist *sg_ptr;
void *block;
int ret, i;

if (priv->nr_sgts == MAX_SGTS)
return -ENOMEM;

nents = DIV_ROUND_UP(size, PAGE_SIZE);

ret = sg_alloc_table(*sgt, nents, GFP_KERNEL);
if (ret)
return -ENOMEM;

priv->sgts[priv->nr_sgts++] = *sgt;

for_each_sg((*sgt)->sgl, sg_ptr, nents, i) {
block = dma_alloc_coherent(priv->dev->parent->parent,
PAGE_SIZE, &sg_dma_address(sg_ptr),
GFP_KERNEL);
sg_set_buf(sg_ptr, block, PAGE_SIZE);
}

return nents;
}

/* See also: msc.c: __msc_buffer_win_free() */
static void msu_sink_free_window(void *data, struct sg_table *sgt)
{
struct msu_sink_private *priv = data;
struct scatterlist *sg_ptr;
int i;

for_each_sg(sgt->sgl, sg_ptr, sgt->nents, i) {
dma_free_coherent(priv->dev->parent->parent, PAGE_SIZE,
sg_virt(sg_ptr), sg_dma_address(sg_ptr));
}

sg_free_table(sgt);
priv->nr_sgts--;
}

static int msu_sink_ready(void *data, struct sg_table *sgt, size_t bytes)
{
struct msu_sink_private *priv = data;

intel_th_msc_window_unlock(priv->dev, sgt);

return 0;
}

static const struct msu_buffer sink_mbuf = {
.name = "sink",
.assign = msu_sink_assign,
.unassign = msu_sink_unassign,
.alloc_window = msu_sink_alloc_window,
.free_window = msu_sink_free_window,
.ready = msu_sink_ready,
};

module_intel_th_msu_buffer(sink_mbuf);

MODULE_LICENSE("GPL v2");

0 comments on commit f220df6

Please sign in to comment.