aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-10-04 09:15:40 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-10 10:49:30 -0400
commitca9c90ba09ca3c9799319f46a56f397afbf617c2 (patch)
tree63085920246ac68f32b80606eac2201b0e8d005b /drivers/edac
parentb968759ee7102f86fec5f3349f7a8ab4556884a3 (diff)
i7core_edac: Use a lockless ringbuffer
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/i7core_edac.c83
1 files changed, 55 insertions, 28 deletions
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 97f6d1759c99..94aeca011ac4 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -28,7 +28,6 @@
28#include <linux/edac.h> 28#include <linux/edac.h>
29#include <linux/mmzone.h> 29#include <linux/mmzone.h>
30#include <linux/edac_mce.h> 30#include <linux/edac_mce.h>
31#include <linux/spinlock.h>
32#include <linux/smp.h> 31#include <linux/smp.h>
33#include <asm/processor.h> 32#include <asm/processor.h>
34 33
@@ -239,9 +238,16 @@ struct i7core_pvt {
239 238
240 /* mcelog glue */ 239 /* mcelog glue */
241 struct edac_mce edac_mce; 240 struct edac_mce edac_mce;
241
242 /* Fifo double buffers */
242 struct mce mce_entry[MCE_LOG_LEN]; 243 struct mce mce_entry[MCE_LOG_LEN];
243 unsigned mce_count; 244 struct mce mce_outentry[MCE_LOG_LEN];
244 spinlock_t mce_lock; 245
246 /* Fifo in/out counters */
247 unsigned mce_in, mce_out;
248
249 /* Count indicator to show errors not got */
250 unsigned mce_overrun;
245}; 251};
246 252
247/* Static vars */ 253/* Static vars */
@@ -1617,30 +1623,50 @@ static void i7core_check_error(struct mem_ctl_info *mci)
1617 struct i7core_pvt *pvt = mci->pvt_info; 1623 struct i7core_pvt *pvt = mci->pvt_info;
1618 int i; 1624 int i;
1619 unsigned count = 0; 1625 unsigned count = 0;
1620 struct mce *m = NULL; 1626 struct mce *m;
1621 unsigned long flags;
1622 1627
1623 /* Copy all mce errors into a temporary buffer */ 1628 /*
1624 spin_lock_irqsave(&pvt->mce_lock, flags); 1629 * MCE first step: Copy all mce errors into a temporary buffer
1625 if (pvt->mce_count) { 1630 * We use a double buffering here, to reduce the risk of
1626 m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); 1631 * loosing an error.
1632 */
1633 smp_rmb();
1634 count = (pvt->mce_out + sizeof(mce_entry) - pvt->mce_in)
1635 % sizeof(mce_entry);
1636 if (!count)
1637 return;
1627 1638
1628 if (m) { 1639 m = pvt->mce_outentry;
1629 count = pvt->mce_count; 1640 if (pvt->mce_in + count > sizeof(mce_entry)) {
1630 memcpy(m, &pvt->mce_entry, sizeof(*m) * count); 1641 unsigned l = sizeof(mce_entry) - pvt->mce_in;
1631 }
1632 pvt->mce_count = 0;
1633 }
1634 1642
1635 spin_unlock_irqrestore(&pvt->mce_lock, flags); 1643 memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * l);
1644 smp_wmb();
1645 pvt->mce_in = 0;
1646 count -= l;
1647 m += l;
1648 }
1649 memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * count);
1650 smp_wmb();
1651 pvt->mce_in += count;
1652
1653 smp_rmb();
1654 if (pvt->mce_overrun) {
1655 i7core_printk(KERN_ERR, "Lost %d memory errors\n",
1656 pvt->mce_overrun);
1657 smp_wmb();
1658 pvt->mce_overrun = 0;
1659 }
1636 1660
1637 /* proccess mcelog errors */ 1661 /*
1662 * MCE second step: parse errors and display
1663 */
1638 for (i = 0; i < count; i++) 1664 for (i = 0; i < count; i++)
1639 i7core_mce_output_error(mci, &m[i]); 1665 i7core_mce_output_error(mci, &pvt->mce_outentry[i]);
1640 1666
1641 kfree(m); 1667 /*
1642 1668 * Now, let's increment CE error counts
1643 /* check memory count errors */ 1669 */
1644 if (!pvt->is_registered) 1670 if (!pvt->is_registered)
1645 i7core_udimm_check_mc_ecc_err(mci); 1671 i7core_udimm_check_mc_ecc_err(mci);
1646 else 1672 else
@@ -1657,7 +1683,6 @@ static int i7core_mce_check_error(void *priv, struct mce *mce)
1657{ 1683{
1658 struct mem_ctl_info *mci = priv; 1684 struct mem_ctl_info *mci = priv;
1659 struct i7core_pvt *pvt = mci->pvt_info; 1685 struct i7core_pvt *pvt = mci->pvt_info;
1660 unsigned long flags;
1661 1686
1662 /* 1687 /*
1663 * Just let mcelog handle it if the error is 1688 * Just let mcelog handle it if the error is
@@ -1679,12 +1704,15 @@ static int i7core_mce_check_error(void *priv, struct mce *mce)
1679 return 0; 1704 return 0;
1680 } 1705 }
1681 1706
1682 spin_lock_irqsave(&pvt->mce_lock, flags); 1707 smp_rmb();
1683 if (pvt->mce_count < MCE_LOG_LEN) { 1708 if ((pvt->mce_out + 1) % sizeof(mce_entry) == pvt->mce_in) {
1684 memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); 1709 smp_wmb();
1685 pvt->mce_count++; 1710 pvt->mce_overrun++;
1711 return 0;
1686 } 1712 }
1687 spin_unlock_irqrestore(&pvt->mce_lock, flags); 1713 smp_wmb();
1714 pvt->mce_out = (pvt->mce_out + 1) % sizeof(mce_entry);
1715 memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce));
1688 1716
1689 /* Handle fatal errors immediately */ 1717 /* Handle fatal errors immediately */
1690 if (mce->mcgstatus & 1) 1718 if (mce->mcgstatus & 1)
@@ -1777,7 +1805,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev,
1777 /* Registers on edac_mce in order to receive memory errors */ 1805 /* Registers on edac_mce in order to receive memory errors */
1778 pvt->edac_mce.priv = mci; 1806 pvt->edac_mce.priv = mci;
1779 pvt->edac_mce.check_error = i7core_mce_check_error; 1807 pvt->edac_mce.check_error = i7core_mce_check_error;
1780 spin_lock_init(&pvt->mce_lock);
1781 1808
1782 rc = edac_mce_register(&pvt->edac_mce); 1809 rc = edac_mce_register(&pvt->edac_mce);
1783 if (unlikely(rc < 0)) { 1810 if (unlikely(rc < 0)) {