int scmi_register_protocol_events()

in arm_scmi/notify.c [748:831]


int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
				  const struct scmi_protocol_handle *ph,
				  const struct scmi_protocol_events *ee)
{
	int i;
	unsigned int num_sources;
	size_t payld_sz = 0;
	struct scmi_registered_events_desc *pd;
	struct scmi_notify_instance *ni;
	const struct scmi_event *evt;

	if (!ee || !ee->ops || !ee->evts || !ph ||
	    (!ee->num_sources && !ee->ops->get_num_sources))
		return -EINVAL;

	ni = scmi_notification_instance_data_get(handle);
	if (!ni)
		return -ENOMEM;

	/* num_sources cannot be <= 0 */
	if (ee->num_sources) {
		num_sources = ee->num_sources;
	} else {
		int nsrc = ee->ops->get_num_sources(ph);

		if (nsrc <= 0)
			return -EINVAL;
		num_sources = nsrc;
	}

	evt = ee->evts;
	for (i = 0; i < ee->num_events; i++)
		payld_sz = max_t(size_t, payld_sz, evt[i].max_payld_sz);
	payld_sz += sizeof(struct scmi_event_header);

	pd = scmi_allocate_registered_events_desc(ni, proto_id, ee->queue_sz,
						  payld_sz, ee->num_events,
						  ee->ops);
	if (IS_ERR(pd))
		return PTR_ERR(pd);

	pd->ph = ph;
	for (i = 0; i < ee->num_events; i++, evt++) {
		struct scmi_registered_event *r_evt;

		r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt),
				     GFP_KERNEL);
		if (!r_evt)
			return -ENOMEM;
		r_evt->proto = pd;
		r_evt->evt = evt;

		r_evt->sources = devm_kcalloc(ni->handle->dev, num_sources,
					      sizeof(refcount_t), GFP_KERNEL);
		if (!r_evt->sources)
			return -ENOMEM;
		r_evt->num_sources = num_sources;
		mutex_init(&r_evt->sources_mtx);

		r_evt->report = devm_kzalloc(ni->handle->dev,
					     evt->max_report_sz, GFP_KERNEL);
		if (!r_evt->report)
			return -ENOMEM;

		pd->registered_events[i] = r_evt;
		/* Ensure events are updated */
		smp_wmb();
		dev_dbg(handle->dev, "registered event - %lX\n",
			MAKE_ALL_SRCS_KEY(r_evt->proto->id, r_evt->evt->id));
	}

	/* Register protocol and events...it will never be removed */
	ni->registered_protocols[proto_id] = pd;
	/* Ensure protocols are updated */
	smp_wmb();

	/*
	 * Finalize any pending events' handler which could have been waiting
	 * for this protocol's events registration.
	 */
	schedule_work(&ni->init_work);

	return 0;
}