Skip to content

Commit

Permalink
Merge tag 'scmi-fixes-5.19-2' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/git/sudeep.holla/linux into arm/fixes

Arm SCMI firmware driver fixes for v5.19

Few more fixes to address:
1. Issue reported on Juno with HDLCD clock which turned out to be yet
   another firmware issue. The firmware is not conformant to the spec and
   we now have to workaround as this may be copied to other platforms as
   well. The spec expects to return size of 3 for a range clock rate
   description while the firmware returns 1. We have other ways to validate
   all the 3 entries the driver reads are polpulated and we use the same
   to workaround this firmware bug.

2. Optee transport not setting the correct reponse length which is similar
   to the one reported earlier on Rockchip platform.

3. Drop the usage of the deprecated ida_simple_{get,remove} and migrate to the
   ida_{alloc,free}

* tag 'scmi-fixes-5.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Remove usage of the deprecated ida_simple_xxx API
  firmware: arm_scmi: Fix response size warning for OPTEE transport
  firmware: arm_scmi: Relax CLOCK_DESCRIBE_RATES out-of-spec checks

Link: https://lore.kernel.org/r/20220628133315.699803-1-sudeep.holla@arm.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
  • Loading branch information
Arnd Bergmann committed Jul 1, 2022
2 parents 1f66f63 + 4ce7e51 commit d95ce66
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 5 deletions.
6 changes: 3 additions & 3 deletions drivers/firmware/arm_scmi/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
return NULL;
}

id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL);
id = ida_alloc_min(&scmi_bus_id, 1, GFP_KERNEL);
if (id < 0) {
kfree_const(scmi_dev->name);
kfree(scmi_dev);
Expand All @@ -204,15 +204,15 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
put_dev:
kfree_const(scmi_dev->name);
put_device(&scmi_dev->dev);
ida_simple_remove(&scmi_bus_id, id);
ida_free(&scmi_bus_id, id);
return NULL;
}

void scmi_device_destroy(struct scmi_device *scmi_dev)
{
kfree_const(scmi_dev->name);
scmi_handle_put(scmi_dev->handle);
ida_simple_remove(&scmi_bus_id, scmi_dev->id);
ida_free(&scmi_bus_id, scmi_dev->id);
device_unregister(&scmi_dev->dev);
}

Expand Down
26 changes: 25 additions & 1 deletion drivers/firmware/arm_scmi/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ static int rate_cmp_func(const void *_r1, const void *_r2)
}

struct scmi_clk_ipriv {
struct device *dev;
u32 clk_id;
struct scmi_clock_info *clk;
};
Expand Down Expand Up @@ -223,6 +224,29 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
st->num_returned = NUM_RETURNED(flags);
p->clk->rate_discrete = RATE_DISCRETE(flags);

/* Warn about out of spec replies ... */
if (!p->clk->rate_discrete &&
(st->num_returned != 3 || st->num_remaining != 0)) {
dev_warn(p->dev,
"Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
p->clk->name, st->num_returned, st->num_remaining,
st->rx_len);

/*
* A known quirk: a triplet is returned but num_returned != 3
* Check for a safe payload size and fix.
*/
if (st->num_returned != 3 && st->num_remaining == 0 &&
st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) {
st->num_returned = 3;
st->num_remaining = 0;
} else {
dev_err(p->dev,
"Cannot fix out-of-spec reply !\n");
return -EPROTO;
}
}

return 0;
}

Expand Down Expand Up @@ -255,7 +279,6 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,

*rate = RATE_TO_U64(r->rate[st->loop_idx]);
p->clk->list.num_rates++;
//XXX dev_dbg(ph->dev, "Rate %llu Hz\n", *rate);
}

return ret;
Expand All @@ -275,6 +298,7 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
struct scmi_clk_ipriv cpriv = {
.clk_id = clk_id,
.clk = clk,
.dev = ph->dev,
};

iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,
Expand Down
1 change: 1 addition & 0 deletions drivers/firmware/arm_scmi/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,7 @@ static int scmi_iterator_run(void *iter)
if (ret)
break;

st->rx_len = i->t->rx.len;
ret = iops->update_state(st, i->resp, i->priv);
if (ret)
break;
Expand Down
7 changes: 6 additions & 1 deletion drivers/firmware/arm_scmi/optee.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ struct scmi_optee_channel {
u32 channel_id;
u32 tee_session;
u32 caps;
u32 rx_len;
struct mutex mu;
struct scmi_chan_info *cinfo;
union {
Expand Down Expand Up @@ -302,6 +303,9 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t
return -EIO;
}

/* Save response size */
channel->rx_len = param[2].u.memref.size;

return 0;
}

Expand Down Expand Up @@ -353,6 +357,7 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch
shbuf = tee_shm_get_va(channel->tee_shm, 0);
memset(shbuf, 0, msg_size);
channel->req.msg = shbuf;
channel->rx_len = msg_size;

return 0;
}
Expand Down Expand Up @@ -508,7 +513,7 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo,
struct scmi_optee_channel *channel = cinfo->transport_info;

if (channel->tee_shm)
msg_fetch_response(channel->req.msg, SCMI_OPTEE_MAX_MSG_SIZE, xfer);
msg_fetch_response(channel->req.msg, channel->rx_len, xfer);
else
shmem_fetch_response(channel->req.shmem, xfer);
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/firmware/arm_scmi/protocols.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ struct scmi_protocol_handle {
* @max_resources: Maximum acceptable number of items, configured by the caller
* depending on the underlying resources that it is querying.
* @loop_idx: The iterator loop index in the current multi-part reply.
* @rx_len: Size in bytes of the currenly processed message; it can be used by
* the user of the iterator to verify a reply size.
* @priv: Optional pointer to some additional state-related private data setup
* by the caller during the iterations.
*/
Expand All @@ -188,6 +190,7 @@ struct scmi_iterator_state {
unsigned int num_remaining;
unsigned int max_resources;
unsigned int loop_idx;
size_t rx_len;
void *priv;
};

Expand Down

0 comments on commit d95ce66

Please sign in to comment.