Skip to content

Commit d1dca85

Browse files
weiny2djbw
authored andcommitted
cxl/test: Add generic mock events
Facilitate testing basic Get/Clear Event functionality by creating multiple logs and generic events with made up UUID's. Data is completely made up with data patterns which should be easy to spot in trace output. A single sysfs entry resets the event data and triggers collecting the events for testing. Test traces are easy to obtain with a small script such as this: #!/bin/bash -x devices=`find /sys/devices/platform -name cxl_mem*` # Turn on tracing echo "" > /sys/kernel/tracing/trace echo 1 > /sys/kernel/tracing/events/cxl/enable echo 1 > /sys/kernel/tracing/tracing_on # Generate fake interrupt for device in $devices; do echo 1 > $device/event_trigger done # Turn off tracing and report events echo 0 > /sys/kernel/tracing/tracing_on cat /sys/kernel/tracing/trace Reviewed-by: Dan Williams <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Signed-off-by: Ira Weiny <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dan Williams <[email protected]>
1 parent 95b4947 commit d1dca85

File tree

2 files changed

+232
-1
lines changed

2 files changed

+232
-1
lines changed

tools/testing/cxl/test/Kbuild

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0
2-
ccflags-y := -I$(srctree)/drivers/cxl/
2+
ccflags-y := -I$(srctree)/drivers/cxl/ -I$(srctree)/drivers/cxl/core
33

44
obj-m += cxl_test.o
55
obj-m += cxl_mock.o

tools/testing/cxl/test/mem.c

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <linux/bits.h>
1010
#include <cxlmem.h>
1111

12+
#include "trace.h"
13+
1214
#define LSA_SIZE SZ_128K
1315
#define DEV_SIZE SZ_2G
1416
#define EFFECT(x) (1U << x)
@@ -67,16 +69,223 @@ static struct {
6769

6870
#define PASS_TRY_LIMIT 3
6971

72+
#define CXL_TEST_EVENT_CNT_MAX 15
73+
74+
/* Set a number of events to return at a time for simulation. */
75+
#define CXL_TEST_EVENT_CNT 3
76+
77+
struct mock_event_log {
78+
u16 clear_idx;
79+
u16 cur_idx;
80+
u16 nr_events;
81+
struct cxl_event_record_raw *events[CXL_TEST_EVENT_CNT_MAX];
82+
};
83+
84+
struct mock_event_store {
85+
struct cxl_dev_state *cxlds;
86+
struct mock_event_log mock_logs[CXL_EVENT_TYPE_MAX];
87+
u32 ev_status;
88+
};
89+
7090
struct cxl_mockmem_data {
7191
void *lsa;
7292
u32 security_state;
7393
u8 user_pass[NVDIMM_PASSPHRASE_LEN];
7494
u8 master_pass[NVDIMM_PASSPHRASE_LEN];
7595
int user_limit;
7696
int master_limit;
97+
struct mock_event_store mes;
98+
u8 event_buf[SZ_4K];
99+
};
100+
101+
static struct mock_event_log *event_find_log(struct device *dev, int log_type)
102+
{
103+
struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
104+
105+
if (log_type >= CXL_EVENT_TYPE_MAX)
106+
return NULL;
107+
return &mdata->mes.mock_logs[log_type];
108+
}
109+
110+
static struct cxl_event_record_raw *event_get_current(struct mock_event_log *log)
111+
{
112+
return log->events[log->cur_idx];
113+
}
114+
115+
static void event_reset_log(struct mock_event_log *log)
116+
{
117+
log->cur_idx = 0;
118+
log->clear_idx = 0;
119+
}
120+
121+
/* Handle can never be 0 use 1 based indexing for handle */
122+
static u16 event_get_clear_handle(struct mock_event_log *log)
123+
{
124+
return log->clear_idx + 1;
125+
}
126+
127+
/* Handle can never be 0 use 1 based indexing for handle */
128+
static __le16 event_get_cur_event_handle(struct mock_event_log *log)
129+
{
130+
u16 cur_handle = log->cur_idx + 1;
131+
132+
return cpu_to_le16(cur_handle);
133+
}
134+
135+
static bool event_log_empty(struct mock_event_log *log)
136+
{
137+
return log->cur_idx == log->nr_events;
138+
}
139+
140+
static void mes_add_event(struct mock_event_store *mes,
141+
enum cxl_event_log_type log_type,
142+
struct cxl_event_record_raw *event)
143+
{
144+
struct mock_event_log *log;
145+
146+
if (WARN_ON(log_type >= CXL_EVENT_TYPE_MAX))
147+
return;
148+
149+
log = &mes->mock_logs[log_type];
150+
if (WARN_ON(log->nr_events >= CXL_TEST_EVENT_CNT_MAX))
151+
return;
152+
153+
log->events[log->nr_events] = event;
154+
log->nr_events++;
155+
}
156+
157+
static int mock_get_event(struct cxl_dev_state *cxlds,
158+
struct cxl_mbox_cmd *cmd)
159+
{
160+
struct cxl_get_event_payload *pl;
161+
struct mock_event_log *log;
162+
u8 log_type;
163+
int i;
164+
165+
if (cmd->size_in != sizeof(log_type))
166+
return -EINVAL;
167+
168+
if (cmd->size_out < struct_size(pl, records, CXL_TEST_EVENT_CNT))
169+
return -EINVAL;
170+
171+
log_type = *((u8 *)cmd->payload_in);
172+
if (log_type >= CXL_EVENT_TYPE_MAX)
173+
return -EINVAL;
174+
175+
memset(cmd->payload_out, 0, cmd->size_out);
176+
177+
log = event_find_log(cxlds->dev, log_type);
178+
if (!log || event_log_empty(log))
179+
return 0;
180+
181+
pl = cmd->payload_out;
182+
183+
for (i = 0; i < CXL_TEST_EVENT_CNT && !event_log_empty(log); i++) {
184+
memcpy(&pl->records[i], event_get_current(log),
185+
sizeof(pl->records[i]));
186+
pl->records[i].hdr.handle = event_get_cur_event_handle(log);
187+
log->cur_idx++;
188+
}
189+
190+
pl->record_count = cpu_to_le16(i);
191+
if (!event_log_empty(log))
192+
pl->flags |= CXL_GET_EVENT_FLAG_MORE_RECORDS;
193+
194+
return 0;
195+
}
196+
197+
static int mock_clear_event(struct cxl_dev_state *cxlds,
198+
struct cxl_mbox_cmd *cmd)
199+
{
200+
struct cxl_mbox_clear_event_payload *pl = cmd->payload_in;
201+
struct mock_event_log *log;
202+
u8 log_type = pl->event_log;
203+
u16 handle;
204+
int nr;
205+
206+
if (log_type >= CXL_EVENT_TYPE_MAX)
207+
return -EINVAL;
208+
209+
log = event_find_log(cxlds->dev, log_type);
210+
if (!log)
211+
return 0; /* No mock data in this log */
212+
213+
/*
214+
* This check is technically not invalid per the specification AFAICS.
215+
* (The host could 'guess' handles and clear them in order).
216+
* However, this is not good behavior for the host so test it.
217+
*/
218+
if (log->clear_idx + pl->nr_recs > log->cur_idx) {
219+
dev_err(cxlds->dev,
220+
"Attempting to clear more events than returned!\n");
221+
return -EINVAL;
222+
}
223+
224+
/* Check handle order prior to clearing events */
225+
for (nr = 0, handle = event_get_clear_handle(log);
226+
nr < pl->nr_recs;
227+
nr++, handle++) {
228+
if (handle != le16_to_cpu(pl->handles[nr])) {
229+
dev_err(cxlds->dev, "Clearing events out of order\n");
230+
return -EINVAL;
231+
}
232+
}
233+
234+
/* Clear events */
235+
log->clear_idx += pl->nr_recs;
236+
return 0;
237+
}
238+
239+
static void cxl_mock_event_trigger(struct device *dev)
240+
{
241+
struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
242+
struct mock_event_store *mes = &mdata->mes;
243+
int i;
244+
245+
for (i = CXL_EVENT_TYPE_INFO; i < CXL_EVENT_TYPE_MAX; i++) {
246+
struct mock_event_log *log;
247+
248+
log = event_find_log(dev, i);
249+
if (log)
250+
event_reset_log(log);
251+
}
252+
253+
cxl_mem_get_event_records(mes->cxlds, mes->ev_status);
254+
}
255+
256+
struct cxl_event_record_raw maint_needed = {
257+
.hdr = {
258+
.id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB,
259+
0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
260+
.length = sizeof(struct cxl_event_record_raw),
261+
.flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED,
262+
/* .handle = Set dynamically */
263+
.related_handle = cpu_to_le16(0xa5b6),
264+
},
265+
.data = { 0xDE, 0xAD, 0xBE, 0xEF },
266+
};
77267

268+
struct cxl_event_record_raw hardware_replace = {
269+
.hdr = {
270+
.id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E,
271+
0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
272+
.length = sizeof(struct cxl_event_record_raw),
273+
.flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE,
274+
/* .handle = Set dynamically */
275+
.related_handle = cpu_to_le16(0xb6a5),
276+
},
277+
.data = { 0xDE, 0xAD, 0xBE, 0xEF },
78278
};
79279

280+
static void cxl_mock_add_event_logs(struct mock_event_store *mes)
281+
{
282+
mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed);
283+
mes->ev_status |= CXLDEV_EVENT_STATUS_INFO;
284+
285+
mes_add_event(mes, CXL_EVENT_TYPE_FATAL, &hardware_replace);
286+
mes->ev_status |= CXLDEV_EVENT_STATUS_FATAL;
287+
}
288+
80289
static int mock_gsl(struct cxl_mbox_cmd *cmd)
81290
{
82291
if (cmd->size_out < sizeof(mock_gsl_payload))
@@ -582,6 +791,12 @@ static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *
582791
case CXL_MBOX_OP_GET_PARTITION_INFO:
583792
rc = mock_partition_info(cxlds, cmd);
584793
break;
794+
case CXL_MBOX_OP_GET_EVENT_RECORD:
795+
rc = mock_get_event(cxlds, cmd);
796+
break;
797+
case CXL_MBOX_OP_CLEAR_EVENT_RECORD:
798+
rc = mock_clear_event(cxlds, cmd);
799+
break;
585800
case CXL_MBOX_OP_SET_LSA:
586801
rc = mock_set_lsa(cxlds, cmd);
587802
break;
@@ -628,6 +843,15 @@ static bool is_rcd(struct platform_device *pdev)
628843
return !!id->driver_data;
629844
}
630845

846+
static ssize_t event_trigger_store(struct device *dev,
847+
struct device_attribute *attr,
848+
const char *buf, size_t count)
849+
{
850+
cxl_mock_event_trigger(dev);
851+
return count;
852+
}
853+
static DEVICE_ATTR_WO(event_trigger);
854+
631855
static int cxl_mock_mem_probe(struct platform_device *pdev)
632856
{
633857
struct device *dev = &pdev->dev;
@@ -655,6 +879,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
655879
cxlds->serial = pdev->id;
656880
cxlds->mbox_send = cxl_mock_mbox_send;
657881
cxlds->payload_size = SZ_4K;
882+
cxlds->event.buf = (struct cxl_get_event_payload *) mdata->event_buf;
658883
if (is_rcd(pdev)) {
659884
cxlds->rcd = true;
660885
cxlds->component_reg_phys = CXL_RESOURCE_NONE;
@@ -672,10 +897,15 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
672897
if (rc)
673898
return rc;
674899

900+
mdata->mes.cxlds = cxlds;
901+
cxl_mock_add_event_logs(&mdata->mes);
902+
675903
cxlmd = devm_cxl_add_memdev(cxlds);
676904
if (IS_ERR(cxlmd))
677905
return PTR_ERR(cxlmd);
678906

907+
cxl_mem_get_event_records(cxlds, CXLDEV_EVENT_STATUS_ALL);
908+
679909
return 0;
680910
}
681911

@@ -714,6 +944,7 @@ static DEVICE_ATTR_RW(security_lock);
714944

715945
static struct attribute *cxl_mock_mem_attrs[] = {
716946
&dev_attr_security_lock.attr,
947+
&dev_attr_event_trigger.attr,
717948
NULL
718949
};
719950
ATTRIBUTE_GROUPS(cxl_mock_mem);

0 commit comments

Comments
 (0)