Skip to content

Commit 28a3ae4

Browse files
AlisonSchofielddjbw
authored andcommitted
cxl/trace: Add an HPA to cxl_poison trace events
When a cxl_poison trace event is reported for a region, the poisoned Device Physical Address (DPA) can be translated to a Host Physical Address (HPA) for consumption by user space. Translate and add the resulting HPA to the cxl_poison trace event. Follow the device decode logic as defined in the CXL Spec 3.0 Section 8.2.4.19.13. If no region currently maps the poison, assign ULLONG_MAX to the cxl_poison event hpa field. Signed-off-by: Alison Schofield <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: Dave Jiang <[email protected]> Reviewed-by: Ira Weiny <[email protected]> Link: https://lore.kernel.org/r/6d3cd726f9042a59902785b0a2cb3ddfb70e0219.1681838292.git.alison.schofield@intel.com Tested-by: Jonathan Cameron <[email protected]> Signed-off-by: Dan Williams <[email protected]>
1 parent f0832a5 commit 28a3ae4

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed

drivers/cxl/core/trace.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,99 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
33

4+
#include <cxl.h>
5+
#include "core.h"
6+
47
#define CREATE_TRACE_POINTS
58
#include "trace.h"
9+
10+
static bool cxl_is_hpa_in_range(u64 hpa, struct cxl_region *cxlr, int pos)
11+
{
12+
struct cxl_region_params *p = &cxlr->params;
13+
int gran = p->interleave_granularity;
14+
int ways = p->interleave_ways;
15+
u64 offset;
16+
17+
/* Is the hpa within this region at all */
18+
if (hpa < p->res->start || hpa > p->res->end) {
19+
dev_dbg(&cxlr->dev,
20+
"Addr trans fail: hpa 0x%llx not in region\n", hpa);
21+
return false;
22+
}
23+
24+
/* Is the hpa in an expected chunk for its pos(-ition) */
25+
offset = hpa - p->res->start;
26+
offset = do_div(offset, gran * ways);
27+
if ((offset >= pos * gran) && (offset < (pos + 1) * gran))
28+
return true;
29+
30+
dev_dbg(&cxlr->dev,
31+
"Addr trans fail: hpa 0x%llx not in expected chunk\n", hpa);
32+
33+
return false;
34+
}
35+
36+
static u64 cxl_dpa_to_hpa(u64 dpa, struct cxl_region *cxlr,
37+
struct cxl_endpoint_decoder *cxled)
38+
{
39+
u64 dpa_offset, hpa_offset, bits_upper, mask_upper, hpa;
40+
struct cxl_region_params *p = &cxlr->params;
41+
int pos = cxled->pos;
42+
u16 eig = 0;
43+
u8 eiw = 0;
44+
45+
ways_to_eiw(p->interleave_ways, &eiw);
46+
granularity_to_eig(p->interleave_granularity, &eig);
47+
48+
/*
49+
* The device position in the region interleave set was removed
50+
* from the offset at HPA->DPA translation. To reconstruct the
51+
* HPA, place the 'pos' in the offset.
52+
*
53+
* The placement of 'pos' in the HPA is determined by interleave
54+
* ways and granularity and is defined in the CXL Spec 3.0 Section
55+
* 8.2.4.19.13 Implementation Note: Device Decode Logic
56+
*/
57+
58+
/* Remove the dpa base */
59+
dpa_offset = dpa - cxl_dpa_resource_start(cxled);
60+
61+
mask_upper = GENMASK_ULL(51, eig + 8);
62+
63+
if (eiw < 8) {
64+
hpa_offset = (dpa_offset & mask_upper) << eiw;
65+
hpa_offset |= pos << (eig + 8);
66+
} else {
67+
bits_upper = (dpa_offset & mask_upper) >> (eig + 8);
68+
bits_upper = bits_upper * 3;
69+
hpa_offset = ((bits_upper << (eiw - 8)) + pos) << (eig + 8);
70+
}
71+
72+
/* The lower bits remain unchanged */
73+
hpa_offset |= dpa_offset & GENMASK_ULL(eig + 7, 0);
74+
75+
/* Apply the hpa_offset to the region base address */
76+
hpa = hpa_offset + p->res->start;
77+
78+
if (!cxl_is_hpa_in_range(hpa, cxlr, cxled->pos))
79+
return ULLONG_MAX;
80+
81+
return hpa;
82+
}
83+
84+
u64 cxl_trace_hpa(struct cxl_region *cxlr, struct cxl_memdev *cxlmd,
85+
u64 dpa)
86+
{
87+
struct cxl_region_params *p = &cxlr->params;
88+
struct cxl_endpoint_decoder *cxled = NULL;
89+
90+
for (int i = 0; i < p->nr_targets; i++) {
91+
cxled = p->targets[i];
92+
if (cxlmd == cxled_to_memdev(cxled))
93+
break;
94+
}
95+
if (!cxled || cxlmd != cxled_to_memdev(cxled))
96+
return ULLONG_MAX;
97+
98+
return cxl_dpa_to_hpa(dpa, cxlr, cxled);
99+
}

drivers/cxl/core/trace.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,8 @@ TRACE_EVENT(cxl_memory_module,
636636
#define cxl_poison_overflow(flags, time) \
637637
(flags & CXL_POISON_FLAG_OVERFLOW ? le64_to_cpu(time) : 0)
638638

639+
u64 cxl_trace_hpa(struct cxl_region *cxlr, struct cxl_memdev *memdev, u64 dpa);
640+
639641
TRACE_EVENT(cxl_poison,
640642

641643
TP_PROTO(struct cxl_memdev *cxlmd, struct cxl_region *region,
@@ -651,6 +653,7 @@ TRACE_EVENT(cxl_poison,
651653
__field(u8, trace_type)
652654
__string(region, region)
653655
__field(u64, overflow_ts)
656+
__field(u64, hpa)
654657
__field(u64, dpa)
655658
__field(u32, dpa_length)
656659
__array(char, uuid, 16)
@@ -671,21 +674,25 @@ TRACE_EVENT(cxl_poison,
671674
if (region) {
672675
__assign_str(region, dev_name(&region->dev));
673676
memcpy(__entry->uuid, &region->params.uuid, 16);
677+
__entry->hpa = cxl_trace_hpa(region, cxlmd,
678+
__entry->dpa);
674679
} else {
675680
__assign_str(region, "");
676681
memset(__entry->uuid, 0, 16);
682+
__entry->hpa = ULLONG_MAX;
677683
}
678684
),
679685

680686
TP_printk("memdev=%s host=%s serial=%lld trace_type=%s region=%s " \
681-
"region_uuid=%pU dpa=0x%llx dpa_length=0x%x source=%s " \
682-
"flags=%s overflow_time=%llu",
687+
"region_uuid=%pU hpa=0x%llx dpa=0x%llx dpa_length=0x%x " \
688+
"source=%s flags=%s overflow_time=%llu",
683689
__get_str(memdev),
684690
__get_str(host),
685691
__entry->serial,
686692
show_poison_trace_type(__entry->trace_type),
687693
__get_str(region),
688694
__entry->uuid,
695+
__entry->hpa,
689696
__entry->dpa,
690697
__entry->dpa_length,
691698
show_poison_source(__entry->source),

0 commit comments

Comments
 (0)