drivers/hwmon/peci/dimmtemp.c

Source file repositories/reference/linux-study-clean/drivers/hwmon/peci/dimmtemp.c

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/peci/dimmtemp.c
Extension
.c
Size
18168 bytes
Lines
678
Domain
Driver Families
Bucket
drivers/hwmon
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct dimm_info {
	int chan_rank_max;
	int dimm_idx_max;
	u8 min_peci_revision;
	int (*read_thresholds)(struct peci_dimmtemp *priv, int dimm_order,
			       int chan_rank, u32 *data);
};

struct peci_dimm_thresholds {
	long temp_max;
	long temp_crit;
	struct peci_sensor_state state;
};

enum peci_dimm_threshold_type {
	temp_max_type,
	temp_crit_type,
};

struct peci_dimmtemp {
	struct peci_device *peci_dev;
	struct device *dev;
	const char *name;
	const struct dimm_info *gen_info;
	struct delayed_work detect_work;
	struct {
		struct peci_sensor_data temp;
		struct peci_dimm_thresholds thresholds;
	} dimm[DIMM_NUMS_MAX];
	char **dimmtemp_label;
	DECLARE_BITMAP(dimm_mask, DIMM_NUMS_MAX);
	u8 no_dimm_retry_count;
};

static u8 __dimm_temp(u32 reg, int dimm_order)
{
	return (reg >> (dimm_order * 8)) & 0xff;
}

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;
	u32 data;
	int ret;

	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)
		return ret;

	priv->dimm[dimm_no].temp.value = __dimm_temp(data, dimm_order) * MILLIDEGREE_PER_DEGREE;

	peci_sensor_mark_updated(&priv->dimm[dimm_no].temp.state);

skip_update:
	*val = priv->dimm[dimm_no].temp.value;
	return 0;
}

static int update_thresholds(struct peci_dimmtemp *priv, int dimm_no)
{
	int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
	int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
	u32 data;
	int ret;

	if (!peci_sensor_need_update(&priv->dimm[dimm_no].thresholds.state))
		return 0;

	ret = priv->gen_info->read_thresholds(priv, dimm_order, chan_rank, &data);
	if (ret)
		return ret;

	priv->dimm[dimm_no].thresholds.temp_max = GET_TEMP_MAX(data) * MILLIDEGREE_PER_DEGREE;
	priv->dimm[dimm_no].thresholds.temp_crit = GET_TEMP_CRIT(data) * MILLIDEGREE_PER_DEGREE;

	peci_sensor_mark_updated(&priv->dimm[dimm_no].thresholds.state);

	return 0;
}

static int get_dimm_thresholds(struct peci_dimmtemp *priv, enum peci_dimm_threshold_type type,
			       int dimm_no, long *val)
{
	int ret;

	ret = update_thresholds(priv, dimm_no);

Annotation

Implementation Notes