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

firmware: arm_scmi: Add iterators for multi-part commands

SCMI specification defines some commands as optionally issued over multiple
messages in order to overcome possible limitations in payload size enforced
by the configured underlyinng transport.

Introduce some common protocol helpers to provide a unified solution for
issuing such SCMI multi-part commands.

Link: https://lore.kernel.org/r/20220330150551.2573938-14-cristian.marussi@arm.com
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

authored by

Cristian Marussi and committed by
Sudeep Holla
36b6ea0f df3576d1

+163
+109
drivers/firmware/arm_scmi/driver.c
··· 1148 1148 return ret; 1149 1149 } 1150 1150 1151 + /** 1152 + * struct scmi_iterator - Iterator descriptor 1153 + * @msg: A reference to the message TX buffer; filled by @prepare_message with 1154 + * a proper custom command payload for each multi-part command request. 1155 + * @resp: A reference to the response RX buffer; used by @update_state and 1156 + * @process_response to parse the multi-part replies. 1157 + * @t: A reference to the underlying xfer initialized and used transparently by 1158 + * the iterator internal routines. 1159 + * @ph: A reference to the associated protocol handle to be used. 1160 + * @ops: A reference to the custom provided iterator operations. 1161 + * @state: The current iterator state; used and updated in turn by the iterators 1162 + * internal routines and by the caller-provided @scmi_iterator_ops. 1163 + * @priv: A reference to optional private data as provided by the caller and 1164 + * passed back to the @@scmi_iterator_ops. 1165 + */ 1166 + struct scmi_iterator { 1167 + void *msg; 1168 + void *resp; 1169 + struct scmi_xfer *t; 1170 + const struct scmi_protocol_handle *ph; 1171 + struct scmi_iterator_ops *ops; 1172 + struct scmi_iterator_state state; 1173 + void *priv; 1174 + }; 1175 + 1176 + static void *scmi_iterator_init(const struct scmi_protocol_handle *ph, 1177 + struct scmi_iterator_ops *ops, 1178 + unsigned int max_resources, u8 msg_id, 1179 + size_t tx_size, void *priv) 1180 + { 1181 + int ret; 1182 + struct scmi_iterator *i; 1183 + 1184 + i = devm_kzalloc(ph->dev, sizeof(*i), GFP_KERNEL); 1185 + if (!i) 1186 + return ERR_PTR(-ENOMEM); 1187 + 1188 + i->ph = ph; 1189 + i->ops = ops; 1190 + i->priv = priv; 1191 + 1192 + ret = ph->xops->xfer_get_init(ph, msg_id, tx_size, 0, &i->t); 1193 + if (ret) { 1194 + devm_kfree(ph->dev, i); 1195 + return ERR_PTR(ret); 1196 + } 1197 + 1198 + i->state.max_resources = max_resources; 1199 + i->msg = i->t->tx.buf; 1200 + i->resp = i->t->rx.buf; 1201 + 1202 + return i; 1203 + } 1204 + 1205 + static int scmi_iterator_run(void *iter) 1206 + { 1207 + int ret = -EINVAL; 1208 + struct scmi_iterator *i = iter; 1209 + struct scmi_iterator_state *st = &i->state; 1210 + struct scmi_iterator_ops *iops = i->ops; 1211 + const struct scmi_protocol_handle *ph = i->ph; 1212 + const struct scmi_xfer_ops *xops = ph->xops; 1213 + 1214 + if (!i) 1215 + return ret; 1216 + 1217 + do { 1218 + iops->prepare_message(i->msg, st->desc_index, i->priv); 1219 + ret = xops->do_xfer(ph, i->t); 1220 + if (ret) 1221 + break; 1222 + 1223 + ret = iops->update_state(st, i->resp, i->priv); 1224 + if (ret) 1225 + break; 1226 + 1227 + if (st->num_returned > st->max_resources - st->desc_index) { 1228 + dev_err(ph->dev, 1229 + "No. of resources can't exceed %d\n", 1230 + st->max_resources); 1231 + ret = -EINVAL; 1232 + break; 1233 + } 1234 + 1235 + for (st->loop_idx = 0; st->loop_idx < st->num_returned; 1236 + st->loop_idx++) { 1237 + ret = iops->process_response(ph, i->resp, st, i->priv); 1238 + if (ret) 1239 + goto out; 1240 + } 1241 + 1242 + st->desc_index += st->num_returned; 1243 + xops->reset_rx_to_maxsz(ph, i->t); 1244 + /* 1245 + * check for both returned and remaining to avoid infinite 1246 + * loop due to buggy firmware 1247 + */ 1248 + } while (st->num_returned && st->num_remaining); 1249 + 1250 + out: 1251 + /* Finalize and destroy iterator */ 1252 + xops->xfer_put(ph, i->t); 1253 + devm_kfree(ph->dev, i); 1254 + 1255 + return ret; 1256 + } 1257 + 1151 1258 static const struct scmi_proto_helpers_ops helpers_ops = { 1152 1259 .extended_name_get = scmi_common_extended_name_get, 1260 + .iter_response_init = scmi_iterator_init, 1261 + .iter_response_run = scmi_iterator_run, 1153 1262 }; 1154 1263 1155 1264 /**
+54
drivers/firmware/arm_scmi/protocols.h
··· 174 174 }; 175 175 176 176 /** 177 + * struct scmi_iterator_state - Iterator current state descriptor 178 + * @desc_index: Starting index for the current mulit-part request. 179 + * @num_returned: Number of returned items in the last multi-part reply. 180 + * @num_remaining: Number of remaining items in the multi-part message. 181 + * @max_resources: Maximum acceptable number of items, configured by the caller 182 + * depending on the underlying resources that it is querying. 183 + * @loop_idx: The iterator loop index in the current multi-part reply. 184 + * @priv: Optional pointer to some additional state-related private data setup 185 + * by the caller during the iterations. 186 + */ 187 + struct scmi_iterator_state { 188 + unsigned int desc_index; 189 + unsigned int num_returned; 190 + unsigned int num_remaining; 191 + unsigned int max_resources; 192 + unsigned int loop_idx; 193 + void *priv; 194 + }; 195 + 196 + /** 197 + * struct scmi_iterator_ops - Custom iterator operations 198 + * @prepare_message: An operation to provide the custom logic to fill in the 199 + * SCMI command request pointed by @message. @desc_index is 200 + * a reference to the next index to use in the multi-part 201 + * request. 202 + * @update_state: An operation to provide the custom logic to update the 203 + * iterator state from the actual message response. 204 + * @process_response: An operation to provide the custom logic needed to process 205 + * each chunk of the multi-part message. 206 + */ 207 + struct scmi_iterator_ops { 208 + void (*prepare_message)(void *message, unsigned int desc_index, 209 + const void *priv); 210 + int (*update_state)(struct scmi_iterator_state *st, 211 + const void *response, void *priv); 212 + int (*process_response)(const struct scmi_protocol_handle *ph, 213 + const void *response, 214 + struct scmi_iterator_state *st, void *priv); 215 + }; 216 + 217 + /** 177 218 * struct scmi_proto_helpers_ops - References to common protocol helpers 178 219 * @extended_name_get: A common helper function to retrieve extended naming 179 220 * for the specified resource using the specified command. 180 221 * Result is returned as a NULL terminated string in the 181 222 * pre-allocated area pointed to by @name with maximum 182 223 * capacity of @len bytes. 224 + * @iter_response_init: A common helper to initialize a generic iterator to 225 + * parse multi-message responses: when run the iterator 226 + * will take care to send the initial command request as 227 + * specified by @msg_id and @tx_size and then to parse the 228 + * multi-part responses using the custom operations 229 + * provided in @ops. 230 + * @iter_response_run: A common helper to trigger the run of a previously 231 + * initialized iterator. 183 232 */ 184 233 struct scmi_proto_helpers_ops { 185 234 int (*extended_name_get)(const struct scmi_protocol_handle *ph, 186 235 u8 cmd_id, u32 res_id, char *name, size_t len); 236 + void *(*iter_response_init)(const struct scmi_protocol_handle *ph, 237 + struct scmi_iterator_ops *ops, 238 + unsigned int max_resources, u8 msg_id, 239 + size_t tx_size, void *priv); 240 + int (*iter_response_run)(void *iter); 187 241 }; 188 242 189 243 /**