Skip to content

Commit d2f9fe6

Browse files
committed
Merge branch 'for-6.5/cxl-perf' into for-6.5/cxl
Pick up initial support for the CXL 3.0 performance monitoring definition. Small conflicts with the firmware update work as they both placed their init code in the same location.
2 parents e2c18eb + c2b34d4 commit d2f9fe6

19 files changed

Lines changed: 1307 additions & 7 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
======================================
4+
CXL Performance Monitoring Unit (CPMU)
5+
======================================
6+
7+
The CXL rev 3.0 specification provides a definition of CXL Performance
8+
Monitoring Unit in section 13.2: Performance Monitoring.
9+
10+
CXL components (e.g. Root Port, Switch Upstream Port, End Point) may have
11+
any number of CPMU instances. CPMU capabilities are fully discoverable from
12+
the devices. The specification provides event definitions for all CXL protocol
13+
message types and a set of additional events for things commonly counted on
14+
CXL devices (e.g. DRAM events).
15+
16+
CPMU driver
17+
===========
18+
19+
The CPMU driver registers a perf PMU with the name pmu_mem<X>.<Y> on the CXL bus
20+
representing the Yth CPMU for memX.
21+
22+
/sys/bus/cxl/device/pmu_mem<X>.<Y>
23+
24+
The associated PMU is registered as
25+
26+
/sys/bus/event_sources/devices/cxl_pmu_mem<X>.<Y>
27+
28+
In common with other CXL bus devices, the id has no specific meaning and the
29+
relationship to specific CXL device should be established via the device parent
30+
of the device on the CXL bus.
31+
32+
PMU driver provides description of available events and filter options in sysfs.
33+
34+
The "format" directory describes all formats of the config (event vendor id,
35+
group id and mask) config1 (threshold, filter enables) and config2 (filter
36+
parameters) fields of the perf_event_attr structure. The "events" directory
37+
describes all documented events show in perf list.
38+
39+
The events shown in perf list are the most fine grained events with a single
40+
bit of the event mask set. More general events may be enable by setting
41+
multiple mask bits in config. For example, all Device to Host Read Requests
42+
may be captured on a single counter by setting the bits for all of
43+
44+
* d2h_req_rdcurr
45+
* d2h_req_rdown
46+
* d2h_req_rdshared
47+
* d2h_req_rdany
48+
* d2h_req_rdownnodata
49+
50+
Example of usage::
51+
52+
$#perf list
53+
cxl_pmu_mem0.0/clock_ticks/ [Kernel PMU event]
54+
cxl_pmu_mem0.0/d2h_req_rdshared/ [Kernel PMU event]
55+
cxl_pmu_mem0.0/h2d_req_snpcur/ [Kernel PMU event]
56+
cxl_pmu_mem0.0/h2d_req_snpdata/ [Kernel PMU event]
57+
cxl_pmu_mem0.0/h2d_req_snpinv/ [Kernel PMU event]
58+
-----------------------------------------------------------
59+
60+
$# perf stat -a -e cxl_pmu_mem0.0/clock_ticks/ -e cxl_pmu_mem0.0/d2h_req_rdshared/
61+
62+
Vendor specific events may also be available and if so can be used via
63+
64+
$# perf stat -a -e cxl_pmu_mem0.0/vid=VID,gid=GID,mask=MASK/
65+
66+
The driver does not support sampling so "perf record" is unsupported.
67+
It only supports system-wide counting so attaching to a task is
68+
unsupported.

Documentation/admin-guide/perf/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ Performance monitor support
2121
alibaba_pmu
2222
nvidia-pmu
2323
meson-ddr-pmu
24+
cxl

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5194,6 +5194,13 @@ S: Maintained
51945194
F: drivers/cxl/
51955195
F: include/uapi/linux/cxl_mem.h
51965196

5197+
COMPUTE EXPRESS LINK PMU (CPMU)
5198+
M: Jonathan Cameron <jonathan.cameron@huawei.com>
5199+
L: linux-cxl@vger.kernel.org
5200+
S: Maintained
5201+
F: Documentation/admin-guide/perf/cxl.rst
5202+
F: drivers/perf/cxl_pmu.c
5203+
51975204
CONEXANT ACCESSRUNNER USB DRIVER
51985205
L: accessrunner-general@lists.sourceforge.net
51995206
S: Orphan

drivers/cxl/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,17 @@ config CXL_REGION_INVALIDATION_TEST
140140
If unsure, or if this kernel is meant for production environments,
141141
say N.
142142

143+
config CXL_PMU
144+
tristate "CXL Performance Monitoring Unit"
145+
default CXL_BUS
146+
depends on PERF_EVENTS
147+
help
148+
Support performance monitoring as defined in CXL rev 3.0
149+
section 13.2: Performance Monitoring. CXL components may have
150+
one or more CXL Performance Monitoring Units (CPMUs).
151+
152+
Say 'y/m' to enable a driver that will attach to performance
153+
monitoring units and provide standard perf based interfaces.
154+
155+
If unsure say 'm'.
143156
endif

drivers/cxl/core/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ cxl_core-y += memdev.o
1212
cxl_core-y += mbox.o
1313
cxl_core-y += pci.o
1414
cxl_core-y += hdm.o
15+
cxl_core-y += pmu.o
1516
cxl_core-$(CONFIG_TRACING) += trace.o
1617
cxl_core-$(CONFIG_CXL_REGION) += region.o

drivers/cxl/core/core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
extern const struct device_type cxl_nvdimm_bridge_type;
88
extern const struct device_type cxl_nvdimm_type;
9+
extern const struct device_type cxl_pmu_type;
910

1011
extern struct attribute_group cxl_base_attribute_group;
1112

drivers/cxl/core/pmu.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Copyright(c) 2023 Huawei. All rights reserved. */
3+
4+
#include <linux/device.h>
5+
#include <linux/slab.h>
6+
#include <linux/idr.h>
7+
#include <cxlmem.h>
8+
#include <pmu.h>
9+
#include <cxl.h>
10+
#include "core.h"
11+
12+
static void cxl_pmu_release(struct device *dev)
13+
{
14+
struct cxl_pmu *pmu = to_cxl_pmu(dev);
15+
16+
kfree(pmu);
17+
}
18+
19+
const struct device_type cxl_pmu_type = {
20+
.name = "cxl_pmu",
21+
.release = cxl_pmu_release,
22+
};
23+
24+
static void remove_dev(void *dev)
25+
{
26+
device_del(dev);
27+
}
28+
29+
int devm_cxl_pmu_add(struct device *parent, struct cxl_pmu_regs *regs,
30+
int assoc_id, int index, enum cxl_pmu_type type)
31+
{
32+
struct cxl_pmu *pmu;
33+
struct device *dev;
34+
int rc;
35+
36+
pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
37+
if (!pmu)
38+
return -ENOMEM;
39+
40+
pmu->assoc_id = assoc_id;
41+
pmu->index = index;
42+
pmu->type = type;
43+
pmu->base = regs->pmu;
44+
dev = &pmu->dev;
45+
device_initialize(dev);
46+
device_set_pm_not_required(dev);
47+
dev->parent = parent;
48+
dev->bus = &cxl_bus_type;
49+
dev->type = &cxl_pmu_type;
50+
switch (pmu->type) {
51+
case CXL_PMU_MEMDEV:
52+
rc = dev_set_name(dev, "pmu_mem%d.%d", assoc_id, index);
53+
break;
54+
}
55+
if (rc)
56+
goto err;
57+
58+
rc = device_add(dev);
59+
if (rc)
60+
goto err;
61+
62+
return devm_add_action_or_reset(parent, remove_dev, dev);
63+
64+
err:
65+
put_device(&pmu->dev);
66+
return rc;
67+
}
68+
EXPORT_SYMBOL_NS_GPL(devm_cxl_pmu_add, CXL);

drivers/cxl/core/port.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ static int cxl_device_id(const struct device *dev)
5656
return CXL_DEVICE_MEMORY_EXPANDER;
5757
if (dev->type == CXL_REGION_TYPE())
5858
return CXL_DEVICE_REGION;
59+
if (dev->type == &cxl_pmu_type)
60+
return CXL_DEVICE_PMU;
5961
return 0;
6062
}
6163

drivers/cxl/core/regs.c

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <linux/pci.h>
77
#include <cxlmem.h>
88
#include <cxlpci.h>
9+
#include <pmu.h>
910

1011
#include "core.h"
1112

@@ -286,20 +287,23 @@ static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi,
286287
}
287288

288289
/**
289-
* cxl_find_regblock() - Locate register blocks by type
290+
* cxl_find_regblock_instance() - Locate a register block by type / index
290291
* @pdev: The CXL PCI device to enumerate.
291292
* @type: Register Block Indicator id
292293
* @map: Enumeration output, clobbered on error
294+
* @index: Index into which particular instance of a regblock wanted in the
295+
* order found in register locator DVSEC.
293296
*
294297
* Return: 0 if register block enumerated, negative error code otherwise
295298
*
296299
* A CXL DVSEC may point to one or more register blocks, search for them
297-
* by @type.
300+
* by @type and @index.
298301
*/
299-
int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
300-
struct cxl_register_map *map)
302+
int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type,
303+
struct cxl_register_map *map, int index)
301304
{
302305
u32 regloc_size, regblocks;
306+
int instance = 0;
303307
int regloc, i;
304308

305309
map->resource = CXL_RESOURCE_NONE;
@@ -323,15 +327,74 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
323327
if (!cxl_decode_regblock(pdev, reg_lo, reg_hi, map))
324328
continue;
325329

326-
if (map->reg_type == type)
327-
return 0;
330+
if (map->reg_type == type) {
331+
if (index == instance)
332+
return 0;
333+
instance++;
334+
}
328335
}
329336

330337
map->resource = CXL_RESOURCE_NONE;
331338
return -ENODEV;
332339
}
340+
EXPORT_SYMBOL_NS_GPL(cxl_find_regblock_instance, CXL);
341+
342+
/**
343+
* cxl_find_regblock() - Locate register blocks by type
344+
* @pdev: The CXL PCI device to enumerate.
345+
* @type: Register Block Indicator id
346+
* @map: Enumeration output, clobbered on error
347+
*
348+
* Return: 0 if register block enumerated, negative error code otherwise
349+
*
350+
* A CXL DVSEC may point to one or more register blocks, search for them
351+
* by @type.
352+
*/
353+
int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
354+
struct cxl_register_map *map)
355+
{
356+
return cxl_find_regblock_instance(pdev, type, map, 0);
357+
}
333358
EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, CXL);
334359

360+
/**
361+
* cxl_count_regblock() - Count instances of a given regblock type.
362+
* @pdev: The CXL PCI device to enumerate.
363+
* @type: Register Block Indicator id
364+
*
365+
* Some regblocks may be repeated. Count how many instances.
366+
*
367+
* Return: count of matching regblocks.
368+
*/
369+
int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type)
370+
{
371+
struct cxl_register_map map;
372+
int rc, count = 0;
373+
374+
while (1) {
375+
rc = cxl_find_regblock_instance(pdev, type, &map, count);
376+
if (rc)
377+
return count;
378+
count++;
379+
}
380+
}
381+
EXPORT_SYMBOL_NS_GPL(cxl_count_regblock, CXL);
382+
383+
int cxl_map_pmu_regs(struct pci_dev *pdev, struct cxl_pmu_regs *regs,
384+
struct cxl_register_map *map)
385+
{
386+
struct device *dev = &pdev->dev;
387+
resource_size_t phys_addr;
388+
389+
phys_addr = map->resource;
390+
regs->pmu = devm_cxl_iomap_block(dev, phys_addr, CXL_PMU_REGMAP_SIZE);
391+
if (!regs->pmu)
392+
return -ENOMEM;
393+
394+
return 0;
395+
}
396+
EXPORT_SYMBOL_NS_GPL(cxl_map_pmu_regs, CXL);
397+
335398
resource_size_t cxl_rcrb_to_component(struct device *dev,
336399
resource_size_t rcrb,
337400
enum cxl_rcrb which)

drivers/cxl/cxl.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ struct cxl_regs {
217217
struct_group_tagged(cxl_device_regs, device_regs,
218218
void __iomem *status, *mbox, *memdev;
219219
);
220+
221+
struct_group_tagged(cxl_pmu_regs, pmu_regs,
222+
void __iomem *pmu;
223+
);
220224
};
221225

222226
struct cxl_reg_map {
@@ -237,6 +241,10 @@ struct cxl_device_reg_map {
237241
struct cxl_reg_map memdev;
238242
};
239243

244+
struct cxl_pmu_reg_map {
245+
struct cxl_reg_map pmu;
246+
};
247+
240248
/**
241249
* struct cxl_register_map - DVSEC harvested register block mapping parameters
242250
* @base: virtual base of the register-block-BAR + @block_offset
@@ -245,6 +253,7 @@ struct cxl_device_reg_map {
245253
* @reg_type: see enum cxl_regloc_type
246254
* @component_map: cxl_reg_map for component registers
247255
* @device_map: cxl_reg_maps for device registers
256+
* @pmu_map: cxl_reg_maps for CXL Performance Monitoring Units
248257
*/
249258
struct cxl_register_map {
250259
void __iomem *base;
@@ -254,6 +263,7 @@ struct cxl_register_map {
254263
union {
255264
struct cxl_component_reg_map component_map;
256265
struct cxl_device_reg_map device_map;
266+
struct cxl_pmu_reg_map pmu_map;
257267
};
258268
};
259269

@@ -266,8 +276,13 @@ int cxl_map_component_regs(struct device *dev, struct cxl_component_regs *regs,
266276
unsigned long map_mask);
267277
int cxl_map_device_regs(struct device *dev, struct cxl_device_regs *regs,
268278
const struct cxl_register_map *map);
279+
int cxl_map_pmu_regs(struct pci_dev *pdev, struct cxl_pmu_regs *regs,
280+
struct cxl_register_map *map);
269281

270282
enum cxl_regloc_type;
283+
int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type);
284+
int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type,
285+
struct cxl_register_map *map, int index);
271286
int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
272287
struct cxl_register_map *map);
273288

@@ -759,6 +774,7 @@ void cxl_driver_unregister(struct cxl_driver *cxl_drv);
759774
#define CXL_DEVICE_REGION 6
760775
#define CXL_DEVICE_PMEM_REGION 7
761776
#define CXL_DEVICE_DAX_REGION 8
777+
#define CXL_DEVICE_PMU 9
762778

763779
#define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
764780
#define CXL_MODALIAS_FMT "cxl:t%d"

0 commit comments

Comments
 (0)