@@ -530,6 +530,284 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
530530 }
531531}
532532
533+ struct dwxgmac3_error_desc {
534+ bool valid ;
535+ const char * desc ;
536+ const char * detailed_desc ;
537+ };
538+
539+ #define STAT_OFF (field ) offsetof(struct stmmac_safety_stats, field)
540+
541+ static void dwxgmac3_log_error (struct net_device * ndev , u32 value , bool corr ,
542+ const char * module_name ,
543+ const struct dwxgmac3_error_desc * desc ,
544+ unsigned long field_offset ,
545+ struct stmmac_safety_stats * stats )
546+ {
547+ unsigned long loc , mask ;
548+ u8 * bptr = (u8 * )stats ;
549+ unsigned long * ptr ;
550+
551+ ptr = (unsigned long * )(bptr + field_offset );
552+
553+ mask = value ;
554+ for_each_set_bit (loc , & mask , 32 ) {
555+ netdev_err (ndev , "Found %s error in %s: '%s: %s'\n" , corr ?
556+ "correctable" : "uncorrectable" , module_name ,
557+ desc [loc ].desc , desc [loc ].detailed_desc );
558+
559+ /* Update counters */
560+ ptr [loc ]++ ;
561+ }
562+ }
563+
564+ static const struct dwxgmac3_error_desc dwxgmac3_mac_errors [32 ]= {
565+ { true, "ATPES" , "Application Transmit Interface Parity Check Error" },
566+ { true, "DPES" , "Descriptor Cache Data Path Parity Check Error" },
567+ { true, "TPES" , "TSO Data Path Parity Check Error" },
568+ { true, "TSOPES" , "TSO Header Data Path Parity Check Error" },
569+ { true, "MTPES" , "MTL Data Path Parity Check Error" },
570+ { true, "MTSPES" , "MTL TX Status Data Path Parity Check Error" },
571+ { true, "MTBUPES" , "MAC TBU Data Path Parity Check Error" },
572+ { true, "MTFCPES" , "MAC TFC Data Path Parity Check Error" },
573+ { true, "ARPES" , "Application Receive Interface Data Path Parity Check Error" },
574+ { true, "MRWCPES" , "MTL RWC Data Path Parity Check Error" },
575+ { true, "MRRCPES" , "MTL RCC Data Path Parity Check Error" },
576+ { true, "CWPES" , "CSR Write Data Path Parity Check Error" },
577+ { true, "ASRPES" , "AXI Slave Read Data Path Parity Check Error" },
578+ { true, "TTES" , "TX FSM Timeout Error" },
579+ { true, "RTES" , "RX FSM Timeout Error" },
580+ { true, "CTES" , "CSR FSM Timeout Error" },
581+ { true, "ATES" , "APP FSM Timeout Error" },
582+ { true, "PTES" , "PTP FSM Timeout Error" },
583+ { false, "UNKNOWN" , "Unknown Error" }, /* 18 */
584+ { false, "UNKNOWN" , "Unknown Error" }, /* 19 */
585+ { false, "UNKNOWN" , "Unknown Error" }, /* 20 */
586+ { true, "MSTTES" , "Master Read/Write Timeout Error" },
587+ { true, "SLVTES" , "Slave Read/Write Timeout Error" },
588+ { true, "ATITES" , "Application Timeout on ATI Interface Error" },
589+ { true, "ARITES" , "Application Timeout on ARI Interface Error" },
590+ { true, "FSMPES" , "FSM State Parity Error" },
591+ { false, "UNKNOWN" , "Unknown Error" }, /* 26 */
592+ { false, "UNKNOWN" , "Unknown Error" }, /* 27 */
593+ { false, "UNKNOWN" , "Unknown Error" }, /* 28 */
594+ { false, "UNKNOWN" , "Unknown Error" }, /* 29 */
595+ { false, "UNKNOWN" , "Unknown Error" }, /* 30 */
596+ { true, "CPI" , "Control Register Parity Check Error" },
597+ };
598+
599+ static void dwxgmac3_handle_mac_err (struct net_device * ndev ,
600+ void __iomem * ioaddr , bool correctable ,
601+ struct stmmac_safety_stats * stats )
602+ {
603+ u32 value ;
604+
605+ value = readl (ioaddr + XGMAC_MAC_DPP_FSM_INT_STATUS );
606+ writel (value , ioaddr + XGMAC_MAC_DPP_FSM_INT_STATUS );
607+
608+ dwxgmac3_log_error (ndev , value , correctable , "MAC" ,
609+ dwxgmac3_mac_errors , STAT_OFF (mac_errors ), stats );
610+ }
611+
612+ static const struct dwxgmac3_error_desc dwxgmac3_mtl_errors [32 ]= {
613+ { true, "TXCES" , "MTL TX Memory Error" },
614+ { true, "TXAMS" , "MTL TX Memory Address Mismatch Error" },
615+ { true, "TXUES" , "MTL TX Memory Error" },
616+ { false, "UNKNOWN" , "Unknown Error" }, /* 3 */
617+ { true, "RXCES" , "MTL RX Memory Error" },
618+ { true, "RXAMS" , "MTL RX Memory Address Mismatch Error" },
619+ { true, "RXUES" , "MTL RX Memory Error" },
620+ { false, "UNKNOWN" , "Unknown Error" }, /* 7 */
621+ { true, "ECES" , "MTL EST Memory Error" },
622+ { true, "EAMS" , "MTL EST Memory Address Mismatch Error" },
623+ { true, "EUES" , "MTL EST Memory Error" },
624+ { false, "UNKNOWN" , "Unknown Error" }, /* 11 */
625+ { true, "RPCES" , "MTL RX Parser Memory Error" },
626+ { true, "RPAMS" , "MTL RX Parser Memory Address Mismatch Error" },
627+ { true, "RPUES" , "MTL RX Parser Memory Error" },
628+ { false, "UNKNOWN" , "Unknown Error" }, /* 15 */
629+ { false, "UNKNOWN" , "Unknown Error" }, /* 16 */
630+ { false, "UNKNOWN" , "Unknown Error" }, /* 17 */
631+ { false, "UNKNOWN" , "Unknown Error" }, /* 18 */
632+ { false, "UNKNOWN" , "Unknown Error" }, /* 19 */
633+ { false, "UNKNOWN" , "Unknown Error" }, /* 20 */
634+ { false, "UNKNOWN" , "Unknown Error" }, /* 21 */
635+ { false, "UNKNOWN" , "Unknown Error" }, /* 22 */
636+ { false, "UNKNOWN" , "Unknown Error" }, /* 23 */
637+ { false, "UNKNOWN" , "Unknown Error" }, /* 24 */
638+ { false, "UNKNOWN" , "Unknown Error" }, /* 25 */
639+ { false, "UNKNOWN" , "Unknown Error" }, /* 26 */
640+ { false, "UNKNOWN" , "Unknown Error" }, /* 27 */
641+ { false, "UNKNOWN" , "Unknown Error" }, /* 28 */
642+ { false, "UNKNOWN" , "Unknown Error" }, /* 29 */
643+ { false, "UNKNOWN" , "Unknown Error" }, /* 30 */
644+ { false, "UNKNOWN" , "Unknown Error" }, /* 31 */
645+ };
646+
647+ static void dwxgmac3_handle_mtl_err (struct net_device * ndev ,
648+ void __iomem * ioaddr , bool correctable ,
649+ struct stmmac_safety_stats * stats )
650+ {
651+ u32 value ;
652+
653+ value = readl (ioaddr + XGMAC_MTL_ECC_INT_STATUS );
654+ writel (value , ioaddr + XGMAC_MTL_ECC_INT_STATUS );
655+
656+ dwxgmac3_log_error (ndev , value , correctable , "MTL" ,
657+ dwxgmac3_mtl_errors , STAT_OFF (mtl_errors ), stats );
658+ }
659+
660+ static const struct dwxgmac3_error_desc dwxgmac3_dma_errors [32 ]= {
661+ { true, "TCES" , "DMA TSO Memory Error" },
662+ { true, "TAMS" , "DMA TSO Memory Address Mismatch Error" },
663+ { true, "TUES" , "DMA TSO Memory Error" },
664+ { false, "UNKNOWN" , "Unknown Error" }, /* 3 */
665+ { true, "DCES" , "DMA DCACHE Memory Error" },
666+ { true, "DAMS" , "DMA DCACHE Address Mismatch Error" },
667+ { true, "DUES" , "DMA DCACHE Memory Error" },
668+ { false, "UNKNOWN" , "Unknown Error" }, /* 7 */
669+ { false, "UNKNOWN" , "Unknown Error" }, /* 8 */
670+ { false, "UNKNOWN" , "Unknown Error" }, /* 9 */
671+ { false, "UNKNOWN" , "Unknown Error" }, /* 10 */
672+ { false, "UNKNOWN" , "Unknown Error" }, /* 11 */
673+ { false, "UNKNOWN" , "Unknown Error" }, /* 12 */
674+ { false, "UNKNOWN" , "Unknown Error" }, /* 13 */
675+ { false, "UNKNOWN" , "Unknown Error" }, /* 14 */
676+ { false, "UNKNOWN" , "Unknown Error" }, /* 15 */
677+ { false, "UNKNOWN" , "Unknown Error" }, /* 16 */
678+ { false, "UNKNOWN" , "Unknown Error" }, /* 17 */
679+ { false, "UNKNOWN" , "Unknown Error" }, /* 18 */
680+ { false, "UNKNOWN" , "Unknown Error" }, /* 19 */
681+ { false, "UNKNOWN" , "Unknown Error" }, /* 20 */
682+ { false, "UNKNOWN" , "Unknown Error" }, /* 21 */
683+ { false, "UNKNOWN" , "Unknown Error" }, /* 22 */
684+ { false, "UNKNOWN" , "Unknown Error" }, /* 23 */
685+ { false, "UNKNOWN" , "Unknown Error" }, /* 24 */
686+ { false, "UNKNOWN" , "Unknown Error" }, /* 25 */
687+ { false, "UNKNOWN" , "Unknown Error" }, /* 26 */
688+ { false, "UNKNOWN" , "Unknown Error" }, /* 27 */
689+ { false, "UNKNOWN" , "Unknown Error" }, /* 28 */
690+ { false, "UNKNOWN" , "Unknown Error" }, /* 29 */
691+ { false, "UNKNOWN" , "Unknown Error" }, /* 30 */
692+ { false, "UNKNOWN" , "Unknown Error" }, /* 31 */
693+ };
694+
695+ static void dwxgmac3_handle_dma_err (struct net_device * ndev ,
696+ void __iomem * ioaddr , bool correctable ,
697+ struct stmmac_safety_stats * stats )
698+ {
699+ u32 value ;
700+
701+ value = readl (ioaddr + XGMAC_DMA_ECC_INT_STATUS );
702+ writel (value , ioaddr + XGMAC_DMA_ECC_INT_STATUS );
703+
704+ dwxgmac3_log_error (ndev , value , correctable , "DMA" ,
705+ dwxgmac3_dma_errors , STAT_OFF (dma_errors ), stats );
706+ }
707+
708+ static int dwxgmac3_safety_feat_config (void __iomem * ioaddr , unsigned int asp )
709+ {
710+ u32 value ;
711+
712+ if (!asp )
713+ return - EINVAL ;
714+
715+ /* 1. Enable Safety Features */
716+ writel (0x0 , ioaddr + XGMAC_MTL_ECC_CONTROL );
717+
718+ /* 2. Enable MTL Safety Interrupts */
719+ value = readl (ioaddr + XGMAC_MTL_ECC_INT_ENABLE );
720+ value |= XGMAC_RPCEIE ; /* RX Parser Memory Correctable Error */
721+ value |= XGMAC_ECEIE ; /* EST Memory Correctable Error */
722+ value |= XGMAC_RXCEIE ; /* RX Memory Correctable Error */
723+ value |= XGMAC_TXCEIE ; /* TX Memory Correctable Error */
724+ writel (value , ioaddr + XGMAC_MTL_ECC_INT_ENABLE );
725+
726+ /* 3. Enable DMA Safety Interrupts */
727+ value = readl (ioaddr + XGMAC_DMA_ECC_INT_ENABLE );
728+ value |= XGMAC_DCEIE ; /* Descriptor Cache Memory Correctable Error */
729+ value |= XGMAC_TCEIE ; /* TSO Memory Correctable Error */
730+ writel (value , ioaddr + XGMAC_DMA_ECC_INT_ENABLE );
731+
732+ /* Only ECC Protection for External Memory feature is selected */
733+ if (asp <= 0x1 )
734+ return 0 ;
735+
736+ /* 4. Enable Parity and Timeout for FSM */
737+ value = readl (ioaddr + XGMAC_MAC_FSM_CONTROL );
738+ value |= XGMAC_PRTYEN ; /* FSM Parity Feature */
739+ value |= XGMAC_TMOUTEN ; /* FSM Timeout Feature */
740+ writel (value , ioaddr + XGMAC_MAC_FSM_CONTROL );
741+
742+ return 0 ;
743+ }
744+
745+ static int dwxgmac3_safety_feat_irq_status (struct net_device * ndev ,
746+ void __iomem * ioaddr ,
747+ unsigned int asp ,
748+ struct stmmac_safety_stats * stats )
749+ {
750+ bool err , corr ;
751+ u32 mtl , dma ;
752+ int ret = 0 ;
753+
754+ if (!asp )
755+ return - EINVAL ;
756+
757+ mtl = readl (ioaddr + XGMAC_MTL_SAFETY_INT_STATUS );
758+ dma = readl (ioaddr + XGMAC_DMA_SAFETY_INT_STATUS );
759+
760+ err = (mtl & XGMAC_MCSIS ) || (dma & XGMAC_MCSIS );
761+ corr = false;
762+ if (err ) {
763+ dwxgmac3_handle_mac_err (ndev , ioaddr , corr , stats );
764+ ret |= !corr ;
765+ }
766+
767+ err = (mtl & (XGMAC_MEUIS | XGMAC_MECIS )) ||
768+ (dma & (XGMAC_MSUIS | XGMAC_MSCIS ));
769+ corr = (mtl & XGMAC_MECIS ) || (dma & XGMAC_MSCIS );
770+ if (err ) {
771+ dwxgmac3_handle_mtl_err (ndev , ioaddr , corr , stats );
772+ ret |= !corr ;
773+ }
774+
775+ err = dma & (XGMAC_DEUIS | XGMAC_DECIS );
776+ corr = dma & XGMAC_DECIS ;
777+ if (err ) {
778+ dwxgmac3_handle_dma_err (ndev , ioaddr , corr , stats );
779+ ret |= !corr ;
780+ }
781+
782+ return ret ;
783+ }
784+
785+ static const struct dwxgmac3_error {
786+ const struct dwxgmac3_error_desc * desc ;
787+ } dwxgmac3_all_errors [] = {
788+ { dwxgmac3_mac_errors },
789+ { dwxgmac3_mtl_errors },
790+ { dwxgmac3_dma_errors },
791+ };
792+
793+ static int dwxgmac3_safety_feat_dump (struct stmmac_safety_stats * stats ,
794+ int index , unsigned long * count ,
795+ const char * * desc )
796+ {
797+ int module = index / 32 , offset = index % 32 ;
798+ unsigned long * ptr = (unsigned long * )stats ;
799+
800+ if (module >= ARRAY_SIZE (dwxgmac3_all_errors ))
801+ return - EINVAL ;
802+ if (!dwxgmac3_all_errors [module ].desc [offset ].valid )
803+ return - EINVAL ;
804+ if (count )
805+ * count = * (ptr + index );
806+ if (desc )
807+ * desc = dwxgmac3_all_errors [module ].desc [offset ].desc ;
808+ return 0 ;
809+ }
810+
533811const struct stmmac_ops dwxgmac210_ops = {
534812 .core_init = dwxgmac2_core_init ,
535813 .set_mac = dwxgmac2_set_mac ,
@@ -559,6 +837,9 @@ const struct stmmac_ops dwxgmac210_ops = {
559837 .pcs_get_adv_lp = NULL ,
560838 .debug = NULL ,
561839 .set_filter = dwxgmac2_set_filter ,
840+ .safety_feat_config = dwxgmac3_safety_feat_config ,
841+ .safety_feat_irq_status = dwxgmac3_safety_feat_irq_status ,
842+ .safety_feat_dump = dwxgmac3_safety_feat_dump ,
562843 .set_mac_loopback = dwxgmac2_set_mac_loopback ,
563844 .rss_configure = dwxgmac2_rss_configure ,
564845 .update_vlan_hash = dwxgmac2_update_vlan_hash ,
0 commit comments