diff --git a/arch/x86/events/zhaoxin/core.c b/arch/x86/events/zhaoxin/core.c index c2e5bdf3893d84aaa4e97c32e21c9f3bf6410f74..e4e7a3373d0fb94f9f7b6e70af916ad806b96437 100644 --- a/arch/x86/events/zhaoxin/core.c +++ b/arch/x86/events/zhaoxin/core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Zhaoxin PMU; + * Zhaoxin PMU; like Intel Architectural PerfMon-v2 */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -28,6 +28,8 @@ static u64 zx_pmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = { [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0515, [PERF_COUNT_HW_CACHE_MISSES] = 0x051a, [PERF_COUNT_HW_BUS_CYCLES] = 0x0083, + [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0028, + [PERF_COUNT_HW_BRANCH_MISSES] = 0x0029, }; static struct event_constraint zxc_event_constraints[] __read_mostly = { @@ -457,7 +459,7 @@ static ssize_t zhaoxin_event_sysfs_show(char *page, u64 config) } static const struct x86_pmu zhaoxin_pmu __initconst = { - .name = "zhaoxin_pmu", + .name = "", .handle_irq = zhaoxin_pmu_handle_irq, .disable_all = zhaoxin_pmu_disable_all, .enable_all = zhaoxin_pmu_enable_all, @@ -553,9 +555,11 @@ __init int zhaoxin_pmu_init(void) zx_pmon_event_map[PERF_COUNT_HW_CACHE_REFERENCES] = 0; zx_pmon_event_map[PERF_COUNT_HW_CACHE_MISSES] = 0; zx_pmon_event_map[PERF_COUNT_HW_BUS_CYCLES] = 0; + zx_pmon_event_map[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0; + zx_pmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0; - pr_cont("C events, "); - break; + pr_cont("ZXC events, "); + break; } return -ENODEV; @@ -576,7 +580,7 @@ __init int zhaoxin_pmu_init(void) zx_pmon_event_map[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0700; zx_pmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x0709; - pr_cont("D events, "); + pr_cont("ZXD events, "); break; case 0x3b: memcpy(hw_cache_event_ids, zxe_hw_cache_event_ids, @@ -584,10 +588,20 @@ __init int zhaoxin_pmu_init(void) x86_pmu.event_constraints = zxd_event_constraints; - zx_pmon_event_map[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0028; - zx_pmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x0029; + pr_cont("ZXE events, "); + break; + case 0x5b: + zx_pmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = + X86_CONFIG(.event = 0x02, .umask = 0x01, .inv = 0x01, .cmask = 0x01); + + memcpy(hw_cache_event_ids, zxe_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + + x86_pmu.event_constraints = zxd_event_constraints; + zx_pmon_event_map[PERF_COUNT_HW_CACHE_REFERENCES] = 0x051a; + zx_pmon_event_map[PERF_COUNT_HW_CACHE_MISSES] = 0; - pr_cont("E events, "); + pr_cont("CNX events, "); break; default: return -ENODEV; @@ -610,3 +624,4 @@ __init int zhaoxin_pmu_init(void) return 0; } + diff --git a/arch/x86/events/zhaoxin/uncore.c b/arch/x86/events/zhaoxin/uncore.c index 4c4ea01d23c8c92c1f33c9acbdecb4c7c16c5483..a06342387814a5cc7221e21136caf01690b7e357 100644 --- a/arch/x86/events/zhaoxin/uncore.c +++ b/arch/x86/events/zhaoxin/uncore.c @@ -1,196 +1,933 @@ // SPDX-License-Identifier: GPL-2.0-only -#include - #include #include "uncore.h" static struct zhaoxin_uncore_type *empty_uncore[] = { NULL, }; static struct zhaoxin_uncore_type **uncore_msr_uncores = empty_uncore; +static struct zhaoxin_uncore_type **uncore_pci_uncores = empty_uncore; + +static bool pcidrv_registered; +static struct pci_driver *uncore_pci_driver; /* mask of cpus that collect uncore events */ static cpumask_t uncore_cpu_mask; +static cpumask_t uncore_cpu_subnode_mask; +static cpumask_t uncore_cpu_cluster_mask; /* constraint for the fixed counter */ static struct event_constraint uncore_constraint_fixed = EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL); -static int max_packages; - -/* CHX event control */ -#define CHX_UNC_CTL_EV_SEL_MASK 0x000000ff -#define CHX_UNC_CTL_UMASK_MASK 0x0000ff00 -#define CHX_UNC_CTL_EDGE_DET (1 << 18) -#define CHX_UNC_CTL_EN (1 << 22) -#define CHX_UNC_CTL_INVERT (1 << 23) -#define CHX_UNC_CTL_CMASK_MASK 0xff000000 -#define CHX_UNC_FIXED_CTR_CTL_EN (1 << 0) - -#define CHX_UNC_RAW_EVENT_MASK (CHX_UNC_CTL_EV_SEL_MASK | \ - CHX_UNC_CTL_UMASK_MASK | \ - CHX_UNC_CTL_EDGE_DET | \ - CHX_UNC_CTL_INVERT | \ - CHX_UNC_CTL_CMASK_MASK) - -/* CHX global control register */ -#define CHX_UNC_PERF_GLOBAL_CTL 0x391 -#define CHX_UNC_FIXED_CTR 0x394 -#define CHX_UNC_FIXED_CTR_CTRL 0x395 - -/* CHX uncore global control */ -#define CHX_UNC_GLOBAL_CTL_EN_PC_ALL ((1ULL << 4) - 1) -#define CHX_UNC_GLOBAL_CTL_EN_FC (1ULL << 32) - -/* CHX uncore register */ -#define CHX_UNC_PERFEVTSEL0 0x3c0 -#define CHX_UNC_UNCORE_PMC0 0x3b0 +static int max_packages, max_subnodes, max_clusters; +static int clusters_per_subnode; +static int subnodes_per_die; +static int dies_per_socket; + +/* get CPU topology register */ +#define BJ_GLOBAL_STATU_MSR 0x1610 +#define BJ_HDW_CONFIG_MSR 0X1628 + +/* Wudaokou/Lujiazui event control */ +#define WUDAOKOU_UNC_CTL_EV_SEL_MASK 0x000000ff +#define WUDAOKOU_UNC_CTL_UMASK_MASK 0x0000ff00 +#define WUDAOKOU_UNC_CTL_EDGE_DET (1 << 18) +#define WUDAOKOU_UNC_CTL_EN (1 << 22) +#define WUDAOKOU_UNC_CTL_INVERT (1 << 23) +#define WUDAOKOU_UNC_CTL_CMASK_MASK 0x7000000 +#define WUDAOKOU_UNC_FIXED_CTR_CTL_EN (1 << 0) + +#define WUDAOKOU_UNC_RAW_EVENT_MASK (WUDAOKOU_UNC_CTL_EV_SEL_MASK | \ + WUDAOKOU_UNC_CTL_UMASK_MASK | \ + WUDAOKOU_UNC_CTL_EDGE_DET | \ + WUDAOKOU_UNC_CTL_INVERT | \ + WUDAOKOU_UNC_CTL_CMASK_MASK) + +/* Wudaokou/Lujiazui uncore global register */ +#define WUDAOKOU_UNC_PERF_GLOBAL_CTL 0x391 +#define WUDAOKOU_UNC_FIXED_CTR 0x394 +#define WUDAOKOU_UNC_FIXED_CTR_CTRL 0x395 + +/* Wudaokou/Lujiazui uncore global control */ +#define WUDAOKOU_UNC_GLOBAL_CTL_EN_PC_ALL ((1ULL << 4) - 1) +#define WUDAOKOU_UNC_GLOBAL_CTL_EN_FC (1ULL << 32) + +/* Wudaokou/Lujiazui uncore register */ +#define WUDAOKOU_UNC_PERFEVTSEL0 0x3c0 +#define WUDAOKOU_UNC_UNCORE_PMC0 0x3b0 + +/* Yongfeng event control */ +#define YONGFENG_PMON_CTL_EV_SEL_MASK 0x000000ff +#define YONGFENG_PMON_CTL_UMASK_MASK 0x0000ff00 +#define YONGFENG_PMON_CTL_RST (1 << 17) +#define YONGFENG_PMON_CTL_EDGE_DET (1 << 18) +#define YONGFENG_PMON_CTL_EV_SEL_EXT (1 << 21) +#define YONGFENG_PMON_CTL_EN (1 << 22) +#define YONGFENG_PMON_CTL_INVERT (1 << 23) +#define YONGFENG_PMON_CTL_TRESH_MASK 0xff000000 +#define YONGFENG_PMON_RAW_EVENT_MASK (YONGFENG_PMON_CTL_EV_SEL_MASK | \ + YONGFENG_PMON_CTL_UMASK_MASK | \ + YONGFENG_PMON_CTL_EDGE_DET | \ + YONGFENG_PMON_CTL_INVERT | \ + YONGFENG_PMON_CTL_TRESH_MASK) + +/* Yongfeng LLC register*/ +#define YONGFENG_LLC_MSR_PMON_CTL0 0x1660 +#define YONGFENG_LLC_MSR_PMON_CTR0 0x165c +#define YONGFENG_LLC_MSR_PMON_BLK_CTL 0x1665 + +/* Yongfeng HIF register*/ +#define YONGFENG_HIF_MSR_PMON_CTL0 0x1656 +#define YONGFENG_HIF_MSR_PMON_CTR0 0x1651 +#define YONGFENG_HIF_MSR_PMON_FIXED_CTL 0x1655 +#define YONGFENG_HIF_MSR_PMON_FIXED_CTR 0x1650 +#define YONGFENG_HIF_MSR_PMON_BLK_CTL 0x165b + +/* Yongfeng ZZI(ZPI+ZOI+INI) register*/ +#define YONGFENG_ZZI_MSR_PMON_CTL0 0x166A +#define YONGFENG_ZZI_MSR_PMON_CTR0 0x1666 +#define YONGFENG_ZZI_MSR_PMON_BLK_CTL 0x166f + +/* Yongfeng MC register*/ +#define YONGFENG_MC0_CHy_PMON_FIXED_CTL 0xf40 +#define YONGFENG_MC0_CHy_PMON_FIXED_CTR 0xf20 +#define YONGFENG_MC0_CHy_PMON_CTR0 0xf00 +#define YONGFENG_MC0_CHy_PMON_CTL0 0xf28 +#define YONGFENG_MC0_CHy_PMON_BLK_CTL 0xf44 + +#define YONGFENG_MC1_CHy_PMON_FIXED_CTL 0xf90 +#define YONGFENG_MC1_CHy_PMON_FIXED_CTR 0xf70 +#define YONGFENG_MC1_CHy_PMON_CTR0 0xf50 +#define YONGFENG_MC1_CHy_PMON_CTL0 0xf78 +#define YONGFENG_MC1_CHy_PMON_BLK_CTL 0xf94 + +/* Yongfeng PCI register*/ +#define YONGFENG_PCI_PMON_CTR0 0xf00 +#define YONGFENG_PCI_PMON_CTL0 0xf28 +#define YONGFENG_PCI_PMON_BLK_CTL 0xf44 + +/* Yongfeng ZPI_DLL register*/ +#define YONGFENG_ZPI_DLL_PMON_FIXED_CTL 0xf40 +#define YONGFENG_ZPI_DLL_PMON_FIXED_CTR 0xf20 +#define YONGFENG_ZPI_DLL_PMON_CTR0 0xf00 +#define YONGFENG_ZPI_DLL_PMON_CTL0 0xf28 +#define YONGFENG_ZPI_DLL_PMON_BLK_CTL 0xf44 + +/* Yongfeng ZDI_DLL register*/ +#define YONGFENG_ZDI_DLL_PMON_FIXED_CTL 0xf40 +#define YONGFENG_ZDI_DLL_PMON_FIXED_CTR 0xf20 +#define YONGFENG_ZDI_DLL_PMON_CTR0 0xf00 +#define YONGFENG_ZDI_DLL_PMON_CTL0 0xf28 +#define YONGFENG_ZDI_DLL_PMON_BLK_CTL 0xf44 + +/* Yongfeng PXPTRF register*/ +#define YONGFENG_PXPTRF_PMON_CTR0 0xf00 +#define YONGFENG_PXPTRF_PMON_CTL0 0xf28 +#define YONGFENG_PXPTRF_PMON_BLK_CTL 0xf44 + +/* Yongfeng Box level control */ +#define YONGFENG_PMON_BOX_CTL_RST_CTRL (1 << 0) +#define YONGFENG_PMON_BOX_CTL_RST_CTRS (1 << 1) +#define YONGFENG_PMON_BOX_CTL_FRZ (1 << 8) +//#define YONGFENG_PMON_BOX_CTL_FRZ_EN (1 << 16) +#define YONGFENG_PMON_PCI_BOX_PMON_EN (1 << 31) + +#define YONGFENG_PMON_BOX_CTL_INT (YONGFENG_PMON_BOX_CTL_RST_CTRL | \ + YONGFENG_PMON_BOX_CTL_RST_CTRS) + + +#define YONGFENG_PMON_PCI_BOX_CTL_INT (YONGFENG_PMON_BOX_CTL_RST_CTRL | \ + YONGFENG_PMON_BOX_CTL_RST_CTRS | \ + YONGFENG_PMON_PCI_BOX_PMON_EN) DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); +DEFINE_UNCORE_FORMAT_ATTR(cmask3, cmask, "config:24-26"); DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31"); -ssize_t zx_uncore_event_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +static void get_hw_info_msr(void *info) +{ + struct hw_info *data = info; + + rdmsrl(BJ_HDW_CONFIG_MSR, data->config_info); + rdmsrl(BJ_GLOBAL_STATU_MSR, data->active_state); +} + +/*topology info : get max cluster*/ +static int topology_clusters(void) +{ + int cpu; + int clusters = 0; + int tmp_clusters; + struct hw_info data; + + u64 sdnc = ~0ULL; //socket_die_subnode_cluster + u64 config; + u64 state; + + for_each_present_cpu(cpu) { + + smp_call_function_single(cpu, get_hw_info_msr, &data, 1); + config = data.config_info; + state = data.active_state; + + config &= 0x3f << 18; + state &= 0x3 << 6; + state >>= 6; + + if (state == 0) + tmp_clusters = 0; + else if (state == 0x1 || state == 0x2) + tmp_clusters = 1; + else + tmp_clusters = 2; + + if (clusters_per_subnode < tmp_clusters) + clusters_per_subnode = tmp_clusters; + + if (config != sdnc) + clusters++; + sdnc = config; + } + + return clusters; + +} + +static int topology_subnodes(void) +{ + int cpu; + int subnodes = 0; + struct hw_info data; + + u64 sdn = ~0ULL; //socket_die_subnode + u64 config; + + int die_info; + int tmp_dies; + int subnode_info; + int tmp_subnodes; + + for_each_present_cpu(cpu) { + + smp_call_function_single(cpu, get_hw_info_msr, &data, 1); + config = data.config_info; + + die_info = (int)(config & (0x3 << 21)); + tmp_dies = (die_info >> 21) + 1; + if (dies_per_socket < tmp_dies) + dies_per_socket = tmp_dies; + + subnode_info = (int)(config & (0x1 << 20)); + tmp_subnodes = (subnode_info >> 20) + 1; + if (subnodes_per_die < tmp_subnodes) + subnodes_per_die = tmp_subnodes; + + config &= 0xf << 20; //bit20~bit23 + + if (config != sdn) + subnodes++; + sdn = config; + } + + return subnodes; +} + +static inline int uncore_pcibus_to_subnodeid(struct pci_bus *bus) +{ + int numbers_per_subnodes = 256/max_subnodes; + + return bus->number/numbers_per_subnodes; +} + +DEFINE_PER_CPU(int, zx_subnode_id); +DEFINE_PER_CPU(int, zx_cluster_id); + +static void get_cluster_info(void) +{ + int cpu; + int cluster_id; + int socket_id; + int die_id; + int subnode_id; + struct hw_info data; + + int socket_info; + int die_info; + int subnode_info; + int cluster_info; + + u64 config; + + for_each_present_cpu(cpu) { + smp_call_function_single(cpu, get_hw_info_msr, &data, 1); + config = data.config_info; + + socket_info = (int)(config & (0x1 << 23)); + socket_info >>= 23; + socket_id = socket_info; + + die_info = (int)(config & (0x3 << 21)); + die_info >>= 21; + die_id = socket_id * dies_per_socket + die_info; + + subnode_info = (int)(config & (0x1 << 20)); + subnode_info >>= 20; + subnode_id = die_id * subnodes_per_die + subnode_info; + + cluster_info = (int)(config & (0x3 << 18)); + cluster_info >>= 18; + + cluster_id = subnode_id * clusters_per_subnode + cluster_info; + + per_cpu(zx_cluster_id, cpu) = cluster_id; + } +} + +static void get_subnode_info(void) +{ + int cpu; + int socket_id; + int die_id; + int subnode_id; + struct hw_info data; + + int socket_info; + int die_info; + int subnode_info; + u64 config; + + for_each_present_cpu(cpu) { + smp_call_function_single(cpu, get_hw_info_msr, &data, 1); + config = data.config_info; + + socket_info = (int)(config & (0x1 << 23)); + socket_info >>= 23; + socket_id = socket_info; + + die_info = (int)(config & (0x3 << 21)); + die_info >>= 21; + die_id = socket_id * dies_per_socket + die_info; + + subnode_info = (int)(config & (0x1 << 20)); + subnode_info >>= 20; + subnode_id = die_id * subnodes_per_die + subnode_info; + + per_cpu(zx_subnode_id, cpu) = subnode_id; + } +} + +static int topology_cluster_id(int cpu) +{ + int cluster_id; + + cluster_id = per_cpu(zx_cluster_id, cpu); + + return cluster_id; +} + +static int topology_subnode_id(int cpu) +{ + int subnode_id; + + subnode_id = per_cpu(zx_subnode_id, cpu); + + return subnode_id; +} + +DEFINE_PER_CPU(cpumask_t, zx_cluster_core_bits); +DEFINE_PER_CPU(cpumask_t, zx_subnode_core_bits); + +static void zx_gen_core_map(void) +{ + int i, nr, cpu; + int cluster_id, subnode_id; + + for_each_present_cpu(cpu) { + + cluster_id = topology_cluster_id(cpu); + + for (i = 0; i < 4; i++) { + nr = (cluster_id << 2) + i; + cpumask_set_cpu(nr, &per_cpu(zx_cluster_core_bits, cpu)); + } + } + + for_each_present_cpu(cpu) { + + subnode_id = topology_subnode_id(cpu); + + for (i = 0; i < 8; i++) { + nr = (subnode_id << 3) + i; + cpumask_set_cpu(nr, &per_cpu(zx_subnode_core_bits, cpu)); + } + } + +} + +static struct cpumask *topology_cluster_core_cpumask(int cpu) +{ + return &per_cpu(zx_cluster_core_bits, cpu); +} + +static struct cpumask *topology_subnode_core_cpumask(int cpu) +{ + return &per_cpu(zx_subnode_core_bits, cpu); +} + +static void uncore_free_pcibus_map(void) +{ + +} + +static int yongfeng_pci2node_map_init(void) +{ + return 0; +} + +ssize_t zx_uncore_event_show(struct device *dev, struct device_attribute *attr, char *buf) { struct uncore_event_desc *event = container_of(attr, struct uncore_event_desc, attr); return sprintf(buf, "%s", event->config); } -/*chx uncore support */ -static void chx_uncore_msr_disable_event(struct zhaoxin_uncore_box *box, struct perf_event *event) +static struct zhaoxin_uncore_box *uncore_pmu_to_box(struct zhaoxin_uncore_pmu *pmu, int cpu) { - wrmsrl(event->hw.config_base, 0); + + if (boot_cpu_data.x86_model == 0x5b) { + if (!strcmp(pmu->type->name, "llc")) + return pmu->boxes[topology_cluster_id(cpu)]; + else + return pmu->boxes[topology_subnode_id(cpu)]; + } else { + return pmu->boxes[topology_logical_package_id(cpu)]; + } } static u64 uncore_msr_read_counter(struct zhaoxin_uncore_box *box, struct perf_event *event) { u64 count; + WARN_ON_ONCE(box->cpu != smp_processor_id()); rdmsrl(event->hw.event_base, count); - return count; } -static void chx_uncore_msr_disable_box(struct zhaoxin_uncore_box *box) +static void uncore_assign_hw_event(struct zhaoxin_uncore_box *box, + struct perf_event *event, int idx) { - wrmsrl(CHX_UNC_PERF_GLOBAL_CTL, 0); + struct hw_perf_event *hwc = &event->hw; + + hwc->idx = idx; + hwc->last_tag = ++box->tags[idx]; + + if (uncore_pmc_fixed(hwc->idx)) { + hwc->event_base = uncore_fixed_ctr(box); + hwc->config_base = uncore_fixed_ctl(box); + return; + } + + hwc->config_base = uncore_event_ctl(box, hwc->idx); + hwc->event_base = uncore_perf_ctr(box, hwc->idx); } -static void chx_uncore_msr_enable_box(struct zhaoxin_uncore_box *box) +void uncore_perf_event_update(struct zhaoxin_uncore_box *box, struct perf_event *event) { - wrmsrl(CHX_UNC_PERF_GLOBAL_CTL, CHX_UNC_GLOBAL_CTL_EN_PC_ALL | CHX_UNC_GLOBAL_CTL_EN_FC); + u64 prev_count, new_count, delta; + int shift; + + if (uncore_pmc_fixed(event->hw.idx)) + shift = 64 - uncore_fixed_ctr_bits(box); + else + shift = 64 - uncore_perf_ctr_bits(box); + + /* the hrtimer might modify the previous event value */ +again: + prev_count = local64_read(&event->hw.prev_count); + new_count = uncore_read_counter(box, event); + if (local64_xchg(&event->hw.prev_count, new_count) != prev_count) + goto again; + + delta = (new_count << shift) - (prev_count << shift); + delta >>= shift; + + local64_add(delta, &event->count); +} + +/*Wudaokou/Lujiazui uncore ops start*/ +static void wudaokou_uncore_msr_disable_event(struct zhaoxin_uncore_box *box, + struct perf_event *event) +{ + wrmsrl(event->hw.config_base, 0); +} + +static void wudaokou_uncore_msr_disable_box(struct zhaoxin_uncore_box *box) +{ + wrmsrl(WUDAOKOU_UNC_PERF_GLOBAL_CTL, 0); +} + +static void wudaokou_uncore_msr_enable_box(struct zhaoxin_uncore_box *box) +{ + wrmsrl(WUDAOKOU_UNC_PERF_GLOBAL_CTL, + WUDAOKOU_UNC_GLOBAL_CTL_EN_PC_ALL | WUDAOKOU_UNC_GLOBAL_CTL_EN_FC); } -static void chx_uncore_msr_enable_event(struct zhaoxin_uncore_box *box, struct perf_event *event) +static void wudaokou_uncore_msr_enable_event(struct zhaoxin_uncore_box *box, + struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; if (hwc->idx < UNCORE_PMC_IDX_FIXED) - wrmsrl(hwc->config_base, hwc->config | CHX_UNC_CTL_EN); + wrmsrl(hwc->config_base, hwc->config | WUDAOKOU_UNC_CTL_EN); else - wrmsrl(hwc->config_base, CHX_UNC_FIXED_CTR_CTL_EN); + wrmsrl(hwc->config_base, WUDAOKOU_UNC_FIXED_CTR_CTL_EN); } -static struct attribute *chx_uncore_formats_attr[] = { +static struct attribute *wudaokou_uncore_formats_attr[] = { &format_attr_event.attr, &format_attr_umask.attr, &format_attr_edge.attr, &format_attr_inv.attr, - &format_attr_cmask8.attr, + &format_attr_cmask3.attr, NULL, }; -static struct attribute_group chx_uncore_format_group = { +static struct attribute_group wudaokou_uncore_format_group = { .name = "format", - .attrs = chx_uncore_formats_attr, + .attrs = wudaokou_uncore_formats_attr, }; -static struct uncore_event_desc chx_uncore_events[] = { +static struct uncore_event_desc wudaokou_uncore_events[] = { { /* end: all zeroes */ }, }; -static struct zhaoxin_uncore_ops chx_uncore_msr_ops = { - .disable_box = chx_uncore_msr_disable_box, - .enable_box = chx_uncore_msr_enable_box, - .disable_event = chx_uncore_msr_disable_event, - .enable_event = chx_uncore_msr_enable_event, +static struct zhaoxin_uncore_ops wudaokou_uncore_msr_ops = { + .disable_box = wudaokou_uncore_msr_disable_box, + .enable_box = wudaokou_uncore_msr_enable_box, + .disable_event = wudaokou_uncore_msr_disable_event, + .enable_event = wudaokou_uncore_msr_enable_event, .read_counter = uncore_msr_read_counter, }; -static struct zhaoxin_uncore_type chx_uncore_box = { +static struct zhaoxin_uncore_type wudaokou_uncore_box = { .name = "", .num_counters = 4, .num_boxes = 1, .perf_ctr_bits = 48, .fixed_ctr_bits = 48, - .event_ctl = CHX_UNC_PERFEVTSEL0, - .perf_ctr = CHX_UNC_UNCORE_PMC0, - .fixed_ctr = CHX_UNC_FIXED_CTR, - .fixed_ctl = CHX_UNC_FIXED_CTR_CTRL, - .event_mask = CHX_UNC_RAW_EVENT_MASK, - .event_descs = chx_uncore_events, - .ops = &chx_uncore_msr_ops, - .format_group = &chx_uncore_format_group, + .event_ctl = WUDAOKOU_UNC_PERFEVTSEL0, + .perf_ctr = WUDAOKOU_UNC_UNCORE_PMC0, + .fixed_ctr = WUDAOKOU_UNC_FIXED_CTR, + .fixed_ctl = WUDAOKOU_UNC_FIXED_CTR_CTRL, + .event_mask = WUDAOKOU_UNC_RAW_EVENT_MASK, + .event_descs = wudaokou_uncore_events, + .ops = &wudaokou_uncore_msr_ops, + .format_group = &wudaokou_uncore_format_group, }; -static struct zhaoxin_uncore_type *chx_msr_uncores[] = { - &chx_uncore_box, +static struct zhaoxin_uncore_type *wudaokou_msr_uncores[] = { + &wudaokou_uncore_box, NULL, }; +/*Wudaokou/Lujiazui uncore ops end*/ -static struct zhaoxin_uncore_box *uncore_pmu_to_box(struct zhaoxin_uncore_pmu *pmu, int cpu) +/*YONGFENG msr ops start*/ +static void yongfeng_uncore_msr_disable_event(struct zhaoxin_uncore_box *box, + struct perf_event *event) { - unsigned int package_id = topology_logical_package_id(cpu); + struct hw_perf_event *hwc = &event->hw; - /* - * The unsigned check also catches the '-1' return value for non - * existent mappings in the topology map. - */ - return package_id < max_packages ? pmu->boxes[package_id] : NULL; + wrmsrl(hwc->config_base, hwc->config); } -static void uncore_assign_hw_event(struct zhaoxin_uncore_box *box, - struct perf_event *event, int idx) +static void yongfeng_uncore_msr_enable_event(struct zhaoxin_uncore_box *box, + struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - hwc->idx = idx; - hwc->last_tag = ++box->tags[idx]; + wrmsrl(hwc->config_base, hwc->config | YONGFENG_PMON_CTL_EN); +} - if (uncore_pmc_fixed(hwc->idx)) { - hwc->event_base = uncore_fixed_ctr(box); - hwc->config_base = uncore_fixed_ctl(box); - return; +static void yongfeng_uncore_msr_disable_box(struct zhaoxin_uncore_box *box) +{ + u64 config; + unsigned int msr; + + msr = uncore_msr_box_ctl(box); + if (msr) { + rdmsrl(msr, config); + config |= YONGFENG_PMON_BOX_CTL_FRZ; + wrmsrl(msr, config); } +} - hwc->config_base = uncore_event_ctl(box, hwc->idx); - hwc->event_base = uncore_perf_ctr(box, hwc->idx); +static void yongfeng_uncore_msr_enable_box(struct zhaoxin_uncore_box *box) +{ + u64 config; + unsigned int msr; + + msr = uncore_msr_box_ctl(box); + if (msr) { + rdmsrl(msr, config); + config &= ~YONGFENG_PMON_BOX_CTL_FRZ; + wrmsrl(msr, config); + } } -void uncore_perf_event_update(struct zhaoxin_uncore_box *box, struct perf_event *event) +static void yongfeng_uncore_msr_init_box(struct zhaoxin_uncore_box *box) { - u64 prev_count, new_count, delta; - int shift; + unsigned int msr = uncore_msr_box_ctl(box); - if (uncore_pmc_fixed(event->hw.idx)) - shift = 64 - uncore_fixed_ctr_bits(box); - else - shift = 64 - uncore_perf_ctr_bits(box); + if (msr) { + wrmsrl(msr, YONGFENG_PMON_BOX_CTL_INT); + wrmsrl(msr, 0); + } - /* the hrtimer might modify the previous event value */ -again: - prev_count = local64_read(&event->hw.prev_count); - new_count = uncore_read_counter(box, event); - if (local64_xchg(&event->hw.prev_count, new_count) != prev_count) - goto again; +} - delta = (new_count << shift) - (prev_count << shift); - delta >>= shift; +static struct attribute *yongfeng_uncore_formats_attr[] = { + &format_attr_event.attr, + &format_attr_umask.attr, + &format_attr_edge.attr, + &format_attr_inv.attr, + &format_attr_cmask8.attr, + NULL, +}; - local64_add(delta, &event->count); +static struct attribute_group yongfeng_uncore_format_group = { + .name = "format", + .attrs = yongfeng_uncore_formats_attr, +}; + +static struct uncore_event_desc yongfeng_uncore_llc_box_events[] = { + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc yongfeng_uncore_hif_box_events[] = { + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc yongfeng_uncore_zzi_box_events[] = { + { /* end: all zeroes */ }, +}; + +static struct zhaoxin_uncore_ops yongfeng_uncore_msr_ops = { + .init_box = yongfeng_uncore_msr_init_box, + .disable_box = yongfeng_uncore_msr_disable_box, + .enable_box = yongfeng_uncore_msr_enable_box, + .disable_event = yongfeng_uncore_msr_disable_event, + .enable_event = yongfeng_uncore_msr_enable_event, + .read_counter = uncore_msr_read_counter, +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_llc_box = { + .name = "llc", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .event_ctl = YONGFENG_LLC_MSR_PMON_CTL0, + .perf_ctr = YONGFENG_LLC_MSR_PMON_CTR0, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_LLC_MSR_PMON_BLK_CTL, + .event_descs = yongfeng_uncore_llc_box_events, + .ops = &yongfeng_uncore_msr_ops, + .format_group = &yongfeng_uncore_format_group, +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_hif_box = { + .name = "hif", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .fixed_ctr_bits = 48, + .event_ctl = YONGFENG_HIF_MSR_PMON_CTL0, + .perf_ctr = YONGFENG_HIF_MSR_PMON_CTR0, + .fixed_ctr = YONGFENG_HIF_MSR_PMON_FIXED_CTR, + .fixed_ctl = YONGFENG_HIF_MSR_PMON_FIXED_CTL, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_HIF_MSR_PMON_BLK_CTL, + .event_descs = yongfeng_uncore_hif_box_events, + .ops = &yongfeng_uncore_msr_ops, + .format_group = &yongfeng_uncore_format_group, +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_zzi_box = { + .name = "zzi", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .event_ctl = YONGFENG_ZZI_MSR_PMON_CTL0, + .perf_ctr = YONGFENG_ZZI_MSR_PMON_CTR0, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_ZZI_MSR_PMON_BLK_CTL, + .event_descs = yongfeng_uncore_zzi_box_events, + .ops = &yongfeng_uncore_msr_ops, + .format_group = &yongfeng_uncore_format_group, +}; + +static struct zhaoxin_uncore_type *yongfeng_msr_uncores[] = { + &yongfeng_uncore_llc_box, + &yongfeng_uncore_hif_box, + &yongfeng_uncore_zzi_box, + NULL, +}; +/*Yongfeng msr ops end*/ + +/*Yongfeng pci ops start*/ +static void yongfeng_uncore_pci_disable_event(struct zhaoxin_uncore_box *box, + struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + + pci_write_config_dword(pdev, hwc->config_base, hwc->config); +} + +static void yongfeng_uncore_pci_enable_event(struct zhaoxin_uncore_box *box, + struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + + pci_write_config_dword(pdev, hwc->config_base, + hwc->config | YONGFENG_PMON_CTL_EN); } +static void yongfeng_uncore_pci_disable_box(struct zhaoxin_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + int box_ctl = uncore_pci_box_ctl(box); + u32 config = 0; + + if (!pci_read_config_dword(pdev, box_ctl, &config)) { + config |= YONGFENG_PMON_BOX_CTL_FRZ; + pci_write_config_dword(pdev, box_ctl, config); + } +} + +static void yongfeng_uncore_pci_enable_box(struct zhaoxin_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + int box_ctl = uncore_pci_box_ctl(box); + u32 config = 0; + + if (!pci_read_config_dword(pdev, box_ctl, &config)) { + config &= ~YONGFENG_PMON_BOX_CTL_FRZ; + pci_write_config_dword(pdev, box_ctl, config); + } +} + +static u64 yongfeng_uncore_pci_read_counter(struct zhaoxin_uncore_box *box, + struct perf_event *event) +{ + struct pci_dev *pdev = box->pci_dev; + struct hw_perf_event *hwc = &event->hw; + u64 count = 0; + + pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count + 1); + pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count); + return count; +} + +static void yongfeng_uncore_pci_init_box(struct zhaoxin_uncore_box *box) +{ + struct pci_dev *pdev = box->pci_dev; + int box_ctl = uncore_pci_box_ctl(box); + + pci_write_config_dword(pdev, box_ctl, YONGFENG_PMON_PCI_BOX_CTL_INT); +} + +static struct uncore_event_desc yongfeng_uncore_imc_events[] = { + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc yongfeng_uncore_pci_events[] = { + + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc yongfeng_uncore_zpi_dll_events[] = { + + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc yongfeng_uncore_zdi_dll_events[] = { + + { /* end: all zeroes */ }, +}; + +static struct uncore_event_desc yongfeng_uncore_pxptrf_events[] = { + + { /* end: all zeroes */ }, +}; + +static struct zhaoxin_uncore_ops yongfeng_uncore_pci_ops = { + .init_box = yongfeng_uncore_pci_init_box, + .disable_box = yongfeng_uncore_pci_disable_box, + .enable_box = yongfeng_uncore_pci_enable_box, + .disable_event = yongfeng_uncore_pci_disable_event, + .enable_event = yongfeng_uncore_pci_enable_event, + .read_counter = yongfeng_uncore_pci_read_counter +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_mc0 = { + .name = "mc0", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .fixed_ctr_bits = 48, + .fixed_ctr = YONGFENG_MC0_CHy_PMON_FIXED_CTR, + .fixed_ctl = YONGFENG_MC0_CHy_PMON_FIXED_CTL, + .event_descs = yongfeng_uncore_imc_events, + .perf_ctr = YONGFENG_MC0_CHy_PMON_CTR0, + .event_ctl = YONGFENG_MC0_CHy_PMON_CTL0, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_MC0_CHy_PMON_BLK_CTL, + .ops = &yongfeng_uncore_pci_ops, + .format_group = &yongfeng_uncore_format_group +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_mc1 = { + .name = "mc1", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .fixed_ctr_bits = 48, + .fixed_ctr = YONGFENG_MC1_CHy_PMON_FIXED_CTR, + .fixed_ctl = YONGFENG_MC1_CHy_PMON_FIXED_CTL, + .event_descs = yongfeng_uncore_imc_events, + .perf_ctr = YONGFENG_MC1_CHy_PMON_CTR0, + .event_ctl = YONGFENG_MC1_CHy_PMON_CTL0, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_MC1_CHy_PMON_BLK_CTL, + .ops = &yongfeng_uncore_pci_ops, + .format_group = &yongfeng_uncore_format_group +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_pci = { + .name = "pci", + .num_counters = 4, + .num_boxes = 2, + .perf_ctr_bits = 48, + .event_descs = yongfeng_uncore_pci_events, + .perf_ctr = YONGFENG_PCI_PMON_CTR0, + .event_ctl = YONGFENG_PCI_PMON_CTL0, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_PCI_PMON_BLK_CTL, + .ops = &yongfeng_uncore_pci_ops, + .format_group = &yongfeng_uncore_format_group +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_zpi_dll = { + .name = "zpi_dll", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .event_descs = yongfeng_uncore_zpi_dll_events, + .perf_ctr = YONGFENG_ZPI_DLL_PMON_CTR0, + .event_ctl = YONGFENG_ZPI_DLL_PMON_CTL0, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_ZPI_DLL_PMON_BLK_CTL, + .ops = &yongfeng_uncore_pci_ops, + .format_group = &yongfeng_uncore_format_group +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_zdi_dll = { + .name = "zdi_dll", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .event_descs = yongfeng_uncore_zdi_dll_events, + .perf_ctr = YONGFENG_ZDI_DLL_PMON_CTR0, + .event_ctl = YONGFENG_ZDI_DLL_PMON_CTL0, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_ZDI_DLL_PMON_BLK_CTL, + .ops = &yongfeng_uncore_pci_ops, + .format_group = &yongfeng_uncore_format_group +}; + +static struct zhaoxin_uncore_type yongfeng_uncore_pxptrf = { + .name = "pxptrf", + .num_counters = 4, + .num_boxes = 1, + .perf_ctr_bits = 48, + .event_descs = yongfeng_uncore_pxptrf_events, + .perf_ctr = YONGFENG_PXPTRF_PMON_CTR0, + .event_ctl = YONGFENG_PXPTRF_PMON_CTL0, + .event_mask = YONGFENG_PMON_RAW_EVENT_MASK, + .box_ctl = YONGFENG_PXPTRF_PMON_BLK_CTL, + .ops = &yongfeng_uncore_pci_ops, + .format_group = &yongfeng_uncore_format_group +}; + +enum { + YONGFENG_PCI_UNCORE_MC0, + YONGFENG_PCI_UNCORE_MC1, + YONGFENG_PCI_UNCORE_PCI, + YONGFENG_PCI_UNCORE_ZPI_DLL, + YONGFENG_PCI_UNCORE_ZDI_DLL, + YONGFENG_PCI_UNCORE_PXPTRF, +}; + +static struct zhaoxin_uncore_type *yongfeng_pci_uncores[] = { + [YONGFENG_PCI_UNCORE_MC0] = &yongfeng_uncore_mc0, + [YONGFENG_PCI_UNCORE_MC1] = &yongfeng_uncore_mc1, + [YONGFENG_PCI_UNCORE_PCI] = &yongfeng_uncore_pci, + [YONGFENG_PCI_UNCORE_ZPI_DLL] = &yongfeng_uncore_zpi_dll, + [YONGFENG_PCI_UNCORE_ZDI_DLL] = &yongfeng_uncore_zdi_dll, + [YONGFENG_PCI_UNCORE_PXPTRF] = &yongfeng_uncore_pxptrf, + NULL, +}; + +static const struct pci_device_id yongfeng_uncore_pci_ids[] = { + + { /* MC Channe0/1 */ + PCI_DEVICE(0x1D17, 0x31b2), + .driver_data = UNCORE_PCI_DEV_DATA(YONGFENG_PCI_UNCORE_MC0, 0), + + }, + + { /* PCIA */ + PCI_DEVICE(0x1D17, 0x0717), + .driver_data = UNCORE_PCI_DEV_DATA(YONGFENG_PCI_UNCORE_PCI, 0), + + }, + + { /* PCIB */ + PCI_DEVICE(0x1D17, 0x071c), + .driver_data = UNCORE_PCI_DEV_DATA(YONGFENG_PCI_UNCORE_PCI, 1), + + }, + + { /* ZPI_DLL */ + PCI_DEVICE(0x1D17, 0x91c1), + .driver_data = UNCORE_PCI_DEV_DATA(YONGFENG_PCI_UNCORE_ZPI_DLL, 0), + + }, + + { /* ZDI_DLL */ + PCI_DEVICE(0x1D17, 0x3b03), + .driver_data = UNCORE_PCI_DEV_DATA(YONGFENG_PCI_UNCORE_ZDI_DLL, 0), + + }, + + { /* PXPTRF */ + PCI_DEVICE(0x1D17, 0x31B4), + .driver_data = UNCORE_PCI_DEV_DATA(YONGFENG_PCI_UNCORE_PXPTRF, 0), + + }, + + { /* end: all zeroes */ } +}; + +static struct pci_driver yongfeng_uncore_pci_driver = { + .name = "yongfeng_uncore", + .id_table = yongfeng_uncore_pci_ids, +}; +/*Yongfeng pci ops end*/ + static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer) { struct zhaoxin_uncore_box *box; @@ -259,6 +996,8 @@ static struct zhaoxin_uncore_box *uncore_alloc_box(struct zhaoxin_uncore_type *t uncore_pmu_init_hrtimer(box); box->cpu = -1; box->package_id = -1; + box->cluster_id = -1; + box->subnode_id = -1; /* set default hrtimer timeout */ box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL; @@ -273,6 +1012,44 @@ static bool is_box_event(struct zhaoxin_uncore_box *box, struct perf_event *even return &box->pmu->pmu == event->pmu; } +static int +uncore_collect_events(struct zhaoxin_uncore_box *box, struct perf_event *leader, + bool dogrp) +{ + struct perf_event *event; + int n, max_count; + + max_count = box->pmu->type->num_counters; + if (box->pmu->type->fixed_ctl) + max_count++; + + if (box->n_events >= max_count) + return -EINVAL; + + n = box->n_events; + + if (is_box_event(box, leader)) { + box->event_list[n] = leader; + n++; + } + + if (!dogrp) + return n; + + for_each_sibling_event(event, leader) { + if (!is_box_event(box, event) || + event->state <= PERF_EVENT_STATE_OFF) + continue; + + if (n >= max_count) + return -EINVAL; + + box->event_list[n] = event; + n++; + } + return n; +} + static struct event_constraint * uncore_get_event_constraint(struct zhaoxin_uncore_box *box, struct perf_event *event) { @@ -408,44 +1185,6 @@ static void uncore_pmu_event_stop(struct perf_event *event, int flags) } } -static int -uncore_collect_events(struct zhaoxin_uncore_box *box, struct perf_event *leader, - bool dogrp) -{ - struct perf_event *event; - int n, max_count; - - max_count = box->pmu->type->num_counters; - if (box->pmu->type->fixed_ctl) - max_count++; - - if (box->n_events >= max_count) - return -EINVAL; - - n = box->n_events; - - if (is_box_event(box, leader)) { - box->event_list[n] = leader; - n++; - } - - if (!dogrp) - return n; - - for_each_sibling_event(event, leader) { - if (!is_box_event(box, event) || - event->state <= PERF_EVENT_STATE_OFF) - continue; - - if (n >= max_count) - return -EINVAL; - - box->event_list[n] = event; - n++; - } - return n; -} - static int uncore_pmu_event_add(struct perf_event *event, int flags) { struct zhaoxin_uncore_box *box = uncore_event_to_box(event); @@ -461,6 +1200,7 @@ static int uncore_pmu_event_add(struct perf_event *event, int flags) return ret; hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; + if (!(flags & PERF_EF_START)) hwc->state |= PERF_HES_ARCH; @@ -507,6 +1247,36 @@ static int uncore_pmu_event_add(struct perf_event *event, int flags) return 0; } +static void uncore_pmu_event_del(struct perf_event *event, int flags) +{ + struct zhaoxin_uncore_box *box = uncore_event_to_box(event); + int i; + + uncore_pmu_event_stop(event, PERF_EF_UPDATE); + + for (i = 0; i < box->n_events; i++) { + if (event == box->event_list[i]) { + uncore_put_event_constraint(box, event); + + for (++i; i < box->n_events; i++) + box->event_list[i - 1] = box->event_list[i]; + + --box->n_events; + break; + } + } + + event->hw.idx = -1; + event->hw.last_tag = ~0ULL; +} + +static void uncore_pmu_event_read(struct perf_event *event) +{ + struct zhaoxin_uncore_box *box = uncore_event_to_box(event); + + uncore_perf_event_update(box, event); +} + static int uncore_validate_group(struct zhaoxin_uncore_pmu *pmu, struct perf_event *event) { @@ -542,36 +1312,6 @@ static int uncore_validate_group(struct zhaoxin_uncore_pmu *pmu, return ret; } -static void uncore_pmu_event_del(struct perf_event *event, int flags) -{ - struct zhaoxin_uncore_box *box = uncore_event_to_box(event); - int i; - - uncore_pmu_event_stop(event, PERF_EF_UPDATE); - - for (i = 0; i < box->n_events; i++) { - if (event == box->event_list[i]) { - uncore_put_event_constraint(box, event); - - for (++i; i < box->n_events; i++) - box->event_list[i - 1] = box->event_list[i]; - - --box->n_events; - break; - } - } - - event->hw.idx = -1; - event->hw.last_tag = ~0ULL; -} - -static void uncore_pmu_event_read(struct perf_event *event) -{ - struct zhaoxin_uncore_box *box = uncore_event_to_box(event); - - uncore_perf_event_update(box, event); -} - static int uncore_pmu_event_init(struct perf_event *event) { struct zhaoxin_uncore_pmu *pmu; @@ -603,7 +1343,7 @@ static int uncore_pmu_event_init(struct perf_event *event) event->cpu = box->cpu; event->pmu_private = box; - event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG; + //event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG; event->hw.idx = -1; event->hw.last_tag = ~0ULL; @@ -633,30 +1373,85 @@ static int uncore_pmu_event_init(struct perf_event *event) } } - if (event->group_leader != event) - ret = uncore_validate_group(pmu, event); - else - ret = 0; - + if (event->group_leader != event) + ret = uncore_validate_group(pmu, event); + else + ret = 0; + + return ret; +} + +static ssize_t uncore_get_attr_cpumask(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + cpumask_t *active_mask; + struct pmu *pmu; + struct zhaoxin_uncore_pmu *uncore_pmu; + + pmu = dev_get_drvdata(dev); + uncore_pmu = container_of(pmu, struct zhaoxin_uncore_pmu, pmu); + + if (boot_cpu_data.x86_model == 0x5b) { + if (!strcmp(uncore_pmu->type->name, "llc")) + active_mask = &uncore_cpu_cluster_mask; + else + active_mask = &uncore_cpu_subnode_mask; + } else { + active_mask = &uncore_cpu_mask; + } + + return cpumap_print_to_pagebuf(true, buf, active_mask); +} + +static DEVICE_ATTR(cpumask, S_IRUGO, uncore_get_attr_cpumask, NULL); + +static struct attribute *uncore_pmu_attrs[] = { + &dev_attr_cpumask.attr, + NULL, +}; + +static const struct attribute_group uncore_pmu_attr_group = { + .attrs = uncore_pmu_attrs, +}; + +static int uncore_pmu_register(struct zhaoxin_uncore_pmu *pmu) +{ + int ret; + + if (!pmu->type->pmu) { + pmu->pmu = (struct pmu) { + .attr_groups = pmu->type->attr_groups, + .task_ctx_nr = perf_invalid_context, + .event_init = uncore_pmu_event_init, + .add = uncore_pmu_event_add, + .del = uncore_pmu_event_del, + .start = uncore_pmu_event_start, + .stop = uncore_pmu_event_stop, + .read = uncore_pmu_event_read, + .module = THIS_MODULE, + }; + } else { + pmu->pmu = *pmu->type->pmu; + pmu->pmu.attr_groups = pmu->type->attr_groups; + } + + if (pmu->type->num_boxes == 1) { + if (strlen(pmu->type->name) > 0) + sprintf(pmu->name, "uncore_%s", pmu->type->name); + else + sprintf(pmu->name, "uncore"); + } else { + sprintf(pmu->name, "uncore_%s_%d", pmu->type->name, + pmu->pmu_idx); + } + + ret = perf_pmu_register(&pmu->pmu, pmu->name, -1); + if (!ret) + pmu->registered = true; return ret; } -static ssize_t uncore_get_attr_cpumask(struct device *dev, struct device_attribute *attr, char *buf) -{ - return cpumap_print_to_pagebuf(true, buf, &uncore_cpu_mask); -} - -static DEVICE_ATTR(cpumask, S_IRUGO, uncore_get_attr_cpumask, NULL); - -static struct attribute *uncore_pmu_attrs[] = { - &dev_attr_cpumask.attr, - NULL, -}; - -static const struct attribute_group uncore_pmu_attr_group = { - .attrs = uncore_pmu_attrs, -}; - static void uncore_pmu_unregister(struct zhaoxin_uncore_pmu *pmu) { if (!pmu->registered) @@ -667,10 +1462,21 @@ static void uncore_pmu_unregister(struct zhaoxin_uncore_pmu *pmu) static void uncore_free_boxes(struct zhaoxin_uncore_pmu *pmu) { - int package; + int i, max; + + if (boot_cpu_data.x86_model == 0x5b) { + + if (!strcmp(pmu->type->name, "llc")) + max = max_clusters; + else + max = max_subnodes; - for (package = 0; package < max_packages; package++) - kfree(pmu->boxes[package]); + } else { + max = max_packages; + } + + for (i = 0; i < max; i++) + kfree(pmu->boxes[i]); kfree(pmu->boxes); } @@ -707,7 +1513,16 @@ static int __init uncore_type_init(struct zhaoxin_uncore_type *type, bool setid) if (!pmus) return -ENOMEM; - size = max_packages*sizeof(struct zhaoxin_uncore_box *); + if (boot_cpu_data.x86_model == 0x5b) { + + if (!strcmp(type->name, "llc")) + size = max_clusters * sizeof(struct zhaoxin_uncore_box *); + else + size = max_subnodes * sizeof(struct zhaoxin_uncore_box *); + + } else { + size = max_packages * sizeof(struct zhaoxin_uncore_box *); + } for (i = 0; i < type->num_boxes; i++) { pmus[i].func_id = setid ? i : -1; @@ -728,6 +1543,7 @@ static int __init uncore_type_init(struct zhaoxin_uncore_type *type, bool setid) struct attribute_group group; struct attribute *attrs[]; } *attr_group; + for (i = 0; type->event_descs[i].attr.attr.name; i++) ; @@ -769,25 +1585,184 @@ uncore_types_init(struct zhaoxin_uncore_type **types, bool setid) return 0; } +/* + * add a pci uncore device + */ +static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct zhaoxin_uncore_type *type; + struct zhaoxin_uncore_pmu *pmu; + struct zhaoxin_uncore_box *box; + struct zhaoxin_uncore_box *boxes[2]; + + int loop, i, j = 0; + int subnode_id, ret = 0; + + subnode_id = uncore_pcibus_to_subnodeid(pdev->bus); + if (subnode_id < 0) + return -EINVAL; + + type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data)]; + + if (!strcmp(type->name, "mc0")) + loop = 2; + else + loop = 1; + + for (i = 0; i < loop; i++) { + + type = uncore_pci_uncores[UNCORE_PCI_DEV_TYPE(id->driver_data) + j]; + + if (!type) + continue; + /* + * for performance monitoring unit with multiple boxes, + * each box has a different function id. + */ + + pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)]; + + if (WARN_ON_ONCE(pmu->boxes[subnode_id] != NULL)) + return -EINVAL; + box = uncore_alloc_box(type, NUMA_NO_NODE); + if (!box) + return -ENOMEM; + + if (pmu->func_id < 0) + pmu->func_id = pdev->devfn; + else + WARN_ON_ONCE(pmu->func_id != pdev->devfn); + + atomic_inc(&box->refcnt); + box->subnode_id = subnode_id; + box->pci_dev = pdev; + box->pmu = pmu; + uncore_box_init(box); + boxes[i] = box; + + pci_set_drvdata(pdev, boxes); + pmu->boxes[subnode_id] = box; + + if (atomic_inc_return(&pmu->activeboxes) > 1) { + if (!strcmp(type->name, "mc0")) + goto next_loop; + else + return 0; + } + /* First active box registers the pmu */ + ret = uncore_pmu_register(pmu); + if (ret) { + pci_set_drvdata(pdev, NULL); + pmu->boxes[subnode_id] = NULL; + uncore_box_exit(box); + kfree(box); + } +next_loop: + j++; + } + + return ret; +} + +static void uncore_pci_remove(struct pci_dev *pdev) +{ + struct zhaoxin_uncore_box **boxes = pci_get_drvdata(pdev); + struct zhaoxin_uncore_box *box; + struct zhaoxin_uncore_pmu *pmu; + int subnode_id; + int i = 0; + + subnode_id = uncore_pcibus_to_subnodeid(pdev->bus); + boxes = pci_get_drvdata(pdev); + +again: + box = boxes[i]; + pmu = box->pmu; + if (WARN_ON_ONCE(subnode_id != box->subnode_id)) + return; + + pci_set_drvdata(pdev, NULL); + pmu->boxes[subnode_id] = NULL; + if (atomic_dec_return(&pmu->activeboxes) == 0) + uncore_pmu_unregister(pmu); + uncore_box_exit(box); + kfree(box); + + if (!strcmp(box->pmu->type->name, "mc0")) { + i++; + goto again; + } +} + +static int __init uncore_pci_init(void) +{ + int ret; + + ret = uncore_types_init(uncore_pci_uncores, false); + if (ret) + goto errtype; + uncore_pci_driver->probe = uncore_pci_probe; + uncore_pci_driver->remove = uncore_pci_remove; + + ret = pci_register_driver(uncore_pci_driver); + if (ret) + goto errtype; + + pcidrv_registered = true; + return 0; + +errtype: + uncore_types_exit(uncore_pci_uncores); + uncore_free_pcibus_map(); + uncore_pci_uncores = empty_uncore; + return ret; +} + +static void uncore_pci_exit(void) +{ + if (pcidrv_registered) { + pcidrv_registered = false; + pci_unregister_driver(uncore_pci_driver); + uncore_types_exit(uncore_pci_uncores); + uncore_free_pcibus_map(); + } +} + static void uncore_change_type_ctx(struct zhaoxin_uncore_type *type, int old_cpu, - int new_cpu) + int new_cpu) { struct zhaoxin_uncore_pmu *pmu = type->pmus; struct zhaoxin_uncore_box *box; - int i, package; + int i, package_id, cluster_id, subnode_id; + + package_id = topology_logical_package_id(old_cpu < 0 ? new_cpu : old_cpu); + cluster_id = topology_cluster_id(old_cpu < 0 ? new_cpu : old_cpu); + subnode_id = topology_subnode_id(old_cpu < 0 ? new_cpu : old_cpu); - package = topology_logical_package_id(old_cpu < 0 ? new_cpu : old_cpu); for (i = 0; i < type->num_boxes; i++, pmu++) { - box = pmu->boxes[package]; - if (!box) - continue; + + if (boot_cpu_data.x86_model == 0x5b) { + if (!strcmp(type->name, "llc")) { + box = pmu->boxes[cluster_id]; + if (!box) + continue; + } else { + box = pmu->boxes[subnode_id]; + if (!box) + continue; + } + } else { + box = pmu->boxes[package_id]; + if (!box) + continue; + } if (old_cpu < 0) { + WARN_ON_ONCE(box->cpu != -1); box->cpu = new_cpu; continue; } - WARN_ON_ONCE(box->cpu != old_cpu); box->cpu = -1; if (new_cpu < 0) @@ -824,13 +1799,36 @@ static void uncore_box_unref(struct zhaoxin_uncore_type **types, int id) } } -static int uncore_event_cpu_offline(unsigned int cpu) +struct zhaoxin_uncore_type *uncore_msr_cluster_uncores[] = { + &yongfeng_uncore_llc_box, + NULL, +}; + +struct zhaoxin_uncore_type *uncore_msr_subnode_uncores[] = { + &yongfeng_uncore_hif_box, + &yongfeng_uncore_zzi_box, + NULL, +}; + +struct zhaoxin_uncore_type *uncore_pci_subnode_uncores[] = { + &yongfeng_uncore_mc0, + &yongfeng_uncore_mc1, + &yongfeng_uncore_pci, + &yongfeng_uncore_zpi_dll, + &yongfeng_uncore_zdi_dll, + &yongfeng_uncore_pxptrf, + NULL, +}; + +static void wudaokou_event_cpu_offline(int cpu) { int package, target; /* Check if exiting cpu is used for collecting uncore events */ + if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask)) - goto unref; + goto unref_cpu_mask; + /* Find a new cpu to collect uncore events */ target = cpumask_any_but(topology_core_cpumask(cpu), cpu); @@ -842,15 +1840,105 @@ static int uncore_event_cpu_offline(unsigned int cpu) uncore_change_context(uncore_msr_uncores, cpu, target); -unref: - /* Clear the references */ +unref_cpu_mask: + /*clear the references*/ package = topology_logical_package_id(cpu); uncore_box_unref(uncore_msr_uncores, package); +} + +static void yongfeng_event_cpu_offline(int cpu) +{ + int cluster_target, subnode_target; + int cluster_id, subnode_id; + + cluster_id = topology_cluster_id(cpu); + subnode_id = topology_subnode_id(cpu); + + /* Check if exiting cpu is used for collecting uncore events */ + + if (cpumask_test_and_clear_cpu(cpu, &uncore_cpu_cluster_mask)) { + cluster_target = cpumask_any_but(topology_cluster_core_cpumask(cpu), cpu); + if (cluster_target < nr_cpu_ids) + cpumask_set_cpu(cluster_target, &uncore_cpu_cluster_mask); + else + cluster_target = -1; + uncore_change_context(uncore_msr_cluster_uncores, cpu, cluster_target); + } else { + + uncore_box_unref(uncore_msr_cluster_uncores, cluster_id); + } + + if (cpumask_test_and_clear_cpu(cpu, &uncore_cpu_subnode_mask)) { + subnode_target = cpumask_any_but(topology_subnode_core_cpumask(cpu), cpu); + if (subnode_target < nr_cpu_ids) + cpumask_set_cpu(subnode_target, &uncore_cpu_subnode_mask); + else + subnode_target = -1; + uncore_change_context(uncore_msr_subnode_uncores, cpu, subnode_target); + uncore_change_context(uncore_pci_subnode_uncores, cpu, subnode_target); + } else { + uncore_box_unref(uncore_msr_subnode_uncores, subnode_id); + } + +} + +static int uncore_event_cpu_offline(unsigned int cpu) +{ + unsigned int x86_model; + + x86_model = boot_cpu_data.x86_model; + + if (x86_model == 0x5b) + yongfeng_event_cpu_offline(cpu); + else + wudaokou_event_cpu_offline(cpu); + + return 0; +} + +static int wudaokou_allocate_boxes(struct zhaoxin_uncore_type **types, + unsigned int id, unsigned int cpu) +{ + struct zhaoxin_uncore_box *box, *tmp; + struct zhaoxin_uncore_type *type; + struct zhaoxin_uncore_pmu *pmu; + LIST_HEAD(allocated); + int i; + + /* Try to allocate all required boxes */ + for (; *types; types++) { + type = *types; + pmu = type->pmus; + + for (i = 0; i < type->num_boxes; i++, pmu++) { + if (pmu->boxes[id]) + continue; + box = uncore_alloc_box(type, cpu_to_node(cpu)); + if (!box) + goto cleanup; + box->pmu = pmu; + box->package_id = id; + list_add(&box->active_list, &allocated); + } + } + + /* Install them in the pmus */ + list_for_each_entry_safe(box, tmp, &allocated, active_list) { + list_del_init(&box->active_list); + box->pmu->boxes[id] = box; + } return 0; + +cleanup: + list_for_each_entry_safe(box, tmp, &allocated, active_list) { + list_del_init(&box->active_list); + kfree(box); + } + return -ENOMEM; } -static int allocate_boxes(struct zhaoxin_uncore_type **types, - unsigned int package, unsigned int cpu) +static int yongfeng_allocate_boxes(struct zhaoxin_uncore_type **types, + unsigned int id, unsigned int cpu) { struct zhaoxin_uncore_box *box, *tmp; struct zhaoxin_uncore_type *type; @@ -862,21 +1950,25 @@ static int allocate_boxes(struct zhaoxin_uncore_type **types, for (; *types; types++) { type = *types; pmu = type->pmus; + for (i = 0; i < type->num_boxes; i++, pmu++) { - if (pmu->boxes[package]) + if (pmu->boxes[id]) continue; box = uncore_alloc_box(type, cpu_to_node(cpu)); if (!box) goto cleanup; box->pmu = pmu; - box->package_id = package; + if (!strcmp(type->name, "llc")) + box->cluster_id = id; + else + box->subnode_id = id; list_add(&box->active_list, &allocated); } } /* Install them in the pmus */ list_for_each_entry_safe(box, tmp, &allocated, active_list) { list_del_init(&box->active_list); - box->pmu->boxes[package] = box; + box->pmu->boxes[id] = box; } return 0; @@ -894,9 +1986,17 @@ static int uncore_box_ref(struct zhaoxin_uncore_type **types, struct zhaoxin_uncore_type *type; struct zhaoxin_uncore_pmu *pmu; struct zhaoxin_uncore_box *box; - int i, ret; + int i, ret = 0; + + int x86_model; + + x86_model = boot_cpu_data.x86_model; + + if (x86_model == 0x5b) + ret = yongfeng_allocate_boxes(types, id, cpu); + else + ret = wudaokou_allocate_boxes(types, id, cpu); - ret = allocate_boxes(types, id, cpu); if (ret) return ret; @@ -912,7 +2012,7 @@ static int uncore_box_ref(struct zhaoxin_uncore_type **types, return 0; } -static int uncore_event_cpu_online(unsigned int cpu) +static int wudaokou_event_cpu_online(unsigned int cpu) { int package, target, msr_ret; @@ -921,7 +2021,6 @@ static int uncore_event_cpu_online(unsigned int cpu) if (msr_ret) return -ENOMEM; - /* * Check if there is an online cpu in the package * which collects uncore events already. @@ -938,41 +2037,62 @@ static int uncore_event_cpu_online(unsigned int cpu) return 0; } -static int uncore_pmu_register(struct zhaoxin_uncore_pmu *pmu) +static int yongfeng_event_cpu_online(unsigned int cpu) { - int ret; + int cluster_target, subnode_target; + int cluster_id, subnode_id; + int cluster_ret, subnode_ret; - if (!pmu->type->pmu) { - pmu->pmu = (struct pmu) { - .attr_groups = pmu->type->attr_groups, - .task_ctx_nr = perf_invalid_context, - .event_init = uncore_pmu_event_init, - .add = uncore_pmu_event_add, - .del = uncore_pmu_event_del, - .start = uncore_pmu_event_start, - .stop = uncore_pmu_event_stop, - .read = uncore_pmu_event_read, - .module = THIS_MODULE, - }; - } else { - pmu->pmu = *pmu->type->pmu; - pmu->pmu.attr_groups = pmu->type->attr_groups; + cluster_id = topology_cluster_id(cpu); + subnode_id = topology_subnode_id(cpu); + + cluster_ret = uncore_box_ref(uncore_msr_cluster_uncores, cluster_id, cpu); + subnode_ret = uncore_box_ref(uncore_msr_subnode_uncores, subnode_id, cpu); + + if (cluster_ret && subnode_ret) + return -ENOMEM; + + /* + * Check if there is an online cpu in the cluster or subnode + * which collects uncore events already. + */ + + cluster_target = cpumask_any_and(&uncore_cpu_cluster_mask, topology_cluster_core_cpumask(cpu)); + subnode_target = cpumask_any_and(&uncore_cpu_subnode_mask, topology_subnode_core_cpumask(cpu)); + + if (cluster_target < nr_cpu_ids && subnode_target < nr_cpu_ids) + return 0; + + if (!cluster_ret && cluster_target >= nr_cpu_ids) { + cpumask_set_cpu(cpu, &uncore_cpu_cluster_mask); + uncore_change_context(uncore_msr_cluster_uncores, -1, cpu); } - if (pmu->type->num_boxes == 1) { - if (strlen(pmu->type->name) > 0) - sprintf(pmu->name, "uncore_%s", pmu->type->name); - else - sprintf(pmu->name, "uncore"); - } else { - sprintf(pmu->name, "uncore_%s_%d", pmu->type->name, - pmu->pmu_idx); + if (!subnode_ret && subnode_target >= nr_cpu_ids) { + cpumask_set_cpu(cpu, &uncore_cpu_subnode_mask); + uncore_change_context(uncore_msr_subnode_uncores, -1, cpu); + uncore_change_context(uncore_pci_subnode_uncores, -1, cpu); } - ret = perf_pmu_register(&pmu->pmu, pmu->name, -1); - if (!ret) - pmu->registered = true; - return ret; + return 0; +} + +static int uncore_event_cpu_online(unsigned int cpu) +{ + int x86_model; + int wudaokou_ret = 0, yongfeng_ret = 0; + + x86_model = boot_cpu_data.x86_model; + + if (x86_model == 0x5b) + yongfeng_ret = yongfeng_event_cpu_online(cpu); + else + wudaokou_ret = wudaokou_event_cpu_online(cpu); + + if (wudaokou_ret || yongfeng_ret) + return -ENOMEM; + + return 0; } static int __init type_pmu_register(struct zhaoxin_uncore_type *type) @@ -1018,31 +2138,53 @@ static int __init uncore_cpu_init(void) return ret; } - -#define CENTAUR_UNCORE_MODEL_MATCH(model, init) \ +#define CENTAUR_UNCORE_MODEL_MATCH(model, init) \ { X86_VENDOR_CENTAUR, 7, model, X86_FEATURE_ANY, (unsigned long)&init } -#define ZHAOXIN_UNCORE_MODEL_MATCH(model, init) \ +#define ZHAOXIN_UNCORE_MODEL_MATCH(model, init) \ { X86_VENDOR_ZHAOXIN, 7, model, X86_FEATURE_ANY, (unsigned long)&init } struct zhaoxin_uncore_init_fun { void (*cpu_init)(void); + int (*pci_init)(void); +}; + +void wudaokou_uncore_cpu_init(void) +{ + uncore_msr_uncores = wudaokou_msr_uncores; +} + +static const struct zhaoxin_uncore_init_fun wudaokou_uncore_init __initconst = { + .cpu_init = wudaokou_uncore_cpu_init, }; -void chx_uncore_cpu_init(void) +void yongfeng_uncore_cpu_init(void) { - uncore_msr_uncores = chx_msr_uncores; + uncore_msr_uncores = yongfeng_msr_uncores; } -static const struct zhaoxin_uncore_init_fun chx_uncore_init __initconst = { - .cpu_init = chx_uncore_cpu_init, +int yongfeng_uncore_pci_init(void) +{ + int ret = yongfeng_pci2node_map_init(); //do nothing + + if (ret) + return ret; + uncore_pci_uncores = yongfeng_pci_uncores; + uncore_pci_driver = &yongfeng_uncore_pci_driver; + return 0; +} +static const struct zhaoxin_uncore_init_fun yongfeng_uncore_init __initconst = { + .cpu_init = yongfeng_uncore_cpu_init, + .pci_init = yongfeng_uncore_pci_init, }; static const struct x86_cpu_id zhaoxin_uncore_match[] __initconst = { - CENTAUR_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_CHX001, chx_uncore_init), - CENTAUR_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_CHX002, chx_uncore_init), - ZHAOXIN_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_CHX001, chx_uncore_init), - ZHAOXIN_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_CHX002, chx_uncore_init), + CENTAUR_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_WUDAOKOU, wudaokou_uncore_init), + CENTAUR_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_LUJIAZUI, wudaokou_uncore_init), + CENTAUR_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_YONGFENG, yongfeng_uncore_init), + ZHAOXIN_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_WUDAOKOU, wudaokou_uncore_init), + ZHAOXIN_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_LUJIAZUI, wudaokou_uncore_init), + ZHAOXIN_UNCORE_MODEL_MATCH(ZHAOXIN_FAM7_YONGFENG, yongfeng_uncore_init), {}, }; @@ -1052,7 +2194,7 @@ static int __init zhaoxin_uncore_init(void) { const struct x86_cpu_id *id; struct zhaoxin_uncore_init_fun *uncore_init; - int cret = 0, ret; + int pret = 0, cret = 0, ret; id = x86_match_cpu(zhaoxin_uncore_match); @@ -1062,18 +2204,30 @@ static int __init zhaoxin_uncore_init(void) if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) return -ENODEV; + pr_info("welcome to uncore!\n"); + max_packages = topology_max_packages(); + max_clusters = topology_clusters(); + max_subnodes = topology_subnodes(); - pr_info("welcome to uncore!\n"); + get_cluster_info(); + get_subnode_info(); + zx_gen_core_map(); uncore_init = (struct zhaoxin_uncore_init_fun *)id->driver_data; + if (uncore_init->pci_init) { + pret = uncore_init->pci_init(); + if (!pret) + pret = uncore_pci_init(); + } + if (uncore_init->cpu_init) { uncore_init->cpu_init(); cret = uncore_cpu_init(); } - if (cret) + if (cret && pret) return -ENODEV; ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE, @@ -1083,10 +2237,13 @@ static int __init zhaoxin_uncore_init(void) if (ret) goto err; - pr_info("uncore init success!\n"); + pr_info("zhaoxin uncore init success.\n"); + return 0; + err: uncore_types_exit(uncore_msr_uncores); + uncore_pci_exit(); return ret; } module_init(zhaoxin_uncore_init); @@ -1095,7 +2252,7 @@ static void __exit zhaoxin_uncore_exit(void) { cpuhp_remove_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE); uncore_types_exit(uncore_msr_uncores); + uncore_pci_exit(); } module_exit(zhaoxin_uncore_exit); - MODULE_LICENSE("GPL"); diff --git a/arch/x86/events/zhaoxin/uncore.h b/arch/x86/events/zhaoxin/uncore.h index 3521123dc95d7e64c6bcb47fe63160f977b3d956..6ce7f06c239f81d7ca8ee9254d05c96165d864fa 100644 --- a/arch/x86/events/zhaoxin/uncore.h +++ b/arch/x86/events/zhaoxin/uncore.h @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0-only #include #include #include @@ -7,13 +6,12 @@ #include #include "../perf_event.h" -#define ZHAOXIN_FAM7_CHX001 0x1b -#define ZHAOXIN_FAM7_CHX002 0x3b +#define ZHAOXIN_FAM7_WUDAOKOU 0x1b +#define ZHAOXIN_FAM7_LUJIAZUI 0x3b +#define ZHAOXIN_FAM7_YONGFENG 0x5b #define UNCORE_PMU_NAME_LEN 32 #define UNCORE_PMU_HRTIMER_INTERVAL (60LL * NSEC_PER_SEC) -#define UNCORE_CHX_IMC_HRTIMER_INTERVAL (5ULL * NSEC_PER_SEC) - #define UNCORE_FIXED_EVENT 0xff #define UNCORE_PMC_IDX_MAX_GENERIC 4 @@ -22,6 +20,10 @@ #define UNCORE_PMC_IDX_MAX (UNCORE_PMC_IDX_FIXED + 1) +#define UNCORE_PCI_DEV_DATA(type, idx) ((type << 8) | idx) +#define UNCORE_PCI_DEV_TYPE(data) ((data >> 8) & 0xff) +#define UNCORE_PCI_DEV_IDX(data) (data & 0xff) + struct zhaoxin_uncore_ops; struct zhaoxin_uncore_pmu; struct zhaoxin_uncore_box; @@ -92,6 +94,8 @@ struct zhaoxin_uncore_extra_reg { struct zhaoxin_uncore_box { int pci_phys_id; int package_id; /*Package ID */ + int cluster_id; + int subnode_id; int n_active; /* number of active events */ int n_events; int cpu; /* cpu to collect events */ @@ -115,12 +119,17 @@ struct zhaoxin_uncore_box { #define UNCORE_BOX_FLAG_INITIATED 0 struct uncore_event_desc { - struct kobj_attribute attr; + struct device_attribute attr; const char *config; }; -ssize_t zx_uncore_event_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf); +struct hw_info { + u64 config_info; + u64 active_state; +}; + +ssize_t zx_uncore_event_show(struct device *dev, + struct device_attribute *attr, char *buf); #define ZHAOXIN_UNCORE_EVENT_DESC(_name, _config) \ { \ @@ -129,14 +138,14 @@ ssize_t zx_uncore_event_show(struct kobject *kobj, } #define DEFINE_UNCORE_FORMAT_ATTR(_var, _name, _format) \ -static ssize_t __uncore_##_var##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, \ +static ssize_t __uncore_##_var##_show(struct device *dev, \ + struct device_attribute *attr, \ char *page) \ { \ BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ return sprintf(page, _format "\n"); \ } \ -static struct kobj_attribute format_attr_##_var = \ +static struct device_attribute format_attr_##_var = \ __ATTR(_name, 0444, __uncore_##_var##_show, NULL) static inline bool uncore_pmc_fixed(int idx) @@ -144,36 +153,62 @@ static inline bool uncore_pmc_fixed(int idx) return idx == UNCORE_PMC_IDX_FIXED; } -static inline unsigned uncore_msr_box_offset(struct zhaoxin_uncore_box *box) +static inline unsigned int uncore_pci_box_ctl(struct zhaoxin_uncore_box *box) { - struct zhaoxin_uncore_pmu *pmu = box->pmu; + return box->pmu->type->box_ctl; +} +static inline unsigned int uncore_pci_fixed_ctl(struct zhaoxin_uncore_box *box) +{ + return box->pmu->type->fixed_ctl; +} + +static inline unsigned int uncore_pci_fixed_ctr(struct zhaoxin_uncore_box *box) +{ + return box->pmu->type->fixed_ctr; +} + +static inline +unsigned int uncore_pci_event_ctl(struct zhaoxin_uncore_box *box, int idx) +{ + return idx * 4 + box->pmu->type->event_ctl; +} + +static inline +unsigned int uncore_pci_perf_ctr(struct zhaoxin_uncore_box *box, int idx) +{ + return idx * 8 + box->pmu->type->perf_ctr; +} + +static inline unsigned int uncore_msr_box_offset(struct zhaoxin_uncore_box *box) +{ + struct zhaoxin_uncore_pmu *pmu = box->pmu; return pmu->type->msr_offsets ? pmu->type->msr_offsets[pmu->pmu_idx] : pmu->type->msr_offset * pmu->pmu_idx; } -static inline unsigned uncore_msr_box_ctl(struct zhaoxin_uncore_box *box) +static inline unsigned int uncore_msr_box_ctl(struct zhaoxin_uncore_box *box) { if (!box->pmu->type->box_ctl) return 0; return box->pmu->type->box_ctl + uncore_msr_box_offset(box); } -static inline unsigned uncore_msr_fixed_ctl(struct zhaoxin_uncore_box *box) +static inline unsigned int uncore_msr_fixed_ctl(struct zhaoxin_uncore_box *box) { if (!box->pmu->type->fixed_ctl) return 0; return box->pmu->type->fixed_ctl + uncore_msr_box_offset(box); } -static inline unsigned uncore_msr_fixed_ctr(struct zhaoxin_uncore_box *box) +static inline unsigned int uncore_msr_fixed_ctr(struct zhaoxin_uncore_box *box) { return box->pmu->type->fixed_ctr + uncore_msr_box_offset(box); } static inline -unsigned uncore_msr_event_ctl(struct zhaoxin_uncore_box *box, int idx) +unsigned int uncore_msr_event_ctl(struct zhaoxin_uncore_box *box, int idx) { return box->pmu->type->event_ctl + (box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) + @@ -181,7 +216,7 @@ unsigned uncore_msr_event_ctl(struct zhaoxin_uncore_box *box, int idx) } static inline -unsigned uncore_msr_perf_ctr(struct zhaoxin_uncore_box *box, int idx) +unsigned int uncore_msr_perf_ctr(struct zhaoxin_uncore_box *box, int idx) { return box->pmu->type->perf_ctr + (box->pmu->type->pair_ctr_ctl ? 2 * idx : idx) + @@ -189,27 +224,37 @@ unsigned uncore_msr_perf_ctr(struct zhaoxin_uncore_box *box, int idx) } static inline -unsigned uncore_fixed_ctl(struct zhaoxin_uncore_box *box) +unsigned int uncore_fixed_ctl(struct zhaoxin_uncore_box *box) { - return uncore_msr_fixed_ctl(box); + if (box->pci_dev) + return uncore_pci_fixed_ctl(box); + else + return uncore_msr_fixed_ctl(box); } static inline -unsigned uncore_fixed_ctr(struct zhaoxin_uncore_box *box) +unsigned int uncore_fixed_ctr(struct zhaoxin_uncore_box *box) { - return uncore_msr_fixed_ctr(box); + if (box->pci_dev) + return uncore_pci_fixed_ctr(box); + else + return uncore_msr_fixed_ctr(box); } static inline -unsigned uncore_event_ctl(struct zhaoxin_uncore_box *box, int idx) -{ - return uncore_msr_event_ctl(box, idx); +unsigned int uncore_event_ctl(struct zhaoxin_uncore_box *box, int idx) +{ if (box->pci_dev) + return uncore_pci_event_ctl(box, idx); + else + return uncore_msr_event_ctl(box, idx); } static inline -unsigned uncore_perf_ctr(struct zhaoxin_uncore_box *box, int idx) -{ - return uncore_msr_perf_ctr(box, idx); +unsigned int uncore_perf_ctr(struct zhaoxin_uncore_box *box, int idx) +{ if (box->pci_dev) + return uncore_pci_perf_ctr(box, idx); + else + return uncore_msr_perf_ctr(box, idx); } static inline int uncore_perf_ctr_bits(struct zhaoxin_uncore_box *box) @@ -288,7 +333,6 @@ static inline struct zhaoxin_uncore_box *uncore_event_to_box(struct perf_event * return event->pmu_private; } - static struct zhaoxin_uncore_box *uncore_pmu_to_box(struct zhaoxin_uncore_pmu *pmu, int cpu); static u64 uncore_msr_read_counter(struct zhaoxin_uncore_box *box, struct perf_event *event); @@ -305,4 +349,6 @@ uncore_get_constraint(struct zhaoxin_uncore_box *box, struct perf_event *event); void uncore_put_constraint(struct zhaoxin_uncore_box *box, struct perf_event *event); u64 uncore_shared_reg_config(struct zhaoxin_uncore_box *box, int idx); -void chx_uncore_cpu_init(void); +void wudaokou_uncore_cpu_init(void); +void yongfeng_uncore_cpu_init(void); +int yongfeng_uncore_pci_init(void);