@@ -294,10 +294,99 @@ static int cat_run_test(const struct resctrl_test *test, const struct user_param
294294 return ret ;
295295}
296296
297+ static int noncont_cat_run_test (const struct resctrl_test * test ,
298+ const struct user_params * uparams )
299+ {
300+ unsigned long full_cache_mask , cont_mask , noncont_mask ;
301+ unsigned int eax , ebx , ecx , edx , sparse_masks ;
302+ int bit_center , ret ;
303+ char schemata [64 ];
304+
305+ /* Check to compare sparse_masks content to CPUID output. */
306+ ret = resource_info_unsigned_get (test -> resource , "sparse_masks" , & sparse_masks );
307+ if (ret )
308+ return ret ;
309+
310+ if (!strcmp (test -> resource , "L3" ))
311+ __cpuid_count (0x10 , 1 , eax , ebx , ecx , edx );
312+ else if (!strcmp (test -> resource , "L2" ))
313+ __cpuid_count (0x10 , 2 , eax , ebx , ecx , edx );
314+ else
315+ return - EINVAL ;
316+
317+ if (sparse_masks != ((ecx >> 3 ) & 1 )) {
318+ ksft_print_msg ("CPUID output doesn't match 'sparse_masks' file content!\n" );
319+ return 1 ;
320+ }
321+
322+ /* Write checks initialization. */
323+ ret = get_full_cbm (test -> resource , & full_cache_mask );
324+ if (ret < 0 )
325+ return ret ;
326+ bit_center = count_bits (full_cache_mask ) / 2 ;
327+
328+ /*
329+ * The bit_center needs to be at least 3 to properly calculate the CBM
330+ * hole in the noncont_mask. If it's smaller return an error since the
331+ * cache mask is too short and that shouldn't happen.
332+ */
333+ if (bit_center < 3 )
334+ return - EINVAL ;
335+ cont_mask = full_cache_mask >> bit_center ;
336+
337+ /* Contiguous mask write check. */
338+ snprintf (schemata , sizeof (schemata ), "%lx" , cont_mask );
339+ ret = write_schemata ("" , schemata , uparams -> cpu , test -> resource );
340+ if (ret ) {
341+ ksft_print_msg ("Write of contiguous CBM failed\n" );
342+ return 1 ;
343+ }
344+
345+ /*
346+ * Non-contiguous mask write check. CBM has a 0xf hole approximately in the middle.
347+ * Output is compared with support information to catch any edge case errors.
348+ */
349+ noncont_mask = ~(0xfUL << (bit_center - 2 )) & full_cache_mask ;
350+ snprintf (schemata , sizeof (schemata ), "%lx" , noncont_mask );
351+ ret = write_schemata ("" , schemata , uparams -> cpu , test -> resource );
352+ if (ret && sparse_masks )
353+ ksft_print_msg ("Non-contiguous CBMs supported but write of non-contiguous CBM failed\n" );
354+ else if (ret && !sparse_masks )
355+ ksft_print_msg ("Non-contiguous CBMs not supported and write of non-contiguous CBM failed as expected\n" );
356+ else if (!ret && !sparse_masks )
357+ ksft_print_msg ("Non-contiguous CBMs not supported but write of non-contiguous CBM succeeded\n" );
358+
359+ return !ret == !sparse_masks ;
360+ }
361+
362+ static bool noncont_cat_feature_check (const struct resctrl_test * test )
363+ {
364+ if (!resctrl_resource_exists (test -> resource ))
365+ return false;
366+
367+ return resource_info_file_exists (test -> resource , "sparse_masks" );
368+ }
369+
297370struct resctrl_test l3_cat_test = {
298371 .name = "L3_CAT" ,
299372 .group = "CAT" ,
300373 .resource = "L3" ,
301374 .feature_check = test_resource_feature_check ,
302375 .run_test = cat_run_test ,
303376};
377+
378+ struct resctrl_test l3_noncont_cat_test = {
379+ .name = "L3_NONCONT_CAT" ,
380+ .group = "CAT" ,
381+ .resource = "L3" ,
382+ .feature_check = noncont_cat_feature_check ,
383+ .run_test = noncont_cat_run_test ,
384+ };
385+
386+ struct resctrl_test l2_noncont_cat_test = {
387+ .name = "L2_NONCONT_CAT" ,
388+ .group = "CAT" ,
389+ .resource = "L2" ,
390+ .feature_check = noncont_cat_feature_check ,
391+ .run_test = noncont_cat_run_test ,
392+ };
0 commit comments