From 2f68693b262c525efb7239889007f4f90ae07ac0 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Sat, 30 Sep 2023 15:27:19 +0800 Subject: [PATCH 1/5] perf hisi-ptt: Fix memory leak in lseek failure handling ANBZ: #31325 commit be7a4caa7c45bd4b0a39cdb260905b52a87c8688 upstream In the previous code, there was a memory leak issue where the previously allocated memory was not freed upon a failed lseek operation. This patch addresses the problem by releasing the old memory before returning -errno in case of a lseek failure. This ensures that memory is properly managed and avoids potential memory leaks. Signed-off-by: Kuan-Wei Chiu Acked-by: Namhyung Kim Cc: yangyicong@hisilicon.com Cc: jonathan.cameron@huawei.com Link: https://lore.kernel.org/r/20230930072719.1267784-1-visitorckw@gmail.com Signed-off-by: Namhyung Kim Signed-off-by: zhangxinghao --- tools/perf/util/hisi-ptt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/hisi-ptt.c b/tools/perf/util/hisi-ptt.c index 764d660d30e2..52d0ce302ca0 100644 --- a/tools/perf/util/hisi-ptt.c +++ b/tools/perf/util/hisi-ptt.c @@ -108,8 +108,10 @@ static int hisi_ptt_process_auxtrace_event(struct perf_session *session, data_offset = 0; } else { data_offset = lseek(fd, 0, SEEK_CUR); - if (data_offset == -1) + if (data_offset == -1) { + free(data); return -errno; + } } err = readn(fd, data, size); -- Gitee From 5a522b79143d7d513c7ba6a3c38936b9ce0a40e4 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Tue, 10 Oct 2023 16:47:27 +0800 Subject: [PATCH 2/5] hwtracing: hisi_ptt: Disable interrupt after trace end ANBZ: #31325 commit 46f69b197b6cd06c709581f7ad271bc02dbedb7a upstream On trace end we disable the hardware but leave the interrupt unmasked. Mask the interrupt to make the process reverse to the start. No actual issue since hardware should send no interrupt after disabled. Signed-off-by: Yicong Yang Acked-by: Jonathan Cameron Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20231010084731.30450-2-yangyicong@huawei.com Signed-off-by: zhangxinghao --- drivers/hwtracing/ptt/hisi_ptt.c | 4 ++++ drivers/hwtracing/ptt/hisi_ptt.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c index 24a1f7797aeb..2a4d717bc413 100644 --- a/drivers/hwtracing/ptt/hisi_ptt.c +++ b/drivers/hwtracing/ptt/hisi_ptt.c @@ -183,6 +183,10 @@ static void hisi_ptt_wait_dma_reset_done(struct hisi_ptt *hisi_ptt) static void hisi_ptt_trace_end(struct hisi_ptt *hisi_ptt) { writel(0, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL); + + /* Mask the interrupt on the end */ + writel(HISI_PTT_TRACE_INT_MASK_ALL, hisi_ptt->iobase + HISI_PTT_TRACE_INT_MASK); + hisi_ptt->trace_ctrl.started = false; } diff --git a/drivers/hwtracing/ptt/hisi_ptt.h b/drivers/hwtracing/ptt/hisi_ptt.h index e17f045d7e72..46030aa88081 100644 --- a/drivers/hwtracing/ptt/hisi_ptt.h +++ b/drivers/hwtracing/ptt/hisi_ptt.h @@ -47,6 +47,7 @@ #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_TRACE_INT_MASK_ALL GENMASK(3, 0) #define HISI_PTT_TUNING_INT_STAT 0x0898 #define HISI_PTT_TUNING_INT_STAT_MASK BIT(0) #define HISI_PTT_TRACE_WR_STS 0x08a0 -- Gitee From 896a1abae4f46bbfc804ac397fce3c19aedefe16 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Tue, 10 Oct 2023 16:47:29 +0800 Subject: [PATCH 3/5] hwtracing: hisi_ptt: Optimize the trace data committing ANBZ: #31325 commit dabf410d8764dbb24832d18bb825fe7ba5e75d30 upstream In the current implementation, there're 4*4MiB trace buffer and hardware will fill the buffer one by one. The driver will get notified if one buffer is full and then copy data to the AUX buffer. If there's no enough room for the next trace buffer, we'll commit the AUX buffer to the perf core and try to apply a new one. In a typical configuration the AUX buffer will be 16MiB, so we'll commit the data after the whole AUX buffer is occupied. Then the driver cannot apply a new AUX buffer immediately until the committed data is consumed by userspace and then there's room in the AUX buffer again. This patch tries to optimize this by commit the data after one single trace buffer is filled. Since there's still room in the AUX buffer, driver can apply a new one without failure and don't need to wait for the userspace to consume the data. Signed-off-by: Yicong Yang Acked-by: Jonathan Cameron Signed-off-by: Suzuki K Poulose Link: https://lore.kernel.org/r/20231010084731.30450-4-yangyicong@huawei.com Signed-off-by: zhangxinghao --- drivers/hwtracing/ptt/hisi_ptt.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c index 2a4d717bc413..4bf04a977840 100644 --- a/drivers/hwtracing/ptt/hisi_ptt.c +++ b/drivers/hwtracing/ptt/hisi_ptt.c @@ -274,15 +274,14 @@ static int hisi_ptt_update_aux(struct hisi_ptt *hisi_ptt, int index, bool stop) buf->pos += size; /* - * Just commit the traced data if we're going to stop. Otherwise if the - * resident AUX buffer cannot contain the data of next trace buffer, - * apply a new one. + * Always commit the data to the AUX buffer in time to make sure + * userspace got enough time to consume the data. + * + * If we're not going to stop, apply a new one and check whether + * there's enough room for the next trace. */ - if (stop) { - perf_aux_output_end(handle, buf->pos); - } else if (buf->length - buf->pos < HISI_PTT_TRACE_BUF_SIZE) { - perf_aux_output_end(handle, buf->pos); - + perf_aux_output_end(handle, size); + if (!stop) { buf = perf_aux_output_begin(handle, event); if (!buf) return -EINVAL; -- Gitee From 2a04f54d0f0dd17b19f9f727cb79be284602a5a6 Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Sat, 15 Feb 2025 17:26:12 +0800 Subject: [PATCH 4/5] hwtracing: hisi_ptt: Initialize the filter sysfs attribute when allocation ANBZ: #31325 commit 049045f499e1cc07a132c3ef010f15abce995e03 openeuler driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBNZ64 CVE: NA -------------------------------- The filter sysfs attribute is initialized when register to the sysfs. This is unnecessary and could be done when allocation without distinguish the filter type. After the changes above, we don't need a wrapper for initializing and registering the filter's sysfs attributes. Remove them and call the sysfs creating/removing functions in place. Fixes: 6373c463ac89 ("hwtracing: hisi_ptt: Export available filters through sysfs") Signed-off-by: Yicong Yang Signed-off-by: lujunhua Signed-off-by: zhangxinghao --- drivers/hwtracing/ptt/hisi_ptt.c | 92 ++++++++++---------------------- 1 file changed, 29 insertions(+), 63 deletions(-) diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c index 4bf04a977840..0f2168e11697 100644 --- a/drivers/hwtracing/ptt/hisi_ptt.c +++ b/drivers/hwtracing/ptt/hisi_ptt.c @@ -368,6 +368,19 @@ static void hisi_ptt_del_free_filter(struct hisi_ptt *hisi_ptt, kfree(filter); } +static ssize_t hisi_ptt_filter_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct hisi_ptt_filter_desc *filter; + unsigned long filter_val; + + filter = container_of(attr, struct hisi_ptt_filter_desc, attr); + filter_val = hisi_ptt_get_filter_val(filter->devid, filter->is_port) | + (filter->is_port ? HISI_PTT_PMU_FILTER_IS_PORT : 0); + + return sysfs_emit(buf, "0x%05lx\n", filter_val); +} + static struct hisi_ptt_filter_desc * hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port) { @@ -396,6 +409,11 @@ hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port) filter->is_port = is_port; filter->devid = devid; + sysfs_attr_init(&filter->attr.attr); + filter->attr.attr.name = filter->name; + filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */ + filter->attr.show = hisi_ptt_filter_show; + if (filter->is_port) { list_add_tail(&filter->list, &hisi_ptt->port_filters); @@ -408,74 +426,18 @@ hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port) return filter; } -static ssize_t hisi_ptt_filter_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct hisi_ptt_filter_desc *filter; - unsigned long filter_val; - - filter = container_of(attr, struct hisi_ptt_filter_desc, attr); - filter_val = hisi_ptt_get_filter_val(filter->devid, filter->is_port) | - (filter->is_port ? HISI_PTT_PMU_FILTER_IS_PORT : 0); - - return sysfs_emit(buf, "0x%05lx\n", filter_val); -} - -static int hisi_ptt_create_rp_filter_attr(struct hisi_ptt *hisi_ptt, - struct hisi_ptt_filter_desc *filter) -{ - struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; - - sysfs_attr_init(&filter->attr.attr); - filter->attr.attr.name = filter->name; - filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */ - filter->attr.show = hisi_ptt_filter_show; - - return sysfs_add_file_to_group(kobj, &filter->attr.attr, - HISI_PTT_RP_FILTERS_GRP_NAME); -} - -static void hisi_ptt_remove_rp_filter_attr(struct hisi_ptt *hisi_ptt, - struct hisi_ptt_filter_desc *filter) -{ - struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; - - sysfs_remove_file_from_group(kobj, &filter->attr.attr, - HISI_PTT_RP_FILTERS_GRP_NAME); -} - -static int hisi_ptt_create_req_filter_attr(struct hisi_ptt *hisi_ptt, - struct hisi_ptt_filter_desc *filter) -{ - struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; - - sysfs_attr_init(&filter->attr.attr); - filter->attr.attr.name = filter->name; - filter->attr.attr.mode = 0400; /* DEVICE_ATTR_ADMIN_RO */ - filter->attr.show = hisi_ptt_filter_show; - - return sysfs_add_file_to_group(kobj, &filter->attr.attr, - HISI_PTT_REQ_FILTERS_GRP_NAME); -} - -static void hisi_ptt_remove_req_filter_attr(struct hisi_ptt *hisi_ptt, - struct hisi_ptt_filter_desc *filter) -{ - struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; - - sysfs_remove_file_from_group(kobj, &filter->attr.attr, - HISI_PTT_REQ_FILTERS_GRP_NAME); -} - static int hisi_ptt_create_filter_attr(struct hisi_ptt *hisi_ptt, struct hisi_ptt_filter_desc *filter) { + struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; int ret; if (filter->is_port) - ret = hisi_ptt_create_rp_filter_attr(hisi_ptt, filter); + ret = sysfs_add_file_to_group(kobj, &filter->attr.attr, + HISI_PTT_RP_FILTERS_GRP_NAME); else - ret = hisi_ptt_create_req_filter_attr(hisi_ptt, filter); + ret = sysfs_add_file_to_group(kobj, &filter->attr.attr, + HISI_PTT_REQ_FILTERS_GRP_NAME); if (ret) pci_err(hisi_ptt->pdev, "failed to create sysfs attribute for filter %s\n", @@ -487,10 +449,14 @@ static int hisi_ptt_create_filter_attr(struct hisi_ptt *hisi_ptt, static void hisi_ptt_remove_filter_attr(struct hisi_ptt *hisi_ptt, struct hisi_ptt_filter_desc *filter) { + struct kobject *kobj = &hisi_ptt->hisi_ptt_pmu.dev->kobj; + if (filter->is_port) - hisi_ptt_remove_rp_filter_attr(hisi_ptt, filter); + sysfs_remove_file_from_group(kobj, &filter->attr.attr, + HISI_PTT_RP_FILTERS_GRP_NAME); else - hisi_ptt_remove_req_filter_attr(hisi_ptt, filter); + sysfs_remove_file_from_group(kobj, &filter->attr.attr, + HISI_PTT_REQ_FILTERS_GRP_NAME); } static void hisi_ptt_remove_all_filter_attributes(void *data) -- Gitee From 18f5b02afc199b178eb690a6b0cea5f8db548bcd Mon Sep 17 00:00:00 2001 From: Yicong Yang Date: Mon, 24 Feb 2025 22:03:12 +0800 Subject: [PATCH 5/5] hwtracing: hisi_ptt: Check duplicate filters before allocation ANBZ: #31325 commit 8945c86d86ee01a8198a9c04cb8082d284622f50 openeuler driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBNZ64 CVE: NA -------------------------------- Abnormally it's reported duplicated filters added in the filter list, though the filter we created should be unique maintained by the PCIe framework. Add a duplicate filters check before allocation to prevent this case. Fixes: 6373c463ac89 ("hwtracing: hisi_ptt: Export available filters through sysfs") Signed-off-by: Yicong Yang Signed-off-by: lujunhua Signed-off-by: zhangxinghao --- drivers/hwtracing/ptt/hisi_ptt.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c index 0f2168e11697..400468e96117 100644 --- a/drivers/hwtracing/ptt/hisi_ptt.c +++ b/drivers/hwtracing/ptt/hisi_ptt.c @@ -381,6 +381,32 @@ static ssize_t hisi_ptt_filter_show(struct device *dev, struct device_attribute return sysfs_emit(buf, "0x%05lx\n", filter_val); } +static int hisi_ptt_check_duplicated_filters(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port) +{ + struct hisi_ptt_filter_desc *filter; + struct list_head *target_list; + u8 devfn = devid & 0xff; + + if (is_port) + target_list = &hisi_ptt->port_filters; + else + target_list = &hisi_ptt->req_filters; + + list_for_each_entry(filter, target_list, list) { + if (filter->devid == devid) { + pci_warn(hisi_ptt->pdev, + "ignore duplicated filter %04x:%02x:%02x.%d\n", + pci_domain_nr(hisi_ptt->pdev->bus), + PCI_BUS_NUM(devid), PCI_SLOT(devfn), + PCI_FUNC(devfn)); + + return -EEXIST; + } + } + + return 0; +} + static struct hisi_ptt_filter_desc * hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port) { @@ -388,6 +414,9 @@ hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port) u8 devfn = devid & 0xff; char *filter_name; + if (hisi_ptt_check_duplicated_filters(hisi_ptt, devid, is_port)) + return NULL; + filter_name = kasprintf(GFP_KERNEL, "%04x:%02x:%02x.%d", pci_domain_nr(hisi_ptt->pdev->bus), PCI_BUS_NUM(devid), PCI_SLOT(devfn), PCI_FUNC(devfn)); if (!filter_name) { -- Gitee