1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
|
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver for HiSilicon PCIe tune and trace device
*
* Copyright (c) 2022 HiSilicon Technologies Co., Ltd.
* Author: Yicong Yang <yangyicong@hisilicon.com>
*/
#ifndef _HISI_PTT_H
#define _HISI_PTT_H
#include <linux/bits.h>
#include <linux/cpumask.h>
#include <linux/device.h>
#include <linux/kfifo.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/pci.h>
#include <linux/perf_event.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#define DRV_NAME "hisi_ptt"
/*
* The definition of the device registers and register fields.
*/
#define HISI_PTT_TUNING_CTRL 0x0000
#define HISI_PTT_TUNING_CTRL_CODE GENMASK(15, 0)
#define HISI_PTT_TUNING_CTRL_SUB GENMASK(23, 16)
#define HISI_PTT_TUNING_DATA 0x0004
#define HISI_PTT_TUNING_DATA_VAL_MASK GENMASK(15, 0)
#define HISI_PTT_TRACE_ADDR_SIZE 0x0800
#define HISI_PTT_TRACE_ADDR_BASE_LO_0 0x0810
#define HISI_PTT_TRACE_ADDR_BASE_HI_0 0x0814
#define HISI_PTT_TRACE_ADDR_STRIDE 0x8
#define HISI_PTT_TRACE_CTRL 0x0850
#define HISI_PTT_TRACE_CTRL_EN BIT(0)
#define HISI_PTT_TRACE_CTRL_RST BIT(1)
#define HISI_PTT_TRACE_CTRL_RXTX_SEL GENMASK(3, 2)
#define HISI_PTT_TRACE_CTRL_TYPE_SEL GENMASK(7, 4)
#define HISI_PTT_TRACE_CTRL_DATA_FORMAT BIT(14)
#define HISI_PTT_TRACE_CTRL_FILTER_MODE BIT(15)
#define HISI_PTT_TRACE_CTRL_TARGET_SEL GENMASK(31, 16)
#define HISI_PTT_TRACE_INT_STAT 0x0890
#define HISI_PTT_TRACE_INT_STAT_MASK GENMASK(3, 0)
#define HISI_PTT_TRACE_INT_MASK 0x0894
#define HISI_PTT_TUNING_INT_STAT 0x0898
#define HISI_PTT_TUNING_INT_STAT_MASK BIT(0)
#define HISI_PTT_TRACE_WR_STS 0x08a0
#define HISI_PTT_TRACE_WR_STS_WRITE GENMASK(27, 0)
#define HISI_PTT_TRACE_WR_STS_BUFFER GENMASK(29, 28)
#define HISI_PTT_TRACE_STS 0x08b0
#define HISI_PTT_TRACE_IDLE BIT(0)
#define HISI_PTT_DEVICE_RANGE 0x0fe0
#define HISI_PTT_DEVICE_RANGE_UPPER GENMASK(31, 16)
#define HISI_PTT_DEVICE_RANGE_LOWER GENMASK(15, 0)
#define HISI_PTT_LOCATION 0x0fe8
#define HISI_PTT_CORE_ID GENMASK(15, 0)
#define HISI_PTT_SICL_ID GENMASK(31, 16)
/* Parameters of PTT trace DMA part. */
#define HISI_PTT_TRACE_DMA_IRQ 0
#define HISI_PTT_TRACE_BUF_CNT 4
#define HISI_PTT_TRACE_BUF_SIZE SZ_4M
#define HISI_PTT_TRACE_TOTAL_BUF_SIZE (HISI_PTT_TRACE_BUF_SIZE * \
HISI_PTT_TRACE_BUF_CNT)
/* Wait time for hardware DMA to reset */
#define HISI_PTT_RESET_TIMEOUT_US 10UL
#define HISI_PTT_RESET_POLL_INTERVAL_US 1UL
/* Poll timeout and interval for waiting hardware work to finish */
#define HISI_PTT_WAIT_TUNE_TIMEOUT_US 1000000UL
#define HISI_PTT_WAIT_TRACE_TIMEOUT_US 100UL
#define HISI_PTT_WAIT_POLL_INTERVAL_US 10UL
/* FIFO size for dynamically updating the PTT trace filter list. */
#define HISI_PTT_FILTER_UPDATE_FIFO_SIZE 16
/* Delay time for filter updating work */
#define HISI_PTT_WORK_DELAY_MS 100UL
#define HISI_PCIE_CORE_PORT_ID(devfn) ((PCI_SLOT(devfn) & 0x7) << 1)
/* Definition of the PMU configs */
#define HISI_PTT_PMU_FILTER_IS_PORT BIT(19)
#define HISI_PTT_PMU_FILTER_VAL_MASK GENMASK(15, 0)
#define HISI_PTT_PMU_DIRECTION_MASK GENMASK(23, 20)
#define HISI_PTT_PMU_TYPE_MASK GENMASK(31, 24)
#define HISI_PTT_PMU_FORMAT_MASK GENMASK(35, 32)
/**
* struct hisi_ptt_tune_desc - Describe tune event for PTT tune
* @hisi_ptt: PTT device this tune event belongs to
* @name: name of this event
* @event_code: code of the event
*/
struct hisi_ptt_tune_desc {
struct hisi_ptt *hisi_ptt;
const char *name;
u32 event_code;
};
/**
* struct hisi_ptt_dma_buffer - Describe a single trace buffer of PTT trace.
* The detail of the data format is described
* in the documentation of PTT device.
* @dma: DMA address of this buffer visible to the device
* @addr: virtual address of this buffer visible to the cpu
*/
struct hisi_ptt_dma_buffer {
dma_addr_t dma;
void *addr;
};
/**
* struct hisi_ptt_trace_ctrl - Control and status of PTT trace
* @trace_buf: array of the trace buffers for holding the trace data.
* the length will be HISI_PTT_TRACE_BUF_CNT.
* @handle: perf output handle of current trace session
* @buf_index: the index of current using trace buffer
* @on_cpu: current tracing cpu
* @started: current trace status, true for started
* @is_port: whether we're tracing root port or not
* @direction: direction of the TLP headers to trace
* @filter: filter value for tracing the TLP headers
* @format: format of the TLP headers to trace
* @type: type of the TLP headers to trace
*/
struct hisi_ptt_trace_ctrl {
struct hisi_ptt_dma_buffer *trace_buf;
struct perf_output_handle handle;
u32 buf_index;
int on_cpu;
bool started;
bool is_port;
u32 direction:2;
u32 filter:16;
u32 format:1;
u32 type:4;
};
/*
* sysfs attribute group name for root port filters and requester filters:
* /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters
* and
* /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters
*/
#define HISI_PTT_RP_FILTERS_GRP_NAME "root_port_filters"
#define HISI_PTT_REQ_FILTERS_GRP_NAME "requester_filters"
/**
* struct hisi_ptt_filter_desc - Descriptor of the PTT trace filter
* @attr: sysfs attribute of this filter
* @list: entry of this descriptor in the filter list
* @is_port: the PCI device of the filter is a Root Port or not
* @name: name of this filter, same as the name of the related PCI device
* @devid: the PCI device's devid of the filter
*/
struct hisi_ptt_filter_desc {
struct device_attribute attr;
struct list_head list;
bool is_port;
char *name;
u16 devid;
};
/**
* struct hisi_ptt_filter_update_info - Information for PTT filter updating
* @is_port: the PCI device to update is a Root Port or not
* @is_add: adding to the filter or not
* @devid: the PCI device's devid of the filter
*/
struct hisi_ptt_filter_update_info {
bool is_port;
bool is_add;
u16 devid;
};
/**
* struct hisi_ptt_pmu_buf - Descriptor of the AUX buffer of PTT trace
* @length: size of the AUX buffer
* @nr_pages: number of pages of the AUX buffer
* @base: start address of AUX buffer
* @pos: position in the AUX buffer to commit traced data
*/
struct hisi_ptt_pmu_buf {
size_t length;
int nr_pages;
void *base;
long pos;
};
/**
* struct hisi_ptt - Per PTT device data
* @trace_ctrl: the control information of PTT trace
* @hisi_ptt_nb: dynamic filter update notifier
* @hotplug_node: node for register cpu hotplug event
* @hisi_ptt_pmu: the pum device of trace
* @iobase: base IO address of the device
* @pdev: pci_dev of this PTT device
* @tune_lock: lock to serialize the tune process
* @pmu_lock: lock to serialize the perf process
* @trace_irq: interrupt number used by trace
* @upper_bdf: the upper BDF range of the PCI devices managed by this PTT device
* @lower_bdf: the lower BDF range of the PCI devices managed by this PTT device
* @port_filters: the filter list of root ports
* @req_filters: the filter list of requester ID
* @filter_lock: lock to protect the filters
* @sysfs_inited: whether the filters' sysfs entries has been initialized
* @port_mask: port mask of the managed root ports
* @work: delayed work for filter updating
* @filter_update_lock: spinlock to protect the filter update fifo
* @filter_update_fifo: fifo of the filters waiting to update the filter list
*/
struct hisi_ptt {
struct hisi_ptt_trace_ctrl trace_ctrl;
struct notifier_block hisi_ptt_nb;
struct hlist_node hotplug_node;
struct pmu hisi_ptt_pmu;
void __iomem *iobase;
struct pci_dev *pdev;
struct mutex tune_lock;
spinlock_t pmu_lock;
int trace_irq;
u32 upper_bdf;
u32 lower_bdf;
/*
* The trace TLP headers can either be filtered by certain
* root port, or by the requester ID. Organize the filters
* by @port_filters and @req_filters here. The mask of all
* the valid ports is also cached for doing sanity check
* of user input.
*/
struct list_head port_filters;
struct list_head req_filters;
struct mutex filter_lock;
bool sysfs_inited;
u16 port_mask;
/*
* We use a delayed work here to avoid indefinitely waiting for
* the hisi_ptt->mutex which protecting the filter list. The
* work will be delayed only if the mutex can not be held,
* otherwise no delay will be applied.
*/
struct delayed_work work;
spinlock_t filter_update_lock;
DECLARE_KFIFO(filter_update_kfifo, struct hisi_ptt_filter_update_info,
HISI_PTT_FILTER_UPDATE_FIFO_SIZE);
};
#define to_hisi_ptt(pmu) container_of(pmu, struct hisi_ptt, hisi_ptt_pmu)
#endif /* _HISI_PTT_H */
|