未验证 提交 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 = {
[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 = {
......@@ -511,7 +513,7 @@ __init int zhaoxin_pmu_init(void)
unsigned int unused;
int version;
pr_info("Welcome to zhaoxin pmu!\n");
pr_info("Welcome to pmu!\n");
/*
* Check whether the Architectural PerfMon supports
......@@ -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_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("ZXC events, ");
break;
......@@ -569,7 +573,7 @@ __init int zhaoxin_pmu_init(void)
switch (boot_cpu_data.x86_model) {
case 0x1b:
memcpy(hw_cache_event_ids, zxd_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
sizeof(hw_cache_event_ids));
x86_pmu.event_constraints = zxd_event_constraints;
......@@ -580,15 +584,26 @@ __init int zhaoxin_pmu_init(void)
break;
case 0x3b:
memcpy(hw_cache_event_ids, zxe_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
sizeof(hw_cache_event_ids));
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("CNX events, ");
break;
default:
return -ENODEV;
}
......
......@@ -4,50 +4,380 @@
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 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 uncore global register */
#define WUDAOKOU_UNC_PERF_GLOBAL_CTL 0x391
#define WUDAOKOU_UNC_FIXED_CTR 0x394
#define WUDAOKOU_UNC_FIXED_CTR_CTRL 0x395
/* 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(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");
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)
{
struct uncore_event_desc *event =
......@@ -55,140 +385,527 @@ ssize_t zx_uncore_event_show(struct device *dev, struct device_attribute *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[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)
{
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 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 chx_uncore_msr_enable_event(struct zhaoxin_uncore_box *box, struct perf_event *event)
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;
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 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;
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,
};
delta = (new_count << shift) - (prev_count << shift);
delta >>= shift;
static struct attribute_group yongfeng_uncore_format_group = {
.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)
{
struct zhaoxin_uncore_box *box;
......@@ -225,7 +942,7 @@ static enum hrtimer_restart uncore_pmu_hrtimer(struct hrtimer *hrtimer)
static void uncore_pmu_start_hrtimer(struct zhaoxin_uncore_box *box)
{
hrtimer_start(&box->hrtimer, ns_to_ktime(box->hrtimer_duration),
HRTIMER_MODE_REL_PINNED);
HRTIMER_MODE_REL_PINNED);
}
static void uncore_pmu_cancel_hrtimer(struct zhaoxin_uncore_box *box)
......@@ -240,7 +957,7 @@ static void uncore_pmu_init_hrtimer(struct zhaoxin_uncore_box *box)
}
static struct zhaoxin_uncore_box *uncore_alloc_box(struct zhaoxin_uncore_type *type,
int node)
int node)
{
int i, size, numshared = type->num_shared_regs;
struct zhaoxin_uncore_box *box;
......@@ -257,6 +974,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;
......@@ -271,6 +990,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)
{
......@@ -343,7 +1100,7 @@ static int uncore_assign_events(struct zhaoxin_uncore_box *box, int assign[], in
/* slow path */
if (i != n)
ret = perf_assign_events(box->event_constraint, n,
wmin, wmax, n, assign);
wmin, wmax, n, assign);
if (!assign || ret) {
for (i = 0; i < n; i++)
......@@ -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)
{
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)
return ret;
hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
if (!(flags & PERF_EF_START))
hwc->state |= PERF_HES_ARCH;
......@@ -501,6 +1221,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)
{
......@@ -536,36 +1286,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;
......@@ -597,7 +1317,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;
......@@ -619,7 +1339,7 @@ static int uncore_pmu_event_init(struct perf_event *event)
hwc->config = 0ULL;
} else {
hwc->config = event->attr.config &
(pmu->type->event_mask | ((u64)pmu->type->event_mask_ext << 32));
(pmu->type->event_mask | ((u64)pmu->type->event_mask_ext << 32));
if (pmu->type->ops->hw_config) {
ret = pmu->type->ops->hw_config(box, event);
if (ret)
......@@ -665,26 +1385,81 @@ static void uncore_pmu_disable(struct pmu *pmu)
if (!box)
return;
if (uncore_pmu->type->ops->disable_box)
uncore_pmu->type->ops->disable_box(box);
}
if (uncore_pmu->type->ops->disable_box)
uncore_pmu->type->ops->disable_box(box);
}
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,
.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);
}
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);
ret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
if (!ret)
pmu->registered = true;
return ret;
}
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)
......@@ -695,10 +1470,19 @@ 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;
} else {
max = max_packages;
}
for (package = 0; package < max_packages; package++)
kfree(pmu->boxes[package]);
for (i = 0; i < max; i++)
kfree(pmu->boxes[i]);
kfree(pmu->boxes);
}
......@@ -735,7 +1519,15 @@ 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;
......@@ -797,25 +1589,183 @@ 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 = 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++) {
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)
......@@ -828,7 +1778,7 @@ static void uncore_change_type_ctx(struct zhaoxin_uncore_type *type, int old_cpu
}
static void uncore_change_context(struct zhaoxin_uncore_type **uncores,
int old_cpu, int new_cpu)
int old_cpu, int new_cpu)
{
for (; *uncores; uncores++)
uncore_change_type_ctx(*uncores, old_cpu, new_cpu);
......@@ -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;
/* 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);
......@@ -870,15 +1842,102 @@ 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 = 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;
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;
......@@ -890,21 +1949,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;
......@@ -917,14 +1980,22 @@ static int allocate_boxes(struct zhaoxin_uncore_type **types,
}
static int uncore_box_ref(struct zhaoxin_uncore_type **types,
int id, unsigned int cpu)
int id, unsigned int cpu)
{
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;
......@@ -940,7 +2011,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;
......@@ -949,7 +2020,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.
......@@ -966,44 +2036,64 @@ 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,
.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;
cluster_id = zx_topology_cluster_id(cpu);
subnode_id = zx_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)
......@@ -1051,32 +2141,56 @@ static int __init uncore_cpu_init(void)
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;
}
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 = {
.cpu_init = chx_uncore_cpu_init,
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 = {
X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_ZXD, &chx_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_ZXE, &chx_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, ZHAOXIN_FAM7_ZXD, &chx_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, ZHAOXIN_FAM7_ZXE, &chx_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_WUDAOKOU, &wudaokou_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, ZHAOXIN_FAM7_WUDAOKOU, &wudaokou_uncore_init),
X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, ZHAOXIN_FAM7_LUJIAZUI, &wudaokou_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);
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);
......@@ -1086,31 +2200,45 @@ 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,
"perf/x86/zhaoxin/uncore:online",
uncore_event_cpu_online,
uncore_event_cpu_offline);
pr_info("zhaoxin uncore init success!\n");
if (ret)
goto err;
pr_info("uncore init success!\n");
return 0;
err:
uncore_types_exit(uncore_msr_uncores);
uncore_pci_exit();
return ret;
}
module_init(zhaoxin_uncore_init);
......@@ -1119,5 +2247,6 @@ 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);
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Zhaoxin PMU; like Intel Architectural PerfMon-v2
*/
#include <linux/slab.h>
#include <linux/pci.h>
#include <asm/apicdef.h>
......@@ -10,13 +7,12 @@
#include <linux/perf_event.h>
#include "../perf_event.h"
#define ZHAOXIN_FAM7_ZXD 0x1b
#define ZHAOXIN_FAM7_ZXE 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
......@@ -25,6 +21,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;
......@@ -62,17 +62,17 @@ struct zhaoxin_uncore_type {
#define events_group attr_groups[2]
struct zhaoxin_uncore_ops {
void (*init_box)(struct zhaoxin_uncore_box *);
void (*exit_box)(struct zhaoxin_uncore_box *);
void (*disable_box)(struct zhaoxin_uncore_box *);
void (*enable_box)(struct zhaoxin_uncore_box *);
void (*disable_event)(struct zhaoxin_uncore_box *, struct perf_event *);
void (*enable_event)(struct zhaoxin_uncore_box *, struct perf_event *);
u64 (*read_counter)(struct zhaoxin_uncore_box *, struct perf_event *);
int (*hw_config)(struct zhaoxin_uncore_box *, struct perf_event *);
struct event_constraint *(*get_constraint)(struct zhaoxin_uncore_box *,
struct perf_event *);
void (*put_constraint)(struct zhaoxin_uncore_box *, struct perf_event *);
void (*init_box)(struct zhaoxin_uncore_box *box);
void (*exit_box)(struct zhaoxin_uncore_box *box);
void (*disable_box)(struct zhaoxin_uncore_box *box);
void (*enable_box)(struct zhaoxin_uncore_box *box);
void (*disable_event)(struct zhaoxin_uncore_box *box, struct perf_event *event);
void (*enable_event)(struct zhaoxin_uncore_box *box, struct perf_event *event);
u64 (*read_counter)(struct zhaoxin_uncore_box *box, struct perf_event *event);
int (*hw_config)(struct zhaoxin_uncore_box *box, struct perf_event *event);
struct event_constraint *(*get_constraint)(struct zhaoxin_uncore_box *box,
struct perf_event *event);
void (*put_constraint)(struct zhaoxin_uncore_box *box, struct perf_event *event);
};
struct zhaoxin_uncore_pmu {
......@@ -95,6 +95,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 */
......@@ -122,8 +124,13 @@ struct uncore_event_desc {
const char *config;
};
struct hw_info {
u64 config_info;
u64 active_state;
};
ssize_t zx_uncore_event_show(struct device *dev,
struct device_attribute *attr, char *buf);
struct device_attribute *attr, char *buf);
#define ZHAOXIN_UNCORE_EVENT_DESC(_name, _config) \
{ \
......@@ -147,6 +154,33 @@ static inline bool uncore_pmc_fixed(int idx)
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)
{
struct zhaoxin_uncore_pmu *pmu = box->pmu;
......@@ -194,25 +228,35 @@ unsigned int uncore_msr_perf_ctr(struct zhaoxin_uncore_box *box, int idx)
static inline
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 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 int uncore_event_ctl(struct zhaoxin_uncore_box *box, int idx)
{
return uncore_msr_event_ctl(box, idx);
{ if (box->pci_dev)
return uncore_pci_event_ctl(box, idx);
else
return uncore_msr_event_ctl(box, idx);
}
static inline
unsigned int uncore_perf_ctr(struct zhaoxin_uncore_box *box, int idx)
{
return uncore_msr_perf_ctr(box, 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)
......@@ -291,7 +335,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);
......@@ -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);
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.
先完成此消息的编辑!
想要评论请 注册