|
@@ -280,6 +280,7 @@ struct sbridge_info {
|
|
u8 max_interleave;
|
|
u8 max_interleave;
|
|
u8 (*get_node_id)(struct sbridge_pvt *pvt);
|
|
u8 (*get_node_id)(struct sbridge_pvt *pvt);
|
|
enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt);
|
|
enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt);
|
|
|
|
+ enum dev_type (*get_width)(struct sbridge_pvt *pvt, u32 mtr);
|
|
struct pci_dev *pci_vtd;
|
|
struct pci_dev *pci_vtd;
|
|
};
|
|
};
|
|
|
|
|
|
@@ -471,6 +472,9 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
|
|
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c
|
|
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c
|
|
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d
|
|
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d
|
|
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd
|
|
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd
|
|
|
|
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1 0x2fbf
|
|
|
|
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2 0x2fb9
|
|
|
|
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3 0x2fbb
|
|
static const struct pci_id_descr pci_dev_descr_haswell[] = {
|
|
static const struct pci_id_descr pci_dev_descr_haswell[] = {
|
|
/* first item must be the HA */
|
|
/* first item must be the HA */
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0) },
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0) },
|
|
@@ -488,6 +492,9 @@ static const struct pci_id_descr pci_dev_descr_haswell[] = {
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1) },
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1) },
|
|
|
|
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1) },
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1) },
|
|
|
|
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1, 1) },
|
|
|
|
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2, 1) },
|
|
|
|
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3, 1) },
|
|
|
|
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1) },
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1) },
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1) },
|
|
{ PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1) },
|
|
@@ -762,6 +769,49 @@ out:
|
|
return mtype;
|
|
return mtype;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr)
|
|
|
|
+{
|
|
|
|
+ /* there's no way to figure out */
|
|
|
|
+ return DEV_UNKNOWN;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static enum dev_type __ibridge_get_width(u32 mtr)
|
|
|
|
+{
|
|
|
|
+ enum dev_type type;
|
|
|
|
+
|
|
|
|
+ switch (mtr) {
|
|
|
|
+ case 3:
|
|
|
|
+ type = DEV_UNKNOWN;
|
|
|
|
+ break;
|
|
|
|
+ case 2:
|
|
|
|
+ type = DEV_X16;
|
|
|
|
+ break;
|
|
|
|
+ case 1:
|
|
|
|
+ type = DEV_X8;
|
|
|
|
+ break;
|
|
|
|
+ case 0:
|
|
|
|
+ type = DEV_X4;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return type;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static enum dev_type ibridge_get_width(struct sbridge_pvt *pvt, u32 mtr)
|
|
|
|
+{
|
|
|
|
+ /*
|
|
|
|
+ * ddr3_width on the documentation but also valid for DDR4 on
|
|
|
|
+ * Haswell
|
|
|
|
+ */
|
|
|
|
+ return __ibridge_get_width(GET_BITFIELD(mtr, 7, 8));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static enum dev_type broadwell_get_width(struct sbridge_pvt *pvt, u32 mtr)
|
|
|
|
+{
|
|
|
|
+ /* ddr3_width on the documentation but also valid for DDR4 */
|
|
|
|
+ return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9));
|
|
|
|
+}
|
|
|
|
+
|
|
static u8 get_node_id(struct sbridge_pvt *pvt)
|
|
static u8 get_node_id(struct sbridge_pvt *pvt)
|
|
{
|
|
{
|
|
u32 reg;
|
|
u32 reg;
|
|
@@ -966,17 +1016,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
|
|
|
|
|
|
dimm->nr_pages = npages;
|
|
dimm->nr_pages = npages;
|
|
dimm->grain = 32;
|
|
dimm->grain = 32;
|
|
- switch (banks) {
|
|
|
|
- case 16:
|
|
|
|
- dimm->dtype = DEV_X16;
|
|
|
|
- break;
|
|
|
|
- case 8:
|
|
|
|
- dimm->dtype = DEV_X8;
|
|
|
|
- break;
|
|
|
|
- case 4:
|
|
|
|
- dimm->dtype = DEV_X4;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ dimm->dtype = pvt->info.get_width(pvt, mtr);
|
|
dimm->mtype = mtype;
|
|
dimm->mtype = mtype;
|
|
dimm->edac_mode = mode;
|
|
dimm->edac_mode = mode;
|
|
snprintf(dimm->label, sizeof(dimm->label),
|
|
snprintf(dimm->label, sizeof(dimm->label),
|
|
@@ -1869,7 +1909,11 @@ static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0:
|
|
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0:
|
|
- pvt->pci_ddrio = pdev;
|
|
|
|
|
|
+ case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1:
|
|
|
|
+ case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2:
|
|
|
|
+ case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3:
|
|
|
|
+ if (!pvt->pci_ddrio)
|
|
|
|
+ pvt->pci_ddrio = pdev;
|
|
break;
|
|
break;
|
|
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1:
|
|
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1:
|
|
pvt->pci_ha1 = pdev;
|
|
pvt->pci_ha1 = pdev;
|
|
@@ -2361,6 +2405,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
|
|
pvt->info.interleave_list = ibridge_interleave_list;
|
|
pvt->info.interleave_list = ibridge_interleave_list;
|
|
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
|
|
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
|
|
pvt->info.interleave_pkg = ibridge_interleave_pkg;
|
|
pvt->info.interleave_pkg = ibridge_interleave_pkg;
|
|
|
|
+ pvt->info.get_width = ibridge_get_width;
|
|
mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx);
|
|
mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx);
|
|
|
|
|
|
/* Store pci devices at mci for faster access */
|
|
/* Store pci devices at mci for faster access */
|
|
@@ -2380,6 +2425,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
|
|
pvt->info.interleave_list = sbridge_interleave_list;
|
|
pvt->info.interleave_list = sbridge_interleave_list;
|
|
pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
|
|
pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
|
|
pvt->info.interleave_pkg = sbridge_interleave_pkg;
|
|
pvt->info.interleave_pkg = sbridge_interleave_pkg;
|
|
|
|
+ pvt->info.get_width = sbridge_get_width;
|
|
mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx);
|
|
mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx);
|
|
|
|
|
|
/* Store pci devices at mci for faster access */
|
|
/* Store pci devices at mci for faster access */
|
|
@@ -2399,6 +2445,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
|
|
pvt->info.interleave_list = ibridge_interleave_list;
|
|
pvt->info.interleave_list = ibridge_interleave_list;
|
|
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
|
|
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
|
|
pvt->info.interleave_pkg = ibridge_interleave_pkg;
|
|
pvt->info.interleave_pkg = ibridge_interleave_pkg;
|
|
|
|
+ pvt->info.get_width = ibridge_get_width;
|
|
mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx);
|
|
mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx);
|
|
|
|
|
|
/* Store pci devices at mci for faster access */
|
|
/* Store pci devices at mci for faster access */
|
|
@@ -2418,6 +2465,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
|
|
pvt->info.interleave_list = ibridge_interleave_list;
|
|
pvt->info.interleave_list = ibridge_interleave_list;
|
|
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
|
|
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
|
|
pvt->info.interleave_pkg = ibridge_interleave_pkg;
|
|
pvt->info.interleave_pkg = ibridge_interleave_pkg;
|
|
|
|
+ pvt->info.get_width = broadwell_get_width;
|
|
mci->ctl_name = kasprintf(GFP_KERNEL, "Broadwell Socket#%d", mci->mc_idx);
|
|
mci->ctl_name = kasprintf(GFP_KERNEL, "Broadwell Socket#%d", mci->mc_idx);
|
|
|
|
|
|
/* Store pci devices at mci for faster access */
|
|
/* Store pci devices at mci for faster access */
|