Commit 7873b7f4 authored by Kan Liang's avatar Kan Liang Committed by Yunying Sun
Browse files

perf/x86/uncore: Apply the unit control RB tree to PCI uncore units

mainline inclusion
from mainline-v6.11-rc1
commit f76a8420444beb1c3968504c8176a67d2d5fe18f
category: feature
bugzilla: https://gitee.com/openeuler/intel-kernel/issues/IAGJQ7
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f76a8420444beb1c3968504c8176a67d2d5fe18f



-------------------------------------

The unit control RB tree has the unit control and unit ID information
for all the PCI units. Use them to replace the box_ctls/pci_offsets to
get an accurate unit control address for PCI uncore units.

The UPI/M3UPI units in the discovery table are ignored. Please see the
commit 65248a9a ("perf/x86/uncore: Add a quirk for UPI on SPR").
Manually allocate a unit control RB tree for UPI/M3UPI.
Add cleanup_extra_boxes to release such manual allocation.

Intel-SIG: commit f76a8420444b perf/x86/uncore: Apply the unit control RB tree to PCI uncore units
Backport SPR/EMR CXL and HBM perfmon support to kernel v5.10

Signed-off-by: default avatarKan Liang <kan.liang@linux.intel.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: default avatarYunying Sun <yunying.sun@intel.com>
Link: https://lore.kernel.org/r/20240614134631.1092359-7-kan.liang@linux.intel.com


Signed-off-by: default avatarYunying Sun <yunying.sun@intel.com>
parent eda807f0
Loading
Loading
Loading
Loading
+25 −28
Original line number Diff line number Diff line
@@ -961,6 +961,9 @@ static void uncore_type_exit(struct intel_uncore_type *type)
	if (type->cleanup_mapping)
		type->cleanup_mapping(type);

	if (type->cleanup_extra_boxes)
		type->cleanup_extra_boxes(type);

	if (pmu) {
		for (i = 0; i < type->num_boxes; i++, pmu++) {
			uncore_pmu_unregister(pmu);
@@ -1076,22 +1079,19 @@ static struct intel_uncore_pmu *
uncore_pci_find_dev_pmu_from_types(struct pci_dev *pdev)
{
	struct intel_uncore_type **types = uncore_pci_uncores;
	struct intel_uncore_discovery_unit *unit;
	struct intel_uncore_type *type;
	u64 box_ctl;
	int i, die;
	struct rb_node *node;

	for (; *types; types++) {
		type = *types;
		for (die = 0; die < __uncore_max_dies; die++) {
			for (i = 0; i < type->num_boxes; i++) {
				if (!type->box_ctls[die])
					continue;
				box_ctl = type->box_ctls[die] + type->pci_offsets[i];
				if (pdev->devfn == UNCORE_DISCOVERY_PCI_DEVFN(box_ctl) &&
				    pdev->bus->number == UNCORE_DISCOVERY_PCI_BUS(box_ctl) &&
				    pci_domain_nr(pdev->bus) == UNCORE_DISCOVERY_PCI_DOMAIN(box_ctl))
					return &type->pmus[i];
			}

		for (node = rb_first(type->boxes); node; node = rb_next(node)) {
			unit = rb_entry(node, struct intel_uncore_discovery_unit, node);
			if (pdev->devfn == UNCORE_DISCOVERY_PCI_DEVFN(unit->addr) &&
			    pdev->bus->number == UNCORE_DISCOVERY_PCI_BUS(unit->addr) &&
			    pci_domain_nr(pdev->bus) == UNCORE_DISCOVERY_PCI_DOMAIN(unit->addr))
				return &type->pmus[unit->pmu_idx];
		}
	}

@@ -1367,28 +1367,25 @@ static struct notifier_block uncore_pci_notifier = {
static void uncore_pci_pmus_register(void)
{
	struct intel_uncore_type **types = uncore_pci_uncores;
	struct intel_uncore_discovery_unit *unit;
	struct intel_uncore_type *type;
	struct intel_uncore_pmu *pmu;
	struct rb_node *node;
	struct pci_dev *pdev;
	u64 box_ctl;
	int i, die;

	for (; *types; types++) {
		type = *types;
		for (die = 0; die < __uncore_max_dies; die++) {
			for (i = 0; i < type->num_boxes; i++) {
				if (!type->box_ctls[die])
					continue;
				box_ctl = type->box_ctls[die] + type->pci_offsets[i];
				pdev = pci_get_domain_bus_and_slot(UNCORE_DISCOVERY_PCI_DOMAIN(box_ctl),
								   UNCORE_DISCOVERY_PCI_BUS(box_ctl),
								   UNCORE_DISCOVERY_PCI_DEVFN(box_ctl));

		for (node = rb_first(type->boxes); node; node = rb_next(node)) {
			unit = rb_entry(node, struct intel_uncore_discovery_unit, node);
			pdev = pci_get_domain_bus_and_slot(UNCORE_DISCOVERY_PCI_DOMAIN(unit->addr),
							   UNCORE_DISCOVERY_PCI_BUS(unit->addr),
							   UNCORE_DISCOVERY_PCI_DEVFN(unit->addr));

			if (!pdev)
				continue;
				pmu = &type->pmus[i];

				uncore_pci_pmu_register(pdev, type, pmu, die);
			}
			pmu = &type->pmus[unit->pmu_idx];
			uncore_pci_pmu_register(pdev, type, pmu, unit->die);
		}
	}

+4 −0
Original line number Diff line number Diff line
@@ -97,6 +97,10 @@ struct intel_uncore_type {
	int (*get_topology)(struct intel_uncore_type *type);
	int (*set_mapping)(struct intel_uncore_type *type);
	void (*cleanup_mapping)(struct intel_uncore_type *type);
	/*
	 * Optional callbacks for extra uncore units cleanup
	 */
	void (*cleanup_extra_boxes)(struct intel_uncore_type *type);
};

#define pmu_group attr_groups[0]
+20 −6
Original line number Diff line number Diff line
@@ -215,7 +215,7 @@ uncore_find_unit(struct rb_root *root, unsigned int id)
	return NULL;
}

static void uncore_find_add_unit(struct intel_uncore_discovery_unit *node,
void uncore_find_add_unit(struct intel_uncore_discovery_unit *node,
			  struct rb_root *root, u16 *num_units)
{
	struct intel_uncore_discovery_unit *unit = uncore_find_unit(root, node->id);
@@ -552,7 +552,7 @@ bool intel_generic_uncore_assign_hw_event(struct perf_event *event,
	if (!box->pmu->type->boxes)
		return false;

	if (box->pci_dev || box->io_addr) {
	if (box->io_addr) {
		hwc->config_base = uncore_pci_event_ctl(box, hwc->idx);
		hwc->event_base  = uncore_pci_perf_ctr(box, hwc->idx);
		return true;
@@ -562,16 +562,28 @@ bool intel_generic_uncore_assign_hw_event(struct perf_event *event,
	if (!box_ctl)
		return false;

	if (box->pci_dev) {
		box_ctl = UNCORE_DISCOVERY_PCI_BOX_CTRL(box_ctl);
		hwc->config_base = box_ctl + uncore_pci_event_ctl(box, hwc->idx);
		hwc->event_base  = box_ctl + uncore_pci_perf_ctr(box, hwc->idx);
		return true;
	}

	hwc->config_base = box_ctl + box->pmu->type->event_ctl + hwc->idx;
	hwc->event_base  = box_ctl + box->pmu->type->perf_ctr + hwc->idx;

	return true;
}

static inline int intel_pci_uncore_box_ctl(struct intel_uncore_box *box)
{
	return UNCORE_DISCOVERY_PCI_BOX_CTRL(intel_generic_uncore_box_ctl(box));
}

void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box)
{
	struct pci_dev *pdev = box->pci_dev;
	int box_ctl = uncore_pci_box_ctl(box);
	int box_ctl = intel_pci_uncore_box_ctl(box);

	__set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags);
	pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_INT);
@@ -580,7 +592,7 @@ void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box)
void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box)
{
	struct pci_dev *pdev = box->pci_dev;
	int box_ctl = uncore_pci_box_ctl(box);
	int box_ctl = intel_pci_uncore_box_ctl(box);

	pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_FRZ);
}
@@ -588,7 +600,7 @@ void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box)
void intel_generic_uncore_pci_enable_box(struct intel_uncore_box *box)
{
	struct pci_dev *pdev = box->pci_dev;
	int box_ctl = uncore_pci_box_ctl(box);
	int box_ctl = intel_pci_uncore_box_ctl(box);

	pci_write_config_dword(pdev, box_ctl, 0);
}
@@ -740,6 +752,8 @@ static bool uncore_update_uncore_type(enum uncore_access_type type_id,
		uncore->box_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl);
		uncore->box_ctls = type->box_ctrl_die;
		uncore->pci_offsets = type->box_offset;
		uncore->boxes = &type->units;
		uncore->num_boxes = type->num_units;
		break;
	case UNCORE_ACCESS_MMIO:
		uncore->ops = &generic_uncore_mmio_ops;
+2 −0
Original line number Diff line number Diff line
@@ -173,3 +173,5 @@ int intel_uncore_find_discovery_unit_id(struct rb_root *units, int die,
					unsigned int pmu_idx);
bool intel_generic_uncore_assign_hw_event(struct perf_event *event,
					  struct intel_uncore_box *box);
void uncore_find_add_unit(struct intel_uncore_discovery_unit *node,
			  struct rb_root *root, u16 *num_units);
+60 −31
Original line number Diff line number Diff line
@@ -5668,6 +5668,24 @@ static u64 spr_upi_pci_offsets[SPR_UNCORE_UPI_NUM_BOXES] = {
	0, 0x8000, 0x10000, 0x18000
};

static void spr_extra_boxes_cleanup(struct intel_uncore_type *type)
{
	struct intel_uncore_discovery_unit *pos;
	struct rb_node *node;

	if (!type->boxes)
		return;

	while (!RB_EMPTY_ROOT(type->boxes)) {
		node = rb_first(type->boxes);
		pos = rb_entry(node, struct intel_uncore_discovery_unit, node);
		rb_erase(node, type->boxes);
		kfree(pos);
	}
	kfree(type->boxes);
	type->boxes = NULL;
}

static struct intel_uncore_type spr_uncore_upi = {
	SPR_UNCORE_PCI_COMMON_FORMAT(),
	.name                   = "upi",
@@ -5675,10 +5693,11 @@ static struct intel_uncore_type spr_uncore_upi = {
	.num_counters           = 4,
	.num_boxes              = SPR_UNCORE_UPI_NUM_BOXES,
	.perf_ctr_bits          = 48,
       .perf_ctr               = ICX_UPI_PCI_PMON_CTR0,
       .event_ctl              = ICX_UPI_PCI_PMON_CTL0,
	.perf_ctr               = ICX_UPI_PCI_PMON_CTR0 - ICX_UPI_PCI_PMON_BOX_CTL,
	.event_ctl              = ICX_UPI_PCI_PMON_CTL0 - ICX_UPI_PCI_PMON_BOX_CTL,
	.box_ctl                = ICX_UPI_PCI_PMON_BOX_CTL,
	.pci_offsets            = spr_upi_pci_offsets,
	.cleanup_extra_boxes    = spr_extra_boxes_cleanup,
};

static struct intel_uncore_type spr_uncore_m3upi = {
@@ -5688,11 +5707,12 @@ static struct intel_uncore_type spr_uncore_m3upi = {
	.num_counters           = 4,
	.num_boxes              = SPR_UNCORE_UPI_NUM_BOXES,
	.perf_ctr_bits          = 48,
       .perf_ctr               = ICX_M3UPI_PCI_PMON_CTR0,
       .event_ctl              = ICX_M3UPI_PCI_PMON_CTL0,
	.perf_ctr               = ICX_M3UPI_PCI_PMON_CTR0 - ICX_M3UPI_PCI_PMON_BOX_CTL,
	.event_ctl              = ICX_M3UPI_PCI_PMON_CTL0 - ICX_M3UPI_PCI_PMON_BOX_CTL,
	.box_ctl                = ICX_M3UPI_PCI_PMON_BOX_CTL,
	.pci_offsets            = spr_upi_pci_offsets,
	.constraints            = icx_uncore_m3upi_constraints,
	.cleanup_extra_boxes    = spr_extra_boxes_cleanup,
};

enum perf_uncore_spr_iio_freerunning_type_id {
@@ -5973,10 +5993,11 @@ void spr_uncore_cpu_init(void)

static void spr_update_device_location(int type_id)
{
	struct intel_uncore_discovery_unit *unit;
	struct intel_uncore_type *type;
	struct pci_dev *dev = NULL;
	struct rb_root *root;
	u32 device, devfn;
	u64 *ctls;
	int die;

	if (type_id == UNCORE_SPR_UPI) {
@@ -5990,27 +6011,35 @@ static void spr_update_device_location(int type_id)
	} else
		return;

	ctls = kcalloc(__uncore_max_dies, sizeof(u64), GFP_KERNEL);
	if (!ctls) {
	root = kzalloc(sizeof(struct rb_root), GFP_KERNEL);
	if (!root) {
		type->num_boxes = 0;
		return;
	}
	*root = RB_ROOT;

	while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, dev)) != NULL) {
		if (devfn != dev->devfn)
			continue;

		die = uncore_device_to_die(dev);
		if (die < 0)
			continue;

		ctls[die] = pci_domain_nr(dev->bus) << UNCORE_DISCOVERY_PCI_DOMAIN_OFFSET |
		unit = kzalloc(sizeof(*unit), GFP_KERNEL);
		if (!unit)
			continue;
		unit->die = die;
		unit->id = PCI_SLOT(dev->devfn) - PCI_SLOT(devfn);
		unit->addr = pci_domain_nr(dev->bus) << UNCORE_DISCOVERY_PCI_DOMAIN_OFFSET |
			     dev->bus->number << UNCORE_DISCOVERY_PCI_BUS_OFFSET |
			     devfn << UNCORE_DISCOVERY_PCI_DEVFN_OFFSET |
			     type->box_ctl;

		unit->pmu_idx = unit->id;

		uncore_find_add_unit(unit, root, NULL);
	}

	type->box_ctls = ctls;
	type->boxes = root;
}

int spr_uncore_pci_init(void)