xref: /openbmc/linux/drivers/hwtracing/intel_th/msu-sink.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1f220df66SAlexander Shishkin // SPDX-License-Identifier: GPL-2.0
2f220df66SAlexander Shishkin /*
3f220df66SAlexander Shishkin  * An example software sink buffer for Intel TH MSU.
4f220df66SAlexander Shishkin  *
5f220df66SAlexander Shishkin  * Copyright (C) 2019 Intel Corporation.
6f220df66SAlexander Shishkin  */
7f220df66SAlexander Shishkin 
8f220df66SAlexander Shishkin #include <linux/intel_th.h>
9f220df66SAlexander Shishkin #include <linux/module.h>
10f220df66SAlexander Shishkin #include <linux/slab.h>
11f220df66SAlexander Shishkin #include <linux/device.h>
12f220df66SAlexander Shishkin #include <linux/dma-mapping.h>
13f220df66SAlexander Shishkin 
14f220df66SAlexander Shishkin #define MAX_SGTS 16
15f220df66SAlexander Shishkin 
16f220df66SAlexander Shishkin struct msu_sink_private {
17f220df66SAlexander Shishkin 	struct device	*dev;
18f220df66SAlexander Shishkin 	struct sg_table **sgts;
19f220df66SAlexander Shishkin 	unsigned int	nr_sgts;
20f220df66SAlexander Shishkin };
21f220df66SAlexander Shishkin 
msu_sink_assign(struct device * dev,int * mode)22f220df66SAlexander Shishkin static void *msu_sink_assign(struct device *dev, int *mode)
23f220df66SAlexander Shishkin {
24f220df66SAlexander Shishkin 	struct msu_sink_private *priv;
25f220df66SAlexander Shishkin 
26f220df66SAlexander Shishkin 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
27f220df66SAlexander Shishkin 	if (!priv)
28f220df66SAlexander Shishkin 		return NULL;
29f220df66SAlexander Shishkin 
30f220df66SAlexander Shishkin 	priv->sgts = kcalloc(MAX_SGTS, sizeof(void *), GFP_KERNEL);
31f220df66SAlexander Shishkin 	if (!priv->sgts) {
32f220df66SAlexander Shishkin 		kfree(priv);
33f220df66SAlexander Shishkin 		return NULL;
34f220df66SAlexander Shishkin 	}
35f220df66SAlexander Shishkin 
36f220df66SAlexander Shishkin 	priv->dev = dev;
37f220df66SAlexander Shishkin 	*mode = MSC_MODE_MULTI;
38f220df66SAlexander Shishkin 
39f220df66SAlexander Shishkin 	return priv;
40f220df66SAlexander Shishkin }
41f220df66SAlexander Shishkin 
msu_sink_unassign(void * data)42f220df66SAlexander Shishkin static void msu_sink_unassign(void *data)
43f220df66SAlexander Shishkin {
44f220df66SAlexander Shishkin 	struct msu_sink_private *priv = data;
45f220df66SAlexander Shishkin 
46f220df66SAlexander Shishkin 	kfree(priv->sgts);
47f220df66SAlexander Shishkin 	kfree(priv);
48f220df66SAlexander Shishkin }
49f220df66SAlexander Shishkin 
50f220df66SAlexander Shishkin /* See also: msc.c: __msc_buffer_win_alloc() */
msu_sink_alloc_window(void * data,struct sg_table ** sgt,size_t size)51f220df66SAlexander Shishkin static int msu_sink_alloc_window(void *data, struct sg_table **sgt, size_t size)
52f220df66SAlexander Shishkin {
53f220df66SAlexander Shishkin 	struct msu_sink_private *priv = data;
54f220df66SAlexander Shishkin 	unsigned int nents;
55f220df66SAlexander Shishkin 	struct scatterlist *sg_ptr;
56f220df66SAlexander Shishkin 	void *block;
57f220df66SAlexander Shishkin 	int ret, i;
58f220df66SAlexander Shishkin 
59f220df66SAlexander Shishkin 	if (priv->nr_sgts == MAX_SGTS)
60f220df66SAlexander Shishkin 		return -ENOMEM;
61f220df66SAlexander Shishkin 
62f220df66SAlexander Shishkin 	nents = DIV_ROUND_UP(size, PAGE_SIZE);
63f220df66SAlexander Shishkin 
64f220df66SAlexander Shishkin 	ret = sg_alloc_table(*sgt, nents, GFP_KERNEL);
65f220df66SAlexander Shishkin 	if (ret)
66f220df66SAlexander Shishkin 		return -ENOMEM;
67f220df66SAlexander Shishkin 
68f220df66SAlexander Shishkin 	priv->sgts[priv->nr_sgts++] = *sgt;
69f220df66SAlexander Shishkin 
70f220df66SAlexander Shishkin 	for_each_sg((*sgt)->sgl, sg_ptr, nents, i) {
71f220df66SAlexander Shishkin 		block = dma_alloc_coherent(priv->dev->parent->parent,
72f220df66SAlexander Shishkin 					   PAGE_SIZE, &sg_dma_address(sg_ptr),
73f220df66SAlexander Shishkin 					   GFP_KERNEL);
74*82f76a4aSJiasheng Jiang 		if (!block)
75*82f76a4aSJiasheng Jiang 			return -ENOMEM;
76*82f76a4aSJiasheng Jiang 
77f220df66SAlexander Shishkin 		sg_set_buf(sg_ptr, block, PAGE_SIZE);
78f220df66SAlexander Shishkin 	}
79f220df66SAlexander Shishkin 
80f220df66SAlexander Shishkin 	return nents;
81f220df66SAlexander Shishkin }
82f220df66SAlexander Shishkin 
83f220df66SAlexander Shishkin /* See also: msc.c: __msc_buffer_win_free() */
msu_sink_free_window(void * data,struct sg_table * sgt)84f220df66SAlexander Shishkin static void msu_sink_free_window(void *data, struct sg_table *sgt)
85f220df66SAlexander Shishkin {
86f220df66SAlexander Shishkin 	struct msu_sink_private *priv = data;
87f220df66SAlexander Shishkin 	struct scatterlist *sg_ptr;
88f220df66SAlexander Shishkin 	int i;
89f220df66SAlexander Shishkin 
90f220df66SAlexander Shishkin 	for_each_sg(sgt->sgl, sg_ptr, sgt->nents, i) {
91f220df66SAlexander Shishkin 		dma_free_coherent(priv->dev->parent->parent, PAGE_SIZE,
92f220df66SAlexander Shishkin 				  sg_virt(sg_ptr), sg_dma_address(sg_ptr));
93f220df66SAlexander Shishkin 	}
94f220df66SAlexander Shishkin 
95f220df66SAlexander Shishkin 	sg_free_table(sgt);
96f220df66SAlexander Shishkin 	priv->nr_sgts--;
97f220df66SAlexander Shishkin }
98f220df66SAlexander Shishkin 
msu_sink_ready(void * data,struct sg_table * sgt,size_t bytes)99f220df66SAlexander Shishkin static int msu_sink_ready(void *data, struct sg_table *sgt, size_t bytes)
100f220df66SAlexander Shishkin {
101f220df66SAlexander Shishkin 	struct msu_sink_private *priv = data;
102f220df66SAlexander Shishkin 
103f220df66SAlexander Shishkin 	intel_th_msc_window_unlock(priv->dev, sgt);
104f220df66SAlexander Shishkin 
105f220df66SAlexander Shishkin 	return 0;
106f220df66SAlexander Shishkin }
107f220df66SAlexander Shishkin 
108f220df66SAlexander Shishkin static const struct msu_buffer sink_mbuf = {
109f220df66SAlexander Shishkin 	.name		= "sink",
110f220df66SAlexander Shishkin 	.assign		= msu_sink_assign,
111f220df66SAlexander Shishkin 	.unassign	= msu_sink_unassign,
112f220df66SAlexander Shishkin 	.alloc_window	= msu_sink_alloc_window,
113f220df66SAlexander Shishkin 	.free_window	= msu_sink_free_window,
114f220df66SAlexander Shishkin 	.ready		= msu_sink_ready,
115f220df66SAlexander Shishkin };
116f220df66SAlexander Shishkin 
117f220df66SAlexander Shishkin module_intel_th_msu_buffer(sink_mbuf);
118f220df66SAlexander Shishkin 
119f220df66SAlexander Shishkin MODULE_LICENSE("GPL v2");
120