Skip to content

Commit

Permalink
perf/x86/intel/uncore: Enable IIO stacks to PMON mapping for multi-se…
Browse files Browse the repository at this point in the history
…gment SKX

IIO stacks to PMON mapping on Skylake servers is exposed through introduced
early attributes /sys/devices/uncore_iio_<pmu_idx>/dieX, where dieX is a
file which holds "Segment:Root Bus" for PCIe root port which can
be monitored by that IIO PMON block. These sysfs attributes are disabled
for multiple segment topologies except VMD domains which start at 0x10000.
This patch removes the limitation and enables IIO stacks to PMON mapping
for multi-segment Skylake servers by introducing segment-aware
intel_uncore_topology structure and attributing the topology configuration
to the segment in skx_iio_get_topology() function.

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Alexander Antonov <alexander.antonov@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Tested-by: Kyle Meyer <kyle.meyer@hpe.com>
Link: https://lkml.kernel.org/r/20210323150507.2013-1-alexander.antonov@linux.intel.com
  • Loading branch information
Alexander Antonov authored and Peter Zijlstra committed Apr 2, 2021
1 parent c4c55e3 commit cface03
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 34 deletions.
12 changes: 12 additions & 0 deletions arch/x86/events/intel/uncore.c
Expand Up @@ -53,6 +53,18 @@ int uncore_pcibus_to_dieid(struct pci_bus *bus)
return die_id;
}

int uncore_die_to_segment(int die)
{
struct pci_bus *bus = NULL;

/* Find first pci bus which attributes to specified die. */
while ((bus = pci_find_next_bus(bus)) &&
(die != uncore_pcibus_to_dieid(bus)))
;

return bus ? pci_domain_nr(bus) : -EINVAL;
}

static void uncore_free_pcibus_map(void)
{
struct pci2phy_map *map, *tmp;
Expand Down
9 changes: 8 additions & 1 deletion arch/x86/events/intel/uncore.h
Expand Up @@ -42,6 +42,7 @@ struct intel_uncore_pmu;
struct intel_uncore_box;
struct uncore_event_desc;
struct freerunning_counters;
struct intel_uncore_topology;

struct intel_uncore_type {
const char *name;
Expand Down Expand Up @@ -87,7 +88,7 @@ struct intel_uncore_type {
* to identify which platform component each PMON block of that type is
* supposed to monitor.
*/
u64 *topology;
struct intel_uncore_topology *topology;
/*
* Optional callbacks for managing mapping of Uncore units to PMONs
*/
Expand Down Expand Up @@ -176,6 +177,11 @@ struct freerunning_counters {
unsigned *box_offsets;
};

struct intel_uncore_topology {
u64 configuration;
int segment;
};

struct pci2phy_map {
struct list_head list;
int segment;
Expand All @@ -184,6 +190,7 @@ struct pci2phy_map {

struct pci2phy_map *__find_pci2phy_map(int segment);
int uncore_pcibus_to_dieid(struct pci_bus *bus);
int uncore_die_to_segment(int die);

ssize_t uncore_event_show(struct device *dev,
struct device_attribute *attr, char *buf);
Expand Down
60 changes: 27 additions & 33 deletions arch/x86/events/intel/uncore_snbep.c
Expand Up @@ -3684,7 +3684,8 @@ static struct intel_uncore_ops skx_uncore_iio_ops = {

static inline u8 skx_iio_stack(struct intel_uncore_pmu *pmu, int die)
{
return pmu->type->topology[die] >> (pmu->pmu_idx * BUS_NUM_STRIDE);
return pmu->type->topology[die].configuration >>
(pmu->pmu_idx * BUS_NUM_STRIDE);
}

static umode_t
Expand All @@ -3697,19 +3698,14 @@ skx_iio_mapping_visible(struct kobject *kobj, struct attribute *attr, int die)
}

static ssize_t skx_iio_mapping_show(struct device *dev,
struct device_attribute *attr, char *buf)
struct device_attribute *attr, char *buf)
{
struct pci_bus *bus = pci_find_next_bus(NULL);
struct intel_uncore_pmu *uncore_pmu = dev_to_uncore_pmu(dev);
struct intel_uncore_pmu *pmu = dev_to_uncore_pmu(dev);
struct dev_ext_attribute *ea = to_dev_ext_attribute(attr);
long die = (long)ea->var;

/*
* Current implementation is for single segment configuration hence it's
* safe to take the segment value from the first available root bus.
*/
return sprintf(buf, "%04x:%02x\n", pci_domain_nr(bus),
skx_iio_stack(uncore_pmu, die));
return sprintf(buf, "%04x:%02x\n", pmu->type->topology[die].segment,
skx_iio_stack(pmu, die));
}

static int skx_msr_cpu_bus_read(int cpu, u64 *topology)
Expand Down Expand Up @@ -3746,34 +3742,32 @@ static int die_to_cpu(int die)

static int skx_iio_get_topology(struct intel_uncore_type *type)
{
int i, ret;
struct pci_bus *bus = NULL;

/*
* Verified single-segment environments only; disabled for multiple
* segment topologies for now except VMD domains.
* VMD domains start at 0x10000 to not clash with ACPI _SEG domains.
*/
while ((bus = pci_find_next_bus(bus))
&& (!pci_domain_nr(bus) || pci_domain_nr(bus) > 0xffff))
;
if (bus)
return -EPERM;
int die, ret = -EPERM;

type->topology = kcalloc(uncore_max_dies(), sizeof(u64), GFP_KERNEL);
type->topology = kcalloc(uncore_max_dies(), sizeof(*type->topology),
GFP_KERNEL);
if (!type->topology)
return -ENOMEM;

for (i = 0; i < uncore_max_dies(); i++) {
ret = skx_msr_cpu_bus_read(die_to_cpu(i), &type->topology[i]);
if (ret) {
kfree(type->topology);
type->topology = NULL;
return ret;
}
for (die = 0; die < uncore_max_dies(); die++) {
ret = skx_msr_cpu_bus_read(die_to_cpu(die),
&type->topology[die].configuration);
if (ret)
break;

ret = uncore_die_to_segment(die);
if (ret < 0)
break;

type->topology[die].segment = ret;
}

return 0;
if (ret < 0) {
kfree(type->topology);
type->topology = NULL;
}

return ret;
}

static struct attribute_group skx_iio_mapping_group = {
Expand All @@ -3794,7 +3788,7 @@ static int skx_iio_set_mapping(struct intel_uncore_type *type)
struct dev_ext_attribute *eas = NULL;

ret = skx_iio_get_topology(type);
if (ret)
if (ret < 0)
goto clear_attr_update;

ret = -ENOMEM;
Expand Down

0 comments on commit cface03

Please sign in to comment.