54
54
#include <asm/cpu_device_id.h>
55
55
#include <asm/mce.h>
56
56
57
+ #include "../debugfs.h"
58
+
57
59
#define INVALID_CPU UINT_MAX
58
60
59
61
/* Validation Bits */
@@ -116,6 +118,9 @@ static u64 *spa_entries;
116
118
117
119
#define INVALID_SPA ~0ULL
118
120
121
+ static struct dentry * fmpm_dfs_dir ;
122
+ static struct dentry * fmpm_dfs_entries ;
123
+
119
124
#define CPER_CREATOR_FMP \
120
125
GUID_INIT(0xcd5c2993, 0xf4b2, 0x41b2, 0xb5, 0xd4, 0xf9, 0xc3, \
121
126
0xa0, 0x33, 0x08, 0x75)
@@ -152,6 +157,11 @@ static unsigned int spa_nr_entries;
152
157
* Protect the local records cache in fru_records and prevent concurrent
153
158
* writes to storage. This is only needed after init once notifier block
154
159
* registration is done.
160
+ *
161
+ * The majority of a record is fixed at module init and will not change
162
+ * during run time. The entries within a record will be updated as new
163
+ * errors are reported. The mutex should be held whenever the entries are
164
+ * accessed during run time.
155
165
*/
156
166
static DEFINE_MUTEX (fmpm_update_mutex );
157
167
@@ -815,6 +825,124 @@ static int allocate_records(void)
815
825
return ret ;
816
826
}
817
827
828
+ static void * fmpm_start (struct seq_file * f , loff_t * pos )
829
+ {
830
+ if (* pos >= (spa_nr_entries + 1 ))
831
+ return NULL ;
832
+ return pos ;
833
+ }
834
+
835
+ static void * fmpm_next (struct seq_file * f , void * data , loff_t * pos )
836
+ {
837
+ if (++ (* pos ) >= (spa_nr_entries + 1 ))
838
+ return NULL ;
839
+ return pos ;
840
+ }
841
+
842
+ static void fmpm_stop (struct seq_file * f , void * data )
843
+ {
844
+ }
845
+
846
+ #define SHORT_WIDTH 8
847
+ #define U64_WIDTH 18
848
+ #define TIMESTAMP_WIDTH 19
849
+ #define LONG_WIDTH 24
850
+ #define U64_PAD (LONG_WIDTH - U64_WIDTH)
851
+ #define TS_PAD (LONG_WIDTH - TIMESTAMP_WIDTH)
852
+ static int fmpm_show (struct seq_file * f , void * data )
853
+ {
854
+ unsigned int fru_idx , entry , spa_entry , line ;
855
+ struct cper_fru_poison_desc * fpd ;
856
+ struct fru_rec * rec ;
857
+
858
+ line = * (loff_t * )data ;
859
+ if (line == 0 ) {
860
+ seq_printf (f , "%-*s" , SHORT_WIDTH , "fru_idx" );
861
+ seq_printf (f , "%-*s" , LONG_WIDTH , "fru_id" );
862
+ seq_printf (f , "%-*s" , SHORT_WIDTH , "entry" );
863
+ seq_printf (f , "%-*s" , LONG_WIDTH , "timestamp" );
864
+ seq_printf (f , "%-*s" , LONG_WIDTH , "hw_id" );
865
+ seq_printf (f , "%-*s" , LONG_WIDTH , "addr" );
866
+ seq_printf (f , "%-*s" , LONG_WIDTH , "spa" );
867
+ goto out_newline ;
868
+ }
869
+
870
+ spa_entry = line - 1 ;
871
+ fru_idx = spa_entry / max_nr_entries ;
872
+ entry = spa_entry % max_nr_entries ;
873
+
874
+ rec = fru_records [fru_idx ];
875
+ if (!rec )
876
+ goto out ;
877
+
878
+ seq_printf (f , "%-*u" , SHORT_WIDTH , fru_idx );
879
+ seq_printf (f , "0x%016llx%-*s" , rec -> fmp .fru_id , U64_PAD , "" );
880
+ seq_printf (f , "%-*u" , SHORT_WIDTH , entry );
881
+
882
+ mutex_lock (& fmpm_update_mutex );
883
+
884
+ if (entry >= rec -> fmp .nr_entries ) {
885
+ seq_printf (f , "%-*s" , LONG_WIDTH , "*" );
886
+ seq_printf (f , "%-*s" , LONG_WIDTH , "*" );
887
+ seq_printf (f , "%-*s" , LONG_WIDTH , "*" );
888
+ seq_printf (f , "%-*s" , LONG_WIDTH , "*" );
889
+ goto out_unlock ;
890
+ }
891
+
892
+ fpd = & rec -> entries [entry ];
893
+
894
+ seq_printf (f , "%ptT%-*s" , & fpd -> timestamp , TS_PAD , "" );
895
+ seq_printf (f , "0x%016llx%-*s" , fpd -> hw_id , U64_PAD , "" );
896
+ seq_printf (f , "0x%016llx%-*s" , fpd -> addr , U64_PAD , "" );
897
+
898
+ if (spa_entries [spa_entry ] == INVALID_SPA )
899
+ seq_printf (f , "%-*s" , LONG_WIDTH , "*" );
900
+ else
901
+ seq_printf (f , "0x%016llx%-*s" , spa_entries [spa_entry ], U64_PAD , "" );
902
+
903
+ out_unlock :
904
+ mutex_unlock (& fmpm_update_mutex );
905
+ out_newline :
906
+ seq_putc (f , '\n' );
907
+ out :
908
+ return 0 ;
909
+ }
910
+
911
+ static const struct seq_operations fmpm_seq_ops = {
912
+ .start = fmpm_start ,
913
+ .next = fmpm_next ,
914
+ .stop = fmpm_stop ,
915
+ .show = fmpm_show ,
916
+ };
917
+
918
+ static int fmpm_open (struct inode * inode , struct file * file )
919
+ {
920
+ return seq_open (file , & fmpm_seq_ops );
921
+ }
922
+
923
+ static const struct file_operations fmpm_fops = {
924
+ .open = fmpm_open ,
925
+ .release = seq_release ,
926
+ .read = seq_read ,
927
+ .llseek = seq_lseek ,
928
+ };
929
+
930
+ static void setup_debugfs (void )
931
+ {
932
+ struct dentry * dfs = ras_get_debugfs_root ();
933
+
934
+ if (!dfs )
935
+ return ;
936
+
937
+ fmpm_dfs_dir = debugfs_create_dir ("fmpm" , dfs );
938
+ if (!fmpm_dfs_dir )
939
+ return ;
940
+
941
+ fmpm_dfs_entries = debugfs_create_file ("entries" , 0400 , fmpm_dfs_dir , NULL , & fmpm_fops );
942
+ if (!fmpm_dfs_entries )
943
+ debugfs_remove (fmpm_dfs_dir );
944
+ }
945
+
818
946
static const struct x86_cpu_id fmpm_cpuids [] = {
819
947
X86_MATCH_VENDOR_FAM (AMD , 0x19 , NULL ),
820
948
{ }
@@ -856,6 +984,8 @@ static int __init fru_mem_poison_init(void)
856
984
if (ret )
857
985
goto out_free ;
858
986
987
+ setup_debugfs ();
988
+
859
989
retire_mem_records ();
860
990
861
991
mce_register_decode_chain (& fru_mem_poison_nb );
@@ -872,6 +1002,7 @@ static int __init fru_mem_poison_init(void)
872
1002
static void __exit fru_mem_poison_exit (void )
873
1003
{
874
1004
mce_unregister_decode_chain (& fru_mem_poison_nb );
1005
+ debugfs_remove (fmpm_dfs_dir );
875
1006
free_records ();
876
1007
}
877
1008
0 commit comments