Skip to content

Commit

Permalink
amd64_edac: Add Family 16h support
Browse files Browse the repository at this point in the history
Add code to handle DRAM ECC errors decoding for Fam16h.

Tested on Fam16h with ECC turned on using the mce_amd_inj facility and
works fine.

Signed-off-by: Aravind Gopalakrishnan <Aravind.Gopalakrishnan@amd.com>
[ Boris: cleanups and clarifications ]
Signed-off-by: Borislav Petkov <bp@suse.de>
  • Loading branch information
Aravind Gopalakrishnan authored and Borislav Petkov committed Apr 19, 2013
1 parent 41ef2d5 commit 94c1acf
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 3 deletions.
3 changes: 2 additions & 1 deletion arch/x86/kernel/amd_nb.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ const struct pci_device_id amd_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
{}
};
EXPORT_SYMBOL(amd_nb_misc_ids);

static struct pci_device_id amd_nb_link_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
{}
};

Expand Down Expand Up @@ -81,7 +83,6 @@ int amd_cache_northbridges(void)
next_northbridge(link, amd_nb_link_ids);
}

/* some CPU families (e.g. family 0x11) do not support GART */
if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
boot_cpu_data.x86 == 0x15)
amd_northbridges.flags |= AMD_NB_GART;
Expand Down
65 changes: 64 additions & 1 deletion drivers/edac/amd64_edac.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
*
* 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)
Expand Down Expand Up @@ -340,6 +341,27 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
base_bits = GENMASK(21, 31) | GENMASK(9, 15);
mask_bits = GENMASK(21, 29) | GENMASK(9, 15);
addr_shift = 4;

/*
* F16h needs two addr_shift values: 8 for high and 6 for low
* (cf. F16h BKDG).
*/
} else if (boot_cpu_data.x86 == 0x16) {
csbase = pvt->csels[dct].csbases[csrow];
csmask = pvt->csels[dct].csmasks[csrow >> 1];

*base = (csbase & GENMASK(5, 15)) << 6;
*base |= (csbase & GENMASK(19, 30)) << 8;

*mask = ~0ULL;
/* poke holes for the csmask */
*mask &= ~((GENMASK(5, 15) << 6) |
(GENMASK(19, 30) << 8));

*mask |= (csmask & GENMASK(5, 15)) << 6;
*mask |= (csmask & GENMASK(19, 30)) << 8;

return;
} else {
csbase = pvt->csels[dct].csbases[csrow];
csmask = pvt->csels[dct].csmasks[csrow >> 1];
Expand Down Expand Up @@ -1150,6 +1172,21 @@ static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
return ddr3_cs_size(cs_mode, false);
}

/*
* F16h has only limited cs_modes
*/
static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
unsigned cs_mode)
{
WARN_ON(cs_mode > 12);

if (cs_mode == 6 || cs_mode == 8 ||
cs_mode == 9 || cs_mode == 12)
return -1;
else
return ddr3_cs_size(cs_mode, false);
}

static void read_dram_ctl_register(struct amd64_pvt *pvt)
{

Expand Down Expand Up @@ -1587,6 +1624,17 @@ static struct amd64_family_type amd64_family_types[] = {
.read_dct_pci_cfg = f15_read_dct_pci_cfg,
}
},
[F16_CPUS] = {
.ctl_name = "F16h",
.f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
.f3_id = PCI_DEVICE_ID_AMD_16H_NB_F3,
.ops = {
.early_channel_count = f1x_early_channel_count,
.map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
.dbam_to_cs = f16_dbam_to_chip_select,
.read_dct_pci_cfg = f10_read_dct_pci_cfg,
}
},
};

/*
Expand Down Expand Up @@ -1939,7 +1987,9 @@ static void read_mc_regs(struct amd64_pvt *pvt)

if (c->x86 >= 0x10) {
amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
if (c->x86 != 0x16)
/* F16h has only DCT0 */
amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);

/* F10h, revD and later can do x8 ECC too */
if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25))
Expand Down Expand Up @@ -2356,6 +2406,11 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
pvt->ops = &amd64_family_types[F15_CPUS].ops;
break;

case 0x16:
fam_type = &amd64_family_types[F16_CPUS];
pvt->ops = &amd64_family_types[F16_CPUS].ops;
break;

default:
amd64_err("Unsupported family!\n");
return NULL;
Expand Down Expand Up @@ -2581,6 +2636,14 @@ static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = {
.class = 0,
.class_mask = 0,
},
{
.vendor = PCI_VENDOR_ID_AMD,
.device = PCI_DEVICE_ID_AMD_16H_NB_F2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.class = 0,
.class_mask = 0,
},

{0, }
};
Expand Down
4 changes: 3 additions & 1 deletion drivers/edac/amd64_edac.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@
*/
#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601
#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602

#define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531
#define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532

/*
* Function 1 - Address Map
Expand Down Expand Up @@ -296,6 +297,7 @@ enum amd_families {
K8_CPUS = 0,
F10_CPUS,
F15_CPUS,
F16_CPUS,
NUM_FAMILIES,
};

Expand Down
2 changes: 2 additions & 0 deletions include/linux/pci_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,8 @@
#define PCI_DEVICE_ID_AMD_15H_NB_F3 0x1603
#define PCI_DEVICE_ID_AMD_15H_NB_F4 0x1604
#define PCI_DEVICE_ID_AMD_15H_NB_F5 0x1605
#define PCI_DEVICE_ID_AMD_16H_NB_F3 0x1533
#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534
#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
Expand Down

0 comments on commit 94c1acf

Please sign in to comment.