9
9
#include <linux/bits.h>
10
10
#include <cxlmem.h>
11
11
12
+ #include "trace.h"
13
+
12
14
#define LSA_SIZE SZ_128K
13
15
#define DEV_SIZE SZ_2G
14
16
#define EFFECT (x ) (1U << x)
@@ -67,16 +69,223 @@ static struct {
67
69
68
70
#define PASS_TRY_LIMIT 3
69
71
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
+
70
90
struct cxl_mockmem_data {
71
91
void * lsa ;
72
92
u32 security_state ;
73
93
u8 user_pass [NVDIMM_PASSPHRASE_LEN ];
74
94
u8 master_pass [NVDIMM_PASSPHRASE_LEN ];
75
95
int user_limit ;
76
96
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
+ };
77
267
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 },
78
278
};
79
279
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
+
80
289
static int mock_gsl (struct cxl_mbox_cmd * cmd )
81
290
{
82
291
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 *
582
791
case CXL_MBOX_OP_GET_PARTITION_INFO :
583
792
rc = mock_partition_info (cxlds , cmd );
584
793
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 ;
585
800
case CXL_MBOX_OP_SET_LSA :
586
801
rc = mock_set_lsa (cxlds , cmd );
587
802
break ;
@@ -628,6 +843,15 @@ static bool is_rcd(struct platform_device *pdev)
628
843
return !!id -> driver_data ;
629
844
}
630
845
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
+
631
855
static int cxl_mock_mem_probe (struct platform_device * pdev )
632
856
{
633
857
struct device * dev = & pdev -> dev ;
@@ -655,6 +879,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
655
879
cxlds -> serial = pdev -> id ;
656
880
cxlds -> mbox_send = cxl_mock_mbox_send ;
657
881
cxlds -> payload_size = SZ_4K ;
882
+ cxlds -> event .buf = (struct cxl_get_event_payload * ) mdata -> event_buf ;
658
883
if (is_rcd (pdev )) {
659
884
cxlds -> rcd = true;
660
885
cxlds -> component_reg_phys = CXL_RESOURCE_NONE ;
@@ -672,10 +897,15 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
672
897
if (rc )
673
898
return rc ;
674
899
900
+ mdata -> mes .cxlds = cxlds ;
901
+ cxl_mock_add_event_logs (& mdata -> mes );
902
+
675
903
cxlmd = devm_cxl_add_memdev (cxlds );
676
904
if (IS_ERR (cxlmd ))
677
905
return PTR_ERR (cxlmd );
678
906
907
+ cxl_mem_get_event_records (cxlds , CXLDEV_EVENT_STATUS_ALL );
908
+
679
909
return 0 ;
680
910
}
681
911
@@ -714,6 +944,7 @@ static DEVICE_ATTR_RW(security_lock);
714
944
715
945
static struct attribute * cxl_mock_mem_attrs [] = {
716
946
& dev_attr_security_lock .attr ,
947
+ & dev_attr_event_trigger .attr ,
717
948
NULL
718
949
};
719
950
ATTRIBUTE_GROUPS (cxl_mock_mem );
0 commit comments