384 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * System Control and Management Interface (SCMI) Message Mailbox Transport4 * driver.5 *6 * Copyright (C) 2019-2024 ARM Ltd.7 */8 9#include <linux/err.h>10#include <linux/device.h>11#include <linux/mailbox_client.h>12#include <linux/of.h>13#include <linux/of_address.h>14#include <linux/platform_device.h>15#include <linux/slab.h>16 17#include "../common.h"18 19/**20 * struct scmi_mailbox - Structure representing a SCMI mailbox transport21 *22 * @cl: Mailbox Client23 * @chan: Transmit/Receive mailbox uni/bi-directional channel24 * @chan_receiver: Optional Receiver mailbox unidirectional channel25 * @chan_platform_receiver: Optional Platform Receiver mailbox unidirectional channel26 * @cinfo: SCMI channel info27 * @shmem: Transmit/Receive shared memory area28 * @chan_lock: Lock that prevents multiple xfers from being queued29 */30struct scmi_mailbox {31 struct mbox_client cl;32 struct mbox_chan *chan;33 struct mbox_chan *chan_receiver;34 struct mbox_chan *chan_platform_receiver;35 struct scmi_chan_info *cinfo;36 struct scmi_shared_mem __iomem *shmem;37 struct mutex chan_lock;38};39 40#define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl)41 42static struct scmi_transport_core_operations *core;43 44static void tx_prepare(struct mbox_client *cl, void *m)45{46 struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);47 48 core->shmem->tx_prepare(smbox->shmem, m, smbox->cinfo);49}50 51static void rx_callback(struct mbox_client *cl, void *m)52{53 struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl);54 55 /*56 * An A2P IRQ is NOT valid when received while the platform still has57 * the ownership of the channel, because the platform at first releases58 * the SMT channel and then sends the completion interrupt.59 *60 * This addresses a possible race condition in which a spurious IRQ from61 * a previous timed-out reply which arrived late could be wrongly62 * associated with the next pending transaction.63 */64 if (cl->knows_txdone &&65 !core->shmem->channel_free(smbox->shmem)) {66 dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n");67 core->bad_message_trace(smbox->cinfo,68 core->shmem->read_header(smbox->shmem),69 MSG_MBOX_SPURIOUS);70 return;71 }72 73 core->rx_callback(smbox->cinfo,74 core->shmem->read_header(smbox->shmem), NULL);75}76 77static bool mailbox_chan_available(struct device_node *of_node, int idx)78{79 int num_mb;80 81 /*82 * Just check if bidirrectional channels are involved, and check the83 * index accordingly; proper full validation will be made later84 * in mailbox_chan_setup().85 */86 num_mb = of_count_phandle_with_args(of_node, "mboxes", "#mbox-cells");87 if (num_mb == 3 && idx == 1)88 idx = 2;89 90 return !of_parse_phandle_with_args(of_node, "mboxes",91 "#mbox-cells", idx, NULL);92}93 94/**95 * mailbox_chan_validate - Validate transport configuration and map channels96 *97 * @cdev: Reference to the underlying transport device carrying the98 * of_node descriptor to analyze.99 * @a2p_rx_chan: A reference to an optional unidirectional channel to use100 * for replies on the a2p channel. Set as zero if not present.101 * @p2a_chan: A reference to the optional p2a channel.102 * Set as zero if not present.103 * @p2a_rx_chan: A reference to the optional p2a completion channel.104 * Set as zero if not present.105 *106 * At first, validate the transport configuration as described in terms of107 * 'mboxes' and 'shmem', then determin which mailbox channel indexes are108 * appropriate to be use in the current configuration.109 *110 * Return: 0 on Success or error111 */112static int mailbox_chan_validate(struct device *cdev, int *a2p_rx_chan,113 int *p2a_chan, int *p2a_rx_chan)114{115 int num_mb, num_sh, ret = 0;116 struct device_node *np = cdev->of_node;117 118 num_mb = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");119 num_sh = of_count_phandle_with_args(np, "shmem", NULL);120 dev_dbg(cdev, "Found %d mboxes and %d shmems !\n", num_mb, num_sh);121 122 /* Bail out if mboxes and shmem descriptors are inconsistent */123 if (num_mb <= 0 || num_sh <= 0 || num_sh > 2 || num_mb > 4 ||124 (num_mb == 1 && num_sh != 1) || (num_mb == 3 && num_sh != 2) ||125 (num_mb == 4 && num_sh != 2)) {126 dev_warn(cdev,127 "Invalid channel descriptor for '%s' - mbs:%d shm:%d\n",128 of_node_full_name(np), num_mb, num_sh);129 return -EINVAL;130 }131 132 /* Bail out if provided shmem descriptors do not refer distinct areas */133 if (num_sh > 1) {134 struct device_node *np_tx __free(device_node) =135 of_parse_phandle(np, "shmem", 0);136 struct device_node *np_rx __free(device_node) =137 of_parse_phandle(np, "shmem", 1);138 139 if (!np_tx || !np_rx || np_tx == np_rx) {140 dev_warn(cdev, "Invalid shmem descriptor for '%s'\n",141 of_node_full_name(np));142 ret = -EINVAL;143 }144 }145 146 /* Calculate channels IDs to use depending on mboxes/shmem layout */147 if (!ret) {148 switch (num_mb) {149 case 1:150 *a2p_rx_chan = 0;151 *p2a_chan = 0;152 *p2a_rx_chan = 0;153 break;154 case 2:155 if (num_sh == 2) {156 *a2p_rx_chan = 0;157 *p2a_chan = 1;158 } else {159 *a2p_rx_chan = 1;160 *p2a_chan = 0;161 }162 *p2a_rx_chan = 0;163 break;164 case 3:165 *a2p_rx_chan = 1;166 *p2a_chan = 2;167 *p2a_rx_chan = 0;168 break;169 case 4:170 *a2p_rx_chan = 1;171 *p2a_chan = 2;172 *p2a_rx_chan = 3;173 break;174 }175 }176 177 return ret;178}179 180static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,181 bool tx)182{183 const char *desc = tx ? "Tx" : "Rx";184 struct device *cdev = cinfo->dev;185 struct scmi_mailbox *smbox;186 int ret, a2p_rx_chan, p2a_chan, p2a_rx_chan;187 struct mbox_client *cl;188 189 ret = mailbox_chan_validate(cdev, &a2p_rx_chan, &p2a_chan, &p2a_rx_chan);190 if (ret)191 return ret;192 193 if (!tx && !p2a_chan)194 return -ENODEV;195 196 smbox = devm_kzalloc(dev, sizeof(*smbox), GFP_KERNEL);197 if (!smbox)198 return -ENOMEM;199 200 smbox->shmem = core->shmem->setup_iomap(cinfo, dev, tx, NULL);201 if (IS_ERR(smbox->shmem))202 return PTR_ERR(smbox->shmem);203 204 cl = &smbox->cl;205 cl->dev = cdev;206 cl->tx_prepare = tx ? tx_prepare : NULL;207 cl->rx_callback = rx_callback;208 cl->tx_block = false;209 cl->knows_txdone = tx;210 211 smbox->chan = mbox_request_channel(cl, tx ? 0 : p2a_chan);212 if (IS_ERR(smbox->chan)) {213 ret = PTR_ERR(smbox->chan);214 if (ret != -EPROBE_DEFER)215 dev_err(cdev,216 "failed to request SCMI %s mailbox\n", desc);217 return ret;218 }219 220 /* Additional unidirectional channel for TX if needed */221 if (tx && a2p_rx_chan) {222 smbox->chan_receiver = mbox_request_channel(cl, a2p_rx_chan);223 if (IS_ERR(smbox->chan_receiver)) {224 ret = PTR_ERR(smbox->chan_receiver);225 if (ret != -EPROBE_DEFER)226 dev_err(cdev, "failed to request SCMI Tx Receiver mailbox\n");227 return ret;228 }229 }230 231 if (!tx && p2a_rx_chan) {232 smbox->chan_platform_receiver = mbox_request_channel(cl, p2a_rx_chan);233 if (IS_ERR(smbox->chan_platform_receiver)) {234 ret = PTR_ERR(smbox->chan_platform_receiver);235 if (ret != -EPROBE_DEFER)236 dev_err(cdev, "failed to request SCMI P2A Receiver mailbox\n");237 return ret;238 }239 }240 241 cinfo->transport_info = smbox;242 smbox->cinfo = cinfo;243 mutex_init(&smbox->chan_lock);244 245 return 0;246}247 248static int mailbox_chan_free(int id, void *p, void *data)249{250 struct scmi_chan_info *cinfo = p;251 struct scmi_mailbox *smbox = cinfo->transport_info;252 253 if (smbox && !IS_ERR(smbox->chan)) {254 mbox_free_channel(smbox->chan);255 mbox_free_channel(smbox->chan_receiver);256 mbox_free_channel(smbox->chan_platform_receiver);257 cinfo->transport_info = NULL;258 smbox->chan = NULL;259 smbox->chan_receiver = NULL;260 smbox->chan_platform_receiver = NULL;261 smbox->cinfo = NULL;262 }263 264 return 0;265}266 267static int mailbox_send_message(struct scmi_chan_info *cinfo,268 struct scmi_xfer *xfer)269{270 struct scmi_mailbox *smbox = cinfo->transport_info;271 int ret;272 273 /*274 * The mailbox layer has its own queue. However the mailbox queue275 * confuses the per message SCMI timeouts since the clock starts when276 * the message is submitted into the mailbox queue. So when multiple277 * messages are queued up the clock starts on all messages instead of278 * only the one inflight.279 */280 mutex_lock(&smbox->chan_lock);281 282 ret = mbox_send_message(smbox->chan, xfer);283 /* mbox_send_message returns non-negative value on success */284 if (ret < 0) {285 mutex_unlock(&smbox->chan_lock);286 return ret;287 }288 289 return 0;290}291 292static void mailbox_mark_txdone(struct scmi_chan_info *cinfo, int ret,293 struct scmi_xfer *__unused)294{295 struct scmi_mailbox *smbox = cinfo->transport_info;296 297 mbox_client_txdone(smbox->chan, ret);298 299 /* Release channel */300 mutex_unlock(&smbox->chan_lock);301}302 303static void mailbox_fetch_response(struct scmi_chan_info *cinfo,304 struct scmi_xfer *xfer)305{306 struct scmi_mailbox *smbox = cinfo->transport_info;307 308 core->shmem->fetch_response(smbox->shmem, xfer);309}310 311static void mailbox_fetch_notification(struct scmi_chan_info *cinfo,312 size_t max_len, struct scmi_xfer *xfer)313{314 struct scmi_mailbox *smbox = cinfo->transport_info;315 316 core->shmem->fetch_notification(smbox->shmem, max_len, xfer);317}318 319static void mailbox_clear_channel(struct scmi_chan_info *cinfo)320{321 struct scmi_mailbox *smbox = cinfo->transport_info;322 struct mbox_chan *intr_chan;323 int ret;324 325 core->shmem->clear_channel(smbox->shmem);326 327 if (!core->shmem->channel_intr_enabled(smbox->shmem))328 return;329 330 if (smbox->chan_platform_receiver)331 intr_chan = smbox->chan_platform_receiver;332 else if (smbox->chan)333 intr_chan = smbox->chan;334 else335 return;336 337 ret = mbox_send_message(intr_chan, NULL);338 /* mbox_send_message returns non-negative value on success, so reset */339 if (ret > 0)340 ret = 0;341 342 mbox_client_txdone(intr_chan, ret);343}344 345static bool346mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)347{348 struct scmi_mailbox *smbox = cinfo->transport_info;349 350 return core->shmem->poll_done(smbox->shmem, xfer);351}352 353static const struct scmi_transport_ops scmi_mailbox_ops = {354 .chan_available = mailbox_chan_available,355 .chan_setup = mailbox_chan_setup,356 .chan_free = mailbox_chan_free,357 .send_message = mailbox_send_message,358 .mark_txdone = mailbox_mark_txdone,359 .fetch_response = mailbox_fetch_response,360 .fetch_notification = mailbox_fetch_notification,361 .clear_channel = mailbox_clear_channel,362 .poll_done = mailbox_poll_done,363};364 365static struct scmi_desc scmi_mailbox_desc = {366 .ops = &scmi_mailbox_ops,367 .max_rx_timeout_ms = 30, /* We may increase this if required */368 .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */369 .max_msg_size = 128,370};371 372static const struct of_device_id scmi_of_match[] = {373 { .compatible = "arm,scmi" },374 { /* Sentinel */ },375};376 377DEFINE_SCMI_TRANSPORT_DRIVER(scmi_mailbox, scmi_mailbox_driver,378 scmi_mailbox_desc, scmi_of_match, core);379module_platform_driver(scmi_mailbox_driver);380 381MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");382MODULE_DESCRIPTION("SCMI Mailbox Transport driver");383MODULE_LICENSE("GPL");384