Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

firmware: arm_scmi: Add support for notifications message processing

Add the mechanisms to distinguish notifications from delayed responses
and command responses. Also add support to properly fetch notification
messages upon reception. Notifications processing does not continue any
further after the fetch phase.

Link: https://lore.kernel.org/r/20200327143438.5382-5-cristian.marussi@arm.com
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
[Reworked/renamed scmi_handle_xfer_delayed_resp()]
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

+64 -20
+64 -20
drivers/firmware/arm_scmi/driver.c
··· 202 202 spin_unlock_irqrestore(&minfo->xfer_lock, flags); 203 203 } 204 204 205 - /** 206 - * scmi_rx_callback() - callback for receiving messages 207 - * 208 - * @cinfo: SCMI channel info 209 - * @msg_hdr: Message header 210 - * 211 - * Processes one received message to appropriate transfer information and 212 - * signals completion of the transfer. 213 - * 214 - * NOTE: This function will be invoked in IRQ context, hence should be 215 - * as optimal as possible. 216 - */ 217 - void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr) 205 + static void scmi_handle_notification(struct scmi_chan_info *cinfo, u32 msg_hdr) 218 206 { 207 + struct scmi_xfer *xfer; 208 + struct device *dev = cinfo->dev; 209 + struct scmi_info *info = handle_to_scmi_info(cinfo->handle); 210 + struct scmi_xfers_info *minfo = &info->rx_minfo; 211 + 212 + xfer = scmi_xfer_get(cinfo->handle, minfo); 213 + if (IS_ERR(xfer)) { 214 + dev_err(dev, "failed to get free message slot (%ld)\n", 215 + PTR_ERR(xfer)); 216 + info->desc->ops->clear_notification(cinfo); 217 + return; 218 + } 219 + 220 + unpack_scmi_header(msg_hdr, &xfer->hdr); 221 + scmi_dump_header_dbg(dev, &xfer->hdr); 222 + info->desc->ops->fetch_notification(cinfo, info->desc->max_msg_size, 223 + xfer); 224 + 225 + trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id, 226 + xfer->hdr.protocol_id, xfer->hdr.seq, 227 + MSG_TYPE_NOTIFICATION); 228 + 229 + __scmi_xfer_put(minfo, xfer); 230 + 231 + info->desc->ops->clear_notification(cinfo); 232 + } 233 + 234 + static void scmi_handle_response(struct scmi_chan_info *cinfo, 235 + u16 xfer_id, u8 msg_type) 236 + { 237 + struct scmi_xfer *xfer; 238 + struct device *dev = cinfo->dev; 219 239 struct scmi_info *info = handle_to_scmi_info(cinfo->handle); 220 240 struct scmi_xfers_info *minfo = &info->tx_minfo; 221 - u16 xfer_id = MSG_XTRACT_TOKEN(msg_hdr); 222 - u8 msg_type = MSG_XTRACT_TYPE(msg_hdr); 223 - struct device *dev = cinfo->dev; 224 - struct scmi_xfer *xfer; 225 - 226 - if (msg_type == MSG_TYPE_NOTIFICATION) 227 - return; /* Notifications not yet supported */ 228 241 229 242 /* Are we even expecting this? */ 230 243 if (!test_bit(xfer_id, minfo->xfer_alloc_table)) { ··· 259 246 complete(xfer->async_done); 260 247 else 261 248 complete(&xfer->done); 249 + } 250 + 251 + /** 252 + * scmi_rx_callback() - callback for receiving messages 253 + * 254 + * @cinfo: SCMI channel info 255 + * @msg_hdr: Message header 256 + * 257 + * Processes one received message to appropriate transfer information and 258 + * signals completion of the transfer. 259 + * 260 + * NOTE: This function will be invoked in IRQ context, hence should be 261 + * as optimal as possible. 262 + */ 263 + void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr) 264 + { 265 + u16 xfer_id = MSG_XTRACT_TOKEN(msg_hdr); 266 + u8 msg_type = MSG_XTRACT_TYPE(msg_hdr); 267 + 268 + switch (msg_type) { 269 + case MSG_TYPE_NOTIFICATION: 270 + scmi_handle_notification(cinfo, msg_hdr); 271 + break; 272 + case MSG_TYPE_COMMAND: 273 + case MSG_TYPE_DELAYED_RESP: 274 + scmi_handle_response(cinfo, xfer_id, msg_type); 275 + break; 276 + default: 277 + WARN_ONCE(1, "received unknown msg_type:%d\n", msg_type); 278 + break; 279 + } 262 280 } 263 281 264 282 /**