diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c index 24a1f7797aeb6a65db6781b4a281f0385cc612cd..400468e9611758bd1acca092346ce65ebde8a8ab 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; } @@ -270,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; @@ -365,6 +368,45 @@ 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 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) { @@ -372,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) { @@ -393,6 +438,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); @@ -405,74 +455,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", @@ -484,10 +478,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) diff --git a/drivers/hwtracing/ptt/hisi_ptt.h b/drivers/hwtracing/ptt/hisi_ptt.h index e17f045d7e72597bc6bb0909722a0492e8db0e43..46030aa880811d1ccb29f5342b07cc9bef9bbef1 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 diff --git a/tools/perf/util/hisi-ptt.c b/tools/perf/util/hisi-ptt.c index 764d660d30e2f595e492c9e6b747da5e9f168141..52d0ce302ca042ed0bae720273443d3f2794affb 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);