99#include <linux/edac.h>
1010#include <linux/module.h>
1111#include <linux/platform_device.h>
12+ #include <linux/spinlock.h>
1213#include <linux/interrupt.h>
1314#include <linux/of.h>
1415
@@ -299,6 +300,7 @@ struct synps_ecc_status {
299300/**
300301 * struct synps_edac_priv - DDR memory controller private instance data.
301302 * @baseaddr: Base address of the DDR controller.
303+ * @reglock: Concurrent CSRs access lock.
302304 * @message: Buffer for framing the event specific info.
303305 * @stat: ECC status information.
304306 * @p_data: Platform data.
@@ -313,6 +315,7 @@ struct synps_ecc_status {
313315 */
314316struct synps_edac_priv {
315317 void __iomem * baseaddr ;
318+ spinlock_t reglock ;
316319 char message [SYNPS_EDAC_MSG_SIZE ];
317320 struct synps_ecc_status stat ;
318321 const struct synps_platform_data * p_data ;
@@ -408,7 +411,8 @@ static int zynq_get_error_info(struct synps_edac_priv *priv)
408411static int zynqmp_get_error_info (struct synps_edac_priv * priv )
409412{
410413 struct synps_ecc_status * p ;
411- u32 regval , clearval = 0 ;
414+ u32 regval , clearval ;
415+ unsigned long flags ;
412416 void __iomem * base ;
413417
414418 base = priv -> baseaddr ;
@@ -452,10 +456,14 @@ static int zynqmp_get_error_info(struct synps_edac_priv *priv)
452456 p -> ueinfo .blknr = (regval & ECC_CEADDR1_BLKNR_MASK );
453457 p -> ueinfo .data = readl (base + ECC_UESYND0_OFST );
454458out :
455- clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT ;
456- clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT ;
459+ spin_lock_irqsave (& priv -> reglock , flags );
460+
461+ clearval = readl (base + ECC_CLR_OFST ) |
462+ ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT |
463+ ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT ;
457464 writel (clearval , base + ECC_CLR_OFST );
458- writel (0x0 , base + ECC_CLR_OFST );
465+
466+ spin_unlock_irqrestore (& priv -> reglock , flags );
459467
460468 return 0 ;
461469}
@@ -515,24 +523,41 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
515523
516524static void enable_intr (struct synps_edac_priv * priv )
517525{
526+ unsigned long flags ;
527+
518528 /* Enable UE/CE Interrupts */
519- if (priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR )
520- writel (DDR_UE_MASK | DDR_CE_MASK ,
521- priv -> baseaddr + ECC_CLR_OFST );
522- else
529+ if (!(priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR )) {
523530 writel (DDR_QOSUE_MASK | DDR_QOSCE_MASK ,
524531 priv -> baseaddr + DDR_QOS_IRQ_EN_OFST );
525532
533+ return ;
534+ }
535+
536+ spin_lock_irqsave (& priv -> reglock , flags );
537+
538+ writel (DDR_UE_MASK | DDR_CE_MASK ,
539+ priv -> baseaddr + ECC_CLR_OFST );
540+
541+ spin_unlock_irqrestore (& priv -> reglock , flags );
526542}
527543
528544static void disable_intr (struct synps_edac_priv * priv )
529545{
546+ unsigned long flags ;
547+
530548 /* Disable UE/CE Interrupts */
531- if (priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR )
532- writel (0x0 , priv -> baseaddr + ECC_CLR_OFST );
533- else
549+ if (!(priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR )) {
534550 writel (DDR_QOSUE_MASK | DDR_QOSCE_MASK ,
535551 priv -> baseaddr + DDR_QOS_IRQ_DB_OFST );
552+
553+ return ;
554+ }
555+
556+ spin_lock_irqsave (& priv -> reglock , flags );
557+
558+ writel (0 , priv -> baseaddr + ECC_CLR_OFST );
559+
560+ spin_unlock_irqrestore (& priv -> reglock , flags );
536561}
537562
538563/**
@@ -576,8 +601,6 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
576601 /* v3.0 of the controller does not have this register */
577602 if (!(priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR ))
578603 writel (regval , priv -> baseaddr + DDR_QOS_IRQ_STAT_OFST );
579- else
580- enable_intr (priv );
581604
582605 return IRQ_HANDLED ;
583606}
@@ -1357,6 +1380,7 @@ static int mc_probe(struct platform_device *pdev)
13571380 priv = mci -> pvt_info ;
13581381 priv -> baseaddr = baseaddr ;
13591382 priv -> p_data = p_data ;
1383+ spin_lock_init (& priv -> reglock );
13601384
13611385 mc_init (mci , pdev );
13621386
0 commit comments