diff options
author | Samuel Gabrielsson <samuel.gabrielsson@gmail.com> | 2011-03-30 09:21:23 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-10-31 13:10:05 -0400 |
commit | e8b6a1271035e621d1c4b22403c697b5c969728c (patch) | |
tree | 2d7d0f1453da9302749f7c4fe0f60aa50b56954a | |
parent | ddeb3547d4823495c6604750c241e5a3810f51a3 (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>
-rw-r--r-- | drivers/edac/i7core_edac.c | 126 |
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 | */ | ||
1919 | static 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 | */ | ||
1972 | static 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 | |||
1997 | static 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 | |||
2012 | static 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 | |||
1904 | static void i7core_pci_ctl_create(struct i7core_pvt *pvt) | 2024 | static 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__ |