Skip to content

Commit 6373c46

Browse files
Yicong YangSuzuki K Poulose
authored andcommitted
hwtracing: hisi_ptt: Export available filters through sysfs
The PTT can only filter the traced TLP headers by the Root Ports or the Requester ID of the Endpoint, which are located on the same PCIe core of the PTT device. The filter value used is derived from the BDF number of the supported Root Port or the Endpoint. It's not friendly enough for the users since it requires the user to be familiar enough with the platform and calculate the filter value manually. This patch export the available filters through sysfs. Each available filters is presented as an individual file with the name of the BDF number of the related PCIe device. The files are created under $(PTT PMU dir)/available_root_port_filters and $(PTT PMU dir)/available_requester_filters respectively. The filter value can be known by reading the related file. Then the users can easily know the available filters for trace and get the filter values without calculating. Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Yicong Yang <yangyicong@hisilicon.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20230621092804.15120-4-yangyicong@huawei.com
1 parent 556ef09 commit 6373c46

4 files changed

Lines changed: 279 additions & 0 deletions

File tree

Documentation/ABI/testing/sysfs-devices-hisi_ptt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,55 @@ Description: (RW) Control the allocated buffer watermark of outbound packets.
5959
The available tune data is [0, 1, 2]. Writing a negative value
6060
will return an error, and out of range values will be converted
6161
to 2. The value indicates a probable level of the event.
62+
63+
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters
64+
Date: May 2023
65+
KernelVersion: 6.5
66+
Contact: Yicong Yang <yangyicong@hisilicon.com>
67+
Description: This directory contains the files providing the PCIe Root Port filters
68+
information used for PTT trace. Each file is named after the supported
69+
Root Port device name <domain>:<bus>:<device>.<function>.
70+
71+
See the description of the "filter" in Documentation/trace/hisi-ptt.rst
72+
for more information.
73+
74+
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters/multiselect
75+
Date: May 2023
76+
KernelVersion: 6.5
77+
Contact: Yicong Yang <yangyicong@hisilicon.com>
78+
Description: (Read) Indicates if this kind of filter can be selected at the same
79+
time as others filters, or must be used on it's own. 1 indicates
80+
the former case and 0 indicates the latter.
81+
82+
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters/<bdf>
83+
Date: May 2023
84+
KernelVersion: 6.5
85+
Contact: Yicong Yang <yangyicong@hisilicon.com>
86+
Description: (Read) Indicates the filter value of this Root Port filter, which
87+
can be used to control the TLP headers to trace by the PTT trace.
88+
89+
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters
90+
Date: May 2023
91+
KernelVersion: 6.5
92+
Contact: Yicong Yang <yangyicong@hisilicon.com>
93+
Description: This directory contains the files providing the PCIe Requester filters
94+
information used for PTT trace. Each file is named after the supported
95+
Endpoint device name <domain>:<bus>:<device>.<function>.
96+
97+
See the description of the "filter" in Documentation/trace/hisi-ptt.rst
98+
for more information.
99+
100+
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters/multiselect
101+
Date: May 2023
102+
KernelVersion: 6.5
103+
Contact: Yicong Yang <yangyicong@hisilicon.com>
104+
Description: (Read) Indicates if this kind of filter can be selected at the same
105+
time as others filters, or must be used on it's own. 1 indicates
106+
the former case and 0 indicates the latter.
107+
108+
What: /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters/<bdf>
109+
Date: May 2023
110+
KernelVersion: 6.5
111+
Contact: Yicong Yang <yangyicong@hisilicon.com>
112+
Description: (Read) Indicates the filter value of this Requester filter, which
113+
can be used to control the TLP headers to trace by the PTT trace.

Documentation/trace/hisi-ptt.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ For example, if the desired filter is Endpoint function 0000:01:00.1 the filter
148148
value will be 0x00101. If the desired filter is Root Port 0000:00:10.0 then
149149
then filter value is calculated as 0x80001.
150150

151+
The driver also presents every supported Root Port and Requester filter through
152+
sysfs. Each filter will be an individual file with name of its related PCIe
153+
device name (domain:bus:device.function). The files of Root Port filters are
154+
under $(PTT PMU dir)/root_port_filters and files of Requester filters
155+
are under $(PTT PMU dir)/requester_filters.
156+
151157
Note that multiple Root Ports can be specified at one time, but only one
152158
Endpoint function can be specified in one trace. Specifying both Root Port
153159
and function at the same time is not supported. Driver maintains a list of

drivers/hwtracing/ptt/hisi_ptt.c

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,144 @@ hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port)
405405
return filter;
406406
}
407407

408+
static ssize_t hisi_ptt_filter_show(struct device *dev, struct device_attribute *attr,
409+
char *buf)
410+
{
411+
struct hisi_ptt_filter_desc *filter;
412+
unsigned long filter_val;
413+
414+
filter = container_of(attr, struct hisi_ptt_filter_desc, attr);
415+
filter_val = hisi_ptt_get_filter_val(filter->devid, filter->is_port) |
416+
(filter->is_port ? HISI_PTT_PMU_FILTER_IS_PORT : 0);
417+
418+
return sysfs_emit(buf, "0x%05lx\n", filter_val);
419+
}
420+
421+
static int hisi_ptt_create_rp_filter_attr(struct hisi_ptt *hisi_ptt,
422+
struct hisi_ptt_filter_desc *filter)
423+
{
424+
struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj;
425+
426+
sysfs_attr_init(&filter->attr.attr);
427+
filter->attr.attr.name = filter->name;
428+
filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */
429+
filter->attr.show = hisi_ptt_filter_show;
430+
431+
return sysfs_add_file_to_group(kobj, &filter->attr.attr,
432+
HISI_PTT_RP_FILTERS_GRP_NAME);
433+
}
434+
435+
static void hisi_ptt_remove_rp_filter_attr(struct hisi_ptt *hisi_ptt,
436+
struct hisi_ptt_filter_desc *filter)
437+
{
438+
struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj;
439+
440+
sysfs_remove_file_from_group(kobj, &filter->attr.attr,
441+
HISI_PTT_RP_FILTERS_GRP_NAME);
442+
}
443+
444+
static int hisi_ptt_create_req_filter_attr(struct hisi_ptt *hisi_ptt,
445+
struct hisi_ptt_filter_desc *filter)
446+
{
447+
struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj;
448+
449+
sysfs_attr_init(&filter->attr.attr);
450+
filter->attr.attr.name = filter->name;
451+
filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */
452+
filter->attr.show = hisi_ptt_filter_show;
453+
454+
return sysfs_add_file_to_group(kobj, &filter->attr.attr,
455+
HISI_PTT_REQ_FILTERS_GRP_NAME);
456+
}
457+
458+
static void hisi_ptt_remove_req_filter_attr(struct hisi_ptt *hisi_ptt,
459+
struct hisi_ptt_filter_desc *filter)
460+
{
461+
struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj;
462+
463+
sysfs_remove_file_from_group(kobj, &filter->attr.attr,
464+
HISI_PTT_REQ_FILTERS_GRP_NAME);
465+
}
466+
467+
static int hisi_ptt_create_filter_attr(struct hisi_ptt *hisi_ptt,
468+
struct hisi_ptt_filter_desc *filter)
469+
{
470+
int ret;
471+
472+
if (filter->is_port)
473+
ret = hisi_ptt_create_rp_filter_attr(hisi_ptt, filter);
474+
else
475+
ret = hisi_ptt_create_req_filter_attr(hisi_ptt, filter);
476+
477+
if (ret)
478+
pci_err(hisi_ptt->pdev, "failed to create sysfs attribute for filter %s\n",
479+
filter->name);
480+
481+
return ret;
482+
}
483+
484+
static void hisi_ptt_remove_filter_attr(struct hisi_ptt *hisi_ptt,
485+
struct hisi_ptt_filter_desc *filter)
486+
{
487+
if (filter->is_port)
488+
hisi_ptt_remove_rp_filter_attr(hisi_ptt, filter);
489+
else
490+
hisi_ptt_remove_req_filter_attr(hisi_ptt, filter);
491+
}
492+
493+
static void hisi_ptt_remove_all_filter_attributes(void *data)
494+
{
495+
struct hisi_ptt_filter_desc *filter;
496+
struct hisi_ptt *hisi_ptt = data;
497+
498+
mutex_lock(&hisi_ptt->filter_lock);
499+
500+
list_for_each_entry(filter, &hisi_ptt->req_filters, list)
501+
hisi_ptt_remove_filter_attr(hisi_ptt, filter);
502+
503+
list_for_each_entry(filter, &hisi_ptt->port_filters, list)
504+
hisi_ptt_remove_filter_attr(hisi_ptt, filter);
505+
506+
hisi_ptt->sysfs_inited = false;
507+
mutex_unlock(&hisi_ptt->filter_lock);
508+
}
509+
510+
static int hisi_ptt_init_filter_attributes(struct hisi_ptt *hisi_ptt)
511+
{
512+
struct hisi_ptt_filter_desc *filter;
513+
int ret;
514+
515+
mutex_lock(&hisi_ptt->filter_lock);
516+
517+
/*
518+
* Register the reset callback in the first stage. In reset we traverse
519+
* the filters list to remove the sysfs attributes so the callback can
520+
* be called safely even without below filter attributes creation.
521+
*/
522+
ret = devm_add_action(&hisi_ptt->pdev->dev,
523+
hisi_ptt_remove_all_filter_attributes,
524+
hisi_ptt);
525+
if (ret)
526+
goto out;
527+
528+
list_for_each_entry(filter, &hisi_ptt->port_filters, list) {
529+
ret = hisi_ptt_create_filter_attr(hisi_ptt, filter);
530+
if (ret)
531+
goto out;
532+
}
533+
534+
list_for_each_entry(filter, &hisi_ptt->req_filters, list) {
535+
ret = hisi_ptt_create_filter_attr(hisi_ptt, filter);
536+
if (ret)
537+
goto out;
538+
}
539+
540+
hisi_ptt->sysfs_inited = true;
541+
out:
542+
mutex_unlock(&hisi_ptt->filter_lock);
543+
return ret;
544+
}
545+
408546
static void hisi_ptt_update_filters(struct work_struct *work)
409547
{
410548
struct delayed_work *delayed_work = to_delayed_work(work);
@@ -429,6 +567,18 @@ static void hisi_ptt_update_filters(struct work_struct *work)
429567
filter = hisi_ptt_alloc_add_filter(hisi_ptt, info.devid, info.is_port);
430568
if (!filter)
431569
continue;
570+
571+
/*
572+
* If filters' sysfs entries hasn't been initialized,
573+
* then we're still at probe stage. Add the filters to
574+
* the list and later hisi_ptt_init_filter_attributes()
575+
* will create sysfs attributes for all the filters.
576+
*/
577+
if (hisi_ptt->sysfs_inited &&
578+
hisi_ptt_create_filter_attr(hisi_ptt, filter)) {
579+
hisi_ptt_del_free_filter(hisi_ptt, filter);
580+
continue;
581+
}
432582
} else {
433583
struct hisi_ptt_filter_desc *tmp;
434584
struct list_head *target_list;
@@ -438,6 +588,9 @@ static void hisi_ptt_update_filters(struct work_struct *work)
438588

439589
list_for_each_entry_safe(filter, tmp, target_list, list)
440590
if (filter->devid == info.devid) {
591+
if (hisi_ptt->sysfs_inited)
592+
hisi_ptt_remove_filter_attr(hisi_ptt, filter);
593+
441594
hisi_ptt_del_free_filter(hisi_ptt, filter);
442595
break;
443596
}
@@ -663,10 +816,58 @@ static struct attribute_group hisi_ptt_pmu_format_group = {
663816
.attrs = hisi_ptt_pmu_format_attrs,
664817
};
665818

819+
static ssize_t hisi_ptt_filter_multiselect_show(struct device *dev,
820+
struct device_attribute *attr,
821+
char *buf)
822+
{
823+
struct dev_ext_attribute *ext_attr;
824+
825+
ext_attr = container_of(attr, struct dev_ext_attribute, attr);
826+
return sysfs_emit(buf, "%s\n", (char *)ext_attr->var);
827+
}
828+
829+
static struct dev_ext_attribute root_port_filters_multiselect = {
830+
.attr = {
831+
.attr = { .name = "multiselect", .mode = 0400 },
832+
.show = hisi_ptt_filter_multiselect_show,
833+
},
834+
.var = "1",
835+
};
836+
837+
static struct attribute *hisi_ptt_pmu_root_ports_attrs[] = {
838+
&root_port_filters_multiselect.attr.attr,
839+
NULL
840+
};
841+
842+
static struct attribute_group hisi_ptt_pmu_root_ports_group = {
843+
.name = HISI_PTT_RP_FILTERS_GRP_NAME,
844+
.attrs = hisi_ptt_pmu_root_ports_attrs,
845+
};
846+
847+
static struct dev_ext_attribute requester_filters_multiselect = {
848+
.attr = {
849+
.attr = { .name = "multiselect", .mode = 0400 },
850+
.show = hisi_ptt_filter_multiselect_show,
851+
},
852+
.var = "0",
853+
};
854+
855+
static struct attribute *hisi_ptt_pmu_requesters_attrs[] = {
856+
&requester_filters_multiselect.attr.attr,
857+
NULL
858+
};
859+
860+
static struct attribute_group hisi_ptt_pmu_requesters_group = {
861+
.name = HISI_PTT_REQ_FILTERS_GRP_NAME,
862+
.attrs = hisi_ptt_pmu_requesters_attrs,
863+
};
864+
666865
static const struct attribute_group *hisi_ptt_pmu_groups[] = {
667866
&hisi_ptt_cpumask_attr_group,
668867
&hisi_ptt_pmu_format_group,
669868
&hisi_ptt_tune_group,
869+
&hisi_ptt_pmu_root_ports_group,
870+
&hisi_ptt_pmu_requesters_group,
670871
NULL
671872
};
672873

@@ -1147,6 +1348,12 @@ static int hisi_ptt_probe(struct pci_dev *pdev,
11471348
return ret;
11481349
}
11491350

1351+
ret = hisi_ptt_init_filter_attributes(hisi_ptt);
1352+
if (ret) {
1353+
pci_err(pdev, "failed to init sysfs filter attributes, ret = %d", ret);
1354+
return ret;
1355+
}
1356+
11501357
return 0;
11511358
}
11521359

drivers/hwtracing/ptt/hisi_ptt.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <linux/bits.h>
1313
#include <linux/cpumask.h>
14+
#include <linux/device.h>
1415
#include <linux/kfifo.h>
1516
#include <linux/list.h>
1617
#include <linux/mutex.h>
@@ -139,14 +140,25 @@ struct hisi_ptt_trace_ctrl {
139140
u32 type:4;
140141
};
141142

143+
/*
144+
* sysfs attribute group name for root port filters and requester filters:
145+
* /sys/devices/hisi_ptt<sicl_id>_<core_id>/root_port_filters
146+
* and
147+
* /sys/devices/hisi_ptt<sicl_id>_<core_id>/requester_filters
148+
*/
149+
#define HISI_PTT_RP_FILTERS_GRP_NAME "root_port_filters"
150+
#define HISI_PTT_REQ_FILTERS_GRP_NAME "requester_filters"
151+
142152
/**
143153
* struct hisi_ptt_filter_desc - Descriptor of the PTT trace filter
154+
* @attr: sysfs attribute of this filter
144155
* @list: entry of this descriptor in the filter list
145156
* @is_port: the PCI device of the filter is a Root Port or not
146157
* @name: name of this filter, same as the name of the related PCI device
147158
* @devid: the PCI device's devid of the filter
148159
*/
149160
struct hisi_ptt_filter_desc {
161+
struct device_attribute attr;
150162
struct list_head list;
151163
bool is_port;
152164
char *name;
@@ -194,6 +206,7 @@ struct hisi_ptt_pmu_buf {
194206
* @port_filters: the filter list of root ports
195207
* @req_filters: the filter list of requester ID
196208
* @filter_lock: lock to protect the filters
209+
* @sysfs_inited: whether the filters' sysfs entries has been initialized
197210
* @port_mask: port mask of the managed root ports
198211
* @work: delayed work for filter updating
199212
* @filter_update_lock: spinlock to protect the filter update fifo
@@ -221,6 +234,7 @@ struct hisi_ptt {
221234
struct list_head port_filters;
222235
struct list_head req_filters;
223236
struct mutex filter_lock;
237+
bool sysfs_inited;
224238
u16 port_mask;
225239

226240
/*

0 commit comments

Comments
 (0)