Skip to content

Commit d77b016

Browse files
committed
Merge tag 'scmi-fixes-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes
Arm SCMI fixes for v6.8 Few fixes addressing the below issues: 1. A spurious IRQ related to the late reply can get wrongly associated with the new enqueued request resulting in misinterpretation of data in shared memory. This race-condition can be detected by looking at the channel status bits which the platform must set to the channel free before triggering the completion IRQ. Adding a consistency check to validate such condition will fix the issue. 2. Incorrect use of asm-generic/bug.h instead of generic linux/bUg.h 3. xa_store() can't check for possible duplication insertion, use xa_insert() instead 4. Fix the SCMI clock protocol version in the v3.2 SCMI specification 5. Incorrect upgrade of highest supported clock protocol version from v2.0 to v3.0 * tag 'scmi-fixes-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_scmi: Fix the clock protocol supported version firmware: arm_scmi: Fix the clock protocol version for v3.2 firmware: arm_scmi: Use xa_insert() when saving raw queues firmware: arm_scmi: Use xa_insert() to store opps firmware: arm_scmi: Replace asm-generic/bug.h with linux/bug.h firmware: arm_scmi: Check mailbox/SMT channel for consistency Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 5e2400f + 6bd1b3f commit d77b016

File tree

6 files changed

+50
-13
lines changed

6 files changed

+50
-13
lines changed

drivers/firmware/arm_scmi/clock.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#include "notify.h"
1414

1515
/* Updated only after ALL the mandatory features for that version are merged */
16-
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001
16+
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
1717

1818
enum scmi_clock_protocol_cmd {
1919
CLOCK_ATTRIBUTES = 0x3,
@@ -954,8 +954,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
954954
scmi_clock_describe_rates_get(ph, clkid, clk);
955955
}
956956

957-
if (PROTOCOL_REV_MAJOR(version) >= 0x2 &&
958-
PROTOCOL_REV_MINOR(version) >= 0x1) {
957+
if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
959958
cinfo->clock_config_set = scmi_clock_config_set_v2;
960959
cinfo->clock_config_get = scmi_clock_config_get_v2;
961960
} else {

drivers/firmware/arm_scmi/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem,
314314
void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem);
315315
bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
316316
struct scmi_xfer *xfer);
317+
bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem);
317318

318319
/* declarations for message passing transports */
319320
struct scmi_msg_payld;

drivers/firmware/arm_scmi/mailbox.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ static void rx_callback(struct mbox_client *cl, void *m)
4545
{
4646
struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);
4747

48+
/*
49+
* An A2P IRQ is NOT valid when received while the platform still has
50+
* the ownership of the channel, because the platform at first releases
51+
* the SMT channel and then sends the completion interrupt.
52+
*
53+
* This addresses a possible race condition in which a spurious IRQ from
54+
* a previous timed-out reply which arrived late could be wrongly
55+
* associated with the next pending transaction.
56+
*/
57+
if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) {
58+
dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n");
59+
return;
60+
}
61+
4862
scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL);
4963
}
5064

drivers/firmware/arm_scmi/perf.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -350,8 +350,8 @@ process_response_opp(struct scmi_opp *opp, unsigned int loop_idx,
350350
}
351351

352352
static inline void
353-
process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp,
354-
unsigned int loop_idx,
353+
process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
354+
struct scmi_opp *opp, unsigned int loop_idx,
355355
const struct scmi_msg_resp_perf_describe_levels_v4 *r)
356356
{
357357
opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val);
@@ -362,10 +362,23 @@ process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp,
362362
/* Note that PERF v4 reports always five 32-bit words */
363363
opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq);
364364
if (dom->level_indexing_mode) {
365+
int ret;
366+
365367
opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index);
366368

367-
xa_store(&dom->opps_by_idx, opp->level_index, opp, GFP_KERNEL);
368-
xa_store(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
369+
ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp,
370+
GFP_KERNEL);
371+
if (ret)
372+
dev_warn(dev,
373+
"Failed to add opps_by_idx at %d - ret:%d\n",
374+
opp->level_index, ret);
375+
376+
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
377+
if (ret)
378+
dev_warn(dev,
379+
"Failed to add opps_by_lvl at %d - ret:%d\n",
380+
opp->perf, ret);
381+
369382
hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq);
370383
}
371384
}
@@ -382,7 +395,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
382395
if (PROTOCOL_REV_MAJOR(p->version) <= 0x3)
383396
process_response_opp(opp, st->loop_idx, response);
384397
else
385-
process_response_opp_v4(p->perf_dom, opp, st->loop_idx,
398+
process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx,
386399
response);
387400
p->perf_dom->opp_count++;
388401

drivers/firmware/arm_scmi/raw_mode.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,7 +1111,6 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
11111111
int i;
11121112

11131113
for (i = 0; i < num_chans; i++) {
1114-
void *xret;
11151114
struct scmi_raw_queue *q;
11161115

11171116
q = scmi_raw_queue_init(raw);
@@ -1120,13 +1119,12 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw,
11201119
goto err_xa;
11211120
}
11221121

1123-
xret = xa_store(&raw->chans_q, channels[i], q,
1122+
ret = xa_insert(&raw->chans_q, channels[i], q,
11241123
GFP_KERNEL);
1125-
if (xa_err(xret)) {
1124+
if (ret) {
11261125
dev_err(dev,
11271126
"Fail to allocate Raw queue 0x%02X\n",
11281127
channels[i]);
1129-
ret = xa_err(xret);
11301128
goto err_xa;
11311129
}
11321130
}
@@ -1322,6 +1320,12 @@ void scmi_raw_message_report(void *r, struct scmi_xfer *xfer,
13221320
dev = raw->handle->dev;
13231321
q = scmi_raw_queue_select(raw, idx,
13241322
SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0);
1323+
if (!q) {
1324+
dev_warn(dev,
1325+
"RAW[%d] - NO queue for chan 0x%X. Dropping report.\n",
1326+
idx, chan_id);
1327+
return;
1328+
}
13251329

13261330
/*
13271331
* Grab the msg_q_lock upfront to avoid a possible race between

drivers/firmware/arm_scmi/shmem.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <linux/processor.h>
1111
#include <linux/types.h>
1212

13-
#include <asm-generic/bug.h>
13+
#include <linux/bug.h>
1414

1515
#include "common.h"
1616

@@ -122,3 +122,9 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem,
122122
(SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR |
123123
SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
124124
}
125+
126+
bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem)
127+
{
128+
return (ioread32(&shmem->channel_status) &
129+
SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
130+
}

0 commit comments

Comments
 (0)