From 17fccd4fd946ca779bd00fb73e2c671c3c09be3f Mon Sep 17 00:00:00 2001 From: YunYi Yang Date: Thu, 12 Oct 2023 22:02:39 +0800 Subject: [PATCH] Add the feature of pcie PTT and Add support 4TB bar --- kernel.spec | 23 +- ...0001-PCI-Support-BAR-sizes-up-to-8TB.patch | 52 + ...ef_domain_type-callback-in-iommu_ops.patch | 186 +++ ...3-Make-default-domain-type-of-HiSili.patch | 78 ++ ...3-Integrate-the-function-for-obtain-.patch | 75 + ...q-Export-affinity-setter-for-modules.patch | 134 ++ ...tt-Add-trace-function-support-for-Hi.patch | 1243 +++++++++++++++++ ...tt-Add-tune-function-support-for-HiS.patch | 272 ++++ ...iSilicon-PTT-device-driver-documenta.patch | 426 ++++++ ...-maintainer-for-HiSilicon-PTT-driver.patch | 57 + ...tt-Fix-up-for-iommu-dma-Make-header-.patch | 61 + ...tt-Only-add-the-supported-devices-to.patch | 59 + ...tt-Factor-out-filter-allocation-and-.patch | 121 ++ ...tt-Add-support-for-dynamically-updat.patch | 423 ++++++ ...tt-Export-available-filters-through-.patch | 435 ++++++ ...tt-Advertise-PERF_PMU_CAP_NO_EXCLUDE.patch | 45 + ...tt-Fix-potential-sleep-in-atomic-con.patch | 111 ++ ...tt-Keep-to-advertise-PERF_PMU_CAP_EX.patch | 39 + ...hisi_ptt-Add-dummy-callback-pmu-read.patch | 106 ++ ...nfig-arm64-Enable-config-of-hisi-ptt.patch | 33 + series.conf | 19 + 21 files changed, 3997 insertions(+), 1 deletion(-) create mode 100644 patches/0001-PCI-Support-BAR-sizes-up-to-8TB.patch create mode 100644 patches/0002-iommu-Add-def_domain_type-callback-in-iommu_ops.patch create mode 100644 patches/0003-iommu-arm-smmu-v3-Make-default-domain-type-of-HiSili.patch create mode 100644 patches/0004-iommu-arm-smmu-v3-Integrate-the-function-for-obtain-.patch create mode 100644 patches/0005-genirq-Export-affinity-setter-for-modules.patch create mode 100644 patches/0006-hwtracing-hisi_ptt-Add-trace-function-support-for-Hi.patch create mode 100644 patches/0007-hwtracing-hisi_ptt-Add-tune-function-support-for-HiS.patch create mode 100644 patches/0008-docs-trace-Add-HiSilicon-PTT-device-driver-documenta.patch create mode 100644 patches/0009-MAINTAINERS-Add-maintainer-for-HiSilicon-PTT-driver.patch create mode 100644 patches/0010-hwtracing-hisi_ptt-Fix-up-for-iommu-dma-Make-header-.patch create mode 100644 patches/0011-hwtracing-hisi_ptt-Only-add-the-supported-devices-to.patch create mode 100644 patches/0012-hwtracing-hisi_ptt-Factor-out-filter-allocation-and-.patch create mode 100644 patches/0013-hwtracing-hisi_ptt-Add-support-for-dynamically-updat.patch create mode 100644 patches/0014-hwtracing-hisi_ptt-Export-available-filters-through-.patch create mode 100644 patches/0015-hwtracing-hisi_ptt-Advertise-PERF_PMU_CAP_NO_EXCLUDE.patch create mode 100644 patches/0016-hwtracing-hisi_ptt-Fix-potential-sleep-in-atomic-con.patch create mode 100644 patches/0017-hwtracing-hisi_ptt-Keep-to-advertise-PERF_PMU_CAP_EX.patch create mode 100644 patches/0018-hwtracing-hisi_ptt-Add-dummy-callback-pmu-read.patch create mode 100644 patches/0019-config-arm64-Enable-config-of-hisi-ptt.patch diff --git a/kernel.spec b/kernel.spec index 9eb806c..5bcf947 100644 --- a/kernel.spec +++ b/kernel.spec @@ -32,7 +32,7 @@ Name: kernel Version: 4.19.90 -Release: %{hulkrelease}.0224 +Release: %{hulkrelease}.0225 Summary: Linux Kernel License: GPLv2 URL: http://www.kernel.org/ @@ -807,6 +807,27 @@ fi %endif %changelog +* Sat Oct 28 2023 YunYi Yang - 4.19.90-2310.4.0.0225 +- config: arm64: Enable config of hisi ptt +- hwtracing: hisi_ptt: Add dummy callback pmu::read() +- hwtracing: hisi_ptt: Keep to advertise PERF_PMU_CAP_EXCLUSIVE +- hwtracing: hisi_ptt: Fix potential sleep in atomic context +- hwtracing: hisi_ptt: Advertise PERF_PMU_CAP_NO_EXCLUDE for PTT PMU +- hwtracing: hisi_ptt: Export available filters through sysfs +- hwtracing: hisi_ptt: Add support for dynamically updating the filter list +- hwtracing: hisi_ptt: Factor out filter allocation and release operation +- hwtracing: hisi_ptt: Only add the supported devices to the filters list +- hwtracing: hisi_ptt: Fix up for "iommu/dma: Make header private" +- MAINTAINERS: Add maintainer for HiSilicon PTT driver +- docs: trace: Add HiSilicon PTT device driver documentation +- hwtracing: hisi_ptt: Add tune function support for HiSilicon PCIe Tune and Trace device +- hwtracing: hisi_ptt: Add trace function support for HiSilicon PCIe Tune and Trace device +- genirq: Export affinity setter for modules +- iommu/arm-smmu-v3: Integrate the function for obtain the device domain type in bypass mode +- iommu/arm-smmu-v3: Make default domain type of HiSilicon PTT device to identity +- iommu: Add def_domain_type() callback in iommu_ops +- PCI: Support BAR sizes up to 8TB + * Fri Oct 27 2023 Luo Shengwei - 4.19.90-2310.4.0.0224 - open macro: with_patch and add file: series.conf, where patches defined can - be applied automatically. diff --git a/patches/0001-PCI-Support-BAR-sizes-up-to-8TB.patch b/patches/0001-PCI-Support-BAR-sizes-up-to-8TB.patch new file mode 100644 index 0000000..80bd720 --- /dev/null +++ b/patches/0001-PCI-Support-BAR-sizes-up-to-8TB.patch @@ -0,0 +1,52 @@ +From fc96a37739f1017fb91a0339f7f9b101704ca130 Mon Sep 17 00:00:00 2001 +From: Dongdong Liu +Date: Tue, 18 Jan 2022 17:21:17 +0800 +Subject: [PATCH 01/19] PCI: Support BAR sizes up to 8TB + +mainline inclusion +from mainline-v5.18-rc1 +commit 3dc8a1f6f64481a8a5a669633e880f26dae0d752 +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I6XOIU +CVE: NA + +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3dc8a1f6f64481a8a5a669633e880f26dae0d752 + +---------------------------------------------------------------------- + +Current kernel reports that BARs larger than 128GB, e.g., this 4TB BAR, are +disabled: + + pci 0000:01:00.0: disabling BAR 4: [mem 0x00000000-0x3ffffffffff 64bit pref] (bad alignment 0x40000000000) + +Increase the maximum BAR size from 128GB to 8TB for future expansion. + +[bhelgaas: commit log] +Link: https://lore.kernel.org/r/20220118092117.10089-1-liudongdong3@huawei.com +Signed-off-by: Dongdong Liu +Signed-off-by: Bjorn Helgaas +Signed-off-by: huangfangrun +Signed-off-by: YunYi Yang + + Conflicts: + drivers/pci/setup-bus.c +--- + drivers/pci/setup-bus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c +index 39d19302f3cb..426d21c1db31 100644 +--- a/drivers/pci/setup-bus.c ++++ b/drivers/pci/setup-bus.c +@@ -968,7 +968,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, + { + struct pci_dev *dev; + resource_size_t min_align, align, size, size0, size1; +- resource_size_t aligns[18]; /* Alignments from 1Mb to 128Gb */ ++ resource_size_t aligns[24]; /* Alignments from 1MB to 8TB */ + int order, max_order; + struct resource *b_res = find_free_bus_resource(bus, + mask | IORESOURCE_PREFETCH, type); +-- +2.27.0 + diff --git a/patches/0002-iommu-Add-def_domain_type-callback-in-iommu_ops.patch b/patches/0002-iommu-Add-def_domain_type-callback-in-iommu_ops.patch new file mode 100644 index 0000000..aa695fc --- /dev/null +++ b/patches/0002-iommu-Add-def_domain_type-callback-in-iommu_ops.patch @@ -0,0 +1,186 @@ +From adb665e7ecae8d4e3f48634e8c0db291d0826aff Mon Sep 17 00:00:00 2001 +From: Sai Praneeth Prakhya +Date: Wed, 29 Apr 2020 15:36:40 +0200 +Subject: [PATCH 02/19] iommu: Add def_domain_type() callback in iommu_ops + +mainline inclusion +from mainline-v5.8-rc1 +commit 4cbf38511a007867def958872203ae8adb8e2351 +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T +CVE: NA +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4cbf38511a007867def958872203ae8adb8e2351 + +------------------------------------------------------------------------ + +Some devices are reqired to use a specific type (identity or dma) +of default domain when they are used with a vendor iommu. When the +system level default domain type is different from it, the vendor +iommu driver has to request a new default domain with +iommu_request_dma_domain_for_dev() and iommu_request_dm_for_dev() +in the add_dev() callback. Unfortunately, these two helpers only +work when the group hasn't been assigned to any other devices, +hence, some vendor iommu driver has to use a private domain if +it fails to request a new default one. + +This adds def_domain_type() callback in the iommu_ops, so that +any special requirement of default domain for a device could be +aware by the iommu generic layer. + +Signed-off-by: Sai Praneeth Prakhya +Signed-off-by: Lu Baolu +[ jroedel@suse.de: Added iommu_get_def_domain_type() function and use + it to allocate the default domain ] +Co-developed-by: Joerg Roedel +Signed-off-by: Joerg Roedel +Tested-by: Marek Szyprowski +Acked-by: Marek Szyprowski +Link: https://lore.kernel.org/r/20200429133712.31431-3-joro@8bytes.org +Signed-off-by: Joerg Roedel +Signed-off-by: YunYi Yang + + Conflicts: + drivers/iommu/iommu.c + include/linux/iommu.h +--- + drivers/iommu/arm-smmu-v3.c | 7 ++----- + drivers/iommu/arm-smmu.c | 8 +------- + drivers/iommu/iommu.c | 22 ++++++++++++++-------- + include/linux/iommu.h | 2 -- + 4 files changed, 17 insertions(+), 22 deletions(-) + +diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c +index 05cb92da6836..5029d9af1100 100644 +--- a/drivers/iommu/arm-smmu-v3.c ++++ b/drivers/iommu/arm-smmu-v3.c +@@ -3067,9 +3067,9 @@ static void arm_smmu_put_resv_regions(struct device *dev, + kfree(entry); + } + +-#ifdef CONFIG_SMMU_BYPASS_DEV + static int arm_smmu_device_domain_type(struct device *dev, unsigned int *type) + { ++#ifdef CONFIG_SMMU_BYPASS_DEV + int i; + struct pci_dev *pdev; + +@@ -3086,10 +3086,9 @@ static int arm_smmu_device_domain_type(struct device *dev, unsigned int *type) + return 0; + } + } +- ++#endif + return -ERANGE; + } +-#endif + + static struct iommu_ops arm_smmu_ops = { + .capable = arm_smmu_capable, +@@ -3118,9 +3117,7 @@ static struct iommu_ops arm_smmu_ops = { + .get_resv_regions = arm_smmu_get_resv_regions, + .put_resv_regions = arm_smmu_put_resv_regions, + .pgsize_bitmap = -1UL, /* Restricted during device attach */ +-#ifdef CONFIG_SMMU_BYPASS_DEV + .device_domain_type = arm_smmu_device_domain_type, +-#endif + }; + + /* Probing and initialisation functions */ +diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c +index d1c00b1dfd2e..01ab7c990a58 100644 +--- a/drivers/iommu/arm-smmu.c ++++ b/drivers/iommu/arm-smmu.c +@@ -1632,8 +1632,6 @@ static void arm_smmu_put_resv_regions(struct device *dev, + kfree(entry); + } + +-#ifdef CONFIG_SMMU_BYPASS_DEV +- + #ifdef CONFIG_ARCH_PHYTIUM + static int phytium_smmu_def_domain_type(struct device *dev, unsigned int *type) + { +@@ -1651,8 +1649,6 @@ static inline int phytium_smmu_def_domain_type(struct device *dev, unsigned int + } + #endif + +-#endif +- + static struct iommu_ops arm_smmu_ops = { + .capable = arm_smmu_capable, + .domain_alloc = arm_smmu_domain_alloc, +@@ -1672,9 +1668,7 @@ static struct iommu_ops arm_smmu_ops = { + .get_resv_regions = arm_smmu_get_resv_regions, + .put_resv_regions = arm_smmu_put_resv_regions, + .pgsize_bitmap = -1UL, /* Restricted during device attach */ +-#ifdef CONFIG_SMMU_BYPASS_DEV +- .device_domain_type = phytium_smmu_def_domain_type, +-#endif ++ .device_domain_type = phytium_smmu_def_domain_type, + }; + + static void arm_smmu_device_reset(struct arm_smmu_device *smmu) +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 1c39d1b8a80a..eb141afbec67 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -1260,6 +1260,17 @@ struct iommu_group *pci_device_group(struct device *dev) + } + EXPORT_SYMBOL_GPL(pci_device_group); + ++static int iommu_get_def_domain_type(struct device *dev) ++{ ++ const struct iommu_ops *ops = dev->bus->iommu_ops; ++ unsigned int type = 0; ++ ++ if (ops->device_domain_type) ++ ops->device_domain_type(dev, &type); ++ ++ return (type == 0) ? iommu_def_domain_type : type; ++} ++ + /** + * iommu_group_get_for_dev - Find or create the IOMMU group for a device + * @dev: target device +@@ -1298,20 +1309,15 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev) + if (!group->default_domain) { + struct iommu_domain *dom; + +-#ifdef CONFIG_SMMU_BYPASS_DEV +- /* direct allocate required default domain type for some specific devices. */ +- if (ops->device_domain_type) { +- if (ops->device_domain_type(dev, &type)) +- type = iommu_def_domain_type; +- } +-#endif ++ type = iommu_get_def_domain_type(dev); ++ + dom = __iommu_domain_alloc(dev->bus, type); + if (!dom && type != IOMMU_DOMAIN_DMA) { + dom = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_DMA); + if (dom) { + dev_warn(dev, + "failed to allocate default IOMMU domain of type %u; falling back to IOMMU_DOMAIN_DMA", +- iommu_def_domain_type); ++ type); + } + } + +diff --git a/include/linux/iommu.h b/include/linux/iommu.h +index d44f3a6762be..790834df8525 100644 +--- a/include/linux/iommu.h ++++ b/include/linux/iommu.h +@@ -363,11 +363,9 @@ struct iommu_ops { + + unsigned long pgsize_bitmap; + +-#ifdef CONFIG_SMMU_BYPASS_DEV + #ifndef __GENKSYMS__ + int (*device_domain_type)(struct device *dev, unsigned int *type); + #endif +-#endif + }; + + /** +-- +2.27.0 + diff --git a/patches/0003-iommu-arm-smmu-v3-Make-default-domain-type-of-HiSili.patch b/patches/0003-iommu-arm-smmu-v3-Make-default-domain-type-of-HiSili.patch new file mode 100644 index 0000000..6495346 --- /dev/null +++ b/patches/0003-iommu-arm-smmu-v3-Make-default-domain-type-of-HiSili.patch @@ -0,0 +1,78 @@ +From f88b39a83ba13280ccef443533b43b53d8d464dd Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Thu, 29 Sep 2022 22:01:00 +0800 +Subject: [PATCH 03/19] iommu/arm-smmu-v3: Make default domain type of + HiSilicon PTT device to identity + +mainline inclusion +from mainline-v6.1-rc1 +commit 24b6c7798a0122012ca848ea0d25e973334266b0 +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T +CVE: NA + +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git/commit/?id=24b6c7798a0122012ca848ea0d25e973334266b0 + +-------------------------------------------------------------------------- + +The DMA operations of HiSilicon PTT device can only work properly with +identical mappings. So add a quirk for the device to force the domain +as passthrough. + +Acked-by: Will Deacon +Signed-off-by: Yicong Yang +Reviewed-by: John Garry +Link: https://lore.kernel.org/r/20220816114414.4092-2-yangyicong@huawei.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Wangming Shao +Reviewed-by: Hanjun Guo +Reviewed-by: Jay Fang +Acked-by: Xie XiuQi +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang + + Conflicts: + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +--- + drivers/iommu/arm-smmu-v3.c | 16 +++++++++++++++- + 1 file changed, 15 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c +index 5029d9af1100..a11f5f03fcd0 100644 +--- a/drivers/iommu/arm-smmu-v3.c ++++ b/drivers/iommu/arm-smmu-v3.c +@@ -3067,9 +3067,16 @@ static void arm_smmu_put_resv_regions(struct device *dev, + kfree(entry); + } + ++/* ++ * HiSilicon PCIe tune and trace device can be used to trace TLP headers on the ++ * PCIe link and save the data to memory by DMA. The hardware is restricted to ++ * use identity mapping only. ++ */ ++#define IS_HISI_PTT_DEVICE(pdev) ((pdev)->vendor == PCI_VENDOR_ID_HUAWEI && \ ++ (pdev)->device == 0xa12e) ++ + static int arm_smmu_device_domain_type(struct device *dev, unsigned int *type) + { +-#ifdef CONFIG_SMMU_BYPASS_DEV + int i; + struct pci_dev *pdev; + +@@ -3077,6 +3084,13 @@ static int arm_smmu_device_domain_type(struct device *dev, unsigned int *type) + return -ERANGE; + + pdev = to_pci_dev(dev); ++ ++ if (IS_HISI_PTT_DEVICE(pdev)) { ++ *type = IOMMU_DOMAIN_IDENTITY; ++ return 0; ++ } ++ ++#ifdef CONFIG_SMMU_BYPASS_DEV + for (i = 0; i < smmu_bypass_devices_num; i++) { + if ((smmu_bypass_devices[i].vendor == pdev->vendor) + && (smmu_bypass_devices[i].device == pdev->device)) { +-- +2.27.0 + diff --git a/patches/0004-iommu-arm-smmu-v3-Integrate-the-function-for-obtain-.patch b/patches/0004-iommu-arm-smmu-v3-Integrate-the-function-for-obtain-.patch new file mode 100644 index 0000000..beeee6c --- /dev/null +++ b/patches/0004-iommu-arm-smmu-v3-Integrate-the-function-for-obtain-.patch @@ -0,0 +1,75 @@ +From 6f5496b19beae6c819d9a9d719e71b4af578c936 Mon Sep 17 00:00:00 2001 +From: YunYi Yang +Date: Tue, 24 Oct 2023 19:41:44 +0800 +Subject: [PATCH 04/19] iommu/arm-smmu-v3: Integrate the function for obtain + the device domain type in bypass mode + +driver inclusion +category: cleanup +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T + +------------------------------------------------------------------- + +When the CONFIG_SMMU_BYPASS_DEV macro is enabled, the obtaining of domain +type is encapsulated as a function as a step in arm_smmu_device_domian_type +function. So that the code is clearer and easier to call later. + +Signed-off-by: YunYi Yang +--- + drivers/iommu/arm-smmu-v3.c | 31 +++++++++++++++++++++---------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c +index a11f5f03fcd0..66fab92a3e26 100644 +--- a/drivers/iommu/arm-smmu-v3.c ++++ b/drivers/iommu/arm-smmu-v3.c +@@ -3075,9 +3075,27 @@ static void arm_smmu_put_resv_regions(struct device *dev, + #define IS_HISI_PTT_DEVICE(pdev) ((pdev)->vendor == PCI_VENDOR_ID_HUAWEI && \ + (pdev)->device == 0xa12e) + +-static int arm_smmu_device_domain_type(struct device *dev, unsigned int *type) ++#ifdef CONFIG_SMMU_BYPASS_DEV ++static int arm_smmu_bypass_dev_domain_type(struct device *dev) + { + int i; ++ struct pci_dev *pdev = to_pci_dev(dev); ++ ++ for (i = 0; i < smmu_bypass_devices_num; i++) { ++ if ((smmu_bypass_devices[i].vendor == pdev->vendor) && ++ (smmu_bypass_devices[i].device == pdev->device)) { ++ dev_info(dev, "device 0x%hx:0x%hx uses identity mapping.", ++ pdev->vendor, pdev->device); ++ return IOMMU_DOMAIN_IDENTITY; ++ } ++ } ++ ++ return 0; ++} ++#endif ++ ++static int arm_smmu_device_domain_type(struct device *dev, unsigned int *type) ++{ + struct pci_dev *pdev; + + if (!dev_is_pci(dev)) +@@ -3091,15 +3109,8 @@ static int arm_smmu_device_domain_type(struct device *dev, unsigned int *type) + } + + #ifdef CONFIG_SMMU_BYPASS_DEV +- for (i = 0; i < smmu_bypass_devices_num; i++) { +- if ((smmu_bypass_devices[i].vendor == pdev->vendor) +- && (smmu_bypass_devices[i].device == pdev->device)) { +- dev_info(dev, "device 0x%hx:0x%hx uses identity mapping.", +- pdev->vendor, pdev->device); +- *type = IOMMU_DOMAIN_IDENTITY; +- return 0; +- } +- } ++ *type = arm_smmu_bypass_dev_domain_type(dev); ++ return 0; + #endif + return -ERANGE; + } +-- +2.27.0 + diff --git a/patches/0005-genirq-Export-affinity-setter-for-modules.patch b/patches/0005-genirq-Export-affinity-setter-for-modules.patch new file mode 100644 index 0000000..bb9a617 --- /dev/null +++ b/patches/0005-genirq-Export-affinity-setter-for-modules.patch @@ -0,0 +1,134 @@ +From b5fad44d7353231e773cce3b45f37c4bf932b7de Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Fri, 30 Jul 2021 15:44:10 +0800 +Subject: [PATCH 05/19] genirq: Export affinity setter for modules + +mainline inclusion +from mainline-v5.14-rc1 +commit 4d80d6ca5d77fde9880da8466e5b64f250e5bf82 +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T +CVE: NA +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4d80d6ca5d77fde9880da8466e5b64f250e5bf82 + +------------------------------------------------------------------------ + +Perf modules abuse irq_set_affinity_hint() to set the affinity of system +PMU interrupts just because irq_set_affinity() was not exported. + +The fact that irq_set_affinity_hint() actually sets the affinity is a +non-documented side effect and the name is clearly saying it's a hint. + +To clean this up, export the real affinity setter. + +Signed-off-by: Thomas Gleixner +Acked-by: Mark Rutland +Link: https://lore.kernel.org/r/20210518093117.968251441@linutronix.de +Reviewed-by: Shaokun Zhang +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang +--- + include/linux/interrupt.h | 35 ++--------------------------------- + kernel/irq/manage.c | 33 ++++++++++++++++++++++++++++++++- + 2 files changed, 34 insertions(+), 34 deletions(-) + +diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h +index 97de36a38770..9c60dc87963a 100644 +--- a/include/linux/interrupt.h ++++ b/include/linux/interrupt.h +@@ -277,39 +277,8 @@ struct irq_affinity { + + extern cpumask_var_t irq_default_affinity; + +-/* Internal implementation. Use the helpers below */ +-extern int __irq_set_affinity(unsigned int irq, const struct cpumask *cpumask, +- bool force); +- +-/** +- * irq_set_affinity - Set the irq affinity of a given irq +- * @irq: Interrupt to set affinity +- * @cpumask: cpumask +- * +- * Fails if cpumask does not contain an online CPU +- */ +-static inline int +-irq_set_affinity(unsigned int irq, const struct cpumask *cpumask) +-{ +- return __irq_set_affinity(irq, cpumask, false); +-} +- +-/** +- * irq_force_affinity - Force the irq affinity of a given irq +- * @irq: Interrupt to set affinity +- * @cpumask: cpumask +- * +- * Same as irq_set_affinity, but without checking the mask against +- * online cpus. +- * +- * Solely for low level cpu hotplug code, where we need to make per +- * cpu interrupts affine before the cpu becomes online. +- */ +-static inline int +-irq_force_affinity(unsigned int irq, const struct cpumask *cpumask) +-{ +- return __irq_set_affinity(irq, cpumask, true); +-} ++extern int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask); ++extern int irq_force_affinity(unsigned int irq, const struct cpumask *cpumask); + + extern int irq_can_set_affinity(unsigned int irq); + extern int irq_select_affinity(unsigned int irq); +diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c +index 163712c76520..f4c0e509d74f 100644 +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -331,7 +331,8 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask, + return ret; + } + +-int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force) ++static int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, ++ bool force) + { + struct irq_desc *desc = irq_to_desc(irq); + unsigned long flags; +@@ -346,6 +347,36 @@ int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force) + return ret; + } + ++/** ++ * irq_set_affinity - Set the irq affinity of a given irq ++ * @irq: Interrupt to set affinity ++ * @cpumask: cpumask ++ * ++ * Fails if cpumask does not contain an online CPU ++ */ ++int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask) ++{ ++ return __irq_set_affinity(irq, cpumask, false); ++} ++EXPORT_SYMBOL_GPL(irq_set_affinity); ++ ++/** ++ * irq_force_affinity - Force the irq affinity of a given irq ++ * @irq: Interrupt to set affinity ++ * @cpumask: cpumask ++ * ++ * Same as irq_set_affinity, but without checking the mask against ++ * online cpus. ++ * ++ * Solely for low level cpu hotplug code, where we need to make per ++ * cpu interrupts affine before the cpu becomes online. ++ */ ++int irq_force_affinity(unsigned int irq, const struct cpumask *cpumask) ++{ ++ return __irq_set_affinity(irq, cpumask, true); ++} ++EXPORT_SYMBOL_GPL(irq_force_affinity); ++ + int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) + { + unsigned long flags; +-- +2.27.0 + diff --git a/patches/0006-hwtracing-hisi_ptt-Add-trace-function-support-for-Hi.patch b/patches/0006-hwtracing-hisi_ptt-Add-trace-function-support-for-Hi.patch new file mode 100644 index 0000000..084615a --- /dev/null +++ b/patches/0006-hwtracing-hisi_ptt-Add-trace-function-support-for-Hi.patch @@ -0,0 +1,1243 @@ +From 9cf88c286dac27974ed45e0eb5c3ce8f95d2f8aa Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Thu, 29 Sep 2022 22:01:01 +0800 +Subject: [PATCH 06/19] hwtracing: hisi_ptt: Add trace function support for + HiSilicon PCIe Tune and Trace device + +mainline inclusion +from mainline-v6.1-rc1 +commit ff0de066b4632ccb2b2e50f90c0c5be7f4689de7 +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T +CVE: NA + +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git/commit/?id=ff0de066b4632ccb2b2e50f90c0c5be7f4689de7 + +-------------------------------------------------------------------------- + +HiSilicon PCIe tune and trace device(PTT) is a PCIe Root Complex integrated +Endpoint(RCiEP) device, providing the capability to dynamically monitor and +tune the PCIe traffic and trace the TLP headers. + +Add the driver for the device to enable the trace function. Register PMU +device of PTT trace, then users can use trace through perf command. The +driver makes use of perf AUX trace function and support the following +events to configure the trace: + +- filter: select Root port or Endpoint to trace +- type: select the type of traced TLP headers +- direction: select the direction of traced TLP headers +- format: select the data format of the traced TLP headers + +This patch initially add basic trace support of PTT device. + +Acked-by: Mathieu Poirier +Reviewed-by: Jonathan Cameron +Reviewed-by: John Garry +Signed-off-by: Yicong Yang +Link: https://lore.kernel.org/r/20220816114414.4092-3-yangyicong@huawei.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Wangming Shao +Reviewed-by: Xiongfeng Wang +Reviewed-by: Hanjun Guo +Reviewed-by: Jay Fang +Acked-by: Xie XiuQi +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang +--- + drivers/Makefile | 1 + + drivers/hwtracing/Kconfig | 2 + + drivers/hwtracing/ptt/Kconfig | 12 + + drivers/hwtracing/ptt/Makefile | 2 + + drivers/hwtracing/ptt/hisi_ptt.c | 941 +++++++++++++++++++++++++++++++ + drivers/hwtracing/ptt/hisi_ptt.h | 179 ++++++ + 6 files changed, 1137 insertions(+) + create mode 100644 drivers/hwtracing/ptt/Kconfig + create mode 100644 drivers/hwtracing/ptt/Makefile + create mode 100644 drivers/hwtracing/ptt/hisi_ptt.c + create mode 100644 drivers/hwtracing/ptt/hisi_ptt.h + +diff --git a/drivers/Makefile b/drivers/Makefile +index 578f469f72fb..2879a0e0b019 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -177,6 +177,7 @@ obj-$(CONFIG_THUNDERBOLT) += thunderbolt/ + obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/ + obj-y += hwtracing/intel_th/ + obj-$(CONFIG_STM) += hwtracing/stm/ ++obj-$(CONFIG_HISI_PTT) += hwtracing/ptt/ + obj-$(CONFIG_ANDROID) += android/ + obj-$(CONFIG_NVMEM) += nvmem/ + obj-$(CONFIG_FPGA) += fpga/ +diff --git a/drivers/hwtracing/Kconfig b/drivers/hwtracing/Kconfig +index f68e025c5131..e1b135c0bfa0 100644 +--- a/drivers/hwtracing/Kconfig ++++ b/drivers/hwtracing/Kconfig +@@ -4,4 +4,6 @@ source "drivers/hwtracing/stm/Kconfig" + + source "drivers/hwtracing/intel_th/Kconfig" + ++source "drivers/hwtracing/ptt/Kconfig" ++ + endmenu +diff --git a/drivers/hwtracing/ptt/Kconfig b/drivers/hwtracing/ptt/Kconfig +new file mode 100644 +index 000000000000..6d46a09ffeb9 +--- /dev/null ++++ b/drivers/hwtracing/ptt/Kconfig +@@ -0,0 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0-only ++config HISI_PTT ++ tristate "HiSilicon PCIe Tune and Trace Device" ++ depends on ARM64 || (COMPILE_TEST && 64BIT) ++ depends on PCI && HAS_DMA && HAS_IOMEM && PERF_EVENTS ++ help ++ HiSilicon PCIe Tune and Trace device exists as a PCIe RCiEP ++ device, and it provides support for PCIe traffic tuning and ++ tracing TLP headers to the memory. ++ ++ This driver can also be built as a module. If so, the module ++ will be called hisi_ptt. +diff --git a/drivers/hwtracing/ptt/Makefile b/drivers/hwtracing/ptt/Makefile +new file mode 100644 +index 000000000000..908c09a98161 +--- /dev/null ++++ b/drivers/hwtracing/ptt/Makefile +@@ -0,0 +1,2 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_HISI_PTT) += hisi_ptt.o +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +new file mode 100644 +index 000000000000..0aa99af85f86 +--- /dev/null ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -0,0 +1,941 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Driver for HiSilicon PCIe tune and trace device ++ * ++ * Copyright (c) 2022 HiSilicon Technologies Co., Ltd. ++ * Author: Yicong Yang ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "hisi_ptt.h" ++ ++/* Dynamic CPU hotplug state used by PTT */ ++static enum cpuhp_state hisi_ptt_pmu_online; ++ ++static u16 hisi_ptt_get_filter_val(u16 devid, bool is_port) ++{ ++ if (is_port) ++ return BIT(HISI_PCIE_CORE_PORT_ID(devid & 0xff)); ++ ++ return devid; ++} ++ ++static bool hisi_ptt_wait_trace_hw_idle(struct hisi_ptt *hisi_ptt) ++{ ++ u32 val; ++ ++ return !readl_poll_timeout_atomic(hisi_ptt->iobase + HISI_PTT_TRACE_STS, ++ val, val & HISI_PTT_TRACE_IDLE, ++ HISI_PTT_WAIT_POLL_INTERVAL_US, ++ HISI_PTT_WAIT_TRACE_TIMEOUT_US); ++} ++ ++static void hisi_ptt_wait_dma_reset_done(struct hisi_ptt *hisi_ptt) ++{ ++ u32 val; ++ ++ readl_poll_timeout_atomic(hisi_ptt->iobase + HISI_PTT_TRACE_WR_STS, ++ val, !val, HISI_PTT_RESET_POLL_INTERVAL_US, ++ HISI_PTT_RESET_TIMEOUT_US); ++} ++ ++static void hisi_ptt_trace_end(struct hisi_ptt *hisi_ptt) ++{ ++ writel(0, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL); ++ hisi_ptt->trace_ctrl.started = false; ++} ++ ++static int hisi_ptt_trace_start(struct hisi_ptt *hisi_ptt) ++{ ++ struct hisi_ptt_trace_ctrl *ctrl = &hisi_ptt->trace_ctrl; ++ u32 val; ++ int i; ++ ++ /* Check device idle before start trace */ ++ if (!hisi_ptt_wait_trace_hw_idle(hisi_ptt)) { ++ pci_err(hisi_ptt->pdev, "Failed to start trace, the device is still busy\n"); ++ return -EBUSY; ++ } ++ ++ ctrl->started = true; ++ ++ /* Reset the DMA before start tracing */ ++ val = readl(hisi_ptt->iobase + HISI_PTT_TRACE_CTRL); ++ val |= HISI_PTT_TRACE_CTRL_RST; ++ writel(val, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL); ++ ++ hisi_ptt_wait_dma_reset_done(hisi_ptt); ++ ++ val = readl(hisi_ptt->iobase + HISI_PTT_TRACE_CTRL); ++ val &= ~HISI_PTT_TRACE_CTRL_RST; ++ writel(val, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL); ++ ++ /* Reset the index of current buffer */ ++ hisi_ptt->trace_ctrl.buf_index = 0; ++ ++ /* Zero the trace buffers */ ++ for (i = 0; i < HISI_PTT_TRACE_BUF_CNT; i++) ++ memset(ctrl->trace_buf[i].addr, 0, HISI_PTT_TRACE_BUF_SIZE); ++ ++ /* Clear the interrupt status */ ++ writel(HISI_PTT_TRACE_INT_STAT_MASK, ++ hisi_ptt->iobase + HISI_PTT_TRACE_INT_STAT); ++ writel(0, hisi_ptt->iobase + HISI_PTT_TRACE_INT_MASK); ++ ++ /* Set the trace control register */ ++ val = FIELD_PREP(HISI_PTT_TRACE_CTRL_TYPE_SEL, ctrl->type); ++ val |= FIELD_PREP(HISI_PTT_TRACE_CTRL_RXTX_SEL, ctrl->direction); ++ val |= FIELD_PREP(HISI_PTT_TRACE_CTRL_DATA_FORMAT, ctrl->format); ++ val |= FIELD_PREP(HISI_PTT_TRACE_CTRL_TARGET_SEL, ++ hisi_ptt->trace_ctrl.filter); ++ if (!hisi_ptt->trace_ctrl.is_port) ++ val |= HISI_PTT_TRACE_CTRL_FILTER_MODE; ++ ++ /* Start the Trace */ ++ val |= HISI_PTT_TRACE_CTRL_EN; ++ writel(val, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL); ++ ++ return 0; ++} ++ ++static int hisi_ptt_update_aux(struct hisi_ptt *hisi_ptt, int index, bool stop) ++{ ++ struct hisi_ptt_trace_ctrl *ctrl = &hisi_ptt->trace_ctrl; ++ struct perf_output_handle *handle = &ctrl->handle; ++ struct perf_event *event = handle->event; ++ struct hisi_ptt_pmu_buf *buf; ++ size_t size; ++ void *addr; ++ ++ buf = perf_get_aux(handle); ++ if (!buf || !handle->size) ++ return -EINVAL; ++ ++ addr = ctrl->trace_buf[ctrl->buf_index].addr; ++ ++ /* ++ * If we're going to stop, read the size of already traced data from ++ * HISI_PTT_TRACE_WR_STS. Otherwise we're coming from the interrupt, ++ * the data size is always HISI_PTT_TRACE_BUF_SIZE. ++ */ ++ if (stop) { ++ u32 reg; ++ ++ reg = readl(hisi_ptt->iobase + HISI_PTT_TRACE_WR_STS); ++ size = FIELD_GET(HISI_PTT_TRACE_WR_STS_WRITE, reg); ++ } else { ++ size = HISI_PTT_TRACE_BUF_SIZE; ++ } ++ ++ memcpy(buf->base + buf->pos, addr, size); ++ 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. ++ */ ++ 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); ++ ++ buf = perf_aux_output_begin(handle, event); ++ if (!buf) ++ return -EINVAL; ++ ++ buf->pos = handle->head % buf->length; ++ if (buf->length - buf->pos < HISI_PTT_TRACE_BUF_SIZE) { ++ perf_aux_output_end(handle, 0); ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t hisi_ptt_isr(int irq, void *context) ++{ ++ struct hisi_ptt *hisi_ptt = context; ++ u32 status, buf_idx; ++ ++ status = readl(hisi_ptt->iobase + HISI_PTT_TRACE_INT_STAT); ++ if (!(status & HISI_PTT_TRACE_INT_STAT_MASK)) ++ return IRQ_NONE; ++ ++ buf_idx = ffs(status) - 1; ++ ++ /* Clear the interrupt status of buffer @buf_idx */ ++ writel(status, hisi_ptt->iobase + HISI_PTT_TRACE_INT_STAT); ++ ++ /* ++ * Update the AUX buffer and cache the current buffer index, ++ * as we need to know this and save the data when the trace ++ * is ended out of the interrupt handler. End the trace ++ * if the updating fails. ++ */ ++ if (hisi_ptt_update_aux(hisi_ptt, buf_idx, false)) ++ hisi_ptt_trace_end(hisi_ptt); ++ else ++ hisi_ptt->trace_ctrl.buf_index = ++ (buf_idx + 1) % HISI_PTT_TRACE_BUF_CNT; ++ ++ return IRQ_HANDLED; ++} ++ ++static void hisi_ptt_irq_free_vectors(void *pdev) ++{ ++ pci_free_irq_vectors(pdev); ++} ++ ++static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt) ++{ ++ struct pci_dev *pdev = hisi_ptt->pdev; ++ int ret; ++ ++ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); ++ if (ret < 0) { ++ pci_err(pdev, "failed to allocate irq vector, ret = %d\n", ret); ++ return ret; ++ } ++ ++ ret = devm_add_action_or_reset(&pdev->dev, ++ hisi_ptt_irq_free_vectors, ++ pdev); ++ if (ret < 0) ++ return ret; ++ ++ ret = devm_request_threaded_irq(&pdev->dev, ++ pci_irq_vector(pdev, ++ HISI_PTT_TRACE_DMA_IRQ), ++ NULL, hisi_ptt_isr, 0, ++ DRV_NAME, hisi_ptt); ++ if (ret) { ++ pci_err(pdev, "failed to request irq %d, ret = %d\n", ++ pci_irq_vector(pdev, ++ HISI_PTT_TRACE_DMA_IRQ), ++ ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data) ++{ ++ struct hisi_ptt_filter_desc *filter; ++ struct hisi_ptt *hisi_ptt = data; ++ ++ /* ++ * We won't fail the probe if filter allocation failed here. The filters ++ * should be partial initialized and users would know which filter fails ++ * through the log. Other functions of PTT device are still available. ++ */ ++ filter = kzalloc(sizeof(*filter), GFP_KERNEL); ++ if (!filter) ++ return -ENOMEM; ++ ++ filter->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); ++ ++ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) { ++ filter->is_port = true; ++ list_add_tail(&filter->list, &hisi_ptt->port_filters); ++ ++ /* Update the available port mask */ ++ hisi_ptt->port_mask |= hisi_ptt_get_filter_val(filter->devid, ++ true); ++ } else { ++ list_add_tail(&filter->list, &hisi_ptt->req_filters); ++ } ++ ++ return 0; ++} ++ ++static void hisi_ptt_release_filters(void *data) ++{ ++ struct hisi_ptt_filter_desc *filter, *tmp; ++ struct hisi_ptt *hisi_ptt = data; ++ ++ list_for_each_entry_safe(filter, tmp, &hisi_ptt->req_filters, list) { ++ list_del(&filter->list); ++ kfree(filter); ++ } ++ ++ list_for_each_entry_safe(filter, tmp, &hisi_ptt->port_filters, list) { ++ list_del(&filter->list); ++ kfree(filter); ++ } ++} ++ ++static int hisi_ptt_config_trace_buf(struct hisi_ptt *hisi_ptt) ++{ ++ struct hisi_ptt_trace_ctrl *ctrl = &hisi_ptt->trace_ctrl; ++ struct device *dev = &hisi_ptt->pdev->dev; ++ int i; ++ ++ ctrl->trace_buf = devm_kcalloc(dev, HISI_PTT_TRACE_BUF_CNT, ++ sizeof(*ctrl->trace_buf), GFP_KERNEL); ++ if (!ctrl->trace_buf) ++ return -ENOMEM; ++ ++ for (i = 0; i < HISI_PTT_TRACE_BUF_CNT; ++i) { ++ ctrl->trace_buf[i].addr = ++ dmam_alloc_coherent(dev, ++ HISI_PTT_TRACE_BUF_SIZE, ++ &ctrl->trace_buf[i].dma, ++ GFP_KERNEL); ++ if (!ctrl->trace_buf[i].addr) ++ return -ENOMEM; ++ } ++ ++ /* Configure the trace DMA buffer */ ++ for (i = 0; i < HISI_PTT_TRACE_BUF_CNT; i++) { ++ writel(lower_32_bits(ctrl->trace_buf[i].dma), ++ hisi_ptt->iobase + HISI_PTT_TRACE_ADDR_BASE_LO_0 + ++ i * HISI_PTT_TRACE_ADDR_STRIDE); ++ writel(upper_32_bits(ctrl->trace_buf[i].dma), ++ hisi_ptt->iobase + HISI_PTT_TRACE_ADDR_BASE_HI_0 + ++ i * HISI_PTT_TRACE_ADDR_STRIDE); ++ } ++ writel(HISI_PTT_TRACE_BUF_SIZE, ++ hisi_ptt->iobase + HISI_PTT_TRACE_ADDR_SIZE); ++ ++ return 0; ++} ++ ++static int hisi_ptt_init_ctrls(struct hisi_ptt *hisi_ptt) ++{ ++ struct pci_dev *pdev = hisi_ptt->pdev; ++ struct pci_bus *bus; ++ int ret; ++ u32 reg; ++ ++ INIT_LIST_HEAD(&hisi_ptt->port_filters); ++ INIT_LIST_HEAD(&hisi_ptt->req_filters); ++ ++ ret = hisi_ptt_config_trace_buf(hisi_ptt); ++ if (ret) ++ return ret; ++ ++ /* ++ * The device range register provides the information about the root ++ * ports which the RCiEP can control and trace. The RCiEP and the root ++ * ports which it supports are on the same PCIe core, with same domain ++ * number but maybe different bus number. The device range register ++ * will tell us which root ports we can support, Bit[31:16] indicates ++ * the upper BDF numbers of the root port, while Bit[15:0] indicates ++ * the lower. ++ */ ++ reg = readl(hisi_ptt->iobase + HISI_PTT_DEVICE_RANGE); ++ hisi_ptt->upper_bdf = FIELD_GET(HISI_PTT_DEVICE_RANGE_UPPER, reg); ++ hisi_ptt->lower_bdf = FIELD_GET(HISI_PTT_DEVICE_RANGE_LOWER, reg); ++ ++ bus = pci_find_bus(pci_domain_nr(pdev->bus), ++ PCI_BUS_NUM(hisi_ptt->upper_bdf)); ++ if (bus) ++ pci_walk_bus(bus, hisi_ptt_init_filters, hisi_ptt); ++ ++ ret = devm_add_action_or_reset(&pdev->dev, ++ hisi_ptt_release_filters, ++ hisi_ptt); ++ if (ret) ++ return ret; ++ ++ hisi_ptt->trace_ctrl.on_cpu = -1; ++ return 0; ++} ++ ++static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct hisi_ptt *hisi_ptt = to_hisi_ptt(dev_get_drvdata(dev)); ++ const cpumask_t *cpumask = cpumask_of_node( ++ dev_to_node(&hisi_ptt->pdev->dev)); ++ ++ return cpumap_print_to_pagebuf(true, buf, cpumask); ++} ++static DEVICE_ATTR_RO(cpumask); ++ ++static struct attribute *hisi_ptt_cpumask_attrs[] = { ++ &dev_attr_cpumask.attr, ++ NULL ++}; ++ ++static const struct attribute_group hisi_ptt_cpumask_attr_group = { ++ .attrs = hisi_ptt_cpumask_attrs, ++}; ++ ++/* ++ * Bit 19 indicates the filter type, 1 for Root Port filter and 0 for Requester ++ * filter. Bit[15:0] indicates the filter value, for Root Port filter it's ++ * a bit mask of desired ports and for Requester filter it's the Requester ID ++ * of the desired PCIe function. Bit[18:16] is reserved for extension. ++ * ++ * See hisi_ptt.rst documentation for detailed information. ++ */ ++PMU_FORMAT_ATTR(filter, "config:0-19"); ++PMU_FORMAT_ATTR(direction, "config:20-23"); ++PMU_FORMAT_ATTR(type, "config:24-31"); ++PMU_FORMAT_ATTR(format, "config:32-35"); ++ ++static struct attribute *hisi_ptt_pmu_format_attrs[] = { ++ &format_attr_filter.attr, ++ &format_attr_direction.attr, ++ &format_attr_type.attr, ++ &format_attr_format.attr, ++ NULL ++}; ++ ++static struct attribute_group hisi_ptt_pmu_format_group = { ++ .name = "format", ++ .attrs = hisi_ptt_pmu_format_attrs, ++}; ++ ++static const struct attribute_group *hisi_ptt_pmu_groups[] = { ++ &hisi_ptt_cpumask_attr_group, ++ &hisi_ptt_pmu_format_group, ++ NULL ++}; ++ ++static int hisi_ptt_trace_valid_direction(u32 val) ++{ ++ /* ++ * The direction values have different effects according to the data ++ * format (specified in the parentheses). TLP set A/B means different ++ * set of TLP types. See hisi_ptt.rst documentation for more details. ++ */ ++ static const u32 hisi_ptt_trace_available_direction[] = { ++ 0, /* inbound(4DW) or reserved(8DW) */ ++ 1, /* outbound(4DW) */ ++ 2, /* {in, out}bound(4DW) or inbound(8DW), TLP set A */ ++ 3, /* {in, out}bound(4DW) or inbound(8DW), TLP set B */ ++ }; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hisi_ptt_trace_available_direction); i++) { ++ if (val == hisi_ptt_trace_available_direction[i]) ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int hisi_ptt_trace_valid_type(u32 val) ++{ ++ /* Different types can be set simultaneously */ ++ static const u32 hisi_ptt_trace_available_type[] = { ++ 1, /* posted_request */ ++ 2, /* non-posted_request */ ++ 4, /* completion */ ++ }; ++ int i; ++ ++ if (!val) ++ return -EINVAL; ++ ++ /* ++ * Walk the available list and clear the valid bits of ++ * the config. If there is any resident bit after the ++ * walk then the config is invalid. ++ */ ++ for (i = 0; i < ARRAY_SIZE(hisi_ptt_trace_available_type); i++) ++ val &= ~hisi_ptt_trace_available_type[i]; ++ ++ if (val) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int hisi_ptt_trace_valid_format(u32 val) ++{ ++ static const u32 hisi_ptt_trace_available_format[] = { ++ 0, /* 4DW */ ++ 1, /* 8DW */ ++ }; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(hisi_ptt_trace_available_format); i++) { ++ if (val == hisi_ptt_trace_available_format[i]) ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int hisi_ptt_trace_valid_filter(struct hisi_ptt *hisi_ptt, u64 config) ++{ ++ unsigned long val, port_mask = hisi_ptt->port_mask; ++ struct hisi_ptt_filter_desc *filter; ++ ++ hisi_ptt->trace_ctrl.is_port = FIELD_GET(HISI_PTT_PMU_FILTER_IS_PORT, ++ config); ++ val = FIELD_GET(HISI_PTT_PMU_FILTER_VAL_MASK, config); ++ ++ /* ++ * Port filters are defined as bit mask. For port filters, check ++ * the bits in the @val are within the range of hisi_ptt->port_mask ++ * and whether it's empty or not, otherwise user has specified ++ * some unsupported root ports. ++ * ++ * For Requester ID filters, walk the available filter list to see ++ * whether we have one matched. ++ */ ++ if (!hisi_ptt->trace_ctrl.is_port) { ++ list_for_each_entry(filter, &hisi_ptt->req_filters, list) { ++ if (val == hisi_ptt_get_filter_val(filter->devid, ++ filter->is_port)) ++ return 0; ++ } ++ } else if (bitmap_subset(&val, &port_mask, BITS_PER_LONG)) { ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static void hisi_ptt_pmu_init_configs(struct hisi_ptt *hisi_ptt, ++ struct perf_event *event) ++{ ++ struct hisi_ptt_trace_ctrl *ctrl = &hisi_ptt->trace_ctrl; ++ u32 val; ++ ++ val = FIELD_GET(HISI_PTT_PMU_FILTER_VAL_MASK, event->attr.config); ++ hisi_ptt->trace_ctrl.filter = val; ++ ++ val = FIELD_GET(HISI_PTT_PMU_DIRECTION_MASK, event->attr.config); ++ ctrl->direction = val; ++ ++ val = FIELD_GET(HISI_PTT_PMU_TYPE_MASK, event->attr.config); ++ ctrl->type = val; ++ ++ val = FIELD_GET(HISI_PTT_PMU_FORMAT_MASK, event->attr.config); ++ ctrl->format = val; ++} ++ ++static int hisi_ptt_pmu_event_init(struct perf_event *event) ++{ ++ struct hisi_ptt *hisi_ptt = to_hisi_ptt(event->pmu); ++ int ret; ++ u32 val; ++ ++ if (event->cpu < 0) { ++ dev_dbg(event->pmu->dev, "Per-task mode not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ if (event->attr.type != hisi_ptt->hisi_ptt_pmu.type) ++ return -ENOENT; ++ ++ ret = hisi_ptt_trace_valid_filter(hisi_ptt, event->attr.config); ++ if (ret < 0) ++ return ret; ++ ++ val = FIELD_GET(HISI_PTT_PMU_DIRECTION_MASK, event->attr.config); ++ ret = hisi_ptt_trace_valid_direction(val); ++ if (ret < 0) ++ return ret; ++ ++ val = FIELD_GET(HISI_PTT_PMU_TYPE_MASK, event->attr.config); ++ ret = hisi_ptt_trace_valid_type(val); ++ if (ret < 0) ++ return ret; ++ ++ val = FIELD_GET(HISI_PTT_PMU_FORMAT_MASK, event->attr.config); ++ return hisi_ptt_trace_valid_format(val); ++} ++ ++static void *hisi_ptt_pmu_setup_aux(struct perf_event *event, void **pages, ++ int nr_pages, bool overwrite) ++{ ++ struct hisi_ptt_pmu_buf *buf; ++ struct page **pagelist; ++ int i; ++ ++ if (overwrite) { ++ dev_warn(event->pmu->dev, "Overwrite mode is not supported\n"); ++ return NULL; ++ } ++ ++ /* If the pages size less than buffers, we cannot start trace */ ++ if (nr_pages < HISI_PTT_TRACE_TOTAL_BUF_SIZE / PAGE_SIZE) ++ return NULL; ++ ++ buf = kzalloc(sizeof(*buf), GFP_KERNEL); ++ if (!buf) ++ return NULL; ++ ++ pagelist = kcalloc(nr_pages, sizeof(*pagelist), GFP_KERNEL); ++ if (!pagelist) ++ goto err; ++ ++ for (i = 0; i < nr_pages; i++) ++ pagelist[i] = virt_to_page(pages[i]); ++ ++ buf->base = vmap(pagelist, nr_pages, VM_MAP, PAGE_KERNEL); ++ if (!buf->base) { ++ kfree(pagelist); ++ goto err; ++ } ++ ++ buf->nr_pages = nr_pages; ++ buf->length = nr_pages * PAGE_SIZE; ++ buf->pos = 0; ++ ++ kfree(pagelist); ++ return buf; ++err: ++ kfree(buf); ++ return NULL; ++} ++ ++static void hisi_ptt_pmu_free_aux(void *aux) ++{ ++ struct hisi_ptt_pmu_buf *buf = aux; ++ ++ vunmap(buf->base); ++ kfree(buf); ++} ++ ++static void hisi_ptt_pmu_start(struct perf_event *event, int flags) ++{ ++ struct hisi_ptt *hisi_ptt = to_hisi_ptt(event->pmu); ++ struct perf_output_handle *handle = &hisi_ptt->trace_ctrl.handle; ++ struct hw_perf_event *hwc = &event->hw; ++ struct device *dev = event->pmu->dev; ++ struct hisi_ptt_pmu_buf *buf; ++ int cpu = event->cpu; ++ int ret; ++ ++ hwc->state = 0; ++ ++ /* Serialize the perf process if user specified several CPUs */ ++ spin_lock(&hisi_ptt->pmu_lock); ++ if (hisi_ptt->trace_ctrl.started) { ++ dev_dbg(dev, "trace has already started\n"); ++ goto stop; ++ } ++ ++ /* ++ * Handle the interrupt on the same cpu which starts the trace to avoid ++ * context mismatch. Otherwise we'll trigger the WARN from the perf ++ * core in event_function_local(). If CPU passed is offline we'll fail ++ * here, just log it since we can do nothing here. ++ */ ++ ret = irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, ++ HISI_PTT_TRACE_DMA_IRQ), ++ cpumask_of(cpu)); ++ if (ret) ++ dev_warn(dev, "failed to set the affinity of trace interrupt\n"); ++ ++ hisi_ptt->trace_ctrl.on_cpu = cpu; ++ ++ buf = perf_aux_output_begin(handle, event); ++ if (!buf) { ++ dev_dbg(dev, "aux output begin failed\n"); ++ goto stop; ++ } ++ ++ buf->pos = handle->head % buf->length; ++ ++ hisi_ptt_pmu_init_configs(hisi_ptt, event); ++ ++ ret = hisi_ptt_trace_start(hisi_ptt); ++ if (ret) { ++ dev_dbg(dev, "trace start failed, ret = %d\n", ret); ++ perf_aux_output_end(handle, 0); ++ goto stop; ++ } ++ ++ spin_unlock(&hisi_ptt->pmu_lock); ++ return; ++stop: ++ event->hw.state |= PERF_HES_STOPPED; ++ spin_unlock(&hisi_ptt->pmu_lock); ++} ++ ++static void hisi_ptt_pmu_stop(struct perf_event *event, int flags) ++{ ++ struct hisi_ptt *hisi_ptt = to_hisi_ptt(event->pmu); ++ struct hw_perf_event *hwc = &event->hw; ++ ++ if (hwc->state & PERF_HES_STOPPED) ++ return; ++ ++ spin_lock(&hisi_ptt->pmu_lock); ++ if (hisi_ptt->trace_ctrl.started) { ++ hisi_ptt_trace_end(hisi_ptt); ++ ++ if (!hisi_ptt_wait_trace_hw_idle(hisi_ptt)) ++ dev_warn(event->pmu->dev, "Device is still busy\n"); ++ ++ hisi_ptt_update_aux(hisi_ptt, ++ hisi_ptt->trace_ctrl.buf_index, ++ true); ++ } ++ spin_unlock(&hisi_ptt->pmu_lock); ++ ++ hwc->state |= PERF_HES_STOPPED; ++ perf_event_update_userpage(event); ++ hwc->state |= PERF_HES_UPTODATE; ++} ++ ++static int hisi_ptt_pmu_add(struct perf_event *event, int flags) ++{ ++ struct hisi_ptt *hisi_ptt = to_hisi_ptt(event->pmu); ++ struct hw_perf_event *hwc = &event->hw; ++ int cpu = event->cpu; ++ ++ /* Only allow the cpus on the device's node to add the event */ ++ if (!cpumask_test_cpu(cpu, cpumask_of_node( ++ dev_to_node(&hisi_ptt->pdev->dev)))) ++ return 0; ++ ++ hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; ++ ++ if (flags & PERF_EF_START) { ++ hisi_ptt_pmu_start(event, PERF_EF_RELOAD); ++ if (hwc->state & PERF_HES_STOPPED) ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void hisi_ptt_pmu_del(struct perf_event *event, int flags) ++{ ++ hisi_ptt_pmu_stop(event, PERF_EF_UPDATE); ++} ++ ++static void hisi_ptt_remove_cpuhp_instance(void *hotplug_node) ++{ ++ cpuhp_state_remove_instance_nocalls(hisi_ptt_pmu_online, hotplug_node); ++} ++ ++static void hisi_ptt_unregister_pmu(void *pmu) ++{ ++ perf_pmu_unregister(pmu); ++} ++ ++static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt) ++{ ++ u16 core_id, sicl_id; ++ char *pmu_name; ++ u32 reg; ++ int ret; ++ ++ ret = cpuhp_state_add_instance_nocalls(hisi_ptt_pmu_online, ++ &hisi_ptt->hotplug_node); ++ if (ret) ++ return ret; ++ ++ ret = devm_add_action_or_reset(&hisi_ptt->pdev->dev, ++ hisi_ptt_remove_cpuhp_instance, ++ &hisi_ptt->hotplug_node); ++ if (ret) ++ return ret; ++ ++ spin_lock_init(&hisi_ptt->pmu_lock); ++ ++ hisi_ptt->hisi_ptt_pmu = (struct pmu) { ++ .module = THIS_MODULE, ++ .capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE, ++ .task_ctx_nr = perf_sw_context, ++ .attr_groups = hisi_ptt_pmu_groups, ++ .event_init = hisi_ptt_pmu_event_init, ++ .setup_aux = hisi_ptt_pmu_setup_aux, ++ .free_aux = hisi_ptt_pmu_free_aux, ++ .start = hisi_ptt_pmu_start, ++ .stop = hisi_ptt_pmu_stop, ++ .add = hisi_ptt_pmu_add, ++ .del = hisi_ptt_pmu_del, ++ }; ++ ++ reg = readl(hisi_ptt->iobase + HISI_PTT_LOCATION); ++ core_id = FIELD_GET(HISI_PTT_CORE_ID, reg); ++ sicl_id = FIELD_GET(HISI_PTT_SICL_ID, reg); ++ ++ pmu_name = devm_kasprintf(&hisi_ptt->pdev->dev, GFP_KERNEL, ++ "hisi_ptt%u_%u", ++ sicl_id, core_id); ++ if (!pmu_name) ++ return -ENOMEM; ++ ++ ret = perf_pmu_register(&hisi_ptt->hisi_ptt_pmu, pmu_name, -1); ++ if (ret) ++ return ret; ++ ++ return devm_add_action_or_reset(&hisi_ptt->pdev->dev, ++ hisi_ptt_unregister_pmu, ++ &hisi_ptt->hisi_ptt_pmu); ++} ++ ++/* ++ * The DMA of PTT trace can only use direct mappings due to some ++ * hardware restriction. Check whether there is no IOMMU or the ++ * policy of the IOMMU domain is passthrough, otherwise the trace ++ * cannot work. ++ * ++ * The PTT device is supposed to behind an ARM SMMUv3, which ++ * should have passthrough the device by a quirk. ++ */ ++static int hisi_ptt_check_iommu_mapping(struct pci_dev *pdev) ++{ ++ struct iommu_domain *iommu_domain; ++ ++ iommu_domain = iommu_get_domain_for_dev(&pdev->dev); ++ if (!iommu_domain || iommu_domain->type == IOMMU_DOMAIN_IDENTITY) ++ return 0; ++ ++ return -EOPNOTSUPP; ++} ++ ++static int hisi_ptt_probe(struct pci_dev *pdev, ++ const struct pci_device_id *id) ++{ ++ struct hisi_ptt *hisi_ptt; ++ int ret; ++ ++ ret = hisi_ptt_check_iommu_mapping(pdev); ++ if (ret) { ++ pci_err(pdev, "requires direct DMA mappings\n"); ++ return ret; ++ } ++ ++ hisi_ptt = devm_kzalloc(&pdev->dev, sizeof(*hisi_ptt), GFP_KERNEL); ++ if (!hisi_ptt) ++ return -ENOMEM; ++ ++ hisi_ptt->pdev = pdev; ++ pci_set_drvdata(pdev, hisi_ptt); ++ ++ ret = pcim_enable_device(pdev); ++ if (ret) { ++ pci_err(pdev, "failed to enable device, ret = %d\n", ret); ++ return ret; ++ } ++ ++ ret = pcim_iomap_regions(pdev, BIT(2), DRV_NAME); ++ if (ret) { ++ pci_err(pdev, "failed to remap io memory, ret = %d\n", ret); ++ return ret; ++ } ++ ++ hisi_ptt->iobase = pcim_iomap_table(pdev)[2]; ++ ++ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); ++ if (ret) { ++ pci_err(pdev, "failed to set 64 bit dma mask, ret = %d\n", ret); ++ return ret; ++ } ++ ++ pci_set_master(pdev); ++ ++ ret = hisi_ptt_register_irq(hisi_ptt); ++ if (ret) ++ return ret; ++ ++ ret = hisi_ptt_init_ctrls(hisi_ptt); ++ if (ret) { ++ pci_err(pdev, "failed to init controls, ret = %d\n", ret); ++ return ret; ++ } ++ ++ ret = hisi_ptt_register_pmu(hisi_ptt); ++ if (ret) { ++ pci_err(pdev, "failed to register PMU device, ret = %d", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct pci_device_id hisi_ptt_id_tbl[] = { ++ { PCI_DEVICE(PCI_VENDOR_ID_HUAWEI, 0xa12e) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(pci, hisi_ptt_id_tbl); ++ ++static struct pci_driver hisi_ptt_driver = { ++ .name = DRV_NAME, ++ .id_table = hisi_ptt_id_tbl, ++ .probe = hisi_ptt_probe, ++}; ++ ++static int hisi_ptt_cpu_teardown(unsigned int cpu, struct hlist_node *node) ++{ ++ struct hisi_ptt *hisi_ptt; ++ struct device *dev; ++ int target, src; ++ ++ hisi_ptt = hlist_entry_safe(node, struct hisi_ptt, hotplug_node); ++ src = hisi_ptt->trace_ctrl.on_cpu; ++ dev = hisi_ptt->hisi_ptt_pmu.dev; ++ ++ if (!hisi_ptt->trace_ctrl.started || src != cpu) ++ return 0; ++ ++ target = cpumask_any_but(cpumask_of_node( ++ dev_to_node(&hisi_ptt->pdev->dev)), ++ cpu); ++ if (target >= nr_cpu_ids) { ++ dev_err(dev, "no available cpu for perf context migration\n"); ++ return 0; ++ } ++ ++ perf_pmu_migrate_context(&hisi_ptt->hisi_ptt_pmu, src, target); ++ ++ /* ++ * Also make sure the interrupt bind to the migrated CPU as well. Warn ++ * the user on failure here. ++ */ ++ if (irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, ++ HISI_PTT_TRACE_DMA_IRQ), ++ cpumask_of(target))) ++ dev_warn(dev, "failed to set the affinity of trace interrupt\n"); ++ ++ hisi_ptt->trace_ctrl.on_cpu = target; ++ return 0; ++} ++ ++static int __init hisi_ptt_init(void) ++{ ++ int ret; ++ ++ ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, DRV_NAME, NULL, ++ hisi_ptt_cpu_teardown); ++ if (ret < 0) ++ return ret; ++ hisi_ptt_pmu_online = ret; ++ ++ ret = pci_register_driver(&hisi_ptt_driver); ++ if (ret) ++ cpuhp_remove_multi_state(hisi_ptt_pmu_online); ++ ++ return ret; ++} ++module_init(hisi_ptt_init); ++ ++static void __exit hisi_ptt_exit(void) ++{ ++ pci_unregister_driver(&hisi_ptt_driver); ++ cpuhp_remove_multi_state(hisi_ptt_pmu_online); ++} ++module_exit(hisi_ptt_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Yicong Yang "); ++MODULE_DESCRIPTION("Driver for HiSilicon PCIe tune and trace device"); +diff --git a/drivers/hwtracing/ptt/hisi_ptt.h b/drivers/hwtracing/ptt/hisi_ptt.h +new file mode 100644 +index 000000000000..c9b635b3bfe9 +--- /dev/null ++++ b/drivers/hwtracing/ptt/hisi_ptt.h +@@ -0,0 +1,179 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Driver for HiSilicon PCIe tune and trace device ++ * ++ * Copyright (c) 2022 HiSilicon Technologies Co., Ltd. ++ * Author: Yicong Yang ++ */ ++ ++#ifndef _HISI_PTT_H ++#define _HISI_PTT_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_NAME "hisi_ptt" ++ ++/* ++ * The definition of the device registers and register fields. ++ */ ++#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_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_TRACE_TIMEOUT_US 100UL ++#define HISI_PTT_WAIT_POLL_INTERVAL_US 10UL ++ ++#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_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; ++}; ++ ++/** ++ * struct hisi_ptt_filter_desc - Descriptor of the PTT trace filter ++ * @list: entry of this descriptor in the filter list ++ * @is_port: the PCI device of the filter is a Root Port or not ++ * @devid: the PCI device's devid of the filter ++ */ ++struct hisi_ptt_filter_desc { ++ struct list_head list; ++ bool is_port; ++ 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 ++ * @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 ++ * @pmu_lock: lock to serialize the perf process ++ * @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 ++ * @port_mask: port mask of the managed root ports ++ */ ++struct hisi_ptt { ++ struct hisi_ptt_trace_ctrl trace_ctrl; ++ struct hlist_node hotplug_node; ++ struct pmu hisi_ptt_pmu; ++ void __iomem *iobase; ++ struct pci_dev *pdev; ++ spinlock_t pmu_lock; ++ 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; ++ u16 port_mask; ++}; ++ ++#define to_hisi_ptt(pmu) container_of(pmu, struct hisi_ptt, hisi_ptt_pmu) ++ ++#endif /* _HISI_PTT_H */ +-- +2.27.0 + diff --git a/patches/0007-hwtracing-hisi_ptt-Add-tune-function-support-for-HiS.patch b/patches/0007-hwtracing-hisi_ptt-Add-tune-function-support-for-HiS.patch new file mode 100644 index 0000000..938839a --- /dev/null +++ b/patches/0007-hwtracing-hisi_ptt-Add-tune-function-support-for-HiS.patch @@ -0,0 +1,272 @@ +From 798f3f7cb4d4a6480c90e18ea96e45c8fe7fd30d Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Thu, 29 Sep 2022 22:01:02 +0800 +Subject: [PATCH 07/19] hwtracing: hisi_ptt: Add tune function support for + HiSilicon PCIe Tune and Trace device + +mainline inclusion +from mainline-v6.1-rc1 +commit 5ca57b03d8c5de4c59234cc11fe9dd9f13d57f48 +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T +CVE: NA + +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git/commit/?id=5ca57b03d8c5de4c59234cc11fe9dd9f13d57f48 + +-------------------------------------------------------------------------- + +Add tune function for the HiSilicon Tune and Trace device. The interface +of tune is exposed through sysfs attributes of PTT PMU device. + +Acked-by: Mathieu Poirier +Reviewed-by: Jonathan Cameron +Reviewed-by: John Garry +Signed-off-by: Yicong Yang +Link: https://lore.kernel.org/r/20220816114414.4092-4-yangyicong@huawei.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Wangming Shao +Reviewed-by: Xiongfeng Wang +Reviewed-by: Jay Fang +Acked-by: Xie XiuQi +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang +--- + drivers/hwtracing/ptt/hisi_ptt.c | 131 +++++++++++++++++++++++++++++++ + drivers/hwtracing/ptt/hisi_ptt.h | 23 ++++++ + 2 files changed, 154 insertions(+) + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index 0aa99af85f86..cffc625665a2 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -25,6 +25,135 @@ + /* Dynamic CPU hotplug state used by PTT */ + static enum cpuhp_state hisi_ptt_pmu_online; + ++static bool hisi_ptt_wait_tuning_finish(struct hisi_ptt *hisi_ptt) ++{ ++ u32 val; ++ ++ return !readl_poll_timeout(hisi_ptt->iobase + HISI_PTT_TUNING_INT_STAT, ++ val, !(val & HISI_PTT_TUNING_INT_STAT_MASK), ++ HISI_PTT_WAIT_POLL_INTERVAL_US, ++ HISI_PTT_WAIT_TUNE_TIMEOUT_US); ++} ++ ++static ssize_t hisi_ptt_tune_attr_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct hisi_ptt *hisi_ptt = to_hisi_ptt(dev_get_drvdata(dev)); ++ struct dev_ext_attribute *ext_attr; ++ struct hisi_ptt_tune_desc *desc; ++ u32 reg; ++ u16 val; ++ ++ ext_attr = container_of(attr, struct dev_ext_attribute, attr); ++ desc = ext_attr->var; ++ ++ mutex_lock(&hisi_ptt->tune_lock); ++ ++ reg = readl(hisi_ptt->iobase + HISI_PTT_TUNING_CTRL); ++ reg &= ~(HISI_PTT_TUNING_CTRL_CODE | HISI_PTT_TUNING_CTRL_SUB); ++ reg |= FIELD_PREP(HISI_PTT_TUNING_CTRL_CODE | HISI_PTT_TUNING_CTRL_SUB, ++ desc->event_code); ++ writel(reg, hisi_ptt->iobase + HISI_PTT_TUNING_CTRL); ++ ++ /* Write all 1 to indicates it's the read process */ ++ writel(~0U, hisi_ptt->iobase + HISI_PTT_TUNING_DATA); ++ ++ if (!hisi_ptt_wait_tuning_finish(hisi_ptt)) { ++ mutex_unlock(&hisi_ptt->tune_lock); ++ return -ETIMEDOUT; ++ } ++ ++ reg = readl(hisi_ptt->iobase + HISI_PTT_TUNING_DATA); ++ reg &= HISI_PTT_TUNING_DATA_VAL_MASK; ++ val = FIELD_GET(HISI_PTT_TUNING_DATA_VAL_MASK, reg); ++ ++ mutex_unlock(&hisi_ptt->tune_lock); ++ return sysfs_emit(buf, "%u\n", val); ++} ++ ++static ssize_t hisi_ptt_tune_attr_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct hisi_ptt *hisi_ptt = to_hisi_ptt(dev_get_drvdata(dev)); ++ struct dev_ext_attribute *ext_attr; ++ struct hisi_ptt_tune_desc *desc; ++ u32 reg; ++ u16 val; ++ ++ ext_attr = container_of(attr, struct dev_ext_attribute, attr); ++ desc = ext_attr->var; ++ ++ if (kstrtou16(buf, 10, &val)) ++ return -EINVAL; ++ ++ mutex_lock(&hisi_ptt->tune_lock); ++ ++ reg = readl(hisi_ptt->iobase + HISI_PTT_TUNING_CTRL); ++ reg &= ~(HISI_PTT_TUNING_CTRL_CODE | HISI_PTT_TUNING_CTRL_SUB); ++ reg |= FIELD_PREP(HISI_PTT_TUNING_CTRL_CODE | HISI_PTT_TUNING_CTRL_SUB, ++ desc->event_code); ++ writel(reg, hisi_ptt->iobase + HISI_PTT_TUNING_CTRL); ++ writel(FIELD_PREP(HISI_PTT_TUNING_DATA_VAL_MASK, val), ++ hisi_ptt->iobase + HISI_PTT_TUNING_DATA); ++ ++ if (!hisi_ptt_wait_tuning_finish(hisi_ptt)) { ++ mutex_unlock(&hisi_ptt->tune_lock); ++ return -ETIMEDOUT; ++ } ++ ++ mutex_unlock(&hisi_ptt->tune_lock); ++ return count; ++} ++ ++#define HISI_PTT_TUNE_ATTR(_name, _val, _show, _store) \ ++ static struct hisi_ptt_tune_desc _name##_desc = { \ ++ .name = #_name, \ ++ .event_code = (_val), \ ++ }; \ ++ static struct dev_ext_attribute hisi_ptt_##_name##_attr = { \ ++ .attr = __ATTR(_name, 0600, _show, _store), \ ++ .var = &_name##_desc, \ ++ } ++ ++#define HISI_PTT_TUNE_ATTR_COMMON(_name, _val) \ ++ HISI_PTT_TUNE_ATTR(_name, _val, \ ++ hisi_ptt_tune_attr_show, \ ++ hisi_ptt_tune_attr_store) ++ ++/* ++ * The value of the tuning event are composed of two parts: main event code ++ * in BIT[0,15] and subevent code in BIT[16,23]. For example, qox_tx_cpl is ++ * a subevent of 'Tx path QoS control' which for tuning the weight of Tx ++ * completion TLPs. See hisi_ptt.rst documentation for more information. ++ */ ++#define HISI_PTT_TUNE_QOS_TX_CPL (0x4 | (3 << 16)) ++#define HISI_PTT_TUNE_QOS_TX_NP (0x4 | (4 << 16)) ++#define HISI_PTT_TUNE_QOS_TX_P (0x4 | (5 << 16)) ++#define HISI_PTT_TUNE_RX_ALLOC_BUF_LEVEL (0x5 | (6 << 16)) ++#define HISI_PTT_TUNE_TX_ALLOC_BUF_LEVEL (0x5 | (7 << 16)) ++ ++HISI_PTT_TUNE_ATTR_COMMON(qos_tx_cpl, HISI_PTT_TUNE_QOS_TX_CPL); ++HISI_PTT_TUNE_ATTR_COMMON(qos_tx_np, HISI_PTT_TUNE_QOS_TX_NP); ++HISI_PTT_TUNE_ATTR_COMMON(qos_tx_p, HISI_PTT_TUNE_QOS_TX_P); ++HISI_PTT_TUNE_ATTR_COMMON(rx_alloc_buf_level, HISI_PTT_TUNE_RX_ALLOC_BUF_LEVEL); ++HISI_PTT_TUNE_ATTR_COMMON(tx_alloc_buf_level, HISI_PTT_TUNE_TX_ALLOC_BUF_LEVEL); ++ ++static struct attribute *hisi_ptt_tune_attrs[] = { ++ &hisi_ptt_qos_tx_cpl_attr.attr.attr, ++ &hisi_ptt_qos_tx_np_attr.attr.attr, ++ &hisi_ptt_qos_tx_p_attr.attr.attr, ++ &hisi_ptt_rx_alloc_buf_level_attr.attr.attr, ++ &hisi_ptt_tx_alloc_buf_level_attr.attr.attr, ++ NULL, ++}; ++ ++static struct attribute_group hisi_ptt_tune_group = { ++ .name = "tune", ++ .attrs = hisi_ptt_tune_attrs, ++}; ++ + static u16 hisi_ptt_get_filter_val(u16 devid, bool is_port) + { + if (is_port) +@@ -407,6 +536,7 @@ static struct attribute_group hisi_ptt_pmu_format_group = { + static const struct attribute_group *hisi_ptt_pmu_groups[] = { + &hisi_ptt_cpumask_attr_group, + &hisi_ptt_pmu_format_group, ++ &hisi_ptt_tune_group, + NULL + }; + +@@ -748,6 +878,7 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt) + if (ret) + return ret; + ++ mutex_init(&hisi_ptt->tune_lock); + spin_lock_init(&hisi_ptt->pmu_lock); + + hisi_ptt->hisi_ptt_pmu = (struct pmu) { +diff --git a/drivers/hwtracing/ptt/hisi_ptt.h b/drivers/hwtracing/ptt/hisi_ptt.h +index c9b635b3bfe9..ae99e5c78102 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.h ++++ b/drivers/hwtracing/ptt/hisi_ptt.h +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -22,6 +23,11 @@ + /* + * 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 +@@ -37,6 +43,8 @@ + #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) +@@ -59,6 +67,7 @@ + #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 + +@@ -71,6 +80,18 @@ + #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 +@@ -143,6 +164,7 @@ struct hisi_ptt_pmu_buf { + * @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 + * @upper_bdf: the upper BDF range of the PCI devices + * managed by this PTT device +@@ -158,6 +180,7 @@ struct hisi_ptt { + struct pmu hisi_ptt_pmu; + void __iomem *iobase; + struct pci_dev *pdev; ++ struct mutex tune_lock; + spinlock_t pmu_lock; + u32 upper_bdf; + u32 lower_bdf; +-- +2.27.0 + diff --git a/patches/0008-docs-trace-Add-HiSilicon-PTT-device-driver-documenta.patch b/patches/0008-docs-trace-Add-HiSilicon-PTT-device-driver-documenta.patch new file mode 100644 index 0000000..8698f96 --- /dev/null +++ b/patches/0008-docs-trace-Add-HiSilicon-PTT-device-driver-documenta.patch @@ -0,0 +1,426 @@ +From ae4cbc7ea0d6805d222dd67083678a5c95825c1d Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Thu, 29 Sep 2022 22:01:03 +0800 +Subject: [PATCH 08/19] docs: trace: Add HiSilicon PTT device driver + documentation + +mainline inclusion +from mainline-v6.1-rc1 +commit a7112b747c324dda8937d4f47b14dc0af0b465d1 +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T +CVE: NA + +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git/commit/?id=a7112b747c324dda8937d4f47b14dc0af0b465d1 + +-------------------------------------------------------------------------- + +Document the introduction and usage of HiSilicon PTT device driver as well +as the sysfs attributes description provided by the driver. + +Signed-off-by: Yicong Yang +Reviewed-by: Jonathan Cameron +Reviewed-by: Bagas Sanjaya +[Fixed month and kernel version] +Link: https://lore.kernel.org/r/20220816114414.4092-5-yangyicong@huawei.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Wangming Shao +Reviewed-by: Xiongfeng Wang +Reviewed-by: Jay Fang +Acked-by: Xie XiuQi +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang + + Conflicts: + Documentation/trace/index.rst +--- + .../ABI/testing/sysfs-devices-hisi_ptt | 61 ++++ + Documentation/trace/hisi-ptt.rst | 298 ++++++++++++++++++ + Documentation/trace/index.rst | 1 + + 3 files changed, 360 insertions(+) + create mode 100644 Documentation/ABI/testing/sysfs-devices-hisi_ptt + create mode 100644 Documentation/trace/hisi-ptt.rst + +diff --git a/Documentation/ABI/testing/sysfs-devices-hisi_ptt b/Documentation/ABI/testing/sysfs-devices-hisi_ptt +new file mode 100644 +index 000000000000..82de6d710266 +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-devices-hisi_ptt +@@ -0,0 +1,61 @@ ++What: /sys/devices/hisi_ptt_/tune ++Date: October 2022 ++KernelVersion: 6.1 ++Contact: Yicong Yang ++Description: This directory contains files for tuning the PCIe link ++ parameters(events). Each file is named after the event ++ of the PCIe link. ++ ++ See Documentation/trace/hisi-ptt.rst for more information. ++ ++What: /sys/devices/hisi_ptt_/tune/qos_tx_cpl ++Date: October 2022 ++KernelVersion: 6.1 ++Contact: Yicong Yang ++Description: (RW) Controls the weight of Tx completion TLPs, which influence ++ the proportion of outbound completion TLPs on the PCIe link. ++ The available tune data is [0, 1, 2]. Writing a negative value ++ will return an error, and out of range values will be converted ++ to 2. The value indicates a probable level of the event. ++ ++What: /sys/devices/hisi_ptt_/tune/qos_tx_np ++Date: October 2022 ++KernelVersion: 6.1 ++Contact: Yicong Yang ++Description: (RW) Controls the weight of Tx non-posted TLPs, which influence ++ the proportion of outbound non-posted TLPs on the PCIe link. ++ The available tune data is [0, 1, 2]. Writing a negative value ++ will return an error, and out of range values will be converted ++ to 2. The value indicates a probable level of the event. ++ ++What: /sys/devices/hisi_ptt_/tune/qos_tx_p ++Date: October 2022 ++KernelVersion: 6.1 ++Contact: Yicong Yang ++Description: (RW) Controls the weight of Tx posted TLPs, which influence the ++ proportion of outbound posted TLPs on the PCIe link. ++ The available tune data is [0, 1, 2]. Writing a negative value ++ will return an error, and out of range values will be converted ++ to 2. The value indicates a probable level of the event. ++ ++What: /sys/devices/hisi_ptt_/tune/rx_alloc_buf_level ++Date: October 2022 ++KernelVersion: 6.1 ++Contact: Yicong Yang ++Description: (RW) Control the allocated buffer watermark for inbound packets. ++ The packets will be stored in the buffer first and then transmitted ++ either when the watermark reached or when timed out. ++ The available tune data is [0, 1, 2]. Writing a negative value ++ will return an error, and out of range values will be converted ++ to 2. The value indicates a probable level of the event. ++ ++What: /sys/devices/hisi_ptt_/tune/tx_alloc_buf_level ++Date: October 2022 ++KernelVersion: 6.1 ++Contact: Yicong Yang ++Description: (RW) Control the allocated buffer watermark of outbound packets. ++ The packets will be stored in the buffer first and then transmitted ++ either when the watermark reached or when timed out. ++ The available tune data is [0, 1, 2]. Writing a negative value ++ will return an error, and out of range values will be converted ++ to 2. The value indicates a probable level of the event. +diff --git a/Documentation/trace/hisi-ptt.rst b/Documentation/trace/hisi-ptt.rst +new file mode 100644 +index 000000000000..4f87d8e21065 +--- /dev/null ++++ b/Documentation/trace/hisi-ptt.rst +@@ -0,0 +1,298 @@ ++.. SPDX-License-Identifier: GPL-2.0 ++ ++====================================== ++HiSilicon PCIe Tune and Trace device ++====================================== ++ ++Introduction ++============ ++ ++HiSilicon PCIe tune and trace device (PTT) is a PCIe Root Complex ++integrated Endpoint (RCiEP) device, providing the capability ++to dynamically monitor and tune the PCIe link's events (tune), ++and trace the TLP headers (trace). The two functions are independent, ++but is recommended to use them together to analyze and enhance the ++PCIe link's performance. ++ ++On Kunpeng 930 SoC, the PCIe Root Complex is composed of several ++PCIe cores. Each PCIe core includes several Root Ports and a PTT ++RCiEP, like below. The PTT device is capable of tuning and ++tracing the links of the PCIe core. ++:: ++ ++ +--------------Core 0-------+ ++ | | [ PTT ] | ++ | | [Root Port]---[Endpoint] ++ | | [Root Port]---[Endpoint] ++ | | [Root Port]---[Endpoint] ++ Root Complex |------Core 1-------+ ++ | | [ PTT ] | ++ | | [Root Port]---[ Switch ]---[Endpoint] ++ | | [Root Port]---[Endpoint] `-[Endpoint] ++ | | [Root Port]---[Endpoint] ++ +---------------------------+ ++ ++The PTT device driver registers one PMU device for each PTT device. ++The name of each PTT device is composed of 'hisi_ptt' prefix with ++the id of the SICL and the Core where it locates. The Kunpeng 930 ++SoC encapsulates multiple CPU dies (SCCL, Super CPU Cluster) and ++IO dies (SICL, Super I/O Cluster), where there's one PCIe Root ++Complex for each SICL. ++:: ++ ++ /sys/devices/hisi_ptt_ ++ ++Tune ++==== ++ ++PTT tune is designed for monitoring and adjusting PCIe link parameters (events). ++Currently we support events in 2 classes. The scope of the events ++covers the PCIe core to which the PTT device belongs. ++ ++Each event is presented as a file under $(PTT PMU dir)/tune, and ++a simple open/read/write/close cycle will be used to tune the event. ++:: ++ ++ $ cd /sys/devices/hisi_ptt_/tune ++ $ ls ++ qos_tx_cpl qos_tx_np qos_tx_p ++ tx_path_rx_req_alloc_buf_level ++ tx_path_tx_req_alloc_buf_level ++ $ cat qos_tx_dp ++ 1 ++ $ echo 2 > qos_tx_dp ++ $ cat qos_tx_dp ++ 2 ++ ++Current value (numerical value) of the event can be simply read ++from the file, and the desired value written to the file to tune. ++ ++1. Tx Path QoS Control ++------------------------ ++ ++The following files are provided to tune the QoS of the tx path of ++the PCIe core. ++ ++- qos_tx_cpl: weight of Tx completion TLPs ++- qos_tx_np: weight of Tx non-posted TLPs ++- qos_tx_p: weight of Tx posted TLPs ++ ++The weight influences the proportion of certain packets on the PCIe link. ++For example, for the storage scenario, increase the proportion ++of the completion packets on the link to enhance the performance as ++more completions are consumed. ++ ++The available tune data of these events is [0, 1, 2]. ++Writing a negative value will return an error, and out of range ++values will be converted to 2. Note that the event value just ++indicates a probable level, but is not precise. ++ ++2. Tx Path Buffer Control ++------------------------- ++ ++Following files are provided to tune the buffer of tx path of the PCIe core. ++ ++- rx_alloc_buf_level: watermark of Rx requested ++- tx_alloc_buf_level: watermark of Tx requested ++ ++These events influence the watermark of the buffer allocated for each ++type. Rx means the inbound while Tx means outbound. The packets will ++be stored in the buffer first and then transmitted either when the ++watermark reached or when timed out. For a busy direction, you should ++increase the related buffer watermark to avoid frequently posting and ++thus enhance the performance. In most cases just keep the default value. ++ ++The available tune data of above events is [0, 1, 2]. ++Writing a negative value will return an error, and out of range ++values will be converted to 2. Note that the event value just ++indicates a probable level, but is not precise. ++ ++Trace ++===== ++ ++PTT trace is designed for dumping the TLP headers to the memory, which ++can be used to analyze the transactions and usage condition of the PCIe ++Link. You can choose to filter the traced headers by either Requester ID, ++or those downstream of a set of Root Ports on the same core of the PTT ++device. It's also supported to trace the headers of certain type and of ++certain direction. ++ ++You can use the perf command `perf record` to set the parameters, start ++trace and get the data. It's also supported to decode the trace ++data with `perf report`. The control parameters for trace is inputted ++as event code for each events, which will be further illustrated later. ++An example usage is like ++:: ++ ++ $ perf record -e hisi_ptt0_2/filter=0x80001,type=1,direction=1, ++ format=1/ -- sleep 5 ++ ++This will trace the TLP headers downstream root port 0000:00:10.1 (event ++code for event 'filter' is 0x80001) with type of posted TLP requests, ++direction of inbound and traced data format of 8DW. ++ ++1. Filter ++--------- ++ ++The TLP headers to trace can be filtered by the Root Ports or the Requester ID ++of the Endpoint, which are located on the same core of the PTT device. You can ++set the filter by specifying the `filter` parameter which is required to start ++the trace. The parameter value is 20 bit. Bit 19 indicates the filter type. ++1 for Root Port filter and 0 for Requester filter. Bit[15:0] indicates the ++filter value. The value for a Root Port is a mask of the core port id which is ++calculated from its PCI Slot ID as (slotid & 7) * 2. The value for a Requester ++is the Requester ID (Device ID of the PCIe function). Bit[18:16] is currently ++reserved for extension. ++ ++For example, if the desired filter is Endpoint function 0000:01:00.1 the filter ++value will be 0x00101. If the desired filter is Root Port 0000:00:10.0 then ++then filter value is calculated as 0x80001. ++ ++Note that multiple Root Ports can be specified at one time, but only one ++Endpoint function can be specified in one trace. Specifying both Root Port ++and function at the same time is not supported. Driver maintains a list of ++available filters and will check the invalid inputs. ++ ++Currently the available filters are detected in driver's probe. If the supported ++devices are removed/added after probe, you may need to reload the driver to update ++the filters. ++ ++2. Type ++------- ++ ++You can trace the TLP headers of certain types by specifying the `type` ++parameter, which is required to start the trace. The parameter value is ++8 bit. Current supported types and related values are shown below: ++ ++- 8'b00000001: posted requests (P) ++- 8'b00000010: non-posted requests (NP) ++- 8'b00000100: completions (CPL) ++ ++You can specify multiple types when tracing inbound TLP headers, but can only ++specify one when tracing outbound TLP headers. ++ ++3. Direction ++------------ ++ ++You can trace the TLP headers from certain direction, which is relative ++to the Root Port or the PCIe core, by specifying the `direction` parameter. ++This is optional and the default parameter is inbound. The parameter value ++is 4 bit. When the desired format is 4DW, directions and related values ++supported are shown below: ++ ++- 4'b0000: inbound TLPs (P, NP, CPL) ++- 4'b0001: outbound TLPs (P, NP, CPL) ++- 4'b0010: outbound TLPs (P, NP, CPL) and inbound TLPs (P, NP, CPL B) ++- 4'b0011: outbound TLPs (P, NP, CPL) and inbound TLPs (CPL A) ++ ++When the desired format is 8DW, directions and related values supported are ++shown below: ++ ++- 4'b0000: reserved ++- 4'b0001: outbound TLPs (P, NP, CPL) ++- 4'b0010: inbound TLPs (P, NP, CPL B) ++- 4'b0011: inbound TLPs (CPL A) ++ ++Inbound completions are classified into two types: ++ ++- completion A (CPL A): completion of CHI/DMA/Native non-posted requests, except for CPL B ++- completion B (CPL B): completion of DMA remote2local and P2P non-posted requests ++ ++4. Format ++-------------- ++ ++You can change the format of the traced TLP headers by specifying the ++`format` parameter. The default format is 4DW. The parameter value is 4 bit. ++Current supported formats and related values are shown below: ++ ++- 4'b0000: 4DW length per TLP header ++- 4'b0001: 8DW length per TLP header ++ ++The traced TLP header format is different from the PCIe standard. ++ ++When using the 8DW data format, the entire TLP header is logged ++(Header DW0-3 shown below). For example, the TLP header for Memory ++Reads with 64-bit addresses is shown in PCIe r5.0, Figure 2-17; ++the header for Configuration Requests is shown in Figure 2.20, etc. ++ ++In addition, 8DW trace buffer entries contain a timestamp and ++possibly a prefix for a PASID TLP prefix (see Figure 6-20, PCIe r5.0). ++Otherwise this field will be all 0. ++ ++The bit[31:11] of DW0 is always 0x1fffff, which can be ++used to distinguish the data format. 8DW format is like ++:: ++ ++ bits [ 31:11 ][ 10:0 ] ++ |---------------------------------------|-------------------| ++ DW0 [ 0x1fffff ][ Reserved (0x7ff) ] ++ DW1 [ Prefix ] ++ DW2 [ Header DW0 ] ++ DW3 [ Header DW1 ] ++ DW4 [ Header DW2 ] ++ DW5 [ Header DW3 ] ++ DW6 [ Reserved (0x0) ] ++ DW7 [ Time ] ++ ++When using the 4DW data format, DW0 of the trace buffer entry ++contains selected fields of DW0 of the TLP, together with a ++timestamp. DW1-DW3 of the trace buffer entry contain DW1-DW3 ++directly from the TLP header. ++ ++4DW format is like ++:: ++ ++ bits [31:30] [ 29:25 ][24][23][22][21][ 20:11 ][ 10:0 ] ++ |-----|---------|---|---|---|---|-------------|-------------| ++ DW0 [ Fmt ][ Type ][T9][T8][TH][SO][ Length ][ Time ] ++ DW1 [ Header DW1 ] ++ DW2 [ Header DW2 ] ++ DW3 [ Header DW3 ] ++ ++5. Memory Management ++-------------------- ++ ++The traced TLP headers will be written to the memory allocated ++by the driver. The hardware accepts 4 DMA address with same size, ++and writes the buffer sequentially like below. If DMA addr 3 is ++finished and the trace is still on, it will return to addr 0. ++:: ++ ++ +->[DMA addr 0]->[DMA addr 1]->[DMA addr 2]->[DMA addr 3]-+ ++ +---------------------------------------------------------+ ++ ++Driver will allocate each DMA buffer of 4MiB. The finished buffer ++will be copied to the perf AUX buffer allocated by the perf core. ++Once the AUX buffer is full while the trace is still on, driver ++will commit the AUX buffer first and then apply for a new one with ++the same size. The size of AUX buffer is default to 16MiB. User can ++adjust the size by specifying the `-m` parameter of the perf command. ++ ++6. Decoding ++----------- ++ ++You can decode the traced data with `perf report -D` command (currently ++only support to dump the raw trace data). The traced data will be decoded ++according to the format described previously (take 8DW as an example): ++:: ++ ++ [...perf headers and other information] ++ . ... HISI PTT data: size 4194304 bytes ++ . 00000000: 00 00 00 00 Prefix ++ . 00000004: 01 00 00 60 Header DW0 ++ . 00000008: 0f 1e 00 01 Header DW1 ++ . 0000000c: 04 00 00 00 Header DW2 ++ . 00000010: 40 00 81 02 Header DW3 ++ . 00000014: 33 c0 04 00 Time ++ . 00000020: 00 00 00 00 Prefix ++ . 00000024: 01 00 00 60 Header DW0 ++ . 00000028: 0f 1e 00 01 Header DW1 ++ . 0000002c: 04 00 00 00 Header DW2 ++ . 00000030: 40 00 81 02 Header DW3 ++ . 00000034: 02 00 00 00 Time ++ . 00000040: 00 00 00 00 Prefix ++ . 00000044: 01 00 00 60 Header DW0 ++ . 00000048: 0f 1e 00 01 Header DW1 ++ . 0000004c: 04 00 00 00 Header DW2 ++ . 00000050: 40 00 81 02 Header DW3 ++ [...] +diff --git a/Documentation/trace/index.rst b/Documentation/trace/index.rst +index 306997941ba1..efbb91b49f39 100644 +--- a/Documentation/trace/index.rst ++++ b/Documentation/trace/index.rst +@@ -22,3 +22,4 @@ Linux Tracing Technologies + hwlat_detector + intel_th + stm ++ hisi-ptt +-- +2.27.0 + diff --git a/patches/0009-MAINTAINERS-Add-maintainer-for-HiSilicon-PTT-driver.patch b/patches/0009-MAINTAINERS-Add-maintainer-for-HiSilicon-PTT-driver.patch new file mode 100644 index 0000000..b6b6acb --- /dev/null +++ b/patches/0009-MAINTAINERS-Add-maintainer-for-HiSilicon-PTT-driver.patch @@ -0,0 +1,57 @@ +From cd5c573c0275b1c83e2afb4e1522f65721e028ae Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Thu, 29 Sep 2022 22:01:04 +0800 +Subject: [PATCH 09/19] MAINTAINERS: Add maintainer for HiSilicon PTT driver + +mainline inclusion +from mainline-v6.1-rc1 +commit 366317eae983a0d96aeed78ad219b9c4ed2a719a +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T +CVE: NA + +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git/commit/?id=366317eae983a0d96aeed78ad219b9c4ed2a719a + +-------------------------------------------------------------------------- + +Add maintainer for driver and documentation of HiSilicon PTT device. + +Signed-off-by: Yicong Yang +Reviewed-by: Jonathan Cameron +Link: https://lore.kernel.org/r/20220816114414.4092-6-yangyicong@huawei.com +Signed-off-by: Mathieu Poirier +Signed-off-by: Wangming Shao +Reviewed-by: Xiongfeng Wang +Reviewed-by: Jay Fang +Acked-by: Xie XiuQi +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang + + Conflicts: + MAINTAINERS +--- + MAINTAINERS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 3ad1e1b1da4a..3fafea62d296 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -6665,6 +6665,14 @@ S: Supported + F: drivers/perf/hisilicon + F: Documentation/perf/hisi-pmu.txt + ++HISILICON PTT DRIVER ++M: Yicong Yang ++L: linux-kernel@vger.kernel.org ++S: Maintained ++F: Documentation/ABI/testing/sysfs-devices-hisi_ptt ++F: Documentation/trace/hisi-ptt.rst ++F: drivers/hwtracing/ptt/ ++ + HISILICON ROCE DRIVER + M: Lijun Ou + M: Wei Hu(Xavier) +-- +2.27.0 + diff --git a/patches/0010-hwtracing-hisi_ptt-Fix-up-for-iommu-dma-Make-header-.patch b/patches/0010-hwtracing-hisi_ptt-Fix-up-for-iommu-dma-Make-header-.patch new file mode 100644 index 0000000..b7ee3b5 --- /dev/null +++ b/patches/0010-hwtracing-hisi_ptt-Fix-up-for-iommu-dma-Make-header-.patch @@ -0,0 +1,61 @@ +From 5bcd48d8586935f02c89d96ca15dae8f144dd790 Mon Sep 17 00:00:00 2001 +From: Stephen Rothwell +Date: Thu, 29 Sep 2022 22:01:05 +0800 +Subject: [PATCH 10/19] hwtracing: hisi_ptt: Fix up for "iommu/dma: Make header + private" + +mainline inclusion +from mainline-v6.1-rc1 +commit 5fc1531dd771cd1481116a66f992a190e01efce6 +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T +CVE: NA + +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/coresight/linux.git/commit/?id=5fc1531dd771cd1481116a66f992a190e01efce6 + +-------------------------------------------------------------------------- + +drivers/hwtracing/ptt/hisi_ptt.c:13:10: fatal error: linux/dma-iommu.h: No such file or directory + 13 | #include + | ^~~~~~~~~~~~~~~~~~~ + +Caused by: + + commit ff0de066b463 ("hwtracing: hisi_ptt: Add trace function support for HiSilicon PCIe Tune and Trace device") + +interacting with: + + commit f2042ed21da7 ("iommu/dma: Make header private") + +from the iommu tree. + +Signed-off-by: Stephen Rothwell +Acked-by: Robin Murphy +Acked-by: Yicong Yang +[Fixed subject line and added changelog text] +Signed-off-by: Mathieu Poirier +Signed-off-by: Wangming Shao +Reviewed-by: Xiongfeng Wang +Reviewed-by: Jay Fang +Acked-by: Xie XiuQi +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang +--- + drivers/hwtracing/ptt/hisi_ptt.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index cffc625665a2..70d3398d341f 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include + #include + #include +-- +2.27.0 + diff --git a/patches/0011-hwtracing-hisi_ptt-Only-add-the-supported-devices-to.patch b/patches/0011-hwtracing-hisi_ptt-Only-add-the-supported-devices-to.patch new file mode 100644 index 0000000..159d007 --- /dev/null +++ b/patches/0011-hwtracing-hisi_ptt-Only-add-the-supported-devices-to.patch @@ -0,0 +1,59 @@ +From 5e414d74bedb6a2da45554952064133ccdead5ca Mon Sep 17 00:00:00 2001 +From: Lei Zhou +Date: Mon, 21 Nov 2022 22:02:10 +0800 +Subject: [PATCH 11/19] hwtracing: hisi_ptt: Only add the supported devices to + the filters list + +mainline inclusion +from mainline-v6.3-rc1 +commit b8d976c7d41a28c0fccf22c7113be9a29dc07e5c +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I60FNG +CVE: NA +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b8d976c7d41a28c0fccf22c7113be9a29dc07e5c + +-------------------------------------------------------------- + +The PTT device can only filter the devices on the same PCIe core, +within BDF range [lower_bdf, upper_bdf]. Add the miss checking when +initialize the filters list. + +Fixes: ff0de066b463 ("hwtracing: hisi_ptt: Add trace function support +for HiSilicon PCIe Tune and Trace device") + +Signed-off-by: Wangming Shao +Signed-off-by: Lei Zhou +Reviewed-by: Yicong Yang +Reviewed-by: Yang Jihong +Signed-off-by: Zheng Zengkai +Signed-off-by: YunYi Yang +--- + drivers/hwtracing/ptt/hisi_ptt.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index 70d3398d341f..8e0dddbad0ec 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -364,8 +364,18 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt) + + static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data) + { ++ struct pci_dev *root_port = pcie_find_root_port(pdev); + struct hisi_ptt_filter_desc *filter; + struct hisi_ptt *hisi_ptt = data; ++ u32 port_devid; ++ ++ if (!root_port) ++ return 0; ++ ++ port_devid = PCI_DEVID(root_port->bus->number, root_port->devfn); ++ if (port_devid < hisi_ptt->lower_bdf || ++ port_devid > hisi_ptt->upper_bdf) ++ return 0; + + /* + * We won't fail the probe if filter allocation failed here. The filters +-- +2.27.0 + diff --git a/patches/0012-hwtracing-hisi_ptt-Factor-out-filter-allocation-and-.patch b/patches/0012-hwtracing-hisi_ptt-Factor-out-filter-allocation-and-.patch new file mode 100644 index 0000000..1034d0c --- /dev/null +++ b/patches/0012-hwtracing-hisi_ptt-Factor-out-filter-allocation-and-.patch @@ -0,0 +1,121 @@ +From f258c5de9bf043c1a363ce80f7a2c90130f21344 Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Wed, 7 Jun 2023 17:31:19 +0800 +Subject: [PATCH 12/19] hwtracing: hisi_ptt: Factor out filter allocation and + release operation + +driver inclusion +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I7BZYX +CVE: NA + +-------------------------------------------------------------------------- + +From: Yicong Yang + +Factor out the allocation and release of filters. This will make it easier +to extend and manage the function of the filter. + +Reviewed-by: Jonathan Cameron +Signed-off-by: Yicong Yang +Signed-off-by: YunYi Yang + + Conflicts: + drivers/hwtracing/ptt/hisi_ptt.c +--- + drivers/hwtracing/ptt/hisi_ptt.c | 61 ++++++++++++++++++++------------ + 1 file changed, 39 insertions(+), 22 deletions(-) + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index 8e0dddbad0ec..18907c47a22e 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -362,6 +362,40 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt) + return 0; + } + ++static void hisi_ptt_del_free_filter(struct hisi_ptt *hisi_ptt, ++ struct hisi_ptt_filter_desc *filter) ++{ ++ list_del(&filter->list); ++ kfree(filter); ++} ++ ++static struct hisi_ptt_filter_desc * ++hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, struct pci_dev *pdev) ++{ ++ struct hisi_ptt_filter_desc *filter; ++ ++ filter = kzalloc(sizeof(*filter), GFP_KERNEL); ++ if (!filter) { ++ pci_err(hisi_ptt->pdev, "failed to add filter for %s\n", ++ pci_name(pdev)); ++ return NULL; ++ } ++ ++ filter->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); ++ filter->is_port = pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT; ++ if (filter->is_port) { ++ list_add_tail(&filter->list, &hisi_ptt->port_filters); ++ ++ /* Update the available port mask */ ++ hisi_ptt->port_mask |= hisi_ptt_get_filter_val(filter->devid, ++ true); ++ } else { ++ list_add_tail(&filter->list, &hisi_ptt->req_filters); ++ } ++ ++ return filter; ++} ++ + static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data) + { + struct pci_dev *root_port = pcie_find_root_port(pdev); +@@ -382,23 +416,10 @@ static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data) + * should be partial initialized and users would know which filter fails + * through the log. Other functions of PTT device are still available. + */ +- filter = kzalloc(sizeof(*filter), GFP_KERNEL); ++ filter = hisi_ptt_alloc_add_filter(hisi_ptt, pdev); + if (!filter) + return -ENOMEM; + +- filter->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); +- +- if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) { +- filter->is_port = true; +- list_add_tail(&filter->list, &hisi_ptt->port_filters); +- +- /* Update the available port mask */ +- hisi_ptt->port_mask |= hisi_ptt_get_filter_val(filter->devid, +- true); +- } else { +- list_add_tail(&filter->list, &hisi_ptt->req_filters); +- } +- + return 0; + } + +@@ -407,15 +428,11 @@ static void hisi_ptt_release_filters(void *data) + struct hisi_ptt_filter_desc *filter, *tmp; + struct hisi_ptt *hisi_ptt = data; + +- list_for_each_entry_safe(filter, tmp, &hisi_ptt->req_filters, list) { +- list_del(&filter->list); +- kfree(filter); +- } ++ list_for_each_entry_safe(filter, tmp, &hisi_ptt->req_filters, list) ++ hisi_ptt_del_free_filter(hisi_ptt, filter); + +- list_for_each_entry_safe(filter, tmp, &hisi_ptt->port_filters, list) { +- list_del(&filter->list); +- kfree(filter); +- } ++ list_for_each_entry_safe(filter, tmp, &hisi_ptt->port_filters, list) ++ hisi_ptt_del_free_filter(hisi_ptt, filter); + } + + static int hisi_ptt_config_trace_buf(struct hisi_ptt *hisi_ptt) +-- +2.27.0 + diff --git a/patches/0013-hwtracing-hisi_ptt-Add-support-for-dynamically-updat.patch b/patches/0013-hwtracing-hisi_ptt-Add-support-for-dynamically-updat.patch new file mode 100644 index 0000000..6c72647 --- /dev/null +++ b/patches/0013-hwtracing-hisi_ptt-Add-support-for-dynamically-updat.patch @@ -0,0 +1,423 @@ +From c0b71e3333323112781c701001761ff2624626db Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Wed, 7 Jun 2023 17:31:20 +0800 +Subject: [PATCH 13/19] hwtracing: hisi_ptt: Add support for dynamically + updating the filter list + +driver inclusion +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I7BZYX +CVE: NA + +-------------------------------------------------------------------------- + +From: Yicong Yang + +The PCIe devices supported by the PTT trace can be removed/rescanned by +hotplug or through sysfs. Add support for dynamically updating the +available filter list by registering a PCI bus notifier block. Then user +can always get latest information about available tracing filters and +driver can block the invalid filters of which related devices no longer +exist in the system. + +Reviewed-by: Jonathan Cameron +Signed-off-by: Yicong Yang +Signed-off-by: YunYi Yang + + Conflicts: + drivers/hwtracing/ptt/hisi_ptt.c +--- + Documentation/trace/hisi-ptt.rst | 6 +- + drivers/hwtracing/ptt/hisi_ptt.c | 183 +++++++++++++++++++++++++++++-- + drivers/hwtracing/ptt/hisi_ptt.h | 40 +++++++ + 3 files changed, 218 insertions(+), 11 deletions(-) + +diff --git a/Documentation/trace/hisi-ptt.rst b/Documentation/trace/hisi-ptt.rst +index 4f87d8e21065..69c538153838 100644 +--- a/Documentation/trace/hisi-ptt.rst ++++ b/Documentation/trace/hisi-ptt.rst +@@ -153,9 +153,9 @@ Endpoint function can be specified in one trace. Specifying both Root Port + and function at the same time is not supported. Driver maintains a list of + available filters and will check the invalid inputs. + +-Currently the available filters are detected in driver's probe. If the supported +-devices are removed/added after probe, you may need to reload the driver to update +-the filters. ++The available filters will be dynamically updated, which means you will always ++get correct filter information when hotplug events happen, or when you manually ++remove/rescan the devices. + + 2. Type + ------- +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index 18907c47a22e..6842c2f623ae 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -365,24 +365,45 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt) + static void hisi_ptt_del_free_filter(struct hisi_ptt *hisi_ptt, + struct hisi_ptt_filter_desc *filter) + { ++ if (filter->is_port) ++ hisi_ptt->port_mask &= ~hisi_ptt_get_filter_val(filter->devid, ++ true); ++ + list_del(&filter->list); ++ kfree(filter->name); + kfree(filter); + } + + static struct hisi_ptt_filter_desc * +-hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, struct pci_dev *pdev) ++hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, u16 devid, bool is_port) + { + struct hisi_ptt_filter_desc *filter; ++ u8 devfn = devid & 0xff; ++ char *filter_name; ++ ++ 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) { ++ pci_err(hisi_ptt->pdev, "failed to allocate name for filter %04x:%02x:%02x.%d\n", ++ pci_domain_nr(hisi_ptt->pdev->bus), PCI_BUS_NUM(devid), ++ PCI_SLOT(devfn), PCI_FUNC(devfn)); ++ return NULL; ++ } + + filter = kzalloc(sizeof(*filter), GFP_KERNEL); + if (!filter) { + pci_err(hisi_ptt->pdev, "failed to add filter for %s\n", +- pci_name(pdev)); ++ filter_name); ++ kfree(filter_name); + return NULL; + } + +- filter->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); +- filter->is_port = pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT; ++ filter->name = filter_name; ++ filter->is_port = is_port; ++ filter->devid = devid; ++ + if (filter->is_port) { + list_add_tail(&filter->list, &hisi_ptt->port_filters); + +@@ -396,6 +417,108 @@ hisi_ptt_alloc_add_filter(struct hisi_ptt *hisi_ptt, struct pci_dev *pdev) + return filter; + } + ++static void hisi_ptt_update_filters(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = to_delayed_work(work); ++ struct hisi_ptt_filter_update_info info; ++ struct hisi_ptt_filter_desc *filter; ++ struct hisi_ptt *hisi_ptt; ++ ++ hisi_ptt = container_of(delayed_work, struct hisi_ptt, work); ++ ++ if (!mutex_trylock(&hisi_ptt->filter_lock)) { ++ schedule_delayed_work(&hisi_ptt->work, HISI_PTT_WORK_DELAY_MS); ++ return; ++ } ++ ++ while (kfifo_get(&hisi_ptt->filter_update_kfifo, &info)) { ++ if (info.is_add) { ++ /* ++ * Notify the users if failed to add this filter, others ++ * still work and available. See the comments in ++ * hisi_ptt_init_filters(). ++ */ ++ filter = hisi_ptt_alloc_add_filter(hisi_ptt, ++ info.devid, ++ info.is_port); ++ if (!filter) ++ continue; ++ } else { ++ struct hisi_ptt_filter_desc *tmp; ++ struct list_head *target_list; ++ ++ target_list = info.is_port ? &hisi_ptt->port_filters : ++ &hisi_ptt->req_filters; ++ ++ list_for_each_entry_safe(filter, tmp, target_list, list) ++ if (filter->devid == info.devid) { ++ hisi_ptt_del_free_filter(hisi_ptt, ++ filter); ++ break; ++ } ++ } ++ } ++ ++ mutex_unlock(&hisi_ptt->filter_lock); ++} ++ ++/* ++ * A PCI bus notifier is used here for dynamically updating the filter ++ * list. ++ */ ++static int hisi_ptt_notifier_call(struct notifier_block *nb, ++ unsigned long action, ++ void *data) ++{ ++ struct hisi_ptt *hisi_ptt = container_of(nb, ++ struct hisi_ptt, ++ hisi_ptt_nb); ++ struct hisi_ptt_filter_update_info info; ++ struct pci_dev *pdev, *root_port; ++ struct device *dev = data; ++ u32 port_devid; ++ ++ pdev = to_pci_dev(dev); ++ root_port = pcie_find_root_port(pdev); ++ if (!root_port) ++ return 0; ++ ++ port_devid = PCI_DEVID(root_port->bus->number, root_port->devfn); ++ if (port_devid < hisi_ptt->lower_bdf || ++ port_devid > hisi_ptt->upper_bdf) ++ return 0; ++ ++ info.is_port = pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT; ++ info.devid = PCI_DEVID(pdev->bus->number, pdev->devfn); ++ ++ switch (action) { ++ case BUS_NOTIFY_ADD_DEVICE: ++ info.is_add = true; ++ break; ++ case BUS_NOTIFY_DEL_DEVICE: ++ info.is_add = false; ++ break; ++ default: ++ return 0; ++ } ++ ++ /* ++ * The FIFO size is 16 which is sufficient for almost all the cases, ++ * since each PCIe core will have most 8 Root Ports (typically only ++ * 1~4 Root Ports). On failure log the failed filter and let user ++ * handle it. ++ */ ++ if (kfifo_in_spinlocked(&hisi_ptt->filter_update_kfifo, &info, 1, ++ &hisi_ptt->filter_update_lock)) ++ schedule_delayed_work(&hisi_ptt->work, 0); ++ else ++ pci_warn(hisi_ptt->pdev, ++ "filter update fifo overflow for target %s\n", ++ pci_name(pdev)); ++ ++ return 0; ++} ++ + static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data) + { + struct pci_dev *root_port = pcie_find_root_port(pdev); +@@ -416,7 +539,11 @@ static int hisi_ptt_init_filters(struct pci_dev *pdev, void *data) + * should be partial initialized and users would know which filter fails + * through the log. Other functions of PTT device are still available. + */ +- filter = hisi_ptt_alloc_add_filter(hisi_ptt, pdev); ++ filter = hisi_ptt_alloc_add_filter(hisi_ptt, ++ PCI_DEVID(pdev->bus->number, ++ pdev->devfn), ++ pci_pcie_type(pdev) == ++ PCI_EXP_TYPE_ROOT_PORT); + if (!filter) + return -ENOMEM; + +@@ -478,8 +605,13 @@ static int hisi_ptt_init_ctrls(struct hisi_ptt *hisi_ptt) + int ret; + u32 reg; + ++ INIT_DELAYED_WORK(&hisi_ptt->work, hisi_ptt_update_filters); ++ INIT_KFIFO(hisi_ptt->filter_update_kfifo); ++ spin_lock_init(&hisi_ptt->filter_update_lock); ++ + INIT_LIST_HEAD(&hisi_ptt->port_filters); + INIT_LIST_HEAD(&hisi_ptt->req_filters); ++ mutex_init(&hisi_ptt->filter_lock); + + ret = hisi_ptt_config_trace_buf(hisi_ptt); + if (ret) +@@ -636,6 +768,7 @@ static int hisi_ptt_trace_valid_filter(struct hisi_ptt *hisi_ptt, u64 config) + { + unsigned long val, port_mask = hisi_ptt->port_mask; + struct hisi_ptt_filter_desc *filter; ++ int ret = 0; + + hisi_ptt->trace_ctrl.is_port = FIELD_GET(HISI_PTT_PMU_FILTER_IS_PORT, + config); +@@ -650,17 +783,21 @@ static int hisi_ptt_trace_valid_filter(struct hisi_ptt *hisi_ptt, u64 config) + * For Requester ID filters, walk the available filter list to see + * whether we have one matched. + */ ++ mutex_lock(&hisi_ptt->filter_lock); + if (!hisi_ptt->trace_ctrl.is_port) { + list_for_each_entry(filter, &hisi_ptt->req_filters, list) { + if (val == hisi_ptt_get_filter_val(filter->devid, + filter->is_port)) +- return 0; ++ goto out; + } + } else if (bitmap_subset(&val, &port_mask, BITS_PER_LONG)) { +- return 0; ++ goto out; + } + +- return -EINVAL; ++ ret = -EINVAL; ++out: ++ mutex_unlock(&hisi_ptt->filter_lock); ++ return ret; + } + + static void hisi_ptt_pmu_init_configs(struct hisi_ptt *hisi_ptt, +@@ -940,6 +1077,31 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt) + &hisi_ptt->hisi_ptt_pmu); + } + ++static void hisi_ptt_unregister_filter_update_notifier(void *data) ++{ ++ struct hisi_ptt *hisi_ptt = data; ++ ++ bus_unregister_notifier(&pci_bus_type, &hisi_ptt->hisi_ptt_nb); ++ ++ /* Cancel any work that has been queued */ ++ cancel_delayed_work_sync(&hisi_ptt->work); ++} ++ ++/* Register the bus notifier for dynamically updating the filter list */ ++static int hisi_ptt_register_filter_update_notifier(struct hisi_ptt *hisi_ptt) ++{ ++ int ret; ++ ++ hisi_ptt->hisi_ptt_nb.notifier_call = hisi_ptt_notifier_call; ++ ret = bus_register_notifier(&pci_bus_type, &hisi_ptt->hisi_ptt_nb); ++ if (ret) ++ return ret; ++ ++ return devm_add_action_or_reset(&hisi_ptt->pdev->dev, ++ hisi_ptt_unregister_filter_update_notifier, ++ hisi_ptt); ++} ++ + /* + * The DMA of PTT trace can only use direct mappings due to some + * hardware restriction. Check whether there is no IOMMU or the +@@ -1011,6 +1173,11 @@ static int hisi_ptt_probe(struct pci_dev *pdev, + return ret; + } + ++ ret = hisi_ptt_register_filter_update_notifier(hisi_ptt); ++ if (ret) ++ pci_warn(pdev, "failed to register filter update notifier, ret = %d", ++ ret); ++ + ret = hisi_ptt_register_pmu(hisi_ptt); + if (ret) { + pci_err(pdev, "failed to register PMU device, ret = %d", ret); +diff --git a/drivers/hwtracing/ptt/hisi_ptt.h b/drivers/hwtracing/ptt/hisi_ptt.h +index ae99e5c78102..814c3ef40acd 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.h ++++ b/drivers/hwtracing/ptt/hisi_ptt.h +@@ -11,12 +11,15 @@ + + #include + #include ++#include + #include + #include ++#include + #include + #include + #include + #include ++#include + + #define DRV_NAME "hisi_ptt" + +@@ -71,6 +74,11 @@ + #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 */ +@@ -135,11 +143,25 @@ struct hisi_ptt_trace_ctrl { + * struct hisi_ptt_filter_desc - Descriptor of the PTT trace 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 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; + }; + +@@ -160,6 +182,7 @@ struct hisi_ptt_pmu_buf { + /** + * 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 +@@ -172,10 +195,15 @@ struct hisi_ptt_pmu_buf { + * 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 + * @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; +@@ -194,7 +222,19 @@ struct hisi_ptt { + */ + struct list_head port_filters; + struct list_head req_filters; ++ struct mutex filter_lock; + 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) +-- +2.27.0 + diff --git a/patches/0014-hwtracing-hisi_ptt-Export-available-filters-through-.patch b/patches/0014-hwtracing-hisi_ptt-Export-available-filters-through-.patch new file mode 100644 index 0000000..da70844 --- /dev/null +++ b/patches/0014-hwtracing-hisi_ptt-Export-available-filters-through-.patch @@ -0,0 +1,435 @@ +From 3f8f04f1a27315514e997194e19adcd0bfe85c27 Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Wed, 7 Jun 2023 17:31:21 +0800 +Subject: [PATCH 14/19] hwtracing: hisi_ptt: Export available filters through + sysfs + +driver inclusion +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I7BZYX +CVE: NA + +-------------------------------------------------------------------------- + +From: Yicong Yang + +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 +Signed-off-by: Yicong Yang +Signed-off-by: YunYi Yang + + Conflicts: + drivers/hwtracing/ptt/hisi_ptt.c +--- + .../ABI/testing/sysfs-devices-hisi_ptt | 52 +++++ + Documentation/trace/hisi-ptt.rst | 6 + + drivers/hwtracing/ptt/hisi_ptt.c | 213 +++++++++++++++++- + drivers/hwtracing/ptt/hisi_ptt.h | 14 ++ + 4 files changed, 283 insertions(+), 2 deletions(-) + +diff --git a/Documentation/ABI/testing/sysfs-devices-hisi_ptt b/Documentation/ABI/testing/sysfs-devices-hisi_ptt +index 82de6d710266..d7e206b4901c 100644 +--- a/Documentation/ABI/testing/sysfs-devices-hisi_ptt ++++ b/Documentation/ABI/testing/sysfs-devices-hisi_ptt +@@ -59,3 +59,55 @@ Description: (RW) Control the allocated buffer watermark of outbound packets. + The available tune data is [0, 1, 2]. Writing a negative value + will return an error, and out of range values will be converted + to 2. The value indicates a probable level of the event. ++ ++What: /sys/devices/hisi_ptt_/root_port_filters ++Date: May 2023 ++KernelVersion: 6.5 ++Contact: Yicong Yang ++Description: This directory contains the files providing the PCIe Root Port filters ++ information used for PTT trace. Each file is named after the supported ++ Root Port device name ::.. ++ ++ See the description of the "filter" in Documentation/trace/hisi-ptt.rst ++ for more information. ++ ++What: /sys/devices/hisi_ptt_/root_port_filters/multiselect ++Date: May 2023 ++KernelVersion: 6.5 ++Contact: Yicong Yang ++Description: (Read) Indicates if this kind of filter can be selected at the same ++ time as others filters, or must be used on it's own. 1 indicates ++ the former case and 0 indicates the latter. ++ ++What: /sys/devices/hisi_ptt_/root_port_filters/ ++Date: May 2023 ++KernelVersion: 6.5 ++Contact: Yicong Yang ++Description: (Read) Indicates the filter value of this Root Port filter, which ++ can be used to control the TLP headers to trace by the PTT trace. ++ ++What: /sys/devices/hisi_ptt_/requester_filters ++Date: May 2023 ++KernelVersion: 6.5 ++Contact: Yicong Yang ++Description: This directory contains the files providing the PCIe Requester filters ++ information used for PTT trace. Each file is named after the supported ++ Endpoint device name ::.. ++ ++ See the description of the "filter" in Documentation/trace/hisi-ptt.rst ++ for more information. ++ ++What: /sys/devices/hisi_ptt_/requester_filters/multiselect ++Date: May 2023 ++KernelVersion: 6.5 ++Contact: Yicong Yang ++Description: (Read) Indicates if this kind of filter can be selected at the same ++ time as others filters, or must be used on it's own. 1 indicates ++ the former case and 0 indicates the latter. ++ ++What: /sys/devices/hisi_ptt_/requester_filters/ ++Date: May 2023 ++KernelVersion: 6.5 ++Contact: Yicong Yang ++Description: (Read) Indicates the filter value of this Requester filter, which ++ can be used to control the TLP headers to trace by the PTT trace. +diff --git a/Documentation/trace/hisi-ptt.rst b/Documentation/trace/hisi-ptt.rst +index 69c538153838..989255eb5622 100644 +--- a/Documentation/trace/hisi-ptt.rst ++++ b/Documentation/trace/hisi-ptt.rst +@@ -148,6 +148,12 @@ For example, if the desired filter is Endpoint function 0000:01:00.1 the filter + value will be 0x00101. If the desired filter is Root Port 0000:00:10.0 then + then filter value is calculated as 0x80001. + ++The driver also presents every supported Root Port and Requester filter through ++sysfs. Each filter will be an individual file with name of its related PCIe ++device name (domain:bus:device.function). The files of Root Port filters are ++under $(PTT PMU dir)/root_port_filters and files of Requester filters ++are under $(PTT PMU dir)/requester_filters. ++ + Note that multiple Root Ports can be specified at one time, but only one + Endpoint function can be specified in one trace. Specifying both Root Port + and function at the same time is not supported. Driver maintains a list of +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index 6842c2f623ae..31977a7c7e68 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -417,6 +417,145 @@ 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) ++{ ++ int ret; ++ ++ if (filter->is_port) ++ ret = hisi_ptt_create_rp_filter_attr(hisi_ptt, filter); ++ else ++ ret = hisi_ptt_create_req_filter_attr(hisi_ptt, filter); ++ ++ if (ret) ++ pci_err(hisi_ptt->pdev, "failed to create sysfs attribute for filter %s\n", ++ filter->name); ++ ++ return ret; ++} ++ ++static void hisi_ptt_remove_filter_attr(struct hisi_ptt *hisi_ptt, ++ struct hisi_ptt_filter_desc *filter) ++{ ++ if (filter->is_port) ++ hisi_ptt_remove_rp_filter_attr(hisi_ptt, filter); ++ else ++ hisi_ptt_remove_req_filter_attr(hisi_ptt, filter); ++} ++ ++static void hisi_ptt_remove_all_filter_attributes(void *data) ++{ ++ struct hisi_ptt_filter_desc *filter; ++ struct hisi_ptt *hisi_ptt = data; ++ ++ mutex_lock(&hisi_ptt->filter_lock); ++ ++ list_for_each_entry(filter, &hisi_ptt->req_filters, list) ++ hisi_ptt_remove_filter_attr(hisi_ptt, filter); ++ ++ list_for_each_entry(filter, &hisi_ptt->port_filters, list) ++ hisi_ptt_remove_filter_attr(hisi_ptt, filter); ++ ++ hisi_ptt->sysfs_inited = false; ++ mutex_unlock(&hisi_ptt->filter_lock); ++} ++ ++static int hisi_ptt_init_filter_attributes(struct hisi_ptt *hisi_ptt) ++{ ++ struct hisi_ptt_filter_desc *filter; ++ int ret; ++ ++ mutex_lock(&hisi_ptt->filter_lock); ++ ++ /* ++ * Register the reset callback in the first stage. In reset we traverse ++ * the filters list to remove the sysfs attributes so the callback can ++ * be called safely even without below filter attributes creation. ++ */ ++ ret = devm_add_action(&hisi_ptt->pdev->dev, ++ hisi_ptt_remove_all_filter_attributes, ++ hisi_ptt); ++ if (ret) ++ goto out; ++ ++ list_for_each_entry(filter, &hisi_ptt->port_filters, list) { ++ ret = hisi_ptt_create_filter_attr(hisi_ptt, filter); ++ if (ret) ++ goto out; ++ } ++ ++ list_for_each_entry(filter, &hisi_ptt->req_filters, list) { ++ ret = hisi_ptt_create_filter_attr(hisi_ptt, filter); ++ if (ret) ++ goto out; ++ } ++ ++ hisi_ptt->sysfs_inited = true; ++out: ++ mutex_unlock(&hisi_ptt->filter_lock); ++ return ret; ++} ++ + static void hisi_ptt_update_filters(struct work_struct *work) + { + struct delayed_work *delayed_work = to_delayed_work(work); +@@ -443,6 +582,18 @@ static void hisi_ptt_update_filters(struct work_struct *work) + info.is_port); + if (!filter) + continue; ++ ++ /* ++ * If filters' sysfs entries hasn't been initialized, ++ * then we're still at probe stage. Add the filters to ++ * the list and later hisi_ptt_init_filter_attributes() ++ * will create sysfs attributes for all the filters. ++ */ ++ if (hisi_ptt->sysfs_inited && ++ hisi_ptt_create_filter_attr(hisi_ptt, filter)) { ++ hisi_ptt_del_free_filter(hisi_ptt, filter); ++ continue; ++ } + } else { + struct hisi_ptt_filter_desc *tmp; + struct list_head *target_list; +@@ -452,8 +603,11 @@ static void hisi_ptt_update_filters(struct work_struct *work) + + list_for_each_entry_safe(filter, tmp, target_list, list) + if (filter->devid == info.devid) { +- hisi_ptt_del_free_filter(hisi_ptt, +- filter); ++ if (hisi_ptt->sysfs_inited) ++ hisi_ptt_remove_filter_attr( ++ hisi_ptt, ++ filter); ++ + break; + } + } +@@ -691,10 +845,58 @@ static struct attribute_group hisi_ptt_pmu_format_group = { + .attrs = hisi_ptt_pmu_format_attrs, + }; + ++static ssize_t hisi_ptt_filter_multiselect_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct dev_ext_attribute *ext_attr; ++ ++ ext_attr = container_of(attr, struct dev_ext_attribute, attr); ++ return sysfs_emit(buf, "%s\n", (char *)ext_attr->var); ++} ++ ++static struct dev_ext_attribute root_port_filters_multiselect = { ++ .attr = { ++ .attr = { .name = "multiselect", .mode = 0400 }, ++ .show = hisi_ptt_filter_multiselect_show, ++ }, ++ .var = "1", ++}; ++ ++static struct attribute *hisi_ptt_pmu_root_ports_attrs[] = { ++ &root_port_filters_multiselect.attr.attr, ++ NULL ++}; ++ ++static struct attribute_group hisi_ptt_pmu_root_ports_group = { ++ .name = HISI_PTT_RP_FILTERS_GRP_NAME, ++ .attrs = hisi_ptt_pmu_root_ports_attrs, ++}; ++ ++static struct dev_ext_attribute requester_filters_multiselect = { ++ .attr = { ++ .attr = { .name = "multiselect", .mode = 0400 }, ++ .show = hisi_ptt_filter_multiselect_show, ++ }, ++ .var = "0", ++}; ++ ++static struct attribute *hisi_ptt_pmu_requesters_attrs[] = { ++ &requester_filters_multiselect.attr.attr, ++ NULL ++}; ++ ++static struct attribute_group hisi_ptt_pmu_requesters_group = { ++ .name = HISI_PTT_REQ_FILTERS_GRP_NAME, ++ .attrs = hisi_ptt_pmu_requesters_attrs, ++}; ++ + static const struct attribute_group *hisi_ptt_pmu_groups[] = { + &hisi_ptt_cpumask_attr_group, + &hisi_ptt_pmu_format_group, + &hisi_ptt_tune_group, ++ &hisi_ptt_pmu_root_ports_group, ++ &hisi_ptt_pmu_requesters_group, + NULL + }; + +@@ -1184,6 +1386,13 @@ static int hisi_ptt_probe(struct pci_dev *pdev, + return ret; + } + ++ ret = hisi_ptt_init_filter_attributes(hisi_ptt); ++ if (ret) { ++ pci_err(pdev, "failed to init sysfs filter attributes, ret = %d", ++ ret); ++ return ret; ++ } ++ + return 0; + } + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.h b/drivers/hwtracing/ptt/hisi_ptt.h +index 814c3ef40acd..8342f2069f16 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.h ++++ b/drivers/hwtracing/ptt/hisi_ptt.h +@@ -11,6 +11,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -139,14 +140,25 @@ struct hisi_ptt_trace_ctrl { + u32 type:4; + }; + ++/* ++ * sysfs attribute group name for root port filters and requester filters: ++ * /sys/devices/hisi_ptt_/root_port_filters ++ * and ++ * /sys/devices/hisi_ptt_/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; +@@ -196,6 +208,7 @@ struct hisi_ptt_pmu_buf { + * @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 +@@ -223,6 +236,7 @@ struct hisi_ptt { + struct list_head port_filters; + struct list_head req_filters; + struct mutex filter_lock; ++ bool sysfs_inited; + u16 port_mask; + + /* +-- +2.27.0 + diff --git a/patches/0015-hwtracing-hisi_ptt-Advertise-PERF_PMU_CAP_NO_EXCLUDE.patch b/patches/0015-hwtracing-hisi_ptt-Advertise-PERF_PMU_CAP_NO_EXCLUDE.patch new file mode 100644 index 0000000..652cb95 --- /dev/null +++ b/patches/0015-hwtracing-hisi_ptt-Advertise-PERF_PMU_CAP_NO_EXCLUDE.patch @@ -0,0 +1,45 @@ +From db12a7b834f2a871db351062740ecafffb78fac6 Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Wed, 7 Jun 2023 17:31:22 +0800 +Subject: [PATCH 15/19] hwtracing: hisi_ptt: Advertise PERF_PMU_CAP_NO_EXCLUDE + for PTT PMU + +driver inclusion +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I7BZYX +CVE: NA + +-------------------------------------------------------------------------- + +From: Yicong Yang + +The PTT trace collects PCIe TLP headers from the PCIe link and don't +have the ability to exclude certain context. It doesn't support itrace +as well. So only advertise PERF_PMU_CAP_NO_EXCLUDE. This will greatly +save the storage of final data. Tested tracing idle link for ~15s, +without this patch we'll collect ~28.682MB data for context related +information and with this patch it reduced to ~0.226MB. + +Reviewed-by: Jonathan Cameron +Signed-off-by: Yicong Yang +Signed-off-by: YunYi Yang +--- + drivers/hwtracing/ptt/hisi_ptt.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index 31977a7c7e68..afd069245a1f 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -1248,7 +1248,7 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt) + + hisi_ptt->hisi_ptt_pmu = (struct pmu) { + .module = THIS_MODULE, +- .capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE, ++ .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + .task_ctx_nr = perf_sw_context, + .attr_groups = hisi_ptt_pmu_groups, + .event_init = hisi_ptt_pmu_event_init, +-- +2.27.0 + diff --git a/patches/0016-hwtracing-hisi_ptt-Fix-potential-sleep-in-atomic-con.patch b/patches/0016-hwtracing-hisi_ptt-Fix-potential-sleep-in-atomic-con.patch new file mode 100644 index 0000000..0798465 --- /dev/null +++ b/patches/0016-hwtracing-hisi_ptt-Fix-potential-sleep-in-atomic-con.patch @@ -0,0 +1,111 @@ +From fde19b199000532ee397f2730c7b1cfca1c48a73 Mon Sep 17 00:00:00 2001 +From: Yicong Yang +Date: Wed, 7 Jun 2023 17:31:23 +0800 +Subject: [PATCH 16/19] hwtracing: hisi_ptt: Fix potential sleep in atomic + context + +mainline inclusion +from mainline-v6.5-rc1 +commit 6c50384ef8b94a527445e3694ae6549e1f15d859 +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I7BZYX +CVE: NA +Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6c50384ef8b94a527445e3694ae6549e1f15d859 + +-------------------------------------------------------------------------- + +From: Yicong Yang + +We're using pci_irq_vector() to obtain the interrupt number and then +bind it to the CPU start perf under the protection of spinlock in +pmu::start(). pci_irq_vector() might sleep since [1] because it will +call msi_domain_get_virq() to get the MSI interrupt number and it +needs to acquire dev->msi.data->mutex. Getting a mutex will sleep on +contention. So use pci_irq_vector() in an atomic context is problematic. + +This patch cached the interrupt number in the probe() and uses the +cached data instead to avoid potential sleep. + +[1] commit 82ff8e6b78fc ("PCI/MSI: Use msi_get_virq() in pci_get_vector()") +Fixes: ff0de066b463 ("hwtracing: hisi_ptt: Add trace function support for HiSilicon PCIe Tune and Trace device") +Reviewed-by: Jonathan Cameron +Signed-off-by: Yicong Yang +Signed-off-by: YunYi Yang + + Conflicts: + drivers/hwtracing/ptt/hisi_ptt.c + drivers/hwtracing/ptt/hisi_ptt.h +--- + drivers/hwtracing/ptt/hisi_ptt.c | 17 +++++------------ + drivers/hwtracing/ptt/hisi_ptt.h | 2 ++ + 2 files changed, 7 insertions(+), 12 deletions(-) + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index afd069245a1f..f8aa66e37a4e 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -346,16 +346,13 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt) + if (ret < 0) + return ret; + +- ret = devm_request_threaded_irq(&pdev->dev, +- pci_irq_vector(pdev, +- HISI_PTT_TRACE_DMA_IRQ), ++ hisi_ptt->trace_irq = pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ); ++ ret = devm_request_threaded_irq(&pdev->dev, hisi_ptt->trace_irq, + NULL, hisi_ptt_isr, 0, + DRV_NAME, hisi_ptt); + if (ret) { + pci_err(pdev, "failed to request irq %d, ret = %d\n", +- pci_irq_vector(pdev, +- HISI_PTT_TRACE_DMA_IRQ), +- ret); ++ hisi_ptt->trace_irq, ret); + return ret; + } + +@@ -1130,9 +1127,7 @@ static void hisi_ptt_pmu_start(struct perf_event *event, int flags) + * core in event_function_local(). If CPU passed is offline we'll fail + * here, just log it since we can do nothing here. + */ +- ret = irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, +- HISI_PTT_TRACE_DMA_IRQ), +- cpumask_of(cpu)); ++ ret = irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(cpu)); + if (ret) + dev_warn(dev, "failed to set the affinity of trace interrupt\n"); + +@@ -1435,9 +1430,7 @@ static int hisi_ptt_cpu_teardown(unsigned int cpu, struct hlist_node *node) + * Also make sure the interrupt bind to the migrated CPU as well. Warn + * the user on failure here. + */ +- if (irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, +- HISI_PTT_TRACE_DMA_IRQ), +- cpumask_of(target))) ++ if (irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(target))) + dev_warn(dev, "failed to set the affinity of trace interrupt\n"); + + hisi_ptt->trace_ctrl.on_cpu = target; +diff --git a/drivers/hwtracing/ptt/hisi_ptt.h b/drivers/hwtracing/ptt/hisi_ptt.h +index 8342f2069f16..435260920267 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.h ++++ b/drivers/hwtracing/ptt/hisi_ptt.h +@@ -201,6 +201,7 @@ struct hisi_ptt_pmu_buf { + * @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 +@@ -223,6 +224,7 @@ struct hisi_ptt { + struct pci_dev *pdev; + struct mutex tune_lock; + spinlock_t pmu_lock; ++ int trace_irq; + u32 upper_bdf; + u32 lower_bdf; + +-- +2.27.0 + diff --git a/patches/0017-hwtracing-hisi_ptt-Keep-to-advertise-PERF_PMU_CAP_EX.patch b/patches/0017-hwtracing-hisi_ptt-Keep-to-advertise-PERF_PMU_CAP_EX.patch new file mode 100644 index 0000000..491305f --- /dev/null +++ b/patches/0017-hwtracing-hisi_ptt-Keep-to-advertise-PERF_PMU_CAP_EX.patch @@ -0,0 +1,39 @@ +From 5fb3efe86694b0340b9bf17b060022495bafdb00 Mon Sep 17 00:00:00 2001 +From: Junhao He +Date: Tue, 20 Jun 2023 22:06:43 +0800 +Subject: [PATCH 17/19] hwtracing: hisi_ptt: Keep to advertise + PERF_PMU_CAP_EXCLUSIVE + +driver inclusion +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I7F2F2 +CVE: NA + +-------------------------------- + +Keep to advertise PERF_PMU_CAP_EXCLUSIVE. Such pmus can only have one +event scheduled at a time, and the perf tool will report device busy. + +Signed-off-by: Junhao He +Signed-off-by: YunYi Yang +--- + drivers/hwtracing/ptt/hisi_ptt.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index f8aa66e37a4e..ea981afb55fe 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -1243,7 +1243,8 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt) + + hisi_ptt->hisi_ptt_pmu = (struct pmu) { + .module = THIS_MODULE, +- .capabilities = PERF_PMU_CAP_NO_EXCLUDE, ++ .capabilities = PERF_PMU_CAP_NO_EXCLUDE | ++ PERF_PMU_CAP_EXCLUSIVE, + .task_ctx_nr = perf_sw_context, + .attr_groups = hisi_ptt_pmu_groups, + .event_init = hisi_ptt_pmu_event_init, +-- +2.27.0 + diff --git a/patches/0018-hwtracing-hisi_ptt-Add-dummy-callback-pmu-read.patch b/patches/0018-hwtracing-hisi_ptt-Add-dummy-callback-pmu-read.patch new file mode 100644 index 0000000..40035bd --- /dev/null +++ b/patches/0018-hwtracing-hisi_ptt-Add-dummy-callback-pmu-read.patch @@ -0,0 +1,106 @@ +From dc4d7fdddf976f9f14ce4b37c5dacd23a2219ed9 Mon Sep 17 00:00:00 2001 +From: Junhao He +Date: Tue, 20 Jun 2023 22:06:42 +0800 +Subject: [PATCH 18/19] hwtracing: hisi_ptt: Add dummy callback pmu::read() + +driver inclusion +category: bugfix +bugzilla: https://gitee.com/openeuler/kernel/issues/I7F2F2 +CVE: NA + +-------------------------------- + +When the perf is tracing hisi_ptt pmu and then stopped immediately +with "ctrl + c". the perf will call pmu::read() to updata trace data, +but driver does not implement the callback pmu::read(). +Will cause the following panic. + + root@localhost:/# perf record -m,16M -e hisi_ptt0_2/xxx/ -C 0 + ^C + [ perf record: Woken up 0 times to write data ] + [ 3693.734230] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 + [ 3693.747212] Mem abort info: + [ 3693.749991] ESR = 0x0000000086000006 + [ 3693.753725] EC = 0x21: IABT (current EL), IL = 32 bits + [ 3693.759022] SET = 0, FnV = 0 + [ 3693.762062] EA = 0, S1PTW = 0 + [ 3693.765188] FSC = 0x06: level 2 translation fault + [ 3693.770051] user pgtable: 4k pages, 48-bit VAs, pgdp=000008302912e000 + [ 3693.776477] [0000000000000000] pgd=0800083019fc2003, p4d=0800083019fc2003, pud=0800083019fca003, pmd=0000000000000000 + [ 3693.787072] Internal error: Oops: 0000000086000006 [#1] PREEMPT SMP + [ 3693.822414] pstate: 614008c9 (nZCv daIF +PAN -UAO -TCO +DIT -SSBS BTYPE=-c) + [ 3693.829361] pc : 0x0 + [ 3693.831534] lr : __perf_event_read+0x110/0x208 + [ 3693.835966] sp : ffff800008003eb0 + [ 3693.839266] x29: ffff800008003eb0 x28: ffffa4f0d14f1100 x27: 0000000000000001 + [ 3693.846388] x26: ffffa4f0d14f1100 x25: 0000000000000000 x24: 0000000000000000 + [ 3693.853509] x23: ffff082197adf4f8 x22: 0000000000000000 x21: ffff80001f8ebc28 + [ 3693.860630] x20: ffff08478be506c8 x19: ffff083028f22220 x18: 0000000000000000 + [ 3693.867751] x17: ffff6356bb355000 x16: ffff800008000000 x15: 0000000000000000 + [ 3693.874871] x14: 0000000000000002 x13: 0000000000000000 x12: 0000000000000040 + [ 3693.881992] x11: ffff08300a915b40 x10: ffff08300a915b42 x9 : ffffa4f0ce6ee5a0 + [ 3693.889113] x8 : ffff083000401268 x7 : 0000000000000000 x6 : 000000108dce8ee0 + [ 3693.896234] x5 : 01ffffffffffffff x4 : 0000000000000000 x3 : 000000000112024a + [ 3693.903355] x2 : 000000003cadb114 x1 : 0000000000000000 x0 : ffff083028f22220 + [ 3693.910476] Call trace: + [ 3693.912908] 0x0 + [ 3693.914733] __flush_smp_call_function_queue+0x154/0x258 + [ 3693.920032] generic_smp_call_function_single_interrupt+0x1c/0x30 + [ 3693.926111] ipi_handler+0x90/0x2d0 + [ 3693.929588] handle_percpu_devid_irq+0x90/0x250 + [ 3693.934105] generic_handle_domain_irq+0x34/0x58 + [ 3693.938708] gic_handle_irq+0x12c/0x270 + [ 3693.942530] call_on_irq_stack+0x24/0x30 + [ 3693.946439] do_interrupt_handler+0x88/0x98 + [ 3693.950608] el1_interrupt+0x48/0xe8 + [ 3693.954171] el1h_64_irq_handler+0x18/0x28 + [ 3693.958253] el1h_64_irq+0x78/0x80 + [ 3693.961641] default_idle_call+0x5c/0x180 + [ 3693.965636] do_idle+0x25c/0x2d0 + [ 3693.968851] cpu_startup_entry+0x2c/0x40 + [ 3693.972760] rest_init+0xec/0xf8 + [ 3693.975974] arch_call_rest_init+0x18/0x20 + [ 3693.980057] start_kernel+0x41c/0x7f0 + [ 3693.983705] __primary_switched+0xbc/0xd0 + [ 3693.987702] Code: ???????? ???????? ???????? ???????? (????????) + [ 3693.993781] ---[ end trace 0000000000000000 ]--- + [ 3694.182495] Kernel panic - not syncing: Oops: Fatal exception in interrupt + [ 3694.189354] SMP: stopping secondary CPUs + [ 3694.193276] Kernel Offset: 0x24f0c6470000 from 0xffff800008000000 + [ 3694.199354] PHYS_OFFSET: 0x0 + [ 3694.202220] CPU features: 0x000000,00d005be,12affea7 + [ 3694.207170] Memory Limit: none + [ 3694.389463] ---[ end Kernel panic - not syncing: Oops: Fatal exception in interrupt ]--- + +Signed-off-by: Junhao He +Signed-off-by: YunYi Yang +--- + drivers/hwtracing/ptt/hisi_ptt.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c +index ea981afb55fe..793352390191 100644 +--- a/drivers/hwtracing/ptt/hisi_ptt.c ++++ b/drivers/hwtracing/ptt/hisi_ptt.c +@@ -1210,6 +1210,10 @@ static void hisi_ptt_pmu_del(struct perf_event *event, int flags) + hisi_ptt_pmu_stop(event, PERF_EF_UPDATE); + } + ++static void hisi_ptt_pmu_read(struct perf_event *event) ++{ ++} ++ + static void hisi_ptt_remove_cpuhp_instance(void *hotplug_node) + { + cpuhp_state_remove_instance_nocalls(hisi_ptt_pmu_online, hotplug_node); +@@ -1254,6 +1258,7 @@ static int hisi_ptt_register_pmu(struct hisi_ptt *hisi_ptt) + .stop = hisi_ptt_pmu_stop, + .add = hisi_ptt_pmu_add, + .del = hisi_ptt_pmu_del, ++ .read = hisi_ptt_pmu_read, + }; + + reg = readl(hisi_ptt->iobase + HISI_PTT_LOCATION); +-- +2.27.0 + diff --git a/patches/0019-config-arm64-Enable-config-of-hisi-ptt.patch b/patches/0019-config-arm64-Enable-config-of-hisi-ptt.patch new file mode 100644 index 0000000..7cc2d1e --- /dev/null +++ b/patches/0019-config-arm64-Enable-config-of-hisi-ptt.patch @@ -0,0 +1,33 @@ +From d8c1e574fad2421eb6c9b394b4d2de33ebb728b5 Mon Sep 17 00:00:00 2001 +From: YunYi Yang +Date: Tue, 24 Oct 2023 19:54:57 +0800 +Subject: [PATCH 19/19] config: arm64: Enable config of hisi ptt + +driver inclusion +category: feature +bugzilla: https://gitee.com/openeuler/kernel/issues/I5RP8T + +------------------------------------------------------------------- + +Enable config of hisi ptt. Set CONFIG_HISI_PTT to m. + +Signed-off-by: YunYi Yang +--- + arch/arm64/configs/openeuler_defconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig +index 60b1db8e190c..6667015bfa35 100644 +--- a/arch/arm64/configs/openeuler_defconfig ++++ b/arch/arm64/configs/openeuler_defconfig +@@ -5135,6 +5135,7 @@ CONFIG_NVMEM=y + # CONFIG_FPGA is not set + # CONFIG_FSI is not set + CONFIG_TEE=m ++CONFIG_HISI_PTT=m + + # + # TEE drivers +-- +2.27.0 + diff --git a/series.conf b/series.conf index 03838b1..5288731 100644 --- a/series.conf +++ b/series.conf @@ -2,3 +2,22 @@ # series.conf - Kernel patches configuration file # patches/linux-kernel-test.patch +patches/0001-PCI-Support-BAR-sizes-up-to-8TB.patch +patches/0002-iommu-Add-def_domain_type-callback-in-iommu_ops.patch +patches/0003-iommu-arm-smmu-v3-Make-default-domain-type-of-HiSili.patch +patches/0004-iommu-arm-smmu-v3-Integrate-the-function-for-obtain-.patch +patches/0005-genirq-Export-affinity-setter-for-modules.patch +patches/0006-hwtracing-hisi_ptt-Add-trace-function-support-for-Hi.patch +patches/0007-hwtracing-hisi_ptt-Add-tune-function-support-for-HiS.patch +patches/0008-docs-trace-Add-HiSilicon-PTT-device-driver-documenta.patch +patches/0009-MAINTAINERS-Add-maintainer-for-HiSilicon-PTT-driver.patch +patches/0010-hwtracing-hisi_ptt-Fix-up-for-iommu-dma-Make-header-.patch +patches/0011-hwtracing-hisi_ptt-Only-add-the-supported-devices-to.patch +patches/0012-hwtracing-hisi_ptt-Factor-out-filter-allocation-and-.patch +patches/0013-hwtracing-hisi_ptt-Add-support-for-dynamically-updat.patch +patches/0014-hwtracing-hisi_ptt-Export-available-filters-through-.patch +patches/0015-hwtracing-hisi_ptt-Advertise-PERF_PMU_CAP_NO_EXCLUDE.patch +patches/0016-hwtracing-hisi_ptt-Fix-potential-sleep-in-atomic-con.patch +patches/0017-hwtracing-hisi_ptt-Keep-to-advertise-PERF_PMU_CAP_EX.patch +patches/0018-hwtracing-hisi_ptt-Add-dummy-callback-pmu-read.patch +patches/0019-config-arm64-Enable-config-of-hisi-ptt.patch