9
9
#include <linux/edac.h>
10
10
#include <linux/module.h>
11
11
#include <linux/platform_device.h>
12
+ #include <linux/spinlock.h>
12
13
#include <linux/interrupt.h>
13
14
#include <linux/of.h>
14
15
@@ -299,6 +300,7 @@ struct synps_ecc_status {
299
300
/**
300
301
* struct synps_edac_priv - DDR memory controller private instance data.
301
302
* @baseaddr: Base address of the DDR controller.
303
+ * @reglock: Concurrent CSRs access lock.
302
304
* @message: Buffer for framing the event specific info.
303
305
* @stat: ECC status information.
304
306
* @p_data: Platform data.
@@ -313,6 +315,7 @@ struct synps_ecc_status {
313
315
*/
314
316
struct synps_edac_priv {
315
317
void __iomem * baseaddr ;
318
+ spinlock_t reglock ;
316
319
char message [SYNPS_EDAC_MSG_SIZE ];
317
320
struct synps_ecc_status stat ;
318
321
const struct synps_platform_data * p_data ;
@@ -408,7 +411,8 @@ static int zynq_get_error_info(struct synps_edac_priv *priv)
408
411
static int zynqmp_get_error_info (struct synps_edac_priv * priv )
409
412
{
410
413
struct synps_ecc_status * p ;
411
- u32 regval , clearval = 0 ;
414
+ u32 regval , clearval ;
415
+ unsigned long flags ;
412
416
void __iomem * base ;
413
417
414
418
base = priv -> baseaddr ;
@@ -452,10 +456,14 @@ static int zynqmp_get_error_info(struct synps_edac_priv *priv)
452
456
p -> ueinfo .blknr = (regval & ECC_CEADDR1_BLKNR_MASK );
453
457
p -> ueinfo .data = readl (base + ECC_UESYND0_OFST );
454
458
out :
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 ;
457
464
writel (clearval , base + ECC_CLR_OFST );
458
- writel (0x0 , base + ECC_CLR_OFST );
465
+
466
+ spin_unlock_irqrestore (& priv -> reglock , flags );
459
467
460
468
return 0 ;
461
469
}
@@ -515,24 +523,41 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
515
523
516
524
static void enable_intr (struct synps_edac_priv * priv )
517
525
{
526
+ unsigned long flags ;
527
+
518
528
/* 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 )) {
523
530
writel (DDR_QOSUE_MASK | DDR_QOSCE_MASK ,
524
531
priv -> baseaddr + DDR_QOS_IRQ_EN_OFST );
525
532
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 );
526
542
}
527
543
528
544
static void disable_intr (struct synps_edac_priv * priv )
529
545
{
546
+ unsigned long flags ;
547
+
530
548
/* 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 )) {
534
550
writel (DDR_QOSUE_MASK | DDR_QOSCE_MASK ,
535
551
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 );
536
561
}
537
562
538
563
/**
@@ -576,8 +601,6 @@ static irqreturn_t intr_handler(int irq, void *dev_id)
576
601
/* v3.0 of the controller does not have this register */
577
602
if (!(priv -> p_data -> quirks & DDR_ECC_INTR_SELF_CLEAR ))
578
603
writel (regval , priv -> baseaddr + DDR_QOS_IRQ_STAT_OFST );
579
- else
580
- enable_intr (priv );
581
604
582
605
return IRQ_HANDLED ;
583
606
}
@@ -1357,6 +1380,7 @@ static int mc_probe(struct platform_device *pdev)
1357
1380
priv = mci -> pvt_info ;
1358
1381
priv -> baseaddr = baseaddr ;
1359
1382
priv -> p_data = p_data ;
1383
+ spin_lock_init (& priv -> reglock );
1360
1384
1361
1385
mc_init (mci , pdev );
1362
1386
0 commit comments