diff options
author | eric wollesen <ericw@xmtp.net> | 2007-02-12 03:53:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-12 12:48:32 -0500 |
commit | 9794f33ddedd878dd92fcf8b4834391840366919 (patch) | |
tree | b64ed2488fe95a1217d14704422cc467193f34a3 /drivers/edac | |
parent | 4f423ddf56e5ecb1fb2eac83b8e228e3d0aae0f6 (diff) |
[PATCH] EDAC: Add Fully-Buffered DIMM APIs to core
Eric Wollesen ported the Bluesmoke Memory Controller driver for the Intel
5000X/V/P (Blackford/Greencreek) chipset to the in kernel EDAC model.
This patch incorporates those required changes to the edac_mc.c and edac_mc.h
core files by added new Fully Buffered DIMM interface to the EDAC Core module.
Signed-off-by: eric wollesen <ericw@xmtp.net>
Signed-off-by: doug thompson <norsk5@xmission.com>
Acked-by: Alan Cox <alan@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/edac_mc.c | 120 | ||||
-rw-r--r-- | drivers/edac/edac_mc.h | 16 |
2 files changed, 130 insertions, 6 deletions
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 1df8c0c5d40a..7b622300d0e5 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -1497,11 +1497,11 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx) | |||
1497 | /* set load time so that error rate can be tracked */ | 1497 | /* set load time so that error rate can be tracked */ |
1498 | mci->start_time = jiffies; | 1498 | mci->start_time = jiffies; |
1499 | 1499 | ||
1500 | if (edac_create_sysfs_mci_device(mci)) { | 1500 | if (edac_create_sysfs_mci_device(mci)) { |
1501 | edac_mc_printk(mci, KERN_WARNING, | 1501 | edac_mc_printk(mci, KERN_WARNING, |
1502 | "failed to create sysfs device\n"); | 1502 | "failed to create sysfs device\n"); |
1503 | goto fail1; | 1503 | goto fail1; |
1504 | } | 1504 | } |
1505 | 1505 | ||
1506 | /* Report action taken */ | 1506 | /* Report action taken */ |
1507 | edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n", | 1507 | edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n", |
@@ -1758,6 +1758,116 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) | |||
1758 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); | 1758 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); |
1759 | 1759 | ||
1760 | 1760 | ||
1761 | /************************************************************* | ||
1762 | * On Fully Buffered DIMM modules, this help function is | ||
1763 | * called to process UE events | ||
1764 | */ | ||
1765 | void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, | ||
1766 | unsigned int csrow, | ||
1767 | unsigned int channela, | ||
1768 | unsigned int channelb, | ||
1769 | char *msg) | ||
1770 | { | ||
1771 | int len = EDAC_MC_LABEL_LEN * 4; | ||
1772 | char labels[len + 1]; | ||
1773 | char *pos = labels; | ||
1774 | int chars; | ||
1775 | |||
1776 | if (csrow >= mci->nr_csrows) { | ||
1777 | /* something is wrong */ | ||
1778 | edac_mc_printk(mci, KERN_ERR, | ||
1779 | "INTERNAL ERROR: row out of range (%d >= %d)\n", | ||
1780 | csrow, mci->nr_csrows); | ||
1781 | edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); | ||
1782 | return; | ||
1783 | } | ||
1784 | |||
1785 | if (channela >= mci->csrows[csrow].nr_channels) { | ||
1786 | /* something is wrong */ | ||
1787 | edac_mc_printk(mci, KERN_ERR, | ||
1788 | "INTERNAL ERROR: channel-a out of range " | ||
1789 | "(%d >= %d)\n", | ||
1790 | channela, mci->csrows[csrow].nr_channels); | ||
1791 | edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); | ||
1792 | return; | ||
1793 | } | ||
1794 | |||
1795 | if (channelb >= mci->csrows[csrow].nr_channels) { | ||
1796 | /* something is wrong */ | ||
1797 | edac_mc_printk(mci, KERN_ERR, | ||
1798 | "INTERNAL ERROR: channel-b out of range " | ||
1799 | "(%d >= %d)\n", | ||
1800 | channelb, mci->csrows[csrow].nr_channels); | ||
1801 | edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); | ||
1802 | return; | ||
1803 | } | ||
1804 | |||
1805 | mci->ue_count++; | ||
1806 | mci->csrows[csrow].ue_count++; | ||
1807 | |||
1808 | /* Generate the DIMM labels from the specified channels */ | ||
1809 | chars = snprintf(pos, len + 1, "%s", | ||
1810 | mci->csrows[csrow].channels[channela].label); | ||
1811 | len -= chars; pos += chars; | ||
1812 | chars = snprintf(pos, len + 1, "-%s", | ||
1813 | mci->csrows[csrow].channels[channelb].label); | ||
1814 | |||
1815 | if (log_ue) | ||
1816 | edac_mc_printk(mci, KERN_EMERG, | ||
1817 | "UE row %d, channel-a= %d channel-b= %d " | ||
1818 | "labels \"%s\": %s\n", csrow, channela, channelb, | ||
1819 | labels, msg); | ||
1820 | |||
1821 | if (panic_on_ue) | ||
1822 | panic("UE row %d, channel-a= %d channel-b= %d " | ||
1823 | "labels \"%s\": %s\n", csrow, channela, | ||
1824 | channelb, labels, msg); | ||
1825 | } | ||
1826 | EXPORT_SYMBOL(edac_mc_handle_fbd_ue); | ||
1827 | |||
1828 | /************************************************************* | ||
1829 | * On Fully Buffered DIMM modules, this help function is | ||
1830 | * called to process CE events | ||
1831 | */ | ||
1832 | void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, | ||
1833 | unsigned int csrow, | ||
1834 | unsigned int channel, | ||
1835 | char *msg) | ||
1836 | { | ||
1837 | |||
1838 | /* Ensure boundary values */ | ||
1839 | if (csrow >= mci->nr_csrows) { | ||
1840 | /* something is wrong */ | ||
1841 | edac_mc_printk(mci, KERN_ERR, | ||
1842 | "INTERNAL ERROR: row out of range (%d >= %d)\n", | ||
1843 | csrow, mci->nr_csrows); | ||
1844 | edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); | ||
1845 | return; | ||
1846 | } | ||
1847 | if (channel >= mci->csrows[csrow].nr_channels) { | ||
1848 | /* something is wrong */ | ||
1849 | edac_mc_printk(mci, KERN_ERR, | ||
1850 | "INTERNAL ERROR: channel out of range (%d >= %d)\n", | ||
1851 | channel, mci->csrows[csrow].nr_channels); | ||
1852 | edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); | ||
1853 | return; | ||
1854 | } | ||
1855 | |||
1856 | if (log_ce) | ||
1857 | /* FIXME - put in DIMM location */ | ||
1858 | edac_mc_printk(mci, KERN_WARNING, | ||
1859 | "CE row %d, channel %d, label \"%s\": %s\n", | ||
1860 | csrow, channel, | ||
1861 | mci->csrows[csrow].channels[channel].label, | ||
1862 | msg); | ||
1863 | |||
1864 | mci->ce_count++; | ||
1865 | mci->csrows[csrow].ce_count++; | ||
1866 | mci->csrows[csrow].channels[channel].ce_count++; | ||
1867 | } | ||
1868 | EXPORT_SYMBOL(edac_mc_handle_fbd_ce); | ||
1869 | |||
1870 | |||
1761 | /* | 1871 | /* |
1762 | * Iterate over all MC instances and check for ECC, et al, errors | 1872 | * Iterate over all MC instances and check for ECC, et al, errors |
1763 | */ | 1873 | */ |
@@ -1861,7 +1971,7 @@ static void __exit edac_mc_exit(void) | |||
1861 | debugf0("%s()\n", __func__); | 1971 | debugf0("%s()\n", __func__); |
1862 | kthread_stop(edac_thread); | 1972 | kthread_stop(edac_thread); |
1863 | 1973 | ||
1864 | /* tear down the sysfs device */ | 1974 | /* tear down the sysfs device */ |
1865 | edac_sysfs_memctrl_teardown(); | 1975 | edac_sysfs_memctrl_teardown(); |
1866 | edac_sysfs_pci_teardown(); | 1976 | edac_sysfs_pci_teardown(); |
1867 | } | 1977 | } |
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index c41986a9ed5b..713444cc4105 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h | |||
@@ -123,7 +123,9 @@ enum mem_type { | |||
123 | MEM_RDR, /* Registered single data rate SDRAM */ | 123 | MEM_RDR, /* Registered single data rate SDRAM */ |
124 | MEM_DDR, /* Double data rate SDRAM */ | 124 | MEM_DDR, /* Double data rate SDRAM */ |
125 | MEM_RDDR, /* Registered Double data rate SDRAM */ | 125 | MEM_RDDR, /* Registered Double data rate SDRAM */ |
126 | MEM_RMBS /* Rambus DRAM */ | 126 | MEM_RMBS, /* Rambus DRAM */ |
127 | MEM_DDR2, /* DDR2 RAM */ | ||
128 | MEM_FB_DDR2, /* fully buffered DDR2 */ | ||
127 | }; | 129 | }; |
128 | 130 | ||
129 | #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) | 131 | #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) |
@@ -137,6 +139,8 @@ enum mem_type { | |||
137 | #define MEM_FLAG_DDR BIT(MEM_DDR) | 139 | #define MEM_FLAG_DDR BIT(MEM_DDR) |
138 | #define MEM_FLAG_RDDR BIT(MEM_RDDR) | 140 | #define MEM_FLAG_RDDR BIT(MEM_RDDR) |
139 | #define MEM_FLAG_RMBS BIT(MEM_RMBS) | 141 | #define MEM_FLAG_RMBS BIT(MEM_RMBS) |
142 | #define MEM_FLAG_DDR2 BIT(MEM_DDR2) | ||
143 | #define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) | ||
140 | 144 | ||
141 | /* chipset Error Detection and Correction capabilities and mode */ | 145 | /* chipset Error Detection and Correction capabilities and mode */ |
142 | enum edac_type { | 146 | enum edac_type { |
@@ -329,6 +333,7 @@ struct mem_ctl_info { | |||
329 | 333 | ||
330 | /* pointer to edac checking routine */ | 334 | /* pointer to edac checking routine */ |
331 | void (*edac_check) (struct mem_ctl_info * mci); | 335 | void (*edac_check) (struct mem_ctl_info * mci); |
336 | |||
332 | /* | 337 | /* |
333 | * Remaps memory pages: controller pages to physical pages. | 338 | * Remaps memory pages: controller pages to physical pages. |
334 | * For most MC's, this will be NULL. | 339 | * For most MC's, this will be NULL. |
@@ -453,6 +458,15 @@ extern void edac_mc_handle_ue(struct mem_ctl_info *mci, | |||
453 | int row, const char *msg); | 458 | int row, const char *msg); |
454 | extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, | 459 | extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, |
455 | const char *msg); | 460 | const char *msg); |
461 | extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, | ||
462 | unsigned int csrow, | ||
463 | unsigned int channel0, | ||
464 | unsigned int channel1, | ||
465 | char *msg); | ||
466 | extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, | ||
467 | unsigned int csrow, | ||
468 | unsigned int channel, | ||
469 | char *msg); | ||
456 | 470 | ||
457 | /* | 471 | /* |
458 | * This kmalloc's and initializes all the structures. | 472 | * This kmalloc's and initializes all the structures. |