summaryrefslogtreecommitdiff
path: root/drivers/hwmon/peci/dimmtemp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/peci/dimmtemp.c')
-rw-r--r--drivers/hwmon/peci/dimmtemp.c124
1 files changed, 93 insertions, 31 deletions
diff --git a/drivers/hwmon/peci/dimmtemp.c b/drivers/hwmon/peci/dimmtemp.c
index 0a633bda3668..bd3e8715dfec 100644
--- a/drivers/hwmon/peci/dimmtemp.c
+++ b/drivers/hwmon/peci/dimmtemp.c
@@ -30,6 +30,10 @@
#define DIMM_IDX_MAX_ON_ICX 2
#define CHAN_RANK_MAX_ON_ICXD 4
#define DIMM_IDX_MAX_ON_ICXD 2
+#define CHAN_RANK_MAX_ON_SPR 8
+#define DIMM_IDX_MAX_ON_SPR 2
+#define CHAN_RANK_MAX_ON_EMR 8
+#define DIMM_IDX_MAX_ON_EMR 2
#define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX
#define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX
@@ -45,7 +49,7 @@
#define GET_TEMP_MAX(x) (((x) & DIMM_TEMP_MAX) >> 8)
#define GET_TEMP_CRIT(x) (((x) & DIMM_TEMP_CRIT) >> 16)
-#define NO_DIMM_RETRY_COUNT_MAX 5
+#define NO_DIMM_RETRY_COUNT_MAX 120
struct peci_dimmtemp;
@@ -92,16 +96,15 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no, long *val)
{
int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
- int ret = 0;
u32 data;
+ int ret;
- mutex_lock(&priv->dimm[dimm_no].temp.state.lock);
if (!peci_sensor_need_update(&priv->dimm[dimm_no].temp.state))
goto skip_update;
ret = peci_pcs_read(priv->peci_dev, PECI_PCS_DDR_DIMM_TEMP, chan_rank, &data);
if (ret)
- goto unlock;
+ return ret;
priv->dimm[dimm_no].temp.value = __dimm_temp(data, dimm_order) * MILLIDEGREE_PER_DEGREE;
@@ -109,9 +112,7 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no, long *val)
skip_update:
*val = priv->dimm[dimm_no].temp.value;
-unlock:
- mutex_unlock(&priv->dimm[dimm_no].temp.state.lock);
- return ret;
+ return 0;
}
static int update_thresholds(struct peci_dimmtemp *priv, int dimm_no)
@@ -125,8 +126,6 @@ static int update_thresholds(struct peci_dimmtemp *priv, int dimm_no)
return 0;
ret = priv->gen_info->read_thresholds(priv, dimm_order, chan_rank, &data);
- if (ret == -ENODATA) /* Use default or previous value */
- return 0;
if (ret)
return ret;
@@ -143,10 +142,9 @@ static int get_dimm_thresholds(struct peci_dimmtemp *priv, enum peci_dimm_thresh
{
int ret;
- mutex_lock(&priv->dimm[dimm_no].thresholds.state.lock);
ret = update_thresholds(priv, dimm_no);
if (ret)
- goto unlock;
+ return ret;
switch (type) {
case temp_max_type:
@@ -159,9 +157,6 @@ static int get_dimm_thresholds(struct peci_dimmtemp *priv, enum peci_dimm_thresh
ret = -EOPNOTSUPP;
break;
}
-unlock:
- mutex_unlock(&priv->dimm[dimm_no].thresholds.state.lock);
-
return ret;
}
@@ -219,19 +214,21 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
{
int chan_rank_max = priv->gen_info->chan_rank_max;
int dimm_idx_max = priv->gen_info->dimm_idx_max;
- u32 chan_rank_empty = 0;
- u32 dimm_mask = 0;
- int chan_rank, dimm_idx, ret;
+ DECLARE_BITMAP(dimm_mask, DIMM_NUMS_MAX);
+ DECLARE_BITMAP(chan_rank_empty, CHAN_RANK_MAX);
+
+ int chan_rank, dimm_idx, ret, i;
u32 pcs;
- BUILD_BUG_ON(BITS_PER_TYPE(chan_rank_empty) < CHAN_RANK_MAX);
- BUILD_BUG_ON(BITS_PER_TYPE(dimm_mask) < DIMM_NUMS_MAX);
if (chan_rank_max * dimm_idx_max > DIMM_NUMS_MAX) {
WARN_ONCE(1, "Unsupported number of DIMMs - chan_rank_max: %d, dimm_idx_max: %d",
chan_rank_max, dimm_idx_max);
return -EINVAL;
}
+ bitmap_zero(dimm_mask, DIMM_NUMS_MAX);
+ bitmap_zero(chan_rank_empty, CHAN_RANK_MAX);
+
for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
ret = peci_pcs_read(priv->peci_dev, PECI_PCS_DDR_DIMM_TEMP, chan_rank, &pcs);
if (ret) {
@@ -242,7 +239,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* detection to be performed at a later point in time.
*/
if (ret == -EINVAL) {
- chan_rank_empty |= BIT(chan_rank);
+ bitmap_set(chan_rank_empty, chan_rank, 1);
continue;
}
@@ -251,7 +248,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
if (__dimm_temp(pcs, dimm_idx))
- dimm_mask |= BIT(chan_rank * dimm_idx_max + dimm_idx);
+ bitmap_set(dimm_mask, chan_rank * dimm_idx_max + dimm_idx, 1);
}
/*
@@ -260,7 +257,7 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* host platform boot. Retrying a couple of times lets us make sure
* that the state is persistent.
*/
- if (chan_rank_empty == GENMASK(chan_rank_max - 1, 0)) {
+ if (bitmap_full(chan_rank_empty, chan_rank_max)) {
if (priv->no_dimm_retry_count < NO_DIMM_RETRY_COUNT_MAX) {
priv->no_dimm_retry_count++;
@@ -274,14 +271,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
* It's possible that memory training is not done yet. In this case we
* defer the detection to be performed at a later point in time.
*/
- if (!dimm_mask) {
+ if (bitmap_empty(dimm_mask, DIMM_NUMS_MAX)) {
priv->no_dimm_retry_count = 0;
return -EAGAIN;
}
- dev_dbg(priv->dev, "Scanned populated DIMMs: %#x\n", dimm_mask);
+ for_each_set_bit(i, dimm_mask, DIMM_NUMS_MAX) {
+ dev_dbg(priv->dev, "Found DIMM%#x\n", i);
+ }
- bitmap_from_arr32(priv->dimm_mask, &dimm_mask, DIMM_NUMS_MAX);
+ bitmap_copy(priv->dimm_mask, dimm_mask, DIMM_NUMS_MAX);
return 0;
}
@@ -300,7 +299,7 @@ static int create_dimm_temp_label(struct peci_dimmtemp *priv, int chan)
return 0;
}
-static const struct hwmon_channel_info *peci_dimmtemp_temp_info[] = {
+static const struct hwmon_channel_info * const peci_dimmtemp_temp_info[] = {
HWMON_CHANNEL_INFO(temp,
[0 ... DIMM_NUMS_MAX - 1] = HWMON_T_LABEL |
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT),
@@ -343,8 +342,6 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
ret = create_dimm_temp_label(priv, i);
if (ret)
return ret;
- mutex_init(&priv->dimm[i].thresholds.state.lock);
- mutex_init(&priv->dimm[i].temp.state.lock);
}
dev = devm_hwmon_device_register_with_info(priv->dev, priv->name, priv,
@@ -503,11 +500,11 @@ read_thresholds_icx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u
ret = peci_ep_pci_local_read(priv->peci_dev, 0, 13, 0, 2, 0xd4, &reg_val);
if (ret || !(reg_val & BIT(31)))
- return -ENODATA; /* Use default or previous value */
+ return -ENODATA;
ret = peci_ep_pci_local_read(priv->peci_dev, 0, 13, 0, 2, 0xd0, &reg_val);
if (ret)
- return -ENODATA; /* Use default or previous value */
+ return -ENODATA;
/*
* Device 26, Offset 224e0: IMC 0 channel 0 -> rank 0
@@ -530,6 +527,49 @@ read_thresholds_icx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u
return 0;
}
+static int
+read_thresholds_spr(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
+{
+ u32 reg_val;
+ u64 offset;
+ int ret;
+ u8 dev;
+
+ ret = peci_ep_pci_local_read(priv->peci_dev, 0, 30, 0, 2, 0xd4, &reg_val);
+ if (ret || !(reg_val & BIT(31)))
+ return -ENODATA;
+
+ ret = peci_ep_pci_local_read(priv->peci_dev, 0, 30, 0, 2, 0xd0, &reg_val);
+ if (ret)
+ return -ENODATA;
+
+ /*
+ * Device 26, Offset 219a8: IMC 0 channel 0 -> rank 0
+ * Device 26, Offset 299a8: IMC 0 channel 1 -> rank 1
+ * Device 27, Offset 219a8: IMC 1 channel 0 -> rank 2
+ * Device 27, Offset 299a8: IMC 1 channel 1 -> rank 3
+ * Device 28, Offset 219a8: IMC 2 channel 0 -> rank 4
+ * Device 28, Offset 299a8: IMC 2 channel 1 -> rank 5
+ * Device 29, Offset 219a8: IMC 3 channel 0 -> rank 6
+ * Device 29, Offset 299a8: IMC 3 channel 1 -> rank 7
+ */
+ dev = 26 + chan_rank / 2;
+ offset = 0x219a8 + dimm_order * 4 + (chan_rank % 2) * 0x8000;
+
+ ret = peci_mmio_read(priv->peci_dev, 0, GET_CPU_SEG(reg_val), GET_CPU_BUS(reg_val),
+ dev, 0, offset, data);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int read_thresholds_emr(struct peci_dimmtemp *priv, int dimm_order,
+ int chan_rank, u32 *data)
+{
+ return read_thresholds_spr(priv, dimm_order, chan_rank, data);
+}
+
static const struct dimm_info dimm_hsx = {
.chan_rank_max = CHAN_RANK_MAX_ON_HSX,
.dimm_idx_max = DIMM_IDX_MAX_ON_HSX,
@@ -572,6 +612,20 @@ static const struct dimm_info dimm_icxd = {
.read_thresholds = &read_thresholds_icx,
};
+static const struct dimm_info dimm_spr = {
+ .chan_rank_max = CHAN_RANK_MAX_ON_SPR,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_SPR,
+ .min_peci_revision = 0x40,
+ .read_thresholds = &read_thresholds_spr,
+};
+
+static const struct dimm_info dimm_emr = {
+ .chan_rank_max = CHAN_RANK_MAX_ON_EMR,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_EMR,
+ .min_peci_revision = 0x40,
+ .read_thresholds = &read_thresholds_emr,
+};
+
static const struct auxiliary_device_id peci_dimmtemp_ids[] = {
{
.name = "peci_cpu.dimmtemp.hsx",
@@ -597,6 +651,14 @@ static const struct auxiliary_device_id peci_dimmtemp_ids[] = {
.name = "peci_cpu.dimmtemp.icxd",
.driver_data = (kernel_ulong_t)&dimm_icxd,
},
+ {
+ .name = "peci_cpu.dimmtemp.spr",
+ .driver_data = (kernel_ulong_t)&dimm_spr,
+ },
+ {
+ .name = "peci_cpu.dimmtemp.emr",
+ .driver_data = (kernel_ulong_t)&dimm_emr,
+ },
{ }
};
MODULE_DEVICE_TABLE(auxiliary, peci_dimmtemp_ids);
@@ -612,4 +674,4 @@ MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
MODULE_DESCRIPTION("PECI dimmtemp driver");
MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS(PECI_CPU);
+MODULE_IMPORT_NS("PECI_CPU");