Skip to content

Commit f04e449

Browse files
virtuosogregkh
authored andcommitted
intel_th: Add Software Trace Hub driver
Software Trace Hub (STH) is a trace source device in the Intel TH architecture, it generates data that then goes through the switch into one or several output ports. STH collects data from software sources using the stm device class abstraction. Signed-off-by: Alexander Shishkin <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b27a6a3 commit f04e449

File tree

4 files changed

+314
-0
lines changed

4 files changed

+314
-0
lines changed

drivers/hwtracing/intel_th/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ config INTEL_TH_GTH
3434

3535
Say Y here to enable GTH subdevice of Intel(R) Trace Hub.
3636

37+
config INTEL_TH_STH
38+
tristate "Intel(R) Trace Hub Software Trace Hub support"
39+
depends on STM
40+
help
41+
Software Trace Hub (STH) enables trace data from software
42+
trace sources to be sent out via Intel(R) Trace Hub. It
43+
uses stm class device to interface with its sources.
44+
45+
Say Y here to enable STH subdevice of Intel(R) Trace Hub.
46+
3747
config INTEL_TH_DEBUG
3848
bool "Intel(R) Trace Hub debugging"
3949
depends on DEBUG_FS

drivers/hwtracing/intel_th/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ intel_th_pci-y := pci.o
77

88
obj-$(CONFIG_INTEL_TH_GTH) += intel_th_gth.o
99
intel_th_gth-y := gth.o
10+
11+
obj-$(CONFIG_INTEL_TH_STH) += intel_th_sth.o
12+
intel_th_sth-y := sth.o

drivers/hwtracing/intel_th/sth.c

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/*
2+
* Intel(R) Trace Hub Software Trace Hub support
3+
*
4+
* Copyright (C) 2014-2015 Intel Corporation.
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms and conditions of the GNU General Public License,
8+
* version 2, as published by the Free Software Foundation.
9+
*
10+
* This program is distributed in the hope it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13+
* more details.
14+
*/
15+
16+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17+
18+
#include <linux/types.h>
19+
#include <linux/module.h>
20+
#include <linux/device.h>
21+
#include <linux/io.h>
22+
#include <linux/mm.h>
23+
#include <linux/slab.h>
24+
#include <linux/stm.h>
25+
26+
#include "intel_th.h"
27+
#include "sth.h"
28+
29+
struct sth_device {
30+
void __iomem *base;
31+
void __iomem *channels;
32+
phys_addr_t channels_phys;
33+
struct device *dev;
34+
struct stm_data stm;
35+
unsigned int sw_nmasters;
36+
};
37+
38+
static struct intel_th_channel __iomem *
39+
sth_channel(struct sth_device *sth, unsigned int master, unsigned int channel)
40+
{
41+
struct intel_th_channel __iomem *sw_map = sth->channels;
42+
43+
return &sw_map[(master - sth->stm.sw_start) * sth->stm.sw_nchannels +
44+
channel];
45+
}
46+
47+
static void sth_iowrite(void __iomem *dest, const unsigned char *payload,
48+
unsigned int size)
49+
{
50+
switch (size) {
51+
#ifdef CONFIG_64BIT
52+
case 8:
53+
writeq_relaxed(*(u64 *)payload, dest);
54+
break;
55+
#endif
56+
case 4:
57+
writel_relaxed(*(u32 *)payload, dest);
58+
break;
59+
case 2:
60+
writew_relaxed(*(u16 *)payload, dest);
61+
break;
62+
case 1:
63+
writeb_relaxed(*(u8 *)payload, dest);
64+
break;
65+
default:
66+
break;
67+
}
68+
}
69+
70+
static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master,
71+
unsigned int channel, unsigned int packet,
72+
unsigned int flags, unsigned int size,
73+
const unsigned char *payload)
74+
{
75+
struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
76+
struct intel_th_channel __iomem *out =
77+
sth_channel(sth, master, channel);
78+
u64 __iomem *outp = &out->Dn;
79+
unsigned long reg = REG_STH_TRIG;
80+
81+
#ifndef CONFIG_64BIT
82+
if (size > 4)
83+
size = 4;
84+
#endif
85+
86+
size = rounddown_pow_of_two(size);
87+
88+
switch (packet) {
89+
/* Global packets (GERR, XSYNC, TRIG) are sent with register writes */
90+
case STP_PACKET_GERR:
91+
reg += 4;
92+
case STP_PACKET_XSYNC:
93+
reg += 8;
94+
case STP_PACKET_TRIG:
95+
if (flags & STP_PACKET_TIMESTAMPED)
96+
reg += 4;
97+
iowrite8(*payload, sth->base + reg);
98+
break;
99+
100+
case STP_PACKET_MERR:
101+
sth_iowrite(&out->MERR, payload, size);
102+
break;
103+
104+
case STP_PACKET_FLAG:
105+
if (flags & STP_PACKET_TIMESTAMPED)
106+
outp = (u64 __iomem *)&out->FLAG_TS;
107+
else
108+
outp = (u64 __iomem *)&out->FLAG;
109+
110+
size = 1;
111+
sth_iowrite(outp, payload, size);
112+
break;
113+
114+
case STP_PACKET_USER:
115+
if (flags & STP_PACKET_TIMESTAMPED)
116+
outp = &out->USER_TS;
117+
else
118+
outp = &out->USER;
119+
sth_iowrite(outp, payload, size);
120+
break;
121+
122+
case STP_PACKET_DATA:
123+
outp = &out->Dn;
124+
125+
if (flags & STP_PACKET_TIMESTAMPED)
126+
outp += 2;
127+
if (flags & STP_PACKET_MARKED)
128+
outp++;
129+
130+
sth_iowrite(outp, payload, size);
131+
break;
132+
}
133+
134+
return size;
135+
}
136+
137+
static phys_addr_t
138+
sth_stm_mmio_addr(struct stm_data *stm_data, unsigned int master,
139+
unsigned int channel, unsigned int nr_chans)
140+
{
141+
struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
142+
phys_addr_t addr;
143+
144+
master -= sth->stm.sw_start;
145+
addr = sth->channels_phys + (master * sth->stm.sw_nchannels + channel) *
146+
sizeof(struct intel_th_channel);
147+
148+
if (offset_in_page(addr) ||
149+
offset_in_page(nr_chans * sizeof(struct intel_th_channel)))
150+
return 0;
151+
152+
return addr;
153+
}
154+
155+
static int sth_stm_link(struct stm_data *stm_data, unsigned int master,
156+
unsigned int channel)
157+
{
158+
struct sth_device *sth = container_of(stm_data, struct sth_device, stm);
159+
160+
intel_th_set_output(to_intel_th_device(sth->dev), master);
161+
162+
return 0;
163+
}
164+
165+
static int intel_th_sw_init(struct sth_device *sth)
166+
{
167+
u32 reg;
168+
169+
reg = ioread32(sth->base + REG_STH_STHCAP1);
170+
sth->stm.sw_nchannels = reg & 0xff;
171+
172+
reg = ioread32(sth->base + REG_STH_STHCAP0);
173+
sth->stm.sw_start = reg & 0xffff;
174+
sth->stm.sw_end = reg >> 16;
175+
176+
sth->sw_nmasters = sth->stm.sw_end - sth->stm.sw_start;
177+
dev_dbg(sth->dev, "sw_start: %x sw_end: %x masters: %x nchannels: %x\n",
178+
sth->stm.sw_start, sth->stm.sw_end, sth->sw_nmasters,
179+
sth->stm.sw_nchannels);
180+
181+
return 0;
182+
}
183+
184+
static int intel_th_sth_probe(struct intel_th_device *thdev)
185+
{
186+
struct device *dev = &thdev->dev;
187+
struct sth_device *sth;
188+
struct resource *res;
189+
void __iomem *base, *channels;
190+
int err;
191+
192+
res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
193+
if (!res)
194+
return -ENODEV;
195+
196+
base = devm_ioremap(dev, res->start, resource_size(res));
197+
if (IS_ERR(base))
198+
return PTR_ERR(base);
199+
200+
res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 1);
201+
if (!res)
202+
return -ENODEV;
203+
204+
channels = devm_ioremap(dev, res->start, resource_size(res));
205+
if (IS_ERR(channels))
206+
return PTR_ERR(channels);
207+
208+
sth = devm_kzalloc(dev, sizeof(*sth), GFP_KERNEL);
209+
if (!sth)
210+
return -ENOMEM;
211+
212+
sth->dev = dev;
213+
sth->base = base;
214+
sth->channels = channels;
215+
sth->channels_phys = res->start;
216+
sth->stm.name = dev_name(dev);
217+
sth->stm.packet = sth_stm_packet;
218+
sth->stm.mmio_addr = sth_stm_mmio_addr;
219+
sth->stm.sw_mmiosz = sizeof(struct intel_th_channel);
220+
sth->stm.link = sth_stm_link;
221+
222+
err = intel_th_sw_init(sth);
223+
if (err)
224+
return err;
225+
226+
err = stm_register_device(dev, &sth->stm, THIS_MODULE);
227+
if (err) {
228+
dev_err(dev, "stm_register_device failed\n");
229+
return err;
230+
}
231+
232+
dev_set_drvdata(dev, sth);
233+
234+
return 0;
235+
}
236+
237+
static void intel_th_sth_remove(struct intel_th_device *thdev)
238+
{
239+
struct sth_device *sth = dev_get_drvdata(&thdev->dev);
240+
241+
stm_unregister_device(&sth->stm);
242+
}
243+
244+
static struct intel_th_driver intel_th_sth_driver = {
245+
.probe = intel_th_sth_probe,
246+
.remove = intel_th_sth_remove,
247+
.driver = {
248+
.name = "sth",
249+
.owner = THIS_MODULE,
250+
},
251+
};
252+
253+
module_driver(intel_th_sth_driver,
254+
intel_th_driver_register,
255+
intel_th_driver_unregister);
256+
257+
MODULE_LICENSE("GPL v2");
258+
MODULE_DESCRIPTION("Intel(R) Trace Hub Software Trace Hub driver");
259+
MODULE_AUTHOR("Alexander Shishkin <[email protected]>");

drivers/hwtracing/intel_th/sth.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Intel(R) Trace Hub Software Trace Hub (STH) data structures
3+
*
4+
* Copyright (C) 2014-2015 Intel Corporation.
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms and conditions of the GNU General Public License,
8+
* version 2, as published by the Free Software Foundation.
9+
*
10+
* This program is distributed in the hope it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13+
* more details.
14+
*/
15+
16+
#ifndef __INTEL_TH_STH_H__
17+
#define __INTEL_TH_STH_H__
18+
19+
enum {
20+
REG_STH_STHCAP0 = 0x0000, /* capabilities pt1 */
21+
REG_STH_STHCAP1 = 0x0004, /* capabilities pt2 */
22+
REG_STH_TRIG = 0x0008, /* TRIG packet payload */
23+
REG_STH_TRIG_TS = 0x000c, /* TRIG_TS packet payload */
24+
REG_STH_XSYNC = 0x0010, /* XSYNC packet payload */
25+
REG_STH_XSYNC_TS = 0x0014, /* XSYNC_TS packet payload */
26+
REG_STH_GERR = 0x0018, /* GERR packet payload */
27+
};
28+
29+
struct intel_th_channel {
30+
u64 Dn;
31+
u64 DnM;
32+
u64 DnTS;
33+
u64 DnMTS;
34+
u64 USER;
35+
u64 USER_TS;
36+
u32 FLAG;
37+
u32 FLAG_TS;
38+
u32 MERR;
39+
u32 __unused;
40+
} __packed;
41+
42+
#endif /* __INTEL_TH_STH_H__ */

0 commit comments

Comments
 (0)