* [PATCH 1/2] i7core_edac: Add xeon 5600 generic non core registers @ 2011-03-30 13:21 Samuel Gabrielsson 2011-03-30 13:21 ` [PATCH 2/2] i7core_edac: Add scrubbing support Samuel Gabrielsson 2011-04-07 16:39 ` [PATCH 1/2] i7core_edac: Add xeon 5600 generic non core registers Nils Carlson 0 siblings, 2 replies; 6+ messages in thread From: Samuel Gabrielsson @ 2011-03-30 13:21 UTC (permalink / raw) To: mchehab; +Cc: linux-edac, linux-kernel, Samuel Gabrielsson This enables writing to registers in device 0 function 0 such as MC_CFG_CONTROL. This also fixes a bug for intel xeon 5600 series when writing to inject_enable where we would get an Oops because pvt->pci_noncore was not set. Signed-off-by: Samuel Gabrielsson <samuel.gabrielsson@gmail.com> --- drivers/edac/i7core_edac.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 81154ab..1db6092 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -322,6 +322,9 @@ static const struct pci_id_descr pci_dev_descr_lynnfield[] = { }; static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = { + /* Generic Non-core registers */ + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) }, + /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) }, -- 1.7.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] i7core_edac: Add scrubbing support 2011-03-30 13:21 [PATCH 1/2] i7core_edac: Add xeon 5600 generic non core registers Samuel Gabrielsson @ 2011-03-30 13:21 ` Samuel Gabrielsson 2011-04-07 16:43 ` Nils Carlson 2011-06-24 21:47 ` Tony Luck 2011-04-07 16:39 ` [PATCH 1/2] i7core_edac: Add xeon 5600 generic non core registers Nils Carlson 1 sibling, 2 replies; 6+ messages in thread From: Samuel Gabrielsson @ 2011-03-30 13:21 UTC (permalink / raw) To: mchehab; +Cc: linux-edac, linux-kernel, Samuel Gabrielsson Add scrubbing support to i7core_edac, tested on intel Xeon L5638. Signed-off-by: Samuel Gabrielsson <samuel.gabrielsson@gmail.com> --- 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 1db6092..3afb187 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"); /* OFFSETS for Device 0 Function 0 */ #define MC_CFG_CONTROL 0x90 + #define MC_CFG_UNLOCK 0x02 + #define MC_CFG_LOCK 0x00 /* OFFSETS for Device 3 Function 0 */ @@ -98,6 +100,14 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices"); #define DIMM0_COR_ERR(r) ((r) & 0x7fff) /* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */ +#define MC_SSRCONTROL 0x48 + #define SSR_MODE_DISABLE 0x00 + #define SSR_MODE_ENABLE 0x01 + #define SSR_MODE_MASK 0x03 + +#define MC_SCRUB_CONTROL 0x4c + #define STARTSCRUB (1 << 24) + #define MC_COR_ECC_CNT_0 0x80 #define MC_COR_ECC_CNT_1 0x84 #define MC_COR_ECC_CNT_2 0x88 @@ -1871,6 +1881,116 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 1; } +/* + * set_sdram_scrub_rate This routine sets byte/sec bandwidth scrub rate + * to hardware according to SCRUBINTERVAL formula + * found in datasheet. + */ +static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw) +{ + struct i7core_pvt *pvt = mci->pvt_info; + struct pci_dev *pdev; + const u32 cache_line_size = 64; + const u32 freq_dclk = 800*1000000; + u32 dw_scrub; + u32 dw_ssr; + + /* Get data from the MC register, function 2 */ + pdev = pvt->pci_mcr[2]; + if (!pdev) + return -ENODEV; + + pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &dw_scrub); + + if (new_bw == 0) { + /* Prepare to disable petrol scrub */ + dw_scrub &= ~STARTSCRUB; + /* Stop the patrol scrub engine */ + write_and_test(pdev, MC_SCRUB_CONTROL, dw_scrub & ~0x00ffffff); + + /* Get current status of scrub rate and set bit to disable */ + pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr); + dw_ssr &= ~SSR_MODE_MASK; + dw_ssr |= SSR_MODE_DISABLE; + } else { + /* + * Translate the desired scrub rate to a register value and + * program the cooresponding register value. + */ + dw_scrub = 0x00ffffff & (cache_line_size * freq_dclk / new_bw); + + /* Start the patrol scrub engine */ + pci_write_config_dword(pdev, MC_SCRUB_CONTROL, + STARTSCRUB | dw_scrub); + + /* Get current status of scrub rate and set bit to enable */ + pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr); + dw_ssr &= ~SSR_MODE_MASK; + dw_ssr |= SSR_MODE_ENABLE; + } + /* Disable or enable scrubbing */ + pci_write_config_dword(pdev, MC_SSRCONTROL, dw_ssr); + + return new_bw; +} + +/* + * get_sdram_scrub_rate This routine convert current scrub rate value + * into byte/sec bandwidth accourding to + * SCRUBINTERVAL formula found in datasheet. + */ +static int get_sdram_scrub_rate(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + struct pci_dev *pdev; + const u32 cache_line_size = 64; + const u32 freq_dclk = 800*1000000; + u32 scrubval; + + /* Get data from the MC register, function 2 */ + pdev = pvt->pci_mcr[2]; + if (!pdev) + return -ENODEV; + + /* Get current scrub control data */ + pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &scrubval); + + /* Mask highest 8-bits to 0 */ + scrubval &= 0x00ffffff; + if (!scrubval) + return 0; + + /* Calculate scrub rate value into byte/sec bandwidth */ + return 0xffffffff & (cache_line_size * freq_dclk / (u64) scrubval); +} + +static void enable_sdram_scrub_setting(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + u32 pci_lock; + + /* Unlock writes to pci registers */ + pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock); + pci_lock &= ~0x3; + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, + pci_lock | MC_CFG_UNLOCK); + + mci->set_sdram_scrub_rate = set_sdram_scrub_rate; + mci->get_sdram_scrub_rate = get_sdram_scrub_rate; +} + +static void disable_sdram_scrub_setting(struct mem_ctl_info *mci) +{ + struct i7core_pvt *pvt = mci->pvt_info; + u32 pci_lock; + + /* Lock writes to pci registers */ + pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock); + pci_lock &= ~0x3; + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, + pci_lock | MC_CFG_LOCK); +} + static void i7core_pci_ctl_create(struct i7core_pvt *pvt) { pvt->i7core_pci = edac_pci_create_generic_ctl( @@ -1909,6 +2029,9 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev) debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", __func__, mci, &i7core_dev->pdev[0]->dev); + /* Disable scrubrate setting */ + disable_sdram_scrub_setting(mci); + /* Disable MCE NMI handler */ edac_mce_unregister(&pvt->edac_mce); @@ -1982,6 +2105,9 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev) /* Set the function pointer to an actual operation function */ mci->edac_check = i7core_check_error; + /* Enable scrubrate setting */ + enable_sdram_scrub_setting(mci); + /* add this new MC control structure to EDAC's list of MCs */ if (unlikely(edac_mc_add_mc(mci))) { debugf0("MC: " __FILE__ -- 1.7.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] i7core_edac: Add scrubbing support 2011-03-30 13:21 ` [PATCH 2/2] i7core_edac: Add scrubbing support Samuel Gabrielsson @ 2011-04-07 16:43 ` Nils Carlson 2011-06-24 21:47 ` Tony Luck 1 sibling, 0 replies; 6+ messages in thread From: Nils Carlson @ 2011-04-07 16:43 UTC (permalink / raw) To: Samuel Gabrielsson; +Cc: mchehab, linux-edac, linux-kernel On Mar 30, 2011, at 3:21 PM, Samuel Gabrielsson wrote: > Add scrubbing support to i7core_edac, tested on intel Xeon L5638. > > Signed-off-by: Samuel Gabrielsson <samuel.gabrielsson@gmail.com> Acked-by: Nils Carlson <nils.carlson@ludd.ltu.se> > --- > 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 1db6092..3afb187 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"); > /* OFFSETS for Device 0 Function 0 */ > > #define MC_CFG_CONTROL 0x90 > + #define MC_CFG_UNLOCK 0x02 > + #define MC_CFG_LOCK 0x00 > > /* OFFSETS for Device 3 Function 0 */ > > @@ -98,6 +100,14 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI > fixup to seek for hidden devices"); > #define DIMM0_COR_ERR(r) ((r) & 0x7fff) > > /* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 > datasheet */ > +#define MC_SSRCONTROL 0x48 > + #define SSR_MODE_DISABLE 0x00 > + #define SSR_MODE_ENABLE 0x01 > + #define SSR_MODE_MASK 0x03 > + > +#define MC_SCRUB_CONTROL 0x4c > + #define STARTSCRUB (1 << 24) > + > #define MC_COR_ECC_CNT_0 0x80 > #define MC_COR_ECC_CNT_1 0x84 > #define MC_COR_ECC_CNT_2 0x88 > @@ -1871,6 +1881,116 @@ static int i7core_mce_check_error(void > *priv, struct mce *mce) > return 1; > } > > +/* > + * set_sdram_scrub_rate This routine sets byte/sec bandwidth scrub > rate > + * to hardware according to SCRUBINTERVAL formula > + * found in datasheet. > + */ > +static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw) > +{ > + struct i7core_pvt *pvt = mci->pvt_info; > + struct pci_dev *pdev; > + const u32 cache_line_size = 64; > + const u32 freq_dclk = 800*1000000; > + u32 dw_scrub; > + u32 dw_ssr; > + > + /* Get data from the MC register, function 2 */ > + pdev = pvt->pci_mcr[2]; > + if (!pdev) > + return -ENODEV; > + > + pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &dw_scrub); > + > + if (new_bw == 0) { > + /* Prepare to disable petrol scrub */ > + dw_scrub &= ~STARTSCRUB; > + /* Stop the patrol scrub engine */ > + write_and_test(pdev, MC_SCRUB_CONTROL, dw_scrub & ~0x00ffffff); > + > + /* Get current status of scrub rate and set bit to disable */ > + pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr); > + dw_ssr &= ~SSR_MODE_MASK; > + dw_ssr |= SSR_MODE_DISABLE; > + } else { > + /* > + * Translate the desired scrub rate to a register value and > + * program the cooresponding register value. > + */ > + dw_scrub = 0x00ffffff & (cache_line_size * freq_dclk / new_bw); > + > + /* Start the patrol scrub engine */ > + pci_write_config_dword(pdev, MC_SCRUB_CONTROL, > + STARTSCRUB | dw_scrub); > + > + /* Get current status of scrub rate and set bit to enable */ > + pci_read_config_dword(pdev, MC_SSRCONTROL, &dw_ssr); > + dw_ssr &= ~SSR_MODE_MASK; > + dw_ssr |= SSR_MODE_ENABLE; > + } > + /* Disable or enable scrubbing */ > + pci_write_config_dword(pdev, MC_SSRCONTROL, dw_ssr); > + > + return new_bw; > +} > + > +/* > + * get_sdram_scrub_rate This routine convert current scrub rate > value > + * into byte/sec bandwidth accourding to > + * SCRUBINTERVAL formula found in datasheet. > + */ > +static int get_sdram_scrub_rate(struct mem_ctl_info *mci) > +{ > + struct i7core_pvt *pvt = mci->pvt_info; > + struct pci_dev *pdev; > + const u32 cache_line_size = 64; > + const u32 freq_dclk = 800*1000000; > + u32 scrubval; > + > + /* Get data from the MC register, function 2 */ > + pdev = pvt->pci_mcr[2]; > + if (!pdev) > + return -ENODEV; > + > + /* Get current scrub control data */ > + pci_read_config_dword(pdev, MC_SCRUB_CONTROL, &scrubval); > + > + /* Mask highest 8-bits to 0 */ > + scrubval &= 0x00ffffff; > + if (!scrubval) > + return 0; > + > + /* Calculate scrub rate value into byte/sec bandwidth */ > + return 0xffffffff & (cache_line_size * freq_dclk / (u64) scrubval); > +} > + > +static void enable_sdram_scrub_setting(struct mem_ctl_info *mci) > +{ > + struct i7core_pvt *pvt = mci->pvt_info; > + u32 pci_lock; > + > + /* Unlock writes to pci registers */ > + pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock); > + pci_lock &= ~0x3; > + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, > + pci_lock | MC_CFG_UNLOCK); > + > + mci->set_sdram_scrub_rate = set_sdram_scrub_rate; > + mci->get_sdram_scrub_rate = get_sdram_scrub_rate; > +} > + > +static void disable_sdram_scrub_setting(struct mem_ctl_info *mci) > +{ > + struct i7core_pvt *pvt = mci->pvt_info; > + u32 pci_lock; > + > + /* Lock writes to pci registers */ > + pci_read_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, &pci_lock); > + pci_lock &= ~0x3; > + pci_write_config_dword(pvt->pci_noncore, MC_CFG_CONTROL, > + pci_lock | MC_CFG_LOCK); > +} > + > static void i7core_pci_ctl_create(struct i7core_pvt *pvt) > { > pvt->i7core_pci = edac_pci_create_generic_ctl( > @@ -1909,6 +2029,9 @@ static void i7core_unregister_mci(struct > i7core_dev *i7core_dev) > debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", > __func__, mci, &i7core_dev->pdev[0]->dev); > > + /* Disable scrubrate setting */ > + disable_sdram_scrub_setting(mci); > + > /* Disable MCE NMI handler */ > edac_mce_unregister(&pvt->edac_mce); > > @@ -1982,6 +2105,9 @@ static int i7core_register_mci(struct > i7core_dev *i7core_dev) > /* Set the function pointer to an actual operation function */ > mci->edac_check = i7core_check_error; > > + /* Enable scrubrate setting */ > + enable_sdram_scrub_setting(mci); > + > /* add this new MC control structure to EDAC's list of MCs */ > if (unlikely(edac_mc_add_mc(mci))) { > debugf0("MC: " __FILE__ > -- > 1.7.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux- > edac" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] i7core_edac: Add scrubbing support 2011-03-30 13:21 ` [PATCH 2/2] i7core_edac: Add scrubbing support Samuel Gabrielsson 2011-04-07 16:43 ` Nils Carlson @ 2011-06-24 21:47 ` Tony Luck 2011-07-22 14:06 ` Nils Carlson 1 sibling, 1 reply; 6+ messages in thread From: Tony Luck @ 2011-06-24 21:47 UTC (permalink / raw) To: Samuel Gabrielsson; +Cc: mchehab, linux-edac, linux-kernel On Wed, Mar 30, 2011 at 6:21 AM, Samuel Gabrielsson <samuel.gabrielsson@gmail.com> wrote: > + const u32 cache_line_size = 64; > + const u32 freq_dclk = 800*1000000; Is dclk always 800 MHz? If so, a #define might me nice - you use it again in get_sdram_scrub_rate(). If not, then getting the actual frequency from some place would be good. > + dw_scrub = 0x00ffffff & (cache_line_size * freq_dclk / new_bw); Does this give the right answer? It looks like you overflow the "u32" size of these calculations when you do 64*800000000 = 51200000000. > + return 0xffffffff & (cache_line_size * freq_dclk / (u64) scrubval); Ditto on the overflow question here. -Tony ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] i7core_edac: Add scrubbing support 2011-06-24 21:47 ` Tony Luck @ 2011-07-22 14:06 ` Nils Carlson 0 siblings, 0 replies; 6+ messages in thread From: Nils Carlson @ 2011-07-22 14:06 UTC (permalink / raw) To: Tony Luck; +Cc: Samuel Gabrielsson, mchehab, linux-edac, linux-kernel Hi, thanks for the comments. Unfortunately Samuel moved on to other stuff so I'll try to fix these. On Fri, 24 Jun 2011, Tony Luck wrote: > On Wed, Mar 30, 2011 at 6:21 AM, Samuel Gabrielsson > <samuel.gabrielsson@gmail.com> wrote: > > + const u32 cache_line_size = 64; > > + const u32 freq_dclk = 800*1000000; > > Is dclk always 800 MHz? If so, a #define might me nice - you use it again in > get_sdram_scrub_rate(). If not, then getting the actual frequency from some > place would be good. Does anybody know a good reliable way to get the frequency from within the kernel? dmidecode works, but any easier ways would be nice. Happy for any help. > > + dw_scrub = 0x00ffffff & (cache_line_size * freq_dclk / new_bw); > > Does this give the right answer? It looks like you overflow the "u32" size > of these calculations when you do 64*800000000 = 51200000000. > > > + return 0xffffffff & (cache_line_size * freq_dclk / (u64) scrubval); > > Ditto on the overflow question here. > Will check. Thanks for the catch. /Nils > -Tony > -- > To unsubscribe from this list: send the line "unsubscribe linux-edac" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] i7core_edac: Add xeon 5600 generic non core registers 2011-03-30 13:21 [PATCH 1/2] i7core_edac: Add xeon 5600 generic non core registers Samuel Gabrielsson 2011-03-30 13:21 ` [PATCH 2/2] i7core_edac: Add scrubbing support Samuel Gabrielsson @ 2011-04-07 16:39 ` Nils Carlson 1 sibling, 0 replies; 6+ messages in thread From: Nils Carlson @ 2011-04-07 16:39 UTC (permalink / raw) To: Samuel Gabrielsson; +Cc: mchehab, linux-edac, linux-kernel On Mar 30, 2011, at 3:21 PM, Samuel Gabrielsson wrote: > This enables writing to registers in device 0 function 0 such as > MC_CFG_CONTROL. This also fixes a bug for intel xeon 5600 series > when writing to inject_enable where we would get an Oops because > pvt->pci_noncore was not set. > > Signed-off-by: Samuel Gabrielsson <samuel.gabrielsson@gmail.com> Acked-by: Nils Carlson <nils.carlson@ludd.ltu.se> > --- > drivers/edac/i7core_edac.c | 3 +++ > 1 files changed, 3 insertions(+), 0 deletions(-) > > diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c > index 81154ab..1db6092 100644 > --- a/drivers/edac/i7core_edac.c > +++ b/drivers/edac/i7core_edac.c > @@ -322,6 +322,9 @@ static const struct pci_id_descr > pci_dev_descr_lynnfield[] = { > }; > > static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = { > + /* Generic Non-core registers */ > + { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) }, > + > /* Memory controller */ > { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) }, > { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) }, > -- > 1.7.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux- > edac" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-07-22 14:48 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-03-30 13:21 [PATCH 1/2] i7core_edac: Add xeon 5600 generic non core registers Samuel Gabrielsson 2011-03-30 13:21 ` [PATCH 2/2] i7core_edac: Add scrubbing support Samuel Gabrielsson 2011-04-07 16:43 ` Nils Carlson 2011-06-24 21:47 ` Tony Luck 2011-07-22 14:06 ` Nils Carlson 2011-04-07 16:39 ` [PATCH 1/2] i7core_edac: Add xeon 5600 generic non core registers Nils Carlson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®