LCOV - code coverage report
Current view: top level - arch/x86/events/amd - uncore.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 4 268 1.5 %
Date: 2022-04-01 13:59:58 Functions: 1 24 4.2 %
Branches: 2 144 1.4 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Copyright (C) 2013 Advanced Micro Devices, Inc.
       4                 :            :  *
       5                 :            :  * Author: Jacob Shin <jacob.shin@amd.com>
       6                 :            :  */
       7                 :            : 
       8                 :            : #include <linux/perf_event.h>
       9                 :            : #include <linux/percpu.h>
      10                 :            : #include <linux/types.h>
      11                 :            : #include <linux/slab.h>
      12                 :            : #include <linux/init.h>
      13                 :            : #include <linux/cpu.h>
      14                 :            : #include <linux/cpumask.h>
      15                 :            : 
      16                 :            : #include <asm/cpufeature.h>
      17                 :            : #include <asm/perf_event.h>
      18                 :            : #include <asm/msr.h>
      19                 :            : #include <asm/smp.h>
      20                 :            : 
      21                 :            : #define NUM_COUNTERS_NB         4
      22                 :            : #define NUM_COUNTERS_L2         4
      23                 :            : #define NUM_COUNTERS_L3         6
      24                 :            : #define MAX_COUNTERS            6
      25                 :            : 
      26                 :            : #define RDPMC_BASE_NB           6
      27                 :            : #define RDPMC_BASE_LLC          10
      28                 :            : 
      29                 :            : #define COUNTER_SHIFT           16
      30                 :            : 
      31                 :            : #undef pr_fmt
      32                 :            : #define pr_fmt(fmt)     "amd_uncore: " fmt
      33                 :            : 
      34                 :            : static int num_counters_llc;
      35                 :            : static int num_counters_nb;
      36                 :            : static bool l3_mask;
      37                 :            : 
      38                 :            : static HLIST_HEAD(uncore_unused_list);
      39                 :            : 
      40                 :            : struct amd_uncore {
      41                 :            :         int id;
      42                 :            :         int refcnt;
      43                 :            :         int cpu;
      44                 :            :         int num_counters;
      45                 :            :         int rdpmc_base;
      46                 :            :         u32 msr_base;
      47                 :            :         cpumask_t *active_mask;
      48                 :            :         struct pmu *pmu;
      49                 :            :         struct perf_event *events[MAX_COUNTERS];
      50                 :            :         struct hlist_node node;
      51                 :            : };
      52                 :            : 
      53                 :            : static struct amd_uncore * __percpu *amd_uncore_nb;
      54                 :            : static struct amd_uncore * __percpu *amd_uncore_llc;
      55                 :            : 
      56                 :            : static struct pmu amd_nb_pmu;
      57                 :            : static struct pmu amd_llc_pmu;
      58                 :            : 
      59                 :            : static cpumask_t amd_nb_active_mask;
      60                 :            : static cpumask_t amd_llc_active_mask;
      61                 :            : 
      62                 :          0 : static bool is_nb_event(struct perf_event *event)
      63                 :            : {
      64                 :          0 :         return event->pmu->type == amd_nb_pmu.type;
      65                 :            : }
      66                 :            : 
      67                 :          0 : static bool is_llc_event(struct perf_event *event)
      68                 :            : {
      69                 :          0 :         return event->pmu->type == amd_llc_pmu.type;
      70                 :            : }
      71                 :            : 
      72                 :          0 : static struct amd_uncore *event_to_amd_uncore(struct perf_event *event)
      73                 :            : {
      74   [ #  #  #  # ]:          0 :         if (is_nb_event(event) && amd_uncore_nb)
      75                 :          0 :                 return *per_cpu_ptr(amd_uncore_nb, event->cpu);
      76   [ #  #  #  # ]:          0 :         else if (is_llc_event(event) && amd_uncore_llc)
      77                 :          0 :                 return *per_cpu_ptr(amd_uncore_llc, event->cpu);
      78                 :            : 
      79                 :            :         return NULL;
      80                 :            : }
      81                 :            : 
      82                 :          0 : static void amd_uncore_read(struct perf_event *event)
      83                 :            : {
      84                 :          0 :         struct hw_perf_event *hwc = &event->hw;
      85                 :          0 :         u64 prev, new;
      86                 :          0 :         s64 delta;
      87                 :            : 
      88                 :            :         /*
      89                 :            :          * since we do not enable counter overflow interrupts,
      90                 :            :          * we do not have to worry about prev_count changing on us
      91                 :            :          */
      92                 :            : 
      93                 :          0 :         prev = local64_read(&hwc->prev_count);
      94                 :          0 :         rdpmcl(hwc->event_base_rdpmc, new);
      95                 :          0 :         local64_set(&hwc->prev_count, new);
      96                 :          0 :         delta = (new << COUNTER_SHIFT) - (prev << COUNTER_SHIFT);
      97                 :          0 :         delta >>= COUNTER_SHIFT;
      98                 :          0 :         local64_add(delta, &event->count);
      99                 :          0 : }
     100                 :            : 
     101                 :          0 : static void amd_uncore_start(struct perf_event *event, int flags)
     102                 :            : {
     103                 :          0 :         struct hw_perf_event *hwc = &event->hw;
     104                 :            : 
     105         [ #  # ]:          0 :         if (flags & PERF_EF_RELOAD)
     106                 :          0 :                 wrmsrl(hwc->event_base, (u64)local64_read(&hwc->prev_count));
     107                 :            : 
     108                 :          0 :         hwc->state = 0;
     109                 :          0 :         wrmsrl(hwc->config_base, (hwc->config | ARCH_PERFMON_EVENTSEL_ENABLE));
     110                 :          0 :         perf_event_update_userpage(event);
     111                 :          0 : }
     112                 :            : 
     113                 :          0 : static void amd_uncore_stop(struct perf_event *event, int flags)
     114                 :            : {
     115                 :          0 :         struct hw_perf_event *hwc = &event->hw;
     116                 :            : 
     117                 :          0 :         wrmsrl(hwc->config_base, hwc->config);
     118                 :          0 :         hwc->state |= PERF_HES_STOPPED;
     119                 :            : 
     120   [ #  #  #  # ]:          0 :         if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
     121                 :          0 :                 amd_uncore_read(event);
     122                 :          0 :                 hwc->state |= PERF_HES_UPTODATE;
     123                 :            :         }
     124                 :          0 : }
     125                 :            : 
     126                 :          0 : static int amd_uncore_add(struct perf_event *event, int flags)
     127                 :            : {
     128                 :          0 :         int i;
     129                 :          0 :         struct amd_uncore *uncore = event_to_amd_uncore(event);
     130                 :          0 :         struct hw_perf_event *hwc = &event->hw;
     131                 :            : 
     132                 :            :         /* are we already assigned? */
     133   [ #  #  #  # ]:          0 :         if (hwc->idx != -1 && uncore->events[hwc->idx] == event)
     134                 :          0 :                 goto out;
     135                 :            : 
     136         [ #  # ]:          0 :         for (i = 0; i < uncore->num_counters; i++) {
     137         [ #  # ]:          0 :                 if (uncore->events[i] == event) {
     138                 :          0 :                         hwc->idx = i;
     139                 :          0 :                         goto out;
     140                 :            :                 }
     141                 :            :         }
     142                 :            : 
     143                 :            :         /* if not, take the first available counter */
     144                 :          0 :         hwc->idx = -1;
     145         [ #  # ]:          0 :         for (i = 0; i < uncore->num_counters; i++) {
     146         [ #  # ]:          0 :                 if (cmpxchg(&uncore->events[i], NULL, event) == NULL) {
     147                 :          0 :                         hwc->idx = i;
     148                 :          0 :                         break;
     149                 :            :                 }
     150                 :            :         }
     151                 :            : 
     152                 :          0 : out:
     153         [ #  # ]:          0 :         if (hwc->idx == -1)
     154                 :            :                 return -EBUSY;
     155                 :            : 
     156                 :          0 :         hwc->config_base = uncore->msr_base + (2 * hwc->idx);
     157                 :          0 :         hwc->event_base = uncore->msr_base + 1 + (2 * hwc->idx);
     158                 :          0 :         hwc->event_base_rdpmc = uncore->rdpmc_base + hwc->idx;
     159                 :          0 :         hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
     160                 :            : 
     161         [ #  # ]:          0 :         if (flags & PERF_EF_START)
     162                 :          0 :                 amd_uncore_start(event, PERF_EF_RELOAD);
     163                 :            : 
     164                 :            :         return 0;
     165                 :            : }
     166                 :            : 
     167                 :          0 : static void amd_uncore_del(struct perf_event *event, int flags)
     168                 :            : {
     169                 :          0 :         int i;
     170                 :          0 :         struct amd_uncore *uncore = event_to_amd_uncore(event);
     171                 :          0 :         struct hw_perf_event *hwc = &event->hw;
     172                 :            : 
     173                 :          0 :         amd_uncore_stop(event, PERF_EF_UPDATE);
     174                 :            : 
     175         [ #  # ]:          0 :         for (i = 0; i < uncore->num_counters; i++) {
     176         [ #  # ]:          0 :                 if (cmpxchg(&uncore->events[i], event, NULL) == event)
     177                 :            :                         break;
     178                 :            :         }
     179                 :            : 
     180                 :          0 :         hwc->idx = -1;
     181                 :          0 : }
     182                 :            : 
     183                 :          0 : static int amd_uncore_event_init(struct perf_event *event)
     184                 :            : {
     185                 :          0 :         struct amd_uncore *uncore;
     186                 :          0 :         struct hw_perf_event *hwc = &event->hw;
     187                 :            : 
     188         [ #  # ]:          0 :         if (event->attr.type != event->pmu->type)
     189                 :            :                 return -ENOENT;
     190                 :            : 
     191                 :            :         /*
     192                 :            :          * NB and Last level cache counters (MSRs) are shared across all cores
     193                 :            :          * that share the same NB / Last level cache.  On family 16h and below,
     194                 :            :          * Interrupts can be directed to a single target core, however, event
     195                 :            :          * counts generated by processes running on other cores cannot be masked
     196                 :            :          * out. So we do not support sampling and per-thread events via
     197                 :            :          * CAP_NO_INTERRUPT, and we do not enable counter overflow interrupts:
     198                 :            :          */
     199                 :          0 :         hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB;
     200                 :          0 :         hwc->idx = -1;
     201                 :            : 
     202         [ #  # ]:          0 :         if (event->cpu < 0)
     203                 :            :                 return -EINVAL;
     204                 :            : 
     205                 :            :         /*
     206                 :            :          * SliceMask and ThreadMask need to be set for certain L3 events in
     207                 :            :          * Family 17h. For other events, the two fields do not affect the count.
     208                 :            :          */
     209   [ #  #  #  # ]:          0 :         if (l3_mask && is_llc_event(event)) {
     210                 :          0 :                 int thread = 2 * (cpu_data(event->cpu).cpu_core_id % 4);
     211                 :            : 
     212         [ #  # ]:          0 :                 if (smp_num_siblings > 1)
     213                 :          0 :                         thread += cpu_data(event->cpu).apicid & 1;
     214                 :            : 
     215                 :          0 :                 hwc->config |= (1ULL << (AMD64_L3_THREAD_SHIFT + thread) &
     216                 :            :                                 AMD64_L3_THREAD_MASK) | AMD64_L3_SLICE_MASK;
     217                 :            :         }
     218                 :            : 
     219                 :          0 :         uncore = event_to_amd_uncore(event);
     220         [ #  # ]:          0 :         if (!uncore)
     221                 :            :                 return -ENODEV;
     222                 :            : 
     223                 :            :         /*
     224                 :            :          * since request can come in to any of the shared cores, we will remap
     225                 :            :          * to a single common cpu.
     226                 :            :          */
     227                 :          0 :         event->cpu = uncore->cpu;
     228                 :            : 
     229                 :          0 :         return 0;
     230                 :            : }
     231                 :            : 
     232                 :          0 : static ssize_t amd_uncore_attr_show_cpumask(struct device *dev,
     233                 :            :                                             struct device_attribute *attr,
     234                 :            :                                             char *buf)
     235                 :            : {
     236                 :          0 :         cpumask_t *active_mask;
     237         [ #  # ]:          0 :         struct pmu *pmu = dev_get_drvdata(dev);
     238                 :            : 
     239         [ #  # ]:          0 :         if (pmu->type == amd_nb_pmu.type)
     240                 :            :                 active_mask = &amd_nb_active_mask;
     241         [ #  # ]:          0 :         else if (pmu->type == amd_llc_pmu.type)
     242                 :            :                 active_mask = &amd_llc_active_mask;
     243                 :            :         else
     244                 :            :                 return 0;
     245                 :            : 
     246                 :          0 :         return cpumap_print_to_pagebuf(true, buf, active_mask);
     247                 :            : }
     248                 :            : static DEVICE_ATTR(cpumask, S_IRUGO, amd_uncore_attr_show_cpumask, NULL);
     249                 :            : 
     250                 :            : static struct attribute *amd_uncore_attrs[] = {
     251                 :            :         &dev_attr_cpumask.attr,
     252                 :            :         NULL,
     253                 :            : };
     254                 :            : 
     255                 :            : static struct attribute_group amd_uncore_attr_group = {
     256                 :            :         .attrs = amd_uncore_attrs,
     257                 :            : };
     258                 :            : 
     259                 :            : /*
     260                 :            :  * Similar to PMU_FORMAT_ATTR but allowing for format_attr to be assigned based
     261                 :            :  * on family
     262                 :            :  */
     263                 :            : #define AMD_FORMAT_ATTR(_dev, _name, _format)                                \
     264                 :            : static ssize_t                                                               \
     265                 :            : _dev##_show##_name(struct device *dev,                                       \
     266                 :            :                 struct device_attribute *attr,                               \
     267                 :            :                 char *page)                                                  \
     268                 :            : {                                                                            \
     269                 :            :         BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE);                       \
     270                 :            :         return sprintf(page, _format "\n");                                \
     271                 :            : }                                                                            \
     272                 :            : static struct device_attribute format_attr_##_dev##_name = __ATTR_RO(_dev);
     273                 :            : 
     274                 :            : /* Used for each uncore counter type */
     275                 :            : #define AMD_ATTRIBUTE(_name)                                                 \
     276                 :            : static struct attribute *amd_uncore_format_attr_##_name[] = {                \
     277                 :            :         &format_attr_event_##_name.attr,                                 \
     278                 :            :         &format_attr_umask.attr,                                         \
     279                 :            :         NULL,                                                                \
     280                 :            : };                                                                           \
     281                 :            : static struct attribute_group amd_uncore_format_group_##_name = {            \
     282                 :            :         .name = "format",                                                  \
     283                 :            :         .attrs = amd_uncore_format_attr_##_name,                             \
     284                 :            : };                                                                           \
     285                 :            : static const struct attribute_group *amd_uncore_attr_groups_##_name[] = {    \
     286                 :            :         &amd_uncore_attr_group,                                                  \
     287                 :            :         &amd_uncore_format_group_##_name,                                \
     288                 :            :         NULL,                                                                \
     289                 :            : };
     290                 :            : 
     291                 :          0 : AMD_FORMAT_ATTR(event, , "config:0-7,32-35");
     292                 :          0 : AMD_FORMAT_ATTR(umask, , "config:8-15");
     293                 :          0 : AMD_FORMAT_ATTR(event, _df, "config:0-7,32-35,59-60");
     294                 :          0 : AMD_FORMAT_ATTR(event, _l3, "config:0-7");
     295                 :            : AMD_ATTRIBUTE(df);
     296                 :            : AMD_ATTRIBUTE(l3);
     297                 :            : 
     298                 :            : static struct pmu amd_nb_pmu = {
     299                 :            :         .task_ctx_nr    = perf_invalid_context,
     300                 :            :         .event_init     = amd_uncore_event_init,
     301                 :            :         .add            = amd_uncore_add,
     302                 :            :         .del            = amd_uncore_del,
     303                 :            :         .start          = amd_uncore_start,
     304                 :            :         .stop           = amd_uncore_stop,
     305                 :            :         .read           = amd_uncore_read,
     306                 :            :         .capabilities   = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT,
     307                 :            : };
     308                 :            : 
     309                 :            : static struct pmu amd_llc_pmu = {
     310                 :            :         .task_ctx_nr    = perf_invalid_context,
     311                 :            :         .event_init     = amd_uncore_event_init,
     312                 :            :         .add            = amd_uncore_add,
     313                 :            :         .del            = amd_uncore_del,
     314                 :            :         .start          = amd_uncore_start,
     315                 :            :         .stop           = amd_uncore_stop,
     316                 :            :         .read           = amd_uncore_read,
     317                 :            :         .capabilities   = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT,
     318                 :            : };
     319                 :            : 
     320                 :          0 : static struct amd_uncore *amd_uncore_alloc(unsigned int cpu)
     321                 :            : {
     322                 :          0 :         return kzalloc_node(sizeof(struct amd_uncore), GFP_KERNEL,
     323                 :            :                         cpu_to_node(cpu));
     324                 :            : }
     325                 :            : 
     326                 :          0 : static int amd_uncore_cpu_up_prepare(unsigned int cpu)
     327                 :            : {
     328                 :          0 :         struct amd_uncore *uncore_nb = NULL, *uncore_llc;
     329                 :            : 
     330         [ #  # ]:          0 :         if (amd_uncore_nb) {
     331                 :          0 :                 uncore_nb = amd_uncore_alloc(cpu);
     332         [ #  # ]:          0 :                 if (!uncore_nb)
     333                 :          0 :                         goto fail;
     334                 :          0 :                 uncore_nb->cpu = cpu;
     335                 :          0 :                 uncore_nb->num_counters = num_counters_nb;
     336                 :          0 :                 uncore_nb->rdpmc_base = RDPMC_BASE_NB;
     337                 :          0 :                 uncore_nb->msr_base = MSR_F15H_NB_PERF_CTL;
     338                 :          0 :                 uncore_nb->active_mask = &amd_nb_active_mask;
     339                 :          0 :                 uncore_nb->pmu = &amd_nb_pmu;
     340                 :          0 :                 uncore_nb->id = -1;
     341                 :          0 :                 *per_cpu_ptr(amd_uncore_nb, cpu) = uncore_nb;
     342                 :            :         }
     343                 :            : 
     344         [ #  # ]:          0 :         if (amd_uncore_llc) {
     345                 :          0 :                 uncore_llc = amd_uncore_alloc(cpu);
     346         [ #  # ]:          0 :                 if (!uncore_llc)
     347                 :          0 :                         goto fail;
     348                 :          0 :                 uncore_llc->cpu = cpu;
     349                 :          0 :                 uncore_llc->num_counters = num_counters_llc;
     350                 :          0 :                 uncore_llc->rdpmc_base = RDPMC_BASE_LLC;
     351                 :          0 :                 uncore_llc->msr_base = MSR_F16H_L2I_PERF_CTL;
     352                 :          0 :                 uncore_llc->active_mask = &amd_llc_active_mask;
     353                 :          0 :                 uncore_llc->pmu = &amd_llc_pmu;
     354                 :          0 :                 uncore_llc->id = -1;
     355                 :          0 :                 *per_cpu_ptr(amd_uncore_llc, cpu) = uncore_llc;
     356                 :            :         }
     357                 :            : 
     358                 :            :         return 0;
     359                 :            : 
     360                 :          0 : fail:
     361         [ #  # ]:          0 :         if (amd_uncore_nb)
     362                 :          0 :                 *per_cpu_ptr(amd_uncore_nb, cpu) = NULL;
     363                 :          0 :         kfree(uncore_nb);
     364                 :          0 :         return -ENOMEM;
     365                 :            : }
     366                 :            : 
     367                 :            : static struct amd_uncore *
     368                 :          0 : amd_uncore_find_online_sibling(struct amd_uncore *this,
     369                 :            :                                struct amd_uncore * __percpu *uncores)
     370                 :            : {
     371                 :          0 :         unsigned int cpu;
     372                 :          0 :         struct amd_uncore *that;
     373                 :            : 
     374         [ #  # ]:          0 :         for_each_online_cpu(cpu) {
     375                 :          0 :                 that = *per_cpu_ptr(uncores, cpu);
     376                 :            : 
     377         [ #  # ]:          0 :                 if (!that)
     378                 :          0 :                         continue;
     379                 :            : 
     380         [ #  # ]:          0 :                 if (this == that)
     381                 :          0 :                         continue;
     382                 :            : 
     383         [ #  # ]:          0 :                 if (this->id == that->id) {
     384         [ #  # ]:          0 :                         hlist_add_head(&this->node, &uncore_unused_list);
     385                 :          0 :                         this = that;
     386                 :          0 :                         break;
     387                 :            :                 }
     388                 :            :         }
     389                 :            : 
     390                 :          0 :         this->refcnt++;
     391                 :          0 :         return this;
     392                 :            : }
     393                 :            : 
     394                 :          0 : static int amd_uncore_cpu_starting(unsigned int cpu)
     395                 :            : {
     396                 :          0 :         unsigned int eax, ebx, ecx, edx;
     397                 :          0 :         struct amd_uncore *uncore;
     398                 :            : 
     399         [ #  # ]:          0 :         if (amd_uncore_nb) {
     400                 :          0 :                 uncore = *per_cpu_ptr(amd_uncore_nb, cpu);
     401                 :          0 :                 cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
     402                 :          0 :                 uncore->id = ecx & 0xff;
     403                 :            : 
     404                 :          0 :                 uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_nb);
     405                 :          0 :                 *per_cpu_ptr(amd_uncore_nb, cpu) = uncore;
     406                 :            :         }
     407                 :            : 
     408         [ #  # ]:          0 :         if (amd_uncore_llc) {
     409                 :          0 :                 uncore = *per_cpu_ptr(amd_uncore_llc, cpu);
     410                 :          0 :                 uncore->id = per_cpu(cpu_llc_id, cpu);
     411                 :            : 
     412                 :          0 :                 uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_llc);
     413                 :          0 :                 *per_cpu_ptr(amd_uncore_llc, cpu) = uncore;
     414                 :            :         }
     415                 :            : 
     416                 :          0 :         return 0;
     417                 :            : }
     418                 :            : 
     419                 :          0 : static void uncore_clean_online(void)
     420                 :            : {
     421                 :          0 :         struct amd_uncore *uncore;
     422                 :          0 :         struct hlist_node *n;
     423                 :            : 
     424   [ #  #  #  #  :          0 :         hlist_for_each_entry_safe(uncore, n, &uncore_unused_list, node) {
                   #  # ]
     425         [ #  # ]:          0 :                 hlist_del(&uncore->node);
     426                 :          0 :                 kfree(uncore);
     427                 :            :         }
     428                 :          0 : }
     429                 :            : 
     430                 :          0 : static void uncore_online(unsigned int cpu,
     431                 :            :                           struct amd_uncore * __percpu *uncores)
     432                 :            : {
     433                 :          0 :         struct amd_uncore *uncore = *per_cpu_ptr(uncores, cpu);
     434                 :            : 
     435                 :          0 :         uncore_clean_online();
     436                 :            : 
     437         [ #  # ]:          0 :         if (cpu == uncore->cpu)
     438                 :          0 :                 cpumask_set_cpu(cpu, uncore->active_mask);
     439                 :          0 : }
     440                 :            : 
     441                 :          0 : static int amd_uncore_cpu_online(unsigned int cpu)
     442                 :            : {
     443         [ #  # ]:          0 :         if (amd_uncore_nb)
     444                 :          0 :                 uncore_online(cpu, amd_uncore_nb);
     445                 :            : 
     446         [ #  # ]:          0 :         if (amd_uncore_llc)
     447                 :          0 :                 uncore_online(cpu, amd_uncore_llc);
     448                 :            : 
     449                 :          0 :         return 0;
     450                 :            : }
     451                 :            : 
     452                 :          0 : static void uncore_down_prepare(unsigned int cpu,
     453                 :            :                                 struct amd_uncore * __percpu *uncores)
     454                 :            : {
     455                 :          0 :         unsigned int i;
     456                 :          0 :         struct amd_uncore *this = *per_cpu_ptr(uncores, cpu);
     457                 :            : 
     458         [ #  # ]:          0 :         if (this->cpu != cpu)
     459                 :            :                 return;
     460                 :            : 
     461                 :            :         /* this cpu is going down, migrate to a shared sibling if possible */
     462         [ #  # ]:          0 :         for_each_online_cpu(i) {
     463                 :          0 :                 struct amd_uncore *that = *per_cpu_ptr(uncores, i);
     464                 :            : 
     465         [ #  # ]:          0 :                 if (cpu == i)
     466                 :          0 :                         continue;
     467                 :            : 
     468         [ #  # ]:          0 :                 if (this == that) {
     469                 :          0 :                         perf_pmu_migrate_context(this->pmu, cpu, i);
     470                 :          0 :                         cpumask_clear_cpu(cpu, that->active_mask);
     471                 :          0 :                         cpumask_set_cpu(i, that->active_mask);
     472                 :          0 :                         that->cpu = i;
     473                 :          0 :                         break;
     474                 :            :                 }
     475                 :            :         }
     476                 :            : }
     477                 :            : 
     478                 :          0 : static int amd_uncore_cpu_down_prepare(unsigned int cpu)
     479                 :            : {
     480         [ #  # ]:          0 :         if (amd_uncore_nb)
     481                 :          0 :                 uncore_down_prepare(cpu, amd_uncore_nb);
     482                 :            : 
     483         [ #  # ]:          0 :         if (amd_uncore_llc)
     484                 :          0 :                 uncore_down_prepare(cpu, amd_uncore_llc);
     485                 :            : 
     486                 :          0 :         return 0;
     487                 :            : }
     488                 :            : 
     489                 :          0 : static void uncore_dead(unsigned int cpu, struct amd_uncore * __percpu *uncores)
     490                 :            : {
     491                 :          0 :         struct amd_uncore *uncore = *per_cpu_ptr(uncores, cpu);
     492                 :            : 
     493         [ #  # ]:          0 :         if (cpu == uncore->cpu)
     494                 :          0 :                 cpumask_clear_cpu(cpu, uncore->active_mask);
     495                 :            : 
     496         [ #  # ]:          0 :         if (!--uncore->refcnt)
     497                 :          0 :                 kfree(uncore);
     498                 :          0 :         *per_cpu_ptr(uncores, cpu) = NULL;
     499                 :          0 : }
     500                 :            : 
     501                 :          0 : static int amd_uncore_cpu_dead(unsigned int cpu)
     502                 :            : {
     503         [ #  # ]:          0 :         if (amd_uncore_nb)
     504                 :          0 :                 uncore_dead(cpu, amd_uncore_nb);
     505                 :            : 
     506         [ #  # ]:          0 :         if (amd_uncore_llc)
     507                 :          0 :                 uncore_dead(cpu, amd_uncore_llc);
     508                 :            : 
     509                 :          0 :         return 0;
     510                 :            : }
     511                 :            : 
     512                 :         78 : static int __init amd_uncore_init(void)
     513                 :            : {
     514                 :         78 :         int ret = -ENODEV;
     515                 :            : 
     516         [ +  - ]:         78 :         if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
     517                 :            :             boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
     518                 :            :                 return -ENODEV;
     519                 :            : 
     520         [ -  + ]:         78 :         if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
     521                 :            :                 return -ENODEV;
     522                 :            : 
     523         [ #  # ]:          0 :         if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) {
     524                 :            :                 /*
     525                 :            :                  * For F17h or F18h, the Northbridge counters are
     526                 :            :                  * repurposed as Data Fabric counters. Also, L3
     527                 :            :                  * counters are supported too. The PMUs are exported
     528                 :            :                  * based on family as either L2 or L3 and NB or DF.
     529                 :            :                  */
     530                 :          0 :                 num_counters_nb           = NUM_COUNTERS_NB;
     531                 :          0 :                 num_counters_llc          = NUM_COUNTERS_L3;
     532                 :          0 :                 amd_nb_pmu.name           = "amd_df";
     533                 :          0 :                 amd_llc_pmu.name          = "amd_l3";
     534                 :          0 :                 format_attr_event_df.show = &event_show_df;
     535                 :          0 :                 format_attr_event_l3.show = &event_show_l3;
     536                 :          0 :                 l3_mask                   = true;
     537                 :            :         } else {
     538                 :          0 :                 num_counters_nb           = NUM_COUNTERS_NB;
     539                 :          0 :                 num_counters_llc          = NUM_COUNTERS_L2;
     540                 :          0 :                 amd_nb_pmu.name           = "amd_nb";
     541                 :          0 :                 amd_llc_pmu.name          = "amd_l2";
     542                 :          0 :                 format_attr_event_df      = format_attr_event;
     543                 :          0 :                 format_attr_event_l3      = format_attr_event;
     544                 :          0 :                 l3_mask                   = false;
     545                 :            :         }
     546                 :            : 
     547                 :          0 :         amd_nb_pmu.attr_groups  = amd_uncore_attr_groups_df;
     548                 :          0 :         amd_llc_pmu.attr_groups = amd_uncore_attr_groups_l3;
     549                 :            : 
     550         [ #  # ]:          0 :         if (boot_cpu_has(X86_FEATURE_PERFCTR_NB)) {
     551                 :          0 :                 amd_uncore_nb = alloc_percpu(struct amd_uncore *);
     552         [ #  # ]:          0 :                 if (!amd_uncore_nb) {
     553                 :          0 :                         ret = -ENOMEM;
     554                 :          0 :                         goto fail_nb;
     555                 :            :                 }
     556                 :          0 :                 ret = perf_pmu_register(&amd_nb_pmu, amd_nb_pmu.name, -1);
     557         [ #  # ]:          0 :                 if (ret)
     558                 :          0 :                         goto fail_nb;
     559                 :            : 
     560         [ #  # ]:          0 :                 pr_info("%s NB counters detected\n",
     561                 :            :                         boot_cpu_data.x86_vendor == X86_VENDOR_HYGON ?
     562                 :            :                                 "HYGON" : "AMD");
     563                 :          0 :                 ret = 0;
     564                 :            :         }
     565                 :            : 
     566         [ #  # ]:          0 :         if (boot_cpu_has(X86_FEATURE_PERFCTR_LLC)) {
     567                 :          0 :                 amd_uncore_llc = alloc_percpu(struct amd_uncore *);
     568         [ #  # ]:          0 :                 if (!amd_uncore_llc) {
     569                 :          0 :                         ret = -ENOMEM;
     570                 :          0 :                         goto fail_llc;
     571                 :            :                 }
     572                 :          0 :                 ret = perf_pmu_register(&amd_llc_pmu, amd_llc_pmu.name, -1);
     573         [ #  # ]:          0 :                 if (ret)
     574                 :          0 :                         goto fail_llc;
     575                 :            : 
     576         [ #  # ]:          0 :                 pr_info("%s LLC counters detected\n",
     577                 :            :                         boot_cpu_data.x86_vendor == X86_VENDOR_HYGON ?
     578                 :            :                                 "HYGON" : "AMD");
     579                 :          0 :                 ret = 0;
     580                 :            :         }
     581                 :            : 
     582                 :            :         /*
     583                 :            :          * Install callbacks. Core will call them for each online cpu.
     584                 :            :          */
     585         [ #  # ]:          0 :         if (cpuhp_setup_state(CPUHP_PERF_X86_AMD_UNCORE_PREP,
     586                 :            :                               "perf/x86/amd/uncore:prepare",
     587                 :            :                               amd_uncore_cpu_up_prepare, amd_uncore_cpu_dead))
     588                 :          0 :                 goto fail_llc;
     589                 :            : 
     590         [ #  # ]:          0 :         if (cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
     591                 :            :                               "perf/x86/amd/uncore:starting",
     592                 :            :                               amd_uncore_cpu_starting, NULL))
     593                 :          0 :                 goto fail_prep;
     594         [ #  # ]:          0 :         if (cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_UNCORE_ONLINE,
     595                 :            :                               "perf/x86/amd/uncore:online",
     596                 :            :                               amd_uncore_cpu_online,
     597                 :            :                               amd_uncore_cpu_down_prepare))
     598                 :          0 :                 goto fail_start;
     599                 :            :         return 0;
     600                 :            : 
     601                 :            : fail_start:
     602                 :          0 :         cpuhp_remove_state(CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING);
     603                 :          0 : fail_prep:
     604                 :          0 :         cpuhp_remove_state(CPUHP_PERF_X86_AMD_UNCORE_PREP);
     605                 :          0 : fail_llc:
     606         [ #  # ]:          0 :         if (boot_cpu_has(X86_FEATURE_PERFCTR_NB))
     607                 :          0 :                 perf_pmu_unregister(&amd_nb_pmu);
     608         [ #  # ]:          0 :         if (amd_uncore_llc)
     609                 :          0 :                 free_percpu(amd_uncore_llc);
     610                 :          0 : fail_nb:
     611         [ #  # ]:          0 :         if (amd_uncore_nb)
     612                 :          0 :                 free_percpu(amd_uncore_nb);
     613                 :            : 
     614                 :            :         return ret;
     615                 :            : }
     616                 :            : device_initcall(amd_uncore_init);

Generated by: LCOV version 1.14