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+
7090struct 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+
80289static 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+
631855static 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
715945static struct attribute * cxl_mock_mem_attrs [] = {
716946 & dev_attr_security_lock .attr ,
947+ & dev_attr_event_trigger .attr ,
717948 NULL
718949};
719950ATTRIBUTE_GROUPS (cxl_mock_mem );
0 commit comments