aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac/i7core_edac.c
diff options
context:
space:
mode:
authorSamuel Gabrielsson <samuel.gabrielsson@gmail.com>2011-03-30 09:21:23 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-10-31 13:10:05 -0400
commite8b6a1271035e621d1c4b22403c697b5c969728c (patch)
tree2d7d0f1453da9302749f7c4fe0f60aa50b56954a /drivers/edac/i7core_edac.c
parentddeb3547d4823495c6604750c241e5a3810f51a3 (diff)
i7core_edac: Add scrubbing support
Add scrubbing support to i7core_edac, tested on intel Xeon L5638. Signed-off-by: Samuel Gabrielsson <samuel.gabrielsson@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/edac/i7core_edac.c')
-rw-r--r--drivers/edac/i7core_edac.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index c64ba267902f..0c02486cf57a 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -78,6 +78,8 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
78 /* OFFSETS for Device 0 Function 0 */ 78 /* OFFSETS for Device 0 Function 0 */
79 79
80#define MC_CFG_CONTROL 0x90 80#define MC_CFG_CONTROL 0x90
81 #define MC_CFG_UNLOCK 0x02
82 #define MC_CFG_LOCK 0x00
81 83
82 /* OFFSETS for Device 3 Function 0 */ 84 /* OFFSETS for Device 3 Function 0 */
83 85
@@ -98,6 +100,14 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
98 #define DIMM0_COR_ERR(r) ((r) & 0x7fff) 100 #define DIMM0_COR_ERR(r) ((r) & 0x7fff)
99 101
100/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */ 102/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */
103#define MC_SSRCONTROL 0x48
104 #define SSR_MODE_DISABLE 0x00
105 #define SSR_MODE_ENABLE 0x01
106 #define SSR_MODE_MASK 0x03
107
108#define MC_SCRUB_CONTROL 0x4c
109 #define STARTSCRUB (1 << 24)
110
101#define MC_COR_ECC_CNT_0 0x80 111#define MC_COR_ECC_CNT_0 0x80
102#define MC_COR_ECC_CNT_1 0x84 112#define MC_COR_ECC_CNT_1 0x84
103#define MC_COR_ECC_CNT_2 0x88 113#define MC_COR_ECC_CNT_2 0x88
@@ -1901,6 +1911,116 @@ static int i7core_mce_check_error(void *priv, struct mce *mce)
1901 return 1; 1911 return 1;
1902} 1912}
1903 1913
1914/*
1915 * set_sdram_scrub_rate This routine sets byte/sec bandwidth scrub rate
1916 * to hardware according to SCRUBINTERVAL formula
1917 * found in datasheet.
1918 */
1919static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
1920{
1921 struct i7core_pvt *pvt = mci->pvt_info;
1922 struct pci_dev *pdev;
1923 const u32 cache_line_size = 64;
1924 const u32 freq_dclk = 800*1000000;
1925 u32 dw_scrub;
1926 u32 dw_ssr;
1927
1928 /* Get data from the MC register, function 2 */
1929 pdev = pvt->pci_mcr[2];
1930 if (!pdev)
1931 return -ENODEV;
1932
1933 pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &dw_scrub);
1934
1935 if (new_bw == 0) {
1936 /* Prepare to disable petrol scrub */
1937 dw_scrub &= ~STARTSCRUB;
1938 /* Stop the patrol scrub engine */
1939 write_and_test(pdev, MC_SCRUB_CONTROL, dw_scrub & ~0x00ffffff);
1940
1941 /* Get current status of scrub rate and set bit to disable */
1942 pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr);
1943 dw_ssr &= ~SSR_MODE_MASK;
1944 dw_ssr |= SSR_MODE_DISABLE;
1945 } else {
1946 /*
1947 * Translate the desired scrub rate to a register value and
1948 * program the cooresponding register value.
1949 */
1950 dw_scrub = 0x00ffffff & (cache_line_size * freq_dclk / new_bw);
1951
1952 /* Start the patrol scrub engine */
1953 pci_write_config_dword(pdev, MC_SCRUB_CONTROL,
1954 STARTSCRUB | dw_scrub);
1955
1956 /* Get current status of scrub rate and set bit to enable */
1957 pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr);
1958 dw_ssr &= ~SSR_MODE_MASK;
1959 dw_ssr |= SSR_MODE_ENABLE;
1960 }
1961 /* Disable or enable scrubbing */
1962 pci_write_config_dword(pdev, MC_SSRCONTROL, dw_ssr);
1963
1964 return new_bw;
1965}
1966
1967/*
1968 * get_sdram_scrub_rate This routine convert current scrub rate value
1969 * into byte/sec bandwidth accourding to
1970 * SCRUBINTERVAL formula found in datasheet.
1971 */
1972static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
1973{
1974 struct i7core_pvt *pvt = mci->pvt_info;
1975 struct pci_dev *pdev;
1976 const u32 cache_line_size = 64;
1977 const u32 freq_dclk = 800*1000000;
1978 u32 scrubval;
1979
1980 /* Get data from the MC register, function 2 */
1981 pdev = pvt->pci_mcr[2];
1982 if (!pdev)
1983 return -ENODEV;
1984
1985 /* Get current scrub control data */
1986 pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &scrubval);
1987
1988 /* Mask highest 8-bits to 0 */
1989 scrubval &= 0x00ffffff;
1990 if (!scrubval)
1991 return 0;
1992
1993 /* Calculate scrub rate value into byte/sec bandwidth */
1994 return 0xffffffff & (cache_line_size * freq_dclk / (u64) scrubval);
1995}
1996
1997static void enable_sdram_scrub_setting(struct mem_ctl_info *mci)
1998{
1999 struct i7core_pvt *pvt = mci->pvt_info;
2000 u32 pci_lock;
2001
2002 /* Unlock writes to pci registers */
2003 pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock);
2004 pci_lock &= ~0x3;
2005 pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL,
2006 pci_lock | MC_CFG_UNLOCK);
2007
2008 mci->set_sdram_scrub_rate = set_sdram_scrub_rate;
2009 mci->get_sdram_scrub_rate = get_sdram_scrub_rate;
2010}
2011
2012static void disable_sdram_scrub_setting(struct mem_ctl_info *mci)
2013{
2014 struct i7core_pvt *pvt = mci->pvt_info;
2015 u32 pci_lock;
2016
2017 /* Lock writes to pci registers */
2018 pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock);
2019 pci_lock &= ~0x3;
2020 pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL,
2021 pci_lock | MC_CFG_LOCK);
2022}
2023
1904static void i7core_pci_ctl_create(struct i7core_pvt *pvt) 2024static void i7core_pci_ctl_create(struct i7core_pvt *pvt)
1905{ 2025{
1906 pvt->i7core_pci = edac_pci_create_generic_ctl( 2026 pvt->i7core_pci = edac_pci_create_generic_ctl(
@@ -1939,6 +2059,9 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev)
1939 debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", 2059 debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n",
1940 __func__, mci, &i7core_dev->pdev[0]->dev); 2060 __func__, mci, &i7core_dev->pdev[0]->dev);
1941 2061
2062 /* Disable scrubrate setting */
2063 disable_sdram_scrub_setting(mci);
2064
1942 /* Disable MCE NMI handler */ 2065 /* Disable MCE NMI handler */
1943 edac_mce_unregister(&pvt->edac_mce); 2066 edac_mce_unregister(&pvt->edac_mce);
1944 2067
@@ -2012,6 +2135,9 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
2012 /* Set the function pointer to an actual operation function */ 2135 /* Set the function pointer to an actual operation function */
2013 mci->edac_check = i7core_check_error; 2136 mci->edac_check = i7core_check_error;
2014 2137
2138 /* Enable scrubrate setting */
2139 enable_sdram_scrub_setting(mci);
2140
2015 /* add this new MC control structure to EDAC's list of MCs */ 2141 /* add this new MC control structure to EDAC's list of MCs */
2016 if (unlikely(edac_mc_add_mc(mci))) { 2142 if (unlikely(edac_mc_add_mc(mci))) {
2017 debugf0("MC: " __FILE__ 2143 debugf0("MC: " __FILE__