lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2db88a5373dd410af6c55210032ed81ceae16323.1757061697.git.michal.simek@amd.com>
Date: Fri, 5 Sep 2025 10:41:46 +0200
From: Michal Simek <michal.simek@....com>
To: <linux-kernel@...r.kernel.org>, <monstr@...str.eu>,
	<michal.simek@...inx.com>, <git@...inx.com>
CC: Anish Kadamathikuttiyil Karthikeyan Pillai
	<anish.kadamathikuttiyil-karthikeyan-pillai@....com>, Andy Shevchenko
	<andy@...nel.org>, David Lechner <dlechner@...libre.com>, Jonathan Cameron
	<jic23@...nel.org>, Nuno Sá <nuno.sa@...log.com>, "Salih
 Erim" <salih.erim@....com>, "open list:IIO SUBSYSTEM AND DRIVERS"
	<linux-iio@...r.kernel.org>
Subject: [PATCH 3/6] iio: adc: versal-sysmon: Support AI Engine thermal monitoring

From: Anish Kadamathikuttiyil Karthikeyan Pillai <anish.kadamathikuttiyil-karthikeyan-pillai@....com>

To enhance the thermal monitoring of AI Engine, the sysmon satellites
close to it are exposed as IIO channels.

The exposed IIO channel are mapped to allow consumer drivers to access
specific sensor data through the IIO framework.

Signed-off-by: Anish Kadamathikuttiyil Karthikeyan Pillai <anish.kadamathikuttiyil-karthikeyan-pillai@....com>
Signed-off-by: Michal Simek <michal.simek@....com>
---

 drivers/iio/adc/versal-sysmon-core.c | 135 ++++++++++++++++++---------
 drivers/iio/adc/versal-sysmon.c      |  35 ++++++-
 drivers/iio/adc/versal-sysmon.h      |   3 +
 3 files changed, 127 insertions(+), 46 deletions(-)

diff --git a/drivers/iio/adc/versal-sysmon-core.c b/drivers/iio/adc/versal-sysmon-core.c
index 21b6a413dccb..bd293ff7d176 100644
--- a/drivers/iio/adc/versal-sysmon-core.c
+++ b/drivers/iio/adc/versal-sysmon-core.c
@@ -272,7 +272,10 @@ static int sysmon_read_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_RAW:
 		switch (chan->type) {
 		case IIO_TEMP:
-			offset = sysmon_temp_offset(chan->address);
+			if (chan->channel != AIE_TEMP_CH)
+				offset = sysmon_temp_offset(chan->address);
+			else
+				offset = chan->address;
 			*val = sysmon->temp_read(sysmon, offset);
 			*val2 = 0;
 			ret = IIO_VAL_INT;
@@ -295,7 +298,10 @@ static int sysmon_read_raw(struct iio_dev *indio_dev,
 		switch (chan->type) {
 		case IIO_TEMP:
 			/* In Deg C */
-			offset = sysmon_temp_offset(chan->address);
+			if (chan->channel != AIE_TEMP_CH)
+				offset = sysmon_temp_offset(chan->address);
+			else
+				offset = chan->address;
 			regval = sysmon->temp_read(sysmon, offset);
 			if (!sysmon->hbm_slr)
 				sysmon_q8p7_to_millicelsius(regval, val, val2);
@@ -1202,8 +1208,10 @@ int sysmon_parse_dt(struct iio_dev *indio_dev, struct device *dev)
 	struct iio_chan_spec *sysmon_channels;
 	struct device_node *child_node = NULL, *np = dev->of_node;
 	int ret, i = 0;
+	int aie_idx = 0;
 	u32 num_supply_chan = 0;
 	u32 reg = 0, num_temp_chan = 0;
+	u32 num_aie_temp_chan = 0;
 	const char *name;
 	u32 chan_size = sizeof(struct iio_chan_spec);
 	u32 temp_chan_size;
@@ -1214,6 +1222,11 @@ int sysmon_parse_dt(struct iio_dev *indio_dev, struct device *dev)
 		return ret;
 
 	sysmon->num_supply_chan = num_supply_chan;
+	ret = of_property_read_u32(np, "xlnx,numaiechannels", &num_aie_temp_chan);
+	if (ret < 0)
+		num_aie_temp_chan = 0;
+
+	sysmon->num_aie_temp_chan = num_aie_temp_chan;
 
 	INIT_LIST_HEAD(&sysmon->region_list);
 
@@ -1233,69 +1246,101 @@ int sysmon_parse_dt(struct iio_dev *indio_dev, struct device *dev)
 	}
 
 	sysmon_channels = devm_kzalloc(dev, (chan_size * num_supply_chan) +
+					    (chan_size * num_aie_temp_chan) +
 					    temp_chan_size,
 					    GFP_KERNEL);
 	if (!sysmon_channels)
 		return -ENOMEM;
 
+	/* Configure the dynamic channels */
 	for_each_child_of_node(np, child_node) {
-		ret = of_property_read_u32(child_node, "reg", &reg);
-		if (ret < 0) {
-			of_node_put(child_node);
-			return ret;
-		}
+		if (of_property_present(child_node, "xlnx,aie-temp")) {
+			ret = of_property_read_u32(child_node, "reg", &reg);
+			if (ret < 0) {
+				of_node_put(child_node);
+				return ret;
+			}
+			ret = of_property_read_string(child_node, "xlnx,name", &name);
+			if (ret < 0) {
+				of_node_put(child_node);
+				return ret;
+			}
+			sysmon_channels[num_supply_chan + aie_idx].type = IIO_TEMP;
+			sysmon_channels[num_supply_chan + aie_idx].indexed = 1;
+			sysmon_channels[num_supply_chan + aie_idx].address =
+				SYSMON_NODE_OFFSET + ((reg - 1) * 4);
+			sysmon_channels[num_supply_chan + aie_idx].channel = AIE_TEMP_CH;
+			sysmon_channels[num_supply_chan + aie_idx].info_mask_separate =
+				BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED);
+			sysmon_channels[num_supply_chan + aie_idx].scan_index = aie_idx;
+			sysmon_channels[num_supply_chan + aie_idx].scan_type.realbits = 15;
+			sysmon_channels[num_supply_chan + aie_idx].scan_type.storagebits =
+				16;
+			sysmon_channels[num_supply_chan + aie_idx].scan_type.endianness =
+				IIO_CPU;
+			sysmon_channels[num_supply_chan + aie_idx].scan_type.sign = 's';
+			sysmon_channels[num_supply_chan + aie_idx].extend_name = name;
+			sysmon_channels[num_supply_chan + aie_idx].datasheet_name = name;
+			aie_idx++;
+		} else {
+			ret = of_property_read_u32(child_node, "reg", &reg);
+			if (ret < 0) {
+				of_node_put(child_node);
+				return ret;
+			}
 
-		ret = of_property_read_string(child_node, "xlnx,name", &name);
-		if (ret < 0) {
-			of_node_put(child_node);
-			return ret;
-		}
+			ret = of_property_read_string(child_node, "xlnx,name", &name);
+			if (ret < 0) {
+				of_node_put(child_node);
+				return ret;
+			}
 
-		sysmon_channels[i].type = IIO_VOLTAGE;
-		sysmon_channels[i].indexed = 1;
-		sysmon_channels[i].address = reg;
-		sysmon_channels[i].channel = reg;
-		sysmon_channels[i].info_mask_separate =
-			BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED);
-		sysmon_channels[i].info_mask_shared_by_type =
-			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
-		sysmon_channels[i].info_mask_shared_by_type_available =
-			BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
-
-		sysmon_channels[i].event_spec = sysmon_supply_events;
-		sysmon_channels[i].num_event_specs = ARRAY_SIZE(sysmon_supply_events);
-
-		sysmon_channels[i].scan_index = i;
-		sysmon_channels[i].scan_type.realbits = 19;
-		sysmon_channels[i].scan_type.storagebits = 32;
-
-		sysmon_channels[i].scan_type.endianness = IIO_CPU;
-		sysmon_channels[i].extend_name = name;
-
-		if (of_property_read_bool(child_node, "xlnx,bipolar"))
-			sysmon_channels[i].scan_type.sign = 's';
-		else
-			sysmon_channels[i].scan_type.sign = 'u';
+			sysmon_channels[i].type = IIO_VOLTAGE;
+			sysmon_channels[i].indexed = 1;
+			sysmon_channels[i].address = reg;
+			sysmon_channels[i].channel = reg;
+			sysmon_channels[i].info_mask_separate =
+				BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED);
+			sysmon_channels[i].info_mask_shared_by_type =
+				BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+			sysmon_channels[i].info_mask_shared_by_type_available =
+				BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
+
+			sysmon_channels[i].event_spec = sysmon_supply_events;
+			sysmon_channels[i].num_event_specs = ARRAY_SIZE(sysmon_supply_events);
+
+			sysmon_channels[i].scan_index = i;
+			sysmon_channels[i].scan_type.realbits = 19;
+			sysmon_channels[i].scan_type.storagebits = 32;
+
+			sysmon_channels[i].scan_type.endianness = IIO_CPU;
+			sysmon_channels[i].extend_name = name;
+
+			if (of_property_read_bool(child_node, "xlnx,bipolar"))
+				sysmon_channels[i].scan_type.sign = 's';
+			else
+				sysmon_channels[i].scan_type.sign = 'u';
 
-		i++;
+			i++;
+		}
 	}
 
 	/* Append static temperature channels to the channel list */
-	indio_dev->num_channels = num_supply_chan;
+	indio_dev->num_channels = num_supply_chan + num_aie_temp_chan;
 
 	if (sysmon->master_slr) {
-		memcpy(sysmon_channels + num_supply_chan, temp_channels,
-		       sizeof(temp_channels));
+		memcpy(sysmon_channels + num_supply_chan + num_aie_temp_chan,
+		       temp_channels, sizeof(temp_channels));
 		indio_dev->num_channels += ARRAY_SIZE(temp_channels);
 	}
 
 	if (sysmon->hbm_slr) {
-		memcpy(sysmon_channels + num_supply_chan, temp_hbm_channels,
-		       sizeof(temp_hbm_channels));
+		memcpy(sysmon_channels + num_supply_chan + num_aie_temp_chan,
+		       temp_hbm_channels, sizeof(temp_hbm_channels));
 		indio_dev->num_channels += num_temp_chan;
 	} else {
-		memcpy(sysmon_channels + num_supply_chan + num_temp_chan,
-		       temp_events, sizeof(temp_events));
+		memcpy(sysmon_channels + num_supply_chan + num_aie_temp_chan +
+			   num_temp_chan, temp_events, sizeof(temp_events));
 		indio_dev->num_channels += ARRAY_SIZE(temp_events);
 	}
 
diff --git a/drivers/iio/adc/versal-sysmon.c b/drivers/iio/adc/versal-sysmon.c
index 79be5111b56c..b839dfdef712 100644
--- a/drivers/iio/adc/versal-sysmon.c
+++ b/drivers/iio/adc/versal-sysmon.c
@@ -108,8 +108,13 @@ static int sysmon_probe(struct platform_device *pdev)
 	struct sysmon *sysmon, *temp_sysmon;
 	struct iio_dev *indio_dev;
 	struct resource *mem;
+	struct iio_map *all_maps;
+	const struct iio_chan_spec *chan;
 	bool exist = false;
 	int ret;
+	int maps_size = 0;
+	int maps_idx = 0;
+	int dyn_idx = 0;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sysmon));
 	if (!indio_dev)
@@ -183,8 +188,36 @@ static int sysmon_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, indio_dev);
 
 	if (sysmon->master_slr) {
+		/* Combine static and dynamic iio maps and register */
+		maps_size = ARRAY_SIZE(sysmon_therm_static_maps) - 1
+				+ sysmon->num_aie_temp_chan;
+		all_maps = devm_kzalloc(&pdev->dev,
+					sizeof(*all_maps) * (maps_size), GFP_KERNEL);
+		if (!all_maps)
+			return -ENOMEM;
+
+		for (maps_idx = 0;
+		     maps_idx < ARRAY_SIZE(sysmon_therm_static_maps) - 1;
+		     maps_idx++)
+			all_maps[maps_idx] =
+				sysmon_therm_static_maps[maps_idx];
+
+		for (dyn_idx = 0; dyn_idx < indio_dev->num_channels && maps_idx < maps_size;
+		     dyn_idx++) {
+			chan = &indio_dev->channels[dyn_idx];
+
+			if (chan->channel == AIE_TEMP_CH) {
+				all_maps[maps_idx].adc_channel_label =
+					chan->extend_name;
+				all_maps[maps_idx].consumer_dev_name =
+					"versal-thermal";
+				all_maps[maps_idx].consumer_channel =
+					chan->extend_name;
+				maps_idx++;
+			}
+		}
 		ret = devm_iio_map_array_register(&pdev->dev, indio_dev,
-						  sysmon_therm_static_maps);
+						  all_maps);
 		if (ret < 0)
 			return dev_err_probe(&pdev->dev, ret, "IIO map register failed\n");
 	}
diff --git a/drivers/iio/adc/versal-sysmon.h b/drivers/iio/adc/versal-sysmon.h
index ba47b6d32f4d..f49a4e60de65 100644
--- a/drivers/iio/adc/versal-sysmon.h
+++ b/drivers/iio/adc/versal-sysmon.h
@@ -45,6 +45,7 @@
 #define TEMP_EVENT	164
 #define OT_EVENT	165
 #define TEMP_HBM	166
+#define AIE_TEMP_CH	200
 
 /* Register Unlock Code */
 #define NPI_UNLOCK	0xF9E8D7C6
@@ -215,6 +216,7 @@ static const unsigned int sysmon_oversampling_avail[5] = {
  * @oversampling_avail: list of available overampling ratios
  * @oversampling_num: total number of available oversampling ratios
  * @num_supply_chan: number of supply channels that are enabled
+ * @num_aie_temp_chan: number of aie temp channels that are enabled
  * @supply_avg_en_attrs: dynamic array of supply averaging enable attributes
  * @temp_avg_en_attrs: dynamic array of temp. sat. averaging enable attributes
  * @avg_attrs: dynamic array of pointers to averaging attributes
@@ -248,6 +250,7 @@ struct sysmon {
 	const unsigned int *oversampling_avail;
 	unsigned int oversampling_num;
 	unsigned int num_supply_chan;
+	unsigned int num_aie_temp_chan;
 	struct iio_dev_attr *supply_avg_en_attrs;
 	struct iio_dev_attr *temp_avg_en_attrs;
 	struct attribute **avg_attrs;
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ