static int scmi_sensor_update_intervals()

in arm_scmi/sensors.c [240:327]


static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph,
					struct scmi_sensor_info *s)
{
	int ret, cnt;
	u32 desc_index = 0;
	u16 num_returned, num_remaining;
	struct scmi_xfer *ti;
	struct scmi_msg_resp_sensor_list_update_intervals *buf;
	struct scmi_msg_sensor_list_update_intervals *msg;

	ret = ph->xops->xfer_get_init(ph, SENSOR_LIST_UPDATE_INTERVALS,
				      sizeof(*msg), 0, &ti);
	if (ret)
		return ret;

	buf = ti->rx.buf;
	do {
		u32 flags;

		msg = ti->tx.buf;
		/* Set the number of sensors to be skipped/already read */
		msg->id = cpu_to_le32(s->id);
		msg->index = cpu_to_le32(desc_index);

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

		flags = le32_to_cpu(buf->num_intervals_flags);
		num_returned = NUM_INTERVALS_RETURNED(flags);
		num_remaining = NUM_INTERVALS_REMAINING(flags);

		/*
		 * Max intervals is not declared previously anywhere so we
		 * assume it's returned+remaining.
		 */
		if (!s->intervals.count) {
			s->intervals.segmented = SEGMENTED_INTVL_FORMAT(flags);
			s->intervals.count = num_returned + num_remaining;
			/* segmented intervals are reported in one triplet */
			if (s->intervals.segmented &&
			    (num_remaining || num_returned != 3)) {
				dev_err(ph->dev,
					"Sensor ID:%d advertises an invalid segmented interval (%d)\n",
					s->id, s->intervals.count);
				s->intervals.segmented = false;
				s->intervals.count = 0;
				ret = -EINVAL;
				break;
			}
			/* Direct allocation when exceeding pre-allocated */
			if (s->intervals.count >= SCMI_MAX_PREALLOC_POOL) {
				s->intervals.desc =
					devm_kcalloc(ph->dev,
						     s->intervals.count,
						     sizeof(*s->intervals.desc),
						     GFP_KERNEL);
				if (!s->intervals.desc) {
					s->intervals.segmented = false;
					s->intervals.count = 0;
					ret = -ENOMEM;
					break;
				}
			}
		} else if (desc_index + num_returned > s->intervals.count) {
			dev_err(ph->dev,
				"No. of update intervals can't exceed %d\n",
				s->intervals.count);
			ret = -EINVAL;
			break;
		}

		for (cnt = 0; cnt < num_returned; cnt++)
			s->intervals.desc[desc_index + cnt] =
					le32_to_cpu(buf->intervals[cnt]);

		desc_index += num_returned;

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

	ph->xops->xfer_put(ph, ti);
	return ret;
}