2121#include <linux/nmi.h>
2222#include <linux/delay.h>
2323#include <linux/mm.h>
24+ #include <linux/platform_device.h>
2425#include <asm/unaligned.h>
2526
2627#include "apei-internal.h"
3637#define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \
3738 ACPI_EINJ_MEMORY_UNCORRECTABLE | \
3839 ACPI_EINJ_MEMORY_FATAL)
40+ #define CXL_ERROR_MASK (ACPI_EINJ_CXL_CACHE_CORRECTABLE | \
41+ ACPI_EINJ_CXL_CACHE_UNCORRECTABLE | \
42+ ACPI_EINJ_CXL_CACHE_FATAL | \
43+ ACPI_EINJ_CXL_MEM_CORRECTABLE | \
44+ ACPI_EINJ_CXL_MEM_UNCORRECTABLE | \
45+ ACPI_EINJ_CXL_MEM_FATAL)
3946
4047/*
4148 * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action.
@@ -137,6 +144,11 @@ static struct apei_exec_ins_type einj_ins_type[] = {
137144 */
138145static DEFINE_MUTEX (einj_mutex );
139146
147+ /*
148+ * Exported APIs use this flag to exit early if einj_probe() failed.
149+ */
150+ bool einj_initialized __ro_after_init ;
151+
140152static void * einj_param ;
141153
142154static void einj_exec_ctx_init (struct apei_exec_context * ctx )
@@ -160,7 +172,7 @@ static int __einj_get_available_error_type(u32 *type)
160172}
161173
162174/* Get error injection capabilities of the platform */
163- static int einj_get_available_error_type (u32 * type )
175+ int einj_get_available_error_type (u32 * type )
164176{
165177 int rc ;
166178
@@ -530,8 +542,8 @@ static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
530542}
531543
532544/* Inject the specified hardware error */
533- static int einj_error_inject (u32 type , u32 flags , u64 param1 , u64 param2 ,
534- u64 param3 , u64 param4 )
545+ int einj_error_inject (u32 type , u32 flags , u64 param1 , u64 param2 , u64 param3 ,
546+ u64 param4 )
535547{
536548 int rc ;
537549 u64 base_addr , size ;
@@ -554,8 +566,17 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
554566 if (type & ACPI5_VENDOR_BIT ) {
555567 if (vendor_flags != SETWA_FLAGS_MEM )
556568 goto inject ;
557- } else if (!(type & MEM_ERROR_MASK ) && !(flags & SETWA_FLAGS_MEM ))
569+ } else if (!(type & MEM_ERROR_MASK ) && !(flags & SETWA_FLAGS_MEM )) {
558570 goto inject ;
571+ }
572+
573+ /*
574+ * Injections targeting a CXL 1.0/1.1 port have to be injected
575+ * via the einj_cxl_rch_error_inject() path as that does the proper
576+ * validation of the given RCRB base (MMIO) address.
577+ */
578+ if (einj_is_cxl_error_type (type ) && (flags & SETWA_FLAGS_MEM ))
579+ return - EINVAL ;
559580
560581 /*
561582 * Disallow crazy address masks that give BIOS leeway to pick
@@ -587,6 +608,21 @@ static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,
587608 return rc ;
588609}
589610
611+ int einj_cxl_rch_error_inject (u32 type , u32 flags , u64 param1 , u64 param2 ,
612+ u64 param3 , u64 param4 )
613+ {
614+ int rc ;
615+
616+ if (!(einj_is_cxl_error_type (type ) && (flags & SETWA_FLAGS_MEM )))
617+ return - EINVAL ;
618+
619+ mutex_lock (& einj_mutex );
620+ rc = __einj_error_inject (type , flags , param1 , param2 , param3 , param4 );
621+ mutex_unlock (& einj_mutex );
622+
623+ return rc ;
624+ }
625+
590626static u32 error_type ;
591627static u32 error_flags ;
592628static u64 error_param1 ;
@@ -607,12 +643,6 @@ static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
607643 { BIT (9 ), "Platform Correctable" },
608644 { BIT (10 ), "Platform Uncorrectable non-fatal" },
609645 { BIT (11 ), "Platform Uncorrectable fatal" },
610- { BIT (12 ), "CXL.cache Protocol Correctable" },
611- { BIT (13 ), "CXL.cache Protocol Uncorrectable non-fatal" },
612- { BIT (14 ), "CXL.cache Protocol Uncorrectable fatal" },
613- { BIT (15 ), "CXL.mem Protocol Correctable" },
614- { BIT (16 ), "CXL.mem Protocol Uncorrectable non-fatal" },
615- { BIT (17 ), "CXL.mem Protocol Uncorrectable fatal" },
616646 { BIT (31 ), "Vendor Defined Error Types" },
617647};
618648
@@ -641,22 +671,26 @@ static int error_type_get(void *data, u64 *val)
641671 return 0 ;
642672}
643673
644- static int error_type_set ( void * data , u64 val )
674+ bool einj_is_cxl_error_type ( u64 type )
645675{
676+ return (type & CXL_ERROR_MASK ) && (!(type & ACPI5_VENDOR_BIT ));
677+ }
678+
679+ int einj_validate_error_type (u64 type )
680+ {
681+ u32 tval , vendor , available_error_type = 0 ;
646682 int rc ;
647- u32 available_error_type = 0 ;
648- u32 tval , vendor ;
649683
650684 /* Only low 32 bits for error type are valid */
651- if (val & GENMASK_ULL (63 , 32 ))
685+ if (type & GENMASK_ULL (63 , 32 ))
652686 return - EINVAL ;
653687
654688 /*
655689 * Vendor defined types have 0x80000000 bit set, and
656690 * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE
657691 */
658- vendor = val & ACPI5_VENDOR_BIT ;
659- tval = val & 0x7fffffff ;
692+ vendor = type & ACPI5_VENDOR_BIT ;
693+ tval = type & GENMASK ( 30 , 0 ) ;
660694
661695 /* Only one error type can be specified */
662696 if (tval & (tval - 1 ))
@@ -665,9 +699,21 @@ static int error_type_set(void *data, u64 val)
665699 rc = einj_get_available_error_type (& available_error_type );
666700 if (rc )
667701 return rc ;
668- if (!(val & available_error_type ))
702+ if (!(type & available_error_type ))
669703 return - EINVAL ;
670704 }
705+
706+ return 0 ;
707+ }
708+
709+ static int error_type_set (void * data , u64 val )
710+ {
711+ int rc ;
712+
713+ rc = einj_validate_error_type (val );
714+ if (rc )
715+ return rc ;
716+
671717 error_type = val ;
672718
673719 return 0 ;
@@ -703,21 +749,21 @@ static int einj_check_table(struct acpi_table_einj *einj_tab)
703749 return 0 ;
704750}
705751
706- static int __init einj_init ( void )
752+ static int __init einj_probe ( struct platform_device * pdev )
707753{
708754 int rc ;
709755 acpi_status status ;
710756 struct apei_exec_context ctx ;
711757
712758 if (acpi_disabled ) {
713- pr_info ("ACPI disabled.\n" );
759+ pr_debug ("ACPI disabled.\n" );
714760 return - ENODEV ;
715761 }
716762
717763 status = acpi_get_table (ACPI_SIG_EINJ , 0 ,
718764 (struct acpi_table_header * * )& einj_tab );
719765 if (status == AE_NOT_FOUND ) {
720- pr_warn ("EINJ table not found.\n" );
766+ pr_debug ("EINJ table not found.\n" );
721767 return - ENODEV ;
722768 } else if (ACPI_FAILURE (status )) {
723769 pr_err ("Failed to get EINJ table: %s\n" ,
@@ -805,7 +851,7 @@ static int __init einj_init(void)
805851 return rc ;
806852}
807853
808- static void __exit einj_exit ( void )
854+ static void __exit einj_remove ( struct platform_device * pdev )
809855{
810856 struct apei_exec_context ctx ;
811857
@@ -826,6 +872,40 @@ static void __exit einj_exit(void)
826872 acpi_put_table ((struct acpi_table_header * )einj_tab );
827873}
828874
875+ static struct platform_device * einj_dev ;
876+ static struct platform_driver einj_driver = {
877+ .remove_new = einj_remove ,
878+ .driver = {
879+ .name = "acpi-einj" ,
880+ },
881+ };
882+
883+ static int __init einj_init (void )
884+ {
885+ struct platform_device_info einj_dev_info = {
886+ .name = "acpi-einj" ,
887+ .id = -1 ,
888+ };
889+ int rc ;
890+
891+ einj_dev = platform_device_register_full (& einj_dev_info );
892+ if (IS_ERR (einj_dev ))
893+ return PTR_ERR (einj_dev );
894+
895+ rc = platform_driver_probe (& einj_driver , einj_probe );
896+ einj_initialized = rc == 0 ;
897+
898+ return 0 ;
899+ }
900+
901+ static void __exit einj_exit (void )
902+ {
903+ if (einj_initialized )
904+ platform_driver_unregister (& einj_driver );
905+
906+ platform_device_del (einj_dev );
907+ }
908+
829909module_init (einj_init );
830910module_exit (einj_exit );
831911
0 commit comments