42
42
43
43
#define ECCW0_FLIP_CTRL 0x109C
44
44
#define ECCW0_FLIP0_OFFSET 0x10A0
45
+ #define ECCW0_FLIP0_BITS 31
46
+ #define ECCW0_FLIP1_OFFSET 0x10A4
45
47
#define ECCW1_FLIP_CTRL 0x10AC
46
48
#define ECCW1_FLIP0_OFFSET 0x10B0
49
+ #define ECCW1_FLIP1_OFFSET 0x10B4
47
50
#define ECCR0_CERR_STAT_OFFSET 0x10BC
48
51
#define ECCR0_CE_ADDR_LO_OFFSET 0x10C0
49
52
#define ECCR0_CE_ADDR_HI_OFFSET 0x10C4
116
119
#define XDDR_BUS_WIDTH_32 1
117
120
#define XDDR_BUS_WIDTH_16 2
118
121
119
- #define ECC_CEPOISON_MASK 0x1
120
- #define ECC_UEPOISON_MASK 0x3
121
-
122
122
#define XDDR_MAX_ROW_CNT 18
123
123
#define XDDR_MAX_COL_CNT 10
124
124
#define XDDR_MAX_RANK_CNT 2
133
133
* https://docs.xilinx.com/r/en-US/am012-versal-register-reference/PCSR_LOCK-XRAM_SLCR-Register
134
134
*/
135
135
#define PCSR_UNLOCK_VAL 0xF9E8D7C6
136
+ #define PCSR_LOCK_VAL 1
136
137
#define XDDR_ERR_TYPE_CE 0
137
138
#define XDDR_ERR_TYPE_UE 1
138
139
142
143
#define XILINX_DRAM_SIZE_12G 3
143
144
#define XILINX_DRAM_SIZE_16G 4
144
145
#define XILINX_DRAM_SIZE_32G 5
146
+ #define NUM_UE_BITPOS 2
145
147
146
148
/**
147
149
* struct ecc_error_info - ECC error log information.
@@ -479,7 +481,7 @@ static void err_callback(const u32 *payload, void *data)
479
481
writel (regval , priv -> ddrmc_baseaddr + XDDR_ISR_OFFSET );
480
482
481
483
/* Lock the PCSR registers */
482
- writel (1 , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
484
+ writel (PCSR_LOCK_VAL , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
483
485
edac_dbg (3 , "Total error count CE %d UE %d\n" ,
484
486
priv -> ce_cnt , priv -> ue_cnt );
485
487
}
@@ -650,7 +652,7 @@ static void enable_intr(struct edac_priv *priv)
650
652
writel (XDDR_IRQ_UE_MASK ,
651
653
priv -> ddrmc_baseaddr + XDDR_IRQ1_EN_OFFSET );
652
654
/* Lock the PCSR registers */
653
- writel (1 , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
655
+ writel (PCSR_LOCK_VAL , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
654
656
}
655
657
656
658
static void disable_intr (struct edac_priv * priv )
@@ -663,7 +665,7 @@ static void disable_intr(struct edac_priv *priv)
663
665
priv -> ddrmc_baseaddr + XDDR_IRQ_DIS_OFFSET );
664
666
665
667
/* Lock the PCSR registers */
666
- writel (1 , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
668
+ writel (PCSR_LOCK_VAL , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
667
669
}
668
670
669
671
#define to_mci (k ) container_of(k, struct mem_ctl_info, dev)
@@ -734,56 +736,174 @@ static void poison_setup(struct edac_priv *priv)
734
736
writel (regval , priv -> ddrmc_noc_baseaddr + XDDR_NOC_REG_ADEC15_OFFSET );
735
737
}
736
738
737
- static ssize_t xddr_inject_data_poison_store (struct mem_ctl_info * mci ,
738
- const char __user * data )
739
+ static void xddr_inject_data_ce_store (struct mem_ctl_info * mci , u8 ce_bitpos )
739
740
{
741
+ u32 ecc0_flip0 , ecc1_flip0 , ecc0_flip1 , ecc1_flip1 ;
740
742
struct edac_priv * priv = mci -> pvt_info ;
741
743
742
- writel (0 , priv -> ddrmc_baseaddr + ECCW0_FLIP0_OFFSET );
743
- writel (0 , priv -> ddrmc_baseaddr + ECCW1_FLIP0_OFFSET );
744
-
745
- if (strncmp (data , "CE" , 2 ) == 0 ) {
746
- writel (ECC_CEPOISON_MASK , priv -> ddrmc_baseaddr +
747
- ECCW0_FLIP0_OFFSET );
748
- writel (ECC_CEPOISON_MASK , priv -> ddrmc_baseaddr +
749
- ECCW1_FLIP0_OFFSET );
744
+ if (ce_bitpos < ECCW0_FLIP0_BITS ) {
745
+ ecc0_flip0 = BIT (ce_bitpos );
746
+ ecc1_flip0 = BIT (ce_bitpos );
747
+ ecc0_flip1 = 0 ;
748
+ ecc1_flip1 = 0 ;
750
749
} else {
751
- writel (ECC_UEPOISON_MASK , priv -> ddrmc_baseaddr +
752
- ECCW0_FLIP0_OFFSET );
753
- writel (ECC_UEPOISON_MASK , priv -> ddrmc_baseaddr +
754
- ECCW1_FLIP0_OFFSET );
750
+ ce_bitpos = ce_bitpos - ECCW0_FLIP0_BITS ;
751
+ ecc0_flip1 = BIT (ce_bitpos );
752
+ ecc1_flip1 = BIT (ce_bitpos );
753
+ ecc0_flip0 = 0 ;
754
+ ecc1_flip0 = 0 ;
755
755
}
756
756
757
- /* Lock the PCSR registers */
758
- writel (1 , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
759
-
760
- return 0 ;
757
+ writel ( ecc0_flip0 , priv -> ddrmc_baseaddr + ECCW0_FLIP0_OFFSET );
758
+ writel (ecc1_flip0 , priv -> ddrmc_baseaddr + ECCW1_FLIP0_OFFSET );
759
+ writel ( ecc0_flip1 , priv -> ddrmc_baseaddr + ECCW0_FLIP1_OFFSET );
760
+ writel ( ecc1_flip1 , priv -> ddrmc_baseaddr + ECCW1_FLIP1_OFFSET ) ;
761
761
}
762
762
763
- static ssize_t inject_data_poison_store (struct file * file , const char __user * data ,
764
- size_t count , loff_t * ppos )
763
+ /*
764
+ * To inject a correctable error, the following steps are needed:
765
+ *
766
+ * - Write the correctable error bit position value:
767
+ * echo <bit_pos val> > /sys/kernel/debug/edac/<controller instance>/inject_ce
768
+ *
769
+ * poison_setup() derives the row, column, bank, group and rank and
770
+ * writes to the ADEC registers based on the address given by the user.
771
+ *
772
+ * The ADEC12 and ADEC13 are mask registers; write 0 to make sure default
773
+ * configuration is there and no addresses are masked.
774
+ *
775
+ * The row, column, bank, group and rank registers are written to the
776
+ * match ADEC bit to generate errors at the particular address. ADEC14
777
+ * and ADEC15 have the match bits.
778
+ *
779
+ * xddr_inject_data_ce_store() updates the ECC FLIP registers with the
780
+ * bits to be corrupted based on the bit position given by the user.
781
+ *
782
+ * Upon doing a read to the address the errors are injected.
783
+ */
784
+ static ssize_t inject_data_ce_store (struct file * file , const char __user * data ,
785
+ size_t count , loff_t * ppos )
765
786
{
766
787
struct device * dev = file -> private_data ;
767
788
struct mem_ctl_info * mci = to_mci (dev );
768
789
struct edac_priv * priv = mci -> pvt_info ;
790
+ u8 ce_bitpos ;
791
+ int ret ;
792
+
793
+ ret = kstrtou8_from_user (data , count , 0 , & ce_bitpos );
794
+ if (ret )
795
+ return ret ;
769
796
770
797
/* Unlock the PCSR registers */
771
798
writel (PCSR_UNLOCK_VAL , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
772
799
writel (PCSR_UNLOCK_VAL , priv -> ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET );
773
800
774
801
poison_setup (priv );
775
802
803
+ xddr_inject_data_ce_store (mci , ce_bitpos );
804
+ ret = count ;
805
+
776
806
/* Lock the PCSR registers */
777
- writel (1 , priv -> ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET );
807
+ writel (PCSR_LOCK_VAL , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
808
+ writel (PCSR_LOCK_VAL , priv -> ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET );
809
+
810
+ return ret ;
811
+ }
812
+
813
+ static const struct file_operations xddr_inject_ce_fops = {
814
+ .open = simple_open ,
815
+ .write = inject_data_ce_store ,
816
+ .llseek = generic_file_llseek ,
817
+ };
818
+
819
+ static void xddr_inject_data_ue_store (struct mem_ctl_info * mci , u32 val0 , u32 val1 )
820
+ {
821
+ struct edac_priv * priv = mci -> pvt_info ;
822
+
823
+ writel (val0 , priv -> ddrmc_baseaddr + ECCW0_FLIP0_OFFSET );
824
+ writel (val0 , priv -> ddrmc_baseaddr + ECCW0_FLIP1_OFFSET );
825
+ writel (val1 , priv -> ddrmc_baseaddr + ECCW1_FLIP1_OFFSET );
826
+ writel (val1 , priv -> ddrmc_baseaddr + ECCW1_FLIP1_OFFSET );
827
+ }
828
+
829
+ /*
830
+ * To inject an uncorrectable error, the following steps are needed:
831
+ * echo <bit_pos val> > /sys/kernel/debug/edac/<controller instance>/inject_ue
832
+ *
833
+ * poison_setup() derives the row, column, bank, group and rank and
834
+ * writes to the ADEC registers based on the address given by the user.
835
+ *
836
+ * The ADEC12 and ADEC13 are mask registers; write 0 so that none of the
837
+ * addresses are masked. The row, column, bank, group and rank registers
838
+ * are written to the match ADEC bit to generate errors at the
839
+ * particular address. ADEC14 and ADEC15 have the match bits.
840
+ *
841
+ * xddr_inject_data_ue_store() updates the ECC FLIP registers with the
842
+ * bits to be corrupted based on the bit position given by the user. For
843
+ * uncorrectable errors
844
+ * 2 bit errors are injected.
845
+ *
846
+ * Upon doing a read to the address the errors are injected.
847
+ */
848
+ static ssize_t inject_data_ue_store (struct file * file , const char __user * data ,
849
+ size_t count , loff_t * ppos )
850
+ {
851
+ struct device * dev = file -> private_data ;
852
+ struct mem_ctl_info * mci = to_mci (dev );
853
+ struct edac_priv * priv = mci -> pvt_info ;
854
+ char buf [6 ], * pbuf , * token [2 ];
855
+ u32 val0 = 0 , val1 = 0 ;
856
+ u8 len , ue0 , ue1 ;
857
+ int i , ret ;
858
+
859
+ len = min_t (size_t , count , sizeof (buf ));
860
+ if (copy_from_user (buf , data , len ))
861
+ return - EFAULT ;
862
+
863
+ buf [len ] = '\0' ;
864
+ pbuf = & buf [0 ];
865
+ for (i = 0 ; i < NUM_UE_BITPOS ; i ++ )
866
+ token [i ] = strsep (& pbuf , "," );
867
+
868
+ ret = kstrtou8 (token [0 ], 0 , & ue0 );
869
+ if (ret )
870
+ return ret ;
871
+
872
+ ret = kstrtou8 (token [1 ], 0 , & ue1 );
873
+ if (ret )
874
+ return ret ;
875
+
876
+ if (ue0 < ECCW0_FLIP0_BITS ) {
877
+ val0 = BIT (ue0 );
878
+ } else {
879
+ ue0 = ue0 - ECCW0_FLIP0_BITS ;
880
+ val1 = BIT (ue0 );
881
+ }
778
882
779
- xddr_inject_data_poison_store (mci , data );
883
+ if (ue1 < ECCW0_FLIP0_BITS ) {
884
+ val0 |= BIT (ue1 );
885
+ } else {
886
+ ue1 = ue1 - ECCW0_FLIP0_BITS ;
887
+ val1 |= BIT (ue1 );
888
+ }
780
889
890
+ /* Unlock the PCSR registers */
891
+ writel (PCSR_UNLOCK_VAL , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
892
+ writel (PCSR_UNLOCK_VAL , priv -> ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET );
893
+
894
+ poison_setup (priv );
895
+
896
+ xddr_inject_data_ue_store (mci , val0 , val1 );
897
+
898
+ /* Lock the PCSR registers */
899
+ writel (PCSR_LOCK_VAL , priv -> ddrmc_noc_baseaddr + XDDR_PCSR_OFFSET );
900
+ writel (PCSR_LOCK_VAL , priv -> ddrmc_baseaddr + XDDR_PCSR_OFFSET );
781
901
return count ;
782
902
}
783
903
784
- static const struct file_operations xddr_inject_enable_fops = {
904
+ static const struct file_operations xddr_inject_ue_fops = {
785
905
.open = simple_open ,
786
- .write = inject_data_poison_store ,
906
+ .write = inject_data_ue_store ,
787
907
.llseek = generic_file_llseek ,
788
908
};
789
909
@@ -795,8 +915,17 @@ static void create_debugfs_attributes(struct mem_ctl_info *mci)
795
915
if (!priv -> debugfs )
796
916
return ;
797
917
798
- edac_debugfs_create_file ("inject_error" , 0200 , priv -> debugfs ,
799
- & mci -> dev , & xddr_inject_enable_fops );
918
+ if (!edac_debugfs_create_file ("inject_ce" , 0200 , priv -> debugfs ,
919
+ & mci -> dev , & xddr_inject_ce_fops )) {
920
+ debugfs_remove_recursive (priv -> debugfs );
921
+ return ;
922
+ }
923
+
924
+ if (!edac_debugfs_create_file ("inject_ue" , 0200 , priv -> debugfs ,
925
+ & mci -> dev , & xddr_inject_ue_fops )) {
926
+ debugfs_remove_recursive (priv -> debugfs );
927
+ return ;
928
+ }
800
929
debugfs_create_x64 ("address" , 0600 , priv -> debugfs ,
801
930
& priv -> err_inject_addr );
802
931
mci -> debugfs = priv -> debugfs ;
0 commit comments