未验证 提交 85778f7b 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!129 [OLK-5.10] update pmu for Zhaoxin CPUs

Merge Pull Request from: @leoliu-oc 
 
Add support for more Zhaoxin processors. And improve the uncore code to provide more functions and support.

### Issue
https://gitee.com/openeuler/kernel/issues/I5SRF7

### Test
`perf list`will display more infomations.

### Knowe Issue
N/A

### Default config change
N/A 
 
Link:https://gitee.com/openeuler/kernel/pulls/129 
Reviewed-by: Jiao Fenfang <jiaofenfang@uniontech.com> 
Signed-off-by: Xie XiuQi <xiexiuqi@huawei.com> 
...@@ -28,6 +28,8 @@ static u64 zx_pmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = { ...@@ -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_REFERENCES] = 0x0515,
[PERF_COUNT_HW_CACHE_MISSES] = 0x051a, [PERF_COUNT_HW_CACHE_MISSES] = 0x051a,
[PERF_COUNT_HW_BUS_CYCLES] = 0x0083, [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 = { static struct event_constraint zxc_event_constraints[] __read_mostly = {
...@@ -511,7 +513,7 @@ __init int zhaoxin_pmu_init(void) ...@@ -511,7 +513,7 @@ __init int zhaoxin_pmu_init(void)
unsigned int unused; unsigned int unused;
int version; int version;
pr_info("Welcome to zhaoxin pmu!\n"); pr_info("Welcome to pmu!\n");
/* /*
* Check whether the Architectural PerfMon supports * Check whether the Architectural PerfMon supports
...@@ -553,6 +555,8 @@ __init int zhaoxin_pmu_init(void) ...@@ -553,6 +555,8 @@ __init int zhaoxin_pmu_init(void)
zx_pmon_event_map[PERF_COUNT_HW_CACHE_REFERENCES] = 0; 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_CACHE_MISSES] = 0;
zx_pmon_event_map[PERF_COUNT_HW_BUS_CYCLES] = 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("ZXC events, "); pr_cont("ZXC events, ");
break; break;
...@@ -584,11 +588,22 @@ __init int zhaoxin_pmu_init(void) ...@@ -584,11 +588,22 @@ __init int zhaoxin_pmu_init(void)
x86_pmu.event_constraints = zxd_event_constraints; 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, "); pr_cont("ZXE events, ");
break; 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("CNX events, ");
break;
default: default:
return -ENODEV; return -ENODEV;
} }
......
...@@ -4,50 +4,380 @@ ...@@ -4,50 +4,380 @@
static struct zhaoxin_uncore_type *empty_uncore[] = { NULL, }; static struct zhaoxin_uncore_type *empty_uncore[] = { NULL, };
static struct zhaoxin_uncore_type **uncore_msr_uncores = empty_uncore; 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 */ /* mask of cpus that collect uncore events */
static cpumask_t uncore_cpu_mask; 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 */ /* constraint for the fixed counter */
static struct event_constraint uncore_constraint_fixed = static struct event_constraint uncore_constraint_fixed =
EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL); EVENT_CONSTRAINT(~0ULL, 1 << UNCORE_PMC_IDX_FIXED, ~0ULL);
static int max_packages; static int max_packages, max_subnodes, max_clusters;
static int clusters_per_subnode;
/* CHX event control */ static int subnodes_per_die;
#define CHX_UNC_CTL_EV_SEL_MASK 0x000000ff static int dies_per_socket;
#define CHX_UNC_CTL_UMASK_MASK 0x0000ff00
#define CHX_UNC_CTL_EDGE_DET (1 << 18) /* get CPU topology register */
#define CHX_UNC_CTL_EN (1 << 22) #define BJ_GLOBAL_STATU_MSR 0x1610
#define CHX_UNC_CTL_INVERT (1 << 23) #define BJ_HDW_CONFIG_MSR 0X1628
#define CHX_UNC_CTL_CMASK_MASK 0xff000000
#define CHX_UNC_FIXED_CTR_CTL_EN (1 << 0) /* WUDAOKOU event control */
#define WUDAOKOU_UNC_CTL_EV_SEL_MASK 0x000000ff
#define CHX_UNC_RAW_EVENT_MASK (CHX_UNC_CTL_EV_SEL_MASK | \ #define WUDAOKOU_UNC_CTL_UMASK_MASK 0x0000ff00
CHX_UNC_CTL_UMASK_MASK | \ #define WUDAOKOU_UNC_CTL_EDGE_DET (1 << 18)
CHX_UNC_CTL_EDGE_DET | \ #define WUDAOKOU_UNC_CTL_EN (1 << 22)
CHX_UNC_CTL_INVERT | \ #define WUDAOKOU_UNC_CTL_INVERT (1 << 23)
CHX_UNC_CTL_CMASK_MASK) #define WUDAOKOU_UNC_CTL_CMASK_MASK 0x7000000
#define WUDAOKOU_UNC_FIXED_CTR_CTL_EN (1 << 0)
/* CHX global control register */
#define CHX_UNC_PERF_GLOBAL_CTL 0x391 #define WUDAOKOU_UNC_RAW_EVENT_MASK (WUDAOKOU_UNC_CTL_EV_SEL_MASK | \
#define CHX_UNC_FIXED_CTR 0x394 WUDAOKOU_UNC_CTL_UMASK_MASK | \
#define CHX_UNC_FIXED_CTR_CTRL 0x395 WUDAOKOU_UNC_CTL_EDGE_DET | \
WUDAOKOU_UNC_CTL_INVERT | \
/* CHX uncore global control */ WUDAOKOU_UNC_CTL_CMASK_MASK)
#define CHX_UNC_GLOBAL_CTL_EN_PC_ALL ((1ULL << 4) - 1)
#define CHX_UNC_GLOBAL_CTL_EN_FC (1ULL << 32) /* WUDAOKOU uncore global register */
#define WUDAOKOU_UNC_PERF_GLOBAL_CTL 0x391
/* CHX uncore register */ #define WUDAOKOU_UNC_FIXED_CTR 0x394
#define CHX_UNC_PERFEVTSEL0 0x3c0 #define WUDAOKOU_UNC_FIXED_CTR_CTRL 0x395
#define CHX_UNC_UNCORE_PMC0 0x3b0
/* WUDAOKOU uncore global control */
#define WUDAOKOU_UNC_GLOBAL_CTL_EN_PC_ALL ((1ULL << 4) - 1)
#define WUDAOKOU_UNC_GLOBAL_CTL_EN_FC (1ULL << 32)
/* WUDAOKOU 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(event, event, "config:0-7");
DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); 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"); DEFINE_UNCORE_FORMAT_ATTR(cmask8, cmask, "config:24-31");
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 zx_topology_cluster_id(int cpu)
{
int cluster_id;
cluster_id = per_cpu(zx_cluster_id, cpu);
return cluster_id;
}
static int zx_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 = zx_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 = zx_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) ssize_t zx_uncore_event_show(struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct uncore_event_desc *event = struct uncore_event_desc *event =
...@@ -55,140 +385,527 @@ ssize_t zx_uncore_event_show(struct device *dev, struct device_attribute *attr, ...@@ -55,140 +385,527 @@ ssize_t zx_uncore_event_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%s", event->config); return sprintf(buf, "%s", event->config);
} }
/*chx uncore support */ static struct zhaoxin_uncore_box *uncore_pmu_to_box(struct zhaoxin_uncore_pmu *pmu, int cpu)
static void chx_uncore_msr_disable_event(struct zhaoxin_uncore_box *box, struct perf_event *event)
{ {
wrmsrl(event->hw.config_base, 0); if (boot_cpu_data.x86_model == 0x5b) {
if (!strcmp(pmu->type->name, "llc"))
return pmu->boxes[zx_topology_cluster_id(cpu)];
else
return pmu->boxes[zx_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) static u64 uncore_msr_read_counter(struct zhaoxin_uncore_box *box, struct perf_event *event)
{ {
u64 count; u64 count;
WARN_ON_ONCE(box->cpu != smp_processor_id());
rdmsrl(event->hw.event_base, count); rdmsrl(event->hw.event_base, count);
return 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 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 chx_uncore_msr_enable_event(struct zhaoxin_uncore_box *box, struct perf_event *event) 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 wudaokou_uncore_msr_enable_event(struct zhaoxin_uncore_box *box,
struct perf_event *event)
{ {
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
if (hwc->idx < UNCORE_PMC_IDX_FIXED) 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 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_event.attr,
&format_attr_umask.attr, &format_attr_umask.attr,
&format_attr_edge.attr, &format_attr_edge.attr,
&format_attr_inv.attr, &format_attr_inv.attr,
&format_attr_cmask8.attr, &format_attr_cmask3.attr,
NULL, NULL,
}; };
static struct attribute_group chx_uncore_format_group = { static struct attribute_group wudaokou_uncore_format_group = {
.name = "format", .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 */ }, { /* end: all zeroes */ },
}; };
static struct zhaoxin_uncore_ops chx_uncore_msr_ops = { static struct zhaoxin_uncore_ops wudaokou_uncore_msr_ops = {
.disable_box = chx_uncore_msr_disable_box, .disable_box = wudaokou_uncore_msr_disable_box,
.enable_box = chx_uncore_msr_enable_box, .enable_box = wudaokou_uncore_msr_enable_box,
.disable_event = chx_uncore_msr_disable_event, .disable_event = wudaokou_uncore_msr_disable_event,
.enable_event = chx_uncore_msr_enable_event, .enable_event = wudaokou_uncore_msr_enable_event,
.read_counter = uncore_msr_read_counter, .read_counter = uncore_msr_read_counter,
}; };
static struct zhaoxin_uncore_type chx_uncore_box = { static struct zhaoxin_uncore_type wudaokou_uncore_box = {
.name = "", .name = "",
.num_counters = 4, .num_counters = 4,
.num_boxes = 1, .num_boxes = 1,
.perf_ctr_bits = 48, .perf_ctr_bits = 48,
.fixed_ctr_bits = 48, .fixed_ctr_bits = 48,
.event_ctl = CHX_UNC_PERFEVTSEL0, .event_ctl = WUDAOKOU_UNC_PERFEVTSEL0,
.perf_ctr = CHX_UNC_UNCORE_PMC0, .perf_ctr = WUDAOKOU_UNC_UNCORE_PMC0,
.fixed_ctr = CHX_UNC_FIXED_CTR, .fixed_ctr = WUDAOKOU_UNC_FIXED_CTR,
.fixed_ctl = CHX_UNC_FIXED_CTR_CTRL, .fixed_ctl = WUDAOKOU_UNC_FIXED_CTR_CTRL,
.event_mask = CHX_UNC_RAW_EVENT_MASK, .event_mask = WUDAOKOU_UNC_RAW_EVENT_MASK,
.event_descs = chx_uncore_events, .event_descs = wudaokou_uncore_events,
.ops = &chx_uncore_msr_ops, .ops = &wudaokou_uncore_msr_ops,
.format_group = &chx_uncore_format_group, .format_group = &wudaokou_uncore_format_group,
}; };
static struct zhaoxin_uncore_type *chx_msr_uncores[] = { static struct zhaoxin_uncore_type *wudaokou_msr_uncores[] = {
&chx_uncore_box, &wudaokou_uncore_box,
NULL, NULL,
}; };
/*WUDAOKOU 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;
/* wrmsrl(hwc->config_base, hwc->config);
* 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;
} }
static void uncore_assign_hw_event(struct zhaoxin_uncore_box *box, static void yongfeng_uncore_msr_enable_event(struct zhaoxin_uncore_box *box,
struct perf_event *event, int idx) struct perf_event *event)
{ {
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
hwc->idx = idx; wrmsrl(hwc->config_base, hwc->config | YONGFENG_PMON_CTL_EN);
hwc->last_tag = ++box->tags[idx]; }
if (uncore_pmc_fixed(hwc->idx)) { static void yongfeng_uncore_msr_disable_box(struct zhaoxin_uncore_box *box)
hwc->event_base = uncore_fixed_ctr(box); {
hwc->config_base = uncore_fixed_ctl(box); u64 config;
return; 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); static void yongfeng_uncore_msr_enable_box(struct zhaoxin_uncore_box *box)
hwc->event_base = uncore_perf_ctr(box, hwc->idx); {
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; unsigned int msr = uncore_msr_box_ctl(box);
int shift;
if (uncore_pmc_fixed(event->hw.idx)) if (msr) {
shift = 64 - uncore_fixed_ctr_bits(box); wrmsrl(msr, YONGFENG_PMON_BOX_CTL_INT);
else wrmsrl(msr, 0);
shift = 64 - uncore_perf_ctr_bits(box); }
}
/* the hrtimer might modify the previous event value */ static struct attribute *yongfeng_uncore_formats_attr[] = {
again: &format_attr_event.attr,
prev_count = local64_read(&event->hw.prev_count); &format_attr_umask.attr,
new_count = uncore_read_counter(box, event); &format_attr_edge.attr,
if (local64_xchg(&event->hw.prev_count, new_count) != prev_count) &format_attr_inv.attr,
goto again; &format_attr_cmask8.attr,
NULL,
};
delta = (new_count << shift) - (prev_count << shift); static struct attribute_group yongfeng_uncore_format_group = {
delta >>= shift; .name = "format",
.attrs = yongfeng_uncore_formats_attr,
};
local64_add(delta, &event->count); 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) static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
{ {
struct zhaoxin_uncore_box *box; struct zhaoxin_uncore_box *box;
...@@ -257,6 +974,8 @@ static struct zhaoxin_uncore_box *uncore_alloc_box(struct zhaoxin_uncore_type *t ...@@ -257,6 +974,8 @@ static struct zhaoxin_uncore_box *uncore_alloc_box(struct zhaoxin_uncore_type *t
uncore_pmu_init_hrtimer(box); uncore_pmu_init_hrtimer(box);
box->cpu = -1; box->cpu = -1;
box->package_id = -1; box->package_id = -1;
box->cluster_id = -1;
box->subnode_id = -1;
/* set default hrtimer timeout */ /* set default hrtimer timeout */
box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL; box->hrtimer_duration = UNCORE_PMU_HRTIMER_INTERVAL;
...@@ -271,6 +990,44 @@ static bool is_box_event(struct zhaoxin_uncore_box *box, struct perf_event *even ...@@ -271,6 +990,44 @@ static bool is_box_event(struct zhaoxin_uncore_box *box, struct perf_event *even
return &box->pmu->pmu == event->pmu; 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 * static struct event_constraint *
uncore_get_event_constraint(struct zhaoxin_uncore_box *box, struct perf_event *event) uncore_get_event_constraint(struct zhaoxin_uncore_box *box, struct perf_event *event)
{ {
...@@ -402,44 +1159,6 @@ static void uncore_pmu_event_stop(struct perf_event *event, int flags) ...@@ -402,44 +1159,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) static int uncore_pmu_event_add(struct perf_event *event, int flags)
{ {
struct zhaoxin_uncore_box *box = uncore_event_to_box(event); struct zhaoxin_uncore_box *box = uncore_event_to_box(event);
...@@ -455,6 +1174,7 @@ static int uncore_pmu_event_add(struct perf_event *event, int flags) ...@@ -455,6 +1174,7 @@ static int uncore_pmu_event_add(struct perf_event *event, int flags)
return ret; return ret;
hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
if (!(flags & PERF_EF_START)) if (!(flags & PERF_EF_START))
hwc->state |= PERF_HES_ARCH; hwc->state |= PERF_HES_ARCH;
...@@ -501,6 +1221,36 @@ static int uncore_pmu_event_add(struct perf_event *event, int flags) ...@@ -501,6 +1221,36 @@ static int uncore_pmu_event_add(struct perf_event *event, int flags)
return 0; 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, static int uncore_validate_group(struct zhaoxin_uncore_pmu *pmu,
struct perf_event *event) struct perf_event *event)
{ {
...@@ -536,36 +1286,6 @@ static int uncore_validate_group(struct zhaoxin_uncore_pmu *pmu, ...@@ -536,36 +1286,6 @@ static int uncore_validate_group(struct zhaoxin_uncore_pmu *pmu,
return ret; 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) static int uncore_pmu_event_init(struct perf_event *event)
{ {
struct zhaoxin_uncore_pmu *pmu; struct zhaoxin_uncore_pmu *pmu;
...@@ -597,7 +1317,7 @@ static int uncore_pmu_event_init(struct perf_event *event) ...@@ -597,7 +1317,7 @@ static int uncore_pmu_event_init(struct perf_event *event)
event->cpu = box->cpu; event->cpu = box->cpu;
event->pmu_private = box; 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.idx = -1;
event->hw.last_tag = ~0ULL; event->hw.last_tag = ~0ULL;
...@@ -669,11 +1389,26 @@ static void uncore_pmu_disable(struct pmu *pmu) ...@@ -669,11 +1389,26 @@ static void uncore_pmu_disable(struct pmu *pmu)
uncore_pmu->type->ops->disable_box(box); uncore_pmu->type->ops->disable_box(box);
} }
static ssize_t uncore_get_attr_cpumask(struct device *dev, struct device_attribute *attr, char *buf) 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); 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 DEVICE_ATTR(cpumask, S_IRUGO, uncore_get_attr_cpumask, NULL);
static struct attribute *uncore_pmu_attrs[] = { static struct attribute *uncore_pmu_attrs[] = {
...@@ -681,9 +1416,49 @@ static struct attribute *uncore_pmu_attrs[] = { ...@@ -681,9 +1416,49 @@ static struct attribute *uncore_pmu_attrs[] = {
NULL, NULL,
}; };
static const struct attribute_group uncore_pmu_attr_group = { static const struct attribute_group uncore_pmu_attr_group = {
.attrs = uncore_pmu_attrs, .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,
.pmu_enable = uncore_pmu_enable,
.pmu_disable = uncore_pmu_disable,
.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,
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
};
} 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 void uncore_pmu_unregister(struct zhaoxin_uncore_pmu *pmu) static void uncore_pmu_unregister(struct zhaoxin_uncore_pmu *pmu)
{ {
...@@ -695,10 +1470,19 @@ static void uncore_pmu_unregister(struct zhaoxin_uncore_pmu *pmu) ...@@ -695,10 +1470,19 @@ static void uncore_pmu_unregister(struct zhaoxin_uncore_pmu *pmu)
static void uncore_free_boxes(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;
} else {
max = max_packages;
}
for (package = 0; package < max_packages; package++) for (i = 0; i < max; i++)
kfree(pmu->boxes[package]); kfree(pmu->boxes[i]);
kfree(pmu->boxes); kfree(pmu->boxes);
} }
...@@ -735,7 +1519,15 @@ static int __init uncore_type_init(struct zhaoxin_uncore_type *type, bool setid) ...@@ -735,7 +1519,15 @@ static int __init uncore_type_init(struct zhaoxin_uncore_type *type, bool setid)
if (!pmus) if (!pmus)
return -ENOMEM; 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++) { for (i = 0; i < type->num_boxes; i++) {
pmus[i].func_id = setid ? i : -1; pmus[i].func_id = setid ? i : -1;
...@@ -797,25 +1589,183 @@ uncore_types_init(struct zhaoxin_uncore_type **types, bool setid) ...@@ -797,25 +1589,183 @@ uncore_types_init(struct zhaoxin_uncore_type **types, bool setid)
return 0; 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, 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_pmu *pmu = type->pmus;
struct zhaoxin_uncore_box *box; 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 = zx_topology_cluster_id(old_cpu < 0 ? new_cpu : old_cpu);
subnode_id = zx_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++) { for (i = 0; i < type->num_boxes; i++, pmu++) {
box = pmu->boxes[package];
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) if (!box)
continue; continue;
}
if (old_cpu < 0) { if (old_cpu < 0) {
WARN_ON_ONCE(box->cpu != -1); WARN_ON_ONCE(box->cpu != -1);
box->cpu = new_cpu; box->cpu = new_cpu;
continue; continue;
} }
WARN_ON_ONCE(box->cpu != old_cpu); WARN_ON_ONCE(box->cpu != old_cpu);
box->cpu = -1; box->cpu = -1;
if (new_cpu < 0) if (new_cpu < 0)
...@@ -852,13 +1802,35 @@ static void uncore_box_unref(struct zhaoxin_uncore_type **types, int id) ...@@ -852,13 +1802,35 @@ 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; int package, target;
/* Check if exiting cpu is used for collecting uncore events */ /* Check if exiting cpu is used for collecting uncore events */
if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask)) if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
goto unref; goto unref_cpu_mask;
/* Find a new cpu to collect uncore events */ /* Find a new cpu to collect uncore events */
target = cpumask_any_but(topology_core_cpumask(cpu), cpu); target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
...@@ -870,15 +1842,102 @@ static int uncore_event_cpu_offline(unsigned int cpu) ...@@ -870,15 +1842,102 @@ static int uncore_event_cpu_offline(unsigned int cpu)
uncore_change_context(uncore_msr_uncores, cpu, target); uncore_change_context(uncore_msr_uncores, cpu, target);
unref: unref_cpu_mask:
/* Clear the references */ /*clear the references*/
package = topology_logical_package_id(cpu); package = topology_logical_package_id(cpu);
uncore_box_unref(uncore_msr_uncores, package); 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 = zx_topology_cluster_id(cpu);
subnode_id = zx_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; 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, static int yongfeng_allocate_boxes(struct zhaoxin_uncore_type **types,
unsigned int package, unsigned int cpu) unsigned int id, unsigned int cpu)
{ {
struct zhaoxin_uncore_box *box, *tmp; struct zhaoxin_uncore_box *box, *tmp;
struct zhaoxin_uncore_type *type; struct zhaoxin_uncore_type *type;
...@@ -890,21 +1949,25 @@ static int allocate_boxes(struct zhaoxin_uncore_type **types, ...@@ -890,21 +1949,25 @@ static int allocate_boxes(struct zhaoxin_uncore_type **types,
for (; *types; types++) { for (; *types; types++) {
type = *types; type = *types;
pmu = type->pmus; pmu = type->pmus;
for (i = 0; i < type->num_boxes; i++, pmu++) { for (i = 0; i < type->num_boxes; i++, pmu++) {
if (pmu->boxes[package]) if (pmu->boxes[id])
continue; continue;
box = uncore_alloc_box(type, cpu_to_node(cpu)); box = uncore_alloc_box(type, cpu_to_node(cpu));
if (!box) if (!box)
goto cleanup; goto cleanup;
box->pmu = pmu; 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); list_add(&box->active_list, &allocated);
} }
} }
/* Install them in the pmus */ /* Install them in the pmus */
list_for_each_entry_safe(box, tmp, &allocated, active_list) { list_for_each_entry_safe(box, tmp, &allocated, active_list) {
list_del_init(&box->active_list); list_del_init(&box->active_list);
box->pmu->boxes[package] = box; box->pmu->boxes[id] = box;
} }
return 0; return 0;
...@@ -922,9 +1985,17 @@ static int uncore_box_ref(struct zhaoxin_uncore_type **types, ...@@ -922,9 +1985,17 @@ static int uncore_box_ref(struct zhaoxin_uncore_type **types,
struct zhaoxin_uncore_type *type; struct zhaoxin_uncore_type *type;
struct zhaoxin_uncore_pmu *pmu; struct zhaoxin_uncore_pmu *pmu;
struct zhaoxin_uncore_box *box; 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) if (ret)
return ret; return ret;
...@@ -940,7 +2011,7 @@ static int uncore_box_ref(struct zhaoxin_uncore_type **types, ...@@ -940,7 +2011,7 @@ static int uncore_box_ref(struct zhaoxin_uncore_type **types,
return 0; 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; int package, target, msr_ret;
...@@ -949,7 +2020,6 @@ static int uncore_event_cpu_online(unsigned int cpu) ...@@ -949,7 +2020,6 @@ static int uncore_event_cpu_online(unsigned int cpu)
if (msr_ret) if (msr_ret)
return -ENOMEM; return -ENOMEM;
/* /*
* Check if there is an online cpu in the package * Check if there is an online cpu in the package
* which collects uncore events already. * which collects uncore events already.
...@@ -966,44 +2036,64 @@ static int uncore_event_cpu_online(unsigned int cpu) ...@@ -966,44 +2036,64 @@ static int uncore_event_cpu_online(unsigned int cpu)
return 0; 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) { cluster_id = zx_topology_cluster_id(cpu);
pmu->pmu = (struct pmu) { subnode_id = zx_topology_subnode_id(cpu);
.attr_groups = pmu->type->attr_groups,
.task_ctx_nr = perf_invalid_context, cluster_ret = uncore_box_ref(uncore_msr_cluster_uncores, cluster_id, cpu);
.pmu_enable = uncore_pmu_enable, subnode_ret = uncore_box_ref(uncore_msr_subnode_uncores, subnode_id, cpu);
.pmu_disable = uncore_pmu_disable,
.event_init = uncore_pmu_event_init, if (cluster_ret && subnode_ret)
.add = uncore_pmu_event_add, return -ENOMEM;
.del = uncore_pmu_event_del,
.start = uncore_pmu_event_start, /*
.stop = uncore_pmu_event_stop, * Check if there is an online cpu in the cluster or subnode
.read = uncore_pmu_event_read, * which collects uncore events already.
.module = THIS_MODULE, */
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
}; cluster_target =
} else { cpumask_any_and(&uncore_cpu_cluster_mask, topology_cluster_core_cpumask(cpu));
pmu->pmu = *pmu->type->pmu; subnode_target =
pmu->pmu.attr_groups = pmu->type->attr_groups; 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 (!subnode_ret && subnode_target >= nr_cpu_ids) {
if (strlen(pmu->type->name) > 0) cpumask_set_cpu(cpu, &uncore_cpu_subnode_mask);
sprintf(pmu->name, "uncore_%s", pmu->type->name); uncore_change_context(uncore_msr_subnode_uncores, -1, cpu);
else uncore_change_context(uncore_pci_subnode_uncores, -1, cpu);
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); return 0;
if (!ret) }
pmu->registered = true;
return ret; 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) static int __init type_pmu_register(struct zhaoxin_uncore_type *type)
...@@ -1051,32 +2141,56 @@ static int __init uncore_cpu_init(void) ...@@ -1051,32 +2141,56 @@ static int __init uncore_cpu_init(void)
struct zhaoxin_uncore_init_fun { struct zhaoxin_uncore_init_fun {
void (*cpu_init)(void); 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;
}
int yongfeng_uncore_pci_init(void)
{
/* pci_bus to package mapping, do nothing */
int ret = yongfeng_pci2node_map_init();
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 chx_uncore_init __initconst = { static const struct zhaoxin_uncore_init_fun yongfeng_uncore_init __initconst = {
.cpu_init = chx_uncore_cpu_init, .cpu_init = yongfeng_uncore_cpu_init,
.pci_init = yongfeng_uncore_pci_init,
}; };
static const struct x86_cpu_id zhaoxin_uncore_match[] __initconst = { static const struct x86_cpu_id zhaoxin_uncore_match[] __initconst = {
X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_ZXD, &chx_uncore_init), X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_WUDAOKOU, &wudaokou_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_ZXE, &chx_uncore_init), X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, ZHAOXIN_FAM7_WUDAOKOU, &wudaokou_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, ZHAOXIN_FAM7_ZXD, &chx_uncore_init), X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_LUJIAZUI, &wudaokou_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, ZHAOXIN_FAM7_ZXE, &chx_uncore_init), X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, ZHAOXIN_FAM7_LUJIAZUI, &wudaokou_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_YONGFENG, &yongfeng_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, ZHAOXIN_FAM7_YONGFENG, &yongfeng_uncore_init),
{}, {},
}; };
MODULE_DEVICE_TABLE(x86cpu, zhaoxin_uncore_match); MODULE_DEVICE_TABLE(x86cpu, zhaoxin_uncore_match);
static int __init zhaoxin_uncore_init(void) static int __init zhaoxin_uncore_init(void)
{ {
const struct x86_cpu_id *id; const struct x86_cpu_id *id;
struct zhaoxin_uncore_init_fun *uncore_init; struct zhaoxin_uncore_init_fun *uncore_init;
int cret = 0, ret; int pret = 0, cret = 0, ret;
id = x86_match_cpu(zhaoxin_uncore_match); id = x86_match_cpu(zhaoxin_uncore_match);
...@@ -1086,31 +2200,45 @@ static int __init zhaoxin_uncore_init(void) ...@@ -1086,31 +2200,45 @@ static int __init zhaoxin_uncore_init(void)
if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
return -ENODEV; return -ENODEV;
pr_info("welcome to uncore.\n");
max_packages = topology_max_packages(); 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; 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) { if (uncore_init->cpu_init) {
uncore_init->cpu_init(); uncore_init->cpu_init();
cret = uncore_cpu_init(); cret = uncore_cpu_init();
} }
if (cret) if (cret && pret)
return -ENODEV; return -ENODEV;
ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE, ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE,
"perf/x86/zhaoxin/uncore:online", "perf/x86/zhaoxin/uncore:online",
uncore_event_cpu_online, uncore_event_cpu_online,
uncore_event_cpu_offline); uncore_event_cpu_offline);
pr_info("zhaoxin uncore init success!\n");
if (ret) if (ret)
goto err; goto err;
pr_info("uncore init success!\n");
return 0; return 0;
err: err:
uncore_types_exit(uncore_msr_uncores); uncore_types_exit(uncore_msr_uncores);
uncore_pci_exit();
return ret; return ret;
} }
module_init(zhaoxin_uncore_init); module_init(zhaoxin_uncore_init);
...@@ -1119,5 +2247,6 @@ static void __exit zhaoxin_uncore_exit(void) ...@@ -1119,5 +2247,6 @@ static void __exit zhaoxin_uncore_exit(void)
{ {
cpuhp_remove_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE); cpuhp_remove_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE);
uncore_types_exit(uncore_msr_uncores); uncore_types_exit(uncore_msr_uncores);
uncore_pci_exit();
} }
module_exit(zhaoxin_uncore_exit); module_exit(zhaoxin_uncore_exit);
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/*
* Zhaoxin PMU; like Intel Architectural PerfMon-v2
*/
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
...@@ -10,13 +7,12 @@ ...@@ -10,13 +7,12 @@
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include "../perf_event.h" #include "../perf_event.h"
#define ZHAOXIN_FAM7_ZXD 0x1b #define ZHAOXIN_FAM7_WUDAOKOU 0x1b
#define ZHAOXIN_FAM7_ZXE 0x3b #define ZHAOXIN_FAM7_LUJIAZUI 0x3b
#define ZHAOXIN_FAM7_YONGFENG 0x5b
#define UNCORE_PMU_NAME_LEN 32 #define UNCORE_PMU_NAME_LEN 32
#define UNCORE_PMU_HRTIMER_INTERVAL (60LL * NSEC_PER_SEC) #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_FIXED_EVENT 0xff
#define UNCORE_PMC_IDX_MAX_GENERIC 4 #define UNCORE_PMC_IDX_MAX_GENERIC 4
...@@ -25,6 +21,10 @@ ...@@ -25,6 +21,10 @@
#define UNCORE_PMC_IDX_MAX (UNCORE_PMC_IDX_FIXED + 1) #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_ops;
struct zhaoxin_uncore_pmu; struct zhaoxin_uncore_pmu;
struct zhaoxin_uncore_box; struct zhaoxin_uncore_box;
...@@ -62,17 +62,17 @@ struct zhaoxin_uncore_type { ...@@ -62,17 +62,17 @@ struct zhaoxin_uncore_type {
#define events_group attr_groups[2] #define events_group attr_groups[2]
struct zhaoxin_uncore_ops { struct zhaoxin_uncore_ops {
void (*init_box)(struct zhaoxin_uncore_box *); void (*init_box)(struct zhaoxin_uncore_box *box);
void (*exit_box)(struct zhaoxin_uncore_box *); void (*exit_box)(struct zhaoxin_uncore_box *box);
void (*disable_box)(struct zhaoxin_uncore_box *); void (*disable_box)(struct zhaoxin_uncore_box *box);
void (*enable_box)(struct zhaoxin_uncore_box *); void (*enable_box)(struct zhaoxin_uncore_box *box);
void (*disable_event)(struct zhaoxin_uncore_box *, struct perf_event *); void (*disable_event)(struct zhaoxin_uncore_box *box, struct perf_event *event);
void (*enable_event)(struct zhaoxin_uncore_box *, struct perf_event *); void (*enable_event)(struct zhaoxin_uncore_box *box, struct perf_event *event);
u64 (*read_counter)(struct zhaoxin_uncore_box *, struct perf_event *); u64 (*read_counter)(struct zhaoxin_uncore_box *box, struct perf_event *event);
int (*hw_config)(struct zhaoxin_uncore_box *, struct perf_event *); int (*hw_config)(struct zhaoxin_uncore_box *box, struct perf_event *event);
struct event_constraint *(*get_constraint)(struct zhaoxin_uncore_box *, struct event_constraint *(*get_constraint)(struct zhaoxin_uncore_box *box,
struct perf_event *); struct perf_event *event);
void (*put_constraint)(struct zhaoxin_uncore_box *, struct perf_event *); void (*put_constraint)(struct zhaoxin_uncore_box *box, struct perf_event *event);
}; };
struct zhaoxin_uncore_pmu { struct zhaoxin_uncore_pmu {
...@@ -95,6 +95,8 @@ struct zhaoxin_uncore_extra_reg { ...@@ -95,6 +95,8 @@ struct zhaoxin_uncore_extra_reg {
struct zhaoxin_uncore_box { struct zhaoxin_uncore_box {
int pci_phys_id; int pci_phys_id;
int package_id; /*Package ID */ int package_id; /*Package ID */
int cluster_id;
int subnode_id;
int n_active; /* number of active events */ int n_active; /* number of active events */
int n_events; int n_events;
int cpu; /* cpu to collect events */ int cpu; /* cpu to collect events */
...@@ -122,6 +124,11 @@ struct uncore_event_desc { ...@@ -122,6 +124,11 @@ struct uncore_event_desc {
const char *config; const char *config;
}; };
struct hw_info {
u64 config_info;
u64 active_state;
};
ssize_t zx_uncore_event_show(struct device *dev, ssize_t zx_uncore_event_show(struct device *dev,
struct device_attribute *attr, char *buf); struct device_attribute *attr, char *buf);
...@@ -147,6 +154,33 @@ static inline bool uncore_pmc_fixed(int idx) ...@@ -147,6 +154,33 @@ static inline bool uncore_pmc_fixed(int idx)
return idx == UNCORE_PMC_IDX_FIXED; return idx == UNCORE_PMC_IDX_FIXED;
} }
static inline unsigned int uncore_pci_box_ctl(struct zhaoxin_uncore_box *box)
{
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) static inline unsigned int uncore_msr_box_offset(struct zhaoxin_uncore_box *box)
{ {
struct zhaoxin_uncore_pmu *pmu = box->pmu; struct zhaoxin_uncore_pmu *pmu = box->pmu;
...@@ -194,24 +228,34 @@ unsigned int uncore_msr_perf_ctr(struct zhaoxin_uncore_box *box, int idx) ...@@ -194,24 +228,34 @@ unsigned int uncore_msr_perf_ctr(struct zhaoxin_uncore_box *box, int idx)
static inline static inline
unsigned int uncore_fixed_ctl(struct zhaoxin_uncore_box *box) unsigned int uncore_fixed_ctl(struct zhaoxin_uncore_box *box)
{ {
if (box->pci_dev)
return uncore_pci_fixed_ctl(box);
else
return uncore_msr_fixed_ctl(box); return uncore_msr_fixed_ctl(box);
} }
static inline static inline
unsigned int uncore_fixed_ctr(struct zhaoxin_uncore_box *box) unsigned int uncore_fixed_ctr(struct zhaoxin_uncore_box *box)
{ {
if (box->pci_dev)
return uncore_pci_fixed_ctr(box);
else
return uncore_msr_fixed_ctr(box); return uncore_msr_fixed_ctr(box);
} }
static inline static inline
unsigned int uncore_event_ctl(struct zhaoxin_uncore_box *box, int 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); return uncore_msr_event_ctl(box, idx);
} }
static inline static inline
unsigned int uncore_perf_ctr(struct zhaoxin_uncore_box *box, int 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); return uncore_msr_perf_ctr(box, idx);
} }
...@@ -291,7 +335,6 @@ static inline struct zhaoxin_uncore_box *uncore_event_to_box(struct perf_event * ...@@ -291,7 +335,6 @@ static inline struct zhaoxin_uncore_box *uncore_event_to_box(struct perf_event *
return event->pmu_private; return event->pmu_private;
} }
static struct zhaoxin_uncore_box *uncore_pmu_to_box(struct zhaoxin_uncore_pmu *pmu, int cpu); 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); static u64 uncore_msr_read_counter(struct zhaoxin_uncore_box *box, struct perf_event *event);
...@@ -308,4 +351,6 @@ uncore_get_constraint(struct zhaoxin_uncore_box *box, struct perf_event *event); ...@@ -308,4 +351,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); 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); 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);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册