On Tue, Sep 09, 2014 at 02:52:26PM -0500, Aravind Gopalakrishnan wrote:
Rationale behind this change:Why aren't we dealing with those registers here then?
- F2x1xx addresses were stopped from being mapped explicitly to DCT1
from F15h (OR) onwards. They use _dct[0:1] mechanism to access the
registers. So we should move away from using address ranges to select
DCT for these families.
- On newer processors, the address ranges used to indicate DCT1 (0x140,
0x1a0) have different meanings than what is assumed currently.
Changes introduced:
- amd64_read_dct_pci_cfg() now takes in dct value and uses it for
'selecting the dct'
- Update usage of the function. Keep in mind that different families
have specific handling requirements
- Remove [k8|f10]_read_dct_pci_cfg() as they don't do much different
from amd64_read_pci_cfg()
- Move the k8 specific check to amd64_read_pci_cfg
- Remove f15_read_dct_pci_cfg() and move logic to amd64_read_dct_pci_cfg()
- Remove now needless .read_dct_pci_cfg
Testing:
- Tested on Fam 10h; Fam15h Models: 00h, 30h; Fam16h using 'EDAC_DEBUG'
and mce_amd_inj
- driver obtains info from F2x registers and caches it in pvt
structures correctly
- ECC decoding works fine
Signed-off-by: Aravind Gopalakrishnan <aravind.gopalakrishnan@xxxxxxx>
---
Change in V4:
- move amd64_read_dct_pci_cfg() to amd64_edac.c and save exporting
f15h_select_dct() in the process
Changes in V3:
- per Boris suggestion
- move dct selection logic to amd64_read_dct_pci_cfg()
- remove f15_read_dct_pci_cfg() and move logic to amd64_read_dct_pci_cfg()
- misc
- modify logic in amd64_read_dct_pci_cfg() to keep in mind the specific
read handling requirements of different families. Previous version had
failed to do that.
Changes in V2: (per Boris suggestion)
- Hide family checks in amd64_read_dct_pci_cfg()
- Use pvt structure for family checks and not boot_cpu_data
drivers/edac/amd64_edac.c | 138 +++++++++++++++++++++++-----------------------
drivers/edac/amd64_edac.h | 5 --
2 files changed, 68 insertions(+), 75 deletions(-)
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index f8bf000..b39d1b0 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -87,35 +87,6 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
}
/*
- *
- * Depending on the family, F2 DCT reads need special handling:
- *
- * K8: has a single DCT only
- *
- * F10h: each DCT has its own set of regs
- * DCT0 -> F2x040..
- * DCT1 -> F2x140..
- *
- * F15h: we select which DCT we access using F1x10C[DctCfgSel]
- *
- * F16h: has only 1 DCT
- */
-static int k8_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
- const char *func)
-{
- if (addr >= 0x100)
- return -EINVAL;
-
- return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
-}
-
-static int f10_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
- const char *func)
-{
- return __amd64_read_pci_cfg_dword(pvt->F2, addr, val, func);
-}
-
-/*
* Select DCT to which PCI cfg accesses are routed
*/
static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct)
@@ -123,25 +94,51 @@ static void f15h_select_dct(struct amd64_pvt *pvt, u8 dct)
u32 reg = 0;
amd64_read_pci_cfg(pvt->F1, DCT_CFG_SEL, ®);
- reg &= (pvt->model >= 0x30) ? ~3 : ~1;
+ reg &= (pvt->model == 0x30) ? ~3 : ~1;
reg |= dct;
amd64_write_pci_cfg(pvt->F1, DCT_CFG_SEL, reg);
}
-static int f15_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
- const char *func)
+/*
+ *
+ * Depending on the family, F2 DCT reads need special handling:
+ *
+ * K8: has a single DCT only and no address offsets >= 0x100
+ *
+ * F10h: each DCT has its own set of regs
+ * DCT0 -> F2x040..
+ * DCT1 -> F2x140..
+ *
+ * F16h: has only 1 DCT
+ */
+static inline int amd64_read_dct_pci_cfg(struct amd64_pvt *pvt, u8 dct,
+ int offset, u32 *val)
{
- u8 dct = 0;
+ if (pvt->fam == 0xf) {
+ if (dct || offset >= 0x100)
+ return -EINVAL;
+ } else if (pvt->fam == 0x10 && dct) {
+ /*
+ * Note: If ganging is enabled, barring the regs
+ * F2x[1,0]98 and F2x[1,0]9C; reads reads to F2x1xx
Btw, let's do this function with a switch-case, for better
readability:
static inline int amd64_read_dct_pci_cfg(struct amd64_pvt *pvt, u8 dct,
int offset, u32 *val)
{
switch (pvt->fam) {
case 0xf:
if (dct || offset >= 0x100)
return -EINVAL;
break;
case 0x10:
if (dct) {
/*
* Note: If ganging is enabled, barring the regs
* F2x[1,0]98 and F2x[1,0]9C; reads reads to F2x1xx
* return 0. (cf. Section 2.8.1 F10h BKDG)
*/
if (dct_ganging_enabled(pvt))
return 0;
offset += 0x100;
}
break;
case 0x15:
/*
* F15h: F2x1xx addresses do not map explicitly to DCT1.
* We should select which DCT we access using F1x10C[DctCfgSel]
*/
dct = (dct && pvt->model == 0x30) ? 3 : dct;
f15h_select_dct(pvt, dct);
break;
case 0x16:
if (dct)
return -EINVAL;
break;
default:
break;
}
return amd64_read_pci_cfg(pvt->F2, offset, val);
}
...
amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);This doesn't look equivalent - above we're checking whether we're ganged
- amd64_read_dct_pci_cfg(pvt, DCLR0, &pvt->dclr0);
- amd64_read_dct_pci_cfg(pvt, DCHR0, &pvt->dchr0);
-
- if (!dct_ganging_enabled(pvt)) {
- amd64_read_dct_pci_cfg(pvt, DCLR1, &pvt->dclr1);
- amd64_read_dct_pci_cfg(pvt, DCHR1, &pvt->dchr1);
- }
+ amd64_read_dct_pci_cfg(pvt, 0, DCLR0, &pvt->dclr0);
+ amd64_read_dct_pci_cfg(pvt, 0, DCHR0, &pvt->dchr0);
pvt->ecc_sym_sz = 4;
if (pvt->fam >= 0x10) {
+ amd64_read_dct_pci_cfg(pvt, 1, DCLR0, &pvt->dclr1);
+ amd64_read_dct_pci_cfg(pvt, 1, DCHR0, &pvt->dchr1);
now you're doing it for >= F10h. Why?
Because only F10h supports ganging?
+
amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
+ /* F16h has only DCT0, so no need to read dbam1 */
if (pvt->fam != 0x16)
- /* F16h has only DCT0 */
- amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
+ amd64_read_dct_pci_cfg(pvt, 1, DBAM0, &pvt->dbam1);
/* F10h, revD and later can do x8 ECC too */
if ((pvt->fam > 0x10 || pvt->model > 7) && tmp & BIT(25))