scp 处理clk_get_val 的流程

linux 中怎么使用scp呢?
首先在arm_scpi.c中export了 get_scpi_ops 这样其他驱动可以调用get_scpi_ops来使用spci
static struct scpi_ops scpi_ops = {
	.get_version = scpi_get_version,
	.clk_get_range = scpi_clk_get_range,
	.clk_get_val = scpi_clk_get_val,
	.clk_set_val = scpi_clk_set_val,
	.dvfs_get_idx = scpi_dvfs_get_idx,
	.dvfs_set_idx = scpi_dvfs_set_idx,
	.dvfs_get_info = scpi_dvfs_get_info,
	.device_domain_id = scpi_dev_domain_id,
	.get_transition_latency = scpi_dvfs_get_transition_latency,
	.add_opps_to_device = scpi_dvfs_add_opps_to_device,
	.sensor_get_capability = scpi_sensor_get_capability,
	.sensor_get_info = scpi_sensor_get_info,
	.sensor_get_value = scpi_sensor_get_value,
	.device_get_power_state = scpi_device_get_power_state,
	.device_set_power_state = scpi_device_set_power_state,
};

struct scpi_ops *get_scpi_ops(void)
{
	return scpi_info ? scpi_info->scpi_ops : NULL;
}
例如clk_get_val的使用如下:
drivers/clk/clk-scpi.c return clk->scpi_ops->clk_get_val(clk->id)

在scpi_clk_get_val 中直接调用scpi_send_message 发送命令

static unsigned long scpi_clk_get_val(u16 clk_id)
{
	int ret;
	__le32 rate;
	__le16 le_clk_id = cpu_to_le16(clk_id);

	ret = scpi_send_message(CMD_GET_CLOCK_VALUE, &le_clk_id,
				sizeof(le_clk_id), &rate, sizeof(rate));

	return ret ? ret : le32_to_cpu(rate);
}

static int scpi_send_message(u8 idx, void *tx_buf, unsigned int tx_len,
			     void *rx_buf, unsigned int rx_len)
{
	int ret;
	u8 chan;
	u8 cmd;
	struct scpi_xfer *msg;
	struct scpi_chan *scpi_chan;

	
	msg->tx_buf = tx_buf;
	msg->tx_len = tx_len;
	msg->rx_buf = rx_buf;
	msg->rx_len = rx_len;
	reinit_completion(&msg->done);
#调用mbox 发送命令
	ret = mbox_send_message(scpi_chan->chan, msg);
	if (ret < 0 || !rx_buf)
		goto out;
#这里会等待完成量释放
	if (!wait_for_completion_timeout(&msg->done, MAX_RX_TIMEOUT))
		ret = -ETIMEDOUT;
	else
		/* first status word */
		ret = msg->status;
	return ret > 0 ? scpi_to_linux_errno(ret) : ret;
}
那什么地方释放完成量呢?
答案是在scpi_probe 中有为mbox_client 注册一个scpi_handle_remote_msg;
		cl->dev = dev;
		cl->rx_callback = scpi_handle_remote_msg;
		cl->tx_prepare = scpi_tx_prepare;
		cl->tx_block = true;
		cl->tx_tout = 20;
		cl->knows_txdone = false; /* controller can't ack */
完成量就是在scpi_handle_remote_msg->scpi_process_cmd中释放的

static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
{
	
	/* check if wait_for_completion is in progress or timed-out */
	if (match && !completion_done(&match->done)) {
		unsigned int len;

		if (scpi_info->is_legacy) {
			struct legacy_scpi_shared_mem __iomem *mem =
							ch->rx_payload;

			/* RX Length is not replied by the legacy Firmware */
			len = match->rx_len;

			match->status = ioread32(&mem->status);
			memcpy_fromio(match->rx_buf, mem->payload, len);
		} else {
			struct scpi_shared_mem __iomem *mem = ch->rx_payload;

			len = min_t(unsigned int, match->rx_len, CMD_SIZE(cmd));

			match->status = ioread32(&mem->status);
			memcpy_fromio(match->rx_buf, mem->payload, len);
		}

		if (match->rx_len > len)
			memset(match->rx_buf + len, 0, match->rx_len - len);
#释放完成量
		complete(&match->done);
	}
	spin_unlock_irqrestore(&ch->rx_lock, flags);
}

 

你可能感兴趣的:(Linux,源码分析)