Commit 409d01fb authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'scmi-updates-5.9' of...

Merge tag 'scmi-updates-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/drivers

ARM SCMI/SCPI updates for v5.9

The main addition for this time is the support for platform notifications.
SCMI protocol specification allows the platform to signal events to the
interested agents via notification messages. We are adding support for
the dispatch and delivery of such notifications to the interested users
inside the kernel.

Other than that, there are minor changes like checking and using the
fast_switch capability quering the firmware instead of doing it
unconditionally(using polling mode transfer), cosmetic trace update,
use of HAVE_ARM_SMCCC_DISCOVERY instead of ARM_PSCI_FW and a fix in
scmi clock registration logic for all the clocks with discrete rates.

* tag 'scmi-updates-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Remove fixed size fields from reports/scmi_event_header
  firmware: arm_scmi: Remove unneeded __packed attribute
  firmware: arm_scmi: Remove zero-length array in SCMI notifications
  firmware: arm_scmi: Provide a missing function param description
  clk: scmi: Fix min and max rate when registering clocks with discrete rates
  firmware: arm_scmi: Keep the discrete clock rates sorted
  firmware: arm_scmi: Add base notifications support
  firmware: arm_scmi: Add reset notifications support
  firmware: arm_scmi: Add sensor notifications support
  firmware: arm_scmi: Add perf notifications support
  firmware: arm_scmi: Add power notifications support
  firmware: arm_scmi: Enable notification core
  firmware: arm_scmi: Add notification dispatch and delivery
  firmware: arm_scmi: Add notification callbacks-registration
  firmware: arm_scmi: Add notification protocol-registration
  firmware: arm_scmi: Fix SCMI genpd domain probing
  firmware: arm_scmi: Use HAVE_ARM_SMCCC_DISCOVERY instead of ARM_PSCI_FW
  cpufreq: arm_scmi: Set fast_switch_possible conditionally
  firmware: arm_scmi: Add fast_switch_possible() interface
  firmware: arm_scmi: Use signed integer to report transfer status

Link: https://lore.kernel.org/r/20200713161410.12324-1-sudeep.holla@arm.com


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 38d9dff1 72a5eb9d
Loading
Loading
Loading
Loading
+19 −3
Original line number Diff line number Diff line
@@ -103,6 +103,8 @@ static const struct clk_ops scmi_clk_ops = {
static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
{
	int ret;
	unsigned long min_rate, max_rate;

	struct clk_init_data init = {
		.flags = CLK_GET_RATE_NOCACHE,
		.num_parents = 0,
@@ -112,9 +114,23 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)

	sclk->hw.init = &init;
	ret = devm_clk_hw_register(dev, &sclk->hw);
	if (!ret)
		clk_hw_set_rate_range(&sclk->hw, sclk->info->range.min_rate,
				      sclk->info->range.max_rate);
	if (ret)
		return ret;

	if (sclk->info->rate_discrete) {
		int num_rates = sclk->info->list.num_rates;

		if (num_rates <= 0)
			return -EINVAL;

		min_rate = sclk->info->list.rates[0];
		max_rate = sclk->info->list.rates[num_rates - 1];
	} else {
		min_rate = sclk->info->range.min_rate;
		max_rate = sclk->info->range.max_rate;
	}

	clk_hw_set_rate_range(&sclk->hw, min_rate, max_rate);
	return ret;
}

+2 −1
Original line number Diff line number Diff line
@@ -198,7 +198,8 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)

	policy->cpuinfo.transition_latency = latency;

	policy->fast_switch_possible = true;
	policy->fast_switch_possible =
		handle->perf_ops->fast_switch_possible(handle, cpu_dev);

	em_register_perf_domain(policy->cpus, nr_opp, &em_cb);

+2 −2
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
obj-y	= scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
scmi-bus-y = bus.o
scmi-driver-y = driver.o
scmi-driver-y = driver.o notify.o
scmi-transport-y = shmem.o
scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
scmi-transport-$(CONFIG_ARM_PSCI_FW) += smc.o
scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
+104 −4
Original line number Diff line number Diff line
@@ -5,7 +5,15 @@
 * Copyright (C) 2018 ARM Ltd.
 */

#define pr_fmt(fmt) "SCMI Notifications BASE - " fmt

#include <linux/scmi_protocol.h>

#include "common.h"
#include "notify.h"

#define SCMI_BASE_NUM_SOURCES		1
#define SCMI_BASE_MAX_CMD_ERR_COUNT	1024

enum scmi_base_protocol_cmd {
	BASE_DISCOVER_VENDOR = 0x3,
@@ -19,16 +27,25 @@ enum scmi_base_protocol_cmd {
	BASE_RESET_AGENT_CONFIGURATION = 0xb,
};

enum scmi_base_protocol_notify {
	BASE_ERROR_EVENT = 0x0,
};

struct scmi_msg_resp_base_attributes {
	u8 num_protocols;
	u8 num_agents;
	__le16 reserved;
};

struct scmi_msg_base_error_notify {
	__le32 event_control;
#define BASE_TP_NOTIFY_ALL	BIT(0)
};

struct scmi_base_error_notify_payld {
	__le32 agent_id;
	__le32 error_status;
#define IS_FATAL_ERROR(x)	((x) & BIT(31))
#define ERROR_CMD_COUNT(x)	FIELD_GET(GENMASK(9, 0), (x))
	__le64 msg_reports[SCMI_BASE_MAX_CMD_ERR_COUNT];
};

/**
 * scmi_base_attributes_get() - gets the implementation details
 *	that are associated with the base protocol.
@@ -222,6 +239,83 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle,
	return ret;
}

static int scmi_base_error_notify(const struct scmi_handle *handle, bool enable)
{
	int ret;
	u32 evt_cntl = enable ? BASE_TP_NOTIFY_ALL : 0;
	struct scmi_xfer *t;
	struct scmi_msg_base_error_notify *cfg;

	ret = scmi_xfer_get_init(handle, BASE_NOTIFY_ERRORS,
				 SCMI_PROTOCOL_BASE, sizeof(*cfg), 0, &t);
	if (ret)
		return ret;

	cfg = t->tx.buf;
	cfg->event_control = cpu_to_le32(evt_cntl);

	ret = scmi_do_xfer(handle, t);

	scmi_xfer_put(handle, t);
	return ret;
}

static int scmi_base_set_notify_enabled(const struct scmi_handle *handle,
					u8 evt_id, u32 src_id, bool enable)
{
	int ret;

	ret = scmi_base_error_notify(handle, enable);
	if (ret)
		pr_debug("FAIL_ENABLED - evt[%X] ret:%d\n", evt_id, ret);

	return ret;
}

static void *scmi_base_fill_custom_report(const struct scmi_handle *handle,
					  u8 evt_id, ktime_t timestamp,
					  const void *payld, size_t payld_sz,
					  void *report, u32 *src_id)
{
	int i;
	const struct scmi_base_error_notify_payld *p = payld;
	struct scmi_base_error_report *r = report;

	/*
	 * BaseError notification payload is variable in size but
	 * up to a maximum length determined by the struct ponted by p.
	 * Instead payld_sz is the effective length of this notification
	 * payload so cannot be greater of the maximum allowed size as
	 * pointed by p.
	 */
	if (evt_id != SCMI_EVENT_BASE_ERROR_EVENT || sizeof(*p) < payld_sz)
		return NULL;

	r->timestamp = timestamp;
	r->agent_id = le32_to_cpu(p->agent_id);
	r->fatal = IS_FATAL_ERROR(le32_to_cpu(p->error_status));
	r->cmd_count = ERROR_CMD_COUNT(le32_to_cpu(p->error_status));
	for (i = 0; i < r->cmd_count; i++)
		r->reports[i] = le64_to_cpu(p->msg_reports[i]);
	*src_id = 0;

	return r;
}

static const struct scmi_event base_events[] = {
	{
		.id = SCMI_EVENT_BASE_ERROR_EVENT,
		.max_payld_sz = sizeof(struct scmi_base_error_notify_payld),
		.max_report_sz = sizeof(struct scmi_base_error_report) +
				  SCMI_BASE_MAX_CMD_ERR_COUNT * sizeof(u64),
	},
};

static const struct scmi_event_ops base_event_ops = {
	.set_notify_enabled = scmi_base_set_notify_enabled,
	.fill_custom_report = scmi_base_fill_custom_report,
};

int scmi_base_protocol_init(struct scmi_handle *h)
{
	int id, ret;
@@ -256,6 +350,12 @@ int scmi_base_protocol_init(struct scmi_handle *h)
	dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols,
		rev->num_agents);

	scmi_register_protocol_events(handle, SCMI_PROTOCOL_BASE,
				      (4 * SCMI_PROTO_QUEUE_SZ),
				      &base_event_ops, base_events,
				      ARRAY_SIZE(base_events),
				      SCMI_BASE_NUM_SOURCES);

	for (id = 0; id < rev->num_agents; id++) {
		scmi_base_discover_agent_get(handle, id, name);
		dev_dbg(dev, "Agent %d: %s\n", id, name);
+18 −2
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@
 * Copyright (C) 2018 ARM Ltd.
 */

#include <linux/sort.h>

#include "common.h"

enum scmi_clock_protocol_cmd {
@@ -121,11 +123,23 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle,
	return ret;
}

static int rate_cmp_func(const void *_r1, const void *_r2)
{
	const u64 *r1 = _r1, *r2 = _r2;

	if (*r1 < *r2)
		return -1;
	else if (*r1 == *r2)
		return 0;
	else
		return 1;
}

static int
scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
			      struct scmi_clock_info *clk)
{
	u64 *rate;
	u64 *rate = 0;
	int ret, cnt;
	bool rate_discrete = false;
	u32 tot_rate_cnt = 0, rates_flag;
@@ -184,8 +198,10 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
		 */
	} while (num_returned && num_remaining);

	if (rate_discrete)
	if (rate_discrete && rate) {
		clk->list.num_rates = tot_rate_cnt;
		sort(rate, tot_rate_cnt, sizeof(*rate), rate_cmp_func, NULL);
	}

	clk->rate_discrete = rate_discrete;

Loading