Skip to content

Commit 409d01f

Browse files
committed
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/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 38d9dff + 72a5eb9 commit 409d01f

File tree

17 files changed

+2258
-49
lines changed

17 files changed

+2258
-49
lines changed

drivers/clk/clk-scmi.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ static const struct clk_ops scmi_clk_ops = {
103103
static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
104104
{
105105
int ret;
106+
unsigned long min_rate, max_rate;
107+
106108
struct clk_init_data init = {
107109
.flags = CLK_GET_RATE_NOCACHE,
108110
.num_parents = 0,
@@ -112,9 +114,23 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk)
112114

113115
sclk->hw.init = &init;
114116
ret = devm_clk_hw_register(dev, &sclk->hw);
115-
if (!ret)
116-
clk_hw_set_rate_range(&sclk->hw, sclk->info->range.min_rate,
117-
sclk->info->range.max_rate);
117+
if (ret)
118+
return ret;
119+
120+
if (sclk->info->rate_discrete) {
121+
int num_rates = sclk->info->list.num_rates;
122+
123+
if (num_rates <= 0)
124+
return -EINVAL;
125+
126+
min_rate = sclk->info->list.rates[0];
127+
max_rate = sclk->info->list.rates[num_rates - 1];
128+
} else {
129+
min_rate = sclk->info->range.min_rate;
130+
max_rate = sclk->info->range.max_rate;
131+
}
132+
133+
clk_hw_set_rate_range(&sclk->hw, min_rate, max_rate);
118134
return ret;
119135
}
120136

drivers/cpufreq/scmi-cpufreq.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,8 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
198198

199199
policy->cpuinfo.transition_latency = latency;
200200

201-
policy->fast_switch_possible = true;
201+
policy->fast_switch_possible =
202+
handle->perf_ops->fast_switch_possible(handle, cpu_dev);
202203

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

drivers/firmware/arm_scmi/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o
33
scmi-bus-y = bus.o
4-
scmi-driver-y = driver.o
4+
scmi-driver-y = driver.o notify.o
55
scmi-transport-y = shmem.o
66
scmi-transport-$(CONFIG_MAILBOX) += mailbox.o
7-
scmi-transport-$(CONFIG_ARM_PSCI_FW) += smc.o
7+
scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o
88
scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
99
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o

drivers/firmware/arm_scmi/base.c

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@
55
* Copyright (C) 2018 ARM Ltd.
66
*/
77

8+
#define pr_fmt(fmt) "SCMI Notifications BASE - " fmt
9+
10+
#include <linux/scmi_protocol.h>
11+
812
#include "common.h"
13+
#include "notify.h"
14+
15+
#define SCMI_BASE_NUM_SOURCES 1
16+
#define SCMI_BASE_MAX_CMD_ERR_COUNT 1024
917

1018
enum scmi_base_protocol_cmd {
1119
BASE_DISCOVER_VENDOR = 0x3,
@@ -19,16 +27,25 @@ enum scmi_base_protocol_cmd {
1927
BASE_RESET_AGENT_CONFIGURATION = 0xb,
2028
};
2129

22-
enum scmi_base_protocol_notify {
23-
BASE_ERROR_EVENT = 0x0,
24-
};
25-
2630
struct scmi_msg_resp_base_attributes {
2731
u8 num_protocols;
2832
u8 num_agents;
2933
__le16 reserved;
3034
};
3135

36+
struct scmi_msg_base_error_notify {
37+
__le32 event_control;
38+
#define BASE_TP_NOTIFY_ALL BIT(0)
39+
};
40+
41+
struct scmi_base_error_notify_payld {
42+
__le32 agent_id;
43+
__le32 error_status;
44+
#define IS_FATAL_ERROR(x) ((x) & BIT(31))
45+
#define ERROR_CMD_COUNT(x) FIELD_GET(GENMASK(9, 0), (x))
46+
__le64 msg_reports[SCMI_BASE_MAX_CMD_ERR_COUNT];
47+
};
48+
3249
/**
3350
* scmi_base_attributes_get() - gets the implementation details
3451
* that are associated with the base protocol.
@@ -222,6 +239,83 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle,
222239
return ret;
223240
}
224241

242+
static int scmi_base_error_notify(const struct scmi_handle *handle, bool enable)
243+
{
244+
int ret;
245+
u32 evt_cntl = enable ? BASE_TP_NOTIFY_ALL : 0;
246+
struct scmi_xfer *t;
247+
struct scmi_msg_base_error_notify *cfg;
248+
249+
ret = scmi_xfer_get_init(handle, BASE_NOTIFY_ERRORS,
250+
SCMI_PROTOCOL_BASE, sizeof(*cfg), 0, &t);
251+
if (ret)
252+
return ret;
253+
254+
cfg = t->tx.buf;
255+
cfg->event_control = cpu_to_le32(evt_cntl);
256+
257+
ret = scmi_do_xfer(handle, t);
258+
259+
scmi_xfer_put(handle, t);
260+
return ret;
261+
}
262+
263+
static int scmi_base_set_notify_enabled(const struct scmi_handle *handle,
264+
u8 evt_id, u32 src_id, bool enable)
265+
{
266+
int ret;
267+
268+
ret = scmi_base_error_notify(handle, enable);
269+
if (ret)
270+
pr_debug("FAIL_ENABLED - evt[%X] ret:%d\n", evt_id, ret);
271+
272+
return ret;
273+
}
274+
275+
static void *scmi_base_fill_custom_report(const struct scmi_handle *handle,
276+
u8 evt_id, ktime_t timestamp,
277+
const void *payld, size_t payld_sz,
278+
void *report, u32 *src_id)
279+
{
280+
int i;
281+
const struct scmi_base_error_notify_payld *p = payld;
282+
struct scmi_base_error_report *r = report;
283+
284+
/*
285+
* BaseError notification payload is variable in size but
286+
* up to a maximum length determined by the struct ponted by p.
287+
* Instead payld_sz is the effective length of this notification
288+
* payload so cannot be greater of the maximum allowed size as
289+
* pointed by p.
290+
*/
291+
if (evt_id != SCMI_EVENT_BASE_ERROR_EVENT || sizeof(*p) < payld_sz)
292+
return NULL;
293+
294+
r->timestamp = timestamp;
295+
r->agent_id = le32_to_cpu(p->agent_id);
296+
r->fatal = IS_FATAL_ERROR(le32_to_cpu(p->error_status));
297+
r->cmd_count = ERROR_CMD_COUNT(le32_to_cpu(p->error_status));
298+
for (i = 0; i < r->cmd_count; i++)
299+
r->reports[i] = le64_to_cpu(p->msg_reports[i]);
300+
*src_id = 0;
301+
302+
return r;
303+
}
304+
305+
static const struct scmi_event base_events[] = {
306+
{
307+
.id = SCMI_EVENT_BASE_ERROR_EVENT,
308+
.max_payld_sz = sizeof(struct scmi_base_error_notify_payld),
309+
.max_report_sz = sizeof(struct scmi_base_error_report) +
310+
SCMI_BASE_MAX_CMD_ERR_COUNT * sizeof(u64),
311+
},
312+
};
313+
314+
static const struct scmi_event_ops base_event_ops = {
315+
.set_notify_enabled = scmi_base_set_notify_enabled,
316+
.fill_custom_report = scmi_base_fill_custom_report,
317+
};
318+
225319
int scmi_base_protocol_init(struct scmi_handle *h)
226320
{
227321
int id, ret;
@@ -256,6 +350,12 @@ int scmi_base_protocol_init(struct scmi_handle *h)
256350
dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols,
257351
rev->num_agents);
258352

353+
scmi_register_protocol_events(handle, SCMI_PROTOCOL_BASE,
354+
(4 * SCMI_PROTO_QUEUE_SZ),
355+
&base_event_ops, base_events,
356+
ARRAY_SIZE(base_events),
357+
SCMI_BASE_NUM_SOURCES);
358+
259359
for (id = 0; id < rev->num_agents; id++) {
260360
scmi_base_discover_agent_get(handle, id, name);
261361
dev_dbg(dev, "Agent %d: %s\n", id, name);

drivers/firmware/arm_scmi/clock.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* Copyright (C) 2018 ARM Ltd.
66
*/
77

8+
#include <linux/sort.h>
9+
810
#include "common.h"
911

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

126+
static int rate_cmp_func(const void *_r1, const void *_r2)
127+
{
128+
const u64 *r1 = _r1, *r2 = _r2;
129+
130+
if (*r1 < *r2)
131+
return -1;
132+
else if (*r1 == *r2)
133+
return 0;
134+
else
135+
return 1;
136+
}
137+
124138
static int
125139
scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
126140
struct scmi_clock_info *clk)
127141
{
128-
u64 *rate;
142+
u64 *rate = 0;
129143
int ret, cnt;
130144
bool rate_discrete = false;
131145
u32 tot_rate_cnt = 0, rates_flag;
@@ -184,8 +198,10 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id,
184198
*/
185199
} while (num_returned && num_remaining);
186200

187-
if (rate_discrete)
201+
if (rate_discrete && rate) {
188202
clk->list.num_rates = tot_rate_cnt;
203+
sort(rate, tot_rate_cnt, sizeof(*rate), rate_cmp_func, NULL);
204+
}
189205

190206
clk->rate_discrete = rate_discrete;
191207

drivers/firmware/arm_scmi/common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*
77
* Copyright (C) 2018 ARM Ltd.
88
*/
9+
#ifndef _SCMI_COMMON_H
10+
#define _SCMI_COMMON_H
911

1012
#include <linux/bitfield.h>
1113
#include <linux/completion.h>
@@ -235,3 +237,5 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
235237
void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
236238
bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
237239
struct scmi_xfer *xfer);
240+
241+
#endif /* _SCMI_COMMON_H */

drivers/firmware/arm_scmi/driver.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/slab.h>
2727

2828
#include "common.h"
29+
#include "notify.h"
2930

3031
#define CREATE_TRACE_POINTS
3132
#include <trace/events/scmi.h>
@@ -208,7 +209,9 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, u32 msg_hdr)
208209
struct device *dev = cinfo->dev;
209210
struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
210211
struct scmi_xfers_info *minfo = &info->rx_minfo;
212+
ktime_t ts;
211213

214+
ts = ktime_get_boottime();
212215
xfer = scmi_xfer_get(cinfo->handle, minfo);
213216
if (IS_ERR(xfer)) {
214217
dev_err(dev, "failed to get free message slot (%ld)\n",
@@ -221,6 +224,8 @@ static void scmi_handle_notification(struct scmi_chan_info *cinfo, u32 msg_hdr)
221224
scmi_dump_header_dbg(dev, &xfer->hdr);
222225
info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size,
223226
xfer);
227+
scmi_notify(cinfo->handle, xfer->hdr.protocol_id,
228+
xfer->hdr.id, xfer->rx.buf, xfer->rx.len, ts);
224229

225230
trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id,
226231
xfer->hdr.protocol_id, xfer->hdr.seq,
@@ -392,8 +397,7 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
392397
info->desc->ops->mark_txdone(cinfo, ret);
393398

394399
trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id,
395-
xfer->hdr.protocol_id, xfer->hdr.seq,
396-
xfer->hdr.status);
400+
xfer->hdr.protocol_id, xfer->hdr.seq, ret);
397401

398402
return ret;
399403
}
@@ -789,6 +793,9 @@ static int scmi_probe(struct platform_device *pdev)
789793
if (ret)
790794
return ret;
791795

796+
if (scmi_notification_init(handle))
797+
dev_err(dev, "SCMI Notifications NOT available.\n");
798+
792799
ret = scmi_base_protocol_init(handle);
793800
if (ret) {
794801
dev_err(dev, "unable to communicate with SCMI(%d)\n", ret);
@@ -831,6 +838,8 @@ static int scmi_remove(struct platform_device *pdev)
831838
struct scmi_info *info = platform_get_drvdata(pdev);
832839
struct idr *idr = &info->tx_idr;
833840

841+
scmi_notification_exit(&info->handle);
842+
834843
mutex_lock(&scmi_list_mutex);
835844
if (info->users)
836845
ret = -EBUSY;
@@ -901,7 +910,7 @@ ATTRIBUTE_GROUPS(versions);
901910
/* Each compatible listed below must have descriptor associated with it */
902911
static const struct of_device_id scmi_of_match[] = {
903912
{ .compatible = "arm,scmi", .data = &scmi_mailbox_desc },
904-
#ifdef CONFIG_ARM_PSCI_FW
913+
#ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY
905914
{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
906915
#endif
907916
{ /* Sentinel */ },

0 commit comments

Comments
 (0)