diff --git a/.github/workflows/build-kernel-arm64.yml b/.github/workflows/build-kernel-arm64.yml index 5ee82c85d87bc..14f0a5929ebb4 100644 --- a/.github/workflows/build-kernel-arm64.yml +++ b/.github/workflows/build-kernel-arm64.yml @@ -30,10 +30,16 @@ jobs: run: | # .config make deepin_arm64_desktop_defconfig + scripts/config --enable CONFIG_DEBUG_INFO_NONE + scripts/config --disable CONFIG_DEBUG_INFO_DWARF5 + make olddefconfig make -j$(nproc) - name: 'Clang build kernel' run: | # .config make LLVM=-18 deepin_arm64_desktop_defconfig + scripts/config --enable CONFIG_DEBUG_INFO_NONE + scripts/config --disable CONFIG_DEBUG_INFO_DWARF5 + make LLVM=-18 olddefconfig make LLVM=-18 -j$(nproc) diff --git a/Documentation/devicetree/bindings/pci/phytium,pe2201-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/phytium,pe2201-pcie-ep.yaml new file mode 100644 index 0000000000000..49ec3e7ae7767 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/phytium,pe2201-pcie-ep.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pci/phytium,pe2201-pcie-ep.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Phytium PCIe endpoint controller + +maintainers: + - Li Tongfeng + +allOf: + - $ref: "pci-ep.yaml#" + +properties: + compatible: + const: phytium,pe2201-pcie-ep + + reg: + maxItems: 2 + + reg-names: + items: + - const: reg + - const: mem + +required: + - compatible + - reg + - reg-names + +examples: + - | + ep0: ep@0x31000000 { + compatible = "phytium,pe2201-pcie-ep"; + interrupts = <0x00000000 0x0000000a 0x00000004 0x00000000 0x0000000b 0x00000004>; + reg = <0x00000000 0x31000000 0x00000000 0x00010000 0x00000011 0x00000000 0x00000001 0x00000000 0x00000000 0x31100000 0x00000000 0x00001000>; + reg-names = "reg", "mem", "hpb"; + max-outbound-regions = <0x00000003>; + max-functions = [02]; + status = "disabled"; + }; diff --git a/MAINTAINERS b/MAINTAINERS index f2c5a9ee20ad8..3574dace0c589 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17547,10 +17547,15 @@ F: Documentation/devicetree/bindings/gpio/phytium,gpio.yaml F: Documentation/devicetree/bindings/usb/phytium,usb2-2.0.yaml F: Documentation/devicetree/bindings/usb/phytium,usb2.yaml F: Documentation/devicetree/bindings/usb/phytium.role-sw.yaml +F: Documentation/devicetree/bindings/pci/phytium,pe2201-pcie-ep.yaml F: drivers/usb/phytium/* +F: drivers/perf/phytium/phytium_ddr_pmu.c +F: drivers/perf/phytium/phytium_msi_pmu.c +F: drivers/perf/phytium/phytium_pcie_link_pmu.c F: drivers/usb/phytium/phytium_usb_v2* F: drivers/usb/typec/role-switch-phytium.c F: arch/arm64/boot/dts/phytium/* +F: arch/arm64/include/asm/phytium_cputype.h F: drivers/gpio/gpio-phytium* QAT DRIVER diff --git a/arch/arm64/configs/deepin_arm64_desktop_defconfig b/arch/arm64/configs/deepin_arm64_desktop_defconfig index 3de1e5f7c8c9c..e76edbbc314b8 100644 --- a/arch/arm64/configs/deepin_arm64_desktop_defconfig +++ b/arch/arm64/configs/deepin_arm64_desktop_defconfig @@ -4089,6 +4089,8 @@ CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_DEVFREQ_GOV_PERFORMANCE=m CONFIG_DEVFREQ_GOV_POWERSAVE=m CONFIG_DEVFREQ_GOV_USERSPACE=m +CONFIG_ARM_PHYTIUM_NOC_DEVFREQ=m +CONFIG_ARM_PHYTIUM_DMU_DEVFREQ=m CONFIG_PM_DEVFREQ_EVENT=y CONFIG_EXTCON_GPIO=m CONFIG_EXTCON_MAX14577=m diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 410bb0b5a0308..8c8d8558c6700 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -156,7 +156,7 @@ #define MICROSOFT_CPU_PART_AZURE_COBALT_100 0xD49 /* Based on r0p0 of ARM Neoverse N2 */ -#define PHYTIUM_CPU_PART_FTC303 0x303 +#define PHYTIUM_CPU_PART_FTC310 0x303 #define PHYTIUM_CPU_PART_FTC660 0x660 #define PHYTIUM_CPU_PART_FTC661 0x661 #define PHYTIUM_CPU_PART_FTC662 0x662 @@ -240,7 +240,7 @@ #define MIDR_APPLE_M2_AVALANCHE_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1) #define MIDR_AMPERE1A MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1A) -#define MIDR_PHYTIUM_FTC303 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC303) +#define MIDR_PHYTIUM_FTC310 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC310) #define MIDR_PHYTIUM_FTC660 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC660) #define MIDR_PHYTIUM_FTC661 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC661) #define MIDR_PHYTIUM_PS17064 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC662) diff --git a/arch/arm64/include/asm/phytium_cputype.h b/arch/arm64/include/asm/phytium_cputype.h new file mode 100644 index 0000000000000..c4edec454597d --- /dev/null +++ b/arch/arm64/include/asm/phytium_cputype.h @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2025, Phytium Technology Co., Ltd. + */ +#ifndef __ASM_PHYTIUM_CPUTYPE_H +#define __ASM_PHYTIUM_CPUTYPE_H + +#include +#include + +#define SOC_ID_PE1702 0x1 +#define SOC_ID_PS17064 0x2 +#define SOC_ID_PD1904 0x3 +#define SOC_ID_PS20064 0x4 + +#define SOC_ID_PD2008 0x5 +#define SOC_ID_PS21064 0x6 +#define SOC_ID_PE220X 0x7 +#define SOC_ID_PS23064 0x8 +#define SOC_ID_PD2308 0x9 +#define SOC_ID_PS2480 0xa +#define SOC_ID_PD2408 0xb + +#define SYS_REG_VAL_PS24080 0x6 +#define SYS_REG_VAL_PS23064 0x8 + +#define SMCCC_SUCCESS 0 +#define SMCCC_FAILURE (-1) +#define FUNC_ID_GET_CPU_VERSION 0xc2000002 + +enum phyt_soc_type { + PE1702 = 1, + PS17064, + PD1904, + PS20064, + PD2008, + PS21064, + PE220X, + PS23064, + PD2308, + PS24080, + PD2408, + PS15016, + UNKNOWN_SOC +}; + +extern enum phyt_soc_type phyt_soc_type_t; + +static enum phyt_soc_type do_smccc_res(struct arm_smccc_res res) +{ + unsigned long smc_cpu_ver = res.a1; + + smc_cpu_ver = (smc_cpu_ver >> 8); + switch (smc_cpu_ver) { + case SOC_ID_PE1702: + return PE1702; + case SOC_ID_PS17064: + return PS17064; + case SOC_ID_PD1904: + return PD1904; + case SOC_ID_PS20064: + return PS20064; + case SOC_ID_PD2008: + return PD2008; + case SOC_ID_PS21064: + return PS21064; + case SOC_ID_PE220X: + return PE220X; + case SOC_ID_PS23064: + return PS23064; + case SOC_ID_PD2308: + return PD2308; + case SOC_ID_PS2480: + return PS24080; + case SOC_ID_PD2408: + return PD2408; + default: + return UNKNOWN_SOC; + } +} + +static enum phyt_soc_type do_read_sysreg(void) +{ + u32 aidr_reg_val = read_sysreg(aidr_el1); + + switch (aidr_reg_val) { + case SYS_REG_VAL_PS24080: + return PS24080; + case SYS_REG_VAL_PS23064: + return PS23064; + default: + return UNKNOWN_SOC; + } +} + +static enum phyt_soc_type do_read_mpidr(void) +{ + u32 part_id = read_cpuid_part_number(); + + switch (part_id) { + case PHYTIUM_CPU_PART_FTC310: + return PE220X; + case PHYTIUM_CPU_PART_FTC660: + return PS15016; + case PHYTIUM_CPU_PART_FTC661: + return PE1702; + case PHYTIUM_CPU_PART_FTC662: + return PS17064; + case PHYTIUM_CPU_PART_FTC663: + return PD1904; + case PHYTIUM_CPU_PART_FTC862: + return PD2408; + default: + return UNKNOWN_SOC; + } +} + +static inline bool is_phytium_soc(void) +{ + if (read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM) + return true; + return false; +} + +static inline enum phyt_soc_type phyt_read_soc_type(void) +{ + enum phyt_soc_type ctype; + struct arm_smccc_res res; + + if (!is_phytium_soc()) + return UNKNOWN_SOC; + + arm_smccc_smc(FUNC_ID_GET_CPU_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); + switch (res.a0) { + case SMCCC_SUCCESS: + ctype = do_smccc_res(res); + if (ctype != UNKNOWN_SOC) + break; + fallthrough; + case SMCCC_FAILURE: + ctype = do_read_sysreg(); + if (ctype != UNKNOWN_SOC) + break; + fallthrough; + default: + ctype = do_read_mpidr(); + break; + } + return ctype; +} + +static inline void phyt_soc_type_init(void) +{ + enum phyt_soc_type ctype = phyt_read_soc_type(); + + switch (ctype) { + case PE1702: + phyt_soc_type_t = PE1702; + break; + case PS17064: + phyt_soc_type_t = PS17064; + break; + case PD1904: + phyt_soc_type_t = PD1904; + break; + case PS20064: + phyt_soc_type_t = PS20064; + break; + case PD2008: + phyt_soc_type_t = PD2008; + break; + case PS21064: + phyt_soc_type_t = PS21064; + break; + case PE220X: + phyt_soc_type_t = PE220X; + break; + case PS23064: + phyt_soc_type_t = PS23064; + break; + case PD2308: + phyt_soc_type_t = PD2308; + break; + case PS24080: + phyt_soc_type_t = PS24080; + break; + case PD2408: + phyt_soc_type_t = PD2408; + break; + case PS15016: + phyt_soc_type_t = PS15016; + break; + default: + phyt_soc_type_t = UNKNOWN_SOC; + break; + } +} + +static inline bool is_pd2408(void) +{ + + if (phyt_soc_type_t == PD2408) + return true; + return false; +} + +static inline bool is_ps23064(void) +{ + + if (phyt_soc_type_t == PS23064) + return true; + return false; +} + +static inline bool is_ps24080(void) +{ + + if (phyt_soc_type_t == PS24080) + return true; + return false; +} + +static inline bool is_pd2308(void) +{ + + if (phyt_soc_type_t == PD2308) + return true; + return false; +} + +static inline bool is_pe220x(void) +{ + + if (phyt_soc_type_t == PE220X) + return true; + return false; +} + +#endif + + diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 9ea67d6565a78..6e7926724866d 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1722,7 +1722,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL), - MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC303), + MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC310), MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC660), MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC661), MIDR_ALL_VERSIONS(MIDR_PHYTIUM_PS17064), diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c index d31a13664b3a1..af04a1739aab4 100644 --- a/arch/arm64/kernel/proton-pack.c +++ b/arch/arm64/kernel/proton-pack.c @@ -163,7 +163,7 @@ static enum mitigation_state spectre_v2_get_cpu_hw_mitigation_state(void) MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53), MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), - MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC303), + MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC310), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_2XX_SILVER), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER), @@ -474,7 +474,7 @@ static enum mitigation_state spectre_v4_get_cpu_hw_mitigation_state(void) MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53), - MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC303), + MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC310), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER), { /* sentinel */ }, diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 3a2d9d822d12d..c6adf753e6d00 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -57,6 +57,12 @@ #include #endif +#ifdef CONFIG_ARCH_PHYTIUM +#include +enum phyt_soc_type phyt_soc_type_t; +EXPORT_SYMBOL(phyt_soc_type_t); +#endif + static int num_standard_resources; static struct resource *standard_resources; @@ -349,6 +355,9 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p) FW_BUG "Booted with MMU enabled!"); } +#ifdef CONFIG_ARCH_PHYTIUM + phyt_soc_type_init(); +#endif arm64_memblock_init(); paging_init(); diff --git a/arch/x86/kernel/cpu/microcode/zhaoxin.c b/arch/x86/kernel/cpu/microcode/zhaoxin.c index ec00451f21bc5..5a925ef04a055 100644 --- a/arch/x86/kernel/cpu/microcode/zhaoxin.c +++ b/arch/x86/kernel/cpu/microcode/zhaoxin.c @@ -176,7 +176,6 @@ static int zhaoxin_microcode_sanity_check(void *mc, bool print_err, int hdr_type static void save_microcode_patch(struct microcode_zhaoxin *patch) { unsigned int size = patch->hdr.total_size; - struct microcode_zhaoxin *mc = NULL; struct page *pg = NULL; void *dst = NULL; @@ -186,18 +185,14 @@ static void save_microcode_patch(struct microcode_zhaoxin *patch) * the memory allocation to this range. */ pg = alloc_pages(GFP_DMA32 | GFP_KERNEL, get_order(size)); - - if (pg) { - dst = page_address(pg); - memcpy(dst, patch, size); - mc = dst; - if (mc) { - zhaoxin_ucode_patch = mc; - return; - } + if (!pg) { + pr_err("Unable to allocate microcode memory size: %u\n", size); + return; } - pr_err("Unable to allocate microcode memory size: %u\n", size); + dst = page_address(pg); + memcpy(dst, patch, size); + zhaoxin_ucode_patch = dst; } static inline u32 @@ -495,6 +490,7 @@ void __init load_ucode_zhaoxin_bsp(struct early_load_data *ed) if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) { zhaoxin_ucode_patch = UCODE_BSP_LOADED; + x86_cpuinit.parallel_bringup = false; ed->new_rev = uci.cpu_sig.rev; } else if (uci.mc) { pr_debug("%s: BSP CPU %d early update failed due to application failure\n", diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 14c3add985264..6c27bc5df4a9f 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1611,6 +1611,8 @@ void __init acpi_ghes_init(void) */ static struct acpi_platform_list plat_list[] = { {"HPE ", "Server ", 0, ACPI_SIG_FADT, all_versions}, + {"__ZX__", "EDK2 ", 3, ACPI_SIG_FADT, greater_than_or_equal}, + {"_BYO_ ", "BYOSOFT ", 3, ACPI_SIG_FADT, greater_than_or_equal}, { } /* End */ }; diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 3c4862a752b5a..043ec397de524 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -150,6 +150,24 @@ config ARM_SUN8I_A33_MBUS_DEVFREQ This adds the DEVFREQ driver for the MBUS controller in some Allwinner sun8i (A33 through H3) and sun50i (A64 and H5) SoCs. +config ARM_PHYTIUM_NOC_DEVFREQ + tristate "ARM PHYTIUM NOC DEVFREQ Driver" + depends on ARCH_PHYTIUM + depends on ACPI + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for Phytium Net On Chip. + It adjusts frequency for noc based on load bandwidth obtained from register. + +config ARM_PHYTIUM_DMU_DEVFREQ + tristate "ARM PHYTIUM DMU DEVFREQ Driver" + depends on ARCH_PHYTIUM + depends on ACPI + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for Phytium DDR Memory Unit. + It adjusts frequency for dmu based on load bandwidth obtained from register. + source "drivers/devfreq/event/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index bf40d04928d03..c57455f9b4818 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -12,6 +12,8 @@ obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx-bus.o obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) += mtk-cci-devfreq.o +obj-$(CONFIG_ARM_PHYTIUM_DMU_DEVFREQ) += phytium_dmu.o +obj-$(CONFIG_ARM_PHYTIUM_NOC_DEVFREQ) += phytium_noc.o obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o diff --git a/drivers/devfreq/phytium_dmu.c b/drivers/devfreq/phytium_dmu.c new file mode 100644 index 0000000000000..e85cd43f9511f --- /dev/null +++ b/drivers/devfreq/phytium_dmu.c @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: GPL-1.0 +/* + * Phytium Processor DMU Frequency Driver (v1/v2 unified) + * + * Copyright (C) 2024, Phytium Technology Co.,Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_TYPE 9 + +#define DMUFREQ_DRIVER_VERSION "1.1.0" + +/* v1 Register definition */ +#define DMU_V1_PMU_STRIDE 0x80000 +#define DMU_V1_AXI_MONITOR2_L 0x084 +#define DMU_V1_AXI_MONITOR3_L 0x08c +#define DMU_V1_AXI_MONITOR_EN 0x01c +#define DMU_V1_TIMER_START 0x000 +#define DMU_V1_TIMER_STOP 0x004 +#define DMU_V1_CLEAR_EVENT 0x008 + +#define DDR_PMU_NOTICE_START 0x0 +#define DDR_PMU_NOTICE_STOP 0x1 + +/* v2 Register definition */ +#define DMU_V2_PDM_START 0xC0000 +#define DMU_V2_PDM_STRIDE 0x1000 +#define DMU_V2_MONITOR_START 0x304 +#define DMU_V2_MONITOR_SNAPSHOT 0x30c +#define DMU_V2_EVENT_CLEAR 0x308 +#define DMU_V2_EVENT_L_CNT 0x310 +#define DMU_V2_EVENT_H_CNT 0x314 + +enum phytium_dmu_type { + PHYTIUM_DMU_V1, + PHYTIUM_DMU_V2, +}; + +struct phytium_dmufreq_info { + enum phytium_dmu_type type; + const char *name; +}; + +struct phytium_dmufreq { + struct device *dev; + const struct phytium_dmufreq_info *info; + + struct devfreq *devfreq; + struct devfreq_dev_profile profile; + struct devfreq_simple_ondemand_data ondemand_data; + + unsigned long rate; + unsigned long bandwidth; + unsigned long single_threshold_value; + int max_count; + int cnt; + + /* v1: multichannel,v2: Single-channel multiple instances */ + union { + void __iomem **basev1; + void __iomem *basev2; + }; + + /* v1 only */ + unsigned long *read_bw; + unsigned long *write_bw; + struct notifier_block nb; + bool pmu_active; + unsigned long last_bust_time; + + /* v2 only */ + unsigned int uid; + struct mutex lock; + + unsigned int freq_count; + unsigned long freq_table[]; +}; + +struct acpi_result { + int status; + unsigned long long value; +}; + +/* v1/v2 Distinguishing-type register access */ +static inline void dmu_v1_write32(struct phytium_dmufreq *priv, + int dmu, unsigned long offset, unsigned long value) +{ + writel_relaxed(value, priv->basev1[dmu] + offset); +} + +static inline unsigned long dmu_v1_read32(struct phytium_dmufreq *priv, + int dmu, unsigned long offset) +{ + return readl_relaxed(priv->basev1[dmu] + offset); +} + +static inline void dmu_v2_write32(struct phytium_dmufreq *priv, + unsigned long offset, unsigned long value) +{ + writel_relaxed(value, priv->basev2 + offset); +} + +static inline unsigned long dmu_v2_read32(struct phytium_dmufreq *priv, + unsigned long offset) +{ + return readl_relaxed(priv->basev2 + offset); +} + +/* ACPI/BIOS Related general methods */ +static struct acpi_result phytium_acpi_eval_integer(struct device *dev, const char *method) +{ + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + unsigned long long val; + struct acpi_result result; + + status = acpi_evaluate_integer(handle, (char *)method, NULL, &val); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Failed to evaluate %s: ACPI status 0x%x\n", method, status); + result.status = -EIO; + result.value = 0; + return result; + } + result.status = 0; + result.value = val; + return result; +} + +/* V1 PMU notification chain, only V1 is registered */ +BLOCKING_NOTIFIER_HEAD(dmu_pmu_notifier_chain); +EXPORT_SYMBOL(dmu_pmu_notifier_chain); + +static int dmu_pmu_notifier_call(struct notifier_block *nb, unsigned long event, void *data) +{ + struct phytium_dmufreq *priv = container_of(nb, struct phytium_dmufreq, nb); + struct device *dev = priv->dev; + + switch (event) { + case DDR_PMU_NOTICE_START: + priv->pmu_active = false; + dev_dbg(dev, "DDR PMU START: Stopping monitoring\n"); + break; + case DDR_PMU_NOTICE_STOP: + priv->cnt = 0; + priv->pmu_active = true; + dev_dbg(dev, "DDR PMU STOP: Resuming monitoring\n"); + break; + default: + break; + } + return NOTIFY_OK; +} + +/* v1/v2 General ACPI Frequency Settings */ +static int phytium_dmu_set_freq(struct device *dev, unsigned long freq) +{ + acpi_handle handle = ACPI_HANDLE(dev); + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + union acpi_object args[4]; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_status status; + unsigned long long ret; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = freq; + if (priv->info->type == PHYTIUM_DMU_V2) + args[2].integer.value = priv->uid; + else + args[2].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[3].type = ACPI_TYPE_INTEGER; + args[3].integer.value = 0; + + if (priv->info->type == PHYTIUM_DMU_V2) + mutex_lock(&priv->lock); + status = acpi_evaluate_integer(handle, "PSCF", &arg_list, &ret); + if (priv->info->type == PHYTIUM_DMU_V2) + mutex_unlock(&priv->lock); + + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PSCF method\n"); + return -EIO; + } + return 0; +} + +static int phytium_dmu_target(struct device *dev, unsigned long *freq, u32 flags) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + unsigned long old_freq = priv->rate; + unsigned long target_rate; + struct dev_pm_opp *opp; + int ret; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + target_rate = dev_pm_opp_get_freq(opp); + dev_pm_opp_put(opp); + + if (target_rate == old_freq) + return 0; + + dev_dbg(dev, "target_rate = %lu\n", target_rate); + ret = phytium_dmu_set_freq(dev, target_rate); + + if (ret) { + dev_warn(dev, "failed to set DRAM frequency: %lu\n", target_rate); + return ret; + } + priv->rate = target_rate; + return ret; +} + +static int phytium_dmu_get_cur_freq(struct device *dev, unsigned long *freq) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + + *freq = priv->rate; + return 0; +} + +/* v1/v2 General ACPI Method */ +static int get_freq_count(struct device *dev) +{ + struct acpi_result result; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3], *package, *element; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + status = acpi_evaluate_object(handle, "PGCL", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCL method, status = %d\n", status); + return -EIO; + } + package = buffer.pointer; + element = &package->package.elements[1]; + result.value = element->integer.value; + + kfree(buffer.pointer); + return result.value; +} + +static int phytium_dmu_get_freq_info(struct device *dev) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3], *package, *element; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + int i; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + status = acpi_evaluate_object(handle, "PGCL", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCL method\n"); + return -EIO; + } + + package = buffer.pointer; + element = &package->package.elements[1]; + priv->freq_count = element->integer.value; + + for (i = 0; i < priv->freq_count; i++) { + element = &package->package.elements[i+2]; + priv->freq_table[i] = element->integer.value; + dev_dbg(dev, "freq_table[%d] = %llu\n", i, element->integer.value); + } + kfree(buffer.pointer); + return 0; +} + +/* v1/v2 General ACPI State */ +static struct acpi_result phytium_dmufreq_state(struct device *dev) +{ + return phytium_acpi_eval_integer(dev, "STAT"); +} +static struct acpi_result phytium_current_enabled_channels(struct device *dev) +{ + return phytium_acpi_eval_integer(dev, "CHAN"); +} +static struct acpi_result phytium_read_threshold_value(struct device *dev) +{ + return phytium_acpi_eval_integer(dev, "BAND"); +} + +/* v1 Bandwidth acquisition with PMU notification chain */ +static u64 phytium_dmufreq_get_real_bw_v1(struct phytium_dmufreq *priv) +{ + unsigned long peak_bw = 0; + unsigned long sum_peak_bw = 0; + int i; + + for (i = 0; i < priv->max_count; i++) { + priv->read_bw[i] = dmu_v1_read32(priv, i, DMU_V1_AXI_MONITOR2_L); + priv->write_bw[i] = dmu_v1_read32(priv, i, DMU_V1_AXI_MONITOR3_L); + + dmu_v1_write32(priv, i, DMU_V1_CLEAR_EVENT, 0x1); + dmu_v1_write32(priv, i, DMU_V1_TIMER_START, 0x1); + sum_peak_bw = priv->read_bw[i] + priv->write_bw[i]; + if (sum_peak_bw > peak_bw) + peak_bw = sum_peak_bw; + } + dev_dbg(priv->dev, "peak_bw = %lu\n", peak_bw); + return peak_bw; +} + +static void polling_handle_v1(struct phytium_dmufreq *priv) +{ + int i; + if (!priv->pmu_active) { + priv->bandwidth = priv->last_bust_time; + return; + } + if (priv->cnt > 0) { + for (i = 0; i < priv->max_count ; i++) { + dmu_v1_write32(priv, i, DMU_V1_AXI_MONITOR_EN, 0x101); + dmu_v1_write32(priv, i, DMU_V1_TIMER_STOP, 0x1); + } + priv->bandwidth = phytium_dmufreq_get_real_bw_v1(priv); + } + priv->cnt = 1; +} + +/* v2 Multi-instance bandwidth acquisition */ +static void phytium_dmufreq_restart_clear_timer_v2(struct phytium_dmufreq *priv) +{ + dmu_v2_write32(priv, DMU_V2_PDM_START + DMU_V2_EVENT_CLEAR, 0x1); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_EVENT_CLEAR, 0x1); + dmu_v2_write32(priv, DMU_V2_PDM_START + DMU_V2_EVENT_CLEAR, 0x0); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_EVENT_CLEAR, 0x0); +} + +static u64 phytium_dmufreq_get_real_bw_v2(struct phytium_dmufreq *priv) +{ + u32 lo, hi; + u64 cnt_0, cnt_1, peak_bw; + + lo = dmu_v2_read32(priv, DMU_V2_PDM_START + DMU_V2_EVENT_L_CNT); + hi = dmu_v2_read32(priv, DMU_V2_PDM_START + DMU_V2_EVENT_H_CNT); + cnt_0 = ((u64)hi << 32) | lo; + lo = dmu_v2_read32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_EVENT_L_CNT); + hi = dmu_v2_read32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_EVENT_H_CNT); + cnt_1 = ((u64)hi << 32) | lo; + peak_bw = (cnt_0 + cnt_1) * 64UL; + + dev_dbg(priv->dev, "peak_bw = %llu\n", peak_bw); + return peak_bw; +} + +static void polling_handle_v2(struct phytium_dmufreq *priv) +{ + dmu_v2_write32(priv, DMU_V2_PDM_START + DMU_V2_MONITOR_SNAPSHOT, 0x1); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_MONITOR_SNAPSHOT, 0x1); + priv->bandwidth = phytium_dmufreq_get_real_bw_v2(priv); + dmu_v2_write32(priv, DMU_V2_PDM_START + DMU_V2_MONITOR_SNAPSHOT, 0x0); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_MONITOR_SNAPSHOT, 0x0); +} + +/* devfreq Framework interface */ +static int phytium_dmu_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + + if (priv->info->type == PHYTIUM_DMU_V1) { + polling_handle_v1(priv); + priv->last_bust_time = stat->busy_time = priv->bandwidth; + } else { + polling_handle_v2(priv); + stat->busy_time = priv->bandwidth; + phytium_dmufreq_restart_clear_timer_v2(priv); + } + stat->total_time = (priv->single_threshold_value * priv->rate) / priv->freq_table[0]; + stat->current_frequency = priv->rate; + return 0; +} + +/* Power Management */ +static __maybe_unused int phytium_dmufreq_suspend(struct device *dev) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + int ret = devfreq_suspend_device(priv->devfreq); + + if (ret < 0) + dev_err(dev, "failed to suspend the devfreq devices\n"); + return ret; +} + +static __maybe_unused int phytium_dmufreq_resume(struct device *dev) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + int ret = devfreq_resume_device(priv->devfreq); + + if (ret < 0) + dev_err(dev, "failed to resume the devfreq devices\n"); + return ret; +} + +static SIMPLE_DEV_PM_OPS(phytium_dmufreq_pm, phytium_dmufreq_suspend, phytium_dmufreq_resume); + +static int phytium_dmufreq_probe(struct platform_device *pdev) +{ + struct phytium_dmufreq *priv; + struct device *dev = &pdev->dev; + const struct phytium_dmufreq_info *info; + struct acpi_result result; + struct resource *res; + const char *gov; + void *gov_data = NULL; + int i, ret; + unsigned int max_state; + + info = device_get_match_data(dev); + if (!info) { + dev_err(dev, "No match data for this device\n"); + return -ENODEV; + } + + max_state = get_freq_count(dev); + if (max_state <= 0) + return -EINVAL; + + result = phytium_dmufreq_state(dev); + if (result.value == 0) { + dev_err(dev, "DMUFREQ is not enabled\n"); + return -ENODEV; + } + + priv = devm_kzalloc(dev, struct_size(priv, freq_table, max_state), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->info = info; + + if (info->type == PHYTIUM_DMU_V1) { + gov = DEVFREQ_GOV_PERFORMANCE; + gov_data = NULL; + } else { + gov = DEVFREQ_GOV_SIMPLE_ONDEMAND; + gov_data = &priv->ondemand_data; + } + + result = phytium_current_enabled_channels(dev); + if (result.status) { + dev_err(dev, "Failed to get enabled channels\n"); + return -EINVAL; + } + + priv->max_count = result.value; + result = phytium_read_threshold_value(dev); + if (result.status) { + dev_err(dev, "Failed to get threshold value\n"); + return -EINVAL; + } + priv->single_threshold_value = result.value; + priv->single_threshold_value = (priv->single_threshold_value * 1024 * 1024) / 10; + platform_set_drvdata(pdev, priv); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (info->type == PHYTIUM_DMU_V1) { + /* V1: Multi-channel, allocation base/read_bw/write_bw */ + priv->basev1 = devm_kcalloc(dev, priv->max_count, + sizeof(void __iomem *), GFP_KERNEL); + priv->read_bw = devm_kcalloc(dev, priv->max_count, + sizeof(unsigned long), GFP_KERNEL); + priv->write_bw = devm_kcalloc(dev, priv->max_count, + sizeof(unsigned long), GFP_KERNEL); + if (!priv->basev1 || !priv->read_bw || !priv->write_bw) + return -ENOMEM; + for (i = 0; i < priv->max_count; i++) { + resource_size_t offset = res->start + i * DMU_V1_PMU_STRIDE; + + priv->basev1[i] = devm_ioremap(dev, offset, resource_size(res)); + if (IS_ERR(priv->basev1[i])) + return PTR_ERR(priv->basev1[i]); + } + /* Register PMU notification chain */ + priv->nb.notifier_call = dmu_pmu_notifier_call; + ret = blocking_notifier_chain_register(&dmu_pmu_notifier_chain, &priv->nb); + if (ret) { + dev_err(dev, "Failed to register notifier\n"); + return ret; + } + priv->pmu_active = true; + priv->cnt = 1; + dev->init_name = "dmufreq"; + } else { + /* V2: Single-channel multi-instance, allocate base, get uid */ + unsigned long long uid; + + mutex_init(&priv->lock); + acpi_evaluate_integer(ACPI_HANDLE(dev), "_UID", NULL, &uid); + priv->uid = uid; + priv->basev2 = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(priv->basev2)) + return PTR_ERR(priv->basev2); + dev_set_name(dev, "dmu%u", priv->uid); + } + + ret = phytium_dmu_get_freq_info(dev); + if (ret) + return ret; + + priv->profile.initial_freq = priv->freq_table[0]; + priv->profile.polling_ms = 100; + priv->profile.timer = DEVFREQ_TIMER_DELAYED; + priv->profile.target = phytium_dmu_target; + priv->profile.get_cur_freq = phytium_dmu_get_cur_freq; + priv->profile.get_dev_status = phytium_dmu_get_dev_status; + priv->profile.freq_table = priv->freq_table; + priv->rate = priv->profile.initial_freq; + priv->profile.max_state = priv->freq_count; + priv->ondemand_data.upthreshold = 80; + priv->ondemand_data.downdifferential = 10; + + for (i = 0; i < max_state; ++i) { + ret = dev_pm_opp_add(dev, priv->freq_table[i], 0); + if (ret < 0) + goto err; + } + + priv->devfreq = devm_devfreq_add_device(dev, &priv->profile, gov, gov_data); + if (IS_ERR(priv->devfreq)) { + ret = PTR_ERR(priv->devfreq); + goto err; + } + + /* v1: Enable PMU */ + if (info->type == PHYTIUM_DMU_V1 && priv->pmu_active) { + for (i = 0; i < priv->max_count; i++) { + dmu_v1_write32(priv, i, DMU_V1_AXI_MONITOR_EN, 0x101); + dmu_v1_write32(priv, i, DMU_V1_CLEAR_EVENT, 0x1); + dmu_v1_write32(priv, i, DMU_V1_TIMER_START, 0x1); + } + } + + /* v2: Enable Monitoring */ + if (info->type == PHYTIUM_DMU_V2) { + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_MONITOR_START, 0x1); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_MONITOR_START, 0x1); + } + + priv->dev = dev; + return 0; +err: + dev_pm_opp_of_remove_table(dev); + return ret; +} + +static int phytium_dmufreq_remove(struct platform_device *pdev) +{ + struct phytium_dmufreq *priv = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int i; + + if (priv->info->type == PHYTIUM_DMU_V1) { + for (i = 0; i < priv->max_count; i++) { + dmu_v1_write32(priv, i, DMU_V1_TIMER_STOP, 0x1); + dmu_v1_write32(priv, i, DMU_V1_AXI_MONITOR_EN, 0x0); + } + blocking_notifier_chain_unregister(&dmu_pmu_notifier_chain, &priv->nb); + } + if (!priv->devfreq) + return 0; + dev_pm_opp_remove_all_dynamic(dev); + return 0; +} + +/* Matching Type Table */ +static const struct phytium_dmufreq_info phytium_dmu_v1_info = { + .type = PHYTIUM_DMU_V1, + .name = "phytium_dmu_v1", +}; + +static const struct phytium_dmufreq_info phytium_dmu_v2_info = { + .type = PHYTIUM_DMU_V2, + .name = "phytium_dmu_v2", +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id phytium_dmufreq_acpi_ids[] = { + { "PHYT0063", (kernel_ulong_t)&phytium_dmu_v1_info }, + { "PHYT3011", (kernel_ulong_t)&phytium_dmu_v2_info }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, phytium_dmufreq_acpi_ids); +#endif + +static struct platform_driver phytium_dmufreq_driver = { + .probe = phytium_dmufreq_probe, + .remove = phytium_dmufreq_remove, + .driver = { + .name = "phytium_dmufreq", + .pm = &phytium_dmufreq_pm, + +#ifdef CONFIG_ACPI + .acpi_match_table = phytium_dmufreq_acpi_ids, +#endif + .suppress_bind_attrs = true, + } +}; +module_platform_driver(phytium_dmufreq_driver); + +MODULE_DESCRIPTION("Phytium DDR Memory Unit frequency driver (v1/v2 unified)"); +MODULE_AUTHOR("Li Mingzhe "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DMUFREQ_DRIVER_VERSION); diff --git a/drivers/devfreq/phytium_noc.c b/drivers/devfreq/phytium_noc.c new file mode 100644 index 0000000000000..e9a60aea0ca4c --- /dev/null +++ b/drivers/devfreq/phytium_noc.c @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: GPL-1.0 +/* + * Phytium Processor NOC Frequency Driver (v1/v2 unified) + * + * Copyright (C) 2024, Phytium Technology Co.,Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NOCFREQ_DRIVER_VERSION "1.1.0" + +enum phytium_noc_type { + PHYTIUM_NOC_V1, + PHYTIUM_NOC_V2, +}; + +struct phytium_nocfreq_info { + enum phytium_noc_type type; + const char *name; +}; + +#define DEVICE_TYPE_V1 7 +#define DEVICE_TYPE_V2 7 + +/* v1 Register definition */ +#define V1_MINI_SIZE 0x400 +#define V1_CNT_ENABLE 0x000 +#define V1_WORK_STATE 0X004 +#define V1_CLR_EN 0X010 +#define V1_SNAPSHOT_EN 0X014 +#define V1_INT_CTRL_CLR 0x024 +#define V1_WR_NOLAST_HANDSHARK_NUM 0x44 + +/* v2 Register definition */ +#define V2_REG_NOC_STATUS 0x0 +#define V2_BUSY_CODE_MASK 0x1f +#define V2_BUSY_CODE_MAX 16 + +/* Fast ramp-up thresholds on each level (busy code out of 16) */ +#define V2_UP_225_TO_450_BUSY 4 +#define V2_UP_450_TO_900_BUSY 8 +#define V2_UP_900_TO_1800_BUSY 12 + +/* Hysteresis hold/down thresholds */ +#define V2_DOWN_450_TO_225_BUSY 2 +#define V2_DOWN_900_TO_450_BUSY 6 +#define V2_DOWN_1800_TO_900_BUSY 10 + +struct phytium_nocfreq { + struct device *dev; + const struct phytium_nocfreq_info *info; + + struct devfreq *devfreq; + struct devfreq_dev_profile profile; + struct devfreq_simple_ondemand_data ondemand_data; + + /* v1 only */ + void __iomem *reg_noc_v1; + + /* v2 only */ + void __iomem *reg_noc_v2; + unsigned int uid; + unsigned int v2_busy_code; + + struct mutex lock; + + unsigned long rate, target_rate, suspend_freq; + unsigned int freq_count; + unsigned long freq_table[]; +}; + +/* v1 Bandwidth acquisition */ +static u32 phytium_nocfreq_get_peak_bw_v1(struct phytium_nocfreq *priv) +{ + unsigned long peak_bw, bw_0, bw_1, bw_2, bw_3; + + bw_0 = readl_relaxed(priv->reg_noc_v1 + V1_WR_NOLAST_HANDSHARK_NUM); + bw_1 = readl_relaxed(priv->reg_noc_v1 + V1_MINI_SIZE*1 + + V1_WR_NOLAST_HANDSHARK_NUM); + bw_2 = readl_relaxed(priv->reg_noc_v1 + V1_MINI_SIZE*2 + + V1_WR_NOLAST_HANDSHARK_NUM); + bw_3 = readl_relaxed(priv->reg_noc_v1 + V1_MINI_SIZE*3 + + V1_WR_NOLAST_HANDSHARK_NUM); + + peak_bw = bw_0; + if (bw_1 > peak_bw) + peak_bw = bw_1; + if (bw_2 > peak_bw) + peak_bw = bw_2; + if (bw_3 > peak_bw) + peak_bw = bw_3; + return peak_bw; +} + +static void phytium_nocfreq_restart_handshark_counters_v1(struct phytium_nocfreq *priv) +{ + writel_relaxed(0x80000000, priv->reg_noc_v1 + V1_INT_CTRL_CLR); + writel_relaxed(0x80000000, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_INT_CTRL_CLR); + writel_relaxed(0x80000000, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_INT_CTRL_CLR); + writel_relaxed(0x80000000, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_INT_CTRL_CLR); + + writel_relaxed(0x1, priv->reg_noc_v1 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_CLR_EN); +} + +/* v2 Bandwidth acquisition */ +static u32 phytium_nocfreq_get_peak_bw_v2(struct phytium_nocfreq *priv) +{ + return readl_relaxed(priv->reg_noc_v2 + V2_REG_NOC_STATUS); +} + +static unsigned long phytium_nocfreq_min_rate(struct phytium_nocfreq *priv) +{ + unsigned long min_rate = priv->freq_table[0]; + int i; + + for (i = 1; i < priv->freq_count; i++) { + if (priv->freq_table[i] < min_rate) + min_rate = priv->freq_table[i]; + } + + return min_rate; +} + +static unsigned long phytium_nocfreq_max_rate(struct phytium_nocfreq *priv) +{ + unsigned long max_rate = priv->freq_table[0]; + int i; + + for (i = 1; i < priv->freq_count; i++) { + if (priv->freq_table[i] > max_rate) + max_rate = priv->freq_table[i]; + } + + return max_rate; +} + +static unsigned long phytium_nocfreq_next_higher_rate(struct phytium_nocfreq *priv, + unsigned long rate) +{ + unsigned long next_rate = ~0UL; + int i; + + for (i = 0; i < priv->freq_count; i++) { + if (priv->freq_table[i] > rate && priv->freq_table[i] < next_rate) + next_rate = priv->freq_table[i]; + } + + if (next_rate == ~0UL) + return rate; + + return next_rate; +} + +/* v1/v2 General frequency setting */ +static int phytium_noc_set_freq(struct device *dev, unsigned long freq) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object args[4]; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_status status; + unsigned long long ret; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE_V1; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = freq; + + if (priv->info->type == PHYTIUM_NOC_V2) { + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = priv->uid; + } else { + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + } + args[3].type = ACPI_TYPE_INTEGER; + args[3].integer.value = 0; + + mutex_lock(&priv->lock); + status = acpi_evaluate_integer(handle, "PSCF", &arg_list, &ret); + mutex_unlock(&priv->lock); + + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PSCF method\n"); + return -EIO; + } + if (ret) { + dev_err(dev, "Failed to set the freq to %lu\n", freq); + return -EIO; + } + dev_dbg(dev, "set target_freq = %lu khz\n", freq); + return 0; +} + +static int phytium_noc_target(struct device *dev, unsigned long *freq, u32 flags) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + unsigned long old_freq = priv->rate; + unsigned long target_rate; + struct dev_pm_opp *opp; + int ret; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + target_rate = dev_pm_opp_get_freq(opp); + dev_pm_opp_put(opp); + + if (priv->info->type == PHYTIUM_NOC_V2) { + unsigned long low = phytium_nocfreq_min_rate(priv); + unsigned long mid1 = phytium_nocfreq_next_higher_rate(priv, low); + unsigned long mid2 = phytium_nocfreq_next_higher_rate(priv, mid1); + unsigned long high = phytium_nocfreq_max_rate(priv); + + if (old_freq == low) { + if (priv->v2_busy_code >= V2_UP_225_TO_450_BUSY && mid1 > low && + target_rate < mid1) + target_rate = mid1; + } else if (old_freq == mid1) { + if (priv->v2_busy_code >= V2_UP_450_TO_900_BUSY && mid2 > mid1 && + target_rate < mid2) + target_rate = mid2; + else if (priv->v2_busy_code > V2_DOWN_450_TO_225_BUSY && + priv->v2_busy_code < V2_UP_450_TO_900_BUSY) + target_rate = mid1; + } else if (old_freq == mid2) { + if (priv->v2_busy_code >= V2_UP_900_TO_1800_BUSY && high > mid2 && + target_rate < high) + target_rate = high; + else if (priv->v2_busy_code > V2_DOWN_900_TO_450_BUSY && + priv->v2_busy_code < V2_UP_900_TO_1800_BUSY) + target_rate = mid2; + } else if (old_freq == high) { + if (priv->v2_busy_code > V2_DOWN_1800_TO_900_BUSY) + target_rate = high; + } + } + + if (target_rate == old_freq) + return 0; + + ret = phytium_noc_set_freq(dev, target_rate); + if (ret) { + dev_warn(dev, "failed to set noc frequency: %d\n", ret); + *freq = old_freq; + } + priv->rate = target_rate; + return ret; +} + +static int phytium_noc_get_cur_freq(struct device *dev, unsigned long *freq) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object args[3]; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_status status; + unsigned long long ret; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE_V1; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + mutex_lock(&priv->lock); + status = acpi_evaluate_integer(handle, "PGCF", &arg_list, &ret); + mutex_unlock(&priv->lock); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCF method\n"); + return -EIO; + } + if (ret < 0) { + dev_err(dev, "Failed to get the freq\n"); + return -EIO; + } + *freq = ret; + return 0; +} + +static int phytium_noc_get_freq_info(struct device *dev, u32 flags) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3], *package, *element; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + int i; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = flags; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + status = acpi_evaluate_object(handle, "PGCL", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCL method\n"); + return -EIO; + } + if (!buffer.length) { + dev_err(dev, "buffer is NULL\n"); + return -EINVAL; + } + + package = buffer.pointer; + element = &package->package.elements[1]; + priv->freq_count = element->integer.value; + + for (i = 0; i < priv->freq_count; i++) { + element = &package->package.elements[i+2]; + priv->freq_table[i] = element->integer.value; + dev_dbg(dev, "freq_table[%d] = %llu\n", i, element->integer.value); + } + kfree(buffer.pointer); + return 0; +} + +static int get_freq_count(struct device *dev) +{ + int freq_count = -1; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3], *package, *element; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE_V1; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + status = acpi_evaluate_object(handle, "PGCL", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCL method\n"); + return -EIO; + } + if (!buffer.length) { + dev_err(dev, "buffer is NULL\n"); + return -EINVAL; + } + + package = buffer.pointer; + element = &package->package.elements[1]; + freq_count = element->integer.value; + dev_dbg(dev, "freq_count = %d\n", freq_count); + kfree(buffer.pointer); + return freq_count; +} + +static int phytium_noc_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + + if (priv->info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x1, priv->reg_noc_v1 + V1_SNAPSHOT_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_SNAPSHOT_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_SNAPSHOT_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_SNAPSHOT_EN); + + stat->busy_time = phytium_nocfreq_get_peak_bw_v1(priv); + stat->total_time = 320000 * DIV_ROUND_CLOSEST(priv->rate * 100, + priv->profile.initial_freq); + stat->current_frequency = priv->rate; + + phytium_nocfreq_restart_handshark_counters_v1(priv); + } else { + u32 raw_busy = phytium_nocfreq_get_peak_bw_v2(priv); + u32 busy_code = raw_busy & V2_BUSY_CODE_MASK; + + if (busy_code > V2_BUSY_CODE_MAX) + busy_code = V2_BUSY_CODE_MAX; + + priv->v2_busy_code = busy_code; + stat->busy_time = busy_code; + stat->total_time = V2_BUSY_CODE_MAX; + stat->current_frequency = priv->rate; + } + return 0; +} + +static __maybe_unused int phytium_nocfreq_suspend(struct device *dev) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + int ret = 0; + + ret = phytium_noc_get_cur_freq(dev, &priv->suspend_freq); + if (ret) + dev_warn(dev, "failed to get suspend freq\n"); + + ret = devfreq_suspend_device(priv->devfreq); + if (ret < 0) + dev_err(dev, "failed to suspend the devfreq devices\n"); + priv->devfreq->stop_polling = true; + + if (priv->info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x0, priv->reg_noc_v1 + V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*1+V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*2+V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*3+V1_CNT_ENABLE); + } + return ret; +} + +static __maybe_unused int phytium_nocfreq_resume(struct device *dev) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + int ret = 0; + + ret = devfreq_resume_device(priv->devfreq); + if (ret < 0) + dev_err(dev, "failed to resume the devfreq devices\n"); + if (!delayed_work_pending(&priv->devfreq->work) && priv->devfreq->profile->polling_ms) + priv->devfreq->stop_polling = true; + + if (priv->info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x02, priv->reg_noc_v1 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_WORK_STATE); + + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*1+V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*2+V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*3+V1_CNT_ENABLE); + } + if (priv->suspend_freq) { + ret = phytium_noc_set_freq(dev, priv->suspend_freq); + if (ret < 0) + dev_warn(dev, "failed to restore suspend freq %lu\n", priv->suspend_freq); + else + priv->rate = priv->suspend_freq; + } + return ret; +} + +static SIMPLE_DEV_PM_OPS(phytium_nocfreq_pm, phytium_nocfreq_suspend, phytium_nocfreq_resume); + +static int phytium_nocfreq_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phytium_nocfreq *priv; + const struct phytium_nocfreq_info *info; + const char *gov = DEVFREQ_GOV_SIMPLE_ONDEMAND; + int i, ret; + unsigned int max_state; + struct resource *mem; + + info = device_get_match_data(dev); + if (!info) { + dev_err(dev, "No match data for this device\n"); + return -ENODEV; + } + + max_state = get_freq_count(dev); + if (max_state <= 0) + return -EINVAL; + priv = devm_kzalloc(dev, struct_size(priv, freq_table, max_state), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->info = info; + mutex_init(&priv->lock); + + platform_set_drvdata(pdev, priv); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(dev, "no mem resource"); + return -EINVAL; + } + + if (info->type == PHYTIUM_NOC_V1) { + priv->reg_noc_v1 = devm_ioremap_resource(dev, mem); + if (!priv->reg_noc_v1) + return PTR_ERR(priv->reg_noc_v1); + dev->init_name = "nocfreq"; + } else { + acpi_handle handle = ACPI_HANDLE(dev); + unsigned long long uid; + + ret = acpi_evaluate_integer(handle, "_UID", NULL, &uid); + priv->uid = uid; + priv->reg_noc_v2 = devm_ioremap_resource(dev, mem); + if (IS_ERR(priv->reg_noc_v2)) + return PTR_ERR(priv->reg_noc_v2); + dev_set_name(dev, "noc-%u", priv->uid); + } + + ret = phytium_noc_get_freq_info(dev, DEVICE_TYPE_V1); + if (ret) + return ret; + priv->profile.initial_freq = priv->freq_table[0]; + priv->profile.polling_ms = 100; + priv->profile.target = phytium_noc_target; + priv->profile.get_cur_freq = phytium_noc_get_cur_freq; + priv->profile.get_dev_status = phytium_noc_get_dev_status; + priv->profile.freq_table = priv->freq_table; + priv->profile.max_state = priv->freq_count; + priv->rate = priv->freq_table[0]; + + if (info->type == PHYTIUM_NOC_V1) { + priv->ondemand_data.upthreshold = 80; + priv->ondemand_data.downdifferential = 10; + } else { + priv->ondemand_data.upthreshold = 80; + priv->ondemand_data.downdifferential = 10; + } + + for (i = 0; i < max_state; ++i) { + ret = dev_pm_opp_add(dev, priv->freq_table[i], 0); + if (ret < 0) + goto err; + } + priv->devfreq = devm_devfreq_add_device(dev, &priv->profile, gov, &priv->ondemand_data); + if (IS_ERR(priv->devfreq)) { + ret = PTR_ERR(priv->devfreq); + goto err; + } + ret = phytium_noc_set_freq(dev, priv->profile.initial_freq); + if (ret) + dev_warn(dev, "failed to init noc frequency: %d\n", ret); + + if (info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x02, priv->reg_noc_v1 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_WORK_STATE); + + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_CNT_ENABLE); + } + return 0; +err: + dev_pm_opp_of_remove_table(dev); + return ret; +} + +static int phytium_nocfreq_remove(struct platform_device *pdev) +{ + struct phytium_nocfreq *priv = platform_get_drvdata(pdev); + unsigned long initial_freq = priv->profile.initial_freq; + struct device *dev = &pdev->dev; + int ret; + + if (priv->info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x0, priv->reg_noc_v1 + V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_CNT_ENABLE); + + writel_relaxed(0x1, priv->reg_noc_v1 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_CLR_EN); + } + + ret = phytium_noc_set_freq(dev, initial_freq); + if (ret) + dev_warn(dev, "failed to restore NOC frequency: %d\n", ret); + + if (!priv->devfreq) + return 0; + dev_pm_opp_remove_all_dynamic(dev); + return 0; +} + +/* Matching Type Table */ +static const struct phytium_nocfreq_info phytium_noc_v1_info = { + .type = PHYTIUM_NOC_V1, + .name = "phytium_noc_v1", +}; +static const struct phytium_nocfreq_info phytium_noc_v2_info = { + .type = PHYTIUM_NOC_V2, + .name = "phytium_noc_v2", +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id phytium_noc_acpi_ids[] = { + { "PHYT0047", (kernel_ulong_t)&phytium_noc_v1_info }, + { "PHYT3010", (kernel_ulong_t)&phytium_noc_v2_info }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, phytium_noc_acpi_ids); +#endif + +static struct platform_driver phytium_nocfreq_driver = { + .probe = phytium_nocfreq_probe, + .remove = phytium_nocfreq_remove, + .driver = { + .name = "phytium_nocfreq", + .pm = &phytium_nocfreq_pm, +#ifdef CONFIG_ACPI + .acpi_match_table = phytium_noc_acpi_ids, +#endif + .suppress_bind_attrs = true, + }, +}; +module_platform_driver(phytium_nocfreq_driver); + +MODULE_DESCRIPTION("Phytium NOC Controller frequency driver (v1/v2 unified)"); +MODULE_AUTHOR("Li Mingzhe "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(NOCFREQ_DRIVER_VERSION); diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 511309542d245..5d31b602ef42c 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -547,12 +547,17 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", pfx, pcie->bridge.secondary_status, pcie->bridge.control); - /* Fatal errors call __ghes_panic() before AER handler prints this */ - if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) && - (gdata->error_severity & CPER_SEV_FATAL)) { + /* + * Print all valid AER info. Record may be from BERT (boot-time) or GHES (run-time). + * + * Fatal errors call __ghes_panic() before AER handler prints this. + */ + if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) { struct aer_capability_regs *aer; aer = (struct aer_capability_regs *)pcie->aer_info; + printk("%saer_cor_status: 0x%08x, aer_cor_mask: 0x%08x\n", + pfx, aer->cor_status, aer->cor_mask); printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n", pfx, aer->uncor_status, aer->uncor_mask); printk("%saer_uncor_severity: 0x%08x\n", diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 4d4757eac9e5f..4841766ca8b68 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1173,6 +1173,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, unsigned int pin = agpio->pin_table[i]; struct acpi_gpio_connection *conn; struct gpio_desc *desc; + u16 word, shift; bool found; mutex_lock(&achip->conn_lock); @@ -1227,10 +1228,22 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, mutex_unlock(&achip->conn_lock); - if (function == ACPI_WRITE) - gpiod_set_raw_value_cansleep(desc, !!(*value & BIT_ULL(i))); - else - *value |= (u64)gpiod_get_raw_value_cansleep(desc) << i; + /* + * For the cases when OperationRegion() consists of more than + * 64 bits calculate the word and bit shift to use that one to + * access the value. + */ + word = i / 64; + shift = i % 64; + + if (function == ACPI_WRITE) { + gpiod_set_raw_value_cansleep(desc, value[word] & BIT_ULL(shift)); + } else { + if (gpiod_get_raw_value_cansleep(desc)) + value[word] |= BIT_ULL(shift); + else + value[word] &= ~BIT_ULL(shift); + } } out: diff --git a/drivers/hwmon/zhaoxin-cputemp.c b/drivers/hwmon/zhaoxin-cputemp.c index 8286665f2c55d..9eca3a3efaa19 100644 --- a/drivers/hwmon/zhaoxin-cputemp.c +++ b/drivers/hwmon/zhaoxin-cputemp.c @@ -122,7 +122,7 @@ static int zhaoxin_cputemp_probe(struct platform_device *pdev) data->id = pdev->id; data->name = "zhaoxin_cputemp"; data->msr_temp = 0x1423; - if (c->x86_model == 0x6b || c->x86_model == 0x7b) { + if (c->x86_model == 0x6b || c->x86_model == 0x7b || c->x86_model == 0x8b) { data->msr_crit = 0x175b; data->msr_max = 0x175a; } else { @@ -265,6 +265,8 @@ static const struct x86_cpu_id __initconst cputemp_ids[] = { X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, 0x6b, NULL), X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, 0x7b, NULL), X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, 0x7b, NULL), + X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, 0x8b, NULL), + X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, 0x8b, NULL), {} }; MODULE_DEVICE_TABLE(x86cpu, cputemp_ids); diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig index 398259dd942f2..e0ce86d257ec3 100644 --- a/drivers/pci/controller/Kconfig +++ b/drivers/pci/controller/Kconfig @@ -217,6 +217,7 @@ config PCIE_MT7621 config PCIE_PHYTIUM_EP tristate "Phytium PCIe endpoint controller" + depends on ARCH_PHYTIUM depends on OF depends on PCI_ENDPOINT help diff --git a/drivers/pci/controller/pcie-phytium-ep.c b/drivers/pci/controller/pcie-phytium-ep.c index 7a9d6a4ab39cd..a00d8cd9db0d9 100644 --- a/drivers/pci/controller/pcie-phytium-ep.c +++ b/drivers/pci/controller/pcie-phytium-ep.c @@ -19,17 +19,23 @@ #include "pcie-phytium-ep.h" #include "pcie-phytium-register.h" -#define PHYTIUM_PCIE_RP_DRIVER_VERSION "1.1.1" +#define PHYTIUM_PCIE_EP_DRIVER_VERSION "1.1.1" #define PHYTIUM_PCIE_EP_IRQ_PCI_ADDR_NONE 0x0 #define PHYTIUM_PCIE_EP_IRQ_PCI_ADDR_LEGACY 0x1 +#define PHYTIUM_PCIE_EP_ADDR_LO_MASK 0xffffffff +#define PHYTIUM_PCIE_EP_DMA_CONTROL_VALUE 0x18017e1 +#define PHYTIUM_PCIE_EP_PCIE_INTERFACE_ID 0x0 +#define PHYTIUM_PCIE_EP_AXI_MASTER_INTERFACE_ID 0x4 +#define PHYTIUM_PCIE_EP_DMA_SHARE_ACCESS 0x3 + static int phytium_pcie_ep_write_header(struct pci_epc *epc, unsigned char fn, u8 vfn, struct pci_epf_header *hdr) { struct phytium_pcie_ep *priv = epc_get_drvdata(epc); u16 tmp = 0; - + fn++; phytium_pcie_writew(priv, fn, PHYTIUM_PCI_VENDOR_ID, hdr->vendorid); phytium_pcie_writew(priv, fn, PHYTIUM_PCI_DEVICE_ID, hdr->deviceid); phytium_pcie_writeb(priv, fn, PHYTIUM_PCI_REVISION_ID, hdr->revid); @@ -53,71 +59,75 @@ static int phytium_pcie_ep_write_header(struct pci_epc *epc, unsigned char fn, u } static int phytium_pcie_ep_set_bar(struct pci_epc *epc, u8 fn, u8 vfn, - struct pci_epf_bar *epf_bar) + struct pci_epf_bar *epf_bar) { struct phytium_pcie_ep *priv = epc_get_drvdata(epc); - u64 sz = 0, sz_mask, atr_size; + u64 base, sz_mask, atr_size, sz = 0; int flags = epf_bar->flags; - u32 setting, src_addr0, src_addr1, trsl_addr0, trsl_addr1, trsl_param; enum pci_barno barno = epf_bar->barno; struct pci_epc_mem *mem = epc->mem; + u32 setting, src_addr0, trsl_param; + fn++; if ((flags & PCI_BASE_ADDRESS_MEM_TYPE_64) && (barno & 1)) { dev_err(&epc->dev, "bar %d do not support mem64\n", barno); return -EINVAL; } - if (barno & 1) { - dev_err(&epc->dev, "not support bar 1/3/5\n"); - return -EINVAL; - } - dev_dbg(epc->dev.parent, "set bar%d mapping address 0x%pa size 0x%lx\n", + if (barno == 0 || barno == 3 || barno == 5) + return 0; + + dev_dbg(&epc->dev, "set bar%d mapping address 0x%pa size 0x%zx\n", barno, &(epf_bar->phys_addr), epf_bar->size); if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { setting = BAR_IO_TYPE; - sz = max_t(size_t, epf_bar->size, BAR_IO_MIN_APERTURE); - sz = 1 << fls64(sz - 1); - sz_mask = ~(sz - 1); + sz_mask = ~(epf_bar->size / 2 - 1); setting |= sz_mask; trsl_param = TRSL_ID_IO; } else { setting = BAR_MEM_TYPE; - sz = max_t(size_t, epf_bar->size, BAR_MEM_MIN_APERTURE); - sz = 1 << fls64(sz - 1); - sz_mask = ~(sz - 1); - setting |= lower_32_bits(sz_mask); if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) setting |= BAR_MEM_64BIT; if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) setting |= BAR_MEM_PREFETCHABLE; - + sz_mask = ~(epf_bar->size / 2 - 1); + setting |= lower_32_bits(sz_mask); trsl_param = TRSL_ID_MASTER; } + sz = max_t(size_t, epf_bar->size / 2, BAR_MEM_MIN_APERTURE); + sz = 1 << fls64(sz - 1); + sz = ALIGN(sz, mem->window.page_size); + atr_size = fls64(sz - 1) - 1; + + base = 0xE00 + fn * 0x40 + (barno - 1) * 0x8; + phytium_hpb_writel(priv, base, upper_32_bits(epf_bar->phys_addr)); + phytium_hpb_writel(priv, (base + 0x4), (lower_32_bits(epf_bar->phys_addr) | (atr_size))); + phytium_pcie_writel(priv, fn, PHYTIUM_PCI_BAR(barno), setting); if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) - phytium_pcie_writel(priv, fn, PHYTIUM_PCI_BAR(barno + 1), + phytium_pcie_writel(priv, fn, PHYTIUM_PCI_BAR((barno + 1)), upper_32_bits(sz_mask)); - dev_dbg(epc->dev.parent, "set bar%d mapping address 0x%pa size 0x%llx 0x%x\n", - barno, &(epf_bar->phys_addr), sz, lower_32_bits(epf_bar->phys_addr)); - sz = ALIGN(sz, mem->window.page_size); - atr_size = fls64(sz - 1) - 1; + + if (barno == 2) { + phytium_pcie_writel(priv, fn, PHYTIUM_PCI_BAR((barno + 1)), 0); + return 0; + } src_addr0 = ATR_IMPL | ((atr_size & ATR_SIZE_MASK) << ATR_SIZE_SHIFT); - src_addr1 = 0; - trsl_addr0 = (lower_32_bits(epf_bar->phys_addr) & TRSL_ADDR_32_12_MASK); - trsl_addr1 = upper_32_bits(epf_bar->phys_addr); phytium_pcie_writel(priv, fn, PHYTIUM_PCI_WIN0_SRC_ADDR0(barno), src_addr0); phytium_pcie_writel(priv, fn, PHYTIUM_PCI_WIN0_SRC_ADDR1(barno), - src_addr1); + 0x0); + phytium_pcie_writel(priv, fn, PHYTIUM_PCI_WIN0_TRSL_ADDR0(barno), - trsl_addr0); + (barno == 1) ? lower_32_bits(epf_bar->phys_addr) : 0); phytium_pcie_writel(priv, fn, PHYTIUM_PCI_WIN0_TRSL_ADDR1(barno), - trsl_addr1); + (barno == 1) ? upper_32_bits(epf_bar->phys_addr) : barno << 10); + phytium_pcie_writel(priv, fn, PHYTIUM_PCI_WIN0_TRSL_PARAM(barno), trsl_param); @@ -130,7 +140,7 @@ static void phytium_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn, struct phytium_pcie_ep *priv = epc_get_drvdata(epc); int flags = epf_bar->flags; enum pci_barno barno = epf_bar->barno; - + fn++; phytium_pcie_writel(priv, fn, PHYTIUM_PCI_BAR(barno), 0); if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) phytium_pcie_writel(priv, fn, PHYTIUM_PCI_BAR(barno + 1), 0); @@ -151,7 +161,7 @@ static int phytium_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn, u64 sz = 0; u32 r; struct pci_epc_mem *mem = epc->mem; - + fn++; r = find_first_zero_bit(&priv->ob_region_map, sizeof(priv->ob_region_map) * BITS_PER_LONG); if (r >= priv->max_regions) { @@ -192,7 +202,7 @@ static void phytium_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn, { struct phytium_pcie_ep *priv = epc_get_drvdata(epc); u32 r; - + fn++; for (r = 0; r < priv->max_regions; r++) if (priv->ob_addr[r] == addr) break; @@ -216,7 +226,7 @@ static int phytium_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 vfn, u8 mmc) { struct phytium_pcie_ep *priv = epc_get_drvdata(epc); u16 flags = 0; - + fn++; flags = (mmc & MSI_NUM_MASK) << MSI_NUM_SHIFT; flags &= ~MSI_MASK_SUPPORT; phytium_pcie_writew(priv, fn, PHYTIUM_PCI_INTERRUPT_PIN, flags); @@ -229,7 +239,7 @@ static int phytium_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn) struct phytium_pcie_ep *priv = epc_get_drvdata(epc); u16 flags, mme; u32 cap = PHYTIUM_PCI_CF_MSI_BASE; - + fn++; flags = phytium_pcie_readw(priv, fn, cap + PCI_MSI_FLAGS); if (!(flags & PCI_MSI_FLAGS_ENABLE)) return -EINVAL; @@ -247,7 +257,7 @@ static int phytium_pcie_ep_send_msi_irq(struct phytium_pcie_ep *priv, u8 fn, u8 msi_count; u64 pci_addr, pci_addr_mask = IRQ_MAPPING_SIZE - 1; u32 src_addr0, src_addr1, trsl_addr0, trsl_addr1, trsl_param, atr_size; - + fn++; flags = phytium_pcie_readw(priv, fn, cap + PCI_MSI_FLAGS); if (!(flags & PCI_MSI_FLAGS_ENABLE)) return -EINVAL; @@ -302,7 +312,7 @@ static int phytium_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn, u16 interrupt_num) { struct phytium_pcie_ep *priv = epc_get_drvdata(epc); - + fn++; switch (type) { case PCI_EPC_IRQ_MSI: return phytium_pcie_ep_send_msi_irq(priv, fn, interrupt_num); @@ -326,6 +336,68 @@ static int phytium_pcie_ep_start(struct pci_epc *epc) return 0; } +static int phytium_pcie_ep_start_dma(struct pci_epc *epc, u8 func_no, u64 cpu_addr, u64 pci_addr, + size_t size, u8 mode) +{ + u32 value; + struct phytium_pcie_ep *priv = epc_get_drvdata(epc); + + func_no++; + dev_dbg(&epc->dev, "%s func_no %d cpu_addr %llu pci_addr %llu size %zu mode %d\n", + __func__, func_no, cpu_addr, pci_addr, size, mode); + + u64 base = 0xE00 + func_no * 0x40; + + phytium_hpb_writel(priv, base, upper_32_bits(cpu_addr)); + phytium_hpb_writel(priv, (base + 0x4), + (lower_32_bits(cpu_addr) & (~0x3f)) | (fls64(size - 1))); + cpu_addr = 0x40000000000 | (cpu_addr & 0x3f); + + phytium_pcie_writel(priv, func_no, DMA_SHARE_ACCESS(mode), + PHYTIUM_PCIE_EP_DMA_SHARE_ACCESS); + if (mode == DMA_READ_ENGINE) { + phytium_pcie_writel(priv, func_no, DMA_SRCPARAM(mode), + PHYTIUM_PCIE_EP_PCIE_INTERFACE_ID); + phytium_pcie_writel(priv, func_no, DMA_DSTPARAM(mode), + PHYTIUM_PCIE_EP_AXI_MASTER_INTERFACE_ID); + value = pci_addr & PHYTIUM_PCIE_EP_ADDR_LO_MASK; + phytium_pcie_writel(priv, func_no, DMA_SRCADDR_LO(mode), value); + value = (pci_addr >> 32); + phytium_pcie_writel(priv, func_no, DMA_SRCADDR_UP(mode), value); + + value = cpu_addr & PHYTIUM_PCIE_EP_ADDR_LO_MASK; + phytium_pcie_writel(priv, func_no, DMA_DESTADDR_LO(mode), value); + value = ((cpu_addr >> 32) | 0x400); + phytium_pcie_writel(priv, func_no, DMA_DESTADDR_UP(mode), value); + } else { + phytium_pcie_writel(priv, func_no, DMA_SRCPARAM(mode), + PHYTIUM_PCIE_EP_AXI_MASTER_INTERFACE_ID); + phytium_pcie_writel(priv, func_no, DMA_DSTPARAM(mode), + PHYTIUM_PCIE_EP_PCIE_INTERFACE_ID); + value = cpu_addr & PHYTIUM_PCIE_EP_ADDR_LO_MASK; + phytium_pcie_writel(priv, func_no, DMA_SRCADDR_LO(mode), value); + value = ((cpu_addr >> 32) | 0x400); + phytium_pcie_writel(priv, func_no, DMA_SRCADDR_UP(mode), value); + + value = pci_addr & PHYTIUM_PCIE_EP_ADDR_LO_MASK; + phytium_pcie_writel(priv, func_no, DMA_DESTADDR_LO(mode), value); + value = (pci_addr >> 32); + phytium_pcie_writel(priv, func_no, DMA_DESTADDR_UP(mode), value); + } + phytium_pcie_writel(priv, func_no, DMA_LENGTH(mode), size); + phytium_pcie_writel(priv, func_no, DMA_CONTROL(mode), PHYTIUM_PCIE_EP_DMA_CONTROL_VALUE); + + return 0; +} + +static int phytium_pcie_ep_dma_status(struct pci_epc *epc, u8 func_no, u8 mode) +{ + struct phytium_pcie_ep *priv = epc_get_drvdata(epc); + + func_no++; + return phytium_pcie_readl(priv, func_no, DMA_STATUS(mode)); +} + static const struct pci_epc_ops phytium_pcie_epc_ops = { .write_header = phytium_pcie_ep_write_header, .set_bar = phytium_pcie_ep_set_bar, @@ -336,10 +408,10 @@ static const struct pci_epc_ops phytium_pcie_epc_ops = { .get_msi = phytium_pcie_ep_get_msi, .raise_irq = phytium_pcie_ep_raise_irq, .start = phytium_pcie_ep_start, + .start_dma = phytium_pcie_ep_start_dma, + .dma_status = phytium_pcie_ep_dma_status, }; - - static int phytium_pcie_ep_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -348,11 +420,33 @@ static int phytium_pcie_ep_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct pci_epc *epc; int ret = 0, value; + const char *compatible; + u32 hpb_c0_pref_base_limit; + u32 hpb_c0_pref_base_limit_up32; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + compatible = of_get_property(np, "compatible", NULL); + if (!compatible) { + dev_err(dev, "Compatible property not found\n"); + return -EINVAL; + } + + if (strcmp(compatible, "phytium,pd2008-pcie-ep") == 0) { + hpb_c0_pref_base_limit = PHYTIUM_PD2008_HPB_C0_PREF_BASE_LIMIT; + hpb_c0_pref_base_limit_up32 = + PHYTIUM_PD2008_HPB_C0_PREF_BASE_LIMIT_UP32; + } else if (strcmp(compatible, "phytium,pe2201-pcie-ep") == 0) { + hpb_c0_pref_base_limit = PHYTIUM_PE2201_HPB_C0_PREF_BASE_LIMIT; + hpb_c0_pref_base_limit_up32 = + PHYTIUM_PE2201_HPB_C0_PREF_BASE_LIMIT_UP32; + } else { + dev_err(dev, "Unsupported chip model\n"); + return -ENODEV; + } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); priv->reg_base = devm_ioremap_resource(dev, res); if (IS_ERR(priv->reg_base)) { @@ -397,6 +491,8 @@ static int phytium_pcie_ep_probe(struct platform_device *pdev) priv->epc = epc; epc_set_drvdata(epc, priv); + priv->pdev = pdev; + if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0) epc->max_functions = 1; dev_info(dev, "%s epc->max_functions %d\n", __func__, epc->max_functions); @@ -424,13 +520,13 @@ static int phytium_pcie_ep_probe(struct platform_device *pdev) & C0_PREF_BASE_MASK) << C0_PREF_BASE_SHIFT; value |= (((lower_32_bits(priv->mem_res->end) >> C0_PREF_VALUE_SHIFT) & C0_PREF_LIMIT_MASK) << C0_PREF_LIMIT_SHIFT); - phytium_hpb_writel(priv, PHYTIUM_HPB_C0_PREF_BASE_LIMIT, value); + phytium_hpb_writel(priv, hpb_c0_pref_base_limit, value); value = ((upper_32_bits(priv->mem_res->start) >> C0_PREF_UP32_VALUE_SHIFT) & C0_PREF_BASE_UP32_MASK) << C0_PREF_BASE_UP32_SHIFT; value |= (((upper_32_bits(priv->mem_res->end) >> C0_PREF_UP32_VALUE_SHIFT) & C0_PREF_LIMIT_UP32_MASK) << C0_PREF_LIMIT_UP32_SHIFT); - phytium_hpb_writel(priv, PHYTIUM_HPB_C0_PREF_BASE_LIMIT_UP32, value); + phytium_hpb_writel(priv, hpb_c0_pref_base_limit_up32, value); dev_dbg(dev, "exit %s successful\n", __func__); return 0; @@ -453,6 +549,7 @@ static int phytium_pcie_ep_remove(struct platform_device *pdev) static const struct of_device_id phytium_pcie_ep_of_match[] = { { .compatible = "phytium,pd2008-pcie-ep" }, + { .compatible = "phytium,pe2201-pcie-ep" }, { }, }; @@ -468,6 +565,6 @@ MODULE_DEVICE_TABLE(of, phytium_pcie_ep_of_match); module_platform_driver(phytium_pcie_ep_driver); MODULE_LICENSE("GPL"); -MODULE_VERSION(PHYTIUM_PCIE_RP_DRIVER_VERSION); +MODULE_VERSION(PHYTIUM_PCIE_EP_DRIVER_VERSION); MODULE_AUTHOR("Yang Xun "); MODULE_DESCRIPTION("Phytium PCIe Controller Endpoint driver"); diff --git a/drivers/pci/controller/pcie-phytium-ep.h b/drivers/pci/controller/pcie-phytium-ep.h index 1c38181fc19d9..bb5f67b57c086 100644 --- a/drivers/pci/controller/pcie-phytium-ep.h +++ b/drivers/pci/controller/pcie-phytium-ep.h @@ -23,6 +23,8 @@ struct phytium_pcie_ep { unsigned long irq_pci_addr; u8 irq_pci_fn; struct pci_epc *epc; + + struct platform_device *pdev; }; static inline void diff --git a/drivers/pci/controller/pcie-phytium-register.h b/drivers/pci/controller/pcie-phytium-register.h index 458df0014504e..5f98a93e4b8ab 100644 --- a/drivers/pci/controller/pcie-phytium-register.h +++ b/drivers/pci/controller/pcie-phytium-register.h @@ -63,13 +63,16 @@ #define PHYTIUM_PCI_CF_MSI_BASE 0x10e0 #define PHYTIUM_PCI_CF_MSI_CONTROL 0x10e2 -#define PHYTIUM_HPB_C0_PREF_BASE_LIMIT 0xa30 +#define PHYTIUM_PD2008_HPB_C0_PREF_BASE_LIMIT 0xa30 +#define PHYTIUM_PE2201_HPB_C0_PREF_BASE_LIMIT 0xa40 #define C0_PREF_LIMIT_MASK 0xfff #define C0_PREF_LIMIT_SHIFT 20 #define C0_PREF_BASE_MASK 0xfff #define C0_PREF_BASE_SHIFT 4 #define C0_PREF_VALUE_SHIFT 20 #define PHYTIUM_HPB_C0_PREF_BASE_LIMIT_UP32 0xa34 +#define PHYTIUM_PD2008_HPB_C0_PREF_BASE_LIMIT_UP32 0xa34 +#define PHYTIUM_PE2201_HPB_C0_PREF_BASE_LIMIT_UP32 0xa44 #define C0_PREF_LIMIT_UP32_MASK 0xff #define C0_PREF_LIMIT_UP32_SHIFT 8 #define C0_PREF_BASE_UP32_MASK 0xff @@ -77,4 +80,19 @@ #define C0_PREF_UP32_VALUE_SHIFT 0 #endif +#define DMA_READ_ENGINE 0 +#define DMA_WRITE_ENGINE 1 +#define DMA_ENGINE0_BASE 0x400 + +#define DMA_SHARE_ACCESS(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x28) // 0x468 +#define DMA_SRCPARAM(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x0) // 0x440 +#define DMA_DSTPARAM(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x4) // 0x444 +#define DMA_SRCADDR_LO(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x8) // 0x448 +#define DMA_SRCADDR_UP(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0xc) // 0x44C +#define DMA_DESTADDR_LO(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x10) // 0x450 +#define DMA_DESTADDR_UP(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x14) // 0x454 +#define DMA_LENGTH(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x18) // 0x458 +#define DMA_CONTROL(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x1c) // 0x45C +#define DMA_STATUS(engnum) (DMA_ENGINE0_BASE + 0x40 * engnum + 0x20) // 0x460 + diff --git a/drivers/pci/endpoint/pci-ep-cfs.c b/drivers/pci/endpoint/pci-ep-cfs.c index 5b64203f100fc..6d43a640206b3 100644 --- a/drivers/pci/endpoint/pci-ep-cfs.c +++ b/drivers/pci/endpoint/pci-ep-cfs.c @@ -31,6 +31,10 @@ struct pci_epc_group { struct config_group group; struct pci_epc *epc; bool start; + +#ifdef CONFIG_ARCH_PHYTIUM + unsigned long function_num_map; +#endif }; static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item) @@ -204,8 +208,41 @@ static ssize_t pci_epc_start_show(struct config_item *item, char *page) CONFIGFS_ATTR(pci_epc_, start); +#ifdef CONFIG_ARCH_PHYTIUM +static ssize_t pci_epc_function_num_map_store(struct config_item *item, const char *page, + size_t len) +{ + int ret; + unsigned long function_num_map; + struct pci_epc *epc; + struct pci_epc_group *epc_group = to_pci_epc_group(item); + + epc = epc_group->epc; + + ret = kstrtoul(page, 10, &function_num_map); + if (ret) + return ret; + + epc_group->function_num_map = function_num_map; + epc->function_num_map = function_num_map; + + return len; +} + +static ssize_t pci_epc_function_num_map_show(struct config_item *item, char *page) +{ + return sprintf(page, "%ld\n", + to_pci_epc_group(item)->function_num_map); +} + +CONFIGFS_ATTR(pci_epc_, function_num_map); +#endif + static struct configfs_attribute *pci_epc_attrs[] = { &pci_epc_attr_start, +#ifdef CONFIG_ARCH_PHYTIUM + &pci_epc_attr_function_num_map, +#endif NULL, }; diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 3a82c6a613a3c..75bd16507e2cc 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -15,6 +15,9 @@ #include static struct class *pci_epc_class; +#ifdef CONFIG_ARCH_PHYTIUM +static DEFINE_SPINLOCK(epc_dma_lock); +#endif static void devm_pci_epc_release(struct device *dev, void *res) { @@ -206,6 +209,54 @@ int pci_epc_start(struct pci_epc *epc) } EXPORT_SYMBOL_GPL(pci_epc_start); +/** + * pci_epc_start_dma() - start dma with phytium-d2000 ep + * @cpu_addr: ep local mem addr + * @pci_addr: pci doamin addr,which means rc mem addr + * @size: transfer total data size bytes + * @mode: which direct the dma work,EP_TO_RC/RC_TO_EP + */ +#ifdef CONFIG_ARCH_PHYTIUM +int pci_epc_start_dma(struct pci_epc *epc, u8 func_no, u64 cpu_addr, u64 pci_addr, + size_t size, u8 mode) +{ + int ret; + unsigned long flags; + + if (IS_ERR(epc)) + return -EINVAL; + + if (!epc->ops->start_dma) + return 0; + + spin_lock_irqsave(&epc_dma_lock, flags); + ret = epc->ops->start_dma(epc, func_no, cpu_addr, pci_addr, size, mode); + spin_unlock_irqrestore(&epc_dma_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(pci_epc_start_dma); + +int pci_epc_dma_status(struct pci_epc *epc, u8 func_no, u8 mode) +{ + int ret; + unsigned long flags; + + if (IS_ERR(epc)) + return -EINVAL; + + if (!epc->ops->dma_status) + return 0; + + spin_lock_irqsave(&epc_dma_lock, flags); + ret = epc->ops->dma_status(epc, func_no, mode); + spin_unlock_irqrestore(&epc_dma_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(pci_epc_dma_status); +#endif + /** * pci_epc_raise_irq() - interrupt the host system * @epc: the EPC device which has to interrupt the host diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 4b105878aa044..1f3890ded6ad4 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -287,7 +287,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) slot_name(ctrl)); #ifdef CONFIG_ARCH_PHYTIUM if (present && link_active) - phytium_clear_ctrl_prot(ctrl->pcie->port, PHYTIUM_PCIE_HOTPLUG); + phytium_pcie_ctrl_smc_op(ctrl->pcie->port, PHYTIUM_PCIE_HOTPLUG); #endif ctrl->request_result = pciehp_enable_slot(ctrl); break; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index b0bccc4d0da28..4aa22caec02c1 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -26,6 +26,9 @@ #include "../pci.h" #include "pciehp.h" +#ifdef CONFIG_ARCH_PHYTIUM +#include +#endif static const struct dmi_system_id inband_presence_disabled_dmi_table[] = { /* @@ -241,6 +244,18 @@ int pciehp_check_link_active(struct controller *ctrl) if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status)) return -ENODEV; +#ifdef CONFIG_ARCH_PHYTIUM + if (is_ps24080()) { + /* PS24080 sometimes reports link up even when it's down */ + static u16 lnksta; + + lnksta = phytium_pcie_ctrl_smc_op(pdev, PHYTIUM_PCIE_GET_LNKSTA); + if (lnksta >= 0) + lnk_status = (lnk_status & ~PCI_EXP_LNKSTA_DLLLA) | + (lnksta & PCI_EXP_LNKSTA_DLLLA); + } +#endif + ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cd18c4b955882..d0f2f8f0363cd 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -48,6 +48,9 @@ EXPORT_SYMBOL_GPL(pci_power_names); int isa_dma_bridge_buggy; EXPORT_SYMBOL(isa_dma_bridge_buggy); #endif +#ifdef CONFIG_ARCH_PHYTIUM +#include +#endif int pci_pci_problems; EXPORT_SYMBOL(pci_pci_problems); @@ -5340,7 +5343,7 @@ void pci_reset_secondary_bus(struct pci_dev *dev) pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); #ifdef CONFIG_ARCH_PHYTIUM - phytium_clear_ctrl_prot(dev, PHYTIUM_PCIE_HOTRESET); + phytium_pcie_ctrl_smc_op(dev, PHYTIUM_PCIE_HOTRESET); #endif } @@ -5349,6 +5352,55 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev) pci_reset_secondary_bus(dev); } +#ifdef CONFIG_ARCH_PHYTIUM +/** + * phytium_pci_bridge_secondary_bus_reset - Reset the secondary bus + * on Phytium bridges. + * @dev: Bridge device + * + * Workaround: Perform a PCIe secondary-bus reset again when + * the link is degraded on the Phytium platform. + */ +static int phytium_pci_bridge_secondary_bus_reset(struct pci_dev *dev) +{ + u16 lnksta, reset_cnt = 0; + u16 cur_speed, cur_width; + u16 next_speed, next_width; + int ret; + + pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); + cur_speed = lnksta & PCI_EXP_LNKSTA_CLS; + cur_width = (lnksta & PCI_EXP_LNKSTA_NLW) >> + PCI_EXP_LNKSTA_NLW_SHIFT; + +retry: + reset_cnt++; + pcibios_reset_secondary_bus(dev); + ret = pci_bridge_wait_for_secondary_bus(dev, "bus reset"); + + pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); + next_speed = lnksta & PCI_EXP_LNKSTA_CLS; + next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >> + PCI_EXP_LNKSTA_NLW_SHIFT; + + /* if link degraded, allow one more retry */ + if ((next_speed < cur_speed) || (next_width < cur_width)) { + if (reset_cnt >= 2) { + pci_err(dev, "phytium: link degraded - pre Gen%u/x%u post Gen%u/x%u\n", + cur_speed, cur_width, next_speed, next_width); + goto out; + } + + pci_info(dev, "phytium: link degraded - pre Gen%u/x%u post Gen%u/x%u, reset again\n", + cur_speed, cur_width, next_speed, next_width); + goto retry; + } + +out: + return ret; +} +#endif + /** * pci_bridge_secondary_bus_reset - Reset the secondary bus on a PCI bridge. * @dev: Bridge device @@ -5358,6 +5410,19 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev) */ int pci_bridge_secondary_bus_reset(struct pci_dev *dev) { +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pd2308()) { + int ret = 0; + + pci_save_state(dev); + pcibios_reset_secondary_bus(dev); + ret = pci_bridge_wait_for_secondary_bus(dev, "bus reset"); + pci_restore_state(dev); + return ret; + } else if (is_ps24080()) { + return phytium_pci_bridge_secondary_bus_reset(dev); + } +#endif pcibios_reset_secondary_bus(dev); return pci_bridge_wait_for_secondary_bus(dev, "bus reset"); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8033f9056a801..c3d912cb71c01 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -877,40 +877,72 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev) #define PHYTIUM_PCIE_HOTRESET 0 #define PHYTIUM_PCIE_HOTPLUG 1 -#define PHYTIUM_PCI_VENDOR_ID 0x1DB7 +#define PHYTIUM_PCIE_GET_LNKSTA 2 #define PHYTIUM_PCI_CTRL_ID 0x0100 -#define PHYTIUM_PCIE_CLEAR_CTRL_PROT_SMC_FUNC_ID 0xC2000020 - -static inline void phytium_clear_ctrl_prot(struct pci_dev *pdev, int op) -{ - int socket; - u8 bus = pdev->bus->number; - u8 device = PCI_SLOT(pdev->devfn); - u8 function = PCI_FUNC(pdev->devfn); - u16 vendor_id = pdev->vendor; - u16 device_id = pdev->device; - struct arm_smccc_res res; - u32 arg; - - if (vendor_id != PHYTIUM_PCI_VENDOR_ID || - device_id != PHYTIUM_PCI_CTRL_ID || - pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) - return; - - socket = dev_to_node(&pdev->dev); - if (socket < 0) { - pci_err(pdev, "Cannot find socket, stop clean pcie protection\n"); - return; - } - - arg = (socket << 16) | (bus << 8) | (device << 3) | function; - arm_smccc_smc(PHYTIUM_PCIE_CLEAR_CTRL_PROT_SMC_FUNC_ID, arg, op, 0, 0, 0, 0, 0, &res); - if (res.a0 != 0) - pci_err(pdev, "Error: Firmware call PCIE protection clear Failed: %d, sbdf: 0x%x\n", - (int)res.a0, arg); - else - pci_info(pdev, "%s : Clear pcie protection successfully\n", - op ? "HotPlug" : "HotReset"); +#define PHYTIUM_PCIE_CTRL_SMC_FUNC_ID 0xC2000020 + +#define PHYTIUM_PCIE_LINKUP 3 +#define PHYTIUM_PCIE_LINKDOWN 0 + +static inline int phytium_pcie_ctrl_smc_op(struct pci_dev *pdev, int op) +{ + int socket; + u8 bus = pdev->bus->number; + u8 device = PCI_SLOT(pdev->devfn); + u8 function = PCI_FUNC(pdev->devfn); + u16 vendor_id = pdev->vendor; + u16 device_id = pdev->device; + struct arm_smccc_res res; + const char *op_str; + u16 link_status = 0; + u32 arg; + + switch (op) { + case PHYTIUM_PCIE_HOTRESET: + op_str = "hotreset"; + break; + case PHYTIUM_PCIE_HOTPLUG: + op_str = "hotplug"; + break; + case PHYTIUM_PCIE_GET_LNKSTA: + op_str = "get-link-status"; + break; + default: + op_str = "unknown"; + break; + } + + if (vendor_id != PCI_VENDOR_ID_PHYTIUM || + device_id != PHYTIUM_PCI_CTRL_ID || + pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) + return -ENOENT; + + socket = dev_to_node(&pdev->dev); + if (socket < 0) { + pci_err(pdev, "no socket found, stop calling SMC 0x%x (%s)\n", + PHYTIUM_PCIE_CTRL_SMC_FUNC_ID, op_str); + return -ENOENT; + } + + arg = (socket << 16) | (bus << 8) | (device << 3) | function; + arm_smccc_smc(PHYTIUM_PCIE_CTRL_SMC_FUNC_ID, arg, op, 0, 0, 0, 0, 0, &res); + if (res.a0 != 0) { + pci_err(pdev, "Error: %s call SMC 0x%x failed (%d), sbdf: 0x%x\n", + op_str, PHYTIUM_PCIE_CTRL_SMC_FUNC_ID, + (int)res.a0, arg); + return -ENOENT; + } + pci_info(pdev, "%s: call SMC completed successfully\n", op_str); + + /* Update link_status bit if op == get-link-status */ + if (op == PHYTIUM_PCIE_GET_LNKSTA) { + if (res.a1 == PHYTIUM_PCIE_LINKUP) + link_status |= PCI_EXP_LNKSTA_DLLLA; + else if (res.a1 == PHYTIUM_PCIE_LINKDOWN) + link_status &= ~PCI_EXP_LNKSTA_DLLLA; + } + + return link_status; } #endif diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index d07c1d9ed0620..094e6bb3ddc6c 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -580,6 +580,9 @@ static void pci_setup_bridge_io(struct pci_dev *bridge) u8 io_base_lo, io_limit_lo; u16 l; u32 io_upper16; +#ifdef CONFIG_ARCH_PHYTIUM + u32 io_base_limit = 0; +#endif io_mask = PCI_IO_RANGE_MASK; if (bridge->io_window_1k) @@ -608,6 +611,14 @@ static void pci_setup_bridge_io(struct pci_dev *bridge) pci_write_config_word(bridge, PCI_IO_BASE, l); /* Update upper 16 bits of I/O base/limit */ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); + +#ifdef CONFIG_ARCH_PHYTIUM + if (bridge->dev.parent) { + if (!fwnode_property_read_u32(dev_fwnode(bridge->dev.parent), + "io-upper", &io_base_limit)) + pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_base_limit); + } +#endif } static void pci_setup_bridge_mmio(struct pci_dev *bridge) diff --git a/drivers/perf/phytium/Kconfig b/drivers/perf/phytium/Kconfig index e9dabba7227eb..6deae721f422c 100644 --- a/drivers/perf/phytium/Kconfig +++ b/drivers/perf/phytium/Kconfig @@ -8,20 +8,50 @@ menuconfig PHYTIUM_PMU if PHYTIUM_PMU config PHYT_DDR_PMU - tristate "Phytium SoC DDR PMU driver" - depends on (ARCH_PHYTIUM && ACPI) || COMPILE_TEST + tristate "Phytium SoC DDR PMU driver" + depends on ARCH_PHYTIUM && ACPI default m - help - Provides support for Phytium SoC DDR Controller performance + help + Provides support and unified interface for Phytium SoC DDR Controller performance + monitoring unit (PMU). + +if PHYT_DDR_PMU + +config PHYT_DMU_PMU_PD2408 + tristate "Provide support for phytium PD2408 SoC DDR PMU driver" + depends on (ARCH_PHYTIUM && ACPI && ARM_PHYTIUM_DMU_DEVFREQ) || (ARCH_PHYTIUM && ACPI && !ARM_PHYTIUM_DMU_DEVFREQ) + default m + help + Provides support for Phytium PD2408 SoC DDR Controller performance monitoring unit (PMU). + When PHYT_DDR_PMU or ARM_PHYTIUM_DMU_DEVFREQ is built as a modules (=m), + this option can only be built as a module (=m) or disabled (=n). + +endif config PHYT_PCIE_PMU tristate "Phytium SoC PCIE PMU driver" - depends on (ARCH_PHYTIUM && ACPI) || COMPILE_TEST + depends on ARCH_PHYTIUM && ACPI default m help Provides support for Phytium SoC PCIe Controller performance monitoring unit (PMU). +config PHYT_PCIE_LINK_PMU + tristate "Phytium SoC PCIE LINK PMU driver" + depends on ARCH_PHYTIUM && ACPI + default m + help + Provides support for Phytium SoC PCIe LINK performance + monitoring unit (PMU). + +config PHYT_MSI_PMU + tristate "Phytium SoC MSI PMU driver" + depends on ARCH_PHYTIUM && ACPI + default m + help + Provides support for Phytium SoC MSI performance + monitoring unit (PMU). + endif diff --git a/drivers/perf/phytium/Makefile b/drivers/perf/phytium/Makefile index af37afc6920c5..a13af49ee95ce 100644 --- a/drivers/perf/phytium/Makefile +++ b/drivers/perf/phytium/Makefile @@ -2,3 +2,5 @@ # obj-$(CONFIG_PHYT_DDR_PMU) += phytium_ddr_pmu.o obj-$(CONFIG_PHYT_PCIE_PMU) += phytium_pcie_pmu.o +obj-$(CONFIG_PHYT_PCIE_LINK_PMU) += phytium_pcie_link_pmu.o +obj-$(CONFIG_PHYT_MSI_PMU) += phytium_msi_pmu.o diff --git a/drivers/perf/phytium/phytium_ddr_pmu.c b/drivers/perf/phytium/phytium_ddr_pmu.c index 64fc031e0e011..cb7ff0fa8f961 100644 --- a/drivers/perf/phytium/phytium_ddr_pmu.c +++ b/drivers/perf/phytium/phytium_ddr_pmu.c @@ -24,68 +24,244 @@ #include #include #include +#include -#if IS_ENABLED(CONFIG_ARM || CONFIG_ARM64) #include -#endif /* CONFIG_ARM || CONFIG_ARM64 */ #include #undef pr_fmt #define pr_fmt(fmt) "phytium_ddr_pmu: " fmt - -#define PHYTIUM_DDR_MAX_COUNTERS 8 -#define DDR_PERF_DRIVER_VERSION "1.3.0" - -#define DDR_START_TIMER 0x000 -#define DDR_STOP_TIMER 0x004 -#define DDR_CLEAR_EVENT 0x008 -#define DDR_SET_TIMER_L 0x00c -#define DDR_SET_TIMER_H 0x010 -#define DDR_TRIG_MODE 0x014 -#define DDR_NOW_STATE 0x0e0 -#define DDR_EVENT_CYCLES 0x0e4 -#define DDR_TPOINT_END_L 0x0e4 -#define DDR_TPOINT_END_H 0x0e8 -#define DDR_STATE_STOP 0x0ec -#define DDR_EVENT_RXREQ 0x100 -#define DDR_EVENT_RXDAT 0x104 -#define DDR_EVENT_TXDAT 0x108 -#define DDR_EVENT_RXREQ_RNS 0x10c -#define DDR_EVENT_RXREQ_WNSP 0x110 -#define DDR_EVENT_RXREQ_WNSF 0x114 -#define DDR_EVENT_BANDWIDTH 0x200 -#define DDR_W_DATA_BASE 0x200 -#define DDR_CLK_FRE 0xe00 -#define DDR_DATA_WIDTH 0xe04 - -#define DDR_PMU_OFL_STOP_TYPE_VAL 0x10 - -#define SOC_ID_PS230XX 0x8 -#define SOC_ID_PS240XX 0x6 -#define MIDR_PSXX 0x700F8620 +#define DDR_PERF_DRIVER_VERSION "1.4.0" + +#define DDR_PMUV1_START_TIMER 0x000 +#define DDR_PMUV1_STOP_TIMER 0x004 +#define DDR_PMUV1_CLEAR_EVENT 0x008 +#define DDR_PMUV1_SET_TIMER_L 0x00c +#define DDR_PMUV1_SET_TIMER_H 0x010 +#define DDR_PMUV1_TRIG_MODE 0x014 +#define DDR_PMUV1_NOW_STATE 0x0e0 +#define DDR_PMUV1_EVENT_CYCLES 0x0e4 +#define DDR_PMUV1_TPOINT_END_L 0x0e4 +#define DDR_PMUV1_TPOINT_END_H 0x0e8 +#define DDR_PMUV1_STATE_STOP 0x0ec +#define DDR_PMUV1_EVENT_RXREQ 0x100 +#define DDR_PMUV1_EVENT_RXDAT 0x104 +#define DDR_PMUV1_EVENT_TXDAT 0x108 +#define DDR_PMUV1_EVENT_RXREQ_RNS 0x10c +#define DDR_PMUV1_EVENT_RXREQ_WNSP 0x110 +#define DDR_PMUV1_EVENT_RXREQ_WNSF 0x114 +#define DDR_PMUV1_EVENT_BANDWIDTH 0x200 +#define DDR_PMUV1_W_DATA_BASE 0x200 +#define DDR_PMUV1_CLK_FRE 0xe00 +#define DDR_PMUV1_DATA_WIDTH 0xe04 + +#define DDR_PMUV1_OFL_STOP_TYPE_VAL 0x10 + +#define PBFVER_FUNC_ID 0x82000001 +#define DDR_PMUV2_TIMER_START 0x0 +#define DDR_PMUV2_TIMER_STOP 0x4 +#define DDR_PMUV2_CLEAR_EVENT 0x8 +#define DDR_PMUV2_SET_TIMER_L 0xc +#define DDR_PMUV2_SET_TIMER_H 0x10 +#define DDR_PMUV2_AXI_MONITOR_EN 0x1c + +#define DDR_PMUV2_TIMER_INT_CLEAR 0x2c +#define DDR_PMUV2_AXI_MONITOR_INT_CLEAR 0x30 +#define DDR_PMUV2_TIMER_INT_STA 0x40 +#define DDR_PMUV2_AXI_MONITOR_INT_STA 0x44 +#define DDR_PMUV2_TIMER_INT_MASK 0x54 +#define DDR_PMUV2_AXI_MONITOR_INT_MASK 0x58 + +#define DDR_PMUV2_EVENT_CYCLES 0x208 +#define DDR_PMUV2_EVENT_AXI_READ_CMD_CNT 0x074 +#define DDR_PMUV2_EVENT_AXI_WRITE_CMD_CNT 0x07c +#define DDR_PMUV2_EVENT_AXI_READ_FLUX_CNT 0x084 +#define DDR_PMUV2_EVENT_AXI_WRITE_FLUX_CNT 0x08c + +#define DDR_PMUV2_ALL_EVENT_CLEAR_BIT 0x1 +#define DDR_PMUV2_TIMER_OPT_BIT 0x1 +#define DDR_PMUV2_AXI_MONITOR_OPT_BIT 0x01010101 + +#define DDR_PMUV2_NOTICE_START 0x0 +#define DDR_PMUV2_NOTICE_STOP 0x1 + +#define DDR_PMUV3_SNAPSHOT_PMU 0x000 +#define DDR_PMUV3_START_TIMER 0x008 +#define DDR_PMUV3_CLEAR_TIMER 0x00C +#define DDR_PMUV3_CLK_EN 0x288 +#define DDR_PMUV3_PIDR0 0xFE0 +#define DDR_PMUV3_PMU_VER_BIT GENMASK(7, 0) +#define DDR_PMUV3_PMU_PART_BIT GENMASK(11, 8) + +#define DDR_PMUV3_HPR_FIFO_THRE 0x010 +#define DDR_PMUV3_LPR_FIFO_THRE 0x014 +#define DDR_PMUV3_WR_DCQ_THRE 0x018 +#define DDR_PMUV3_WDP_BUFFER_THRE 0x01C +#define DDR_PMUV3_RDAT_INFO_THRE 0x020 +#define DDR_PMUV3_RDAT_FIFO_THRE 0x024 +#define DDR_PMUV3_RSP_COMP_THRE 0x028 +#define DDR_PMUV3_RSP_DBID_THRE 0x02C +#define DDR_PMUV3_RSP_REQ_THRE 0x030 +#define DDR_PMUV3_RSP_CRQ_THRE 0x034 +#define DDR_PMUV3_RSP_RTQ_THRE 0x038 + +#define DDR_PMUV3_MC_DFI_CMD_CNT_SEL 0x03C +#define DDR_PMUV3_MC_UIF_CNT_SEL 0x040 +#define DDR_PMUV3_MC_CAM_OCCU_CNT_SEL 0x044 +#define DDR_PMUV3_MC_CMD_SCHEDULING_CNT_SEL 0x048 +#define DDR_PMUV3_PORT_CMD_CNT_SEL 0x04C +#define DDR_PMUV3_PORT_CMD_OPCODE_CNT_SEL 0x050 +#define DDR_PMUV3_PORT_CMD_RETRY_CNT_SEL 0x054 +#define DDR_PMUV3_PORT_PREF_STATUS_CNT_SEL 0x058 +#define DDR_PMUV3_PORT_CQ_OCCU_CNT_SEL 0x05C +#define DDR_PMUV3_PORT_DATA_OCCU_CNT_SEL 0x060 +#define DDR_PMUV3_PORT_RSP_OCCU_CNT_SEL 0x064 +#define DDR_PMUV3_MC_RDWR_SWITCH_CNT_SEL 0x2f0 + +#define DDR_PMUV3_MC_DFI_CMD_CNT_L 0x070 +#define DDR_PMUV3_MC_UIF_CNT_L 0x074 +#define DDR_PMUV3_MC_BANK_MAGT_CNT_L 0x078 +#define DDR_PMUV3_MC_CAM_OCCU_CNT_L 0x07C +#define DDR_PMUV3_MC_CAM_OCCU_CNT_H 0x080 +#define DDR_PMUV3_MC_CMD_SCHE_CNT_L 0x084 +#define DDR_PMUV3_MC_CMD_SCHE_CNT_H 0x088 +#define DDR_PMUV3_MC_T_CMD_SCHE_CNT_L 0x08C +#define DDR_PMUV3_MC_T_CMD_SCHE_CNT_H 0x090 +#define DDR_PMUV3_PORT_CMD_CNT_L 0x0B8 +#define DDR_PMUV3_PORT_CMD_OPCODE_CNT_L 0x0BC +#define DDR_PMUV3_PORT_RETRY_CNT_L 0x0C0 +#define DDR_PMUV3_PORT_PREF_STATUS_CNT_L 0x0C4 +#define DDR_PMUV3_PORT_CQ_OCCU_CNT_L 0x0C8 +#define DDR_PMUV3_PORT_CQ_OCCU_CNT_H 0x0CC +#define DDR_PMUV3_PORT_DATA_OCCU_CNT_L 0x0D0 +#define DDR_PMUV3_PORT_DATA_OCCU_CNT_H 0x0D4 +#define DDR_PMUV3_PORT_RSP_OCCU_CNT_L 0x0D8 +#define DDR_PMUV3_PORT_RSP_OCCU_CNT_H 0x0DC +#define DDR_PMUV3_MC_RDWR_SWITCH_CNT_L 0x2f4 +#define DDR_PMUV3_MC_RDWR_SWITCH_CNT_H 0x2f8 +#define DDR_PMUV3_MC_T_RDWR_SWITCH_CNT_L 0x2fc +#define DDR_PMUV3_MC_T_RDWR_SWITCH_CNT_H 0x300 + +#define DDR_PMUV3_GLOBAL_CNT_L 0x068 +#define DDR_PMUV3_GLOBAL_CNT_H 0x06C +#define DDR_PMUV3_MC_CQ_IDLE_CNT_L 0x094 +#define DDR_PMUV3_MC_EXP_GPR_CNT_L 0x098 +#define DDR_PMUV3_MC_EXP_GPW_CNT_L 0x09C +#define DDR_PMUV3_MC_ADDR_COLLISION_CNT_L 0x0A0 +#define DDR_PMUV3_MC_RDCAM_CRITICAL_CNT_L 0x0A4 +#define DDR_PMUV3_MC_RDCAM_CRITICAL_CNT_H 0x0A8 +#define DDR_PMUV3_MC_WRCAM_CRITICAL_CNT_L 0x0AC +#define DDR_PMUV3_MC_WECAM_CRITICAL_CNT_H 0x0B0 +#define DDR_PMUV3_MC_RETRY_CMD_CNT_L 0x0B4 +#define DDR_PMUV3_PORT_WDAT_BE_CNT_L 0x0E0 +#define DDR_PMUV3_PORT_WDAT_RM_BUFFER_DEALLOC_CNT_L 0x0E4 +#define DDR_PMUV3_PORT_RD_CMD_DELAY1 0x2BC +#define DDR_PMUV3_PORT_RD_CMD_DELAY2 0x2C0 +#define DDR_PMUV3_PORT_WR_CMD_DELAY1 0x2C4 +#define DDR_PMUV3_PORT_WR_CMD_DELAY2 0x2C8 + +#define DDR_PMUV3_CNT_OVERFLOW_FLAG 0x0E8 +#define DDR_PMUV3_MC_DFI_CMD_CNT_OFL_BIT BIT(0) +#define DDR_PMUV3_MC_UFI_CMD_CNT_OFL_BIT BIT(1) +#define DDR_PMUV3_MC_BANK_MAGT_CNT_OFL_BIT BIT(2) +#define DDR_PMUV3_MC_CQ_IDLE_CNT_OFL_BIT BIT(3) +#define DDR_PMUV3_MC_EXP_GPR_CNT_OFL_BIT BIT(4) +#define DDR_PMUV3_MC_EXP_GPW_CNT_OFL_BIT BIT(5) +#define DDR_PMUV3_MC_ADDR_COLLISION_CNT_OFL_BIT BIT(6) + +#define DDR_PMUV3_PORT_CMD_CNT_OFL_BIT BIT(7) +#define DDR_PMUV3_PORT_CMD_OPCODE_CNT_OFL_BIT BIT(8) +#define DDR_PMUV3_PORT_RETRY_CNT_OFL_BIT BIT(9) +#define DDR_PMUV3_PORT_PREF_STATUS_CNT_OFL_BIT BIT(10) +#define DDR_PMUV3_PORT_WDAT_BE_CNT_OFL_BIT BIT(11) +#define DDR_PMUV3_PORT_WDAT_RM_BUFFER_DEALLOC_CNT_OFL_BIT BIT(12) + +#define DDR_PMUV3_MC_DFI_CMD_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_MC_UIF_CMD_SEL_MASK GENMASK(2, 0) +#define DDR_PMUV3_MC_BANK_SRC_SEL_MASK GENMASK(6, 5) +#define DDR_PMUV3_MC_CAM_OCCU_SEL_MASK GENMASK(4, 0) +#define DDR_PMUV3_MC_T_CMD_SCHE_SEL_MASK GENMASK(7, 4) +#define DDR_PMUV3_MC_CMD_SCHE_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_PORT_CMD_SEL_MASK GENMASK(2, 0) +#define DDR_PMUV3_PORT_CMD_OPCODE_SEL_MASK GENMASK(2, 0) +#define DDR_PMUV3_PORT_CMD_RETRY_SEL_MASK GENMASK(2, 0) +#define DDR_PMUV3_PORT_PREF_STATUS_SEL_MASK GENMASK(2, 0) + +#define DDR_PMUV3_LPR_FIFO_OCCU_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_HPR_FIFO_OCCU_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_WR_DCQ_OCCU_SEL_MASK GENMASK(3, 0) + +#define DDR_PMUV3_RDAT_INFO_OCCU_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_RDAT_FIFO_OCCU_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_WDP_BUFFER_OCCU_SEL_MASK GENMASK(3, 0) + +#define DDR_PMUV3_RSP_COMP_OCCU_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_REP_DBID_OCCU_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_RSP_CRQ_OCCU_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_RSP_REQ_OCCU_SEL_MASK GENMASK(3, 0) +#define DDR_PMUV3_RSP_RTQ_OCCU_SEL_MASK GENMASK(3, 0) + +#define DDR_PMUV3_MC_T_RDWR_SWITCH_CNT_SEL_MASK GENMASK(7, 4) +#define DDR_PMUV3_MC_RDWR_SWITCH_CNT_SEL_MASK GENMASK(3, 0) + +#define DDR_PMUV3_HPR_FIFO_THRE_BIT_SIZE 6 +#define DDR_PMUV3_LPR_FIFO_THRE_BIT_SIZE 6 +#define DDR_PMUV3_WR_DCQ_THRE_BIT_SIZE 6 +#define DDR_PMUV3_WDP_BUFFER_THRE_BIT_SIZE 6 +#define DDR_PMUV3_RDAT_INFO_THRE_BIT_SIZE 7 +#define DDR_PMUV3_RDAT_FIFO_THRE_BIT_SIZE 7 +#define DDR_PMUV3_RSP_COMP_THRE_BIT_SIZE 5 +#define DDR_PMUV3_RSP_DBID_THRE_BIT_SIZE 5 +#define DDR_PMUV3_RSP_REQ_THRE_BIT_SIZE 6 +#define DDR_PMUV3_RSP_CRQ_THRE_BIT_SIZE 6 +#define DDR_PMUV3_RSP_RTQ_THRE_BIT_SIZE 6 + +#define DDR_PMUV3_MC_DFI_CMD_EVENT_NUM 15 +#define DDR_PMUV3_MC_UIF_CMD_EVENT_NUM 5 +#define DDR_PMUV3_MC_BANK_SRC_EVENT_NUM 3 +#define DDR_PMUV3_MC_CAM_OCCU_EVENT_NUM 18 +#define DDR_PMUV3_MC_T_CMD_SCHE_EVENT_NUM 16 +#define DDR_PMUV3_MC_CMD_SCHE_EVENT_NUM 16 +#define DDR_PMUV3_PORT_CMD_EVENT_NUM 7 +#define DDR_PMUV3_PORT_CMD_OPCODE_EVENT_NUM 6 +#define DDR_PMUV3_PORT_CMD_RETRY_EVENT_NUM 5 +#define DDR_PMUV3_PORT_PREF_STATUS_EVENT_NUM 5 +#define DDR_PMUV3_LPR_FIFO_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_HPR_FIFO_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_WR_DCQ_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_RDAT_INFO_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_RDAT_FIFO_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_WDP_BUFFER_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_RSP_COMP_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_RSP_DBID_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_RSP_CRQ_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_RSP_REQ_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_RSP_RTQ_OCCU_EVENT_NUM 3 +#define DDR_PMUV3_MC_RDWR_SWTICH_EVENT_NUM 12 +#define DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT_NUM 12 +#define DDR_PMUV3_SPECIAL_EVENT_NUM 12 + +#define PHYTIUM_DDR_MAX_COUNTERS 165 +#define PHYTIUM_DDR_PMUV1_COUNTERS_NUM 8 +#define PHYTIUM_DDR_PMUV2_COUNTERS_NUM 5 +#define PHYTIUM_DDR_PMUV3_COUNTERS_NUM 165 +#define PHYTIUM_DDR_PMUV1V2_EVENTS_MAX_MASK 0x7 +#define PHYTIUM_DDR_PMUV3_EVENTS_MAX_MASK 0xA5 + +#define GET_DDR_PMUV1V2_EVENTID(hwc) (hwc->config_base & PHYTIUM_DDR_PMUV1V2_EVENTS_MAX_MASK) +#define EVENT_VALID_V1(idx) ((idx >= 0) && (idx < PHYTIUM_DDR_PMUV1_COUNTERS_NUM)) +#define EVENT_VALID_V2(idx) ((idx >= 0) && (idx < PHYTIUM_DDR_PMUV2_COUNTERS_NUM)) +#define EVENT_VALID_V3(idx) ((idx >= 0) && (idx < PHYTIUM_DDR_PMUV3_COUNTERS_NUM)) #define to_phytium_ddr_pmu(p) (container_of(p, struct phytium_ddr_pmu, pmu)) - enum { - PS230XX = 0x01, - PS240XX = 0x02, -}; + DDR_PMUV1P0 = 0x01, + DDR_PMUV1P5 = 0x02, + DDR_PMUV2P0, + DDR_PMUV3P0, -static inline int phytium_socs_type(void) -{ - unsigned int soc_id, cpu_id; - - soc_id = read_sysreg_s(SYS_AIDR_EL1); - cpu_id = read_cpuid_id(); - - if ((soc_id == SOC_ID_PS230XX) && (cpu_id == MIDR_PSXX)) - return PS230XX; - else if ((soc_id == SOC_ID_PS240XX) && (cpu_id == MIDR_PSXX)) - return PS240XX; - else - return 0; -} +}; static int phytium_ddr_pmu_hp_state; @@ -94,33 +270,109 @@ struct phytium_ddr_pmu_hwevents { DECLARE_BITMAP(used_mask, PHYTIUM_DDR_MAX_COUNTERS); }; +int used_event_v2; + +struct phytium_ddr_pmu_v3_port_occu_thre { + u32 lpr_fifo_low_thre; + u32 lpr_fifo_hight_thre; + u32 hpr_fifo_low_thre; + u32 hpr_fifo_hight_thre; + u32 wr_dcq_low_thre; + u32 wr_dcq_hight_thre; + + u32 rdat_info_low_thre; + u32 rdat_info_hight_thre; + u32 rdat_fifo_low_thre; + u32 rdat_fifo_hight_thre; + u32 wdp_buffer_low_thre; + u32 wdp_buffer_hight_thre; + + u32 rsp_comp_low_thre; + u32 rsp_comp_hight_thre; + + u32 rsp_dbid_low_thre; + u32 rsp_dbid_hight_thre; + u32 rsp_crq_low_thre; + u32 rsp_crq_hight_thre; + u32 rsp_req_low_thre; + u32 rsp_req_hight_thre; + u32 rsp_rtq_low_thre; + u32 rsp_rtq_hight_thre; +}; + +enum ddr_pmu_v3_event_type { + DDR_PMUV3_MC_DFI_CMD_EVTYPE, + DDR_PMUV3_MC_UIF_CMD_EVTYPE, + DDR_PMUV3_MC_BANK_SRC_EVTYPE, + DDR_PMUV3_MC_CAM_OCCU_EVTYPE, + DDR_PMUV3_MC_T_CMD_SCHE_EVTYPE, + DDR_PMUV3_MC_CMD_SCHE_EVTYPE, + DDR_PMUV3_PORT_CMD_EVTYPE, + DDR_PMUV3_PORT_CMD_OPCODE_EVTYPE, + DDR_PMUV3_PORT_CMD_RETRY_EVTYPE, + DDR_PMUV3_PORT_PREF_STATUS_EVTYPE, + DDR_PMUV3_MC_RDWR_SWTICH_EVTYPE, + DDR_PMUV3_MC_T_RDWR_SWTICH_EVTYPE, + + DDR_PMUV3_LPR_FIFO_OCCU_EVTYPE, + DDR_PMUV3_HPR_FIFO_OCCU_EVTYPE, + DDR_PMUV3_WR_DCQ_OCCU_EVTYPE, + + DDR_PMUV3_RDAT_INFO_OCCU_EVTYPE, + DDR_PMUV3_RDAT_FIFO_OCCU_EVTYPE, + DDR_PMUV3_WDP_BUFFER_OCCU_EVTYPE, + + DDR_PMUV3_RSP_COMP_OCCU_EVTYPE, + DDR_PMUV3_RSP_DBID_OCCU_EVTYPE, + DDR_PMUV3_RSP_CRQ_OCCU_EVTYPE, + DDR_PMUV3_RSP_REQ_OCCU_EVTYPE, + DDR_PMUV3_RSP_RTQ_OCCU_EVTYPE, + + DDR_PMUV3_SPECIAL_EVTYPE +}; + +struct phytium_ddr_pmu_v3_event_attr { + struct device_attribute attr; + enum ddr_pmu_v3_event_type type; + u8 eventid; + u8 occupid; + u8 cntsize; + u8 occuflag; +}; + struct phytium_ddr_pmu { struct device *dev; void __iomem *base; void __iomem *cfg_base; void __iomem *irq_reg; struct pmu pmu; + const struct phytium_ddr_pmu_ops *ops; struct phytium_ddr_pmu_hwevents pmu_events; + struct phytium_ddr_pmu_v3_port_occu_thre port_occu_thre; u32 die_id; u32 ddr_id; u32 pmu_id; int irq_bit; int on_cpu; int irq; - int soc_version; + int ver; + int cnts_num; + bool used_flag; struct hlist_node node; }; -#define GET_DDR_EVENTID(hwc) (hwc->config_base & 0x7) -#define EVENT_VALID(idx) ((idx >= 0) && (idx < PHYTIUM_DDR_MAX_COUNTERS)) - -static const u32 ddr_counter_reg_offset[] = { - DDR_EVENT_CYCLES, DDR_EVENT_RXREQ, DDR_EVENT_RXDAT, - DDR_EVENT_TXDAT, DDR_EVENT_RXREQ_RNS, DDR_EVENT_RXREQ_WNSP, - DDR_EVENT_RXREQ_WNSF, DDR_EVENT_BANDWIDTH +struct phytium_ddr_pmu_ops { + irqreturn_t (*overflow_handler)(int irq, void *dev_id); + u64 (*read_counter)(struct phytium_ddr_pmu *pmu, struct perf_event *event); + void (*clear_all_counters)(struct phytium_ddr_pmu *pmu); + void (*start_all_counters)(struct phytium_ddr_pmu *pmu); + void (*stop_all_counters)(struct phytium_ddr_pmu *pmu); + void (*enable_counters)(struct phytium_ddr_pmu *pmu); + void (*disable_counters)(struct phytium_ddr_pmu *pmu); + void (*enable_clk)(struct phytium_ddr_pmu *pmu); + void (*disable_clk)(struct phytium_ddr_pmu *pmu); }; - ssize_t phytium_ddr_pmu_format_sysfs_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -128,6 +380,7 @@ ssize_t phytium_ddr_pmu_format_sysfs_show(struct device *dev, struct dev_ext_attribute *eattr; eattr = container_of(attr, struct dev_ext_attribute, attr); + return sprintf(buf, "%s\n", (char *)eattr->var); } @@ -142,8 +395,30 @@ ssize_t phytium_ddr_pmu_event_sysfs_show(struct device *dev, return sprintf(page, "config=0x%lx\n", (unsigned long)eattr->var); } +static bool phytium_ddr_pmu_v3_is_port_occup_event(enum ddr_pmu_v3_event_type type, + unsigned int occuflag) +{ + bool ret = (type != DDR_PMUV3_MC_CAM_OCCU_EVTYPE) && (occuflag == 1); + + return ret; +} + +static ssize_t phytium_ddr_pmu_v3_event_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct phytium_ddr_pmu_v3_event_attr *eattr; + + eattr = container_of(attr, typeof(*eattr), attr); + + if (phytium_ddr_pmu_v3_is_port_occup_event(eattr->type, eattr->occuflag)) + return snprintf(buf, PAGE_SIZE, "type=0x%x,eventid=0x%x,low_thre=?,hight_thre=?\n", + eattr->type, eattr->eventid); + + return snprintf(buf, PAGE_SIZE, "type=0x%x,eventid=0x%x\n", eattr->type, eattr->eventid); +} + static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(dev_get_drvdata(dev)); @@ -153,42 +428,524 @@ static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, #define PHYTIUM_PMU_ATTR(_name, _func, _config) \ (&((struct dev_ext_attribute[]){ \ - { __ATTR(_name, 0444, _func, NULL), (void *)_config } })[0] \ - .attr.attr) + { __ATTR(_name, 0444, _func, NULL), (void *)_config } })[0] \ + .attr.attr) #define PHYTIUM_DDR_PMU_FORMAT_ATTR(_name, _config) \ PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_format_sysfs_show, \ - (void *)_config) + (void *)_config) + +static const u32 ddr_pmu_v1_counter_reg_offset[] = { + DDR_PMUV1_EVENT_CYCLES, DDR_PMUV1_EVENT_RXREQ, DDR_PMUV1_EVENT_RXDAT, + DDR_PMUV1_EVENT_TXDAT, DDR_PMUV1_EVENT_RXREQ_RNS, DDR_PMUV1_EVENT_RXREQ_WNSP, + DDR_PMUV1_EVENT_RXREQ_WNSF, DDR_PMUV1_EVENT_BANDWIDTH +}; -#define PHYTIUM_DDR_PMU_EVENT_ATTR(_name, _config) \ +static const u32 ddr_pmu_v2_counter_reg_offset[] = { + DDR_PMUV2_EVENT_CYCLES, + DDR_PMUV2_EVENT_AXI_WRITE_FLUX_CNT, DDR_PMUV2_EVENT_AXI_READ_FLUX_CNT, + DDR_PMUV2_EVENT_AXI_WRITE_CMD_CNT, DDR_PMUV2_EVENT_AXI_READ_CMD_CNT +}; + +#define PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(_name, _config) \ PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_event_sysfs_show, \ (unsigned long)_config) -static struct attribute *phytium_ddr_pmu_format_attr[] = { +static struct attribute *phytium_ddr_pmu_v1v2_format_attr[] = { PHYTIUM_DDR_PMU_FORMAT_ATTR(event, "config:0-2"), NULL, }; -static const struct attribute_group phytium_ddr_pmu_format_group = { - .name = "format", - .attrs = phytium_ddr_pmu_format_attr, -}; - -static struct attribute *phytium_ddr_pmu_events_attr[] = { - PHYTIUM_DDR_PMU_EVENT_ATTR(cycles, 0x00), - PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq, 0x01), - PHYTIUM_DDR_PMU_EVENT_ATTR(rxdat, 0x02), - PHYTIUM_DDR_PMU_EVENT_ATTR(txdat, 0x03), - PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_RNS, 0x04), - PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_WNSP, 0x05), - PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_WNSF, 0x06), - PHYTIUM_DDR_PMU_EVENT_ATTR(bandwidth, 0x07), +static struct attribute *phytium_ddr_pmu_v1_events_attr[] = { + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(ddr_cycles, 0x00), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(rxreq, 0x01), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(rxdat, 0x02), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(txdat, 0x03), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(rxreq_rns, 0x04), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(rxreq_wnsp, 0x05), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(rxreq_wnsf, 0x06), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(bandwidth, 0x07), + NULL, +}; + +static struct attribute *phytium_ddr_pmu_v2_events_attr[] = { + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(ddr_axi_cycles, 0x00), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(axi_write_flux, 0x01), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(axi_read_flux, 0x02), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(axi_write_cmd, 0x03), + PHYTIUM_DDR_PMUV1V2_EVENT_ATTR(axi_read_cmd, 0x04), NULL, }; -static const struct attribute_group phytium_ddr_pmu_events_group = { +static const u32 phytium_ddr_pmu_v3_event_num[] = { + DDR_PMUV3_MC_DFI_CMD_EVENT_NUM, + DDR_PMUV3_MC_UIF_CMD_EVENT_NUM, + DDR_PMUV3_MC_BANK_SRC_EVENT_NUM, + DDR_PMUV3_MC_CAM_OCCU_EVENT_NUM, + DDR_PMUV3_MC_T_CMD_SCHE_EVENT_NUM, + DDR_PMUV3_MC_CMD_SCHE_EVENT_NUM, + DDR_PMUV3_PORT_CMD_EVENT_NUM, + DDR_PMUV3_PORT_CMD_OPCODE_EVENT_NUM, + DDR_PMUV3_PORT_CMD_RETRY_EVENT_NUM, + DDR_PMUV3_PORT_PREF_STATUS_EVENT_NUM, + DDR_PMUV3_MC_RDWR_SWTICH_EVENT_NUM, + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT_NUM, + DDR_PMUV3_LPR_FIFO_OCCU_EVENT_NUM, + DDR_PMUV3_HPR_FIFO_OCCU_EVENT_NUM, + DDR_PMUV3_WR_DCQ_OCCU_EVENT_NUM, + DDR_PMUV3_RDAT_INFO_OCCU_EVENT_NUM, + DDR_PMUV3_RDAT_FIFO_OCCU_EVENT_NUM, + DDR_PMUV3_WDP_BUFFER_OCCU_EVENT_NUM, + DDR_PMUV3_RSP_COMP_OCCU_EVENT_NUM, + DDR_PMUV3_RSP_DBID_OCCU_EVENT_NUM, + DDR_PMUV3_RSP_CRQ_OCCU_EVENT_NUM, + DDR_PMUV3_RSP_REQ_OCCU_EVENT_NUM, + DDR_PMUV3_RSP_RTQ_OCCU_EVENT_NUM, + DDR_PMUV3_SPECIAL_EVENT_NUM +}; + +static const u32 phytium_ddr_pmu_v3_event_sel_reg_offset[] = { + DDR_PMUV3_MC_DFI_CMD_CNT_SEL, + DDR_PMUV3_MC_UIF_CNT_SEL, + DDR_PMUV3_MC_CAM_OCCU_CNT_SEL, + DDR_PMUV3_MC_CAM_OCCU_CNT_SEL, + DDR_PMUV3_MC_CMD_SCHEDULING_CNT_SEL, + DDR_PMUV3_MC_CMD_SCHEDULING_CNT_SEL, + DDR_PMUV3_PORT_CMD_CNT_SEL, + DDR_PMUV3_PORT_CMD_OPCODE_CNT_SEL, + DDR_PMUV3_PORT_CMD_RETRY_CNT_SEL, + DDR_PMUV3_PORT_PREF_STATUS_CNT_SEL, + DDR_PMUV3_MC_RDWR_SWITCH_CNT_SEL, + DDR_PMUV3_MC_RDWR_SWITCH_CNT_SEL, + DDR_PMUV3_PORT_CQ_OCCU_CNT_SEL, + DDR_PMUV3_PORT_CQ_OCCU_CNT_SEL, + DDR_PMUV3_PORT_CQ_OCCU_CNT_SEL, + DDR_PMUV3_PORT_DATA_OCCU_CNT_SEL, + DDR_PMUV3_PORT_DATA_OCCU_CNT_SEL, + DDR_PMUV3_PORT_DATA_OCCU_CNT_SEL, + DDR_PMUV3_PORT_RSP_OCCU_CNT_SEL, + DDR_PMUV3_PORT_RSP_OCCU_CNT_SEL, + DDR_PMUV3_PORT_RSP_OCCU_CNT_SEL, + DDR_PMUV3_PORT_RSP_OCCU_CNT_SEL, + DDR_PMUV3_PORT_RSP_OCCU_CNT_SEL +}; + +static const u32 phytium_ddr_pmu_v3_cnt_sel_mask_offset[] = { + DDR_PMUV3_MC_DFI_CMD_SEL_MASK, + DDR_PMUV3_MC_UIF_CMD_SEL_MASK, + DDR_PMUV3_MC_BANK_SRC_SEL_MASK, + DDR_PMUV3_MC_CAM_OCCU_SEL_MASK, + DDR_PMUV3_MC_T_CMD_SCHE_SEL_MASK, + DDR_PMUV3_MC_CMD_SCHE_SEL_MASK, + DDR_PMUV3_PORT_CMD_SEL_MASK, + DDR_PMUV3_PORT_CMD_OPCODE_SEL_MASK, + DDR_PMUV3_PORT_CMD_RETRY_SEL_MASK, + DDR_PMUV3_PORT_PREF_STATUS_SEL_MASK, + DDR_PMUV3_MC_RDWR_SWITCH_CNT_SEL_MASK, + DDR_PMUV3_MC_T_RDWR_SWITCH_CNT_SEL_MASK, + DDR_PMUV3_LPR_FIFO_OCCU_SEL_MASK, + DDR_PMUV3_HPR_FIFO_OCCU_SEL_MASK, + DDR_PMUV3_WR_DCQ_OCCU_SEL_MASK, + DDR_PMUV3_RDAT_INFO_OCCU_SEL_MASK, + DDR_PMUV3_RDAT_FIFO_OCCU_SEL_MASK, + DDR_PMUV3_WDP_BUFFER_OCCU_SEL_MASK, + DDR_PMUV3_RSP_COMP_OCCU_SEL_MASK, + DDR_PMUV3_REP_DBID_OCCU_SEL_MASK, + DDR_PMUV3_RSP_CRQ_OCCU_SEL_MASK, + DDR_PMUV3_RSP_REQ_OCCU_SEL_MASK, + DDR_PMUV3_RSP_RTQ_OCCU_SEL_MASK +}; + +static const u32 phytium_ddr_pmu_v3_thre_reg_offset[] = { + DDR_PMUV3_LPR_FIFO_THRE, + DDR_PMUV3_HPR_FIFO_THRE, + DDR_PMUV3_WR_DCQ_THRE, + DDR_PMUV3_WDP_BUFFER_THRE, + DDR_PMUV3_RDAT_INFO_THRE, + DDR_PMUV3_RDAT_FIFO_THRE, + DDR_PMUV3_RSP_COMP_THRE, + DDR_PMUV3_RSP_DBID_THRE, + DDR_PMUV3_RSP_REQ_THRE, + DDR_PMUV3_RSP_CRQ_THRE, + DDR_PMUV3_RSP_RTQ_THRE +}; + +static const u32 phytium_ddr_pmu_v3_thre_bit_size[] = { + DDR_PMUV3_LPR_FIFO_THRE_BIT_SIZE, + DDR_PMUV3_HPR_FIFO_THRE_BIT_SIZE, + DDR_PMUV3_WR_DCQ_THRE_BIT_SIZE, + DDR_PMUV3_WDP_BUFFER_THRE_BIT_SIZE, + DDR_PMUV3_RDAT_INFO_THRE_BIT_SIZE, + DDR_PMUV3_RDAT_FIFO_THRE_BIT_SIZE, + DDR_PMUV3_RSP_COMP_THRE_BIT_SIZE, + DDR_PMUV3_RSP_DBID_THRE_BIT_SIZE, + DDR_PMUV3_RSP_REQ_THRE_BIT_SIZE, + DDR_PMUV3_RSP_CRQ_THRE_BIT_SIZE, + DDR_PMUV3_RSP_RTQ_THRE_BIT_SIZE +}; + +static const u32 phytium_ddr_pmu_v3_genc_cnt_reg_offset[] = { + DDR_PMUV3_MC_DFI_CMD_CNT_L, + DDR_PMUV3_MC_UIF_CNT_L, + DDR_PMUV3_MC_BANK_MAGT_CNT_L, + DDR_PMUV3_MC_CAM_OCCU_CNT_L, + DDR_PMUV3_MC_T_CMD_SCHE_CNT_L, + DDR_PMUV3_MC_CMD_SCHE_CNT_L, + DDR_PMUV3_PORT_CMD_CNT_L, + DDR_PMUV3_PORT_CMD_OPCODE_CNT_L, + DDR_PMUV3_PORT_RETRY_CNT_L, + DDR_PMUV3_PORT_PREF_STATUS_CNT_L, + DDR_PMUV3_MC_RDWR_SWITCH_CNT_L, + DDR_PMUV3_MC_T_RDWR_SWITCH_CNT_L, + DDR_PMUV3_PORT_CQ_OCCU_CNT_L, + DDR_PMUV3_PORT_CQ_OCCU_CNT_L, + DDR_PMUV3_PORT_CQ_OCCU_CNT_L, + DDR_PMUV3_PORT_DATA_OCCU_CNT_L, + DDR_PMUV3_PORT_DATA_OCCU_CNT_L, + DDR_PMUV3_PORT_DATA_OCCU_CNT_L, + DDR_PMUV3_PORT_RSP_OCCU_CNT_L, + DDR_PMUV3_PORT_RSP_OCCU_CNT_L, + DDR_PMUV3_PORT_RSP_OCCU_CNT_L, + DDR_PMUV3_PORT_RSP_OCCU_CNT_L, + DDR_PMUV3_PORT_RSP_OCCU_CNT_L +}; + +static const u32 phytium_ddr_pmu_v3_spec_cnt_reg_offset[] = { + DDR_PMUV3_GLOBAL_CNT_L, + DDR_PMUV3_MC_CQ_IDLE_CNT_L, + DDR_PMUV3_MC_EXP_GPR_CNT_L, + DDR_PMUV3_MC_EXP_GPW_CNT_L, + DDR_PMUV3_MC_ADDR_COLLISION_CNT_L, + DDR_PMUV3_MC_RDCAM_CRITICAL_CNT_L, + DDR_PMUV3_MC_WRCAM_CRITICAL_CNT_L, + DDR_PMUV3_MC_RETRY_CMD_CNT_L, + DDR_PMUV3_PORT_WDAT_BE_CNT_L, + DDR_PMUV3_PORT_WDAT_RM_BUFFER_DEALLOC_CNT_L, + DDR_PMUV3_PORT_RD_CMD_DELAY1, + DDR_PMUV3_PORT_WR_CMD_DELAY1 +}; + +static const u32 phytium_ddr_pmu_v3_genc_cnt_overflow_bit[] = { + 0, // DDR_PMUV3_MC_DFI_CMD_CNT_L, + 1, // DDR_PMUV3_MC_UIF_CNT_L, + 2, // DDR_PMUV3_MC_BANK_MAGT_CNT_L, + -1, // DDR_PMUV3_MC_CAM_OCCU_CNT_L, + -1, // DDR_PMUV3_MC_T_CMD_SCHE_CNT_L, + -1, // DDR_PMUV3_MC_CMD_SCHE_CNT_L, + 7, // DDR_PMUV3_PORT_CMD_CNT_L, + 8, // DDR_PMUV3_PORT_CMD_OPCODE_CNT_L, + 9, // DDR_PMUV3_PORT_RETRY_CNT_L, + 10, // DDR_PMUV3_PORT_PREF_STATUS_CNT_L, + -1, // DDR_PMUV3_MC_RDWR_SWITCH_CNT_L + -1, // DDR_PMUV3_MC_T_RDWR_SWITCH_CNT_L + -1, // DDR_PMUV3_PORT_CQ_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_CQ_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_CQ_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_DATA_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_DATA_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_DATA_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_RSP_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_RSP_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_RSP_OCCU_CNT_L, + -1, // DDR_PMUV3_PORT_RSP_OCCU_CNT_L, + -1 // DDR_PMUV3_PORT_RSP_OCCU_CNT_L +}; + +static const int phytium_ddr_pmu_v3_spec_cnt_overflow_bit[] = { + -1, + 3, // DDR_PMUV3_MC_CQ_IDLE_CNT_L, + 4, // DDR_PMUV3_MC_EXP_GPR_CNT_L, + 5, // DDR_PMUV3_MC_EXP_GPW_CNT_L, + 6, // DDR_PMUV3_MC_ADDR_COLLISION_CNT_L, + -1, // DDR_PMUV3_MC_RDCAM_CRITICAL_CNT_L, + -1, // DDR_PMUV3_MC_WRCAM_CRITICAL_CNT_L, + -1, // DDR_PMUV3_MC_RETRY_CMD_CNT_L, + 11, // DDR_PMUV3_PORT_WDAT_BE_CNT_L, + 12, // DDR_PMUV3_PORT_WDAT_RM_BUFFER_DEALLOC_CNT_L, + -1, // DDR_PMUV3_PORT_RD_CMD_DELAY1, + -1 // DDR_PMUV3_PORT_WR_CMD_DELAY1 +}; + +#define DDR_PMUV3_EVENT_ATTR(_name, _type, _eventid, _cntsize, _occuflag) \ + (&((struct phytium_ddr_pmu_v3_event_attr[]){{ \ + .attr = __ATTR(_name, 0444, phytium_ddr_pmu_v3_event_show, NULL), \ + .type = _type, \ + .eventid = _eventid, \ + .cntsize = _cntsize, \ + .occuflag = _occuflag, \ + }})[0] \ + .attr.attr) + +#define DDR_PMUV3_SPECIAL_EVENT(_name, _event, _cntsize) \ + DDR_PMUV3_EVENT_ATTR(_name, DDR_PMUV3_SPECIAL_EVTYPE, _event, _cntsize, 0) +#define DDR_PMUV3_MC_DFI_CMD_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(mc_dfi_##_name, DDR_PMUV3_MC_DFI_CMD_EVTYPE, _event, 32, 0) +#define DDR_PMUV3_MC_UIF_CMD_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(mc_uif_##_name, DDR_PMUV3_MC_UIF_CMD_EVTYPE, _event, 32, 0) +#define DDR_PMUV3_MC_BANK_SRC_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(mc_bank_mgt_##_name, DDR_PMUV3_MC_BANK_SRC_EVTYPE, _event, 32, 0) +#define DDR_PMUV3_MC_CAM_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(mc_occu_##_name, DDR_PMUV3_MC_CAM_OCCU_EVTYPE, _event, 64, 1) +#define DDR_PMUV3_MC_T_CMD_SCHE_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(mc_t_cmd_sche_##_name, DDR_PMUV3_MC_T_CMD_SCHE_EVTYPE, _event, 64, 0) +#define DDR_PMUV3_MC_CMD_SCHE_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(mc_cmd_sche_##_name, DDR_PMUV3_MC_CMD_SCHE_EVTYPE, _event, 64, 0) +#define DDR_PMUV3_PORT_CMD_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_##_name, DDR_PMUV3_PORT_CMD_EVTYPE, _event, 32, 0) +#define DDR_PMUV3_PORT_CMD_OPCODE_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_opcode_##_name, DDR_PMUV3_PORT_CMD_OPCODE_EVTYPE, _event, 32, 0) +#define DDR_PMUV3_PORT_CMD_RETRY_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_retry_##_name, DDR_PMUV3_PORT_CMD_RETRY_EVTYPE, _event, 32, 0) +#define DDR_PMUV3_PORT_PREF_STATUS_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_pref_##_name, DDR_PMUV3_PORT_PREF_STATUS_EVTYPE, _event, 32, 0) + +#define DDR_PMUV3_LPR_FIFO_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_cq_occu_lpr_##_name, DDR_PMUV3_LPR_FIFO_OCCU_EVTYPE, _event, \ + 64, 1) +#define DDR_PMUV3_HPR_FIFO_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_cq_occu_hpr_##_name, DDR_PMUV3_HPR_FIFO_OCCU_EVTYPE, _event, \ + 64, 1) +#define DDR_PMUV3_WR_DCQ_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_cq_occu_dwr_cq_##_name, DDR_PMUV3_WR_DCQ_OCCU_EVTYPE, _event, \ + 64, 1) + +#define DDR_PMUV3_RDAT_INFO_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_data_occu_rdatinfo_##_name, DDR_PMUV3_RDAT_INFO_OCCU_EVTYPE, \ + _event, 64, 1) +#define DDR_PMUV3_RDAT_FIFO_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_data_occu_rdatfifo_##_name, DDR_PMUV3_RDAT_FIFO_OCCU_EVTYPE, \ + _event, 64, 1) +#define DDR_PMUV3_WDP_BUFFER_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_data_occu_wdp_buffer_##_name, DDR_PMUV3_WDP_BUFFER_OCCU_EVTYPE,\ + _event, 64, 1) + +#define DDR_PMUV3_RSP_COMP_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_rsp_occu_rspcomp_##_name, DDR_PMUV3_RSP_COMP_OCCU_EVTYPE, \ + _event, 64, 1) +#define DDR_PMUV3_RSP_DBID_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_rsp_occu_rspdbid_##_name, DDR_PMUV3_RSP_DBID_OCCU_EVTYPE, \ + _event, 64, 1) +#define DDR_PMUV3_RSP_CRQ_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_rsp_occu_rspcrq_##_name, DDR_PMUV3_RSP_CRQ_OCCU_EVTYPE, _event, \ + 64, 1) +#define DDR_PMUV3_RSP_REQ_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_rsp_occu_rspreq_##_name, DDR_PMUV3_RSP_REQ_OCCU_EVTYPE, _event, \ + 64, 1) +#define DDR_PMUV3_RSP_RTQ_OCCU_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(port_rsp_occu_rsprtq_##_name, DDR_PMUV3_RSP_RTQ_OCCU_EVTYPE, _event, \ + 64, 1) +#define DDR_PMUV3_MC_RDWR_SWTICH_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(mc_switch_##_name, DDR_PMUV3_MC_RDWR_SWTICH_EVTYPE, _event, 64, 0) +#define DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(_name, _event) \ + DDR_PMUV3_EVENT_ATTR(mc_switch_t_##_name, DDR_PMUV3_MC_T_RDWR_SWTICH_EVTYPE, _event, 64, 0) + +#define PHYTIUM_DDR_PMUV3_EVENT_ATTR_EXTRACTOR(_name, _config, _start, _end) \ +static inline u32 get_##_name(struct perf_event *event) \ +{ \ + return FIELD_GET(GENMASK_ULL(_end, _start), \ + event->attr._config); \ +} + +PHYTIUM_DDR_PMUV3_EVENT_ATTR_EXTRACTOR(eventid, config, 0, 4); +PHYTIUM_DDR_PMUV3_EVENT_ATTR_EXTRACTOR(type, config, 5, 9); +PHYTIUM_DDR_PMUV3_EVENT_ATTR_EXTRACTOR(cntsize, config, 10, 16); +PHYTIUM_DDR_PMUV3_EVENT_ATTR_EXTRACTOR(occuflag, config, 17, 17); +PHYTIUM_DDR_PMUV3_EVENT_ATTR_EXTRACTOR(low_thre, config, 18, 24); +PHYTIUM_DDR_PMUV3_EVENT_ATTR_EXTRACTOR(hight_thre, config, 25, 31); + + +static struct attribute *phytium_ddr_pmu_v3_format_attr[] = { + PHYTIUM_DDR_PMU_FORMAT_ATTR(eventid, "config:0-4"), + PHYTIUM_DDR_PMU_FORMAT_ATTR(type, "config:5-9"), + PHYTIUM_DDR_PMU_FORMAT_ATTR(cntsize, "config:10-16"), + PHYTIUM_DDR_PMU_FORMAT_ATTR(occuflag, "config:17"), + PHYTIUM_DDR_PMU_FORMAT_ATTR(low_thre, "config:18-24"), + PHYTIUM_DDR_PMU_FORMAT_ATTR(hight_thre, "config:25-31"), + NULL, +}; + +static struct attribute *phytium_ddr_pmu_v3_events_attr[] = { + DDR_PMUV3_MC_DFI_CMD_EVENT(act_cnt, 0x0), DDR_PMUV3_MC_DFI_CMD_EVENT(pdx_cnt, 0x1), + DDR_PMUV3_MC_DFI_CMD_EVENT(pde_cnt, 0x2), DDR_PMUV3_MC_DFI_CMD_EVENT(mrs_cnt, 0x3), + DDR_PMUV3_MC_DFI_CMD_EVENT(rd_cnt, 0x4), DDR_PMUV3_MC_DFI_CMD_EVENT(rda_cnt, 0x5), + DDR_PMUV3_MC_DFI_CMD_EVENT(wr_cnt, 0x6), DDR_PMUV3_MC_DFI_CMD_EVENT(wra_cnt, 0x7), + DDR_PMUV3_MC_DFI_CMD_EVENT(pre_cnt, 0x8), DDR_PMUV3_MC_DFI_CMD_EVENT(refpb_cnt, 0x9), + DDR_PMUV3_MC_DFI_CMD_EVENT(refab_cnt, 0xa), DDR_PMUV3_MC_DFI_CMD_EVENT(rfmab_cnt, 0xb), + DDR_PMUV3_MC_DFI_CMD_EVENT(rfmpb_cnt, 0xc), DDR_PMUV3_MC_DFI_CMD_EVENT(ctrlupd_cnt, 0xd), + DDR_PMUV3_MC_DFI_CMD_EVENT(phyupd_cnt, 0xe), + + DDR_PMUV3_MC_UIF_CMD_EVENT(hpr_cnt, 0x0), DDR_PMUV3_MC_UIF_CMD_EVENT(lpr_cnt, 0x1), + DDR_PMUV3_MC_UIF_CMD_EVENT(gpr_cnt, 0x2), DDR_PMUV3_MC_UIF_CMD_EVENT(tpw_cnt, 0x3), + DDR_PMUV3_MC_UIF_CMD_EVENT(gpw_cnt, 0x4), + + DDR_PMUV3_MC_BANK_SRC_EVENT(new_cnt, 0x0), DDR_PMUV3_MC_BANK_SRC_EVENT(hit_cnt, 0x1), + DDR_PMUV3_MC_BANK_SRC_EVENT(reallocate_cnt, 0x2), + + DDR_PMUV3_MC_CAM_OCCU_EVENT(lgpr_thre16_cnt, 0x0), + DDR_PMUV3_MC_CAM_OCCU_EVENT(lgpr_thre24_cnt, 0x1), + DDR_PMUV3_MC_CAM_OCCU_EVENT(lgpr_thre32_cnt, 0x2), + DDR_PMUV3_MC_CAM_OCCU_EVENT(lgpr_thre40_cnt, 0x3), + DDR_PMUV3_MC_CAM_OCCU_EVENT(lgpr_thre48_cnt, 0x4), + DDR_PMUV3_MC_CAM_OCCU_EVENT(lgpr_thre64_cnt, 0x5), + DDR_PMUV3_MC_CAM_OCCU_EVENT(hpr_thre16_cnt, 0x6), + DDR_PMUV3_MC_CAM_OCCU_EVENT(hpr_thre24_cnt, 0x7), + DDR_PMUV3_MC_CAM_OCCU_EVENT(hpr_thre32_cnt, 0x8), + DDR_PMUV3_MC_CAM_OCCU_EVENT(hpr_thre40_cnt, 0x9), + DDR_PMUV3_MC_CAM_OCCU_EVENT(hpr_thre48_cnt, 0xa), + DDR_PMUV3_MC_CAM_OCCU_EVENT(hpr_thre64_cnt, 0xb), + DDR_PMUV3_MC_CAM_OCCU_EVENT(tpw_thre16_cnt, 0xc), + DDR_PMUV3_MC_CAM_OCCU_EVENT(tpw_thre24_cnt, 0xd), + DDR_PMUV3_MC_CAM_OCCU_EVENT(tpw_thre32_cnt, 0xe), + DDR_PMUV3_MC_CAM_OCCU_EVENT(tpw_thre40_cnt, 0xf), + DDR_PMUV3_MC_CAM_OCCU_EVENT(tpw_thre48_cnt, 0x10), + DDR_PMUV3_MC_CAM_OCCU_EVENT(tpw_thre64_cnt, 0x11), + + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(rd2rd_diff_rank_cnt, 0x0), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(rd2rd_diff_bg_cnt, 0x1), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(rd2rd_diff_page_cnt, 0x2), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(rd2rd_same_page_cnt, 0x3), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(rd2wr_diff_rank_cnt, 0x4), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(rd2wr_diff_bg_cnt, 0x5), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(rd2wr_diff_page_cnt, 0x6), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(rd2wr_same_page_cnt, 0x7), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(wr2wr_diff_rank_cnt, 0x8), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(wr2wr_diff_bg_cnt, 0x9), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(wr2wr_diff_page_cnt, 0xa), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(wr2wr_same_page_cnt, 0xb), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(wr2rd_diff_rank_cnt, 0xc), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(wr2rd_diff_bg_cnt, 0xd), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(wr2rd_diff_page_cnt, 0xe), + DDR_PMUV3_MC_T_CMD_SCHE_EVENT(wr2rd_same_page_cnt, 0xf), + + DDR_PMUV3_MC_CMD_SCHE_EVENT(rd2rd_diff_rank_cnt, 0x0), + DDR_PMUV3_MC_CMD_SCHE_EVENT(rd2rd_diff_bg_cnt, 0x1), + DDR_PMUV3_MC_CMD_SCHE_EVENT(rd2rd_diff_page_cnt, 0x2), + DDR_PMUV3_MC_CMD_SCHE_EVENT(rd2rd_same_page_cnt, 0x3), + DDR_PMUV3_MC_CMD_SCHE_EVENT(rd2wr_diff_rank_cnt, 0x4), + DDR_PMUV3_MC_CMD_SCHE_EVENT(rd2wr_diff_bg_cnt, 0x5), + DDR_PMUV3_MC_CMD_SCHE_EVENT(rd2wr_diff_page_cnt, 0x6), + DDR_PMUV3_MC_CMD_SCHE_EVENT(rd2wr_same_page_cnt, 0x7), + DDR_PMUV3_MC_CMD_SCHE_EVENT(wr2wr_diff_rank_cnt, 0x8), + DDR_PMUV3_MC_CMD_SCHE_EVENT(wr2wr_diff_bg_cnt, 0x9), + DDR_PMUV3_MC_CMD_SCHE_EVENT(wr2wr_diff_page_cnt, 0xa), + DDR_PMUV3_MC_CMD_SCHE_EVENT(wr2wr_same_page_cnt, 0xb), + DDR_PMUV3_MC_CMD_SCHE_EVENT(wr2rd_diff_rank_cnt, 0xc), + DDR_PMUV3_MC_CMD_SCHE_EVENT(wr2rd_diff_bg_cnt, 0xd), + DDR_PMUV3_MC_CMD_SCHE_EVENT(wr2rd_diff_page_cnt, 0xe), + DDR_PMUV3_MC_CMD_SCHE_EVENT(wr2rd_same_page_cnt, 0xf), + + DDR_PMUV3_PORT_CMD_EVENT(hpr_cnt, 0x0), DDR_PMUV3_PORT_CMD_EVENT(lpr_cnt, 0x1), + DDR_PMUV3_PORT_CMD_EVENT(gpr_cnt, 0x2), DDR_PMUV3_PORT_CMD_EVENT(tpw_cnt, 0x3), + DDR_PMUV3_PORT_CMD_EVENT(gpw_cnt, 0x4), DDR_PMUV3_PORT_CMD_EVENT(gpr_expired_cnt, 0x5), + DDR_PMUV3_PORT_CMD_EVENT(gpw_expired_cnt, 0x6), + + DDR_PMUV3_PORT_CMD_OPCODE_EVENT(pcrd_return_cnt, 0x0), + DDR_PMUV3_PORT_CMD_OPCODE_EVENT(read_no_snp_cnt, 0x1), + DDR_PMUV3_PORT_CMD_OPCODE_EVENT(write_no_snpfull_cnt, 0x2), + DDR_PMUV3_PORT_CMD_OPCODE_EVENT(write_no_snp_ptl_cnt, 0x3), + DDR_PMUV3_PORT_CMD_OPCODE_EVENT(prefetch_tgt_cnt, 0x4), + DDR_PMUV3_PORT_CMD_OPCODE_EVENT(cleansharepersist_cnt, 0x5), + + DDR_PMUV3_PORT_CMD_RETRY_EVENT(hpr_cnt, 0x0), DDR_PMUV3_PORT_CMD_RETRY_EVENT(lpr_cnt, 0x1), + DDR_PMUV3_PORT_CMD_RETRY_EVENT(gpr_cnt, 0x2), DDR_PMUV3_PORT_CMD_RETRY_EVENT(tpw_cnt, 0x3), + DDR_PMUV3_PORT_CMD_RETRY_EVENT(gpw_cnt, 0x4), + + DDR_PMUV3_PORT_PREF_STATUS_EVENT(hit_cnt, 0x0), + DDR_PMUV3_PORT_PREF_STATUS_EVENT(invalid_cnt, 0x1), + DDR_PMUV3_PORT_PREF_STATUS_EVENT(replace_cnt, 0x2), + DDR_PMUV3_PORT_PREF_STATUS_EVENT(discard_bcs_resource_cnt, 0x3), + DDR_PMUV3_PORT_PREF_STATUS_EVENT(discard_bcs_addr_coll_cnt, 0x4), + + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(rdw_1cmd_cnt, 0x0), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(rdw_2cmd_cnt, 0x1), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(rdw_3to4cmd_cnt, 0x2), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(rdw_5to8cmd_cnt, 0x3), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(rdw_9to12cmd_cnt, 0x4), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(rdw_13cmd_cnt, 0x5), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(wdr_1cmd_cnt, 0x6), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(wdr_2cmd_cnt, 0x7), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(wdr_3to4cmd_cnt, 0x8), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(wdr_5to8cmd_cnt, 0x9), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(wdr_9to12cmd_cnt, 0xa), + DDR_PMUV3_MC_RDWR_SWTICH_EVENT(wdr_ge13cmd_cnt, 0xb), + + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(rdw_1cmd_cnt, 0x0), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(rdw_2cmd_cnt, 0x1), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(rdw_3to4cmd_cnt, 0x2), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(rdw_5to8cmd_cnt, 0x3), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(rdw_9to12cmd_cnt, 0x4), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(rdw_13cmd_cnt, 0x5), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(wdr_1cmd_cnt, 0x6), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(wdr_2cmd_cnt, 0x7), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(wdr_3to4cmd_cnt, 0x8), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(wdr_5to8cmd_cnt, 0x9), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(wdr_9to12cmd_cnt, 0xa), + DDR_PMUV3_MC_T_RDWR_SWTICH_EVENT(wdr_ge13cmd_cnt, 0xb), + + DDR_PMUV3_LPR_FIFO_OCCU_EVENT(low_thre, 0x0), DDR_PMUV3_LPR_FIFO_OCCU_EVENT(med_thre, 0x1), + DDR_PMUV3_LPR_FIFO_OCCU_EVENT(high_thre, 0x2), + DDR_PMUV3_HPR_FIFO_OCCU_EVENT(low_thre, 0x3), DDR_PMUV3_HPR_FIFO_OCCU_EVENT(med_thre, 0x4), + DDR_PMUV3_HPR_FIFO_OCCU_EVENT(high_thre, 0x5), + DDR_PMUV3_WR_DCQ_OCCU_EVENT(low_thre, 0x6), DDR_PMUV3_WR_DCQ_OCCU_EVENT(med_thre, 0x7), + DDR_PMUV3_WR_DCQ_OCCU_EVENT(high_thre, 0x8), + + DDR_PMUV3_RDAT_INFO_OCCU_EVENT(low_thre, 0x0), + DDR_PMUV3_RDAT_INFO_OCCU_EVENT(med_thre, 0x1), + DDR_PMUV3_RDAT_INFO_OCCU_EVENT(high_thre, 0x2), + DDR_PMUV3_RDAT_FIFO_OCCU_EVENT(low_thre, 0x3), + DDR_PMUV3_RDAT_FIFO_OCCU_EVENT(med_thre, 0x4), + DDR_PMUV3_RDAT_FIFO_OCCU_EVENT(high_thre, 0x5), + DDR_PMUV3_WDP_BUFFER_OCCU_EVENT(low_thre, 0x6), + DDR_PMUV3_WDP_BUFFER_OCCU_EVENT(med_thre, 0x7), + DDR_PMUV3_WDP_BUFFER_OCCU_EVENT(high_thre, 0x8), + + DDR_PMUV3_RSP_COMP_OCCU_EVENT(low_thre, 0x0), DDR_PMUV3_RSP_COMP_OCCU_EVENT(med_thre, 0x1), + DDR_PMUV3_RSP_COMP_OCCU_EVENT(high_thre, 0x2), + DDR_PMUV3_RSP_DBID_OCCU_EVENT(low_thre, 0x3), DDR_PMUV3_RSP_DBID_OCCU_EVENT(med_thre, 0x4), + DDR_PMUV3_RSP_DBID_OCCU_EVENT(high_thre, 0x5), + DDR_PMUV3_RSP_CRQ_OCCU_EVENT(low_thre, 0x6), DDR_PMUV3_RSP_CRQ_OCCU_EVENT(med_thre, 0x7), + DDR_PMUV3_RSP_CRQ_OCCU_EVENT(high_thre, 0x8), + DDR_PMUV3_RSP_REQ_OCCU_EVENT(low_thre, 0x9), DDR_PMUV3_RSP_REQ_OCCU_EVENT(med_thre, 0xa), + DDR_PMUV3_RSP_REQ_OCCU_EVENT(high_thre, 0xb), + DDR_PMUV3_RSP_RTQ_OCCU_EVENT(low_thre, 0xc), DDR_PMUV3_RSP_RTQ_OCCU_EVENT(med_thre, 0xd), + DDR_PMUV3_RSP_RTQ_OCCU_EVENT(high_thre, 0xe), + + DDR_PMUV3_SPECIAL_EVENT(dmu_cycles, 0x0, 64), DDR_PMUV3_SPECIAL_EVENT(mc_cq_idle, 0x1, 32), + DDR_PMUV3_SPECIAL_EVENT(mc_exp_gpr, 0x2, 32), DDR_PMUV3_SPECIAL_EVENT(mc_exp_gpw, 0x3, 32), + DDR_PMUV3_SPECIAL_EVENT(mc_addr_collision, 0x4, 32), + DDR_PMUV3_SPECIAL_EVENT(mc_rdcam_critical, 0x5, 64), + DDR_PMUV3_SPECIAL_EVENT(mc_wrcam_critical, 0x6, 64), + DDR_PMUV3_SPECIAL_EVENT(mc_retry_cmd, 0x7, 32), + DDR_PMUV3_SPECIAL_EVENT(port_wdat_be, 0x8, 32), + DDR_PMUV3_SPECIAL_EVENT(port_wdat_rm_buffer_dealloc, 0x9, 32), + DDR_PMUV3_SPECIAL_EVENT(port_rd_cmd_delay, 0xa, 64), + DDR_PMUV3_SPECIAL_EVENT(port_wr_cmd_delay, 0xb, 64), + NULL, +}; + +static const struct attribute_group phytium_ddr_pmu_v1v2_format_group = { + .name = "format", + .attrs = phytium_ddr_pmu_v1v2_format_attr, +}; + +static const struct attribute_group phytium_ddr_pmu_v3_format_group = { + .name = "format", + .attrs = phytium_ddr_pmu_v3_format_attr, +}; + +static const struct attribute_group phytium_ddr_pmu_v1_events_group = { + .name = "events", + .attrs = phytium_ddr_pmu_v1_events_attr, +}; + +static const struct attribute_group phytium_ddr_pmu_v2_events_group = { .name = "events", - .attrs = phytium_ddr_pmu_events_attr, + .attrs = phytium_ddr_pmu_v2_events_attr, +}; + +static const struct attribute_group phytium_ddr_pmu_v3_events_group = { + .name = "events", + .attrs = phytium_ddr_pmu_v3_events_attr, }; static DEVICE_ATTR_RO(cpumask); @@ -202,23 +959,57 @@ static const struct attribute_group phytium_ddr_pmu_cpumask_attr_group = { .attrs = phytium_ddr_pmu_cpumask_attrs, }; -static const struct attribute_group *phytium_ddr_pmu_attr_groups[] = { - &phytium_ddr_pmu_format_group, - &phytium_ddr_pmu_events_group, +static const struct attribute_group *phytium_ddr_pmu_v1_attr_groups[] = { + &phytium_ddr_pmu_v1v2_format_group, + &phytium_ddr_pmu_v1_events_group, + &phytium_ddr_pmu_cpumask_attr_group, + NULL, +}; + +static const struct attribute_group *phytium_ddr_pmu_v2_attr_groups[] = { + &phytium_ddr_pmu_v1v2_format_group, + &phytium_ddr_pmu_v2_events_group, + &phytium_ddr_pmu_cpumask_attr_group, + NULL, +}; + +static const struct attribute_group *phytium_ddr_pmu_v3_attr_groups[] = { + &phytium_ddr_pmu_v3_format_group, + &phytium_ddr_pmu_v3_events_group, &phytium_ddr_pmu_cpumask_attr_group, NULL, }; -static u64 phytium_ddr_pmu_read_counter(struct phytium_ddr_pmu *ddr_pmu, - struct hw_perf_event *hwc) +#if IS_ENABLED(CONFIG_ARM_PHYTIUM_DMU_DEVFREQ) +extern struct blocking_notifier_head dmu_pmu_notifier_chain; + +void phytium_ddr_pmu_v2_notifier_chain_trigger(struct phytium_ddr_pmu *ddr_pmu, int event) +{ + static bool start_flag; + + if ((event == DDR_PMUV2_NOTICE_START) && (start_flag == false)) { + blocking_notifier_call_chain(&dmu_pmu_notifier_chain, event, NULL); + start_flag = true; + ddr_pmu->used_flag = true; + } else if ((event == DDR_PMUV2_NOTICE_STOP) && (start_flag == true)) { + blocking_notifier_call_chain(&dmu_pmu_notifier_chain, event, NULL); + start_flag = false; + ddr_pmu->used_flag = false; + } +} +#endif + +static u64 phytium_ddr_pmu_v1_read_counter(struct phytium_ddr_pmu *ddr_pmu, + struct perf_event *event) { - u32 idx = GET_DDR_EVENTID(hwc); + struct hw_perf_event *hwc = &event->hw; + u32 idx = GET_DDR_PMUV1V2_EVENTID(hwc); u32 cycle_l, cycle_h, w_data, ddr_data_width; + u32 counter_offset = ddr_pmu_v1_counter_reg_offset[idx]; u64 val64 = 0; int i; - u32 counter_offset = ddr_counter_reg_offset[idx]; - if (!EVENT_VALID(idx)) { + if (!EVENT_VALID_V1(idx)) { dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); return 0; } @@ -230,7 +1021,7 @@ static u64 phytium_ddr_pmu_read_counter(struct phytium_ddr_pmu *ddr_pmu, val64 = (u64)cycle_h << 32 | (u64)cycle_l; break; case 7: - ddr_data_width = readl(ddr_pmu->base + DDR_DATA_WIDTH); + ddr_data_width = readl(ddr_pmu->base + DDR_PMUV1_DATA_WIDTH); for (i = 0; i < (ddr_data_width / 8); i++) { w_data = readl(ddr_pmu->base + counter_offset + 4 * i); val64 += w_data; @@ -244,11 +1035,99 @@ static u64 phytium_ddr_pmu_read_counter(struct phytium_ddr_pmu *ddr_pmu, return val64; } -static void phytium_ddr_pmu_enable_clk(struct phytium_ddr_pmu *ddr_pmu) +static u64 phytium_ddr_pmu_v2_read_counter(struct phytium_ddr_pmu *ddr_pmu, + struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + u32 val32_l, val32_h, idx, counter_offset; + u64 val64; + + idx = GET_DDR_PMUV1V2_EVENTID(hwc); + counter_offset = ddr_pmu_v2_counter_reg_offset[idx]; + + if (!EVENT_VALID_V2(idx)) { + dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); + return 0; + } + + val32_l = readl(ddr_pmu->base + counter_offset); + val32_h = readl(ddr_pmu->base + counter_offset + 4); + val64 = (u64)val32_h << 32 | (u64)val32_l; + + return val64; +} + +static u64 phytium_ddr_pmu_v3_read_counter(struct phytium_ddr_pmu *ddr_pmu, + struct perf_event *event) +{ + u32 evid, evtype, cntsize; + u32 cnt_offset, sel_offset, sel_mask; + u32 val32_l, val32_h; + u32 overflow_flag; + u64 val64; + int overflow_flag_bit; + unsigned long overflow_mask; + + evid = get_eventid(event); + evtype = get_type(event); + cntsize = get_cntsize(event); + val64 = 0; + switch (evtype) { + case DDR_PMUV3_SPECIAL_EVTYPE: + cnt_offset = phytium_ddr_pmu_v3_spec_cnt_reg_offset[evid]; + overflow_flag_bit = phytium_ddr_pmu_v3_spec_cnt_overflow_bit[evid]; + + overflow_mask = readl(ddr_pmu->base + DDR_PMUV3_CNT_OVERFLOW_FLAG); + if (overflow_flag_bit > 0) + overflow_flag = (u32)(overflow_mask & (1 << overflow_flag_bit)); + break; + default: + cnt_offset = phytium_ddr_pmu_v3_genc_cnt_reg_offset[evtype]; + sel_offset = phytium_ddr_pmu_v3_event_sel_reg_offset[evtype]; + sel_mask = phytium_ddr_pmu_v3_cnt_sel_mask_offset[evtype]; + overflow_flag_bit = phytium_ddr_pmu_v3_genc_cnt_overflow_bit[evtype]; + + if (evtype == DDR_PMUV3_MC_BANK_SRC_EVTYPE) + sel_mask &= (evid << 5); + else if (evtype == DDR_PMUV3_MC_T_CMD_SCHE_EVTYPE) + sel_mask &= (evid << 4); + else if (evtype == DDR_PMUV3_MC_T_RDWR_SWTICH_EVTYPE) + sel_mask &= (evid << 4); + else + sel_mask &= evid; + + writel(sel_mask, ddr_pmu->base + sel_offset); + + overflow_mask = readl(ddr_pmu->base + DDR_PMUV3_CNT_OVERFLOW_FLAG); + if (overflow_flag_bit > 0) + overflow_flag = (u32)(overflow_mask & (1 << overflow_flag_bit)); + + break; + } + + if (cntsize == 64) { + val32_l = readl(ddr_pmu->base + cnt_offset); + val32_h = readl(ddr_pmu->base + cnt_offset + 4); + val64 = (u64)val32_h << 32 | (u64)val32_l; + } else { + val32_l = readl(ddr_pmu->base + cnt_offset); + val64 = (u64)val32_l; + } + + if (overflow_flag == 1) { + dev_warn(ddr_pmu->dev, + "The Event(type=%u,eventid=%u) counter value has overflowed.\n", + evtype, evid); + return 0; + } + return val64; +} + +static void phytium_ddr_pmu_v1_enable_clk(struct phytium_ddr_pmu *ddr_pmu) { u32 val; - if (ddr_pmu->soc_version == PS240XX) + if (ddr_pmu->ver == DDR_PMUV1P5) return; val = readl(ddr_pmu->cfg_base); @@ -256,11 +1135,16 @@ static void phytium_ddr_pmu_enable_clk(struct phytium_ddr_pmu *ddr_pmu) writel(val, ddr_pmu->cfg_base); } -static void phytium_ddr_pmu_disable_clk(struct phytium_ddr_pmu *ddr_pmu) +static void phytium_ddr_pmu_v3_enable_clk(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(0x0, ddr_pmu->base + DDR_PMUV3_CLK_EN); +} + +static void phytium_ddr_pmu_v1_disable_clk(struct phytium_ddr_pmu *ddr_pmu) { u32 val; - if (ddr_pmu->soc_version == PS240XX) + if (ddr_pmu->ver == DDR_PMUV1P5) return; val = readl(ddr_pmu->cfg_base); @@ -268,32 +1152,80 @@ static void phytium_ddr_pmu_disable_clk(struct phytium_ddr_pmu *ddr_pmu) writel(val, ddr_pmu->cfg_base); } -static void phytium_ddr_pmu_clear_all_counters(struct phytium_ddr_pmu *ddr_pmu) +static void phytium_ddr_pmu_v3_disable_clk(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(0x1, ddr_pmu->base + DDR_PMUV3_CLK_EN); +} + +static void phytium_ddr_pmu_v3_snapshot_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(0x0, ddr_pmu->base + DDR_PMUV3_SNAPSHOT_PMU); + writel(BIT(0), ddr_pmu->base + DDR_PMUV3_SNAPSHOT_PMU); +} + +static void phytium_ddr_pmu_v1_clear_all_counters(struct phytium_ddr_pmu *ddr_pmu) { - writel(0x1, ddr_pmu->base + DDR_CLEAR_EVENT); + writel(0x1, ddr_pmu->base + DDR_PMUV1_CLEAR_EVENT); } -static void phytium_ddr_pmu_start_all_counters(struct phytium_ddr_pmu *ddr_pmu) +static void phytium_ddr_pmu_v2_clear_all_counters(struct phytium_ddr_pmu *ddr_pmu) { - writel(0x1, ddr_pmu->base + DDR_START_TIMER); + writel(0x1, ddr_pmu->base + DDR_PMUV2_CLEAR_EVENT); } -static void phytium_ddr_pmu_stop_all_counters(struct phytium_ddr_pmu *ddr_pmu) +static void phytium_ddr_pmu_v3_clear_all_counters(struct phytium_ddr_pmu *ddr_pmu) { - writel(0x1, ddr_pmu->base + DDR_STOP_TIMER); + writel(0x1, ddr_pmu->base + DDR_PMUV3_CLEAR_TIMER); + writel(0x0, ddr_pmu->base + DDR_PMUV3_CLEAR_TIMER); +} + +static void phytium_ddr_pmu_v1_start_all_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(0x1, ddr_pmu->base + DDR_PMUV1_START_TIMER); +} + +static void phytium_ddr_pmu_v2_start_all_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(BIT(0), ddr_pmu->base + DDR_PMUV2_TIMER_START); +} + +static void phytium_ddr_pmu_v3_start_all_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(BIT(0), ddr_pmu->base + DDR_PMUV3_START_TIMER); +} + +static void phytium_ddr_pmu_v1_stop_all_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(0x1, ddr_pmu->base + DDR_PMUV1_STOP_TIMER); +} + +static void phytium_ddr_pmu_v2_stop_all_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(BIT(0), ddr_pmu->base + DDR_PMUV2_TIMER_STOP); +} + +static void phytium_ddr_pmu_v3_stop_all_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(0x0, ddr_pmu->base + DDR_PMUV3_START_TIMER); +} + +static void phytium_ddr_pmu_v2_reset_timer(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(0xFFFFFFFF, ddr_pmu->base + DDR_PMUV2_SET_TIMER_L); + writel(0xFFFFFFFF, ddr_pmu->base + DDR_PMUV2_SET_TIMER_H); } static unsigned long -phytium_ddr_pmu_get_stop_state(struct phytium_ddr_pmu *ddr_pmu) +phytium_ddr_pmu_v1_get_stop_state(struct phytium_ddr_pmu *ddr_pmu) { unsigned long val; - val = (unsigned long)readl(ddr_pmu->base + DDR_STATE_STOP); + val = (unsigned long)readl(ddr_pmu->base + DDR_PMUV1_STATE_STOP); return val; } static unsigned long -phytium_ddr_pmu_get_irq_flag(struct phytium_ddr_pmu *ddr_pmu) +phytium_ddr_pmu_v1_get_irq_flag(struct phytium_ddr_pmu *ddr_pmu) { unsigned long val; @@ -301,13 +1233,63 @@ phytium_ddr_pmu_get_irq_flag(struct phytium_ddr_pmu *ddr_pmu) return val; } +static void phytium_ddr_pmu_v2_enable_events(struct phytium_ddr_pmu *ddr_pmu, int idx) +{ + u8 en_bit; + u32 en_offset, irq_offset, val; + + if (idx == 0) { + en_bit = 0; + en_offset = 0; + irq_offset = DDR_PMUV2_TIMER_INT_MASK; + } else { + en_bit = (idx - 1) * 8; + en_offset = DDR_PMUV2_AXI_MONITOR_EN; + irq_offset = DDR_PMUV2_AXI_MONITOR_INT_MASK; + } + + if (en_offset) { + val = readl(ddr_pmu->base + en_offset); + val |= BIT(en_bit); + writel(val, ddr_pmu->base + en_offset); + } + + val = readl(ddr_pmu->base + irq_offset); + val &= ~BIT(en_bit); + writel(val, ddr_pmu->base + irq_offset); +} + +static int phytium_ddr_pmu_v3_get_event_idx(struct perf_event *event) +{ + int i, idx; + u32 event_type, event_id; + + event_type = get_type(event); + event_id = get_eventid(event); + idx = 0; + + for (i = 0; i < event_type; i++) + idx += phytium_ddr_pmu_v3_event_num[i]; + + if (event_type < DDR_PMUV3_LPR_FIFO_OCCU_EVTYPE || event_type == DDR_PMUV3_SPECIAL_EVTYPE) + idx += event_id; + else + idx += (event_id % 3); + + return idx; +} + static int phytium_ddr_pmu_mark_event(struct perf_event *event) { struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(event->pmu); unsigned long *used_mask = ddr_pmu->pmu_events.used_mask; struct hw_perf_event *hwc = &event->hw; + int idx; - int idx = GET_DDR_EVENTID(hwc); + if (ddr_pmu->ver == DDR_PMUV3P0) + idx = phytium_ddr_pmu_v3_get_event_idx(event); + else + idx = GET_DDR_PMUV1V2_EVENTID(hwc); if (test_bit(idx, used_mask)) return -EAGAIN; @@ -317,15 +1299,199 @@ static int phytium_ddr_pmu_mark_event(struct perf_event *event) return idx; } -static void phytium_ddr_pmu_unmark_event(struct phytium_ddr_pmu *ddr_pmu, - int idx) +static void phytium_ddr_pmu_unmark_event(struct perf_event *event) { - if (!EVENT_VALID(idx)) { - dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); - return; + struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u32 idx = GET_DDR_PMUV1V2_EVENTID(hwc); + + if (ddr_pmu->ver <= DDR_PMUV1P5) { + if (!EVENT_VALID_V1(idx)) { + dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); + return; + } + } else if (ddr_pmu->ver == DDR_PMUV2P0) { + if (!EVENT_VALID_V2(idx)) { + dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); + return; + } + } else if (ddr_pmu->ver == DDR_PMUV3P0) { + if (!EVENT_VALID_V3(phytium_ddr_pmu_v3_get_event_idx(event))) { + dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); + return; + } + + int idx, i; + + u32 event_type, event_id; + + event_type = get_type(event); + event_id = get_eventid(event); + idx = 0; + + for (i = 0; i < event_type; i++) + idx += phytium_ddr_pmu_v3_event_num[i]; + + if (event_type < DDR_PMUV3_LPR_FIFO_OCCU_EVTYPE || + event_type == DDR_PMUV3_SPECIAL_EVTYPE) + idx += event_id; + else + idx += (event_id % 3); } clear_bit(idx, ddr_pmu->pmu_events.used_mask); + ddr_pmu->pmu_events.hw_events[hwc->idx] = NULL; +} + +static int phytium_ddr_pmu_v3_verify_port_occu_threshold(u32 low_thre, u32 hight_thre, + u32 *in_low_thre, u32 *in_hight_thre) +{ + if (((*in_low_thre) == 0) || ((*in_hight_thre) == 0)) { + *in_low_thre = low_thre; + *in_hight_thre = hight_thre; + } else if (((*in_low_thre) != low_thre) || ((*in_hight_thre) != hight_thre)) { + *in_low_thre = 0; + *in_hight_thre = 0; + return -EINVAL; + } + return 0; +} + +static int phytium_ddr_pmu_v3_get_port_occu_threshold(struct phytium_ddr_pmu *ddr_pmu, + struct perf_event *event) +{ + u32 low_thre, hight_thre, evtype; + u32 thre_reg_idx, thre_max_val; + int ret; + + low_thre = get_low_thre(event); + hight_thre = get_hight_thre(event); + evtype = get_type(event); + + thre_reg_idx = evtype - DDR_PMUV3_LPR_FIFO_OCCU_EVTYPE; + thre_max_val = (1 << phytium_ddr_pmu_v3_thre_bit_size[thre_reg_idx]) - 1; + + if ((hight_thre <= low_thre) || thre_max_val < low_thre) + return -EINVAL; + switch (evtype) { + case DDR_PMUV3_LPR_FIFO_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.lpr_fifo_low_thre, + &ddr_pmu->port_occu_thre.lpr_fifo_hight_thre); + break; + case DDR_PMUV3_HPR_FIFO_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.hpr_fifo_low_thre, + &ddr_pmu->port_occu_thre.hpr_fifo_hight_thre); + break; + case DDR_PMUV3_WR_DCQ_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.wr_dcq_low_thre, + &ddr_pmu->port_occu_thre.wr_dcq_hight_thre); + break; + case DDR_PMUV3_RDAT_INFO_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.rdat_info_low_thre, + &ddr_pmu->port_occu_thre.rdat_info_hight_thre); + break; + case DDR_PMUV3_RDAT_FIFO_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.rdat_fifo_low_thre, + &ddr_pmu->port_occu_thre.rdat_fifo_hight_thre); + break; + case DDR_PMUV3_WDP_BUFFER_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.wdp_buffer_low_thre, + &ddr_pmu->port_occu_thre.wdp_buffer_hight_thre); + break; + case DDR_PMUV3_RSP_COMP_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.rsp_comp_low_thre, + &ddr_pmu->port_occu_thre.rsp_comp_hight_thre); + break; + case DDR_PMUV3_RSP_DBID_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.rsp_dbid_low_thre, + &ddr_pmu->port_occu_thre.rsp_dbid_hight_thre); + break; + case DDR_PMUV3_RSP_CRQ_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.rsp_crq_low_thre, + &ddr_pmu->port_occu_thre.rsp_crq_hight_thre); + break; + case DDR_PMUV3_RSP_REQ_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.rsp_req_low_thre, + &ddr_pmu->port_occu_thre.rsp_req_hight_thre); + break; + case DDR_PMUV3_RSP_RTQ_OCCU_EVTYPE: + ret = phytium_ddr_pmu_v3_verify_port_occu_threshold(low_thre, hight_thre, + &ddr_pmu->port_occu_thre.rsp_rtq_low_thre, + &ddr_pmu->port_occu_thre.rsp_rtq_hight_thre); + break; + default: + ret = 0; + break; + } + + return ret; +} + +static void phytium_ddr_pmu_v3_set_port_occu_threshold(struct phytium_ddr_pmu *ddr_pmu, + u32 evtype, u32 low_thre, u32 hight_thre) +{ + u32 thre_reg_offset, thre_reg_idx, thre_bit_size; + u32 val; + + thre_reg_idx = evtype - DDR_PMUV3_LPR_FIFO_OCCU_EVTYPE; + thre_reg_offset = phytium_ddr_pmu_v3_thre_reg_offset[thre_reg_idx]; + thre_bit_size = phytium_ddr_pmu_v3_thre_bit_size[thre_reg_idx]; + + val = low_thre | (hight_thre << thre_bit_size); + + writel(val, ddr_pmu->base + thre_reg_offset); +} + +static void phytium_ddr_pmu_v3_reset_port_occu_threshold(struct phytium_ddr_pmu *ddr_pmu) +{ + u32 thre_reg_offset, thre_bit_size; + u32 val; + int i = 0; + + for (i = 0; i < 11; i++) { + thre_reg_offset = phytium_ddr_pmu_v3_thre_reg_offset[i]; + thre_bit_size = phytium_ddr_pmu_v3_thre_bit_size[i]; + + val = readl(ddr_pmu->base + thre_reg_offset); + val &= ~((1 << thre_bit_size) - 1); + writel(val, ddr_pmu->base + thre_reg_offset); + } + + ddr_pmu->port_occu_thre.lpr_fifo_low_thre = 0; + ddr_pmu->port_occu_thre.lpr_fifo_hight_thre = 0; + ddr_pmu->port_occu_thre.hpr_fifo_low_thre = 0; + ddr_pmu->port_occu_thre.hpr_fifo_hight_thre = 0; + ddr_pmu->port_occu_thre.wr_dcq_low_thre = 0; + ddr_pmu->port_occu_thre.wr_dcq_hight_thre = 0; + + ddr_pmu->port_occu_thre.rdat_info_low_thre = 0; + ddr_pmu->port_occu_thre.rdat_info_hight_thre = 0; + ddr_pmu->port_occu_thre.rdat_fifo_low_thre = 0; + ddr_pmu->port_occu_thre.rdat_fifo_hight_thre = 0; + ddr_pmu->port_occu_thre.wdp_buffer_low_thre = 0; + ddr_pmu->port_occu_thre.wdp_buffer_hight_thre = 0; + + ddr_pmu->port_occu_thre.rsp_comp_low_thre = 0; + ddr_pmu->port_occu_thre.rsp_comp_hight_thre = 0; + + ddr_pmu->port_occu_thre.rsp_dbid_low_thre = 0; + ddr_pmu->port_occu_thre.rsp_dbid_hight_thre = 0; + ddr_pmu->port_occu_thre.rsp_crq_low_thre = 0; + ddr_pmu->port_occu_thre.rsp_crq_hight_thre = 0; + ddr_pmu->port_occu_thre.rsp_req_low_thre = 0; + ddr_pmu->port_occu_thre.rsp_req_hight_thre = 0; + ddr_pmu->port_occu_thre.rsp_rtq_low_thre = 0; + ddr_pmu->port_occu_thre.rsp_rtq_hight_thre = 0; } int phytium_ddr_pmu_event_init(struct perf_event *event) @@ -346,8 +1512,13 @@ int phytium_ddr_pmu_event_init(struct perf_event *event) return -EINVAL; } - if (event->attr.config > PHYTIUM_DDR_MAX_COUNTERS) - return -EINVAL; + if (ddr_pmu->ver <= DDR_PMUV2P0) { + if ((event->attr.config & PHYTIUM_DDR_PMUV1V2_EVENTS_MAX_MASK) > ddr_pmu->cnts_num) + return -EINVAL; + } else if (ddr_pmu->ver == DDR_PMUV3P0) { + if ((event->attr.config & PHYTIUM_DDR_PMUV3_EVENTS_MAX_MASK) > ddr_pmu->cnts_num) + return -EINVAL; + } if (ddr_pmu->on_cpu == -1) return -EINVAL; @@ -357,16 +1528,48 @@ int phytium_ddr_pmu_event_init(struct perf_event *event) event->cpu = ddr_pmu->on_cpu; + if (ddr_pmu->ver == DDR_PMUV2P0) + used_event_v2 = 0; + else if (ddr_pmu->ver == DDR_PMUV3P0) { + int ret; + u32 event_type, occu_flag; + u32 low_thre, hight_thre; + int idx; + struct attribute *attr; + struct device_attribute *dev_attr; + struct phytium_ddr_pmu_v3_event_attr *eattr; + + event_type = get_type(event); + low_thre = get_low_thre(event); + hight_thre = get_hight_thre(event); + idx = phytium_ddr_pmu_v3_get_event_idx(event); + + attr = phytium_ddr_pmu_v3_events_attr[idx]; + dev_attr = container_of(attr, struct device_attribute, attr); + eattr = container_of(dev_attr, struct phytium_ddr_pmu_v3_event_attr, attr); + occu_flag = eattr->occuflag; + + if (phytium_ddr_pmu_v3_is_port_occup_event(event_type, occu_flag)) { + ret = phytium_ddr_pmu_v3_get_port_occu_threshold(ddr_pmu, event); + if (ret < 0) + return ret; + phytium_ddr_pmu_v3_set_port_occu_threshold(ddr_pmu, event_type, low_thre, + hight_thre); + } + } + return 0; } void phytium_ddr_pmu_event_update(struct perf_event *event) { struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; u64 delta; - delta = phytium_ddr_pmu_read_counter(ddr_pmu, hwc); + if (ddr_pmu->ver == DDR_PMUV2P0) + ddr_pmu->ops->stop_all_counters(ddr_pmu); + + delta = ddr_pmu->ops->read_counter(ddr_pmu, event); local64_add(delta, &event->count); } @@ -397,105 +1600,304 @@ int phytium_ddr_pmu_event_add(struct perf_event *event, int flags) hwc->state |= PERF_HES_STOPPED; idx = phytium_ddr_pmu_mark_event(event); - if (idx < 0) - return idx; - + if (ddr_pmu->ver <= DDR_PMUV1P5) { + if (!EVENT_VALID_V1(idx)) { + dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); + return idx; + } + } else if (ddr_pmu->ver == DDR_PMUV2P0) { + if (!EVENT_VALID_V2(idx)) { + dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); + return idx; + } + #if IS_ENABLED(CONFIG_ARM_PHYTIUM_DMU_DEVFREQ) + phytium_ddr_pmu_v2_notifier_chain_trigger(ddr_pmu, DDR_PMUV2_NOTICE_START); + #endif + } else if (ddr_pmu->ver == DDR_PMUV3P0) { + if (!EVENT_VALID_V3(phytium_ddr_pmu_v3_get_event_idx(event))) { + dev_err(ddr_pmu->dev, "Unsupported event index:%d!\n", idx); + return idx; + } + } event->hw.idx = idx; ddr_pmu->pmu_events.hw_events[idx] = event; + if (ddr_pmu->ver == DDR_PMUV2P0) { + phytium_ddr_pmu_v2_enable_events(ddr_pmu, idx); + used_event_v2 += 1; + } return 0; } void phytium_ddr_pmu_event_del(struct perf_event *event, int flags) { struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - unsigned long val; + + if (ddr_pmu->ver == DDR_PMUV2P0) + used_event_v2 -= 1; phytium_ddr_pmu_event_stop(event, PERF_EF_UPDATE); - val = phytium_ddr_pmu_get_irq_flag(ddr_pmu); - val = phytium_ddr_pmu_get_stop_state(ddr_pmu); - phytium_ddr_pmu_unmark_event(ddr_pmu, hwc->idx); + + if (ddr_pmu->ver == DDR_PMUV3P0) + phytium_ddr_pmu_v3_reset_port_occu_threshold(ddr_pmu); + + phytium_ddr_pmu_unmark_event(event); perf_event_update_userpage(event); - ddr_pmu->pmu_events.hw_events[hwc->idx] = NULL; + + if (ddr_pmu->ver == DDR_PMUV2P0) { +#if IS_ENABLED(CONFIG_ARM_PHYTIUM_DMU_DEVFREQ) + if (used_event_v2 == 0) + phytium_ddr_pmu_v2_notifier_chain_trigger(ddr_pmu, DDR_PMUV2_NOTICE_STOP); +#endif + } +} + +void phytium_ddr_pmu_v1_enable_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + ddr_pmu->ops->clear_all_counters(ddr_pmu); + ddr_pmu->ops->start_all_counters(ddr_pmu); +} + +void phytium_ddr_pmu_v2_enable_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + ddr_pmu->ops->stop_all_counters(ddr_pmu); + ddr_pmu->ops->clear_all_counters(ddr_pmu); + phytium_ddr_pmu_v2_reset_timer(ddr_pmu); + ddr_pmu->ops->start_all_counters(ddr_pmu); +} + +void phytium_ddr_pmu_v3_enable_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + ddr_pmu->ops->enable_clk(ddr_pmu); + ddr_pmu->ops->clear_all_counters(ddr_pmu); + ddr_pmu->ops->start_all_counters(ddr_pmu); } void phytium_ddr_pmu_enable(struct pmu *pmu) { struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(pmu); int event_added = bitmap_weight(ddr_pmu->pmu_events.used_mask, - PHYTIUM_DDR_MAX_COUNTERS); + ddr_pmu->cnts_num); if (event_added) { - phytium_ddr_pmu_clear_all_counters(ddr_pmu); - phytium_ddr_pmu_start_all_counters(ddr_pmu); + ddr_pmu->ops->enable_counters(ddr_pmu); } } +static void phytium_ddr_pmu_v2_mask_all_irq(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(DDR_PMUV2_TIMER_OPT_BIT, ddr_pmu->base + DDR_PMUV2_TIMER_INT_MASK); + writel(DDR_PMUV2_AXI_MONITOR_OPT_BIT, ddr_pmu->base + DDR_PMUV2_AXI_MONITOR_INT_MASK); +} + +static void phytium_ddr_pmu_v2_disable_axi_cmd_events(struct phytium_ddr_pmu *ddr_pmu) +{ + writel(0x0, ddr_pmu->base + DDR_PMUV2_AXI_MONITOR_EN); +} + +void phytium_ddr_pmu_v1_disable_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + ddr_pmu->ops->stop_all_counters(ddr_pmu); +} + +void phytium_ddr_pmu_v2_disable_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + if (ddr_pmu->used_flag) { + phytium_ddr_pmu_v2_mask_all_irq(ddr_pmu); + phytium_ddr_pmu_v2_disable_axi_cmd_events(ddr_pmu); + } +} + +void phytium_ddr_pmu_v3_disable_counters(struct phytium_ddr_pmu *ddr_pmu) +{ + ddr_pmu->ops->stop_all_counters(ddr_pmu); + phytium_ddr_pmu_v3_snapshot_counters(ddr_pmu); +} + void phytium_ddr_pmu_disable(struct pmu *pmu) { struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(pmu); int event_added = bitmap_weight(ddr_pmu->pmu_events.used_mask, - PHYTIUM_DDR_MAX_COUNTERS); + ddr_pmu->cnts_num); if (event_added) - phytium_ddr_pmu_stop_all_counters(ddr_pmu); + ddr_pmu->ops->disable_counters(ddr_pmu); } -void phytium_ddr_pmu_reset(struct phytium_ddr_pmu *ddr_pmu) +void phytium_ddr_pmu_v1_reset(struct phytium_ddr_pmu *ddr_pmu) { - phytium_ddr_pmu_disable_clk(ddr_pmu); - phytium_ddr_pmu_clear_all_counters(ddr_pmu); + ddr_pmu->ops->disable_clk(ddr_pmu); + ddr_pmu->ops->clear_all_counters(ddr_pmu); } static const struct acpi_device_id phytium_ddr_pmu_acpi_match[] = { - { - "PHYT0043", - }, + { "PHYT0043", }, + { "PHYT0067", }, + { "PHYT0069", }, {}, }; MODULE_DEVICE_TABLE(acpi, phytium_ddr_pmu_acpi_match); -static irqreturn_t phytium_ddr_pmu_overflow_handler(int irq, void *dev_id) +static irqreturn_t phytium_ddr_pmu_v1_overflow_handler(int irq, void *dev_id) { struct phytium_ddr_pmu *ddr_pmu = dev_id; struct perf_event *event; unsigned long overflown, stop_state; unsigned long *used_mask = ddr_pmu->pmu_events.used_mask; int idx; - int event_added = bitmap_weight(used_mask, PHYTIUM_DDR_MAX_COUNTERS); + int event_added = bitmap_weight(used_mask, ddr_pmu->cnts_num); - overflown = phytium_ddr_pmu_get_irq_flag(ddr_pmu); + overflown = phytium_ddr_pmu_v1_get_irq_flag(ddr_pmu); if (!test_bit(ddr_pmu->irq_bit, &overflown)) return IRQ_NONE; - stop_state = phytium_ddr_pmu_get_stop_state(ddr_pmu); + stop_state = phytium_ddr_pmu_v1_get_stop_state(ddr_pmu); if (bitmap_weight(&stop_state, 6)) { - for_each_set_bit(idx, used_mask, PHYTIUM_DDR_MAX_COUNTERS) { + for_each_set_bit(idx, used_mask, ddr_pmu->cnts_num) { event = ddr_pmu->pmu_events.hw_events[idx]; if (!event) continue; phytium_ddr_pmu_event_update(event); } - phytium_ddr_pmu_clear_all_counters(ddr_pmu); - if ((stop_state & DDR_PMU_OFL_STOP_TYPE_VAL) == 0) - phytium_ddr_pmu_start_all_counters(ddr_pmu); + ddr_pmu->ops->clear_all_counters(ddr_pmu); + if ((stop_state & DDR_PMUV1_OFL_STOP_TYPE_VAL) == 0) + ddr_pmu->ops->start_all_counters(ddr_pmu); return IRQ_HANDLED; } if (!event_added) { - phytium_ddr_pmu_clear_all_counters(ddr_pmu); + ddr_pmu->ops->clear_all_counters(ddr_pmu); return IRQ_HANDLED; } return IRQ_NONE; } +static irqreturn_t phytium_ddr_pmu_v2_overflow_handler(int irq, void *dev_id) +{ + struct phytium_ddr_pmu *ddr_pmu = dev_id; + struct perf_event *event; + int idx; + unsigned long *used_mask = ddr_pmu->pmu_events.used_mask; + u32 timer_int_sta, axi_int_sta; + + timer_int_sta = readl(ddr_pmu->base + DDR_PMUV2_TIMER_INT_STA); + axi_int_sta = readl(ddr_pmu->base + DDR_PMUV2_AXI_MONITOR_INT_STA); + + if ((timer_int_sta + axi_int_sta) == 0) + return IRQ_NONE; + + if (timer_int_sta) + writel(0x1, ddr_pmu->base + DDR_PMUV2_TIMER_INT_CLEAR); + + if (axi_int_sta) + writel(axi_int_sta, ddr_pmu->base + ddr_pmu->cnts_num); + + if (!ddr_pmu->used_flag) { + phytium_ddr_pmu_v2_mask_all_irq(ddr_pmu); + return IRQ_HANDLED; + } + + for_each_set_bit(idx, used_mask, PHYTIUM_DDR_PMUV2_COUNTERS_NUM) { + event = ddr_pmu->pmu_events.hw_events[idx]; + if (!event) + continue; + phytium_ddr_pmu_event_update(event); + } + writel(DDR_PMUV2_ALL_EVENT_CLEAR_BIT, ddr_pmu->base + DDR_PMUV2_CLEAR_EVENT); + ddr_pmu->ops->start_all_counters(ddr_pmu); + + return IRQ_HANDLED; +} + +static const struct phytium_ddr_pmu_ops phytium_ddr_pmu_v1_ops = { + .overflow_handler = phytium_ddr_pmu_v1_overflow_handler, + .read_counter = phytium_ddr_pmu_v1_read_counter, + .clear_all_counters = phytium_ddr_pmu_v1_clear_all_counters, + .start_all_counters = phytium_ddr_pmu_v1_start_all_counters, + .stop_all_counters = phytium_ddr_pmu_v1_stop_all_counters, + .enable_counters = phytium_ddr_pmu_v1_enable_counters, + .disable_counters = phytium_ddr_pmu_v1_disable_counters, + .enable_clk = phytium_ddr_pmu_v1_enable_clk, + .disable_clk = phytium_ddr_pmu_v1_disable_clk, +}; + +static const struct phytium_ddr_pmu_ops phytium_ddr_pmu_v2_ops = { + .overflow_handler = phytium_ddr_pmu_v2_overflow_handler, + .read_counter = phytium_ddr_pmu_v2_read_counter, + .clear_all_counters = phytium_ddr_pmu_v2_clear_all_counters, + .start_all_counters = phytium_ddr_pmu_v2_start_all_counters, + .stop_all_counters = phytium_ddr_pmu_v2_stop_all_counters, + .enable_counters = phytium_ddr_pmu_v2_enable_counters, + .disable_counters = phytium_ddr_pmu_v2_disable_counters, +}; + +static const struct phytium_ddr_pmu_ops phytium_ddr_pmu_v3_ops = { + .read_counter = phytium_ddr_pmu_v3_read_counter, + .clear_all_counters = phytium_ddr_pmu_v3_clear_all_counters, + .start_all_counters = phytium_ddr_pmu_v3_start_all_counters, + .stop_all_counters = phytium_ddr_pmu_v3_stop_all_counters, + .enable_clk = phytium_ddr_pmu_v3_enable_clk, + .disable_clk = phytium_ddr_pmu_v3_disable_clk, + .enable_counters = phytium_ddr_pmu_v3_enable_counters, + .disable_counters = phytium_ddr_pmu_v3_disable_counters, +}; + +static int phytium_ddr_pmu_v1_verify_pbf_version(struct platform_device *pdev) +{ + struct arm_smccc_res res; + unsigned long major_ver, minor_ver; + + arm_smccc_smc(PBFVER_FUNC_ID, 0, 0, 0, 0, 0, 0, 0, &res); + if (res.a0 <= 0) { + dev_warn(&pdev->dev, "Can not recognize PBF Firmware version!\n"); + return -EINVAL; + } + + minor_ver = res.a0 & 0xFFFF; + major_ver = (res.a0 >> 16) & 0xFFFF; + + if (major_ver < 1 || (major_ver == 1 && minor_ver < 20)) { + dev_err(&pdev->dev, + "Driver load failed, Please upgrade PBF Firmware version to 1.20 or later!\n"); + return -EINVAL; + } + + return 0; + +} + +static int phytium_ddr_pmu_version(struct platform_device *pdev, + struct phytium_ddr_pmu *ddr_pmu) +{ + struct acpi_device *acpi_dev; + + acpi_dev = ACPI_COMPANION(&pdev->dev); + if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0043")) { + ddr_pmu->ver = DDR_PMUV1P0; + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0067")) { + ddr_pmu->ver = DDR_PMUV1P5; + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0069")) { + ddr_pmu->ver = DDR_PMUV2P0; + #if !IS_ENABLED(CONFIG_PHYT_DMU_PMU_PD2408) + dev_err(&pdev->dev, "CONFIG_PHYT_DMU_PMU_PD2408 not enabled\n"); + return -ENODEV; + #endif + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT3003")) { + ddr_pmu->ver = DDR_PMUV3P0; + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + } + + return 0; +} + static int phytium_ddr_pmu_init_irq(struct phytium_ddr_pmu *ddr_pmu, struct platform_device *pdev) { @@ -506,9 +1908,10 @@ static int phytium_ddr_pmu_init_irq(struct phytium_ddr_pmu *ddr_pmu, return irq; ret = devm_request_irq(&pdev->dev, irq, - phytium_ddr_pmu_overflow_handler, + ddr_pmu->ops->overflow_handler, IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_SHARED, dev_name(&pdev->dev), ddr_pmu); + if (ret < 0) { dev_err(&pdev->dev, "Fail to request IRQ:%d ret:%d\n", irq, ret); @@ -520,39 +1923,29 @@ static int phytium_ddr_pmu_init_irq(struct phytium_ddr_pmu *ddr_pmu, return 0; } -static int phytium_ddr_pmu_init_data(struct platform_device *pdev, +static int phytium_ddr_pmu_v1_init_data(struct platform_device *pdev, struct phytium_ddr_pmu *ddr_pmu) { struct resource *res, *clkres, *irqres; - ddr_pmu->soc_version = phytium_socs_type(); - - - if (ddr_pmu->soc_version == 0) { - dev_err(&pdev->dev, "The DDR PMU driver can't be installed in this SoC!\n"); - return -EINVAL; - } - if (device_property_read_u32(&pdev->dev, "phytium,die-id", - &ddr_pmu->die_id)) { + &ddr_pmu->die_id)) { dev_err(&pdev->dev, "Can not read phytium,die-id!\n"); return -EINVAL; } if (device_property_read_u32(&pdev->dev, "phytium,ddr-id", - &ddr_pmu->ddr_id)) { + &ddr_pmu->ddr_id)) { dev_err(&pdev->dev, "Can not read phytium,ddr-id!\n"); return -EINVAL; } if (device_property_read_u32(&pdev->dev, "phytium,pmu-id", - &ddr_pmu->pmu_id)) { + &ddr_pmu->pmu_id)) { dev_err(&pdev->dev, "Can not read ddr pmu-id!\n"); return -EINVAL; } - ddr_pmu->irq_bit = ddr_pmu->ddr_id * 2 + ddr_pmu->pmu_id; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ddr_pmu->base = devm_ioremap_resource(&pdev->dev, res); @@ -562,24 +1955,28 @@ static int phytium_ddr_pmu_init_data(struct platform_device *pdev, return PTR_ERR(ddr_pmu->base); } + ddr_pmu->irq_bit = ddr_pmu->ddr_id * 2 + ddr_pmu->pmu_id; + clkres = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!clkres) { dev_err(&pdev->dev, "failed for get ddr_pmu clk resource.\n"); return -EINVAL; } - ddr_pmu->cfg_base = devm_ioremap(&pdev->dev, clkres->start, resource_size(clkres)); + ddr_pmu->cfg_base = devm_ioremap(&pdev->dev, clkres->start, + resource_size(clkres)); if (IS_ERR(ddr_pmu->cfg_base)) { dev_err(&pdev->dev, "ioremap failed for ddr_pmu clk resource\n"); return PTR_ERR(ddr_pmu->cfg_base); } - if (ddr_pmu->soc_version == PS240XX) { + if (ddr_pmu->ver == DDR_PMUV1P5) { irqres = platform_get_resource(pdev, IORESOURCE_MEM, 2); if (!irqres) { dev_err(&pdev->dev, "failed for get ddr_pmu irq resource.\n"); return -EINVAL; } - ddr_pmu->irq_reg = devm_ioremap(&pdev->dev, irqres->start, resource_size(irqres)); + ddr_pmu->irq_reg = devm_ioremap(&pdev->dev, irqres->start, + resource_size(irqres)); if (IS_ERR(ddr_pmu->irq_reg)) { dev_err(&pdev->dev, "ioremap failed for ddr_pmu irq resource\n"); return PTR_ERR(ddr_pmu->irq_reg); @@ -588,7 +1985,77 @@ static int phytium_ddr_pmu_init_data(struct platform_device *pdev, ddr_pmu->irq_reg = ddr_pmu->cfg_base + 0x4; } - phytium_ddr_pmu_reset(ddr_pmu); + ddr_pmu->cnts_num = PHYTIUM_DDR_PMUV1_COUNTERS_NUM; + ddr_pmu->ops = &phytium_ddr_pmu_v1_ops; + + phytium_ddr_pmu_v1_reset(ddr_pmu); + + return 0; +} + +static int phytium_ddr_pmu_v2_init_data(struct platform_device *pdev, + struct phytium_ddr_pmu *ddr_pmu) +{ + struct resource *res; + + if (device_property_read_u32(&pdev->dev, "phytium,ddr-id", + &ddr_pmu->ddr_id)) { + dev_err(&pdev->dev, "Can not read phytium,ddr-id!\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ddr_pmu->base = devm_ioremap_resource(&pdev->dev, res); + + if (IS_ERR(ddr_pmu->base)) { + dev_err(&pdev->dev, + "ioremap failed for ddr_pmu base resource\n"); + return PTR_ERR(ddr_pmu->base); + } + + ddr_pmu->used_flag = true; + phytium_ddr_pmu_v2_mask_all_irq(ddr_pmu); + + ddr_pmu->cnts_num = PHYTIUM_DDR_PMUV2_COUNTERS_NUM; + ddr_pmu->ops = &phytium_ddr_pmu_v2_ops; + + return 0; +} + +static int phytium_ddr_pmu_v3_init_data(struct platform_device *pdev, + struct phytium_ddr_pmu *ddr_pmu) +{ + struct resource *res; + + if (device_property_read_u32(&pdev->dev, "phytium,die-id", + &ddr_pmu->die_id)) { + dev_err(&pdev->dev, "Can not read phytium,die-id!\n"); + return -EINVAL; + } + + if (device_property_read_u32(&pdev->dev, "phytium,ddr-id", + &ddr_pmu->ddr_id)) { + dev_err(&pdev->dev, "Can not read phytium,ddr-id!\n"); + return -EINVAL; + } + + if (device_property_read_u32(&pdev->dev, "phytium,pmu-id", + &ddr_pmu->pmu_id)) { + dev_err(&pdev->dev, "Can not read ddr pmu-id!\n"); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ddr_pmu->base = devm_ioremap_resource(&pdev->dev, res); + + if (IS_ERR(ddr_pmu->base)) { + dev_err(&pdev->dev, + "ioremap failed for ddr_pmu base resource\n"); + return PTR_ERR(ddr_pmu->base); + } + + ddr_pmu->cnts_num = PHYTIUM_DDR_PMUV3_COUNTERS_NUM; + ddr_pmu->ops = &phytium_ddr_pmu_v3_ops; return 0; } @@ -598,14 +2065,31 @@ static int phytium_ddr_pmu_dev_probe(struct platform_device *pdev, { int ret; - ret = phytium_ddr_pmu_init_data(pdev, ddr_pmu); + ret = phytium_ddr_pmu_version(pdev, ddr_pmu); if (ret) return ret; - ret = phytium_ddr_pmu_init_irq(ddr_pmu, pdev); + if (ddr_pmu->ver == DDR_PMUV1P0) { + ret = phytium_ddr_pmu_v1_verify_pbf_version(pdev); + if (ret) + return ret; + } + + if (ddr_pmu->ver <= DDR_PMUV1P5) + ret = phytium_ddr_pmu_v1_init_data(pdev, ddr_pmu); + else if (ddr_pmu->ver == DDR_PMUV2P0) + ret = phytium_ddr_pmu_v2_init_data(pdev, ddr_pmu); + else if (ddr_pmu->ver == DDR_PMUV3P0) + ret = phytium_ddr_pmu_v3_init_data(pdev, ddr_pmu); if (ret) return ret; + if (ddr_pmu->ver <= DDR_PMUV2P0) { + ret = phytium_ddr_pmu_init_irq(ddr_pmu, pdev); + if (ret) + return ret; + } + ddr_pmu->dev = &pdev->dev; ddr_pmu->on_cpu = -1; @@ -635,9 +2119,13 @@ static int phytium_ddr_pmu_probe(struct platform_device *pdev) return ret; } - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_ddr%u_pmu%u", - ddr_pmu->die_id, ddr_pmu->ddr_id, - ddr_pmu->pmu_id); + if (ddr_pmu->ver == DDR_PMUV2P0) + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt_ddr%u_pmu", + ddr_pmu->ddr_id); + else + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_ddr%u_pmu%u", + ddr_pmu->die_id, ddr_pmu->ddr_id, + ddr_pmu->pmu_id); ddr_pmu->pmu = (struct pmu){ .name = name, .module = THIS_MODULE, @@ -650,9 +2138,24 @@ static int phytium_ddr_pmu_probe(struct platform_device *pdev) .start = phytium_ddr_pmu_event_start, .stop = phytium_ddr_pmu_event_stop, .read = phytium_ddr_pmu_event_update, - .attr_groups = phytium_ddr_pmu_attr_groups, }; + if (ddr_pmu->ver == DDR_PMUV2P0) { + ddr_pmu->pmu.attr_groups = phytium_ddr_pmu_v2_attr_groups; + dev_info(ddr_pmu->dev, "%s on cpu%d.\n", + name, ddr_pmu->on_cpu); + } else { + if (ddr_pmu->ver <= DDR_PMUV1P5) + ddr_pmu->pmu.attr_groups = phytium_ddr_pmu_v1_attr_groups; + else if (ddr_pmu->ver == DDR_PMUV3P0) + ddr_pmu->pmu.attr_groups = phytium_ddr_pmu_v3_attr_groups; + + ddr_pmu->ops->enable_clk(ddr_pmu); + + dev_info(ddr_pmu->dev, "die%d_ddr%d_pmu%d on cpu%d.\n", ddr_pmu->die_id, + ddr_pmu->ddr_id, ddr_pmu->pmu_id, ddr_pmu->on_cpu); + } + ret = perf_pmu_register(&ddr_pmu->pmu, name, -1); if (ret) { dev_err(ddr_pmu->dev, "DDR PMU register failed!\n"); @@ -660,11 +2163,6 @@ static int phytium_ddr_pmu_probe(struct platform_device *pdev) &ddr_pmu->node); } - phytium_ddr_pmu_enable_clk(ddr_pmu); - - pr_info("die%d_ddr%d_pmu%d on cpu%d.\n", ddr_pmu->die_id, - ddr_pmu->ddr_id, ddr_pmu->pmu_id, ddr_pmu->on_cpu); - return ret; } @@ -672,7 +2170,10 @@ static int phytium_ddr_pmu_remove(struct platform_device *pdev) { struct phytium_ddr_pmu *ddr_pmu = platform_get_drvdata(pdev); - phytium_ddr_pmu_disable_clk(ddr_pmu); + if (ddr_pmu->ver <= DDR_PMUV1P5 || ddr_pmu->ver == DDR_PMUV3P0) + ddr_pmu->ops->disable_clk(ddr_pmu); + else if (ddr_pmu->ver == DDR_PMUV2P0) + phytium_ddr_pmu_v2_mask_all_irq(ddr_pmu); perf_pmu_unregister(&ddr_pmu->pmu); cpuhp_state_remove_instance_nocalls(phytium_ddr_pmu_hp_state, @@ -779,3 +2280,4 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DDR_PERF_DRIVER_VERSION); MODULE_AUTHOR("Hu Xianghua "); MODULE_AUTHOR("Tan Rui "); +MODULE_AUTHOR("Fu Boyi "); diff --git a/drivers/perf/phytium/phytium_msi_pmu.c b/drivers/perf/phytium/phytium_msi_pmu.c new file mode 100644 index 0000000000000..5b73a35ad6bbc --- /dev/null +++ b/drivers/perf/phytium/phytium_msi_pmu.c @@ -0,0 +1,1206 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Phytium SoC MSI performance monitoring unit support + * + * Copyright (c) 2025, Phytium Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "phytium_msi_pmu: " fmt + +#define MISC_PERF_DRIVER_VERSION "1.0.0" + +#define PHYTIUM_MISC_MAX_COUNTERS 15 +#define PHYTIUM_MSI_PMU_EVENT_MASK 0xF + +#define MISC_MSI_MON_CLR_REG 0x1F8 +#define MISC_MSI_MON_CLKEN_REG 0x1FC +#define MISC_MSI_MON_STOP_REG 0x200 +#define MISC_MSI_MON_START_REG 0x204 +#define MISC_MSI_MON_OPT_MASK GENMASK(2, 0) +#define MISC_PCIE0_MSI_MON_OPT_BIT BIT(2) +#define MISC_PCIE1_MSI_MON_OPT_BIT BIT(1) +#define MISC_PCIE2_MSI_MON_OPT_BIT BIT(0) + +#define MISC_PCIE0_MON_SET_TIME_H 0x208 +#define MISC_PCIE0_MON_SET_TIME_L 0x20C +#define MISC_PCIE1_MON_SET_TIME_H 0x210 +#define MISC_PCIE1_MON_SET_TIME_L 0x214 +#define MISC_PCIE2_MON_SET_TIME_H 0x218 +#define MISC_PCIE2_MON_SET_TIME_L 0x21C + +#define MISC_MSI_MON_MODE 0x220 +#define MISC_MSI_MON_MODE_MASK 0x15 +#define MISC_PCIE0_MSI_BYREQID_MODE_BIT BIT(0) +#define MISC_PCIE1_MSI_BYREQID_MODE_BIT BIT(2) +#define MISC_PCIE2_MSI_BYREQID_MODE_BIT BIT(4) +#define MISC_MSI_MON_TRIG_MODE_MASK 0x2A +#define MISC_PCIE0_MSI_TRIG_MODE_BIT BIT(1) +#define MISC_PCIE1_MSI_TRIG_MODE_BIT BIT(3) +#define MISC_PCIE2_MSI_TRIG_MODE_BIT BIT(5) + +#define MISC_PCIE0_MSI_REG_ID_CFG_REG_23 0x250 +#define MISC_PCIE0_MSI_REG_ID_CFG_REG_01 0x254 +#define MISC_PCIE1_MSI_REG_ID_CFG_REG_23 0x258 +#define MISC_PCIE1_MSI_REG_ID_CFG_REG_01 0x25C +#define MISC_PCIE2_MSI_REG_ID_CFG_REG_23 0x260 +#define MISC_PCIE2_MSI_REG_ID_CFG_REG_01 0x264 +#define MISC_MSI_MON_STATE 0x268 + +#define MISC_MSI_MON_STATE_STOP 0x284 +#define MISC_PCIE0_MON_STATE_STOP_MASK GENMASK(13, 12) +#define MISC_PCIE1_MON_STATE_STOP_MASK GENMASK(5, 4) +#define MISC_PCIE2_MON_STATE_STOP_MASK GENMASK(1, 0) +#define MISC_MSI_MON_OVFL_STATE_MASK 0x2 +#define MISC_MSI_MON_COUNT_FULL_MASK 0x2022 + +#define MISC_PCIE0_REQ_ID_RECORD_23 0x224 +#define MISC_PCIE0_REQ_ID_RECORD_01 0x228 +#define MISC_PCIE0_REQ_ID_CNT 0x22C + +#define MISC_PCIE1_REQ_ID_RECORD_23 0x230 +#define MISC_PCIE1_REQ_ID_RECORD_01 0x234 +#define MISC_PCIE1_REQ_ID_CNT 0x238 + +#define MISC_PCIE2_REQ_ID_RECORD_23 0x23C +#define MISC_PCIE2_REQ_ID_RECORD_01 0x240 +#define MISC_PCIE2_REQ_ID_CNT 0x24C + +#define MISC_PCIE0_MON_TPOINT_END_H 0x26C +#define MISC_PCIE0_MON_TPOINT_END_L 0x270 +#define MISC_PCIE1_MON_TPOINT_END_H 0x274 +#define MISC_PCIE1_MON_TPOINT_END_L 0x278 +#define MISC_PCIE2_MON_TPOINT_END_H 0x27C +#define MISC_PCIE2_MON_TPOINT_END_L 0x280 + +#define MISC_MON_PIDR0 0xFE0 +#define MISC_PMU_VER_BIT GENMASK(7, 0) +#define MISC_PMU_PART_BIT GENMASK(11, 8) + +#define to_phytium_msi_pmu(p) (container_of(p, struct phytium_msi_pmu, pmu)) + +static int phytium_msi_pmu_hp_state; + +enum { + MISCV1P0 = 0x01, +}; + +struct phytium_msi_pmu_hwevents { + struct perf_event *hw_events[PHYTIUM_MISC_MAX_COUNTERS]; + DECLARE_BITMAP(used_mask, PHYTIUM_MISC_MAX_COUNTERS); + DECLARE_BITMAP(dev_mask, 3); +}; + +struct phytium_msi_pmu_event_cfg { + int by_timer; + int trig_mode; + int pcie0_by_reqid; + int pcie1_by_reqid; + int pcie2_by_reqid; + int pcie0_reqid0; + int pcie0_reqid1; + int pcie0_reqid2; + int pcie0_reqid3; + int pcie1_reqid0; + int pcie1_reqid1; + int pcie1_reqid2; + int pcie1_reqid3; + int pcie2_reqid0; + int pcie2_reqid1; + int pcie2_reqid2; + int pcie2_reqid3; + u64 timer; +}; + +struct phytium_msi_pmu { + struct device *dev; + void __iomem *base; + struct pmu pmu; + struct phytium_msi_pmu_hwevents pmu_events; + struct phytium_msi_pmu_event_cfg event_cfg; + struct hlist_node node; + u32 die_id; + u32 ver; + int on_cpu; + int irq; +}; + +#define GET_MISC_EVENTID(hwc) (hwc->config_base & PHYTIUM_MSI_PMU_EVENT_MASK) +#define EVENT_VALID(idx) ((idx >= 0) && (idx < PHYTIUM_MISC_MAX_COUNTERS)) + +static const u32 misc_counter_reg_offset[] = { + MISC_PCIE0_REQ_ID_CNT, MISC_PCIE0_REQ_ID_CNT, MISC_PCIE0_REQ_ID_CNT, + MISC_PCIE0_REQ_ID_CNT, MISC_PCIE0_MON_TPOINT_END_H, + MISC_PCIE1_REQ_ID_CNT, MISC_PCIE1_REQ_ID_CNT, MISC_PCIE1_REQ_ID_CNT, + MISC_PCIE1_REQ_ID_CNT, MISC_PCIE1_MON_TPOINT_END_H, + MISC_PCIE2_REQ_ID_CNT, MISC_PCIE2_REQ_ID_CNT, MISC_PCIE2_REQ_ID_CNT, + MISC_PCIE2_REQ_ID_CNT, MISC_PCIE2_MON_TPOINT_END_H +}; + +static const u32 misc_reqid_record_reg_offset[] = { + MISC_PCIE0_REQ_ID_RECORD_01, MISC_PCIE0_REQ_ID_RECORD_01, + MISC_PCIE0_REQ_ID_RECORD_23, MISC_PCIE0_REQ_ID_RECORD_23, 0, + MISC_PCIE1_REQ_ID_RECORD_01, MISC_PCIE1_REQ_ID_RECORD_01, + MISC_PCIE2_REQ_ID_RECORD_01, MISC_PCIE2_REQ_ID_RECORD_01, 0, + MISC_PCIE1_REQ_ID_RECORD_23, MISC_PCIE1_REQ_ID_RECORD_23, + MISC_PCIE2_REQ_ID_RECORD_23, MISC_PCIE2_REQ_ID_RECORD_23, 0 +}; + +static const unsigned long pcie_dev_msi_mon_stop_mask[] = { + MISC_PCIE0_MON_STATE_STOP_MASK, + MISC_PCIE1_MON_STATE_STOP_MASK, + MISC_PCIE2_MON_STATE_STOP_MASK +}; + +static const unsigned long pcie_dev_msi_mon_opt_bits[] = { + MISC_PCIE0_MSI_MON_OPT_BIT, + MISC_PCIE1_MSI_MON_OPT_BIT, + MISC_PCIE2_MSI_MON_OPT_BIT +}; + +ssize_t phytium_msi_pmu_format_sysfs_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *eattr; + + eattr = container_of(attr, struct dev_ext_attribute, attr); + return sprintf(buf, "%s\n", (char *)eattr->var); +} + +ssize_t phytium_msi_pmu_event_sysfs_show(struct device *dev, struct device_attribute *attr, + char *page) +{ + struct dev_ext_attribute *eattr; + + eattr = container_of(attr, struct dev_ext_attribute, attr); + return sprintf(page, "config=0x%lx\n", (unsigned long)eattr->var); +} + +static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct phytium_msi_pmu *misc_pmu = + to_phytium_msi_pmu(dev_get_drvdata(dev)); + + return cpumap_print_to_pagebuf(true, buf, cpumask_of(misc_pmu->on_cpu)); +} + +#define PHYTIUM_PMU_ATTR(_name, _func, _config) \ + (&((struct dev_ext_attribute[]) \ + {{__ATTR(_name, 0444, _func, NULL), (void *)_config}})[0] \ + .attr.attr) + +#define PHYTIUM_MSI_PMU_FORMAT_ATTR(_name, _config) \ + PHYTIUM_PMU_ATTR(_name, phytium_msi_pmu_format_sysfs_show, (void *)_config) + +#define PHYTIUM_MSI_PMU_EVENT_ATTR(_name, _config) \ + PHYTIUM_PMU_ATTR(_name, phytium_msi_pmu_event_sysfs_show, (unsigned long)_config) + +#define MISC_PMU_EVENT_ATTR_EXTRACTOR(_name, _config, _start, _end) \ + static inline int misc_pmu_get_##_name(struct perf_event *event) \ + { \ + return FIELD_GET(GENMASK_ULL(_end, _start), \ + event->attr._config); \ + } + +MISC_PMU_EVENT_ATTR_EXTRACTOR(event, config, 0, 3); +MISC_PMU_EVENT_ATTR_EXTRACTOR(trig_mode, config, 4, 4); +MISC_PMU_EVENT_ATTR_EXTRACTOR(by_reqid, config, 5, 5); +MISC_PMU_EVENT_ATTR_EXTRACTOR(timer, config2, 0, 63); +MISC_PMU_EVENT_ATTR_EXTRACTOR(reqid0, config1, 0, 15); +MISC_PMU_EVENT_ATTR_EXTRACTOR(reqid1, config1, 16, 31); +MISC_PMU_EVENT_ATTR_EXTRACTOR(reqid2, config1, 32, 47); +MISC_PMU_EVENT_ATTR_EXTRACTOR(reqid3, config1, 48, 63); + +static struct attribute *PHYTIUM_MSI_PMU_FORMAT_ATTR[] = { + PHYTIUM_MSI_PMU_FORMAT_ATTR(event, "config:0-3"), + PHYTIUM_MSI_PMU_FORMAT_ATTR(trig_mode, "config:4-4"), + PHYTIUM_MSI_PMU_FORMAT_ATTR(by_reqid, "config:5-5"), + PHYTIUM_MSI_PMU_FORMAT_ATTR(timer, "config2:0-63"), + PHYTIUM_MSI_PMU_FORMAT_ATTR(reqid0, "config1:0-15"), + PHYTIUM_MSI_PMU_FORMAT_ATTR(reqid1, "config1:16-31"), + PHYTIUM_MSI_PMU_FORMAT_ATTR(reqid2, "config1:32-47"), + PHYTIUM_MSI_PMU_FORMAT_ATTR(reqid3, "config1:48-63"), + NULL, +}; + +static const struct attribute_group phytium_msi_pmu_format_group = { + .name = "format", + .attrs = PHYTIUM_MSI_PMU_FORMAT_ATTR, +}; + +static struct attribute *phytium_msi_pmu_events_attr[] = { + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie0_msi_cnt0, 0x00), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie0_msi_cnt1, 0x01), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie0_msi_cnt2, 0x02), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie0_msi_cnt3, 0x03), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie0_msi_cycles, 0x4), + + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie1_msi_cnt0, 0x05), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie1_msi_cnt1, 0x06), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie1_msi_cnt2, 0x07), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie1_msi_cnt3, 0x08), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie1_msi_cycles, 0x09), + + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie2_msi_cnt0, 0x0a), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie2_msi_cnt1, 0x0b), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie2_msi_cnt2, 0x0c), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie2_msi_cnt3, 0x0d), + PHYTIUM_MSI_PMU_EVENT_ATTR(pcie2_msi_cycles, 0x0e), + + NULL, +}; + +static const struct attribute_group phytium_msi_pmu_events_group = { + .name = "events", + .attrs = phytium_msi_pmu_events_attr, +}; + +static DEVICE_ATTR_RO(cpumask); + +static struct attribute *phytium_msi_pmu_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL, +}; + +static const struct attribute_group phytium_msi_pmu_cpumask_attr_group = { + .attrs = phytium_msi_pmu_cpumask_attrs, +}; + +static const struct attribute_group *phytium_msi_pmu_attr_groups[] = { + &phytium_msi_pmu_format_group, + &phytium_msi_pmu_events_group, + &phytium_msi_pmu_cpumask_attr_group, + NULL, +}; + +int phytium_msi_pmu_get_event_type(struct perf_event *event) +{ + int idx, event_type; + + idx = (int)misc_pmu_get_event(event); + event_type = (int)(idx / 5); + + return event_type; +} + +static void phytium_msi_pmu_enable_clk(struct phytium_msi_pmu *misc_pmu) +{ + u32 val; + + val = readl(misc_pmu->base + MISC_MSI_MON_CLKEN_REG); + val |= MISC_MSI_MON_OPT_MASK; + writel(val, misc_pmu->base + MISC_MSI_MON_CLKEN_REG); +} + +static void phytium_msi_pmu_disable_clk(struct phytium_msi_pmu *misc_pmu) +{ + writel(0, misc_pmu->base + MISC_MSI_MON_CLKEN_REG); +} + +static void phytium_msi_pmu_start_counters(struct phytium_msi_pmu *misc_pmu, u32 st_val) +{ + writel(st_val, misc_pmu->base + MISC_MSI_MON_START_REG); +} + +static void phytium_msi_pmu_start_all_counters(struct phytium_msi_pmu *misc_pmu) +{ + u32 val; + + val = MISC_MSI_MON_OPT_MASK; + writel(val, misc_pmu->base + MISC_MSI_MON_START_REG); +} + +static void phytium_msi_pmu_stop_all_counters(struct phytium_msi_pmu *misc_pmu) +{ + u32 val; + + val = MISC_PCIE0_MSI_MON_OPT_BIT | MISC_PCIE1_MSI_MON_OPT_BIT | MISC_PCIE2_MSI_MON_OPT_BIT; + writel(val, misc_pmu->base + MISC_MSI_MON_STOP_REG); +} + +static void phytium_msi_pmu_clean_mon_mode(struct phytium_msi_pmu *misc_pmu) +{ + writel(0, misc_pmu->base + MISC_MSI_MON_MODE); +} + +static void phytium_msi_pmu_set_trig_mode(struct phytium_msi_pmu *misc_pmu, + u32 trig_mode) +{ + u32 val; + + val = readl(misc_pmu->base + MISC_MSI_MON_MODE); + if (trig_mode) + val |= MISC_MSI_MON_TRIG_MODE_MASK; + else + val &= MISC_MSI_MON_MODE_MASK; + + writel(val, misc_pmu->base + MISC_MSI_MON_MODE); +} + +// config by_reqid +static void phytium_msi_pmu_by_reqid_mode(struct phytium_msi_pmu *misc_pmu, + u32 opt_bit, u32 by_reqid) +{ + u32 val, mask; + + if (by_reqid) { + mask = MISC_MSI_MON_MODE_MASK & opt_bit; + val = readl(misc_pmu->base + MISC_MSI_MON_MODE); + val |= mask; + writel(val, misc_pmu->base + MISC_MSI_MON_MODE); + } else { + val = readl(misc_pmu->base + MISC_MSI_MON_MODE); + val &= ~opt_bit; + writel(val, misc_pmu->base + MISC_MSI_MON_MODE); + } +} + +// config 4 reqids +static void phytium_msi_pmu_set_req_id(struct phytium_msi_pmu *misc_pmu, + u32 offset, u32 req_id_val) +{ + u32 val; + + val = readl(misc_pmu->base + offset); + val |= req_id_val; + + writel(val, misc_pmu->base + offset); +} + + +// overflow stop status +static unsigned long phytium_msi_pmu_get_now_status(struct phytium_msi_pmu *misc_pmu) +{ + unsigned long val; + + val = (unsigned long)readl(misc_pmu->base + MISC_MSI_MON_STATE); + return val; +} + +// overflow stop reason +static unsigned long phytium_msi_pmu_get_stop_status(struct phytium_msi_pmu *misc_pmu) +{ + unsigned long val; + + val = (unsigned long)readl(misc_pmu->base + MISC_MSI_MON_STATE_STOP); + return val; +} + +static void phytium_msi_pmu_clear_all_counters(struct phytium_msi_pmu *misc_pmu) +{ + u32 val; + + val = MISC_MSI_MON_OPT_MASK; + writel(val, misc_pmu->base + MISC_MSI_MON_CLR_REG); +} + +static void phytium_msi_pmu_clear_counters(struct phytium_msi_pmu *misc_pmu, + u32 clr_val) +{ + writel(clr_val, misc_pmu->base + MISC_MSI_MON_CLR_REG); +} + +static u64 phytium_msi_pmu_read_counter(struct phytium_msi_pmu *misc_pmu, + struct hw_perf_event *hwc) +{ + u32 cycles_l, cycles_h, req_cnt, reqid_val; + u32 counter_offset, offset_id, mov_bits, cnt_mov_bits, record_mov_bits; + u32 reqid[4], reqcnt[4]; + u64 val64; + int idx, event_type, i, j; + struct perf_event *event; + + idx = GET_MISC_EVENTID(hwc); + event = misc_pmu->pmu_events.hw_events[idx]; + if (!EVENT_VALID(idx)) { + dev_err(misc_pmu->dev, "Unsupported event index:%d!\n", idx); + return 0; + } + + counter_offset = misc_counter_reg_offset[idx]; + event_type = phytium_msi_pmu_get_event_type(event); + + if ((idx % 5) == 4) { + cycles_l = readl(misc_pmu->base + counter_offset + 4); + cycles_h = readl(misc_pmu->base + counter_offset); + val64 = (u64)cycles_h << 32 | (u64)cycles_l; + } else { + offset_id = (u32)(idx % 5); + req_cnt = readl(misc_pmu->base + counter_offset); + mov_bits = offset_id * 4; + val64 = (u64)(0xF & (req_cnt >> mov_bits)); + + j = event_type * 5; + for (i = 0; i < 4; i++) { + reqid_val = readl(misc_pmu->base + misc_reqid_record_reg_offset[j]); + req_cnt = readl(misc_pmu->base + misc_counter_reg_offset[j]); + record_mov_bits = (i % 2) * 16; + reqid[i] = (u32)(0xFFFF & (reqid_val >> record_mov_bits)); + cnt_mov_bits = i * 4; + reqcnt[i] = (u32)(0xF & (req_cnt >> cnt_mov_bits)); + dev_info(misc_pmu->dev, "reqid(%u),cnt=%u\n", reqid[i], reqcnt[i]); + j += 1; + } + } + return val64; +} + +static void phytium_msi_pmu_set_timer(struct perf_event *event, u64 th_val) +{ + struct phytium_msi_pmu *misc_pmu = to_phytium_msi_pmu(event->pmu); + u32 val_l, val_h; + + val_l = th_val & 0xFFFFFFFF; + val_h = (th_val >> 32) & 0xFFFFFFFF; + + writel(val_l, misc_pmu->base + MISC_PCIE0_MON_SET_TIME_L); + writel(val_h, misc_pmu->base + MISC_PCIE0_MON_SET_TIME_H); + writel(val_l, misc_pmu->base + MISC_PCIE1_MON_SET_TIME_L); + writel(val_h, misc_pmu->base + MISC_PCIE1_MON_SET_TIME_H); + writel(val_l, misc_pmu->base + MISC_PCIE2_MON_SET_TIME_L); + writel(val_h, misc_pmu->base + MISC_PCIE2_MON_SET_TIME_H); +} + +static void phytium_msi_pmu_reset_timer(struct phytium_msi_pmu *misc_pmu) +{ + writel(0xFFFFFFFF, misc_pmu->base + MISC_PCIE0_MON_SET_TIME_L); + writel(0xFFFFFFFF, misc_pmu->base + MISC_PCIE0_MON_SET_TIME_H); + + writel(0xFFFFFFFF, misc_pmu->base + MISC_PCIE1_MON_SET_TIME_L); + writel(0xFFFFFFFF, misc_pmu->base + MISC_PCIE1_MON_SET_TIME_H); + + writel(0xFFFFFFFF, misc_pmu->base + MISC_PCIE2_MON_SET_TIME_L); + writel(0xFFFFFFFF, misc_pmu->base + MISC_PCIE2_MON_SET_TIME_H); +} + +void phytium_msi_pmu_clean_event_config(struct phytium_msi_pmu *misc_pmu) +{ + misc_pmu->event_cfg.pcie0_by_reqid = -1; + misc_pmu->event_cfg.pcie1_by_reqid = -1; + misc_pmu->event_cfg.pcie2_by_reqid = -1; + + misc_pmu->event_cfg.pcie0_reqid0 = -1; + misc_pmu->event_cfg.pcie0_reqid1 = -1; + misc_pmu->event_cfg.pcie0_reqid2 = -1; + misc_pmu->event_cfg.pcie0_reqid3 = -1; + + misc_pmu->event_cfg.pcie1_reqid0 = -1; + misc_pmu->event_cfg.pcie1_reqid1 = -1; + misc_pmu->event_cfg.pcie1_reqid2 = -1; + misc_pmu->event_cfg.pcie1_reqid3 = -1; + + misc_pmu->event_cfg.pcie2_reqid0 = -1; + misc_pmu->event_cfg.pcie2_reqid1 = -1; + misc_pmu->event_cfg.pcie2_reqid2 = -1; + misc_pmu->event_cfg.pcie2_reqid3 = -1; + + misc_pmu->event_cfg.trig_mode = -1; + + phytium_msi_pmu_set_trig_mode(misc_pmu, 0); + phytium_msi_pmu_clean_mon_mode(misc_pmu); +} + +static int phytium_msi_pmu_mark_event(struct perf_event *event) +{ + struct phytium_msi_pmu *misc_pmu = to_phytium_msi_pmu(event->pmu); + unsigned long *used_mask = misc_pmu->pmu_events.used_mask; + unsigned long *dev_mask = misc_pmu->pmu_events.dev_mask; + int idx = (int)misc_pmu_get_event(event); + int event_type = phytium_msi_pmu_get_event_type(event); + + if (test_bit(idx, used_mask)) + return -EAGAIN; + set_bit(idx, used_mask); + + if (!test_bit(event_type, dev_mask)) + set_bit(event_type, dev_mask); + + return idx; +} + +static void phytium_msi_pmu_unmark_event(struct perf_event *event) +{ + struct phytium_msi_pmu *misc_pmu = to_phytium_msi_pmu(event->pmu); + int idx = (int)misc_pmu_get_event(event); + int event_type = phytium_msi_pmu_get_event_type(event); + + if (!EVENT_VALID(idx)) { + dev_err(misc_pmu->dev, "Unsupported event index:%d!\n", idx); + return; + } + + clear_bit(idx, misc_pmu->pmu_events.used_mask); + clear_bit(event_type, misc_pmu->pmu_events.dev_mask); +} + +int phytium_msi_pmu_event_init(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct phytium_msi_pmu *misc_pmu; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) + return -EOPNOTSUPP; + + misc_pmu = to_phytium_msi_pmu(event->pmu); + + if (event->cpu < 0) { + dev_warn(misc_pmu->dev, "Can't provide per-task data!\n"); + return -EINVAL; + } + + if ((event->attr.config & PHYTIUM_MSI_PMU_EVENT_MASK) > PHYTIUM_MISC_MAX_COUNTERS) + return -EINVAL; + + if (misc_pmu->on_cpu == -1) + return -EINVAL; + + hwc->idx = -1; + hwc->config_base = event->attr.config; + + event->cpu = misc_pmu->on_cpu; + + return 0; +} + +void phytium_msi_pmu_event_update(struct perf_event *event) +{ + struct phytium_msi_pmu *misc_pmu = to_phytium_msi_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u64 delta; + + delta = phytium_msi_pmu_read_counter(misc_pmu, hwc); + local64_add(delta, &event->count); +} + +void phytium_msi_pmu_event_start(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + + hwc->state = 0; + perf_event_update_userpage(event); +} + +void phytium_msi_pmu_event_stop(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + + hwc->state |= PERF_HES_STOPPED; + + if (flags & PERF_EF_UPDATE) + phytium_msi_pmu_event_update(event); +} + +int phytium_msi_pmu_set_event_config(struct phytium_msi_pmu *misc_pmu, int idx) +{ + int event_type; + int dec0, dec1, dec2, dec3; + u32 trig_mode, by_reqid, reqid0, reqid1, reqid2, reqid3; + u32 by_reqid_val, reqid_cfg_offset01, reqid_cfg_offset23; + struct perf_event *event = misc_pmu->pmu_events.hw_events[idx]; + + trig_mode = misc_pmu_get_trig_mode(event); + if (misc_pmu->event_cfg.trig_mode < 0) { + phytium_msi_pmu_set_trig_mode(misc_pmu, trig_mode); + misc_pmu->event_cfg.trig_mode = trig_mode; + } else if (misc_pmu->event_cfg.trig_mode != trig_mode) { + dev_err(misc_pmu->dev, + "Incorrect trig_mode parameter for the same PMU"); + dev_err(misc_pmu->dev, "The event parameters should be the same!"); + return -EINVAL; + } + + event_type = phytium_msi_pmu_get_event_type(event); + switch (event_type) { + case 0: + /* peu */ + by_reqid = misc_pmu_get_by_reqid(event); + reqid0 = misc_pmu_get_reqid0(event); + reqid1 = misc_pmu_get_reqid1(event); + reqid2 = misc_pmu_get_reqid2(event); + reqid3 = misc_pmu_get_reqid3(event); + if (misc_pmu->event_cfg.pcie0_by_reqid < 0) { + // first read + misc_pmu->event_cfg.pcie0_by_reqid = by_reqid; + if (by_reqid) { + misc_pmu->event_cfg.pcie0_reqid0 = reqid0; + misc_pmu->event_cfg.pcie0_reqid1 = reqid1; + misc_pmu->event_cfg.pcie0_reqid2 = reqid2; + misc_pmu->event_cfg.pcie0_reqid3 = reqid3; + } + } else if (misc_pmu->event_cfg.pcie0_by_reqid == 1) { + dec0 = reqid0 - misc_pmu->event_cfg.pcie0_reqid0; + dec1 = reqid1 - misc_pmu->event_cfg.pcie0_reqid1; + dec2 = reqid2 - misc_pmu->event_cfg.pcie0_reqid2; + dec3 = reqid3 - misc_pmu->event_cfg.pcie0_reqid3; + if (dec0 || dec1 || dec2 || dec3 || (by_reqid == 0)) { + dev_err(misc_pmu->dev, + "Incorrect reqid parameter of pcie0 for the same PMU!"); + dev_err(misc_pmu->dev, "The event parameters should be the same!"); + return -EINVAL; + } + } else { + if (by_reqid) { + dev_err(misc_pmu->dev, + "Incorrect by_reqid parameter of pcie0 for the same PMU"); + dev_err(misc_pmu->dev, "The event parameters should be the same!"); + return -EINVAL; + } + } + by_reqid_val = MISC_PCIE0_MSI_BYREQID_MODE_BIT; + reqid_cfg_offset01 = MISC_PCIE0_MSI_REG_ID_CFG_REG_01; + reqid_cfg_offset23 = MISC_PCIE0_MSI_REG_ID_CFG_REG_23; + break; + case 1: + /* pxu */ + by_reqid = misc_pmu_get_by_reqid(event); + reqid0 = misc_pmu_get_reqid0(event); + reqid1 = misc_pmu_get_reqid1(event); + reqid2 = misc_pmu_get_reqid2(event); + reqid3 = misc_pmu_get_reqid3(event); + if (misc_pmu->event_cfg.pcie1_by_reqid < 0) { + misc_pmu->event_cfg.pcie1_by_reqid = by_reqid; + if (by_reqid) { + misc_pmu->event_cfg.pcie1_reqid0 = reqid0; + misc_pmu->event_cfg.pcie1_reqid1 = reqid1; + misc_pmu->event_cfg.pcie1_reqid2 = reqid2; + misc_pmu->event_cfg.pcie1_reqid3 = reqid3; + } + } else if (misc_pmu->event_cfg.pcie1_by_reqid == 1) { + dec0 = reqid0 - misc_pmu->event_cfg.pcie1_reqid0; + dec1 = reqid1 - misc_pmu->event_cfg.pcie1_reqid1; + dec2 = reqid2 - misc_pmu->event_cfg.pcie1_reqid2; + dec3 = reqid3 - misc_pmu->event_cfg.pcie1_reqid3; + if (dec0 || dec1 || dec2 || dec3 || (by_reqid == 0)) { + dev_err(misc_pmu->dev, + "Incorrect reqid parameter of pcie1 for the same PMU!"); + dev_err(misc_pmu->dev, "The event parameters should be the same!"); + return -EINVAL; + } + } else { + if (by_reqid) { + dev_err(misc_pmu->dev, + "Incorrect by_reqid parameter of pcie1 for the same PMU"); + dev_err(misc_pmu->dev, "The event parameters should be the same!"); + return -EINVAL; + } + } + by_reqid_val = MISC_PCIE1_MSI_BYREQID_MODE_BIT; + reqid_cfg_offset01 = MISC_PCIE1_MSI_REG_ID_CFG_REG_01; + reqid_cfg_offset23 = MISC_PCIE1_MSI_REG_ID_CFG_REG_23; + break; + case 2: + /* pcu */ + by_reqid = misc_pmu_get_by_reqid(event); + reqid0 = misc_pmu_get_reqid0(event); + reqid1 = misc_pmu_get_reqid1(event); + reqid2 = misc_pmu_get_reqid2(event); + reqid3 = misc_pmu_get_reqid3(event); + if (misc_pmu->event_cfg.pcie2_by_reqid < 0) { + misc_pmu->event_cfg.pcie2_by_reqid = by_reqid; + if (by_reqid) { + misc_pmu->event_cfg.pcie2_reqid0 = reqid0; + misc_pmu->event_cfg.pcie2_reqid1 = reqid1; + misc_pmu->event_cfg.pcie2_reqid2 = reqid2; + misc_pmu->event_cfg.pcie2_reqid3 = reqid3; + } + } else if (misc_pmu->event_cfg.pcie2_by_reqid == 1) { + dec0 = reqid0 - misc_pmu->event_cfg.pcie2_reqid0; + dec1 = reqid1 - misc_pmu->event_cfg.pcie2_reqid1; + dec2 = reqid2 - misc_pmu->event_cfg.pcie2_reqid2; + dec3 = reqid3 - misc_pmu->event_cfg.pcie2_reqid3; + if (dec0 || dec1 || dec2 || dec3 || (by_reqid == 0)) { + dev_err(misc_pmu->dev, + "Incorrect reqid parameter of pcie2 for the same PMU!"); + dev_err(misc_pmu->dev, "The event parameters should be the same!"); + return -EINVAL; + } + } else { + if (by_reqid) { + dev_err(misc_pmu->dev, + "Incorrect by_reqid parameter of pcie2 for the same PMU"); + dev_err(misc_pmu->dev, "The event parameters should be the same!"); + return -EINVAL; + } + } + by_reqid_val = MISC_PCIE2_MSI_BYREQID_MODE_BIT; + reqid_cfg_offset01 = MISC_PCIE2_MSI_REG_ID_CFG_REG_01; + reqid_cfg_offset23 = MISC_PCIE2_MSI_REG_ID_CFG_REG_23; + break; + default: + return 0; + } + + phytium_msi_pmu_by_reqid_mode(misc_pmu, by_reqid_val, by_reqid); + if (by_reqid) { + phytium_msi_pmu_set_req_id(misc_pmu, reqid_cfg_offset01, + (reqid0 | (reqid1 << 16))); + phytium_msi_pmu_set_req_id(misc_pmu, reqid_cfg_offset23, + (reqid2 | (reqid3 << 16))); + } + + return 0; +} + +void phytium_msi_pmu_reset_event_config(struct phytium_msi_pmu *misc_pmu, + unsigned long dev_mask) +{ + int idx; + u32 by_reqid, reqid_cfg_offset01, reqid_cfg_offset23, by_reqid_val; + u32 reqid0, reqid1, reqid2, reqid3; + + for_each_set_bit(idx, &dev_mask, 3) { + switch (idx) { + case 0: + by_reqid = misc_pmu->event_cfg.pcie0_by_reqid; + reqid0 = misc_pmu->event_cfg.pcie0_reqid0; + reqid1 = misc_pmu->event_cfg.pcie0_reqid1; + reqid2 = misc_pmu->event_cfg.pcie0_reqid2; + reqid3 = misc_pmu->event_cfg.pcie0_reqid3; + by_reqid_val = MISC_PCIE0_MSI_BYREQID_MODE_BIT; + reqid_cfg_offset01 = MISC_PCIE0_MSI_REG_ID_CFG_REG_01; + reqid_cfg_offset23 = MISC_PCIE0_MSI_REG_ID_CFG_REG_23; + break; + case 1: + by_reqid = misc_pmu->event_cfg.pcie1_by_reqid; + reqid0 = misc_pmu->event_cfg.pcie1_reqid0; + reqid1 = misc_pmu->event_cfg.pcie1_reqid1; + reqid2 = misc_pmu->event_cfg.pcie1_reqid2; + reqid3 = misc_pmu->event_cfg.pcie1_reqid3; + by_reqid_val = MISC_PCIE1_MSI_BYREQID_MODE_BIT; + reqid_cfg_offset01 = MISC_PCIE1_MSI_REG_ID_CFG_REG_01; + reqid_cfg_offset23 = MISC_PCIE1_MSI_REG_ID_CFG_REG_23; + break; + case 2: + by_reqid = misc_pmu->event_cfg.pcie2_by_reqid; + reqid0 = misc_pmu->event_cfg.pcie2_reqid0; + reqid1 = misc_pmu->event_cfg.pcie2_reqid1; + reqid2 = misc_pmu->event_cfg.pcie2_reqid2; + reqid3 = misc_pmu->event_cfg.pcie2_reqid3; + by_reqid_val = MISC_PCIE2_MSI_BYREQID_MODE_BIT; + reqid_cfg_offset01 = MISC_PCIE2_MSI_REG_ID_CFG_REG_01; + reqid_cfg_offset23 = MISC_PCIE2_MSI_REG_ID_CFG_REG_23; + break; + default: + return; + } + + phytium_msi_pmu_by_reqid_mode(misc_pmu, by_reqid_val, by_reqid); + if (by_reqid) { + phytium_msi_pmu_set_req_id(misc_pmu, reqid_cfg_offset01, + (reqid0 | (reqid1 << 16))); + phytium_msi_pmu_set_req_id(misc_pmu, reqid_cfg_offset23, + (reqid2 | (reqid3 << 16))); + } + } + + if (misc_pmu->event_cfg.trig_mode >= 0) + phytium_msi_pmu_set_trig_mode(misc_pmu, misc_pmu->event_cfg.trig_mode); + +} + +int phytium_msi_pmu_event_add(struct perf_event *event, int flags) +{ + struct phytium_msi_pmu *misc_pmu = to_phytium_msi_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int idx, ret; + u64 event_timer = misc_pmu_get_timer(event); + + phytium_msi_pmu_enable_clk(misc_pmu); + + hwc->state |= PERF_HES_STOPPED; + + idx = phytium_msi_pmu_mark_event(event); + if (idx < 0) + return idx; + + event->hw.idx = idx; + misc_pmu->pmu_events.hw_events[idx] = event; + + ret = phytium_msi_pmu_set_event_config(misc_pmu, idx); + if (ret) + return ret; + + if (event_timer != 0) + phytium_msi_pmu_set_timer(event, event_timer); + return 0; +} + +void phytium_msi_pmu_event_del(struct perf_event *event, int flags) +{ + struct phytium_msi_pmu *misc_pmu = to_phytium_msi_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u32 event_timer; + + phytium_msi_pmu_event_stop(event, PERF_EF_UPDATE); + + event_timer = misc_pmu_get_timer(event); + if (event_timer != 0) + phytium_msi_pmu_reset_timer(misc_pmu); + + phytium_msi_pmu_unmark_event(event); + + perf_event_update_userpage(event); + misc_pmu->pmu_events.hw_events[hwc->idx] = NULL; +} + +void phytium_msi_pmu_enable(struct pmu *pmu) +{ + struct phytium_msi_pmu *misc_pmu = to_phytium_msi_pmu(pmu); + int event_added = bitmap_weight(misc_pmu->pmu_events.used_mask, PHYTIUM_MISC_MAX_COUNTERS); + + if (event_added) { + phytium_msi_pmu_clear_all_counters(misc_pmu); + phytium_msi_pmu_start_all_counters(misc_pmu); + } +} + +void phytium_msi_pmu_disable(struct pmu *pmu) +{ + struct phytium_msi_pmu *misc_pmu = to_phytium_msi_pmu(pmu); + int event_added = bitmap_weight(misc_pmu->pmu_events.used_mask, PHYTIUM_MISC_MAX_COUNTERS); + + if (event_added) + phytium_msi_pmu_stop_all_counters(misc_pmu); + else + phytium_msi_pmu_clean_event_config(misc_pmu); +} + +static const struct acpi_device_id phytium_msi_pmu_acpi_match[] = { + { "PHYT300D", }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, phytium_msi_pmu_acpi_match); + +static int phytium_msi_pmu_version(struct platform_device *pdev, + struct phytium_msi_pmu *misc_pmu) +{ + u32 pidr; + + pidr = readl(misc_pmu->base + MISC_MON_PIDR0); + dev_info(&pdev->dev, "PIDR=%#x,VER=%#lx.\n", pidr, (pidr & MISC_PMU_VER_BIT)); + pidr &= MISC_PMU_VER_BIT; + if (pidr == 0x1) { + misc_pmu->ver = MISCV1P0; + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + } + return 0; +} + +bool is_interrupt_state(unsigned long now_state) +{ + const int shifts[] = {0, 4, 8}; + + for (int i = 0; i < 3; i++) { + unsigned int group_val = (now_state >> shifts[i]) & 0x0F; + + if (group_val == MISC_MSI_MON_OVFL_STATE_MASK) + return true; + } + + return false; +} + +static irqreturn_t phytium_msi_pmu_overflow_handler(int irq, void *dev_id) +{ + struct phytium_msi_pmu *misc_pmu = dev_id; + struct perf_event *event; + unsigned long now_state, stop_state; + int idx, event_type; + unsigned long dev_stop_mask, dev_mask; + unsigned long *used_mask = misc_pmu->pmu_events.used_mask; + u32 opt_val = 0; + int event_added = bitmap_weight(used_mask, PHYTIUM_MISC_MAX_COUNTERS); + + // 0:pcu 1:pxu 2:peu + now_state = phytium_msi_pmu_get_now_status(misc_pmu); + + if (!is_interrupt_state(now_state)) + return IRQ_NONE; + + if (!event_added) { + phytium_msi_pmu_clear_counters(misc_pmu, MISC_MSI_MON_OPT_MASK); + return IRQ_HANDLED; + } + + stop_state = phytium_msi_pmu_get_stop_status(misc_pmu); + if (stop_state & MISC_MSI_MON_COUNT_FULL_MASK) { + for_each_set_bit(idx, used_mask, PHYTIUM_MISC_MAX_COUNTERS) { + event = misc_pmu->pmu_events.hw_events[idx]; + if (!event) + continue; + event_type = phytium_msi_pmu_get_event_type(event); + dev_stop_mask = pcie_dev_msi_mon_stop_mask[event_type]; + + if (stop_state & dev_stop_mask & MISC_MSI_MON_COUNT_FULL_MASK) { + phytium_msi_pmu_event_update(event); + opt_val |= pcie_dev_msi_mon_opt_bits[event_type]; + set_bit(event_type, &dev_mask); + } + } + phytium_msi_pmu_clear_counters(misc_pmu, opt_val); + phytium_msi_pmu_start_counters(misc_pmu, opt_val); + } else { + for_each_set_bit(idx, used_mask, PHYTIUM_MISC_MAX_COUNTERS) { + event = misc_pmu->pmu_events.hw_events[idx]; + if (!event) + continue; + phytium_msi_pmu_event_update(event); + } + phytium_msi_pmu_clear_all_counters(misc_pmu); + } + + return IRQ_HANDLED; +} + +static int phytium_msi_pmu_init_irq(struct platform_device *pdev, + struct phytium_msi_pmu *misc_pmu) +{ + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(&pdev->dev, irq, phytium_msi_pmu_overflow_handler, + IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_SHARED, + dev_name(&pdev->dev), misc_pmu); + if (ret < 0) { + dev_err(&pdev->dev, "Fail to request IRQ:%d ret:%d\n", irq, ret); + return ret; + } + + misc_pmu->irq = irq; + + return 0; +} + +static int phytium_msi_pmu_init_data(struct platform_device *pdev, + struct phytium_msi_pmu *misc_pmu) +{ + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + misc_pmu->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(misc_pmu->base)) { + dev_err(&pdev->dev, "ioremap failed for misc_pmu base resource\n"); + return PTR_ERR(misc_pmu->base); + } + + ret = phytium_msi_pmu_version(pdev, misc_pmu); + if (ret) + return ret; + if (device_property_read_u32(&pdev->dev, "phytium,die-id", &misc_pmu->die_id)) { + dev_err(&pdev->dev, "Can not read phytium,die-id!\n"); + return -EINVAL; + } + + return 0; +} + +static int phytium_msi_pmu_dev_probe(struct platform_device *pdev, + struct phytium_msi_pmu *misc_pmu) +{ + int ret; + + ret = phytium_msi_pmu_init_data(pdev, misc_pmu); + if (ret) + return ret; + + ret = phytium_msi_pmu_init_irq(pdev, misc_pmu); + if (ret) + return ret; + + misc_pmu->dev = &pdev->dev; + misc_pmu->on_cpu = -1; + + return 0; +} + +static int phytium_msi_pmu_probe(struct platform_device *pdev) +{ + struct phytium_msi_pmu *misc_pmu; + char *name; + int ret; + + misc_pmu = devm_kzalloc(&pdev->dev, sizeof(*misc_pmu), GFP_KERNEL); + if (!misc_pmu) + return -ENOMEM; + + platform_set_drvdata(pdev, misc_pmu); + + ret = phytium_msi_pmu_dev_probe(pdev, misc_pmu); + if (ret) + return ret; + + ret = cpuhp_state_add_instance(phytium_msi_pmu_hp_state, &misc_pmu->node); + if (ret) { + dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret); + return ret; + } + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_msi_pmu", misc_pmu->die_id); + + misc_pmu->pmu = (struct pmu){ + .name = name, + .module = THIS_MODULE, + .task_ctx_nr = perf_invalid_context, + .event_init = phytium_msi_pmu_event_init, + .pmu_enable = phytium_msi_pmu_enable, + .pmu_disable = phytium_msi_pmu_disable, + .add = phytium_msi_pmu_event_add, + .del = phytium_msi_pmu_event_del, + .start = phytium_msi_pmu_event_start, + .stop = phytium_msi_pmu_event_stop, + .read = phytium_msi_pmu_event_update, + .attr_groups = phytium_msi_pmu_attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + }; + + ret = perf_pmu_register(&misc_pmu->pmu, name, -1); + if (ret) { + dev_err(misc_pmu->dev, "MISC PMU register failed!\n"); + cpuhp_state_remove_instance_nocalls(phytium_msi_pmu_hp_state, &misc_pmu->node); + } + + phytium_msi_pmu_enable_clk(misc_pmu); + + pr_info("%s on cpu%d.\n", name, misc_pmu->on_cpu); + + return ret; +} + +static int phytium_msi_pmu_remove(struct platform_device *pdev) +{ + struct phytium_msi_pmu *misc_pmu = platform_get_drvdata(pdev); + + phytium_msi_pmu_disable_clk(misc_pmu); + perf_pmu_unregister(&misc_pmu->pmu); + cpuhp_state_remove_instance_nocalls(phytium_msi_pmu_hp_state, &misc_pmu->node); + + return 0; +} + +static struct platform_driver phytium_msi_pmu_driver = { + .driver = { + .name = "phytium_msi_pmu", + .acpi_match_table = ACPI_PTR(phytium_msi_pmu_acpi_match), + .suppress_bind_attrs = true, + }, + .probe = phytium_msi_pmu_probe, + .remove = phytium_msi_pmu_remove, +}; + +int phytium_msi_pmu_online_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct phytium_msi_pmu *misc_pmu = + hlist_entry_safe(node, struct phytium_msi_pmu, node); + + if (!cpumask_test_cpu(cpu, cpumask_of_node(misc_pmu->die_id))) + return 0; + + if (misc_pmu->on_cpu != -1) { + if (!cpumask_test_cpu(misc_pmu->on_cpu, cpumask_of_node(misc_pmu->die_id))) { + perf_pmu_migrate_context(&misc_pmu->pmu, misc_pmu->on_cpu, cpu); + misc_pmu->on_cpu = cpu; + WARN_ON(irq_set_affinity_hint(misc_pmu->irq, cpumask_of(cpu))); + } + return 0; + } + + misc_pmu->on_cpu = cpu; + + return 0; +} + +int phytium_msi_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct phytium_msi_pmu *misc_pmu = hlist_entry_safe(node, + struct phytium_msi_pmu, node); + unsigned int target; + cpumask_t available_cpus; + + if (misc_pmu->on_cpu != cpu) + return 0; + + if (cpumask_and(&available_cpus, cpumask_of_node(misc_pmu->die_id), cpu_online_mask) && + cpumask_andnot(&available_cpus, &available_cpus, cpumask_of(cpu))) + target = cpumask_last(&available_cpus); + else { + cpumask_andnot(&available_cpus, cpu_online_mask, cpumask_of(cpu)); + target = cpumask_last(&available_cpus); + } + + if (target >= nr_cpu_ids) { + dev_err(misc_pmu->dev, "offline cpu%d with no target to migrate.\n", cpu); + return 0; + } + + perf_pmu_migrate_context(&misc_pmu->pmu, cpu, target); + misc_pmu->on_cpu = target; + + return 0; +} + +static int __init phytium_msi_pmu_module_init(void) +{ + int ret; + + phytium_msi_pmu_hp_state = + cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, + "perf/phytium/miscpmu:online", + phytium_msi_pmu_online_cpu, + phytium_msi_pmu_offline_cpu); + if (phytium_msi_pmu_hp_state < 0) { + pr_err("MISC PMU: setup hotplug, ret = %d\n", phytium_msi_pmu_hp_state); + return phytium_msi_pmu_hp_state; + } + + ret = platform_driver_register(&phytium_msi_pmu_driver); + if (ret) + cpuhp_remove_multi_state(phytium_msi_pmu_hp_state); + + return ret; +} +module_init(phytium_msi_pmu_module_init); + +static void __exit phytium_msi_pmu_module_exit(void) +{ + platform_driver_unregister(&phytium_msi_pmu_driver); + cpuhp_remove_multi_state(phytium_msi_pmu_hp_state); +} +module_exit(phytium_msi_pmu_module_exit); + +MODULE_DESCRIPTION("Phytium MISC PMU driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MISC_PERF_DRIVER_VERSION); +MODULE_AUTHOR("Tan Rui "); +MODULE_AUTHOR("Fu Boyi "); diff --git a/drivers/perf/phytium/phytium_pcie_link_pmu.c b/drivers/perf/phytium/phytium_pcie_link_pmu.c new file mode 100644 index 0000000000000..60f0568024bea --- /dev/null +++ b/drivers/perf/phytium/phytium_pcie_link_pmu.c @@ -0,0 +1,1082 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Phytium SoC PCIe Link performance monitoring unit support + * + * Copyright (c) 2025, Phytium Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "phytium_pcie_link_pmu: " fmt +#define PCIE_LINK_PERF_DRIVER_VERSION "1.0.0" +#define REG_ENABLE 0x000 +#define REG_SIG_CLEAR 0x00C + +// TLP/DLLP Package +#define REG_XTLH_XDLH_SOT_CNT 0x02c +#define REG_XTLH_XDLH_EOT_CNT 0x030 +#define REG_RDLH_RTLH_TLP_SOT_CNT 0x034 +#define REG_RDLH_RTLH_TLP_EOT_CNT 0x038 +#define REG_XDLH_XPLH_SDP_CNT 0x03c +#define REG_XDLH_XPLH_STP_CNT 0x040 +#define REG_XDLH_XPLH_EOT_CNT 0x044 +// TLP/PL/DLLP ERR +#define REG_ERRO_SIG_SEL 0x008 +#define REG_TLP_ERR_CNT 0x048 +#define REG_DLLP_ERR_CNT 0x04C +#define REG_PL_ERR_CNT 0x050 +#define REG_TLP_ERR_MASK GENMASK(23, 16) +#define REG_DLLP_ERR_MASK GENMASK(15, 8) +#define REG_PL_ERR_MASK GENMASK(7, 0) +#define TLP_ERR_IDX 0x07 +#define DLLP_ERR_IDX 0x08 +#define PL_ERR_IDX 0x09 +#define PL_DLLP_ERR_NUM 0x05 +#define TLP_ERR_NUM 0x08 + +// TLP TYPE +#define REG_TLP_TYPE_CNT_ENABLE 0x0e0 +#define REG_TLP_TYPE_CNT_CLEAR 0x0e4 + +#define REG_CONTROL_TIME_MODE_TYPE 0x0e8 +#define REG_START_TYPE_CNT 0x0ec +#define REG_TLP_TIMER_TYPE_CNT_0 0x0f4 +#define REG_TLP_TIMER_TYPE_CNT_1 0x0f8 + +#define REG_TX_MRD_CNT 0x19c +#define REG_TX_MRDLK_CNT 0x1a0 +#define REG_TX_MWR_CNT 0x1a4 +#define REG_TX_IORD_CNT 0x1a8 +#define REG_TX_IOWR_CNT 0x1ac +#define REG_TX_CFGRD0_CNT 0x1b0 +#define REG_TX_CFGWR0_CNT 0x1b4 +#define REG_TX_CFGRD1_CNT 0x1b8 +#define REG_TX_CFGWR1_CNT 0x1bc +#define REG_TX_MSG_CNT 0x1c0 +#define REG_TX_MSGD_CNT 0x1c4 +#define REG_TX_CPL_CNT 0x1c8 +#define REG_TX_CPLD_CNT 0x1cc +#define REG_TX_CPLLK_CNT 0x1d0 +#define REG_TX_CPLDLK_CNT 0x1d4 +#define REG_TX_FAA_REQ_CNT 0x1d8 +#define REG_TX_USA_REQ_CNT 0x1dc +#define REG_TX_CSA_REQ_CNT 0x1e0 +#define REG_TX_LOCAL_TLP_PREFIX_CNT 0x1e4 +#define REG_TX_ENDTOEND_TLP_PREFIX_CNT 0x1e8 +#define REG_TX_TCFGRD_CNT 0x1ec +#define REG_TX_TCFGWR_CNT 0x1f0 +#define REG_RX_MRD_CNT 0x1f8 +#define REG_RX_MRDLK_CNT 0x1fc +#define REG_RX_MWR_CNT 0x200 +#define REG_RX_IORD_CNT 0x204 +#define REG_RX_IOWR_CNT 0x208 +#define REG_RX_CFGRD0_CNT 0x20c +#define REG_RX_CFGWR0_CNT 0x210 +#define REG_RX_CFGRD1_CNT 0x214 +#define REG_RX_CFGWR1_CNT 0x218 +#define REG_RX_MSG_CNT 0x21c +#define REG_RX_MSGD_CNT 0x220 +#define REG_RX_CPL_CNT 0x224 +#define REG_RX_CPLD_CNT 0x228 +#define REG_RX_CPLLK_CNT 0x22c +#define REG_RX_CPLDLK_CNT 0x230 +#define REG_RX_FAA_REQ_CNT 0x234 +#define REG_RX_USA_REQ_CNT 0x238 +#define REG_RX_CSA_REQ_CNT 0x23c +#define REG_RX_LOCAL_TLP_PREFIX_CNT 0x240 +#define REG_RX_ENDTOEND_TLP_PREFIX_CNT 0x244 +#define REG_RX_TCFGRD_CNT 0x248 +#define REG_RX_TCFGWR_CNT 0x24c +// window time (start-top) +#define REG_WINDOW_TIME_TLP_RX_TYPE_CNT_1 0x254 +#define REG_WINDOW_TIME_TLP_RX_TYPE_CNT_0 0x258 +#define REG_WINDOW_TIME_TLP_TX_TYPE_CNT_1 0x25c +#define REG_WINDOW_TIME_TLP_TX_TYPE_CNT_0 0x260 + +// tlp performance +#define REG_ENABLE_TLP_PERFORMANCE 0x0fc +#define REG_CLEAR_TLP_PERFORMANCE 0x100 +#define REG_CONTROL_TIME_MODE_TLP_PERFORMANCE 0x104 +#define REG_START_TLP_PERFORMANCE 0x108 +#define REG_TIMER_TLP_PERFORMANCE_0 0x110 +#define REG_TIMER_TLP_PERFORMANCE_1 0x114 + +#define REG_WINDOW_TIME_TLP_PERFORMANCE_0 0x264 +#define REG_WINDOW_TIME_TLP_PERFORMANCE_1 0x268 +#define REG_TX_PAYLOAD_TOTAL_0 0x134 +#define REG_TX_PAYLOAD_TOTAL_1 0x138 +#define REG_TX_HEADER_TOTAL_0 0x13c +#define REG_TX_HEADER_TOTAL_1 0x140 +#define REG_RX_PAYLOAD_TOTAL_0 0x144 +#define REG_RX_PAYLOAD_TOTAL_1 0x148 +#define REG_RX_HEADER_TOTAL_0 0x14c +#define REG_RX_HEADER_TOTAL_1 0x150 + +// buffer usage +#define REG_ENABLE_BUFFER 0x118 +#define REG_CLEAR_BUFFER 0x11c +#define REG_CONTROL_TIME_MODE_BUFFER 0x120 +#define REG_START_BUFFER 0x124 +#define REG_TIMER_BUFFER_0 0x12c +#define REG_TIMER_BUFFER_1 0x130 + +#define REG_BUFFER_USAGE_LN0 0x158 +#define REG_BUFFER_USAGE_LN1 0x15c +#define REG_BUFFER_USAGE_LN2 0x160 +#define REG_BUFFER_USAGE_LN3 0x164 +#define REG_BUFFER_USAGE_LN4 0x168 +#define REG_BUFFER_USAGE_LN5 0x16c +#define REG_BUFFER_USAGE_LN6 0x170 +#define REG_BUFFER_USAGE_LN7 0x174 +#define REG_BUFFER_USAGE_LN8 0x178 +#define REG_BUFFER_USAGE_LN9 0x17c +#define REG_BUFFER_USAGE_LN10 0x180 +#define REG_BUFFER_USAGE_LN11 0x184 +#define REG_BUFFER_USAGE_LN12 0x18c +#define REG_BUFFER_USAGE_LN13 0x190 +#define REG_BUFFER_USAGE_LN14 0x194 +#define REG_BUFFER_USAGE_LN15 0x198 +#define REG_BUFFER_CURR_USAGE_MASK GENMASK(15, 8) +#define REG_BUFFER_PEAK_USAGE_MASK GENMASK(7, 0) + +#define TLP_TYPE_CLASSIFY_0 0x0a +#define TLP_TYPE_CLASSIFY_1 0x37 +#define TLP_PERFORM_TYPE_1 0x38 +#define BUFFER_USAGE_TYPE_0 0x3d +#define TLP_WINDOW_TIME_RX_TYPE 0x36 +#define TLP_WINDOW_TIME_TX_TYPE 0x37 +#define TLP_RX_HEADER_TOTAL_TYPE 0x3c + +#define PCIE_LINK_DEVCH 0xFE0 +#define PCIE_LINK_PMU_VER_BIT GENMASK(7, 0) +#define PHYTIUM_PCIE_LINK_MAX_COUNTERS 93 + +#define to_phytium_pcie_link_pmu(p) (container_of(p, struct phytium_pcie_link_pmu, pmu)) + +enum { + PCIEV1P0 = 0x01, + PCIEV1P5 = 0x02, + PCIEV2P0 = 0x03, +}; + +static int phytium_pcie_link_pmu_hp_state; + +struct phytium_pcie_link_pmu_hwevents { + struct perf_event *hw_events[PHYTIUM_PCIE_LINK_MAX_COUNTERS]; + DECLARE_BITMAP(used_mask_pcie_link, PHYTIUM_PCIE_LINK_MAX_COUNTERS); +}; + +struct phytium_pcie_link_pmu { + struct device *dev; + void __iomem *base; + struct pmu pmu; + struct phytium_pcie_link_pmu_hwevents pmu_events; + u32 die_id; + u32 pcie_id; + u32 pmu_id; + int on_cpu; + int ver; + struct hlist_node node; +}; + +#define EVENT_VALID(idx) ((idx >= 0) && (idx < PHYTIUM_PCIE_LINK_MAX_COUNTERS)) + +static const u32 pcie_link_counter_reg_offset[] = { + REG_XTLH_XDLH_SOT_CNT, + REG_XTLH_XDLH_EOT_CNT, + REG_RDLH_RTLH_TLP_SOT_CNT, + REG_RDLH_RTLH_TLP_EOT_CNT, + REG_XDLH_XPLH_SDP_CNT, + REG_XDLH_XPLH_STP_CNT, + REG_XDLH_XPLH_EOT_CNT, + + REG_TLP_ERR_CNT, + REG_DLLP_ERR_CNT, + REG_PL_ERR_CNT, + + REG_TX_MRD_CNT, + REG_TX_MRDLK_CNT, + REG_TX_MWR_CNT, + REG_TX_IORD_CNT, + REG_TX_IOWR_CNT, + REG_TX_CFGRD0_CNT, + REG_TX_CFGWR0_CNT, + REG_TX_CFGRD1_CNT, + REG_TX_CFGWR1_CNT, + REG_TX_MSG_CNT, + REG_TX_MSGD_CNT, + REG_TX_CPL_CNT, + REG_TX_CPLD_CNT, + REG_TX_CPLLK_CNT, + REG_TX_CPLDLK_CNT, + REG_TX_FAA_REQ_CNT, + REG_TX_USA_REQ_CNT, + REG_TX_CSA_REQ_CNT, + REG_TX_LOCAL_TLP_PREFIX_CNT, + REG_TX_ENDTOEND_TLP_PREFIX_CNT, + REG_TX_TCFGRD_CNT, + REG_TX_TCFGWR_CNT, + REG_RX_MRD_CNT, + REG_RX_MRDLK_CNT, + REG_RX_MWR_CNT, + REG_RX_IORD_CNT, + REG_RX_IOWR_CNT, + REG_RX_CFGRD0_CNT, + REG_RX_CFGWR0_CNT, + REG_RX_CFGRD1_CNT, + REG_RX_CFGWR1_CNT, + REG_RX_MSG_CNT, + REG_RX_MSGD_CNT, + REG_RX_CPL_CNT, + REG_RX_CPLD_CNT, + REG_RX_CPLLK_CNT, + REG_RX_CPLDLK_CNT, + REG_RX_FAA_REQ_CNT, + REG_RX_USA_REQ_CNT, + REG_RX_CSA_REQ_CNT, + REG_RX_LOCAL_TLP_PREFIX_CNT, + REG_RX_ENDTOEND_TLP_PREFIX_CNT, + REG_RX_TCFGRD_CNT, + REG_RX_TCFGWR_CNT, + REG_WINDOW_TIME_TLP_RX_TYPE_CNT_0, + REG_WINDOW_TIME_TLP_TX_TYPE_CNT_0, + + REG_WINDOW_TIME_TLP_PERFORMANCE_0, + REG_TX_PAYLOAD_TOTAL_0, + REG_TX_HEADER_TOTAL_0, + REG_RX_PAYLOAD_TOTAL_0, + REG_RX_HEADER_TOTAL_0, + + REG_BUFFER_USAGE_LN0, + REG_BUFFER_USAGE_LN0, + REG_BUFFER_USAGE_LN1, + REG_BUFFER_USAGE_LN1, + REG_BUFFER_USAGE_LN2, + REG_BUFFER_USAGE_LN2, + REG_BUFFER_USAGE_LN3, + REG_BUFFER_USAGE_LN3, + REG_BUFFER_USAGE_LN4, + REG_BUFFER_USAGE_LN4, + REG_BUFFER_USAGE_LN5, + REG_BUFFER_USAGE_LN5, + REG_BUFFER_USAGE_LN6, + REG_BUFFER_USAGE_LN6, + REG_BUFFER_USAGE_LN7, + REG_BUFFER_USAGE_LN7, + REG_BUFFER_USAGE_LN8, + REG_BUFFER_USAGE_LN8, + REG_BUFFER_USAGE_LN9, + REG_BUFFER_USAGE_LN9, + REG_BUFFER_USAGE_LN10, + REG_BUFFER_USAGE_LN10, + REG_BUFFER_USAGE_LN11, + REG_BUFFER_USAGE_LN11, + REG_BUFFER_USAGE_LN12, + REG_BUFFER_USAGE_LN12, + REG_BUFFER_USAGE_LN13, + REG_BUFFER_USAGE_LN13, + REG_BUFFER_USAGE_LN14, + REG_BUFFER_USAGE_LN14, + REG_BUFFER_USAGE_LN15, + REG_BUFFER_USAGE_LN15 +}; + +ssize_t phytium_pcie_link_pmu_format_sysfs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dev_ext_attribute *eattr; + + eattr = container_of(attr, struct dev_ext_attribute, attr); + + return sprintf(buf, "%s\n", (char *)eattr->var); +} + +ssize_t phytium_pcie_link_pmu_event_sysfs_show(struct device *dev, + struct device_attribute *attr, + char *page) +{ + struct dev_ext_attribute *eattr; + + eattr = container_of(attr, struct dev_ext_attribute, attr); + unsigned long var_val = (unsigned long)eattr->var; + + if (var_val >= 7 && var_val <= 9) + return sprintf(page, "config=0x%lx,err_sig=?\n", var_val); + + return sprintf(page, "config=0x%lx\n", var_val); +} + +static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = + to_phytium_pcie_link_pmu(dev_get_drvdata(dev)); + + return cpumap_print_to_pagebuf(true, buf, cpumask_of(pcie_link_pmu->on_cpu)); +} + +#define PHYTIUM_PMU_ATTR(_name, _func, _config) \ + (&((struct dev_ext_attribute[]){ \ + { __ATTR(_name, 0444, _func, NULL), (void *)_config } })[0] \ + .attr.attr) + +#define PHYTIUM_PCIE_LINK_PMU_FORMAT_ATTR(_name, _config) \ + PHYTIUM_PMU_ATTR(_name, phytium_pcie_link_pmu_format_sysfs_show, \ + (void *)_config) + +#define PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(_name, _config) \ + PHYTIUM_PMU_ATTR(_name, phytium_pcie_link_pmu_event_sysfs_show, \ + (unsigned long)_config) + +static struct attribute *phytium_pcie_link_pmu_events_attr[] = { + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_xtlh_xdlh_sot, 0x00), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_xtlh_xdlh_eot, 0x01), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rdlh_rtlh_sot, 0x02), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rdlh_rtlh_eot, 0x03), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(dllp_xdlh_xplh_sdp, 0x04), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_xdlh_xplh_stp, 0x05), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_dllp_xdlh_xplh_eot, 0x06), + + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_type_err, 0x07), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(dllp_type_err, 0x08), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(pl_type_err, 0x09), + + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_mrd, 0x0a), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_mrdlk, 0x0b), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_mwr, 0x0c), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_iord, 0x0d), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_iowr, 0x0e), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_cfgrd0, 0x0f), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_cfgwr0, 0x10), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_cfgrd1, 0x11), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_cfgwr1, 0x12), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_msg, 0x13), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_msgd, 0x14), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_cpl, 0x15), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_cpld, 0x16), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_cpllk, 0x17), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_cpldlk, 0x18), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_faa_req, 0x19), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_usa_req, 0x1a), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_csa_req, 0x1b), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_loal_tlp_prefix, 0x1c), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_endtoend_tlp_prefix, 0x1d), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_tcfgrd, 0x1e), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_tcfgwr, 0x1f), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_mrd, 0x20), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_mrdlk, 0x21), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_mwr, 0x22), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_iord, 0x23), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_iowr, 0x24), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_cfgrd0, 0x25), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_cfgwr0, 0x26), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_cfgrd1, 0x27), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_cfgwr1, 0x28), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_msg, 0x29), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_msgd, 0x2a), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_cpl, 0x2b), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_cpld, 0x2c), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_cpllk, 0x2d), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_cpldlk, 0x2e), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_faa_req, 0x2f), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_usa_req, 0x30), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_csa_req, 0x31), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_local_tlp_prefix, 0x32), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_endtoend_tlp_prefix, 0x33), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_tcfgrd, 0x34), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_tcfgwr, 0x35), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_window_time_rx_type, 0x36), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_window_time_tx_type, 0x37), + + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_window_time_performance, 0x38), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_payload_total, 0x39), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_tx_header_total, 0x3a), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_payload_total, 0x3b), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(tlp_rx_header_total, 0x3c), + + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln0, 0x3d), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln0, 0x3e), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln1, 0x3f), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln1, 0x40), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln2, 0x41), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln2, 0x42), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln3, 0x43), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln3, 0x44), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln4, 0x45), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln4, 0x46), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln5, 0x47), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln5, 0x48), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln6, 0x49), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln6, 0x4a), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln7, 0x4b), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln7, 0x4c), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln8, 0x4d), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln8, 0x4e), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln9, 0x4f), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln9, 0x50), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln10, 0x51), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln10, 0x52), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln11, 0x53), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln11, 0x54), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln12, 0x55), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln12, 0x56), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln13, 0x57), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln13, 0x58), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln14, 0x59), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln14, 0x5a), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_curr_usage_ln15, 0x5b), + PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR(buffer_peak_usage_ln15, 0x5c), + NULL +}; + +#define PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR_EXTRACTOR(_name, _config, _start, _end) \ +static inline u32 get_##_name(struct perf_event *event) \ +{ \ + return FIELD_GET(GENMASK_ULL(_end, _start), \ + event->attr._config); \ +} \ + +PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR_EXTRACTOR(eventid, config, 0, 6); +PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR_EXTRACTOR(err_sig, config, 7, 10); +PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR_EXTRACTOR(time_mode, config, 11, 11); +PHYTIUM_PCIE_LINK_PMU_EVENT_ATTR_EXTRACTOR(timer, config1, 0, 63); + +static struct attribute *phytium_pcie_link_pmu_format_attr[] = { + PHYTIUM_PCIE_LINK_PMU_FORMAT_ATTR(event, "config:0-6"), + PHYTIUM_PCIE_LINK_PMU_FORMAT_ATTR(err_sig, "config:7-10"), + PHYTIUM_PCIE_LINK_PMU_FORMAT_ATTR(time_mode, "config:11-11"), + PHYTIUM_PCIE_LINK_PMU_FORMAT_ATTR(timer, "config1:0-63"), + NULL, +}; + +static const struct attribute_group phytium_pcie_link_pmu_format_group = { + .name = "format", + .attrs = phytium_pcie_link_pmu_format_attr, +}; + +static const struct attribute_group phytium_pcie_link_pmu_events_group = { + .name = "events", + .attrs = phytium_pcie_link_pmu_events_attr, +}; + +static DEVICE_ATTR_RO(cpumask); + +static struct attribute *phytium_pcie_link_pmu_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL, +}; + +static const struct attribute_group phytium_pcie_link_pmu_cpumask_attr_group = { + .attrs = phytium_pcie_link_pmu_cpumask_attrs, +}; + +static const struct attribute_group *phytium_pcie_link_pmu_attr_groups[] = { + &phytium_pcie_link_pmu_format_group, + &phytium_pcie_link_pmu_events_group, + &phytium_pcie_link_pmu_cpumask_attr_group, + NULL, +}; + + +static const u32 phytium_pcie_link_err_reg_mask[] = { + REG_TLP_ERR_MASK, + REG_DLLP_ERR_MASK, + REG_PL_ERR_MASK +}; + +static u64 phytium_pcie_link_pmu_read_counter(struct phytium_pcie_link_pmu *pcie_link_pmu, + struct perf_event *event) +{ + u32 val64, val32_l, val32_h; + u32 idx = get_eventid(event); + u32 counter_offset = pcie_link_counter_reg_offset[idx]; + + if (!EVENT_VALID(idx)) { + dev_err(pcie_link_pmu->dev, "Unsupported event index:%d!\n", idx); + return 0; + } + + if (idx >= BUFFER_USAGE_TYPE_0) { + val32_l = readl(pcie_link_pmu->base + counter_offset); + if (idx % 2 == 0) + val32_l = (val32_l & REG_BUFFER_CURR_USAGE_MASK) >> 8; + else + val32_l = val32_l & REG_BUFFER_PEAK_USAGE_MASK; + val64 = (u64)val32_l; + } else if (idx == TLP_WINDOW_TIME_RX_TYPE || idx == TLP_WINDOW_TIME_TX_TYPE) { + val32_l = readl(pcie_link_pmu->base + counter_offset); + val32_h = readl(pcie_link_pmu->base + counter_offset - 4); + val64 = (u64)val32_h << 32 | (u64)val32_l; + } else if (idx > TLP_WINDOW_TIME_TX_TYPE && idx <= TLP_RX_HEADER_TOTAL_TYPE) { + val32_l = readl(pcie_link_pmu->base + counter_offset); + val32_h = readl(pcie_link_pmu->base + counter_offset + 4); + val64 = (u64)val32_h << 32 | (u64)val32_l; + } else { + val32_l = readl(pcie_link_pmu->base + counter_offset); + val64 = (u64)val32_l; + } + return val64; +} + +static void phytium_pcie_link_pmu_clear_all_counters(struct phytium_pcie_link_pmu *pcie_link_pmu) +{ + writel(0xffffffff, pcie_link_pmu->base + REG_SIG_CLEAR); + writel(0x00000000, pcie_link_pmu->base + REG_SIG_CLEAR); + + writel(0x3, pcie_link_pmu->base + REG_TLP_TYPE_CNT_CLEAR); + writel(0x0, pcie_link_pmu->base + REG_TLP_TYPE_CNT_CLEAR); + writel(0x1, pcie_link_pmu->base + REG_CLEAR_TLP_PERFORMANCE); + writel(0x0, pcie_link_pmu->base + REG_CLEAR_TLP_PERFORMANCE); + writel(0x1, pcie_link_pmu->base + REG_CLEAR_BUFFER); + writel(0x0, pcie_link_pmu->base + REG_CLEAR_BUFFER); +} + +static void phytium_pcie_link_pmu_enable_all_counters(struct phytium_pcie_link_pmu *pcie_link_pmu) +{ + writel(0xffffffff, pcie_link_pmu->base + REG_ENABLE); + writel(0x3, pcie_link_pmu->base + REG_TLP_TYPE_CNT_ENABLE); + writel(0x1, pcie_link_pmu->base + REG_ENABLE_TLP_PERFORMANCE); + writel(0x1, pcie_link_pmu->base + REG_ENABLE_BUFFER); +} + +static void phytium_pcie_link_pmu_disable_all_counters(struct phytium_pcie_link_pmu *pcie_link_pmu) +{ + writel(0x00000000, pcie_link_pmu->base + REG_ENABLE); + writel(0x00, pcie_link_pmu->base + REG_TLP_TYPE_CNT_ENABLE); + writel(0x0, pcie_link_pmu->base + REG_ENABLE_TLP_PERFORMANCE); + writel(0x0, pcie_link_pmu->base + REG_ENABLE_BUFFER); +} + +static void phytium_pcie_link_pmu_start_all_counters(struct perf_event *event) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + u32 idx = get_eventid(event); + + if (idx >= TLP_TYPE_CLASSIFY_0 && idx <= TLP_TYPE_CLASSIFY_1) + writel(0x1, pcie_link_pmu->base + REG_START_TYPE_CNT); + else if (idx >= TLP_PERFORM_TYPE_1 && idx < BUFFER_USAGE_TYPE_0) + writel(0x1, pcie_link_pmu->base + REG_START_TLP_PERFORMANCE); + else if (idx >= BUFFER_USAGE_TYPE_0) + writel(0x1, pcie_link_pmu->base + REG_START_BUFFER); +} + +static void phytium_pcie_link_pmu_stop_all_counters(struct perf_event *event) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + u32 idx = get_eventid(event); + + if (idx >= TLP_TYPE_CLASSIFY_0 && idx <= TLP_TYPE_CLASSIFY_1) + writel(0x0, pcie_link_pmu->base + REG_START_TYPE_CNT); + else if (idx >= TLP_PERFORM_TYPE_1 && idx < BUFFER_USAGE_TYPE_0) + writel(0x0, pcie_link_pmu->base + REG_START_TLP_PERFORMANCE); + else if (idx >= BUFFER_USAGE_TYPE_0) + writel(0x0, pcie_link_pmu->base + REG_START_BUFFER); +} + +static void phytium_pcie_link_pmu_set_timer(struct perf_event *event, u64 th_val) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + + u32 val_l, val_h; + + val_l = th_val & 0xFFFFFFFF; + val_h = (th_val >> 32) & 0xFFFFFFFF; + u32 idx = get_eventid(event); + + if (idx >= TLP_TYPE_CLASSIFY_0 && idx <= TLP_TYPE_CLASSIFY_1) { + writel(0x1, pcie_link_pmu->base + REG_CONTROL_TIME_MODE_TYPE); + writel(val_l, pcie_link_pmu->base + REG_TLP_TIMER_TYPE_CNT_0); + writel(val_h, pcie_link_pmu->base + REG_TLP_TIMER_TYPE_CNT_1); + } else if (idx >= TLP_PERFORM_TYPE_1 && idx < BUFFER_USAGE_TYPE_0) { + writel(0x1, pcie_link_pmu->base + REG_CONTROL_TIME_MODE_TLP_PERFORMANCE); + writel(val_l, pcie_link_pmu->base + REG_TIMER_TLP_PERFORMANCE_0); + writel(val_h, pcie_link_pmu->base + REG_TIMER_TLP_PERFORMANCE_1); + } else if (idx >= BUFFER_USAGE_TYPE_0) { + writel(0x1, pcie_link_pmu->base + REG_CONTROL_TIME_MODE_BUFFER); + writel(val_l, pcie_link_pmu->base + REG_TIMER_BUFFER_0); + writel(val_h, pcie_link_pmu->base + REG_TIMER_BUFFER_1); + } +} + +static void phytium_pcie_link_pmu_reset_timer(struct perf_event *event) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + + u32 idx = get_eventid(event); + + if (idx >= TLP_TYPE_CLASSIFY_0 && idx <= TLP_TYPE_CLASSIFY_1) { + writel(0x0, pcie_link_pmu->base + REG_CONTROL_TIME_MODE_TYPE); + writel(0xFFFFFFFF, pcie_link_pmu->base + REG_TLP_TIMER_TYPE_CNT_0); + writel(0xFFFFFFFF, pcie_link_pmu->base + REG_TLP_TIMER_TYPE_CNT_1); + } else if (idx >= TLP_PERFORM_TYPE_1 && idx < BUFFER_USAGE_TYPE_0) { + writel(0x0, pcie_link_pmu->base + REG_CONTROL_TIME_MODE_TLP_PERFORMANCE); + writel(0xFFFFFFFF, pcie_link_pmu->base + REG_TIMER_TLP_PERFORMANCE_0); + writel(0xFFFFFFFF, pcie_link_pmu->base + REG_TIMER_TLP_PERFORMANCE_1); + } else if (idx >= BUFFER_USAGE_TYPE_0) { + writel(0x0, pcie_link_pmu->base + REG_CONTROL_TIME_MODE_BUFFER); + writel(0xFFFFFFFF, pcie_link_pmu->base + REG_TIMER_BUFFER_0); + writel(0xFFFFFFFF, pcie_link_pmu->base + REG_TIMER_BUFFER_1); + } +} + +static int phytium_pcie_link_pmu_mark_event(struct perf_event *event) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + unsigned long *used_mask; + int idx = get_eventid(event); + + used_mask = pcie_link_pmu->pmu_events.used_mask_pcie_link; + + if (test_bit(idx, used_mask)) + return -EAGAIN; + + set_bit(idx, used_mask); + + return idx; +} + +static void phytium_pcie_link_pmu_unmark_event(struct phytium_pcie_link_pmu *pcie_link_pmu, int idx) +{ + unsigned long *used_mask; + + if (!EVENT_VALID(idx)) { + dev_err(pcie_link_pmu->dev, "Unsupported event index:%d!\n", idx); + return; + } + + used_mask = pcie_link_pmu->pmu_events.used_mask_pcie_link; + + clear_bit(idx, used_mask); +} + +static bool phytium_pcie_link_pmu_is_reg_err_sig(u32 event_id, u32 err_id) +{ + if (event_id == PL_ERR_IDX || event_id == DLLP_ERR_IDX) { + if (err_id > PL_DLLP_ERR_NUM) + return false; + } else if (event_id == TLP_ERR_IDX) { + if (err_id > TLP_ERR_NUM) + return false; + } + return true; +} + +static void phytium_pcie_link_pmu_set_reg_err_sig(struct phytium_pcie_link_pmu *pcie_link_pmu, + u32 event_id, u32 err_id) +{ + int err_mask_id = event_id - 7; + + u32 err_reg_mask = phytium_pcie_link_err_reg_mask[err_mask_id]; + u32 val = readl(pcie_link_pmu->base + REG_ERRO_SIG_SEL); + + if (event_id == PL_ERR_IDX) + err_reg_mask &= (err_id << 16); + else if (event_id == DLLP_ERR_IDX) + err_reg_mask &= (err_id << 8); + else + err_reg_mask &= err_id; + val |= err_reg_mask; + + writel(val, pcie_link_pmu->base + REG_ERRO_SIG_SEL); +} + +int phytium_pcie_link_pmu_event_init(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + struct phytium_pcie_link_pmu *pcie_link_pmu; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK) + return -EOPNOTSUPP; + + pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + + if (event->cpu < 0) { + dev_warn(pcie_link_pmu->dev, "Can't provide per-task data!\n"); + return -EINVAL; + } + + if (pcie_link_pmu->on_cpu == -1) + return -EINVAL; + + hwc->idx = -1; + hwc->config_base = event->attr.config; + + event->cpu = pcie_link_pmu->on_cpu; + + return 0; +} + +void phytium_pcie_link_pmu_event_update(struct perf_event *event) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + u64 delta; + + delta = phytium_pcie_link_pmu_read_counter(pcie_link_pmu, event); + local64_add(delta, &event->count); +} + +void phytium_pcie_link_pmu_event_start(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + + hwc->state = 0; + perf_event_update_userpage(event); +} + +void phytium_pcie_link_pmu_event_stop(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + + hwc->state |= PERF_HES_STOPPED; + + if (flags & PERF_EF_UPDATE) + phytium_pcie_link_pmu_event_update(event); +} + +int phytium_pcie_link_pmu_event_add(struct perf_event *event, int flags) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int idx; + u32 event_id = get_eventid(event); + u32 err_id = get_err_sig(event); + u64 event_timer = get_timer(event); + int time_mode = get_time_mode(event); + + if (event_id >= TLP_ERR_IDX && event_id <= PL_ERR_IDX) { + if (phytium_pcie_link_pmu_is_reg_err_sig(event_id, err_id)) + phytium_pcie_link_pmu_set_reg_err_sig(pcie_link_pmu, event_id, err_id); + else { + dev_err(pcie_link_pmu->dev, "Register's err type is incorrect!\n"); + return -EINVAL; + } + } + + if (event_timer != 0 && time_mode != 0) + phytium_pcie_link_pmu_set_timer(event, event_timer); + else + phytium_pcie_link_pmu_start_all_counters(event); + + hwc->state |= PERF_HES_STOPPED; + + idx = phytium_pcie_link_pmu_mark_event(event); + if (idx < 0) + return idx; + + event->hw.idx = idx; + pcie_link_pmu->pmu_events.hw_events[idx] = event; + + return 0; +} + +void phytium_pcie_link_pmu_event_del(struct perf_event *event, int flags) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + u32 event_timer = get_timer(event); + + phytium_pcie_link_pmu_event_stop(event, PERF_EF_UPDATE); + if (event_timer != 0) + phytium_pcie_link_pmu_reset_timer(event); + else + phytium_pcie_link_pmu_stop_all_counters(event); + + phytium_pcie_link_pmu_unmark_event(pcie_link_pmu, hwc->idx); + + perf_event_update_userpage(event); + pcie_link_pmu->pmu_events.hw_events[hwc->idx] = NULL; +} + +void phytium_pcie_link_pmu_enable(struct pmu *pmu) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(pmu); + int event_added = 0; + + event_added = bitmap_weight(pcie_link_pmu->pmu_events.used_mask_pcie_link, + PHYTIUM_PCIE_LINK_MAX_COUNTERS); + + if (event_added) { + phytium_pcie_link_pmu_clear_all_counters(pcie_link_pmu); + phytium_pcie_link_pmu_enable_all_counters(pcie_link_pmu); + } +} + +void phytium_pcie_link_pmu_disable(struct pmu *pmu) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = to_phytium_pcie_link_pmu(pmu); + int event_added = 0; + + event_added = bitmap_weight(pcie_link_pmu->pmu_events.used_mask_pcie_link, + PHYTIUM_PCIE_LINK_MAX_COUNTERS); + + if (event_added) + phytium_pcie_link_pmu_disable_all_counters(pcie_link_pmu); +} + +static const struct acpi_device_id phytium_pcie_link_pmu_acpi_match[] = { + { "PHYT300E", }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, phytium_pcie_link_pmu_acpi_match); + +static int phytium_pcie_link_pmu_version(struct phytium_pcie_link_pmu *pcie_link_pmu, + struct platform_device *pdev) +{ + u32 pidr; + + pidr = readl(pcie_link_pmu->base + PCIE_LINK_DEVCH); + dev_info(pcie_link_pmu->dev, "PIDR=%#x,VER=%#lx.\n", pidr, (pidr & PCIE_LINK_PMU_VER_BIT)); + pidr &= PCIE_LINK_PMU_VER_BIT; + + if (pidr == 0x1) { + pcie_link_pmu->ver = PCIEV1P0; + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + } + + return 0; +} + +static int phytium_pcie_link_pmu_init_data(struct platform_device *pdev, + struct phytium_pcie_link_pmu *pcie_link_pmu) +{ + int ret; + struct resource *res; + + if (device_property_read_u32(&pdev->dev, "phytium,die-id", + &pcie_link_pmu->die_id)) { + dev_err(&pdev->dev, "Can not read phytium,die-id!\n"); + return -EINVAL; + } + + if (device_property_read_u32(&pdev->dev, "phytium,pcie-id", + &pcie_link_pmu->pcie_id)) { + dev_err(&pdev->dev, "Can not read phytium,pcie-id!\n"); + return -EINVAL; + } + + if (device_property_read_u32(&pdev->dev, "phytium,pmu-id", + &pcie_link_pmu->pmu_id)) { + dev_err(&pdev->dev, "Can not read pcie link pmu-id!\n"); +return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pcie_link_pmu->base = devm_ioremap_resource(&pdev->dev, res); + + if (IS_ERR(pcie_link_pmu->base)) { + dev_err(&pdev->dev, + "ioremap failed for pcie_link_pmu base resource\n"); + return PTR_ERR(pcie_link_pmu->base); + } + + ret = phytium_pcie_link_pmu_version(pcie_link_pmu, pdev); + if (ret) + return ret; + + return 0; +} + +static int phytium_pcie_link_pmu_dev_probe(struct platform_device *pdev, + struct phytium_pcie_link_pmu *pcie_link_pmu) +{ + int ret; + + ret = phytium_pcie_link_pmu_init_data(pdev, pcie_link_pmu); + if (ret) + return ret; + + pcie_link_pmu->dev = &pdev->dev; + pcie_link_pmu->on_cpu = -1; + + return 0; +} + +static int phytium_pcie_link_pmu_probe(struct platform_device *pdev) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu; + char *name; + int ret; + + pcie_link_pmu = devm_kzalloc(&pdev->dev, sizeof(*pcie_link_pmu), GFP_KERNEL); + if (!pcie_link_pmu) + return -ENOMEM; + + platform_set_drvdata(pdev, pcie_link_pmu); + + ret = phytium_pcie_link_pmu_dev_probe(pdev, pcie_link_pmu); + if (ret) + return ret; + + ret = cpuhp_state_add_instance(phytium_pcie_link_pmu_hp_state, + &pcie_link_pmu->node); + if (ret) { + dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret); + return ret; + } + + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie%u_link_pmu%u", + pcie_link_pmu->die_id, pcie_link_pmu->pcie_id, + pcie_link_pmu->pmu_id); + pcie_link_pmu->pmu = (struct pmu){ + .name = name, + .module = THIS_MODULE, + .task_ctx_nr = perf_invalid_context, + .event_init = phytium_pcie_link_pmu_event_init, + .pmu_enable = phytium_pcie_link_pmu_enable, + .pmu_disable = phytium_pcie_link_pmu_disable, + .add = phytium_pcie_link_pmu_event_add, + .del = phytium_pcie_link_pmu_event_del, + .start = phytium_pcie_link_pmu_event_start, + .stop = phytium_pcie_link_pmu_event_stop, + .read = phytium_pcie_link_pmu_event_update, + .attr_groups = phytium_pcie_link_pmu_attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + }; + + ret = perf_pmu_register(&pcie_link_pmu->pmu, name, -1); + if (ret) { + dev_err(pcie_link_pmu->dev, "PCIE LINK PMU register failed!\n"); + cpuhp_state_remove_instance_nocalls(phytium_pcie_link_pmu_hp_state, + &pcie_link_pmu->node); + } + + dev_info(pcie_link_pmu->dev, "%s on cpu%d.\n", name, pcie_link_pmu->on_cpu); + return ret; +} + +static int phytium_pcie_link_pmu_remove(struct platform_device *pdev) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = platform_get_drvdata(pdev); + + phytium_pcie_link_pmu_disable_all_counters(pcie_link_pmu); + + perf_pmu_unregister(&pcie_link_pmu->pmu); + cpuhp_state_remove_instance_nocalls(phytium_pcie_link_pmu_hp_state, + &pcie_link_pmu->node); + + return 0; +} + +static struct platform_driver phytium_pcie_link_pmu_driver = { + .driver = { + .name = "phytium_pcie_link_pmu", + .acpi_match_table = ACPI_PTR(phytium_pcie_link_pmu_acpi_match), + .suppress_bind_attrs = true, + }, + .probe = phytium_pcie_link_pmu_probe, + .remove = phytium_pcie_link_pmu_remove, +}; + +int phytium_pcie_link_pmu_online_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = + hlist_entry_safe(node, struct phytium_pcie_link_pmu, node); + + if (!cpumask_test_cpu(cpu, cpumask_of_node(pcie_link_pmu->die_id))) + return 0; + + if (pcie_link_pmu->on_cpu != -1) { + if (!cpumask_test_cpu(pcie_link_pmu->on_cpu, + cpumask_of_node(pcie_link_pmu->die_id))) { + perf_pmu_migrate_context(&pcie_link_pmu->pmu, pcie_link_pmu->on_cpu, cpu); + pcie_link_pmu->on_cpu = cpu; + } + return 0; + } + + pcie_link_pmu->on_cpu = cpu; + + return 0; +} + +int phytium_pcie_link_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node) +{ + struct phytium_pcie_link_pmu *pcie_link_pmu = + hlist_entry_safe(node, struct phytium_pcie_link_pmu, node); + unsigned int target; + cpumask_t available_cpus; + + if (pcie_link_pmu->on_cpu != cpu) + return 0; + + if (cpumask_and(&available_cpus, cpumask_of_node(pcie_link_pmu->die_id), cpu_online_mask) && + cpumask_andnot(&available_cpus, &available_cpus, cpumask_of(cpu))) + target = cpumask_last(&available_cpus); + else { + cpumask_andnot(&available_cpus, cpu_online_mask, cpumask_of(cpu)); + target = cpumask_last(&available_cpus); + } + + if (target >= nr_cpu_ids) { + dev_err(pcie_link_pmu->dev, "offline cpu%d with no target to migrate.\n", cpu); + return 0; + } + + perf_pmu_migrate_context(&pcie_link_pmu->pmu, cpu, target); + pcie_link_pmu->on_cpu = target; + + return 0; +} + +static int __init phytium_pcie_link_pmu_module_init(void) +{ + int ret; + + phytium_pcie_link_pmu_hp_state = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, + "perf/phytium/pcielinkpmu:online", + phytium_pcie_link_pmu_online_cpu, + phytium_pcie_link_pmu_offline_cpu); + if (phytium_pcie_link_pmu_hp_state < 0) { + pr_err("PCIE LINK PMU: setup hotplug, phytium_pcie_link_pmu_hp_state = %d\n", + phytium_pcie_link_pmu_hp_state); + return phytium_pcie_link_pmu_hp_state; + } + + ret = platform_driver_register(&phytium_pcie_link_pmu_driver); + if (ret) + cpuhp_remove_multi_state(phytium_pcie_link_pmu_hp_state); + + return ret; +} +module_init(phytium_pcie_link_pmu_module_init); + +static void __exit phytium_pcie_link_pmu_module_exit(void) +{ + platform_driver_unregister(&phytium_pcie_link_pmu_driver); + cpuhp_remove_multi_state(phytium_pcie_link_pmu_hp_state); +} +module_exit(phytium_pcie_link_pmu_module_exit); + +MODULE_DESCRIPTION("Phytium PCIE LINK PMU driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(PCIE_LINK_PERF_DRIVER_VERSION); +MODULE_AUTHOR("Fu Boyi "); diff --git a/drivers/perf/phytium/phytium_pcie_pmu.c b/drivers/perf/phytium/phytium_pcie_pmu.c index 9172c152756b2..b04fcb8f31608 100644 --- a/drivers/perf/phytium/phytium_pcie_pmu.c +++ b/drivers/perf/phytium/phytium_pcie_pmu.c @@ -33,73 +33,236 @@ #undef pr_fmt #define pr_fmt(fmt) "phytium_pcie_pmu: " fmt -#define PHYTIUM_PCIE_MAX_COUNTERS 18 -#define PCIE_PERF_DRIVER_VERSION "1.3.0" - -#define PCIE_START_TIMER 0x000 -#define PCIE_STOP_TIMER 0x004 -#define PCIE_CLEAR_EVENT 0x008 - -#define PCIE_EVENT_CYCLES 0x0e4 -#define PCIE_TPOINT_END_L 0x0e4 -#define PCIE_TPOINT_END_H 0x0e8 -#define PCIE_STATE_STOP 0x0ec - -#define PCIE_EVENT_AW 0x100 -#define PCIE_EVENT_W_LAST 0x104 -#define PCIE_EVENT_B 0x108 -#define PCIE_EVENT_AR 0x10c -#define PCIE_EVENT_R_LAST 0x110 -#define PCIE_EVENT_R_FULL 0x114 -#define PCIE_EVENT_R_ERR 0x118 -#define PCIE_EVENT_W_ERR 0x11c -#define PCIE_EVENT_DELAY_RD 0x120 -#define PCIE_EVENT_DELAY_WR 0x124 -#define PCIE_EVENT_RD_MAX 0x128 -#define PCIE_EVENT_RD_MIN 0x12c -#define PCIE_EVENT_WR_MAX 0x130 -#define PCIE_EVENT_WR_MIN 0x134 - -#define PCIE_EVENT_W_DATA 0x200 -#define PCIE_W_DATA_BASE 0x200 - +#define PCIE_PERF_DRIVER_VERSION "1.4.0" + +#define PHYTIUM_PCIE_MAX_COUNTERS 112 +#define PHYTIUM_PCIE_V1_COUNTERS_NUM 18 +#define PHYTIUM_PCIE_V2_COUNTERS_NUM 112 +#define PHYTIUM_PCIE_EVENTS_MAX_MASK 0x7F + +#define PCIE_START_TIMER 0x000 +#define PCIE_STOP_TIMER 0x004 +#define PCIE_CLEAR_EVENT 0x008 +#define PCIE_SET_TIMER_L 0x00C +#define PCIE_SET_TIMER_H 0x010 +#define PCIE_TRIG_MODE 0x014 +#define PCIE_NOW_STATE 0x0E0 +#define PCIE_STATE_STOP 0x0EC +#define PCIE_EVENT_THRESHOLD_EN 0x01C +#define PCIE_EVENT_THRESHOLD_0 0x020 +#define PCIE_EVENT_THRESHOLD_1 0x024 +#define PCIE_PMU_OVER_STATE 0x2 + +#define PCIE_TPOINT_END_L 0x0E4 +#define PCIE_TPOINT_END_H 0x0E8 + +#define PCIE_V2_PMU_TIME_RG_THD_0 0x030 +#define PCIE_V2_PMU_TIME_RG_THD_1 0x034 +#define PCIE_V2_PMU_TIME_RG_THD_2 0x038 +#define PCIE_V2_PMU_SORT_MODE 0x080 +#define PCIE_V2_PMU_REQID_CFG 0x084 +#define PCIE_V2_PMU_AT_CFG 0x090 +#define PCIE_V2_PMU_MEM_STOP_EN 0x094 +#define PCIE_V2_PMU_NOW_STATE 0x0E0 +#define PCIE_V2_PMU_TPOINT_END_L 0x0E4 +#define PCIE_V2_PMU_TPOINT_END_H 0x0E8 +#define PCIE_V2_PMU_STATE_STOP 0x0EC + +#define PCIE_V2_TIMEOUT_EN 0x600 +#define PCIE_V2_TIMEOUT_THRESHOLD 0x604 + +#define PCIE_V2_PMU_CLK_EN 0x650 +#define PCIE_V2_PMU_CHANNEL_SEL 0x654 + +#define PCIEA_V2P0_CHANNEL_NUM 8 +#define PCIEB_V2P0_CHANNEL_NUM 6 +#define PCIEC_V2P0_CHANNEL_NUM 5 + +#define PCIE_EVENT_CYCLES 0x0E4 +#define PCIE_EVENT_AW 0x100 +#define PCIE_EVENT_W_LAST 0x104 +#define PCIE_EVENT_B 0x108 +#define PCIE_EVENT_AR 0x10c +#define PCIE_EVENT_R_LAST 0x110 +#define PCIE_EVENT_R_FULL 0x114 +#define PCIE_EVENT_R_ERR 0x118 +#define PCIE_EVENT_W_ERR 0x11c +#define PCIE_EVENT_W_DATA 0x200 +#define PCIE_W_DATA_BASE 0x200 + +#define PCIE_EVENT_DELAY_RD 0x120 +#define PCIE_EVENT_DELAY_WR 0x124 +#define PCIE_EVENT_RD_MAX 0x128 +#define PCIE_EVENT_RD_MIN 0x12c +#define PCIE_EVENT_WR_MAX 0x130 +#define PCIE_EVENT_WR_MIN 0x134 #define PCIE_EVENT_RDELAY_TIME 0x300 -#define PCIE_RDELAY_TIME_BASE 0x300 - #define PCIE_EVENT_WDELAY_TIME 0x700 -#define PCIE_WDELAY_TIME_BASE 0x700 - -#define PCIE_DATA_WIDTH 0xe04 - -#define PCIE_PMU_OFL_STOP_TYPE_VAL 0x10 -#define SYS_AIDR_EL1 sys_reg(3, 1, 0, 0, 7) -#define SOC_ID_PS230XX 0x8 -#define SOC_ID_PS240XX 0x6 -#define MIDR_PSXX 0x700f8620 +#define PCIE_V2_G0_EVENT_AW 0x100 +#define PCIE_V2_G0_EVENT_W_LAST 0x104 +#define PCIE_V2_G0_EVENT_B 0x108 +#define PCIE_V2_G0_EVENT_AR 0x10C +#define PCIE_V2_G0_EVENT_R_LAST 0x110 +#define PCIE_V2_G0_EVENT_R_FULL 0x114 +#define PCIE_V2_G0_EVENT_R_ERR 0x118 +#define PCIE_V2_G0_EVENT_W_ERR 0x11C +#define PCIE_V2_G0_EVENT_ATOMIC_AW 0x120 +#define PCIE_V2_G0_EVENT_R_DISCARDED 0x124 +#define PCIE_V2_G0_EVENT_AT_AW 0x128 +#define PCIE_V2_G0_EVENT_AT_AR 0x12C +#define PCIE_V2_G0_EVENT_W_DATA_AW_L 0x140 +#define PCIE_V2_G0_EVENT_W_DATA_AW_H 0x144 +#define PCIE_V2_EVENT_W_DATA 0x200 +#define PCIE_V2_G0_EVENT_DELAY_RD 0x400 +#define PCIE_V2_G0_EVENT_DELAY_WR 0x404 +#define PCIE_V2_G0_EVENT_DELAY_RD_MAX 0x408 +#define PCIE_V2_G0_EVENT_DELAY_RD_MIN 0x40C +#define PCIE_V2_G0_EVENT_DELAY_WR_MAX 0x410 +#define PCIE_V2_G0_EVENT_DELAY_WR_MIN 0x414 +#define PCIE_V2_G0_EVENT_DELAY_RD_TOTAL_H 0x418 +#define PCIE_V2_G0_EVENT_DELAY_RD_TOTAL_L 0x41C +#define PCIE_V2_G0_EVENT_DELAY_WR_TOTAL_H 0x420 +#define PCIE_V2_G0_EVENT_DELAY_WR_TOTAL_L 0x424 +#define PCIE_V2_G0_EVENT_DELAY_RD_0 0x428 +#define PCIE_V2_G0_EVENT_DELAY_RD_1 0x42C +#define PCIE_V2_G0_EVENT_DELAY_RD_2 0x430 +#define PCIE_V2_G0_EVENT_DELAY_RD_3 0x434 +#define PCIE_V2_G0_EVENT_DELAY_WR_0 0x438 +#define PCIE_V2_G0_EVENT_DELAY_WR_1 0x43C +#define PCIE_V2_G0_EVENT_DELAY_WR_2 0x440 +#define PCIE_V2_G0_EVENT_DELAY_WR_3 0x444 + +#define PCIE_V2_G1_EVENT_AW 0x900 +#define PCIE_V2_G1_EVENT_B 0x908 +#define PCIE_V2_G1_EVENT_AR 0x90C +#define PCIE_V2_G1_EVENT_R_LAST 0x910 +#define PCIE_V2_G1_EVENT_R_FULL 0x914 +#define PCIE_V2_G1_EVENT_R_ERR 0x918 +#define PCIE_V2_G1_EVENT_W_ERR 0x91C +#define PCIE_V2_G1_EVENT_ATOMIC_AW 0x920 +#define PCIE_V2_G1_EVENT_AT_AW 0x928 +#define PCIE_V2_G1_EVENT_AT_AR 0x92C +#define PCIE_V2_G1_EVENT_W_DATA_AW_L 0x940 +#define PCIE_V2_G1_EVENT_W_DATA_AW_H 0x944 +#define PCIE_V2_G1_EVENT_DELAY_RD 0xa00 +#define PCIE_V2_G1_EVENT_DELAY_WR 0xa04 +#define PCIE_V2_G1_EVENT_DELAY_RD_MAX 0xa08 +#define PCIE_V2_G1_EVENT_DELAY_RD_MIN 0xa0C +#define PCIE_V2_G1_EVENT_DELAY_WR_MAX 0xa10 +#define PCIE_V2_G1_EVENT_DELAY_WR_MIN 0xa14 +#define PCIE_V2_G1_EVENT_DELAY_RD_TOTAL_H 0xa18 +#define PCIE_V2_G1_EVENT_DELAY_RD_TOTAL_L 0xa1C +#define PCIE_V2_G1_EVENT_DELAY_WR_TOTAL_H 0xa20 +#define PCIE_V2_G1_EVENT_DELAY_WR_TOTAL_L 0xa24 +#define PCIE_V2_G1_EVENT_DELAY_RD_0 0xa28 +#define PCIE_V2_G1_EVENT_DELAY_RD_1 0xa2C +#define PCIE_V2_G1_EVENT_DELAY_RD_2 0xa30 +#define PCIE_V2_G1_EVENT_DELAY_RD_3 0xa34 +#define PCIE_V2_G1_EVENT_DELAY_WR_0 0xa38 +#define PCIE_V2_G1_EVENT_DELAY_WR_1 0xa3C +#define PCIE_V2_G1_EVENT_DELAY_WR_2 0xa40 +#define PCIE_V2_G1_EVENT_DELAY_WR_3 0xa44 + +#define PCIE_V2_G2_EVENT_AW 0xb00 +#define PCIE_V2_G2_EVENT_B 0xb08 +#define PCIE_V2_G2_EVENT_AR 0xb0C +#define PCIE_V2_G2_EVENT_R_LAST 0xb10 +#define PCIE_V2_G2_EVENT_R_FULL 0xb14 +#define PCIE_V2_G2_EVENT_R_ERR 0xb18 +#define PCIE_V2_G2_EVENT_W_ERR 0xb1C +#define PCIE_V2_G2_EVENT_ATOMIC_AW 0xb20 +#define PCIE_V2_G2_EVENT_AT_AW 0xb28 +#define PCIE_V2_G2_EVENT_AT_AR 0xb2C +#define PCIE_V2_G2_EVENT_W_DATA_AW_L 0xb40 +#define PCIE_V2_G2_EVENT_W_DATA_AW_H 0xb44 +#define PCIE_V2_G2_EVENT_DELAY_RD 0xc00 +#define PCIE_V2_G2_EVENT_DELAY_WR 0xc04 +#define PCIE_V2_G2_EVENT_DELAY_RD_MAX 0xc08 +#define PCIE_V2_G2_EVENT_DELAY_RD_MIN 0xc0C +#define PCIE_V2_G2_EVENT_DELAY_WR_MAX 0xc10 +#define PCIE_V2_G2_EVENT_DELAY_WR_MIN 0xc14 +#define PCIE_V2_G2_EVENT_DELAY_RD_TOTAL_H 0xc18 +#define PCIE_V2_G2_EVENT_DELAY_RD_TOTAL_L 0xc1C +#define PCIE_V2_G2_EVENT_DELAY_WR_TOTAL_H 0xc20 +#define PCIE_V2_G2_EVENT_DELAY_WR_TOTAL_L 0xc24 +#define PCIE_V2_G2_EVENT_DELAY_RD_0 0xc28 +#define PCIE_V2_G2_EVENT_DELAY_RD_1 0xc2C +#define PCIE_V2_G2_EVENT_DELAY_RD_2 0xc30 +#define PCIE_V2_G2_EVENT_DELAY_RD_3 0xc34 +#define PCIE_V2_G2_EVENT_DELAY_WR_0 0xc38 +#define PCIE_V2_G2_EVENT_DELAY_WR_1 0xc3C +#define PCIE_V2_G2_EVENT_DELAY_WR_2 0xc40 +#define PCIE_V2_G2_EVENT_DELAY_WR_3 0xc44 + +#define PCIE_V2_G3_EVENT_AW 0xd00 +#define PCIE_V2_G3_EVENT_B 0xd08 +#define PCIE_V2_G3_EVENT_AR 0xd0C +#define PCIE_V2_G3_EVENT_R_LAST 0xd10 +#define PCIE_V2_G3_EVENT_R_FULL 0xd14 +#define PCIE_V2_G3_EVENT_R_ERR 0xd18 +#define PCIE_V2_G3_EVENT_W_ERR 0xd1C +#define PCIE_V2_G3_EVENT_ATOMIC_AW 0xd20 +#define PCIE_V2_G3_EVENT_AT_AW 0xd28 +#define PCIE_V2_G3_EVENT_AT_AR 0xd2C +#define PCIE_V2_G3_EVENT_W_DATA_AW_L 0xd40 +#define PCIE_V2_G3_EVENT_W_DATA_AW_H 0xd44 +#define PCIE_V2_G3_EVENT_DELAY_RD 0xe00 +#define PCIE_V2_G3_EVENT_DELAY_WR 0xe04 +#define PCIE_V2_G3_EVENT_DELAY_RD_MAX 0xe08 +#define PCIE_V2_G3_EVENT_DELAY_RD_MIN 0xe0C +#define PCIE_V2_G3_EVENT_DELAY_WR_MAX 0xe10 +#define PCIE_V2_G3_EVENT_DELAY_WR_MIN 0xe14 +#define PCIE_V2_G3_EVENT_DELAY_RD_TOTAL_H 0xe18 +#define PCIE_V2_G3_EVENT_DELAY_RD_TOTAL_L 0xe1C +#define PCIE_V2_G3_EVENT_DELAY_WR_TOTAL_H 0xe20 +#define PCIE_V2_G3_EVENT_DELAY_WR_TOTAL_L 0xe24 +#define PCIE_V2_G3_EVENT_DELAY_RD_0 0xe28 +#define PCIE_V2_G3_EVENT_DELAY_RD_1 0xe2C +#define PCIE_V2_G3_EVENT_DELAY_RD_2 0xe30 +#define PCIE_V2_G3_EVENT_DELAY_RD_3 0xe34 +#define PCIE_V2_G3_EVENT_DELAY_WR_0 0xe38 +#define PCIE_V2_G3_EVENT_DELAY_WR_1 0xe3C +#define PCIE_V2_G3_EVENT_DELAY_WR_2 0xe40 +#define PCIE_V2_G3_EVENT_DELAY_WR_3 0xe44 + +#define PCIE_V1_AXI_CLK_FRE 0xE00 +#define PCIE_V1_DATA_WIDTH 0xE04 + +#define PCIE_V2_AXI_CLK_FRE 0xF00 +#define PCIE_V2_DATA_WIDTH 0xF04 + +#define PCIE_PMU_PIDR 0xFE0 +#define PCIE_PMU_VER_BIT GENMASK(7, 0) +#define PCIE_PMU_PART_BIT GENMASK(11, 8) +#define PMU_CHANNEL_SEL_BIT GENMASK(2, 0) + +#define PCIEV2_PMU_CLK_EN_BIT BIT(0) +#define PCIE_EVENT_AW_THD_ENBIT BIT(0) +#define PCIE_EVENT_AR_THD_ENBIT BIT(1) + +#define PCIE_EVENT_THD0_STOP_TYPE 0x1 +#define PCIE_EVENT_THD1_STOP_TYPE 0x2 +#define PCIE_TIME_STOP_TYPE 0x10 + +#define PCIE_PMU_DEFAULT_THD0 1000000 +#define PCIE_PMU_DEFAULT_THD1 10000000 +#define PCIE_PMU_DEFAULT_THD2 100000000 #define to_phytium_pcie_pmu(p) (container_of(p, struct phytium_pcie_pmu, pmu)) +#define GET_PCIE_EVENTID(hwc) (hwc->config_base & PHYTIUM_PCIE_EVENTS_MAX_MASK) +#define EVENT_VALID_V1(idx) ((idx >= 0) && (idx < PHYTIUM_PCIE_V1_COUNTERS_NUM)) +#define EVENT_VALID_V2(idx) ((idx >= 0) && (idx < PHYTIUM_PCIE_V2_COUNTERS_NUM)) + enum { - PS230XX = 0x1, - PS240XX = 0x2, + PCIEA_V1P0 = 1, + PCIEA_V1P5 = 3, + PCIEA_V2P0 = 5, + PCIEB_V2P0, + PCIEC_V2P0, }; -static inline int phytium_socs_type(void) -{ - unsigned int soc_id, cpu_id; - - soc_id = read_sysreg_s(SYS_AIDR_EL1); - cpu_id = read_cpuid_id(); - - if ((soc_id == SOC_ID_PS230XX) && (cpu_id == MIDR_PSXX)) - return PS230XX; - else if ((soc_id == SOC_ID_PS240XX) && (cpu_id == MIDR_PSXX)) - return PS240XX; - else - return 0; -} - static int phytium_pcie_pmu_hp_state; struct phytium_pcie_pmu_hwevents { @@ -107,31 +270,71 @@ struct phytium_pcie_pmu_hwevents { DECLARE_BITMAP(used_mask, PHYTIUM_PCIE_MAX_COUNTERS); }; +struct phytium_pcie_pmu; + +struct phytium_pcie_pmu_ops { + void (*get_event_config)(struct perf_event *event, struct phytium_pcie_pmu *pmu); + int (*set_event_config)(struct perf_event *event, struct phytium_pcie_pmu *pmu); + void (*reset_event_config)(struct phytium_pcie_pmu *pmu); + u64 (*read_counter)(struct phytium_pcie_pmu *pmu, struct hw_perf_event *event); + void (*enable_clk)(struct phytium_pcie_pmu *pmu); + void (*disable_clk)(struct phytium_pcie_pmu *pmu); + void (*clear_all_counters)(struct phytium_pcie_pmu *pmu); + void (*start_all_counters)(struct phytium_pcie_pmu *pmu); + void (*stop_all_counters)(struct phytium_pcie_pmu *pmu); + unsigned long (*get_stop_state)(struct phytium_pcie_pmu *pmu); + u32 (*get_counter_offset)(u32 idx); + void (*reset_pmu)(struct phytium_pcie_pmu *pmu); +}; + +struct phytium_pcie_pmu_event_cfg { + u32 chansel; + u32 by_timer; + u32 by_trig_mode; + u32 delay_thd0_us; + u32 delay_thd1_us; + u32 delay_thd2_us; + u32 by_evthod; + u32 aw_threshold; + u32 ar_threshold; + u32 by_reqid; + u32 bdf_id; + u32 sort_mode; + u32 byargs0; + u32 byargs1; + u64 timer_64; +}; + struct phytium_pcie_pmu { struct device *dev; void __iomem *base; void __iomem *cfg_base; void __iomem *irq_reg; struct pmu pmu; + const struct phytium_pcie_pmu_ops *ops; struct phytium_pcie_pmu_hwevents pmu_events; + struct phytium_pcie_pmu_event_cfg event_cfg; u32 die_id; + u32 dev_id; u32 pcie_id; u32 pmu_id; int on_cpu; int irq; int irq_bit; + int cnts_num; + int channel_num; struct hlist_node node; int ctrler_id; int real_ctrler; u32 clk_bits; - u32 soc_version; + u32 ver; }; -#define GET_PCIE_EVENTID(hwc) (hwc->config_base & 0x1F) - -#define EVENT_VALID(idx) ((idx >= 0) && (idx < PHYTIUM_PCIE_MAX_COUNTERS)) +static const char pcie_type_part_name[] = { + 'a', 'b', 'c' +}; -static const u32 pcie_counter_reg_offset[] = { +static const u32 pcie_v1_counter_reg_offset[] = { PCIE_EVENT_CYCLES, PCIE_EVENT_AW, PCIE_EVENT_W_LAST, PCIE_EVENT_B, PCIE_EVENT_AR, PCIE_EVENT_R_LAST, PCIE_EVENT_R_FULL, PCIE_EVENT_R_ERR, PCIE_EVENT_W_ERR, @@ -140,9 +343,63 @@ static const u32 pcie_counter_reg_offset[] = { PCIE_EVENT_W_DATA, PCIE_EVENT_RDELAY_TIME, PCIE_EVENT_WDELAY_TIME }; +static const u32 pcie_v2_counter_reg_offset[] = { + PCIE_EVENT_CYCLES, + PCIE_V2_G0_EVENT_AW, PCIE_V2_G0_EVENT_B, PCIE_V2_G0_EVENT_AR, + PCIE_V2_G0_EVENT_R_LAST, PCIE_V2_G0_EVENT_R_FULL, + PCIE_V2_G0_EVENT_R_ERR, PCIE_V2_G0_EVENT_W_ERR, + PCIE_V2_G0_EVENT_ATOMIC_AW, PCIE_V2_G0_EVENT_AT_AW, PCIE_V2_G0_EVENT_AT_AR, + PCIE_V2_G0_EVENT_W_DATA_AW_L, PCIE_V2_G0_EVENT_DELAY_RD, PCIE_V2_G0_EVENT_DELAY_WR, + PCIE_V2_G0_EVENT_DELAY_RD_MAX, PCIE_V2_G0_EVENT_DELAY_RD_MIN, + PCIE_V2_G0_EVENT_DELAY_WR_MAX, PCIE_V2_G0_EVENT_DELAY_WR_MIN, + PCIE_V2_G0_EVENT_DELAY_RD_TOTAL_H, PCIE_V2_G0_EVENT_DELAY_WR_TOTAL_H, + PCIE_V2_G0_EVENT_DELAY_RD_0, PCIE_V2_G0_EVENT_DELAY_RD_1, + PCIE_V2_G0_EVENT_DELAY_RD_2, PCIE_V2_G0_EVENT_DELAY_RD_3, + PCIE_V2_G0_EVENT_DELAY_WR_0, PCIE_V2_G0_EVENT_DELAY_WR_1, + PCIE_V2_G0_EVENT_DELAY_WR_2, PCIE_V2_G0_EVENT_DELAY_WR_3, + PCIE_V2_EVENT_W_DATA, PCIE_V2_G0_EVENT_W_LAST, PCIE_V2_G0_EVENT_R_DISCARDED, + PCIE_V2_G1_EVENT_AW, PCIE_V2_G1_EVENT_B, PCIE_V2_G1_EVENT_AR, + PCIE_V2_G1_EVENT_R_LAST, PCIE_V2_G1_EVENT_R_FULL, + PCIE_V2_G1_EVENT_R_ERR, PCIE_V2_G1_EVENT_W_ERR, + PCIE_V2_G1_EVENT_ATOMIC_AW, PCIE_V2_G1_EVENT_AT_AW, PCIE_V2_G1_EVENT_AT_AR, + PCIE_V2_G1_EVENT_W_DATA_AW_L, PCIE_V2_G1_EVENT_DELAY_RD, PCIE_V2_G1_EVENT_DELAY_WR, + PCIE_V2_G1_EVENT_DELAY_RD_MAX, PCIE_V2_G1_EVENT_DELAY_RD_MIN, + PCIE_V2_G1_EVENT_DELAY_WR_MAX, PCIE_V2_G1_EVENT_DELAY_WR_MIN, + PCIE_V2_G1_EVENT_DELAY_RD_TOTAL_H, PCIE_V2_G1_EVENT_DELAY_WR_TOTAL_H, + PCIE_V2_G1_EVENT_DELAY_RD_0, PCIE_V2_G1_EVENT_DELAY_RD_1, + PCIE_V2_G1_EVENT_DELAY_RD_2, PCIE_V2_G1_EVENT_DELAY_RD_3, + PCIE_V2_G1_EVENT_DELAY_WR_0, PCIE_V2_G1_EVENT_DELAY_WR_1, + PCIE_V2_G1_EVENT_DELAY_WR_2, PCIE_V2_G1_EVENT_DELAY_WR_3, + PCIE_V2_G2_EVENT_AW, PCIE_V2_G2_EVENT_B, PCIE_V2_G2_EVENT_AR, + PCIE_V2_G2_EVENT_R_LAST, PCIE_V2_G2_EVENT_R_FULL, + PCIE_V2_G2_EVENT_R_ERR, PCIE_V2_G2_EVENT_W_ERR, + PCIE_V2_G2_EVENT_ATOMIC_AW, PCIE_V2_G2_EVENT_AT_AW, PCIE_V2_G2_EVENT_AT_AR, + PCIE_V2_G2_EVENT_W_DATA_AW_L, PCIE_V2_G2_EVENT_DELAY_RD, PCIE_V2_G2_EVENT_DELAY_WR, + PCIE_V2_G2_EVENT_DELAY_RD_MAX, PCIE_V2_G2_EVENT_DELAY_RD_MIN, + PCIE_V2_G2_EVENT_DELAY_WR_MAX, PCIE_V2_G2_EVENT_DELAY_WR_MIN, + PCIE_V2_G2_EVENT_DELAY_RD_TOTAL_H, PCIE_V2_G2_EVENT_DELAY_WR_TOTAL_H, + PCIE_V2_G2_EVENT_DELAY_RD_0, PCIE_V2_G2_EVENT_DELAY_RD_1, + PCIE_V2_G2_EVENT_DELAY_RD_2, PCIE_V2_G2_EVENT_DELAY_RD_3, + PCIE_V2_G2_EVENT_DELAY_WR_0, PCIE_V2_G2_EVENT_DELAY_WR_1, + PCIE_V2_G2_EVENT_DELAY_WR_2, PCIE_V2_G2_EVENT_DELAY_WR_3, + PCIE_V2_G3_EVENT_AW, PCIE_V2_G3_EVENT_B, PCIE_V2_G3_EVENT_AR, + PCIE_V2_G3_EVENT_R_LAST, PCIE_V2_G3_EVENT_R_FULL, + PCIE_V2_G3_EVENT_R_ERR, PCIE_V2_G3_EVENT_W_ERR, + PCIE_V2_G3_EVENT_ATOMIC_AW, PCIE_V2_G3_EVENT_AT_AW, + PCIE_V2_G3_EVENT_AT_AR, PCIE_V2_G3_EVENT_W_DATA_AW_L, + PCIE_V2_G3_EVENT_DELAY_RD, PCIE_V2_G3_EVENT_DELAY_WR, + PCIE_V2_G3_EVENT_DELAY_RD_MAX, PCIE_V2_G3_EVENT_DELAY_RD_MIN, + PCIE_V2_G3_EVENT_DELAY_WR_MAX, PCIE_V2_G3_EVENT_DELAY_WR_MIN, + PCIE_V2_G3_EVENT_DELAY_RD_TOTAL_H, PCIE_V2_G3_EVENT_DELAY_WR_TOTAL_H, + PCIE_V2_G3_EVENT_DELAY_RD_0, PCIE_V2_G3_EVENT_DELAY_RD_1, + PCIE_V2_G3_EVENT_DELAY_RD_2, PCIE_V2_G3_EVENT_DELAY_RD_3, + PCIE_V2_G3_EVENT_DELAY_WR_0, PCIE_V2_G3_EVENT_DELAY_WR_1, + PCIE_V2_G3_EVENT_DELAY_WR_2, PCIE_V2_G3_EVENT_DELAY_WR_3 +}; + ssize_t phytium_pcie_pmu_format_sysfs_show(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct dev_ext_attribute *eattr; @@ -152,8 +409,8 @@ ssize_t phytium_pcie_pmu_format_sysfs_show(struct device *dev, } ssize_t phytium_pcie_pmu_event_sysfs_show(struct device *dev, - struct device_attribute *attr, - char *page) + struct device_attribute *attr, + char *page) { struct dev_ext_attribute *eattr; @@ -176,7 +433,7 @@ static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, { __ATTR(_name, 0444, _func, NULL), (void *)_config } })[0] \ .attr.attr) -#define PHYTIUM_PCIE_PMU_FORMAT_ATTR(_name, _config) \ +#define PHYTIUM_PCIE_PMU_FORMAT_ATTR(_name, _config) \ PHYTIUM_PMU_ATTR(_name, phytium_pcie_pmu_format_sysfs_show, \ (void *)_config) @@ -184,19 +441,79 @@ static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, PHYTIUM_PMU_ATTR(_name, phytium_pcie_pmu_event_sysfs_show, \ (unsigned long)_config) -static struct attribute *phytium_pcie_pmu_format_attr[] = { +#define PCIE_PMU_V1_EVENT_ATTR_EXTRACTOR_U32(_name, _config, _start, _end) \ +static inline u32 pcie_pmu_v1_get_u32_##_name(struct perf_event *event) \ +{ \ + return FIELD_GET(GENMASK_ULL(_end, _start), \ + event->attr._config); \ +} + +#define PCIE_PMU_V1_EVENT_ATTR_EXTRACTOR_U64(_name, _config, _start, _end) \ +static inline u64 pcie_pmu_v1_get_u64_##_name(struct perf_event *event) \ +{ \ + return FIELD_GET(GENMASK_ULL(_end, _start), \ + event->attr._config); \ +} + +#define PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(_name, _config, _start, _end) \ +static inline u32 pcie_pmu_v2_get_##_name(struct perf_event *event) \ +{ \ + return FIELD_GET(GENMASK_ULL(_end, _start), \ + event->attr._config); \ +} + +PCIE_PMU_V1_EVENT_ATTR_EXTRACTOR_U32(event, config, 0, 4); +PCIE_PMU_V1_EVENT_ATTR_EXTRACTOR_U32(ctrler, config, 8, 10); +PCIE_PMU_V1_EVENT_ATTR_EXTRACTOR_U64(timer, config1, 0, 63); + +static struct attribute *phytium_pcie_pmu_v1_format_attr[] = { PHYTIUM_PCIE_PMU_FORMAT_ATTR(event, "config:0-4"), PHYTIUM_PCIE_PMU_FORMAT_ATTR(ctrler, "config:8-10"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(timer, "config1:0-63"), + NULL, +}; + +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(event, config, 0, 6); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(chansel, config, 7, 9); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(by_timer, config, 10, 10); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(by_evthod, config, 11, 11); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(by_trig_mode, config, 12, 12); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(sort_mode, config, 13, 14); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(bdf_id, config, 16, 31); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(delay_thd0_us, config, 32, 63); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(delay_thd1_us, config1, 0, 31); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(delay_thd2_us, config1, 32, 63); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(byargs0, config2, 0, 31); +PCIE_PMU_V2_EVENT_ATTR_EXTRACTOR(byargs1, config2, 32, 63); + +static struct attribute *phytium_pcie_pmu_v2_format_attr[] = { + PHYTIUM_PCIE_PMU_FORMAT_ATTR(event, "config:0-6"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(chansel, "config:7-9"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(by_timer, "config:10-10"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(by_evthod, "config:11-11"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(by_trig_mode, "config:12-12"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(sort_mode, "config:13-14"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(bdf_id, "config:16-31"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(delay_thd0_us, "config:32-63"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(delay_thd1_us, "config1:0-31"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(delay_thd2_us, "config1:32-63"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(byargs0, "config2:0-31"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(byargs1, "config2:32-63"), NULL, }; -static const struct attribute_group phytium_pcie_pmu_format_group = { +static const struct attribute_group phytium_pcie_pmu_v1_format_group = { .name = "format", - .attrs = phytium_pcie_pmu_format_attr, + .attrs = phytium_pcie_pmu_v1_format_attr, }; -static struct attribute *phytium_pcie_pmu_events_attr[] = { - PHYTIUM_PCIE_PMU_EVENT_ATTR(cycles, 0x00), +static const struct attribute_group phytium_pcie_pmu_v2_format_group = { + .name = "format", + .attrs = phytium_pcie_pmu_v2_format_attr, +}; + +static struct attribute *phytium_pcie_pmu_v1_events_attr[] = { + PHYTIUM_PCIE_PMU_EVENT_ATTR(pcie_cycles, 0x00), PHYTIUM_PCIE_PMU_EVENT_ATTR(aw, 0x01), PHYTIUM_PCIE_PMU_EVENT_ATTR(w_last, 0x02), PHYTIUM_PCIE_PMU_EVENT_ATTR(b, 0x03), @@ -217,9 +534,130 @@ static struct attribute *phytium_pcie_pmu_events_attr[] = { NULL, }; -static const struct attribute_group phytium_pcie_pmu_events_group = { +static struct attribute *phytium_pcie_pmu_v2_events_attr[] = { + PHYTIUM_PCIE_PMU_EVENT_ATTR(pcie_cycles, 0x0), + PHYTIUM_PCIE_PMU_EVENT_ATTR(aw_g0, 0x1), + PHYTIUM_PCIE_PMU_EVENT_ATTR(b_g0, 0x2), + PHYTIUM_PCIE_PMU_EVENT_ATTR(ar_g0, 0x3), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_last_g0, 0x4), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_full_g0, 0x5), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_err_g0, 0x6), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_err_g0, 0x7), + PHYTIUM_PCIE_PMU_EVENT_ATTR(atomic_aw_g0, 0x8), + PHYTIUM_PCIE_PMU_EVENT_ATTR(at_aw_g0, 0x9), + PHYTIUM_PCIE_PMU_EVENT_ATTR(at_ar_g0, 0xA), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_data_aw_g0, 0xB), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_g0, 0xC), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_g0, 0xD), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_max_g0, 0xE), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_min_g0, 0xF), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_max_g0, 0x10), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_min_g0, 0x11), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_total_g0, 0x12), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_total_g0, 0x13), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_0_g0, 0x14), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_1_g0, 0x15), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_2_g0, 0x16), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_3_g0, 0x17), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_0_g0, 0x18), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_1_g0, 0x19), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_2_g0, 0x1A), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_3_g0, 0x1B), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_data_g0, 0x1C), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_last_g0, 0x1D), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_discarded_g0, 0x1E), + PHYTIUM_PCIE_PMU_EVENT_ATTR(aw_g1, 0x1F), + PHYTIUM_PCIE_PMU_EVENT_ATTR(b_g1, 0x20), + PHYTIUM_PCIE_PMU_EVENT_ATTR(ar_g1, 0x21), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_last_g1, 0x22), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_full_g1, 0x23), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_err_g1, 0x24), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_err_g1, 0x25), + PHYTIUM_PCIE_PMU_EVENT_ATTR(atomic_aw_g1, 0x26), + PHYTIUM_PCIE_PMU_EVENT_ATTR(at_aw_g1, 0x27), + PHYTIUM_PCIE_PMU_EVENT_ATTR(at_ar_g1, 0x28), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_data_aw_g1, 0x29), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_g1, 0x2A), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_g1, 0x2B), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_max_g1, 0x2C), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_min_g1, 0x2D), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_max_g1, 0x2E), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_min_g1, 0x2F), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_total_g1, 0x30), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_total_g1, 0x31), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_0_g1, 0x32), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_1_g1, 0x33), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_2_g1, 0x34), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_3_g1, 0x35), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_0_g1, 0x36), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_1_g1, 0x37), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_2_g1, 0x38), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_3_g1, 0x39), + PHYTIUM_PCIE_PMU_EVENT_ATTR(aw_g2, 0x3A), + PHYTIUM_PCIE_PMU_EVENT_ATTR(b_g2, 0x3B), + PHYTIUM_PCIE_PMU_EVENT_ATTR(ar_g2, 0x3C), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_last_g2, 0x3D), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_full_g2, 0x3E), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_err_g2, 0x3F), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_err_g2, 0x40), + PHYTIUM_PCIE_PMU_EVENT_ATTR(atomic_aw_g2, 0x41), + PHYTIUM_PCIE_PMU_EVENT_ATTR(at_aw_g2, 0x42), + PHYTIUM_PCIE_PMU_EVENT_ATTR(at_ar_g2, 0x43), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_data_aw_g2, 0x44), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_g2, 0x45), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_g2, 0x46), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_max_g2, 0x47), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_min_g2, 0x48), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_max_g2, 0x49), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_min_g2, 0x4A), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_total_g2, 0x4B), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_total_g2, 0x4C), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_0_g2, 0x4D), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_1_g2, 0x4E), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_2_g2, 0x4F), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_3_g2, 0x50), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_0_g2, 0x51), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_1_g2, 0x52), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_2_g2, 0x53), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_3_g2, 0x54), + PHYTIUM_PCIE_PMU_EVENT_ATTR(aw_g3, 0x55), + PHYTIUM_PCIE_PMU_EVENT_ATTR(b_g3, 0x56), + PHYTIUM_PCIE_PMU_EVENT_ATTR(ar_g3, 0x57), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_last_g3, 0x58), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_full_g3, 0x59), + PHYTIUM_PCIE_PMU_EVENT_ATTR(r_err_g3, 0x5A), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_err_g3, 0x5B), + PHYTIUM_PCIE_PMU_EVENT_ATTR(atomic_aw_g3, 0x5C), + PHYTIUM_PCIE_PMU_EVENT_ATTR(at_aw_g3, 0x5D), + PHYTIUM_PCIE_PMU_EVENT_ATTR(at_ar_g3, 0x5E), + PHYTIUM_PCIE_PMU_EVENT_ATTR(w_data_aw_g3, 0x5F), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_g3, 0x60), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_g3, 0x61), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_max_g3, 0x62), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_min_g3, 0x63), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_max_g3, 0x64), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_min_g3, 0x65), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_total_g3, 0x66), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_total_g3, 0x67), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_0_g3, 0x68), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_1_g3, 0x69), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_2_g3, 0x6A), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_rd_3_g3, 0x6B), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_0_g3, 0x6C), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_1_g3, 0x6D), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_2_g3, 0x6E), + PHYTIUM_PCIE_PMU_EVENT_ATTR(delay_wr_3_g3, 0x6F), + NULL, +}; + +static const struct attribute_group phytium_pcie_pmu_v1_events_group = { + .name = "events", + .attrs = phytium_pcie_pmu_v1_events_attr, +}; + +static const struct attribute_group phytium_pcie_pmu_v2_events_group = { .name = "events", - .attrs = phytium_pcie_pmu_events_attr, + .attrs = phytium_pcie_pmu_v2_events_attr, }; static DEVICE_ATTR_RO(cpumask); @@ -233,19 +671,374 @@ static const struct attribute_group phytium_pcie_pmu_cpumask_attr_group = { .attrs = phytium_pcie_pmu_cpumask_attrs, }; -static const struct attribute_group *phytium_pcie_pmu_attr_groups[] = { - &phytium_pcie_pmu_format_group, - &phytium_pcie_pmu_events_group, +static const struct attribute_group *phytium_pcie_pmu_v1_attr_groups[] = { + &phytium_pcie_pmu_v1_format_group, + &phytium_pcie_pmu_v1_events_group, + &phytium_pcie_pmu_cpumask_attr_group, + NULL, +}; + +static const struct attribute_group *phytium_pcie_pmu_v2_attr_groups[] = { + &phytium_pcie_pmu_v2_format_group, + &phytium_pcie_pmu_v2_events_group, &phytium_pcie_pmu_cpumask_attr_group, NULL, }; -static u32 phytium_pcie_pmu_get_event_ctrler(struct perf_event *event) +static void phytium_pcie_pmu_v1_set_timer(struct phytium_pcie_pmu *pcie_pmu, u64 th_val) +{ + u32 val_l, val_h; + + val_l = th_val & 0xFFFFFFFF; + val_h = (th_val >> 32) & 0xFFFFFFFF; + writel(val_l, pcie_pmu->base + PCIE_SET_TIMER_L); + writel(val_h, pcie_pmu->base + PCIE_SET_TIMER_H); +} + +static void phytium_pcie_pmu_v1_reset_timer(struct phytium_pcie_pmu *pcie_pmu) +{ + writel(0xFFFFFFFF, pcie_pmu->base + PCIE_SET_TIMER_L); + writel(0xFFFFFFFF, pcie_pmu->base + PCIE_SET_TIMER_H); +} + +static void phytium_pcie_pmu_v1_select_ctrler(struct phytium_pcie_pmu *pcie_pmu) +{ + u32 val, offset; + u32 mask = 0xfffffffc; + + if (pcie_pmu->ver == PCIEA_V1P0) { + if (pcie_pmu->pmu_id == 2) { + mask = 0xffffffcf; + offset = 0x0; + } else + offset = 0xc; + } else { + offset = 0x170; + } + + val = readl(pcie_pmu->cfg_base + offset); + val &= mask; + val |= pcie_pmu->real_ctrler; + writel(val, pcie_pmu->cfg_base + offset); +} + +static void phytium_pcie_pmu_v2_set_timer(struct phytium_pcie_pmu *pcie_pmu, + u64 th_val) +{ + u32 val_l, val_h; + + val_l = th_val & 0xFFFFFFFF; + val_h = (th_val >> 32) & 0xFFFFFFFF; + + writel(val_l, pcie_pmu->base + PCIE_SET_TIMER_L); + writel(val_h, pcie_pmu->base + PCIE_SET_TIMER_H); + +} + +static void phytium_pcie_pmu_v2_reset_timer(struct phytium_pcie_pmu *pcie_pmu) +{ + writel(0xFFFFFFFF, pcie_pmu->base + PCIE_SET_TIMER_L); + writel(0xFFFFFFFF, pcie_pmu->base + PCIE_SET_TIMER_H); + +} + +static void phytium_pcie_pmu_v2_set_delay_threshold(struct phytium_pcie_pmu *pcie_pmu) +{ + u32 clk_fre; + u32 thd0_val, thd1_val, thd2_val; + + // MHz + clk_fre = readl(pcie_pmu->base + PCIE_V2_AXI_CLK_FRE); + + thd0_val = clk_fre * pcie_pmu->event_cfg.delay_thd0_us; + thd1_val = clk_fre * pcie_pmu->event_cfg.delay_thd1_us; + thd2_val = clk_fre * pcie_pmu->event_cfg.delay_thd2_us; + + writel(thd0_val, pcie_pmu->base + PCIE_V2_PMU_TIME_RG_THD_0); + writel(thd1_val, pcie_pmu->base + PCIE_V2_PMU_TIME_RG_THD_1); + writel(thd1_val, pcie_pmu->base + PCIE_V2_PMU_TIME_RG_THD_2); +} + +static void phytium_pcie_pmu_v2_reset_delay_threshold(struct phytium_pcie_pmu *pcie_pmu) +{ + writel(PCIE_PMU_DEFAULT_THD0, pcie_pmu->base + PCIE_V2_PMU_TIME_RG_THD_0); + writel(PCIE_PMU_DEFAULT_THD1, pcie_pmu->base + PCIE_V2_PMU_TIME_RG_THD_1); + writel(PCIE_PMU_DEFAULT_THD2, pcie_pmu->base + PCIE_V2_PMU_TIME_RG_THD_2); +} + +static void phytium_pcie_pmu_v2_set_event_trig_mode(struct phytium_pcie_pmu *pcie_pmu) +{ + writel(0x1, pcie_pmu->base + PCIE_TRIG_MODE); +} + +static void phytium_pcie_pmu_v2_reset_event_trig_mode(struct phytium_pcie_pmu *pcie_pmu) +{ + writel(0, pcie_pmu->base + PCIE_TRIG_MODE); +} + +static void phytium_pcie_pmu_v2_set_event_threshold(struct phytium_pcie_pmu *pcie_pmu, + u32 val, u32 en_bit, u32 offset) +{ + writel(en_bit, pcie_pmu->base + PCIE_EVENT_THRESHOLD_EN); + writel(val, pcie_pmu->base + offset); +} + +static void phytium_pcie_pmu_v2_reset_event_threshold(struct phytium_pcie_pmu *pcie_pmu) +{ + writel(0x0, pcie_pmu->base + PCIE_EVENT_THRESHOLD_EN); + writel(0xFFFFFFFF, pcie_pmu->base + PCIE_EVENT_THRESHOLD_0); + writel(0xFFFFFFFF, pcie_pmu->base + PCIE_EVENT_THRESHOLD_1); +} + +static void phytium_pcie_pmu_v2_select_monitor_channel(struct phytium_pcie_pmu *pcie_pmu) +{ + /* + *peu: 0:c0, 1:c1, 2:c2, 3:c3, 4:iommu_tbu, 5:qtw, 6:pio_in, 7:vdm_in + *pxu: 0:c0, 1:c1, 2:vdm, 3:pio, 4:qtw, 5:iommu_out + *pcu: 0:pio_in, 2:ncc dma_out, 3:iommu_out,4:c0 dma + */ + writel(pcie_pmu->real_ctrler, pcie_pmu->cfg_base + PCIE_V2_PMU_CHANNEL_SEL); +} + +static void phytium_pcie_pmu_v2_set_event_group_sort_mode(struct phytium_pcie_pmu *pcie_pmu) +{ + writel(pcie_pmu->event_cfg.sort_mode, pcie_pmu->base + PCIE_V2_PMU_SORT_MODE); +} + +static void phytium_pcie_pmu_v2_reset_event_group_sort_mode(struct phytium_pcie_pmu *pcie_pmu) +{ + writel(0, pcie_pmu->base + PCIE_V2_PMU_SORT_MODE); +} + +static void phytium_pcie_pmu_v2_set_bdf_id_cfg(struct phytium_pcie_pmu *pcie_pmu, u32 bdf_id) +{ + bdf_id &= 0xFFFF; + writel(bdf_id, pcie_pmu->base + PCIE_V2_PMU_REQID_CFG); +} + +static void phytium_pcie_pmu_v2_reset_bdf_id_cfg(struct phytium_pcie_pmu *pcie_pmu) { - return FIELD_GET(GENMASK(10, 8), event->attr.config); + writel(0, pcie_pmu->base + PCIE_V2_PMU_REQID_CFG); } -static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, +static void phytium_pcie_pmu_v1_get_event_config(struct perf_event *event, + struct phytium_pcie_pmu *pcie_pmu) +{ + pcie_pmu->event_cfg.chansel = pcie_pmu_v1_get_u32_ctrler(event); + pcie_pmu->event_cfg.timer_64 = pcie_pmu_v1_get_u64_timer(event); +} + +static void phytium_pcie_pmu_v2_get_event_config(struct perf_event *event, + struct phytium_pcie_pmu *pcie_pmu) +{ + u32 delay_thd0_us, delay_thd1_us, delay_thd2_us; + + pcie_pmu->event_cfg.chansel = pcie_pmu_v2_get_chansel(event); + pcie_pmu->event_cfg.by_timer = pcie_pmu_v2_get_by_timer(event); + pcie_pmu->event_cfg.by_evthod = pcie_pmu_v2_get_by_evthod(event); + pcie_pmu->event_cfg.by_trig_mode = pcie_pmu_v2_get_by_trig_mode(event); + pcie_pmu->event_cfg.sort_mode = pcie_pmu_v2_get_sort_mode(event); + pcie_pmu->event_cfg.bdf_id = pcie_pmu_v2_get_bdf_id(event); + pcie_pmu->event_cfg.byargs0 = pcie_pmu_v2_get_byargs0(event); + pcie_pmu->event_cfg.byargs1 = pcie_pmu_v2_get_byargs1(event); + delay_thd0_us = pcie_pmu_v2_get_delay_thd0_us(event); + delay_thd1_us = pcie_pmu_v2_get_delay_thd1_us(event); + delay_thd2_us = pcie_pmu_v2_get_delay_thd2_us(event); + if (delay_thd0_us + delay_thd1_us + delay_thd2_us == 0) { + pcie_pmu->event_cfg.delay_thd0_us = PCIE_PMU_DEFAULT_THD0; + pcie_pmu->event_cfg.delay_thd1_us = PCIE_PMU_DEFAULT_THD1; + pcie_pmu->event_cfg.delay_thd2_us = PCIE_PMU_DEFAULT_THD2; + } else { + pcie_pmu->event_cfg.delay_thd0_us = delay_thd0_us; + pcie_pmu->event_cfg.delay_thd1_us = delay_thd1_us; + pcie_pmu->event_cfg.delay_thd2_us = delay_thd2_us; + } + +} + +static int phytium_pcie_pmu_v1_set_event_config(struct perf_event *event, + struct phytium_pcie_pmu *pcie_pmu) +{ + if (pcie_pmu->event_cfg.timer_64 > 0) + phytium_pcie_pmu_v1_set_timer(pcie_pmu, pcie_pmu->event_cfg.timer_64); + + if (pcie_pmu->ver == PCIEA_V1P5) { + if (pcie_pmu->pmu_id == 2) { + if (pcie_pmu->event_cfg.chansel == 0) + pcie_pmu->event_cfg.chansel = 2; + else if ((pcie_pmu->event_cfg.chansel < 2) || + (pcie_pmu->event_cfg.chansel > 3)) { + dev_warn(pcie_pmu->dev, "Wrong ctrler id(%d) for pciea%u-pmu2!\n", + pcie_pmu->event_cfg.chansel, pcie_pmu->pcie_id); + return -EINVAL; + } + if (pcie_pmu->ctrler_id != pcie_pmu->event_cfg.chansel) { + pcie_pmu->ctrler_id = pcie_pmu->event_cfg.chansel; + pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; + phytium_pcie_pmu_v1_select_ctrler(pcie_pmu); + } + } else { + if (pcie_pmu->event_cfg.chansel != 0) { + dev_warn(pcie_pmu->dev, "Don't set ctrler id(%d) for pciea%u-pmu%d!\n", + pcie_pmu->event_cfg.chansel, pcie_pmu->pcie_id, + pcie_pmu->pmu_id); + return -EINVAL; + } + pcie_pmu->ctrler_id = pcie_pmu->pmu_id; + pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; + } + } else if (pcie_pmu->ver == PCIEA_V1P0) { + switch (pcie_pmu->pmu_id) { + case 0: + if (pcie_pmu->event_cfg.chansel != 0) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pciea%u-pmu0!\n", + pcie_pmu->event_cfg.chansel, pcie_pmu->pcie_id); + return -EINVAL; + } + break; + case 1: + if (pcie_pmu->event_cfg.chansel == 0) + pcie_pmu->event_cfg.chansel = 1; + else if ((pcie_pmu->event_cfg.chansel < 1) || + (pcie_pmu->event_cfg.chansel > 3)) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pciea%u-pmu1!\n", + pcie_pmu->event_cfg.chansel, pcie_pmu->pcie_id); + return -EINVAL; + } + break; + case 2: + if (pcie_pmu->event_cfg.chansel == 0) + pcie_pmu->event_cfg.chansel = 4; + else if ((pcie_pmu->event_cfg.chansel < 4) || + (pcie_pmu->event_cfg.chansel > 7)) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pciea%u-pmu2!\n", + pcie_pmu->event_cfg.chansel, pcie_pmu->pcie_id); + return -EINVAL; + } + break; + default: + dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", + pcie_pmu->pmu_id); + return -EINVAL; + } + + pcie_pmu->ctrler_id = pcie_pmu->event_cfg.chansel; + switch (pcie_pmu->pmu_id) { + case 0: + case 1: + pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; + break; + case 2: + pcie_pmu->real_ctrler = (pcie_pmu->ctrler_id - 4) * 16; + break; + default: + dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", + pcie_pmu->pmu_id); + return -EINVAL; + } + phytium_pcie_pmu_v1_select_ctrler(pcie_pmu); + } + + return 0; +} + +static int phytium_pcie_pmu_v2_set_event_config(struct perf_event *event, + struct phytium_pcie_pmu *pcie_pmu) +{ + pcie_pmu->ctrler_id = pcie_pmu->event_cfg.chansel; + + if (pcie_pmu->event_cfg.chansel >= pcie_pmu->channel_num) { + dev_err(pcie_pmu->dev, "Wrong ctrler id(%d) for pcie-pmu!\n", + pcie_pmu->event_cfg.chansel); + return -EINVAL; + } + + pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; + phytium_pcie_pmu_v2_select_monitor_channel(pcie_pmu); + + if ((pcie_pmu->event_cfg.delay_thd0_us < pcie_pmu->event_cfg.delay_thd1_us) + && (pcie_pmu->event_cfg.delay_thd1_us < pcie_pmu->event_cfg.delay_thd2_us)) { + phytium_pcie_pmu_v2_set_delay_threshold(pcie_pmu); + } else { + dev_err(pcie_pmu->dev, "Wrong delay threshold value for pcie%u-pmu%d!\n", + pcie_pmu->pcie_id, pcie_pmu->pmu_id); + + dev_err(pcie_pmu->dev, "Wrong value:(delay_thd0_us:%d,delay_thd1_us:%d,delay_thd2_us:%d).\n", + pcie_pmu->event_cfg.delay_thd0_us, pcie_pmu->event_cfg.delay_thd1_us, + pcie_pmu->event_cfg.delay_thd2_us); + return -EINVAL; + } + + if (pcie_pmu->event_cfg.by_trig_mode) + phytium_pcie_pmu_v2_set_event_trig_mode(pcie_pmu); + + if (pcie_pmu->event_cfg.by_evthod) { + if (pcie_pmu->event_cfg.by_timer) { + dev_err(pcie_pmu->dev, "The by_ethod and by_timer are set incorrectly!"); + dev_err(pcie_pmu->dev, "Cannot be set for pcie%u-pmu%d at the same time!", + pcie_pmu->pcie_id, pcie_pmu->pmu_id); + return -EINVAL; + } + + if (pcie_pmu->event_cfg.byargs0 > 0) { + pcie_pmu->event_cfg.aw_threshold = pcie_pmu->event_cfg.byargs0; + phytium_pcie_pmu_v2_set_event_threshold(pcie_pmu, + pcie_pmu->event_cfg.aw_threshold, + PCIE_EVENT_AW_THD_ENBIT, PCIE_EVENT_THRESHOLD_0); + } else if (pcie_pmu->event_cfg.byargs1 > 0) { + pcie_pmu->event_cfg.ar_threshold = pcie_pmu->event_cfg.byargs1; + phytium_pcie_pmu_v2_set_event_threshold(pcie_pmu, + pcie_pmu->event_cfg.ar_threshold, + PCIE_EVENT_AR_THD_ENBIT, PCIE_EVENT_THRESHOLD_1); + } + } else if (pcie_pmu->event_cfg.by_timer == 1 && pcie_pmu->event_cfg.byargs0 > 0) { + pcie_pmu->event_cfg.timer_64 = pcie_pmu->event_cfg.byargs0; + phytium_pcie_pmu_v2_set_timer(pcie_pmu, pcie_pmu->event_cfg.timer_64); + } + + if (pcie_pmu->event_cfg.sort_mode > 1) + phytium_pcie_pmu_v2_set_bdf_id_cfg(pcie_pmu, pcie_pmu->event_cfg.bdf_id); + + phytium_pcie_pmu_v2_set_event_group_sort_mode(pcie_pmu); + + return 0; +} + +static void phytium_pcie_pmu_v1_reset_event_config(struct phytium_pcie_pmu *pcie_pmu) +{ + phytium_pcie_pmu_v1_reset_timer(pcie_pmu); + pcie_pmu->event_cfg.timer_64 = 0; + pcie_pmu->event_cfg.chansel = -1; +} + +static void phytium_pcie_pmu_v2_reset_event_config(struct phytium_pcie_pmu *pcie_pmu) +{ + phytium_pcie_pmu_v2_reset_timer(pcie_pmu); + phytium_pcie_pmu_v2_reset_event_trig_mode(pcie_pmu); + phytium_pcie_pmu_v2_reset_delay_threshold(pcie_pmu); + phytium_pcie_pmu_v2_reset_event_threshold(pcie_pmu); + phytium_pcie_pmu_v2_reset_event_group_sort_mode(pcie_pmu); + phytium_pcie_pmu_v2_reset_bdf_id_cfg(pcie_pmu); + pcie_pmu->event_cfg.by_timer = 0; + pcie_pmu->event_cfg.by_evthod = 0; + pcie_pmu->event_cfg.by_trig_mode = 0; + pcie_pmu->event_cfg.sort_mode = 0; + pcie_pmu->event_cfg.bdf_id = 0; + pcie_pmu->event_cfg.byargs0 = 0; + pcie_pmu->event_cfg.byargs1 = 0; + pcie_pmu->event_cfg.timer_64 = 0; + pcie_pmu->event_cfg.chansel = -1; + pcie_pmu->event_cfg.aw_threshold = 0; + pcie_pmu->event_cfg.ar_threshold = 0; + pcie_pmu->event_cfg.delay_thd0_us = PCIE_PMU_DEFAULT_THD0; + pcie_pmu->event_cfg.delay_thd1_us = PCIE_PMU_DEFAULT_THD1; + pcie_pmu->event_cfg.delay_thd2_us = PCIE_PMU_DEFAULT_THD2; +} + +static u64 phytium_pcie_pmu_v1_read_counter(struct phytium_pcie_pmu *pcie_pmu, struct hw_perf_event *hwc) { u32 idx = GET_PCIE_EVENTID(hwc); @@ -253,15 +1046,15 @@ static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, pcie_data_width; u64 val64 = 0; int i; - u32 counter_offset = pcie_counter_reg_offset[idx]; + u32 counter_offset = pcie_pmu->ops->get_counter_offset(idx); u32 rdelay_num = 127; - if (!EVENT_VALID(idx)) { + if (!EVENT_VALID_V1(idx)) { dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); return 0; } - if (pcie_pmu->soc_version == PS240XX && pcie_pmu->pmu_id == 3) + if (pcie_pmu->ver == PCIEA_V1P5 && pcie_pmu->pmu_id == 3) rdelay_num = 63; switch (idx) { @@ -271,7 +1064,7 @@ static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, val64 = (u64)cycle_h << 32 | (u64)cycle_l; break; case 15: - pcie_data_width = readl(pcie_pmu->base + PCIE_DATA_WIDTH); + pcie_data_width = readl(pcie_pmu->base + PCIE_V1_DATA_WIDTH); for (i = 0; i < (pcie_data_width / 8); i++) { w_data = readl(pcie_pmu->base + counter_offset + 4 * i); val64 += w_data; @@ -288,10 +1081,8 @@ static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, break; case 17: for (i = 0; i <= 63; i++) { - wdelay_l = - readl(pcie_pmu->base + counter_offset + 4 * i); - wdelay_h = readl(pcie_pmu->base + counter_offset + - 4 * i + 4); + wdelay_l = readl(pcie_pmu->base + counter_offset + 4 * i); + wdelay_h = readl(pcie_pmu->base + counter_offset + 4 * i + 4); val64 += (u64)wdelay_h << 32 | (u64)wdelay_l; } break; @@ -299,10 +1090,65 @@ static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, val64 = readl(pcie_pmu->base + counter_offset); break; } + + return val64; +} + +static u64 phytium_pcie_pmu_v2_read_counter(struct phytium_pcie_pmu *pcie_pmu, + struct hw_perf_event *hwc) +{ + int i; + u64 val64; + u32 w_data, pcie_data_width, val_l, val_h; + u32 idx = GET_PCIE_EVENTID(hwc); + u32 counter_offset = pcie_pmu->ops->get_counter_offset(idx); + + if (!EVENT_VALID_V2(idx)) { + dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); + return 0; + } + + switch (idx) { + case 0x0: + case 0xb: + case 0x29: + case 0x44: + case 0x5f: + // cycles、w_data_aw_g* + val_l = readl(pcie_pmu->base + counter_offset); + val_h = readl(pcie_pmu->base + counter_offset + 4); + val64 = (u64)val_h << 32 | (u64)val_l; + break; + case 0x1C: + // w_data_g0 + pcie_data_width = readl(pcie_pmu->base + PCIE_V2_DATA_WIDTH); + val64 = 0; + for (i = 0; i < (pcie_data_width / 8); i++) { + w_data = readl(pcie_pmu->base + counter_offset + 4 * i); + val64 += w_data; + } + break; + case 0x12: + case 0x13: + case 0x30: + case 0x31: + case 0x4b: + case 0x4c: + case 0x66: + case 0x67: + // rd_total_g*、wr_total_g* + val_l = readl(pcie_pmu->base + counter_offset + 4); + val_h = readl(pcie_pmu->base + counter_offset); + val64 = (u64)val_h << 32 | (u64)val_l; + break; + default: + val64 = readl(pcie_pmu->base + counter_offset); + break; + } return val64; } -static void phytium_pcie_pmu_enable_clk(struct phytium_pcie_pmu *pcie_pmu) +static void phytium_pcie_pmu_v1_enable_clk(struct phytium_pcie_pmu *pcie_pmu) { u32 val; @@ -311,35 +1157,34 @@ static void phytium_pcie_pmu_enable_clk(struct phytium_pcie_pmu *pcie_pmu) writel(val, pcie_pmu->cfg_base); } -static void phytium_pcie_pmu_disable_clk(struct phytium_pcie_pmu *pcie_pmu) +static void phytium_pcie_pmu_v1_disable_clk(struct phytium_pcie_pmu *pcie_pmu) { u32 val; + writel(0x1, pcie_pmu->base + PCIE_CLEAR_EVENT); + val = readl(pcie_pmu->cfg_base); val &= ~(pcie_pmu->clk_bits); + writel(val, pcie_pmu->cfg_base); } -static void phytium_pcie_pmu_select_ctrler(struct phytium_pcie_pmu *pcie_pmu) +static void phytium_pcie_pmu_v2_enable_clk(struct phytium_pcie_pmu *pcie_pmu) { - u32 val, offset; - u32 mask = 0xfffffffc; + u32 val; - if (pcie_pmu->soc_version == PS230XX) { - if (pcie_pmu->pmu_id == 2) { - mask = 0xffffffcf; - offset = 0x0; - } else - offset = 0xc; - } else { - offset = 0x170; - } + val = readl(pcie_pmu->cfg_base + PCIE_V2_PMU_CLK_EN); + val |= (pcie_pmu->clk_bits); + writel(val, pcie_pmu->cfg_base + PCIE_V2_PMU_CLK_EN); +} - val = readl(pcie_pmu->cfg_base + offset); - val &= mask; - val |= pcie_pmu->real_ctrler; - writel(val, pcie_pmu->cfg_base + offset); +static void phytium_pcie_pmu_v2_disable_clk(struct phytium_pcie_pmu *pcie_pmu) +{ + u32 val; + val = readl(pcie_pmu->cfg_base + PCIE_V2_PMU_CLK_EN); + val &= ~(pcie_pmu->clk_bits); + writel(val, pcie_pmu->cfg_base + PCIE_V2_PMU_CLK_EN); } static void @@ -369,6 +1214,65 @@ phytium_pcie_pmu_get_stop_state(struct phytium_pcie_pmu *pcie_pmu) return val; } +static unsigned long +phytium_pcie_pmu_get_now_state(struct phytium_pcie_pmu *pcie_pmu) +{ + unsigned long val; + + val = (unsigned long)readl(pcie_pmu->base + PCIE_NOW_STATE); + return val; +} + +static u32 phytium_pcie_pmu_v1_get_counter_offset(u32 idx) +{ + return pcie_v1_counter_reg_offset[idx]; +} + +static u32 phytium_pcie_pmu_v2_get_counter_offset(u32 idx) +{ + return pcie_v2_counter_reg_offset[idx]; +} + +void phytium_pcie_pmu_v1_reset(struct phytium_pcie_pmu *pcie_pmu) +{ + phytium_pcie_pmu_clear_all_counters(pcie_pmu); +} + +void phytium_pcie_pmu_v2_reset(struct phytium_pcie_pmu *pcie_pmu) +{ + phytium_pcie_pmu_clear_all_counters(pcie_pmu); +} + +static const struct phytium_pcie_pmu_ops phytium_pcie_pmu_v1_ops = { + .get_event_config = phytium_pcie_pmu_v1_get_event_config, + .set_event_config = phytium_pcie_pmu_v1_set_event_config, + .reset_event_config = phytium_pcie_pmu_v1_reset_event_config, + .read_counter = phytium_pcie_pmu_v1_read_counter, + .enable_clk = phytium_pcie_pmu_v1_enable_clk, + .disable_clk = phytium_pcie_pmu_v1_disable_clk, + .clear_all_counters = phytium_pcie_pmu_clear_all_counters, + .start_all_counters = phytium_pcie_pmu_start_all_counters, + .stop_all_counters = phytium_pcie_pmu_stop_all_counters, + .get_stop_state = phytium_pcie_pmu_get_stop_state, + .get_counter_offset = phytium_pcie_pmu_v1_get_counter_offset, + .reset_pmu = phytium_pcie_pmu_v1_reset, +}; + +static const struct phytium_pcie_pmu_ops phytium_pcie_pmu_v2_ops = { + .get_event_config = phytium_pcie_pmu_v2_get_event_config, + .set_event_config = phytium_pcie_pmu_v2_set_event_config, + .reset_event_config = phytium_pcie_pmu_v2_reset_event_config, + .read_counter = phytium_pcie_pmu_v2_read_counter, + .enable_clk = phytium_pcie_pmu_v2_enable_clk, + .disable_clk = phytium_pcie_pmu_v2_disable_clk, + .clear_all_counters = phytium_pcie_pmu_clear_all_counters, + .start_all_counters = phytium_pcie_pmu_start_all_counters, + .stop_all_counters = phytium_pcie_pmu_stop_all_counters, + .get_stop_state = phytium_pcie_pmu_get_stop_state, + .get_counter_offset = phytium_pcie_pmu_v2_get_counter_offset, + .reset_pmu = phytium_pcie_pmu_v2_reset, +}; + static unsigned long phytium_pcie_pmu_get_irq_flag(struct phytium_pcie_pmu *pcie_pmu) { @@ -386,6 +1290,18 @@ static int phytium_pcie_pmu_mark_event(struct perf_event *event) int idx = GET_PCIE_EVENTID(hwc); + if (pcie_pmu->ver < PCIEA_V2P0) { + if (!EVENT_VALID_V1(idx)) { + dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); + return -ENODEV; + } + } else { + if (!EVENT_VALID_V2(idx)) { + dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); + return -ENODEV; + } + } + if (test_bit(idx, used_mask)) return -EAGAIN; @@ -397,9 +1313,16 @@ static int phytium_pcie_pmu_mark_event(struct perf_event *event) static void phytium_pcie_pmu_unmark_event(struct phytium_pcie_pmu *pcie_pmu, int idx) { - if (!EVENT_VALID(idx)) { - dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); - return; + if (pcie_pmu->ver < PCIEA_V2P0) { + if (!EVENT_VALID_V1(idx)) { + dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); + return; + } + } else { + if (!EVENT_VALID_V2(idx)) { + dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); + return; + } } clear_bit(idx, pcie_pmu->pmu_events.used_mask); @@ -409,7 +1332,6 @@ int phytium_pcie_pmu_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; struct phytium_pcie_pmu *pcie_pmu; - u32 event_ctrler; if (event->attr.type != event->pmu->type) return -ENOENT; @@ -424,90 +1346,12 @@ int phytium_pcie_pmu_event_init(struct perf_event *event) return -EINVAL; } - if ((event->attr.config & 0x1F) > PHYTIUM_PCIE_MAX_COUNTERS) + if ((event->attr.config & PHYTIUM_PCIE_EVENTS_MAX_MASK) > pcie_pmu->cnts_num) return -EINVAL; if (pcie_pmu->on_cpu == -1) return -EINVAL; - if (pcie_pmu->soc_version == PS240XX) { - event_ctrler = phytium_pcie_pmu_get_event_ctrler(event); - if (pcie_pmu->pmu_id == 2) { - if (event_ctrler == 0) - event_ctrler = 2; - else if ((event_ctrler < 2) || (event_ctrler > 3)) { - dev_warn(pcie_pmu->dev, "Wrong ctrler id(%d) for pcie-pmu2!\n", - event_ctrler); - return -EINVAL; - } - if (pcie_pmu->ctrler_id != event_ctrler) { - pcie_pmu->ctrler_id = event_ctrler; - pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; - phytium_pcie_pmu_select_ctrler(pcie_pmu); - } - } else { - if (event_ctrler != 0) { - dev_warn(pcie_pmu->dev, "Don't need to set ctrler id(%d) for pcie-pmu%d!\n", - event_ctrler, pcie_pmu->pmu_id); - return -EINVAL; - } - pcie_pmu->ctrler_id = pcie_pmu->pmu_id; - pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; - } - } else { - event_ctrler = phytium_pcie_pmu_get_event_ctrler(event); - switch (pcie_pmu->pmu_id) { - case 0: - if (event_ctrler != 0) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu0!\n", - event_ctrler); - return -EINVAL; - } - break; - case 1: - if (event_ctrler == 0) - event_ctrler = 1; - else if ((event_ctrler < 1) || (event_ctrler > 3)) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu1!\n", - event_ctrler); - return -EINVAL; - } - break; - case 2: - if (event_ctrler == 0) - event_ctrler = 4; - else if ((event_ctrler < 4) || (event_ctrler > 7)) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu2!\n", - event_ctrler); - return -EINVAL; - } - break; - default: - dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", - pcie_pmu->pmu_id); - return -EINVAL; - } - - pcie_pmu->ctrler_id = event_ctrler; - switch (pcie_pmu->pmu_id) { - case 0: - case 1: - pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; - break; - case 2: - pcie_pmu->real_ctrler = (pcie_pmu->ctrler_id - 4) * 16; - break; - default: - dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", - pcie_pmu->pmu_id); - return -EINVAL; - } - phytium_pcie_pmu_select_ctrler(pcie_pmu); - } - hwc->idx = -1; hwc->config_base = event->attr.config; @@ -521,7 +1365,7 @@ void phytium_pcie_pmu_event_update(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; u64 delta; - delta = phytium_pcie_pmu_read_counter(pcie_pmu, hwc); + delta = pcie_pmu->ops->read_counter(pcie_pmu, hwc); local64_add(delta, &event->count); } @@ -547,9 +1391,13 @@ int phytium_pcie_pmu_event_add(struct perf_event *event, int flags) { struct phytium_pcie_pmu *pcie_pmu = to_phytium_pcie_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - int idx; + int idx, ret; hwc->state |= PERF_HES_STOPPED; + pcie_pmu->ops->get_event_config(event, pcie_pmu); + ret = pcie_pmu->ops->set_event_config(event, pcie_pmu); + if (ret < 0) + return ret; idx = phytium_pcie_pmu_mark_event(event); if (idx < 0) @@ -565,13 +1413,12 @@ void phytium_pcie_pmu_event_del(struct perf_event *event, int flags) { struct phytium_pcie_pmu *pcie_pmu = to_phytium_pcie_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - unsigned long val; phytium_pcie_pmu_event_stop(event, PERF_EF_UPDATE); - val = phytium_pcie_pmu_get_irq_flag(pcie_pmu); - val = phytium_pcie_pmu_get_stop_state(pcie_pmu); phytium_pcie_pmu_unmark_event(pcie_pmu, hwc->idx); + pcie_pmu->ops->reset_event_config(pcie_pmu); + perf_event_update_userpage(event); pcie_pmu->pmu_events.hw_events[hwc->idx] = NULL; } @@ -580,34 +1427,32 @@ void phytium_pcie_pmu_enable(struct pmu *pmu) { struct phytium_pcie_pmu *pcie_pmu = to_phytium_pcie_pmu(pmu); int event_added = bitmap_weight(pcie_pmu->pmu_events.used_mask, - PHYTIUM_PCIE_MAX_COUNTERS); + pcie_pmu->cnts_num); if (event_added) { - phytium_pcie_pmu_clear_all_counters(pcie_pmu); - phytium_pcie_pmu_start_all_counters(pcie_pmu); + pcie_pmu->ops->clear_all_counters(pcie_pmu); + pcie_pmu->ops->enable_clk(pcie_pmu); + pcie_pmu->ops->start_all_counters(pcie_pmu); } } void phytium_pcie_pmu_disable(struct pmu *pmu) { struct phytium_pcie_pmu *pcie_pmu = to_phytium_pcie_pmu(pmu); - int event_added = bitmap_weight(pcie_pmu->pmu_events.used_mask, - PHYTIUM_PCIE_MAX_COUNTERS); + int event_added; + event_added = bitmap_weight(pcie_pmu->pmu_events.used_mask, + pcie_pmu->cnts_num); if (event_added) - phytium_pcie_pmu_stop_all_counters(pcie_pmu); -} - -void phytium_pcie_pmu_reset(struct phytium_pcie_pmu *pcie_pmu) -{ - phytium_pcie_pmu_disable_clk(pcie_pmu); - phytium_pcie_pmu_clear_all_counters(pcie_pmu); + pcie_pmu->ops->stop_all_counters(pcie_pmu); } static const struct acpi_device_id phytium_pcie_pmu_acpi_match[] = { - { - "PHYT0044", - }, + { "PHYT0044", }, + { "PHYT0068", }, + { "PHYT3009", }, + { "PHYT300B", }, + { "PHYT300A", }, {}, }; MODULE_DEVICE_TABLE(acpi, phytium_pcie_pmu_acpi_match); @@ -616,38 +1461,117 @@ static irqreturn_t phytium_pcie_pmu_overflow_handler(int irq, void *dev_id) { struct phytium_pcie_pmu *pcie_pmu = dev_id; struct perf_event *event; - unsigned long overflown, stop_state; + unsigned long overflown, stop_state, now_state; int idx; - unsigned long *used_mask = pcie_pmu->pmu_events.used_mask; - int event_added = bitmap_weight(used_mask, PHYTIUM_PCIE_MAX_COUNTERS); - overflown = phytium_pcie_pmu_get_irq_flag(pcie_pmu); + unsigned long *used_mask = pcie_pmu->pmu_events.used_mask; + int event_added = bitmap_weight(used_mask, pcie_pmu->cnts_num); - if (!test_bit(pcie_pmu->irq_bit, &overflown)) + now_state = phytium_pcie_pmu_get_now_state(pcie_pmu); + if (now_state != PCIE_PMU_OVER_STATE) return IRQ_NONE; + if (!event_added) { + pcie_pmu->ops->clear_all_counters(pcie_pmu); + return IRQ_HANDLED; + } + overflown = phytium_pcie_pmu_get_irq_flag(pcie_pmu); stop_state = phytium_pcie_pmu_get_stop_state(pcie_pmu); + dev_dbg(pcie_pmu->dev, "%s, pcie_pmu->irq_bit=%d,overflown=%lu, stop_state=%lu, now_state=%lu, event_added=%u.\n", + __func__, pcie_pmu->irq_bit, overflown, stop_state, now_state, event_added); + if (bitmap_weight(&stop_state, 6)) { - for_each_set_bit(idx, used_mask, PHYTIUM_PCIE_MAX_COUNTERS) { + for_each_set_bit(idx, used_mask, pcie_pmu->cnts_num) { event = pcie_pmu->pmu_events.hw_events[idx]; if (!event) continue; phytium_pcie_pmu_event_update(event); } - phytium_pcie_pmu_clear_all_counters(pcie_pmu); - if ((stop_state & PCIE_PMU_OFL_STOP_TYPE_VAL) == 0) - phytium_pcie_pmu_start_all_counters(pcie_pmu); + pcie_pmu->ops->clear_all_counters(pcie_pmu); + + if (stop_state & PCIE_TIME_STOP_TYPE) + dev_info(pcie_pmu->dev, "Setting time has been reached, pmu stopped!"); + else if (stop_state & PCIE_EVENT_THD0_STOP_TYPE) + dev_info(pcie_pmu->dev, "Setting event(aw) threshold has been reached, pmu stopped!"); + else if (stop_state & PCIE_EVENT_THD1_STOP_TYPE) + dev_info(pcie_pmu->dev, "Setting event(ar) threshold has been reached, pmu stopped!"); + else + pcie_pmu->ops->start_all_counters(pcie_pmu); return IRQ_HANDLED; } - if (!event_added) { - phytium_pcie_pmu_clear_all_counters(pcie_pmu); - return IRQ_HANDLED; - } + return IRQ_NONE; } +static int phytium_pcie_pmu_version(struct platform_device *pdev, + struct phytium_pcie_pmu *pcie_pmu) +{ + struct acpi_device *acpi_dev; + const char *hid; + u32 pidr, clkfre, data_width; + + acpi_dev = ACPI_COMPANION(&pdev->dev); + hid = acpi_device_hid(acpi_dev); + if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0044")) { + pcie_pmu->ver = PCIEA_V1P0; + pcie_pmu->dev_id = 0; + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0068")) { + pcie_pmu->ver = PCIEA_V1P5; + pcie_pmu->dev_id = 0; + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT3009")) { + pidr = readl(pcie_pmu->base + PCIE_PMU_PIDR); + clkfre = readl(pcie_pmu->base + PCIE_V2_AXI_CLK_FRE); + data_width = readl(pcie_pmu->base + PCIE_V2_DATA_WIDTH); + dev_dbg(pcie_pmu->dev, "PCIE0 PIDR=%#x,VER=%#lx,clkfre=%u, data_width=%u.\n", + pidr, (pidr & PCIE_PMU_VER_BIT), clkfre, data_width); + pidr &= PCIE_PMU_VER_BIT; + if (pidr == 0x1) { + pcie_pmu->ver = PCIEA_V2P0; + pcie_pmu->dev_id = 0; + pcie_pmu->channel_num = PCIEA_V2P0_CHANNEL_NUM; + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + } + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT300B")) { + pidr = readl(pcie_pmu->base + PCIE_PMU_PIDR); + clkfre = readl(pcie_pmu->base + PCIE_V2_AXI_CLK_FRE); + data_width = readl(pcie_pmu->base + PCIE_V2_DATA_WIDTH); + dev_dbg(pcie_pmu->dev, "PCIE1 PIDR=%#x,VER=%#lx,clkfre=%u, data_width=%u.\n", + pidr, (pidr & PCIE_PMU_VER_BIT), clkfre, data_width); + pidr &= PCIE_PMU_VER_BIT; + if (pidr == 0x1) { + pcie_pmu->ver = PCIEB_V2P0; + pcie_pmu->channel_num = PCIEB_V2P0_CHANNEL_NUM; + pcie_pmu->dev_id = 1; + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + } + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT300A")) { + pidr = readl(pcie_pmu->base + PCIE_PMU_PIDR); + clkfre = readl(pcie_pmu->base + PCIE_V2_AXI_CLK_FRE); + data_width = readl(pcie_pmu->base + PCIE_V2_DATA_WIDTH); + dev_dbg(pcie_pmu->dev, "PCIE1 PIDR=%#x,VER=%#lx,clkfre=%u, data_width=%u.\n", + pidr, (pidr & PCIE_PMU_VER_BIT), clkfre, data_width); + pidr &= PCIE_PMU_VER_BIT; + if (pidr == 0x1) { + pcie_pmu->ver = PCIEC_V2P0; + pcie_pmu->channel_num = PCIEC_V2P0_CHANNEL_NUM; + pcie_pmu->dev_id = 2; + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + } + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + } + return 0; +} + static int phytium_pcie_pmu_init_irq(struct phytium_pcie_pmu *pcie_pmu, struct platform_device *pdev) { @@ -657,6 +1581,8 @@ static int phytium_pcie_pmu_init_irq(struct phytium_pcie_pmu *pcie_pmu, if (irq < 0) return irq; + phytium_pcie_pmu_clear_all_counters(pcie_pmu); + ret = devm_request_irq(&pdev->dev, irq, phytium_pcie_pmu_overflow_handler, IRQF_NOBALANCING | IRQF_NO_THREAD | IRQF_SHARED, @@ -675,26 +1601,63 @@ static int phytium_pcie_pmu_init_irq(struct phytium_pcie_pmu *pcie_pmu, static int phytium_pcie_pmu_init_data(struct platform_device *pdev, struct phytium_pcie_pmu *pcie_pmu) { - struct resource *res, *clkres, *irqres; - pcie_pmu->soc_version = phytium_socs_type(); - if (pcie_pmu->soc_version == 0) { - dev_err(&pdev->dev, "The PCIe PMU driver can't be installed in this SoC.\n"); + struct resource *res, *csr, *irqres; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pcie_pmu->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pcie_pmu->base)) { + dev_err(&pdev->dev, "ioremap failed for pcie_pmu resource\n"); + return PTR_ERR(pcie_pmu->base); + } + + csr = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!csr) { + dev_err(&pdev->dev, "failed for get pcie_pmu csr resource.\n"); + return -EINVAL; + } + pcie_pmu->cfg_base = + devm_ioremap(&pdev->dev, csr->start, resource_size(csr)); + if (IS_ERR(pcie_pmu->cfg_base)) { + dev_err(&pdev->dev, + "ioremap failed for pcie_pmu csr resource\n"); + return PTR_ERR(pcie_pmu->cfg_base); + } + + irqres = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (!irqres) { + dev_err(&pdev->dev, + "failed for get pcie_pmu irq reg resource.\n"); return -EINVAL; } + pcie_pmu->irq_reg = + devm_ioremap(&pdev->dev, irqres->start, resource_size(irqres)); + if (IS_ERR(pcie_pmu->irq_reg)) { + dev_err(&pdev->dev, + "ioremap failed for pcie_pmu irq resource\n"); + return PTR_ERR(pcie_pmu->irq_reg); + } + + ret = phytium_pcie_pmu_version(pdev, pcie_pmu); + if (ret) + return ret; if (device_property_read_u32(&pdev->dev, "phytium,die-id", - &pcie_pmu->die_id)) { + &pcie_pmu->die_id)) { dev_err(&pdev->dev, "Can not read phytium,die-id!\n"); return -EINVAL; } if (device_property_read_u32(&pdev->dev, "phytium,pmu-id", - &pcie_pmu->pmu_id)) { + &pcie_pmu->pmu_id)) { dev_err(&pdev->dev, "Can not read phytium,pmu-id!\n"); return -EINVAL; } - if (pcie_pmu->soc_version == PS230XX) { + if (pcie_pmu->ver == PCIEA_V1P0) { + pcie_pmu->cnts_num = PHYTIUM_PCIE_V1_COUNTERS_NUM; + pcie_pmu->ops = &phytium_pcie_pmu_v1_ops; + switch (pcie_pmu->pmu_id) { case 0: pcie_pmu->clk_bits = 0x1; @@ -711,7 +1674,10 @@ static int phytium_pcie_pmu_init_data(struct platform_device *pdev, } pcie_pmu->irq_bit = pcie_pmu->pmu_id + 4; - } else { + } else if (pcie_pmu->ver == PCIEA_V1P5) { + pcie_pmu->cnts_num = PHYTIUM_PCIE_V1_COUNTERS_NUM; + pcie_pmu->ops = &phytium_pcie_pmu_v1_ops; + if (device_property_read_u32(&pdev->dev, "phytium,pcie-id", &pcie_pmu->pcie_id)) { dev_err(&pdev->dev, "Can not read phytium,pcie-id!\n"); return -EINVAL; @@ -732,47 +1698,21 @@ static int phytium_pcie_pmu_init_data(struct platform_device *pdev, dev_err(&pdev->dev, "Unsupported pmu id:%d!\n", pcie_pmu->pmu_id); break; } - pcie_pmu->irq_bit = pcie_pmu->pcie_id * 4 + pcie_pmu->pmu_id + 16; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pcie_pmu->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pcie_pmu->base)) { - dev_err(&pdev->dev, "ioremap failed for pcie_pmu resource\n"); - return PTR_ERR(pcie_pmu->base); - } - - clkres = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!clkres) { - dev_err(&pdev->dev, "failed for get pcie_pmu clk resource.\n"); - return -EINVAL; - } - - pcie_pmu->cfg_base = - devm_ioremap(&pdev->dev, clkres->start, resource_size(clkres)); - if (IS_ERR(pcie_pmu->cfg_base)) { - dev_err(&pdev->dev, - "ioremap failed for pcie_pmu csr resource\n"); - return PTR_ERR(pcie_pmu->cfg_base); - } + } else { + pcie_pmu->cnts_num = PHYTIUM_PCIE_V2_COUNTERS_NUM; + pcie_pmu->ops = &phytium_pcie_pmu_v2_ops; - irqres = platform_get_resource(pdev, IORESOURCE_MEM, 2); - if (!irqres) { - dev_err(&pdev->dev, - "failed for get pcie_pmu irq reg resource.\n"); - return -EINVAL; - } + if (device_property_read_u32(&pdev->dev, "phytium,pcie-id", &pcie_pmu->pcie_id)) { + dev_err(&pdev->dev, "Can not read phytium,pcie-id!\n"); + return -EINVAL; + } - pcie_pmu->irq_reg = - devm_ioremap(&pdev->dev, irqres->start, resource_size(irqres)); - if (IS_ERR(pcie_pmu->irq_reg)) { - dev_err(&pdev->dev, - "ioremap failed for pcie_pmu irq resource\n"); - return PTR_ERR(pcie_pmu->irq_reg); + pcie_pmu->clk_bits = PCIEV2_PMU_CLK_EN_BIT; + pcie_pmu->irq_bit = 2 - pcie_pmu->dev_id; } - phytium_pcie_pmu_reset(pcie_pmu); + pcie_pmu->ops->reset_pmu(pcie_pmu); return 0; } @@ -799,6 +1739,7 @@ static int phytium_pcie_pmu_dev_probe(struct platform_device *pdev, static int phytium_pcie_pmu_probe(struct platform_device *pdev) { struct phytium_pcie_pmu *pcie_pmu; + char *name; int ret; @@ -819,13 +1760,14 @@ static int phytium_pcie_pmu_probe(struct platform_device *pdev) return ret; } - if (pcie_pmu->soc_version == PS230XX) + if (pcie_pmu->ver == PCIEA_V1P0) name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie_pmu%u", pcie_pmu->die_id, pcie_pmu->pmu_id); else name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie%u_pmu%u", pcie_pmu->die_id, pcie_pmu->pcie_id, pcie_pmu->pmu_id); - pcie_pmu->pmu = (struct pmu){ + + pcie_pmu->pmu = (struct pmu) { .name = name, .module = THIS_MODULE, .task_ctx_nr = perf_invalid_context, @@ -837,25 +1779,23 @@ static int phytium_pcie_pmu_probe(struct platform_device *pdev) .start = phytium_pcie_pmu_event_start, .stop = phytium_pcie_pmu_event_stop, .read = phytium_pcie_pmu_event_update, - .attr_groups = phytium_pcie_pmu_attr_groups, }; + if (pcie_pmu->ver < PCIEA_V2P0) + pcie_pmu->pmu.attr_groups = phytium_pcie_pmu_v1_attr_groups; + else + pcie_pmu->pmu.attr_groups = phytium_pcie_pmu_v2_attr_groups; ret = perf_pmu_register(&pcie_pmu->pmu, name, -1); if (ret) { - dev_err(pcie_pmu->dev, "PCIE PMU register failed!\n"); + dev_err(pcie_pmu->dev, "%s register failed!\n", name); cpuhp_state_remove_instance_nocalls( phytium_pcie_pmu_hp_state, &pcie_pmu->node); } - phytium_pcie_pmu_enable_clk(pcie_pmu); + pcie_pmu->ops->enable_clk(pcie_pmu); - if (pcie_pmu->soc_version == PS230XX) - pr_info("die%d_pcie_pmu%d on cpu%d.\n", - pcie_pmu->die_id, pcie_pmu->pmu_id, pcie_pmu->on_cpu); - else - pr_info("die%d_pcie%d_pmu%d on cpu%d.\n", - pcie_pmu->die_id, pcie_pmu->pcie_id, pcie_pmu->pmu_id, pcie_pmu->on_cpu); + dev_info(pcie_pmu->dev, "%s on cpu%d.\n", name, pcie_pmu->on_cpu); return ret; } @@ -864,7 +1804,7 @@ static int phytium_pcie_pmu_remove(struct platform_device *pdev) { struct phytium_pcie_pmu *pcie_pmu = platform_get_drvdata(pdev); - phytium_pcie_pmu_disable_clk(pcie_pmu); + pcie_pmu->ops->disable_clk(pcie_pmu); perf_pmu_unregister(&pcie_pmu->pmu); cpuhp_state_remove_instance_nocalls( @@ -897,7 +1837,6 @@ int phytium_pcie_pmu_online_cpu(unsigned int cpu, struct hlist_node *node) pcie_pmu->on_cpu = cpu; WARN_ON(irq_set_affinity_hint(pcie_pmu->irq, cpumask_of(cpu))); } - return 0; } diff --git a/drivers/pinctrl/zhaoxin/pinctrl-kh50000.c b/drivers/pinctrl/zhaoxin/pinctrl-kh50000.c index 8c607953eaf30..279110cd56d3d 100644 --- a/drivers/pinctrl/zhaoxin/pinctrl-kh50000.c +++ b/drivers/pinctrl/zhaoxin/pinctrl-kh50000.c @@ -16,166 +16,184 @@ #include "pinctrl-zhaoxin.h" +#define KH50000_SOCKET_PINS(sock) \ + SOCKET_PINCTRL_PIN(sock, 0, "IOD_CLK27M_G0"), \ + SOCKET_PINCTRL_PIN(sock, 1, "IOD_CLK27M_G1"), \ + SOCKET_PINCTRL_PIN(sock, 2, "IOD_CLK27M_G2"), \ + SOCKET_PINCTRL_PIN(sock, 3, "IOD_CLK27M_G3"), \ + SOCKET_PINCTRL_PIN(sock, 4, "IOD_CPURST_G0"), \ + SOCKET_PINCTRL_PIN(sock, 5, "IOD_CPURST_G1"), \ + SOCKET_PINCTRL_PIN(sock, 6, "IOD_CPURST_G2"), \ + SOCKET_PINCTRL_PIN(sock, 7, "IOD_CPURST_G3"), \ + SOCKET_PINCTRL_PIN(sock, 8, "IOD_RSMRST_G0"), \ + SOCKET_PINCTRL_PIN(sock, 9, "IOD_RSMRST_G1"), \ + SOCKET_PINCTRL_PIN(sock, 10, "IOD_RSMRST_G2"), \ + SOCKET_PINCTRL_PIN(sock, 11, "IOD_RSMRST_G3"), \ + SOCKET_PINCTRL_PIN(sock, 12, "IOD_PWROK_G0"), \ + SOCKET_PINCTRL_PIN(sock, 13, "IOD_PWROK_G1"), \ + SOCKET_PINCTRL_PIN(sock, 14, "IOD_PWROK_G2"), \ + SOCKET_PINCTRL_PIN(sock, 15, "IOD_PWROK_G3"), \ + SOCKET_PINCTRL_PIN(sock, 16, "IOD_THRMTRIP_G0"), \ + SOCKET_PINCTRL_PIN(sock, 17, "IOD_THRMTRIP_G1"), \ + SOCKET_PINCTRL_PIN(sock, 18, "IOD_THRMTRIP_G2"), \ + SOCKET_PINCTRL_PIN(sock, 19, "IOD_THRMTRIP_G3"), \ + SOCKET_PINCTRL_PIN(sock, 20, "IOD_CLK50M_G0"), \ + SOCKET_PINCTRL_PIN(sock, 21, "IOD_CLK50M_G1"), \ + SOCKET_PINCTRL_PIN(sock, 22, "IOD_CLK50M_G2"), \ + SOCKET_PINCTRL_PIN(sock, 23, "IOD_CLK50M_G3"), \ + /*GPIO range 0 */ \ + SOCKET_PINCTRL_PIN(sock, 24, "USBHOC0"), /*PGPIO0------gpio36*/ \ + SOCKET_PINCTRL_PIN(sock, 25, "USBHOC1"), /*PGPIO1------gpio37*/ \ + SOCKET_PINCTRL_PIN(sock, 26, "USBHOC2"), /*PGPIO2------gpio38*/ \ + SOCKET_PINCTRL_PIN(sock, 27, "USBHOC3"), /*PGPIO3------gpio39*/ \ + SOCKET_PINCTRL_PIN(sock, 28, "I3C0DT"), \ + SOCKET_PINCTRL_PIN(sock, 29, "I3C0CK"), \ + SOCKET_PINCTRL_PIN(sock, 30, "I3C1DT"), \ + SOCKET_PINCTRL_PIN(sock, 31, "I3C1CK"), \ + SOCKET_PINCTRL_PIN(sock, 32, "I3C2DT"), \ + SOCKET_PINCTRL_PIN(sock, 33, "I3C2CK"), \ + SOCKET_PINCTRL_PIN(sock, 34, "I3C3DT"), \ + SOCKET_PINCTRL_PIN(sock, 35, "I3C3CK"), \ + SOCKET_PINCTRL_PIN(sock, 36, "SMBDT0"), \ + /*GPIO range 1*/ \ + SOCKET_PINCTRL_PIN(sock, 37, "SMBCK0"), /*PGPIO11------gpio47*/ \ + SOCKET_PINCTRL_PIN(sock, 38, "SMBDT1"), /*PGPIO12------gpio48*/ \ + SOCKET_PINCTRL_PIN(sock, 39, "SMBCK1"), /*PGPIO13------gpio49*/ \ + SOCKET_PINCTRL_PIN(sock, 40, "SMBDT2"), /*PGPIO7------gpio43*/ \ + SOCKET_PINCTRL_PIN(sock, 41, "SMBCK2"), /*PGPIO8------gpio44*/ \ + SOCKET_PINCTRL_PIN(sock, 42, "SMBALRT"), /*PGPIO14------gpio50*/ \ + SOCKET_PINCTRL_PIN(sock, 43, "SME_I2CDT_S"), \ + SOCKET_PINCTRL_PIN(sock, 44, "SME_I2CCK_S"), \ + /*GPIO range 2*/ \ + SOCKET_PINCTRL_PIN(sock, 45, "GPIO0"), /*GPIO0--------gpio0*/ \ + SOCKET_PINCTRL_PIN(sock, 46, "GPIO1"), /*GPIO1--------gpio1*/ \ + SOCKET_PINCTRL_PIN(sock, 47, "GPIO2"), /*GPIO2--------gpio2*/ \ + SOCKET_PINCTRL_PIN(sock, 48, "GPIO3"), /*GPIO3--------gpio3*/ \ + SOCKET_PINCTRL_PIN(sock, 49, "GPIO4"), /*GPIO4--------gpio4*/ \ + SOCKET_PINCTRL_PIN(sock, 50, "GPIO5"), /*GPIO5--------gpio5*/ \ + SOCKET_PINCTRL_PIN(sock, 51, "GPIO6"), /*GPIO6--------gpio6*/ \ + SOCKET_PINCTRL_PIN(sock, 52, "GPIO7"), /*GPIO7--------gpio7*/ \ + SOCKET_PINCTRL_PIN(sock, 53, "GPIO8"), /*GPIO8--------gpio8*/ \ + SOCKET_PINCTRL_PIN(sock, 54, "GPIO9"), /*GPIO9--------gpio9*/ \ + SOCKET_PINCTRL_PIN(sock, 55, "GPIO10"), /*GPIO10-------gpio10*/ \ + SOCKET_PINCTRL_PIN(sock, 56, "GPIO11"), /*GPIO11-------gpio11*/ \ + SOCKET_PINCTRL_PIN(sock, 57, "GPIO12"), /*GPIO12-------gpio12*/ \ + SOCKET_PINCTRL_PIN(sock, 58, "GPIO13"), /*GPIO13-------gpio13*/ \ + SOCKET_PINCTRL_PIN(sock, 59, "GPIO14"), /*GPIO14-------gpio14*/ \ + SOCKET_PINCTRL_PIN(sock, 60, "GPIO15"), /*GPIO15-------gpio15*/ \ + SOCKET_PINCTRL_PIN(sock, 61, "GPIO16"), /*GPIO16-------gpio16*/ \ + SOCKET_PINCTRL_PIN(sock, 62, "GPIO17"), /*GPIO17-------gpio17*/ \ + SOCKET_PINCTRL_PIN(sock, 63, "GPIO18"), /*GPIO18-------gpio18*/ \ + SOCKET_PINCTRL_PIN(sock, 64, "GPIO19"), /*GPIO19-------gpio19*/ \ + SOCKET_PINCTRL_PIN(sock, 65, "GPIO20"), /*GPIO20-------gpio20*/ \ + SOCKET_PINCTRL_PIN(sock, 66, "GPIO21"), /*GPIO21-------gpio21*/ \ + SOCKET_PINCTRL_PIN(sock, 67, "GPIO22"), /*GPIO22-------gpio22*/ \ + SOCKET_PINCTRL_PIN(sock, 68, "GPIO23"), /*GPIO23-------gpio23*/ \ + SOCKET_PINCTRL_PIN(sock, 69, "GPIO24"), /*GPIO24-------gpio24*/ \ + SOCKET_PINCTRL_PIN(sock, 70, "GPIO25"), /*GPIO25-------gpio25*/ \ + SOCKET_PINCTRL_PIN(sock, 71, "GPIO26"), /*GPIO26-------gpio26*/ \ + SOCKET_PINCTRL_PIN(sock, 72, "GPIO27"), /*GPIO27-------gpio27*/ \ + SOCKET_PINCTRL_PIN(sock, 73, "GPIO28"), /*GPIO28-------gpio28*/ \ + SOCKET_PINCTRL_PIN(sock, 74, "GPIO29"), /*GPIO29-------gpio29*/ \ + SOCKET_PINCTRL_PIN(sock, 75, "GPIO30"), /*GPIO30-------gpio30*/ \ + SOCKET_PINCTRL_PIN(sock, 76, "GPIO31"), /*GPIO31-------gpio31*/ \ + SOCKET_PINCTRL_PIN(sock, 77, "GPIO32"), /*GPIO32-------gpio32*/ \ + SOCKET_PINCTRL_PIN(sock, 78, "GPIO33"), /*GPIO33-------gpio33*/ \ + SOCKET_PINCTRL_PIN(sock, 79, "GPIO34"), /*GPIO34-------gpio34*/ \ + SOCKET_PINCTRL_PIN(sock, 80, "GPIO35"), /*GPIO35-------gpio35*/ \ + /*GPIO range 3*/ \ + SOCKET_PINCTRL_PIN(sock, 81, "LPCCLK"), /*PGPIO16------gpio52*/ \ + SOCKET_PINCTRL_PIN(sock, 82, "LPCDRQ1"), /*PGPIO17------gpio53*/ \ + SOCKET_PINCTRL_PIN(sock, 83, "LPCDRQ0"), /*PGPIO18------gpio54*/ \ + SOCKET_PINCTRL_PIN(sock, 84, "LPCFRAME"), /*PGPIO19------gpio55*/ \ + SOCKET_PINCTRL_PIN(sock, 85, "LPCAD3"), /*PGPIO20------gpio56*/ \ + SOCKET_PINCTRL_PIN(sock, 86, "LPCAD2"), /*PGPIO21------gpio57*/ \ + SOCKET_PINCTRL_PIN(sock, 87, "LPCAD1"), /*PGPIO22------gpio58*/ \ + SOCKET_PINCTRL_PIN(sock, 88, "LPCAD0"), /*PGPIO23------gpio59*/ \ + SOCKET_PINCTRL_PIN(sock, 89, "SERIRQ"), /*PGPIO24------gpio60*/ \ + /*GPIO range 4*/ \ + SOCKET_PINCTRL_PIN(sock, 90, "ESPICLK"), /*PGPIO15------gpio51*/ \ + /*GPIO range 5*/ \ + SOCKET_PINCTRL_PIN(sock, 91, "ESPIRST"), /*PGPIO29------gpio65*/ \ + SOCKET_PINCTRL_PIN(sock, 92, "ESPICS"), /*PGPIO30------gpio66*/ \ + SOCKET_PINCTRL_PIN(sock, 93, "ESPIIO3"), /*PGPIO31------gpio67*/ \ + /*GPIO range 6*/ \ + SOCKET_PINCTRL_PIN(sock, 94, "ESPIIO2"), /*PGPIO4------gpio40*/ \ + SOCKET_PINCTRL_PIN(sock, 95, "ESPIIO1"), /*PGPIO5------gpio41*/ \ + SOCKET_PINCTRL_PIN(sock, 96, "ESPIIO0"), /*PGPIO6------gpio42*/ \ + /* jump */ \ + SOCKET_PINCTRL_PIN(sock, 97, "SPIDI"), \ + SOCKET_PINCTRL_PIN(sock, 98, "SPIDO"), \ + SOCKET_PINCTRL_PIN(sock, 99, "SPICLK"), \ + SOCKET_PINCTRL_PIN(sock, 100, "SPISS"), \ + SOCKET_PINCTRL_PIN(sock, 101, "TPMRST"), \ + SOCKET_PINCTRL_PIN(sock, 102, "TPMIRQ"), \ + SOCKET_PINCTRL_PIN(sock, 103, "MSPIDI"), \ + SOCKET_PINCTRL_PIN(sock, 104, "MSPIDO"), \ + SOCKET_PINCTRL_PIN(sock, 105, "MSPIIO2"), \ + SOCKET_PINCTRL_PIN(sock, 106, "MSPIIO3"), \ + SOCKET_PINCTRL_PIN(sock, 107, "MSPICLK"), \ + SOCKET_PINCTRL_PIN(sock, 108, "MSPISS0"), \ + /*GPIO range 7*/ \ + SOCKET_PINCTRL_PIN(sock, 109, "MSPISS1"), /*PGPIO9------gpio45*/ \ + /*GPIO range 8 */ \ + SOCKET_PINCTRL_PIN(sock, 110, "MSPISS2"), /*PGPIO22------gpio58*/ \ + /*GPIO range 9*/ \ + SOCKET_PINCTRL_PIN(sock, 111, "SPIDEVINT"), /*PGPIO25------gpio61*/ \ + /*jump*/ \ + SOCKET_PINCTRL_PIN(sock, 112, "ZLSDATA_TX_P0"), \ + SOCKET_PINCTRL_PIN(sock, 113, "ZLSDATA_RX_P0"), \ + SOCKET_PINCTRL_PIN(sock, 114, "ZLSDATA_TX_P1"), \ + SOCKET_PINCTRL_PIN(sock, 115, "ZLSDATA_RX_P1"), \ + SOCKET_PINCTRL_PIN(sock, 116, "ZLSDATA_TX_P2"), \ + SOCKET_PINCTRL_PIN(sock, 117, "ZLSDATA_RX_P2"), \ + SOCKET_PINCTRL_PIN(sock, 118, "BOOT_EN"), \ + SOCKET_PINCTRL_PIN(sock, 119, "BOOT_DONE"), \ + SOCKET_PINCTRL_PIN(sock, 120, "MST_SKT"), \ + SOCKET_PINCTRL_PIN(sock, 121, "HRX_BEVO_CLK"), \ + SOCKET_PINCTRL_PIN(sock, 122, "HRX_BEVO_DATA"), \ + SOCKET_PINCTRL_PIN(sock, 123, "HTX_BEVO_CLK"), \ + SOCKET_PINCTRL_PIN(sock, 124, "HTX_BEVO_DATA"), \ + SOCKET_PINCTRL_PIN(sock, 125, "THRMTRIP_I"), \ + SOCKET_PINCTRL_PIN(sock, 126, "CLK50M_I"), \ + SOCKET_PINCTRL_PIN(sock, 127, "CLK50M_O"), \ + SOCKET_PINCTRL_PIN(sock, 128, "PCIRST_IO"), \ + SOCKET_PINCTRL_PIN(sock, 129, "RSMRST_IO"), \ + SOCKET_PINCTRL_PIN(sock, 130, "PWRGD_IO"), \ + SOCKET_PINCTRL_PIN(sock, 131, "CLK32K_IO"), \ + SOCKET_PINCTRL_PIN(sock, 132, "BIOSSEL"), \ + SOCKET_PINCTRL_PIN(sock, 133, "THRMRIP"), \ + /*GPIO range 10 */ \ + SOCKET_PINCTRL_PIN(sock, 134, "THRM"), /*PGPIO26------gpio62*/ \ + /*GPIO range 11*/ \ + SOCKET_PINCTRL_PIN(sock, 135, "PEXWAKE"), /*PGPIO10------gpio46*/ \ + /*jump*/ \ + SOCKET_PINCTRL_PIN(sock, 136, "PWRBTN"), \ + SOCKET_PINCTRL_PIN(sock, 137, "PCIRST"), \ + /*GPIO range 12*/ \ + SOCKET_PINCTRL_PIN(sock, 138, "SPKR"), /*PGPIO27------gpio63*/ \ + SOCKET_PINCTRL_PIN(sock, 139, "PME"), /*PGPIO28------gpio64*/ \ + SOCKET_PINCTRL_PIN(sock, 140, "SUSA"), \ + SOCKET_PINCTRL_PIN(sock, 141, "SUSB"), \ + SOCKET_PINCTRL_PIN(sock, 142, "SUSC"), \ + SOCKET_PINCTRL_PIN(sock, 143, "SVID0_VREN"), \ + SOCKET_PINCTRL_PIN(sock, 144, "SVID1_VREN"), + /* kh50000 pin define */ -static const struct pinctrl_pin_desc kh50000_pins[] = { - PINCTRL_PIN(0, "IOD_CLK27M_G0"), - PINCTRL_PIN(1, "IOD_CLK27M_G1"), - PINCTRL_PIN(2, "IOD_CLK27M_G2"), - PINCTRL_PIN(3, "IOD_CLK27M_G3"), - PINCTRL_PIN(4, "IOD_CPURST_G0"), - PINCTRL_PIN(5, "IOD_CPURST_G1"), - PINCTRL_PIN(6, "IOD_CPURST_G2"), - PINCTRL_PIN(7, "IOD_CPURST_G3"), - PINCTRL_PIN(8, "IOD_RSMRST_G0"), - PINCTRL_PIN(9, "IOD_RSMRST_G1"), - PINCTRL_PIN(10, "IOD_RSMRST_G2"), - PINCTRL_PIN(11, "IOD_RSMRST_G3"), - PINCTRL_PIN(12, "IOD_PWROK_G0"), - PINCTRL_PIN(13, "IOD_PWROK_G1"), - PINCTRL_PIN(14, "IOD_PWROK_G2"), - PINCTRL_PIN(15, "IOD_PWROK_G3"), - PINCTRL_PIN(16, "IOD_THRMTRIP_G0"), - PINCTRL_PIN(17, "IOD_THRMTRIP_G1"), - PINCTRL_PIN(18, "IOD_THRMTRIP_G2"), - PINCTRL_PIN(19, "IOD_THRMTRIP_G3"), - PINCTRL_PIN(20, "IOD_CLK50M_G0"), - PINCTRL_PIN(21, "IOD_CLK50M_G1"), - PINCTRL_PIN(22, "IOD_CLK50M_G2"), - PINCTRL_PIN(23, "IOD_CLK50M_G3"), - /* GPIO range 0 */ - PINCTRL_PIN(24, "USBHOC0"), - PINCTRL_PIN(25, "USBHOC1"), - PINCTRL_PIN(26, "USBHOC2"), - PINCTRL_PIN(27, "USBHOC3"), - PINCTRL_PIN(28, "I3C0DT"), - PINCTRL_PIN(29, "I3C0CK"), - PINCTRL_PIN(30, "I3C1DT"), - PINCTRL_PIN(31, "I3C1CK"), - PINCTRL_PIN(32, "I3C2DT"), - PINCTRL_PIN(33, "I3C2CK"), - PINCTRL_PIN(34, "I3C3DT"), - PINCTRL_PIN(35, "I3C3CK"), - PINCTRL_PIN(36, "SMBDT0"), - /* GPIO range 1 */ - PINCTRL_PIN(37, "SMBCK0"), - PINCTRL_PIN(38, "SMBDT1"), - PINCTRL_PIN(39, "SMBCK1"), - PINCTRL_PIN(40, "SMBDT2"), - PINCTRL_PIN(41, "SMBCK2"), - PINCTRL_PIN(42, "SMBALRT"), - PINCTRL_PIN(43, "SME_I2CDT_S"), - PINCTRL_PIN(44, "SME_I2CCK_S"), - /* GPIO range 2 */ - PINCTRL_PIN(45, "GPIO0"), - PINCTRL_PIN(46, "GPIO1"), - PINCTRL_PIN(47, "GPIO2"), - PINCTRL_PIN(48, "GPIO3"), - PINCTRL_PIN(49, "GPIO4"), - PINCTRL_PIN(50, "GPIO5"), - PINCTRL_PIN(51, "GPIO6"), - PINCTRL_PIN(52, "GPIO7"), - PINCTRL_PIN(53, "GPIO8"), - PINCTRL_PIN(54, "GPIO9"), - PINCTRL_PIN(55, "GPIO10"), - PINCTRL_PIN(56, "GPIO11"), - PINCTRL_PIN(57, "GPIO12"), - PINCTRL_PIN(58, "GPIO13"), - PINCTRL_PIN(59, "GPIO14"), - PINCTRL_PIN(60, "GPIO15"), - PINCTRL_PIN(61, "GPIO16"), - PINCTRL_PIN(62, "GPIO17"), - PINCTRL_PIN(63, "GPIO18"), - PINCTRL_PIN(64, "GPIO19"), - PINCTRL_PIN(65, "GPIO20"), - PINCTRL_PIN(66, "GPIO21"), - PINCTRL_PIN(67, "GPIO22"), - PINCTRL_PIN(68, "GPIO23"), - PINCTRL_PIN(69, "GPIO24"), - PINCTRL_PIN(70, "GPIO25"), - PINCTRL_PIN(71, "GPIO26"), - PINCTRL_PIN(72, "GPIO27"), - PINCTRL_PIN(73, "GPIO28"), - PINCTRL_PIN(74, "GPIO29"), - PINCTRL_PIN(75, "GPIO30"), - PINCTRL_PIN(76, "GPIO31"), - PINCTRL_PIN(77, "GPIO32"), - PINCTRL_PIN(78, "GPIO33"), - PINCTRL_PIN(79, "GPIO34"), - PINCTRL_PIN(80, "GPIO35"), - /* GPIO range 3 */ - PINCTRL_PIN(81, "LPCCLK"), - PINCTRL_PIN(82, "LPCDRQ1"), - PINCTRL_PIN(83, "LPCDRQ0"), - PINCTRL_PIN(84, "LPCFRAME"), - PINCTRL_PIN(85, "LPCAD3"), - PINCTRL_PIN(86, "LPCAD2"), - PINCTRL_PIN(87, "LPCAD1"), - PINCTRL_PIN(88, "LPCAD0"), - PINCTRL_PIN(89, "SERIRQ"), - /* GPIO range 4 */ - PINCTRL_PIN(90, "ESPICLK"), - /* GPIO range 5 */ - PINCTRL_PIN(91, "ESPIRST"), - PINCTRL_PIN(92, "ESPICS"), - PINCTRL_PIN(93, "ESPIIO3"), - /* GPIO range 6 */ - PINCTRL_PIN(94, "ESPIIO2"), - PINCTRL_PIN(95, "ESPIIO1"), - PINCTRL_PIN(96, "ESPIIO0"), - PINCTRL_PIN(97, "SPIDI"), - PINCTRL_PIN(98, "SPIDO"), - PINCTRL_PIN(99, "SPICLK"), - PINCTRL_PIN(100, "SPISS"), - PINCTRL_PIN(101, "TPMRST"), - PINCTRL_PIN(102, "TPMIRQ"), - PINCTRL_PIN(103, "MSPIDI"), - PINCTRL_PIN(104, "MSPIDO"), - PINCTRL_PIN(105, "MSPIIO2"), - PINCTRL_PIN(106, "MSPIIO3"), - PINCTRL_PIN(107, "MSPICLK"), - PINCTRL_PIN(108, "MSPISS0"), - /* GPIO range 7 */ - PINCTRL_PIN(109, "MSPISS1"), - /* GPIO range 8 */ - PINCTRL_PIN(110, "MSPISS2"), - /* GPIO range 9 */ - PINCTRL_PIN(111, "SPIDEVINT"), - PINCTRL_PIN(112, "ZLSDATA_TX_P0"), - PINCTRL_PIN(113, "ZLSDATA_RX_P0"), - PINCTRL_PIN(114, "ZLSDATA_TX_P1"), - PINCTRL_PIN(115, "ZLSDATA_RX_P1"), - PINCTRL_PIN(116, "ZLSDATA_TX_P2"), - PINCTRL_PIN(117, "ZLSDATA_RX_P2"), - PINCTRL_PIN(118, "BOOT_EN"), - PINCTRL_PIN(119, "BOOT_DONE"), - PINCTRL_PIN(120, "MST_SKT"), - PINCTRL_PIN(121, "HRX_BEVO_CLK"), - PINCTRL_PIN(122, "HRX_BEVO_DATA"), - PINCTRL_PIN(123, "HTX_BEVO_CLK"), - PINCTRL_PIN(124, "HTX_BEVO_DATA"), - PINCTRL_PIN(125, "THRMTRIP_I"), - PINCTRL_PIN(126, "CLK50M_I"), - PINCTRL_PIN(127, "CLK50M_O"), - PINCTRL_PIN(128, "PCIRST_IO"), - PINCTRL_PIN(129, "RSMRST_IO"), - PINCTRL_PIN(130, "PWRGD_IO"), - PINCTRL_PIN(131, "CLK32K_IO"), - PINCTRL_PIN(132, "BIOSSEL"), - PINCTRL_PIN(133, "THRMRIP"), - /* GPIO range 10 */ - PINCTRL_PIN(134, "THRM"), - /* GPIO range 11 */ - PINCTRL_PIN(135, "PEXWAKE"), - PINCTRL_PIN(136, "PWRBTN"), - PINCTRL_PIN(137, "PCIRST"), - /* GPIO range 12 */ - PINCTRL_PIN(138, "SPKR"), - PINCTRL_PIN(139, "PME"), - PINCTRL_PIN(140, "SUSA"), - PINCTRL_PIN(141, "SUSB"), - PINCTRL_PIN(142, "SUSC"), - PINCTRL_PIN(143, "SVID0_VREN"), - PINCTRL_PIN(144, "SVID1_VREN"), +static const struct pinctrl_pin_desc kh50000_pins_0[] = { + KH50000_SOCKET_PINS(0) +}; + +static const struct pinctrl_pin_desc kh50000_pins_1[] = { + KH50000_SOCKET_PINS(1) +}; + +static const struct pinctrl_pin_desc kh50000_pins_2[] = { + KH50000_SOCKET_PINS(2) +}; + +static const struct pinctrl_pin_desc kh50000_pins_3[] = { + KH50000_SOCKET_PINS(3) }; #define NOT_DEFINE -30000 @@ -326,23 +344,75 @@ static zx_gpio_type kh50000_gpio_type(struct zhaoxin_pinctrl *pctrl, unsigned in static void kh50000_gpio_init(struct zhaoxin_pinctrl *pctrl) { - pctrl->pmio_base = 0x800; - pctrl->pmio_rx90 = 0x90; - pctrl->pmio_rx8c = 0x8c; + struct resource *res_pmio; + struct platform_device *pdev = to_platform_device(pctrl->dev); + + res_pmio = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res_pmio) { + dev_err(&pdev->dev, "can't fetch device pmio resource info\n"); + return; + } + + if (!request_region(res_pmio->start, resource_size(res_pmio), pdev->name)) { + dev_err(&pdev->dev, "can't request region\n"); + return; + } + pctrl->pmio_base = res_pmio->start; + pctrl->pmio_rx90 = 4; + pctrl->pmio_rx8c = 0; zx_pad_write16(pctrl, 0xF8, 0x7F); dev_info(pctrl->dev, "KH50000 private init\n"); } -static const struct zhaoxin_pinctrl_soc_data kh50000_soc_data = { - .pins = kh50000_pins, - .npins = ARRAY_SIZE(kh50000_pins), +static const struct zhaoxin_pinctrl_soc_data socket_0_soc_data = { + .uid = "0", + .pins = kh50000_pins_0, + .npins = ARRAY_SIZE(kh50000_pins_0), .pin_topologys = kh50000_pin_topologys, .gpio_type = kh50000_gpio_type, .private_init = kh50000_gpio_init, .zhaoxin_pin_maps = kh50000_pinmap_gpps, .pin_map_size = ARRAY_SIZE(kh50000_pinmap_gpps), }; +static const struct zhaoxin_pinctrl_soc_data socket_1_soc_data = { + .uid = "1", + .pins = kh50000_pins_1, + .npins = ARRAY_SIZE(kh50000_pins_1), + .pin_topologys = kh50000_pin_topologys, + .gpio_type = kh50000_gpio_type, + .private_init = kh50000_gpio_init, + .zhaoxin_pin_maps = kh50000_pinmap_gpps, + .pin_map_size = ARRAY_SIZE(kh50000_pinmap_gpps), +}; +static const struct zhaoxin_pinctrl_soc_data socket_2_soc_data = { + .uid = "2", + .pins = kh50000_pins_2, + .npins = ARRAY_SIZE(kh50000_pins_2), + .pin_topologys = kh50000_pin_topologys, + .gpio_type = kh50000_gpio_type, + .private_init = kh50000_gpio_init, + .zhaoxin_pin_maps = kh50000_pinmap_gpps, + .pin_map_size = ARRAY_SIZE(kh50000_pinmap_gpps), +}; +static const struct zhaoxin_pinctrl_soc_data socket_3_soc_data = { + .uid = "3", + .pins = kh50000_pins_3, + .npins = ARRAY_SIZE(kh50000_pins_3), + .pin_topologys = kh50000_pin_topologys, + .gpio_type = kh50000_gpio_type, + .private_init = kh50000_gpio_init, + .zhaoxin_pin_maps = kh50000_pinmap_gpps, + .pin_map_size = ARRAY_SIZE(kh50000_pinmap_gpps), +}; + +static const struct zhaoxin_pinctrl_soc_data *kh50000_soc_data[] = { + &socket_0_soc_data, + &socket_1_soc_data, + &socket_2_soc_data, + &socket_3_soc_data, + NULL, +}; static const struct acpi_device_id kh50000_pinctrl_acpi_match[] = { { "KH8344B", (kernel_ulong_t)&kh50000_soc_data }, @@ -355,7 +425,7 @@ static const struct dev_pm_ops kh50000_pinctrl_pm_ops = { }; static struct platform_driver kh50000_pinctrl_driver = { - .probe = zhaoxin_pinctrl_probe_by_hid, + .probe = zhaoxin_pinctrl_probe_by_uid, .driver = { .name = "kh50000-pinctrl", .acpi_match_table = kh50000_pinctrl_acpi_match, diff --git a/drivers/pinctrl/zhaoxin/pinctrl-zhaoxin.h b/drivers/pinctrl/zhaoxin/pinctrl-zhaoxin.h index c0516daa5897a..1525d10cc53f5 100644 --- a/drivers/pinctrl/zhaoxin/pinctrl-zhaoxin.h +++ b/drivers/pinctrl/zhaoxin/pinctrl-zhaoxin.h @@ -20,6 +20,8 @@ struct platform_device; struct device; struct zhaoxin_pinctrl; +#define SOCKET_PINCTRL_PIN(sock, a, b) PINCTRL_PIN(a, b"_"#sock) + #define PMIO_RX90 100 #define PMIO_RX8C 200 diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 10e9ea557baa9..e7010c601c56c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -818,7 +818,7 @@ config SPI_PHYTIUM_PCI config SPI_PHYTIUM_QSPI tristate "Phytium Quad SPI controller" - depends on ARCH_PHYTIUM || COMPILE_TEST + depends on ARCH_PHYTIUM && COMPILE_TEST depends on OF depends on SPI_MEM help diff --git a/drivers/spi/spi-phytium-qspi.c b/drivers/spi/spi-phytium-qspi.c index 25c4af62a1cf5..579f98a1073aa 100644 --- a/drivers/spi/spi-phytium-qspi.c +++ b/drivers/spi/spi-phytium-qspi.c @@ -181,8 +181,8 @@ struct phytium_qspi { u8 fnum; bool nodirmap; - u32 wr_cfg_reg; - u32 rd_cfg_reg; + u32 wr_cfg_reg[PHYTIUM_QSPI_MAX_NORCHIP]; + u32 rd_cfg_reg[PHYTIUM_QSPI_MAX_NORCHIP]; u32 flash_cap; }; @@ -538,7 +538,7 @@ static int phytium_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) cmd |= flash->clk_div & QSPI_RD_CFG_RD_SCK_SEL_MASK; writel_relaxed(cmd, qspi->io_base + QSPI_RD_CFG_REG); - qspi->rd_cfg_reg = cmd; + qspi->rd_cfg_reg[spi->chip_select] = cmd; dev_dbg(qspi->dev, "Create read dirmap and setup RD_CFG_REG [%#x].\n", cmd); } else if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) { @@ -555,7 +555,7 @@ static int phytium_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) cmd |= QSPI_WR_CFG_WR_MODE_MASK; cmd |= flash->clk_div & QSPI_WR_CFG_WR_SCK_SEL_MASK; - qspi->wr_cfg_reg = cmd; + qspi->wr_cfg_reg[spi->chip_select] = cmd; } else { ret = -EINVAL; } @@ -574,6 +574,7 @@ static ssize_t phytium_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, void __iomem *src = flash->base + offs; u8 *buf_rx = buf; + writel_relaxed(qspi->rd_cfg_reg[spi->chip_select], qspi->io_base + QSPI_RD_CFG_REG); memcpy_fromio(buf_rx, src, len); return len; @@ -593,7 +594,7 @@ static ssize_t phytium_qspi_dirmap_write(struct spi_mem_dirmap_desc *desc, u_char tmp[4] = {0}; /* set wr_cfg for drimap write */ - writel_relaxed(qspi->wr_cfg_reg, qspi->io_base + QSPI_WR_CFG_REG); + writel_relaxed(qspi->wr_cfg_reg[spi->chip_select], qspi->io_base + QSPI_WR_CFG_REG); if (offs & 0x03) { dev_err(qspi->dev, "Addr not four-byte aligned!\n"); @@ -889,7 +890,6 @@ static int __maybe_unused phytium_qspi_resume(struct device *dev) if (!qspi->nodirmap) { /* set rd_cfg reg and flash_capacity reg after resume */ - writel_relaxed(qspi->rd_cfg_reg, qspi->io_base + QSPI_RD_CFG_REG); writel_relaxed(qspi->flash_cap, qspi->io_base + QSPI_FLASH_CAP_REG); } else { writel_relaxed(WR_CFG_NODIR_VALUE, qspi->io_base + QSPI_WR_CFG_REG); diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 5c481d0df8518..7f68005d52c7f 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -774,7 +774,9 @@ DEFINE_INODE_EVENT(xfs_get_acl); #endif DEFINE_INODE_EVENT(xfs_vm_bmap); DEFINE_INODE_EVENT(xfs_file_ioctl); +#ifdef CONFIG_COMPAT DEFINE_INODE_EVENT(xfs_file_compat_ioctl); +#endif DEFINE_INODE_EVENT(xfs_ioctl_setattr); DEFINE_INODE_EVENT(xfs_dir_fsync); DEFINE_INODE_EVENT(xfs_file_fsync); @@ -1550,8 +1552,6 @@ DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert); DEFINE_SIMPLE_IO_EVENT(xfs_setfilesize); DEFINE_SIMPLE_IO_EVENT(xfs_zero_eof); DEFINE_SIMPLE_IO_EVENT(xfs_end_io_direct_write); -DEFINE_SIMPLE_IO_EVENT(xfs_end_io_direct_write_unwritten); -DEFINE_SIMPLE_IO_EVENT(xfs_end_io_direct_write_append); DEFINE_SIMPLE_IO_EVENT(xfs_file_splice_read); DECLARE_EVENT_CLASS(xfs_itrunc_class, @@ -1583,31 +1583,6 @@ DEFINE_EVENT(xfs_itrunc_class, name, \ DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_start); DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_end); -TRACE_EVENT(xfs_pagecache_inval, - TP_PROTO(struct xfs_inode *ip, xfs_off_t start, xfs_off_t finish), - TP_ARGS(ip, start, finish), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fsize_t, size) - __field(xfs_off_t, start) - __field(xfs_off_t, finish) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->size = ip->i_disk_size; - __entry->start = start; - __entry->finish = finish; - ), - TP_printk("dev %d:%d ino 0x%llx disize 0x%llx start 0x%llx finish 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->size, - __entry->start, - __entry->finish) -); - TRACE_EVENT(xfs_bunmap, TP_PROTO(struct xfs_inode *ip, xfs_fileoff_t fileoff, xfs_filblks_t len, int flags, unsigned long caller_ip), @@ -1875,14 +1850,12 @@ DEFINE_EVENT(xfs_alloc_class, name, \ DEFINE_ALLOC_EVENT(xfs_alloc_exact_done); DEFINE_ALLOC_EVENT(xfs_alloc_exact_notfound); DEFINE_ALLOC_EVENT(xfs_alloc_exact_error); -DEFINE_ALLOC_EVENT(xfs_alloc_near_nominleft); DEFINE_ALLOC_EVENT(xfs_alloc_near_first); DEFINE_ALLOC_EVENT(xfs_alloc_cur); DEFINE_ALLOC_EVENT(xfs_alloc_cur_right); DEFINE_ALLOC_EVENT(xfs_alloc_cur_left); DEFINE_ALLOC_EVENT(xfs_alloc_cur_lookup); DEFINE_ALLOC_EVENT(xfs_alloc_cur_lookup_done); -DEFINE_ALLOC_EVENT(xfs_alloc_near_error); DEFINE_ALLOC_EVENT(xfs_alloc_near_noentry); DEFINE_ALLOC_EVENT(xfs_alloc_near_busy); DEFINE_ALLOC_EVENT(xfs_alloc_size_neither); @@ -2079,13 +2052,8 @@ DEFINE_ATTR_EVENT(xfs_attr_leaf_toosmall); DEFINE_ATTR_EVENT(xfs_attr_node_addname); DEFINE_ATTR_EVENT(xfs_attr_node_get); DEFINE_ATTR_EVENT(xfs_attr_node_replace); -DEFINE_ATTR_EVENT(xfs_attr_node_removename); - -DEFINE_ATTR_EVENT(xfs_attr_fillstate); -DEFINE_ATTR_EVENT(xfs_attr_refillstate); DEFINE_ATTR_EVENT(xfs_attr_rmtval_get); -DEFINE_ATTR_EVENT(xfs_attr_rmtval_set); #define DEFINE_DA_EVENT(name) \ DEFINE_EVENT(xfs_da_class, name, \ @@ -3541,36 +3509,6 @@ DEFINE_INODE_ERROR_EVENT(xfs_reflink_remap_extent_error); DEFINE_INODE_IREC_EVENT(xfs_reflink_remap_extent_src); DEFINE_INODE_IREC_EVENT(xfs_reflink_remap_extent_dest); -/* dedupe tracepoints */ -DEFINE_DOUBLE_IO_EVENT(xfs_reflink_compare_extents); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_compare_extents_error); - -/* ioctl tracepoints */ -TRACE_EVENT(xfs_ioctl_clone, - TP_PROTO(struct inode *src, struct inode *dest), - TP_ARGS(src, dest), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(unsigned long, src_ino) - __field(loff_t, src_isize) - __field(unsigned long, dest_ino) - __field(loff_t, dest_isize) - ), - TP_fast_assign( - __entry->dev = src->i_sb->s_dev; - __entry->src_ino = src->i_ino; - __entry->src_isize = i_size_read(src); - __entry->dest_ino = dest->i_ino; - __entry->dest_isize = i_size_read(dest); - ), - TP_printk("dev %d:%d ino 0x%lx isize 0x%llx -> ino 0x%lx isize 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->src_ino, - __entry->src_isize, - __entry->dest_ino, - __entry->dest_isize) -); - /* unshare tracepoints */ DEFINE_SIMPLE_IO_EVENT(xfs_reflink_unshare); DEFINE_INODE_ERROR_EVENT(xfs_reflink_unshare_error); @@ -3578,7 +3516,6 @@ DEFINE_INODE_ERROR_EVENT(xfs_reflink_unshare_error); /* copy on write */ DEFINE_INODE_IREC_EVENT(xfs_reflink_trim_around_shared); DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_found); -DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_enospc); DEFINE_INODE_IREC_EVENT(xfs_reflink_convert_cow); DEFINE_SIMPLE_IO_EVENT(xfs_reflink_cancel_cow_range); @@ -4369,7 +4306,6 @@ DEFINE_ICLOG_EVENT(xlog_iclog_switch); DEFINE_ICLOG_EVENT(xlog_iclog_sync); DEFINE_ICLOG_EVENT(xlog_iclog_syncing); DEFINE_ICLOG_EVENT(xlog_iclog_sync_done); -DEFINE_ICLOG_EVENT(xlog_iclog_want_sync); DEFINE_ICLOG_EVENT(xlog_iclog_wait_on); DEFINE_ICLOG_EVENT(xlog_iclog_write); @@ -4418,7 +4354,6 @@ DEFINE_DAS_STATE_EVENT(xfs_attr_sf_addname_return); DEFINE_DAS_STATE_EVENT(xfs_attr_set_iter_return); DEFINE_DAS_STATE_EVENT(xfs_attr_leaf_addname_return); DEFINE_DAS_STATE_EVENT(xfs_attr_node_addname_return); -DEFINE_DAS_STATE_EVENT(xfs_attr_remove_iter_return); DEFINE_DAS_STATE_EVENT(xfs_attr_rmtval_alloc); DEFINE_DAS_STATE_EVENT(xfs_attr_rmtval_remove_return); DEFINE_DAS_STATE_EVENT(xfs_attr_defer_add); diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h index 5cb6940310729..d700332362950 100644 --- a/include/linux/pci-epc.h +++ b/include/linux/pci-epc.h @@ -86,6 +86,13 @@ struct pci_epc_ops { u32 *msi_addr_offset); int (*start)(struct pci_epc *epc); void (*stop)(struct pci_epc *epc); + +#ifdef CONFIG_ARCH_PHYTIUM + int (*start_dma)(struct pci_epc *epc, u8 func_no, u64 cpu_addr, u64 pci_addr, + size_t size, u8 mode); + int (*dma_status)(struct pci_epc *epc, u8 func_no, u8 mode); +#endif + const struct pci_epc_features* (*get_features)(struct pci_epc *epc, u8 func_no, u8 vfunc_no); struct module *owner; @@ -251,4 +258,11 @@ void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, phys_addr_t *phys_addr, size_t size); void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr, void __iomem *virt_addr, size_t size); + +#ifdef CONFIG_ARCH_PHYTIUM +int pci_epc_start_dma(struct pci_epc *epc, u8 func_no, u64 cpu_addr, + u64 pci_addr, size_t size, u8 mode); +int pci_epc_dma_status(struct pci_epc *epc, u8 func_no, u8 mode); +#endif + #endif /* __LINUX_PCI_EPC_H */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d6587e42518b8..0775d3fdc11d3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1646,7 +1646,8 @@ static int check_position_fix(struct azx *chip, int fix) } /* Check VIA/ATI HD Audio Controller exist */ - if (chip->driver_type == AZX_DRIVER_VIA) { + if (chip->driver_type == AZX_DRIVER_VIA || + chip->driver_type == AZX_DRIVER_ZHAOXIN) { dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n"); return POS_FIX_VIACOMBO; } @@ -1800,7 +1801,8 @@ static void azx_check_snoop_available(struct azx *chip) snoop = true; if (azx_get_snoop_type(chip) == AZX_SNOOP_TYPE_NONE && - chip->driver_type == AZX_DRIVER_VIA) { + (chip->driver_type == AZX_DRIVER_VIA || + chip->driver_type == AZX_DRIVER_ZHAOXIN)) { /* force to non-snoop mode for a new VIA controller * when BIOS is set */ @@ -2846,6 +2848,21 @@ static const struct pci_device_id azx_ids[] = { { PCI_VDEVICE(VIA, 0x9170), .driver_data = AZX_DRIVER_GENERIC }, /* VIA GFX VT6122/VX11 */ { PCI_VDEVICE(VIA, 0x9140), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(VIA, 0x9141), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(VIA, 0x9142), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(VIA, 0x9144), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(VIA, 0x9145), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(VIA, 0x9146), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, /* SIS966 */ { PCI_VDEVICE(SI, 0x7502), .driver_data = AZX_DRIVER_SIS }, /* ULI M5461 */ diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d679154a6d8a8..aa8fc88cdf769 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -4641,6 +4641,17 @@ HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi), HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x11069f86, "ZX-100S HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f87, "ZX-100S HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f88, "KX-5000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f89, "KX-5000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8a, "KX-6000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8b, "KX-6000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8c, "KX-6000G HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8d, "KX-6000G HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8e, "KX-7000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8f, "KX-7000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f90, "KX-7000 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f87, "ZX-100S HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f88, "KX-5000 HDMI/DP", patch_gf_hdmi), diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4a22fb36ca367..3c00c149df39c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1381,6 +1381,7 @@ config SND_SOC_PEB2466 config SND_SOC_PHYTIUM_CODEC_V2 tristate "Phytium Codec V2 driver" + depends on ARCH_PHYTIUM help Select Y if you want to add Phytium codec V2 driver. diff --git a/sound/soc/codecs/es8388.c b/sound/soc/codecs/es8388.c index d9b1c80e3c38e..f086e2c52ad2e 100644 --- a/sound/soc/codecs/es8388.c +++ b/sound/soc/codecs/es8388.c @@ -23,7 +23,7 @@ #include #include -#define ES8388_V1_VERSION "1.0.0" +#define ES8388_V1_VERSION "1.0.1" static const unsigned int rates_12288[] = { 8000, 12000, 16000, 24000, 32000, 48000, 96000, @@ -720,8 +720,13 @@ static int es8388_resume(struct snd_soc_component *component) static int es8388_component_probe(struct snd_soc_component *component) { - snd_soc_component_write(component, ES8388_ADCPOWER, 0xf0); - snd_soc_component_write(component, ES8388_CONTROL1, 0x30); + int ret = 0; + + ret = snd_soc_component_write(component, ES8388_ADCPOWER, 0xf0); + if (ret) + return ret; + + snd_soc_component_write(component, ES8388_CONTROL1, 0x20); snd_soc_component_write(component, ES8388_DACCONTROL21, 0x80); snd_soc_component_write(component, ES8388_ADCCONTROL10, 0xda); diff --git a/sound/soc/codecs/phytium-codec-v2.c b/sound/soc/codecs/phytium-codec-v2.c index ab63ceb2c826f..88dd9e81a89e8 100644 --- a/sound/soc/codecs/phytium-codec-v2.c +++ b/sound/soc/codecs/phytium-codec-v2.c @@ -101,17 +101,20 @@ static const struct snd_soc_dapm_route phyt_dapm_routes[] = { static void phyt_codec_show_status(uint8_t status) { switch (status) { - case 0: + case ERR_CODEC_SUCCESS: pr_err("success\n"); break; - case 2: + case ERR_CODEC_DEV_BUSY: pr_err("device busy\n"); break; - case 3: + case ERR_CODEC_RW_ERROR: pr_err("read/write error\n"); break; - case 4: - pr_err("no device\n"); + case ERR_CODEC_NODEV: + pr_err("no hw device\n"); + break; + case ERR_CODEC_NO_INIT: + pr_err("no init\n"); break; default: pr_err("unknown error: %d\n", status); @@ -325,6 +328,9 @@ static int phyt_get_cmd(struct phytium_codec *priv, unsigned int cmd) static int phyt_probe(struct snd_soc_component *component) { struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); return phyt_set_cmd(priv, PHYTCODEC_MSG_CMD_SET_PROBE); } @@ -332,6 +338,9 @@ static int phyt_probe(struct snd_soc_component *component) static void phyt_remove(struct snd_soc_component *component) { struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); phyt_set_cmd(priv, PHYTCODEC_MSG_CMD_SET_REMOVE); } @@ -339,6 +348,9 @@ static void phyt_remove(struct snd_soc_component *component) static int phyt_suspend(struct snd_soc_component *component) { struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); return phyt_pm_cmd(priv, PHYTCODEC_MSG_CMD_SET_SUSPEND); } @@ -346,6 +358,9 @@ static int phyt_suspend(struct snd_soc_component *component) static int phyt_resume(struct snd_soc_component *component) { struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); return phyt_pm_cmd(priv, PHYTCODEC_MSG_CMD_SET_RESUME); } @@ -425,6 +440,9 @@ static int phyt_startup(struct snd_pcm_substream *substream, int ret; struct snd_soc_component *component = dai->component; struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ret = phyt_set_cmd(priv, PHYTCODEC_MSG_CMD_SET_STARTUP); @@ -440,6 +458,9 @@ static void phyt_shutdown(struct snd_pcm_substream *substream, int ret; struct snd_soc_component *component = dai->component; struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ret = phyt_set_cmd(priv, PHYTCODEC_MSG_CMD_SET_SHUTDOWN); @@ -492,6 +513,9 @@ static int phyt_set_dai_fmt(struct snd_soc_dai *codec_dai, int ret; struct snd_soc_component *component = codec_dai->component; struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) return -EINVAL; @@ -742,6 +766,7 @@ static ssize_t debug_store(struct device *dev, struct device_attribute *da, dev_err(dev, "dump command requires one argument\n"); goto error; } + memset(priv->sharemem_base, 0, sizeof(struct phytcodec_cmd)); phyt_get_cmd(priv, PHYTCODEC_MSG_CMD_GET_ALL_REGS); } else if (strcmp(cmd, "help") == 0) { dev_info(dev, "Available commands:\n" @@ -801,8 +826,9 @@ static void phyt_codec_init(struct phytium_codec *priv) if (sysfs_create_group(&priv->dev->kobj, &phyt_codec_device_group)) dev_warn(priv->dev, "failed to create sysfs\n"); - phyt_dai.playback.channels_max = phyt_get_channels(priv); - phyt_dai.capture.channels_max = phyt_dai.playback.channels_max; + priv->channels = phyt_get_channels(priv); + phyt_dai.playback.channels_max = priv->channels; + phyt_dai.capture.channels_max = priv->channels; phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_MASK, 0x0); phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_ENABLE, 0x1); diff --git a/sound/soc/codecs/phytium-codec-v2.h b/sound/soc/codecs/phytium-codec-v2.h index f0515d0cfabbb..e9b20079975cc 100644 --- a/sound/soc/codecs/phytium-codec-v2.h +++ b/sound/soc/codecs/phytium-codec-v2.h @@ -95,6 +95,15 @@ enum phytcodec_complete { PHYTCODEC_COMPLETE_INVALID_PARAMETERS, }; +enum phytcodec_status { + ERR_CODEC_SUCCESS = 0, + ERR_CODEC_BUS_BUSY, + ERR_CODEC_DEV_BUSY, + ERR_CODEC_RW_ERROR, + ERR_CODEC_NODEV, //HW + ERR_CODEC_NO_INIT, //SW +}; + struct phytcodec_rw_data { uint8_t addr; uint8_t reg; diff --git a/sound/soc/phytium/Kconfig b/sound/soc/phytium/Kconfig index c567699bcb568..a30c865d4af53 100644 --- a/sound/soc/phytium/Kconfig +++ b/sound/soc/phytium/Kconfig @@ -27,18 +27,19 @@ config SND_PMDK_ES8336 ES8336 codecs. config SND_SOC_PHYTIUM_I2S_V2 - tristate "Phytium I2S V2 Device Driver" - help - Say Y or M if you want to add support for I2S v2 driver for - Phytium I2S device . The device supports 2 channels each - for play and record. + tristate "Phytium I2S V2 Device Driver" + depends on ARCH_PHYTIUM + help + Say Y or M if you want to add support for I2S v2 driver for + Phytium I2S device . The device supports 2 channels each + for play and record. config SND_SOC_PHYTIUM_MACHINE_V2 - tristate "Phytium Machine V2 Driver" - depends on SND_SOC_PHYTIUM_I2S_V2 - help - Say Y or M if you want to add Phytium machine v2 support for - codecs. + tristate "Phytium Machine V2 Driver" + depends on SND_SOC_PHYTIUM_I2S_V2 + help + Say Y or M if you want to add Phytium machine v2 support for + codecs. config SND_PMDK_DP tristate "Phytium machine support with DP" diff --git a/sound/soc/phytium/phytium-i2s-v2.c b/sound/soc/phytium/phytium-i2s-v2.c index 83c4ee1ae65d1..d0074a81a874d 100644 --- a/sound/soc/phytium/phytium-i2s-v2.c +++ b/sound/soc/phytium/phytium-i2s-v2.c @@ -30,7 +30,7 @@ #include #include "phytium-i2s-v2.h" -#define PHYT_I2S_V2_VERSION "1.0.6" +#define PHYT_I2S_V2_VERSION "1.0.9" static struct snd_soc_jack hs_jack; static irqreturn_t phyt_i2s_gpio_interrupt(int irq, void *dev_id); @@ -539,6 +539,8 @@ static int phyt_pcm_component_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver phytium_i2s_component = { .name = "phytium-i2s", + .use_dai_pcm_id = true, + .probe_order = SND_SOC_COMP_ORDER_LATE, .pcm_construct = phyt_pcm_new, .pcm_destruct = phyt_pcm_free, .suspend = phyt_pcm_suspend, @@ -951,8 +953,54 @@ static ssize_t phyt_i2s_debug_store(struct device *dev, static DEVICE_ATTR_RW(phyt_i2s_debug); +static ssize_t phyt_i2s_control_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct phytium_i2s *priv = dev_get_drvdata(dev); + char *p, *token; + u8 loc; + int ret; + long value; + + p = kmalloc(size, GFP_KERNEL); + if (p == NULL) + return -EINVAL; + strscpy(p, buf, sizeof(p)); + + token = strsep(&p, " "); + if (!token) { + ret = -EINVAL; + goto error; + } + + ret = kstrtol(token, 0, &value); + if (ret) + goto error; + loc = (u8)value; + + if (loc == 1) { + //Enable I2S and DMA + phyt_writel_reg(priv->dma_reg_base, PHYTIUM_DMA_CTL, 1); + phyt_writel_reg(priv->regfile_base, PHYTIUM_REGFILE_ITER, TX_EN); + } else if (loc == 0) { + //Disable I2S and DMA + phyt_writel_reg(priv->regfile_base, PHYTIUM_REGFILE_ITER, TX_DIS); + phyt_writel_reg(priv->dma_reg_base, PHYTIUM_DMA_CTL, 0); + } + + kfree(p); + return size; +error: + kfree(p); + return ret; +} + +static DEVICE_ATTR_WO(phyt_i2s_control); + static struct attribute *phyt_i2s_device_attrs[] = { &dev_attr_phyt_i2s_debug.attr, + &dev_attr_phyt_i2s_control.attr, NULL, }; diff --git a/sound/soc/phytium/phytium-machine-v2.c b/sound/soc/phytium/phytium-machine-v2.c index d02ae022e5591..12f08b4ba445a 100644 --- a/sound/soc/phytium/phytium-machine-v2.c +++ b/sound/soc/phytium/phytium-machine-v2.c @@ -48,6 +48,7 @@ SND_SOC_DAILINK_DEFS(phyt_machine, static struct snd_soc_dai_link phyt_machine_dai[] = { { .name = "PHYTIUM HIFI V2", + .id = 0, .stream_name = "PHYTIUM HIFT V2", .dai_fmt = PMDK_DAI_FMT, SND_SOC_DAILINK_REG(phyt_machine), diff --git a/sound/soc/phytium/pmdk_dp.c b/sound/soc/phytium/pmdk_dp.c index c0760d3a7cd5f..c00b2c7069950 100644 --- a/sound/soc/phytium/pmdk_dp.c +++ b/sound/soc/phytium/pmdk_dp.c @@ -67,7 +67,8 @@ static int pmdk_dp0_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "Jack creation failed %d\n", ret); return ret; } - snd_soc_component_set_jack(component, &priv->jack0, NULL); + ret = snd_soc_component_set_jack(component, &priv->jack0, NULL); + return ret; } @@ -85,7 +86,8 @@ static int pmdk_dp1_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "Jack creation failed %d\n", ret); return ret; } - snd_soc_component_set_jack(component, &priv->jack1, NULL); + ret = snd_soc_component_set_jack(component, &priv->jack1, NULL); + return ret; } @@ -103,7 +105,8 @@ static int pmdk_dp2_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "Jack creation failed %d\n", ret); return ret; } - snd_soc_component_set_jack(component, &priv->jack2, NULL); + ret = snd_soc_component_set_jack(component, &priv->jack2, NULL); + return ret; } @@ -124,6 +127,7 @@ SND_SOC_DAILINK_DEFS(pmdk_dp2_dai, static struct snd_soc_dai_link pmdk_dai0 = { .name = "Phytium dp0-audio", + .id = 0, .stream_name = "Playback", .dai_fmt = SMDK_DAI_FMT, .init = pmdk_dp0_init, @@ -133,6 +137,7 @@ static struct snd_soc_dai_link pmdk_dai0 = { static struct snd_soc_dai_link pmdk_dai1 = { .name = "Phytium dp1-audio", + .id = 1, .stream_name = "Playback", .dai_fmt = SMDK_DAI_FMT, .init = pmdk_dp1_init, @@ -142,6 +147,7 @@ static struct snd_soc_dai_link pmdk_dai1 = { static struct snd_soc_dai_link pmdk_dai2 = { .name = "Phytium dp2-audio", + .id = 2, .stream_name = "Playback", .dai_fmt = SMDK_DAI_FMT, .init = pmdk_dp2_init,