Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 149833 Details for
Bug 231854
[RHEL4] Incorrect memory sizing reported by EDAC on HP xw9400
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
test patch
edac-k8_add_support_to_rev_f_cpus.patch (text/plain), 24.19 KB, created by
Aristeu Rozanski
on 2007-03-12 16:22:01 UTC
(
hide
)
Description:
test patch
Filename:
MIME Type:
Creator:
Aristeu Rozanski
Created:
2007-03-12 16:22:01 UTC
Size:
24.19 KB
patch
obsolete
>Index: linux-2.6.9/drivers/edac/edac_mc.h >=================================================================== >--- linux-2.6.9.orig/drivers/edac/edac_mc.h >+++ linux-2.6.9/drivers/edac/edac_mc.h >@@ -100,7 +100,10 @@ enum mem_type { > MEM_RDR, /* Registered single data rate SDRAM */ > MEM_DDR, /* Double data rate SDRAM */ > MEM_RDDR, /* Registered Double data rate SDRAM */ >- MEM_RMBS /* Rambus DRAM */ >+ MEM_RMBS, /* Rambus DRAM */ >+ MEM_DDR2, /* DDR2 RAM */ >+ MEM_FB_DDR2, /* fully buffered DDR2 */ >+ MEM_RDDR2, /* Registered DDR2 RAM */ > }; > > #define MEM_FLAG_EMPTY BIT(MEM_EMPTY) >@@ -114,6 +117,9 @@ enum mem_type { > #define MEM_FLAG_DDR BIT(MEM_DDR) > #define MEM_FLAG_RDDR BIT(MEM_RDDR) > #define MEM_FLAG_RMBS BIT(MEM_RMBS) >+#define MEM_FLAG_DDR2 BIT(MEM_DDR2) >+#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2) >+#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2) > > > /* chipset Error Detection and Correction capabilities and mode */ >Index: linux-2.6.9/drivers/edac/k8_edac.c >=================================================================== >--- linux-2.6.9.orig/drivers/edac/k8_edac.c >+++ linux-2.6.9/drivers/edac/k8_edac.c >@@ -91,7 +91,7 @@ > /* > * Alter this version for the K8 module when modifications are made > */ >-#define EDAC_K8_VERSION " Ver: 2.0.0 " __DATE__ >+#define EDAC_K8_VERSION " Ver: 2.0.2 " __DATE__ > #define EDAC_MOD_STR "k8_edac" > > #ifndef PCI_DEVICE_ID_AMD_OPT_0_HT >@@ -114,6 +114,11 @@ > #define OPTERON_CPU_LE_REV_C 0 > #define OPTERON_CPU_REV_D 1 > #define OPTERON_CPU_REV_E 2 >+/* Unknown Extended Model value */ >+#define OPTERON_CPU_REV_X 3 >+/* NPT processors have the following Extended Models */ >+#define OPTERON_CPU_REV_F 4 >+#define OPTERON_CPU_REV_FA 5 > > #define K8_NR_CSROWS 8 > #define MAX_K8_NODES 8 >@@ -152,12 +157,42 @@ > /* K8 register addresses - device 0 function 2 - DRAM controller */ > #define K8_DCSB 0x40 /* DRAM Chip-Select Base (8 x 32b) > * >+ * For Rev E and prior > * 31:21 Base addr high 35:25 > * 20:16 reserved > * 15:9 Base addr low 19:13 (interlvd) > * 8:1 reserved > * 0 chip-select bank enable >+ * >+ * For Rev F (NPT) and later >+ * 31:29 reserved >+ * 28:19 Base address (36:27) >+ * 18:14 reserved >+ * 13:5 Base address (21:13) >+ * 4:3 reserved >+ * 2 TestFail >+ * 1 Spare Rank >+ * 0 CESenable > */ >+#define K8_DCSB_CS_ENABLE 0x1 >+#define K8_DCSB_NPT_SPARE 0x2 >+#define K8_DCSB_NPT_TESTFAIL 0x4 >+ >+/* REV E: selects bits 31-21 and 15-9 from DCSB >+ * and the shift amount to form address >+ */ >+#define REV_E_DCSB_BASE_BITS (0xFFE0FE00ULL) >+#define REV_E_DCS_SHIFT 4 >+#define REV_E_DCSM_SHIFT 0 >+#define REF_E_DCSM_COUNT 4 >+ >+/* REV F: selects bits 28-19 and 13-5 from DCSB >+ * and the shift amount to form address >+ */ >+#define REV_F_DCSB_BASE_BITS (0x1FF83FE0ULL) >+#define REV_F_DCS_SHIFT 8 >+#define REV_F_DCSM_SHIFT 1 >+#define REF_F_DCSM_COUNT 8 > > #define K8_DCSM 0x60 /* DRAM Chip-Select Mask (8 x 32b) > * >@@ -168,13 +203,22 @@ > * 8:0 reserved > */ > >-/* selects bits 29-21 and 15-9 from DCSM */ >-#define DCSM_MASK_BITS 0x3fe0fe00 >+/* REV E: selects bits 29-21 and 15-9 from DCSM */ >+#define REV_E_DCSM_MASK_BITS 0x3FE0FE00 >+/* represents unused bits [24-20] and [12-0] */ >+#define REV_E_DCS_NOTUSED_BITS 0x1f01fff >+ >+/* REV F: selects bits 28-19 and 13-5 from DCSM */ >+#define REV_F_DCSM_MASK_BITS 0x1FF83FC0 >+/* represents unused bits [26-22] and [12-0] */ >+#define REV_F_DCS_NOTUSED_BITS 0x03c1fff > > #define K8_DBAM 0x80 /* DRAM Base Addr Mapping (32b) */ > > #define K8_DCL 0x90 /* DRAM configuration low reg (32b) > * >+ * Rev E and earlier CPUS: >+ * > * 31:28 reserved > * 27:25 Bypass Max: 000b=respect > * 24 Dissable receivers - no sockets >@@ -195,6 +239,24 @@ > * 2 QFC enabled > * 1 DRAM drive strength > * 0 Digital Locked Loop disable >+ * >+ * Rev F and later CPUs: >+ * >+ * 31:20 reserved >+ * 19 DIMM ECC Enable >+ * 18:17 reserved >+ * 16 Unbuffered DIMM >+ * 15:12 x4 DIMMs >+ * 11 Width128 bits >+ * 10 burstLength32 >+ * 9 SelRefRateEn >+ * 8 ParEn >+ * 7 DramDrvWeak >+ * 6 reserved >+ * 5:4 DramTerm >+ * 3:2 reserved >+ * 1 ExitSelfRef >+ * 0 InitDram > */ > > /* K8 register addresses - device 0 function 3 - Misc Control */ >@@ -210,6 +272,8 @@ > * 22 ECC enable > * 1 CPU ECC enable > */ >+#define K8_NBCFG_CHIPKILL 23 >+#define K8_NBCFG_ECC_ENABLE 22 > > #define K8_NBSL 0x48 /* MCA NB Status Low (32b) > * >@@ -261,6 +325,8 @@ > * 4 S4ECD4ED capable > * 3 SECDED capable > */ >+#define K8_NBCAP_CHIPKILL 4 >+#define K8_NBCAP_SECDED 3 > > /* MSR's */ > >@@ -318,9 +384,9 @@ > #define K8_MSR_MC4STAT 0x0411 /* North Bridge status (64b) */ > #define K8_MSR_MC4ADDR 0x0412 /* North Bridge Address (64b) */ > >-static inline int MCI_TO_NODE_ID(struct mem_ctl_info *mci) >+static inline int MCI_TO_NODE_ID(struct pci_dev *pdev) > { >- return PCI_SLOT(mci->pdev->devfn) - 0x18; >+ return PCI_SLOT(pdev->devfn) - 0x18; > } > > /* Ugly hack that allows module to compile when built as part of a 32-bit >@@ -373,6 +439,7 @@ struct k8_pvt { > struct pci_dev *misc_ctl; > > int node_id; /* ID of this node */ >+ int ext_model; > > /* The values of these registers will remain constant so we might as > * well cache them here. >@@ -381,8 +448,27 @@ struct k8_pvt { > u32 dbr[MAX_K8_NODES]; > u32 dlr[MAX_K8_NODES]; > u32 nbcap; >+ u32 nbcfg; > u32 dcsb[K8_NR_CSROWS]; > u32 dcsm[K8_NR_CSROWS]; >+ >+ /* The following 3 fields are set at run time, after Revision has >+ * been determine, since the dcsb and dcsm registers vary >+ * by CPU Revsion >+ */ >+ u32 dcsb_mask; /* DCSB mask bits */ >+ u32 dcsm_mask; /* DCSM mask bits */ >+ u32 num_dcsm; /* Number of DCSM registers */ >+ u32 dcs_mask_notused; /* DCSM notused mask bits */ >+ u32 dcs_shift; /* DCSB and DCSM shift value */ >+ >+ /* On Rev E there are 8 DCSM registers, >+ * On Rev F there are 4 DCSM registers. >+ * This field is set as a 0 (Rev E) or 1 (Rev F) to indicate >+ * number of bits to shift the index for DCSM array look ups >+ */ >+ u32 dcsm_shift_bit; >+ > u32 dhar; > u32 dbam; > }; >@@ -396,7 +482,6 @@ struct k8_error_info_regs { > > struct k8_error_info { > struct k8_error_info_regs error_info; >- u32 nbcfg; > int race_condition_detected; > }; > >@@ -664,30 +749,150 @@ static const char *htlink_msgs[] = { > "1 2 3" > }; > >-static inline u64 base_from_dcsb(u32 dcsb) >+/* >+ * The DCSB and DCSM registers differ between Rev E and Rev F CPUs >+ * The following several functions intialize and extract information >+ * from this registers >+ */ >+ >+/* >+ * set_dcsb_dcsm_rev_specific(pvt) >+ * >+ * NOTE: CPU Revision Dependent code >+ * >+ * Set the DCSB and DCSM mask values depending on the >+ * CPU revision value. >+ * Also set the shift factor for the DCSB and DCSM values >+ * >+ * member dcs_mask_notused, REV E: >+ * >+ * To find the max InputAddr for the csrow, start with the base >+ * address and set all bits that are "don't care" bits in the test at >+ * the start of section 3.5.4 (p. 84). >+ * >+ * The "don't care" bits are all set bits in the mask and >+ * all bits in the gaps between bit ranges [35-25] and [19-13]. >+ * The value REV_E_DCS_NOTUSED_BITS represents bits [24-20] and [12-0], >+ * which are all bits in the above-mentioned gaps. >+ * >+ * member dcs_mask_notused, REV F: >+ * >+ * To find the max InputAddr for the csrow, start with the base >+ * address and set all bits that are "don't care" bits in the test at >+ * the start of NPT section 4.5.4 (p. 87). >+ * >+ * The "don't care" bits are all set bits in the mask and >+ * all bits in the gaps between bit ranges [36-27] and [21-13]. >+ * The value REV_F_DCS_NOTUSED_BITS represents bits [26-22] and [12-0], >+ * which are all bits in the above-mentioned gaps. >+ */ >+static void set_dcsb_dcsm_rev_specific(struct k8_pvt *pvt) >+{ >+ if ( pvt->ext_model >= OPTERON_CPU_REV_F) { >+ pvt->dcsb_mask = REV_F_DCSB_BASE_BITS; >+ pvt->dcsm_mask = REV_F_DCSM_MASK_BITS; >+ pvt->dcs_mask_notused = REV_F_DCS_NOTUSED_BITS; >+ pvt->dcs_shift = REV_F_DCS_SHIFT; >+ pvt->dcsm_shift_bit = REV_F_DCSM_SHIFT; >+ pvt->num_dcsm = REF_F_DCSM_COUNT; >+ } else { >+ pvt->dcsb_mask = REV_E_DCSB_BASE_BITS; >+ pvt->dcsm_mask = REV_E_DCSM_MASK_BITS; >+ pvt->dcs_mask_notused = REV_E_DCS_NOTUSED_BITS; >+ pvt->dcs_shift = REV_E_DCS_SHIFT; >+ pvt->dcsm_shift_bit = REV_E_DCSM_SHIFT; >+ pvt->num_dcsm = REF_E_DCSM_COUNT; >+ } >+} >+ >+/* >+ * get_dcsb() >+ * >+ * getter function to return the 'base' address the i'th CS entry. >+ */ >+static u32 get_dcsb(struct k8_pvt *pvt, int csrow) > { > /* 0xffe0fe00 selects bits 31-21 and 15-9 of a DRAM CS Base Address > * Register (section 3.5.4). Shifting the bits left 4 puts them in > * their proper bit positions of 35-25 and 19-13. > */ >- return ((u64) (dcsb & 0xffe0fe00)) << 4; >+ return pvt->dcsb[csrow]; >+} >+ >+/* >+ * get_dcsm() >+ * >+ * getter function to return the 'mask' address the i'th CS entry. >+ * This getter function is needed because there different number >+ * of DCSM registers on Rev E and prior vs Rev F and later >+ */ >+static u32 get_dcsm(struct k8_pvt *pvt, int csrow) >+{ >+ return pvt->dcsm[csrow >> pvt->dcsm_shift_bit]; >+} >+ >+ >+/* >+ * base_from_dcsb >+ * >+ * Extract the DRAM CS base address from selected csrow register >+ */ >+static u64 base_from_dcsb(struct k8_pvt *pvt, int csrow) >+{ >+ return ((u64)(get_dcsb(pvt, csrow) & pvt->dcsb_mask)) << >+ pvt->dcs_shift; > } > >-static u64 mask_from_dcsm(u32 dcsm) >+static u64 mask_from_dcsm(struct k8_pvt *pvt, int csrow) > { > u64 dcsm_bits, other_bits; > > /* Extract bits bits 29-21 and 15-9 from DCSM (section 3.5.5). */ >- dcsm_bits = dcsm & DCSM_MASK_BITS; >+ dcsm_bits = get_dcsm(pvt, csrow) & pvt->dcsm_mask; > > /* Set all bits except bits 33-25 and 19-13. */ >- other_bits = DCSM_MASK_BITS; >- other_bits = ~(other_bits << 4); >+ other_bits = pvt->dcsm_mask; >+ other_bits = ~(other_bits << pvt->dcs_shift); > > /* The extracted bits from DCSM belong in the spaces represented by > * the cleared bits in other_bits. > */ >- return (dcsm_bits << 4) | other_bits; >+ return (dcsm_bits << pvt->dcs_shift) | other_bits; >+} >+ >+/* >+ * setup_dcsb_dcsm() >+ * >+ * Setup the DCSB and DCSM arrays from hardware >+ */ >+static void setup_dcsb_dcsm(struct k8_pvt *pvt, struct pci_dev *pdev) >+{ >+ int i; >+ >+ /* Set the dcsb and dcsm mask bits and their shift value */ >+ set_dcsb_dcsm_rev_specific(pvt); >+ >+ /* Retrieve the DRAM CS Base Address Registers from hardware >+ */ >+ for (i = 0; i < K8_NR_CSROWS; i++) { >+ pci_read_config_dword(pdev, K8_DCSB + (i * 4), &pvt->dcsb[i]); >+ debugf1(" dcsb[%d]: 0x%x\n", i, pvt->dcsb[i]); >+ } >+ >+ /* The number of DCSMs differents at the Rev E/Rev F boundary >+ * so we retrieve the number of registers defined for this processor >+ */ >+ for (i = 0; i < pvt->num_dcsm; i++) { >+ pci_read_config_dword(pdev, K8_DCSM + (i * 4), &pvt->dcsm[i]); >+ debugf1(" dcsm[%d]: 0x%x\n", i, pvt->dcsm[i]); >+ } >+ >+ /* Debug dump only of DCSB and DCSM registers */ >+ for (i = 0; i < K8_NR_CSROWS; i++) { >+ debugf1(" dcsb[%d]: 0x%8.8x dcsm[%d]: 0x%x\n", >+ i, get_dcsb(pvt,i), >+ i>> pvt->dcsm_shift_bit, get_dcsm(pvt,i)); >+ } > } > > /* In *base and *limit, pass back the full 40-bit base and limit physical >@@ -845,9 +1050,9 @@ static int get_dram_hole_info(struct mem > > pvt = mci->pvt_info; > >- if (node_rev(pvt->node_id) < OPTERON_CPU_REV_E) { >+ if (pvt->ext_model < OPTERON_CPU_REV_E) { > debugf2("revision %d for node %d does not support DHAR\n", >- node_rev(pvt->node_id), pvt->node_id); >+ pvt->ext_model, pvt->node_id); > return 1; > } > >@@ -1032,15 +1237,15 @@ static int input_addr_to_csrow(struct me > dcsb = pvt->dcsb[i]; > dcsm = pvt->dcsm[i]; > >- if ((dcsb & 0x01) == 0) { >+ if ((dcsb & K8_DCSB_CS_ENABLE) == 0) { > debugf2("input_addr_to_csrow: CSBE bit is cleared " > "for csrow %d (node %d)\n", i, > pvt->node_id); > continue; /* CSBE bit is cleared */ > } > >- base = base_from_dcsb(dcsb); >- mask = ~mask_from_dcsm(dcsm); >+ base = base_from_dcsb(pvt, i); >+ mask = ~mask_from_dcsm(pvt, i); > > if ((input_addr & mask) == (base & mask)) { > debugf2("InputAddr 0x%lx matches csrow %d " >@@ -1159,8 +1364,8 @@ static void find_csrow_limits(struct mem > > pvt = mci->pvt_info; > BUG_ON((csrow < 0) || (csrow >= K8_NR_CSROWS)); >- base = base_from_dcsb(pvt->dcsb[csrow]); >- mask = mask_from_dcsm(pvt->dcsm[csrow]); >+ base = base_from_dcsb(pvt, csrow); >+ mask = mask_from_dcsm(pvt, csrow); > *input_addr_min = base & ~mask; > > /* To find the max InputAddr for the csrow, start with the base >@@ -1170,7 +1375,7 @@ static void find_csrow_limits(struct mem > * [35-25] and [19-13]. The value 0x1f01fff represents bits [24-20] > * and [12-0], which are all bits in the above-mentioned gaps. > */ >- *input_addr_max = base | mask | 0x1f01fff; >+ *input_addr_max = base | mask | pvt->dcs_mask_notused; > } > > /* Extract error address from MCA NB Address Low (section 3.6.4.5) and >@@ -1265,7 +1470,7 @@ static void k8_get_error_info(struct mem > /* clear the error */ > pci_write_bits32(pvt->misc_ctl, K8_NBSH, 0, K8_NBSH_VALID_BIT); > >- pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &info->nbcfg); >+ pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &pvt->nbcfg); > info->race_condition_detected = > ((regs.nbsh != info->error_info.nbsh) || > (regs.nbsl != info->error_info.nbsl) || >@@ -1346,7 +1551,7 @@ static void k8_handle_ce(struct mem_ctl_ > error_address = error_address_from_k8_error_info(info); > syndrome = ((info->error_info.nbsh >> 15) & 0xff); > >- if (info->nbcfg & BIT(23)) { >+ if (pvt->nbcfg & BIT(K8_NBCFG_CHIPKILL)) { > /* chipkill ecc mode */ > syndrome += (info->error_info.nbsl >> 16) & 0xff00; > channel = chan_from_chipkill_syndrome(syndrome); >@@ -1613,7 +1818,10 @@ static void k8_get_mc_regs(struct mem_ct > > pdev = mci->pdev; > pvt = mci->pvt_info; >- debugf1("k8 regs:\n"); >+ debugf1("%s(MC node-id=%d): (ExtModel=%d) %s\n", >+ __func__, pvt->node_id, pvt->ext_model, >+ (pvt->ext_model >= OPTERON_CPU_REV_F) ? >+ "Rev F or later" : "Rev E or earlier"); > > for (i = 0; i < MAX_K8_NODES; i++) { > pci_read_config_dword(pvt->addr_map, K8_DBR + (i * 8), >@@ -1624,46 +1832,173 @@ static void k8_get_mc_regs(struct mem_ct > debugf1(" dlr[%d]: 0x%x\n", i, pvt->dlr[i]); > } > >- pci_read_config_dword(pvt->misc_ctl, K8_NBCAP, &pvt->nbcap); >- debugf1(" nbcap: %u\n", pvt->nbcap); >- >- for (i = 0; i < K8_NR_CSROWS; i++) { >- pci_read_config_dword(pdev, K8_DCSB + (i * 4), &pvt->dcsb[i]); >- pci_read_config_dword(pdev, K8_DCSM + (i * 4), &pvt->dcsm[i]); >- debugf1(" dcsb[%d]: 0x%x\n", i, pvt->dcsb[i]); >- debugf1(" dcsm[%d]: 0x%x\n", i, pvt->dcsm[i]); >- } >+ /* Setup the DCSB and DCSM arrays from hardware */ >+ setup_dcsb_dcsm(pvt,pdev); > > pci_read_config_dword(pvt->addr_map, K8_DHAR, &pvt->dhar); > pci_read_config_dword(pdev, K8_DBAM, &pvt->dbam); >+ pci_read_config_dword(pvt->misc_ctl, K8_NBCAP, &pvt->nbcap); > debugf1(" dhar: 0x%x\n", pvt->dhar); > debugf1(" dbam: 0x%x\n", pvt->dbam); >+ debugf1(" dcl: 0x%x\n", pvt->dcl); >+ debugf1(" nbcap: %u\n", pvt->nbcap); > } > > /* Return 1 if dual channel mode is active. Else return 0. */ >-static inline int dual_channel_active(u32 dcl) >+static inline int dual_channel_active(u32 dcl, int mc_device_index) > { >- return (dcl >> 16) & 0x1; >+ int flag; >+ int ext_model = node_rev(mc_device_index); >+ >+ if (ext_model >= OPTERON_CPU_REV_F) { >+ /* Rev F (NPT) and later */ >+ flag = (dcl >> 11) & 0x1; >+ } else { >+ /* Rev E and earlier */ >+ flag = (dcl >> 16) & 0x1; >+ } >+ >+ return flag; > } > > static u32 csrow_nr_pages(int csrow_nr, struct k8_pvt *pvt) > { >- u32 cs; >+ u32 shift, nr_pages; >+ int ext_model = pvt->ext_model; > > /* The math on this doesn't look right on the surface because x/2*4 > * can be simplified to x*2 but this expression makes use of the fact > * that it is integral math where 1/2=0 > */ >- cs = (pvt->dbam >> ((csrow_nr / 2) * 4)) & 0xF; /* PG88 */ >- >- /* This line is tricky. It collapses the table used by revision D and >- * later to one that matches revision CG and earlier >+ shift = (pvt->dbam >> ((csrow_nr / 2) * 4)) & 0xF; /*PG88 */ >+ debugf0(" %s(csrow=%d) DBAM index= %d\n", __func__, csrow_nr, >+ shift); >+ /* First step is to calc the number of bits to shift a value of 1 >+ * left to indicate show many pages. Start with the DBAM value >+ * as the starting bits, then proceed to adjust those shift >+ * bits, based on CPU REV and the table. See BKDG on the DBAM > */ >- cs -= (node_rev(pvt->node_id) >= OPTERON_CPU_REV_D) ? >- (cs > 8 ? 4 : (cs > 5 ? 3 : (cs > 2 ? 1 : 0))) : 0; > >- /* 25 is 32MiB minimum DIMM size */ >- return 1 << (cs + 25 - PAGE_SHIFT + dual_channel_active(pvt->dcl)); >+ if (ext_model >= OPTERON_CPU_REV_F) { >+ /* 27 shift, is 128Mib minimum DIMM size in REV F and later >+ * upto 8 Gb, in a step function progression >+ */ >+ static u32 rev_f_shift[] = { 27, 28, 29, 29, 29, 30, 30, 31, >+ 31, 32, 32, 33, 0, 0, 0, 0 }; >+ nr_pages = 1 << (rev_f_shift[shift] - PAGE_SHIFT); >+ } else { >+ /* REV E and less section This line is tricky. >+ * It collapses the table used by revision D and later to one >+ * that matches revision CG and earlier >+ */ >+ shift -= (ext_model >= OPTERON_CPU_REV_D)? >+ (shift > 8 ? 4: >+ (shift > 5 ? 3: >+ (shift > 2 ? 1 : 0))): 0; >+ /* 25 shift, is 32MiB minimum DIMM size in REV E and prior */ >+ nr_pages = 1 << (shift + 25 - PAGE_SHIFT); >+ } >+ >+ /* If dual channel then double thememory size of single channel */ >+ nr_pages <<= dual_channel_active(pvt->dcl, pvt->node_id); >+ >+ debugf0(" nr_pages= %u dual channel_active = %d\n", >+ nr_pages, dual_channel_active(pvt->dcl, pvt->node_id)); >+ >+ return nr_pages; >+} >+ >+/* >+ * determine_parity_enabled() >+ * >+ * NOTE: CPU Revision Dependent code >+ * >+ * determine if Parity is Enabled >+ */ >+static int determine_parity_enabled(struct k8_pvt *pvt) >+{ >+ int rc = 0; >+ >+ if (pvt->ext_model >= OPTERON_CPU_REV_F) { >+ if (pvt->dcl & BIT(8)) >+ rc = 1; >+ } >+ >+ return rc; >+} >+ >+/* >+* determine_memory_type() >+* >+* NOTE: CPU Revision Dependent code >+* >+* determine the memory type in operation on this controller >+*/ >+static enum mem_type determine_memory_type(struct k8_pvt *pvt) >+{ >+ enum mem_type type; >+ >+ if (pvt->ext_model >= OPTERON_CPU_REV_F) { >+ /* Rev F and later */ >+ type = ((pvt->dcl >> 16) & 0x1) ? MEM_DDR2 : MEM_RDDR2; >+ } else { >+ /* Rev E and earlier */ >+ type = ((pvt->dcl >> 18) & 0x1) ? MEM_DDR : MEM_RDDR; >+ } >+ >+ debugf1(" Memory type is: %s\n", >+ (type == MEM_DDR2) ? "MEM_DDR2" : >+ (type == MEM_RDDR2) ? "MEM_RDDR2" : >+ (type == MEM_DDR) ? "MEM_DDR" : "MEM_RDDR"); >+ >+ return type; >+} >+ >+/* >+ * determine_dram_type() >+ * >+ * NOTE: CPU Revision Dependent code >+ * >+ * determine the DRAM type in operation >+ * There are K8_NR_CSROWS (8) and 2 CSROWS per DIMM, therefore >+ * there are 4 Logical DIMMs possible, thus 4 bits in the >+ * configuration register indicating whether there are >+ * X4 or X8 devices, one per logical DIMM >+ */ >+static enum dev_type determine_dram_type(struct k8_pvt *pvt, int row) >+{ >+ int bit; >+ enum dev_type type; >+ >+ /* the starting bit depends on Revision value */ >+ bit = (pvt->ext_model >= OPTERON_CPU_REV_F) ? 12 : 20; >+ type = ((pvt->dcl >> (bit + (row / 2))) & 0x01) ? DEV_X4 : DEV_X8; >+ >+ debugf1(" DRAM type is: %s\n", (type == DEV_X4) ? "DEV-x4" : "DEV-x8"); >+ >+ return type; >+} >+ >+/* >+ * determine_edac_cap() >+ * >+ * NOTE: CPU Revision Dependent code >+ * >+ * determine if the DIMMs have ECC enabled >+ * ECC is enabled ONLY if all the DIMMs are ECC capable >+ */ >+static enum edac_type determine_edac_cap(struct k8_pvt *pvt) >+{ >+ int bit; >+ enum dev_type edac_cap = EDAC_NONE; >+ >+ bit = (pvt->ext_model >= OPTERON_CPU_REV_F) ? 19 : 17; >+ if ((pvt->dcl >> bit) & 0x1) { >+ debugf1(" edac_type is: EDAC_FLAG_SECDED\n"); >+ edac_cap = EDAC_FLAG_SECDED; >+ } >+ >+ return edac_cap; > } > > static int k8_init_csrows(struct mem_ctl_info *mci) >@@ -1672,16 +2007,15 @@ static int k8_init_csrows(struct mem_ctl > struct k8_pvt *pvt; > int i, empty; > u64 input_addr_min, input_addr_max, sys_addr; >- u32 nbcfg; > > pvt = mci->pvt_info; >- pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &nbcfg); >+ pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &pvt->nbcfg); > empty = 1; > > for (i = 0; i < K8_NR_CSROWS; i++) { > csrow = &mci->csrows[i]; > >- if ((pvt->dcsb[i] & 0x01) == 0) { >+ if ((pvt->dcsb[i] & K8_DCSB_CS_ENABLE) == 0) { > debugf1("csrow %d empty for node %d\n", i, > pvt->node_id); > continue; /* empty */ >@@ -1696,11 +2030,10 @@ static int k8_init_csrows(struct mem_ctl > csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT); > sys_addr = input_addr_to_sys_addr(mci, input_addr_max); > csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT); >- csrow->page_mask = ~mask_from_dcsm(pvt->dcsm[i]); >+ csrow->page_mask = ~mask_from_dcsm(pvt, i); > csrow->grain = 8; /* 8 bytes of resolution */ >- csrow->mtype = ((pvt->dcl >> 18) & 0x1) ? MEM_DDR : MEM_RDDR; >- csrow->dtype = ((pvt->dcl >> (20 + (i / 2))) & 0x01) ? >- DEV_X4 : DEV_UNKNOWN; >+ csrow->mtype = determine_memory_type(pvt); >+ csrow->dtype = determine_dram_type(pvt, i); > debugf1("for node %d csrow %d:\n nr_pages: %u " > "input_addr_min: 0x%lx input_addr_max: 0x%lx " > "sys_addr: 0x%lx first_page: 0x%lx last_page: 0x%lx " >@@ -1712,8 +2045,8 @@ static int k8_init_csrows(struct mem_ctl > csrow->first_page, csrow->last_page, > csrow->page_mask); > >- if (nbcfg & BIT(22)) >- csrow->edac_mode = (nbcfg & BIT(23)) ? >+ if (pvt->nbcfg & BIT(K8_NBCFG_ECC_ENABLE)) >+ csrow->edac_mode = (pvt->nbcfg & BIT(K8_NBCFG_CHIPKILL)) ? > EDAC_S4ECD4ED : EDAC_SECDED; > else > csrow->edac_mode = EDAC_NONE; >@@ -1744,15 +2077,17 @@ static int k8_probe1(struct pci_dev *pde > struct mem_ctl_info *mci; > struct k8_pvt *pvt; > u32 dcl, dual_channel; >+ int parity_enable; > > debugf0("%s()\n", __func__); > build_node_revision_table(); > debugf1("pdev bus %u devfn %u\n", pdev->bus->number, pdev->devfn); > pci_read_config_dword(pdev, K8_DCL, &dcl); >- dual_channel = dual_channel_active(dcl); >+ dual_channel = dual_channel_active(dcl, >+ MCI_TO_NODE_ID(pdev)); > debugf1("dual_channel is %u (dcl is 0x%x)\n", dual_channel, dcl); >- mci = edac_mc_alloc(sizeof(*pvt), K8_NR_CSROWS, dual_channel + 1); > >+ mci = edac_mc_alloc(sizeof(*pvt), K8_NR_CSROWS, dual_channel + 1); > if (mci == NULL) > return -ENOMEM; > >@@ -1760,33 +2095,39 @@ static int k8_probe1(struct pci_dev *pde > pvt = mci->pvt_info; > pvt->dcl = dcl; > mci->pdev = pdev; >- pvt->node_id = MCI_TO_NODE_ID(mci); >+ pvt->node_id = MCI_TO_NODE_ID(pdev); >+ pvt->ext_model = node_rev(pvt->node_id); > > if (k8_get_devs(mci, dev_idx)) > goto fail0; > > k8_get_mc_regs(mci); >- mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR; >+ mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2; > mci->edac_ctl_cap = EDAC_FLAG_NONE; > debugf1("Initializing mci->edac_cap to EDAC_FLAG_NONE\n"); > mci->edac_cap = EDAC_FLAG_NONE; > >- if ((pvt->nbcap >> 3) & 0x1) >+ if (pvt->nbcap & BIT(K8_NBCAP_SECDED)) > mci->edac_ctl_cap |= EDAC_FLAG_SECDED; > >- if ((pvt->nbcap >> 4) & 0x1) >+ if (pvt->nbcap & BIT(K8_NBCAP_CHIPKILL)) > mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED; > >- if ((pvt->dcl >> 17) & 0x1) { >+ mci->edac_cap = determine_edac_cap(pvt); >+ if (mci->edac_cap & EDAC_FLAG_SECDED) { > debugf1("setting EDAC_FLAG_SECDED in mci->edac_cap\n"); > mci->edac_cap |= EDAC_FLAG_SECDED; > >+#if 0 > if (dual_channel) { > debugf1("setting EDAC_FLAG_S4ECD4ED in " > "mci->edac_cap\n"); > mci->edac_cap |= EDAC_FLAG_S4ECD4ED; > } >+#endif > } >+ parity_enable = determine_parity_enabled(pvt); >+ debugf1(" Parity is %s\n", parity_enable ? "Enabled" : "Disabled"); > > mci->mod_name = EDAC_MOD_STR; > mci->mod_ver = EDAC_K8_VERSION; >@@ -1877,6 +2218,6 @@ module_init(k8_init); > module_exit(k8_exit); > > MODULE_LICENSE("GPL"); >-MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); >+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh, Doug Thompson, Dave Peterson"); > MODULE_DESCRIPTION("MC support for AMD K8 memory controllers - " EDAC_K8_VERSION ); > >Index: linux-2.6.9/drivers/edac/edac_mc.c >=================================================================== >--- linux-2.6.9.orig/drivers/edac/edac_mc.c >+++ linux-2.6.9/drivers/edac/edac_mc.c >@@ -116,7 +116,10 @@ static const char *mem_types[] = { > [MEM_RDR] = "Registered-SDR", > [MEM_DDR] = "Unbuffered-DDR", > [MEM_RDDR] = "Registered-DDR", >- [MEM_RMBS] = "RMBS" >+ [MEM_RMBS] = "RMBS", >+ [MEM_DDR2] = "DDR2", >+ [MEM_FB_DDR2] = "Fully-Buffered-DDR2", >+ [MEM_RDDR2] = "Registered-DDR2", > }; > > static const char *dev_types[] = {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 231854
: 149833