static int scmi_sensor_description_get()

in arm_scmi/sensors.c [421:561]


static int scmi_sensor_description_get(const struct scmi_protocol_handle *ph,
				       struct sensors_info *si)
{
	int ret, cnt;
	u32 desc_index = 0;
	u16 num_returned, num_remaining;
	struct scmi_xfer *t;
	struct scmi_msg_resp_sensor_description *buf;

	ret = ph->xops->xfer_get_init(ph, SENSOR_DESCRIPTION_GET,
				      sizeof(__le32), 0, &t);
	if (ret)
		return ret;

	buf = t->rx.buf;

	do {
		struct scmi_sensor_descriptor *sdesc;

		/* Set the number of sensors to be skipped/already read */
		put_unaligned_le32(desc_index, t->tx.buf);

		ret = ph->xops->do_xfer(ph, t);
		if (ret)
			break;

		num_returned = le16_to_cpu(buf->num_returned);
		num_remaining = le16_to_cpu(buf->num_remaining);

		if (desc_index + num_returned > si->num_sensors) {
			dev_err(ph->dev, "No. of sensors can't exceed %d",
				si->num_sensors);
			break;
		}

		sdesc = &buf->desc[0];
		for (cnt = 0; cnt < num_returned; cnt++) {
			u32 attrh, attrl;
			struct scmi_sensor_info *s;
			size_t dsize = SCMI_MSG_RESP_SENS_DESCR_BASE_SZ;

			s = &si->sensors[desc_index + cnt];
			s->id = le32_to_cpu(sdesc->id);

			attrl = le32_to_cpu(sdesc->attributes_low);
			/* common bitfields parsing */
			s->async = SUPPORTS_ASYNC_READ(attrl);
			s->num_trip_points = NUM_TRIP_POINTS(attrl);
			/**
			 * only SCMIv3.0 specific bitfield below.
			 * Such bitfields are assumed to be zeroed on non
			 * relevant fw versions...assuming fw not buggy !
			 */
			s->update = SUPPORTS_UPDATE_NOTIFY(attrl);
			s->timestamped = SUPPORTS_TIMESTAMP(attrl);
			if (s->timestamped)
				s->tstamp_scale =
					S32_EXT(SENSOR_TSTAMP_EXP(attrl));
			s->extended_scalar_attrs =
				SUPPORTS_EXTEND_ATTRS(attrl);

			attrh = le32_to_cpu(sdesc->attributes_high);
			/* common bitfields parsing */
			s->scale = S32_EXT(SENSOR_SCALE(attrh));
			s->type = SENSOR_TYPE(attrh);
			/* Use pre-allocated pool wherever possible */
			s->intervals.desc = s->intervals.prealloc_pool;
			if (si->version == SCMIv2_SENSOR_PROTOCOL) {
				s->intervals.segmented = false;
				s->intervals.count = 1;
				/*
				 * Convert SCMIv2.0 update interval format to
				 * SCMIv3.0 to be used as the common exposed
				 * descriptor, accessible via common macros.
				 */
				s->intervals.desc[0] =
					(SENSOR_UPDATE_BASE(attrh) << 5) |
					 SENSOR_UPDATE_SCALE(attrh);
			} else {
				/*
				 * From SCMIv3.0 update intervals are retrieved
				 * via a dedicated (optional) command.
				 * Since the command is optional, on error carry
				 * on without any update interval.
				 */
				if (scmi_sensor_update_intervals(ph, s))
					dev_dbg(ph->dev,
						"Update Intervals not available for sensor ID:%d\n",
						s->id);
			}
			/**
			 * only > SCMIv2.0 specific bitfield below.
			 * Such bitfields are assumed to be zeroed on non
			 * relevant fw versions...assuming fw not buggy !
			 */
			s->num_axis = min_t(unsigned int,
					    SUPPORTS_AXIS(attrh) ?
					    SENSOR_AXIS_NUMBER(attrh) : 0,
					    SCMI_MAX_NUM_SENSOR_AXIS);
			strlcpy(s->name, sdesc->name, SCMI_MAX_STR_SIZE);

			if (s->extended_scalar_attrs) {
				s->sensor_power = le32_to_cpu(sdesc->power);
				dsize += sizeof(sdesc->power);
				/* Only for sensors reporting scalar values */
				if (s->num_axis == 0) {
					unsigned int sres =
						le32_to_cpu(sdesc->resolution);

					s->resolution = SENSOR_RES(sres);
					s->exponent =
						S32_EXT(SENSOR_RES_EXP(sres));
					dsize += sizeof(sdesc->resolution);

					scmi_parse_range_attrs(&s->scalar_attrs,
							       &sdesc->scalar_attrs);
					dsize += sizeof(sdesc->scalar_attrs);
				}
			}
			if (s->num_axis > 0) {
				ret = scmi_sensor_axis_description(ph, s);
				if (ret)
					goto out;
			}

			sdesc = (typeof(sdesc))((u8 *)sdesc + dsize);
		}

		desc_index += num_returned;

		ph->xops->reset_rx_to_maxsz(ph, t);
		/*
		 * check for both returned and remaining to avoid infinite
		 * loop due to buggy firmware
		 */
	} while (num_returned && num_remaining);

out:
	ph->xops->xfer_put(ph, t);
	return ret;
}