diff options
-rw-r--r-- | Documentation/remoteproc.txt | 127 | ||||
-rw-r--r-- | drivers/remoteproc/remoteproc_core.c | 306 | ||||
-rw-r--r-- | include/linux/remoteproc.h | 289 |
3 files changed, 505 insertions, 217 deletions
diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt index 23ff7349ffe7..07057cacfeae 100644 --- a/Documentation/remoteproc.txt +++ b/Documentation/remoteproc.txt | |||
@@ -221,43 +221,52 @@ resource entries that publish the existence of supported features | |||
221 | or configurations by the remote processor, such as trace buffers and | 221 | or configurations by the remote processor, such as trace buffers and |
222 | supported virtio devices (and their configurations). | 222 | supported virtio devices (and their configurations). |
223 | 223 | ||
224 | Currently the resource table is just an array of: | 224 | The resource table begins with this header: |
225 | 225 | ||
226 | /** | 226 | /** |
227 | * struct fw_resource - describes an entry from the resource section | 227 | * struct resource_table - firmware resource table header |
228 | * @ver: version number | ||
229 | * @num: number of resource entries | ||
230 | * @reserved: reserved (must be zero) | ||
231 | * @offset: array of offsets pointing at the various resource entries | ||
232 | * | ||
233 | * The header of the resource table, as expressed by this structure, | ||
234 | * contains a version number (should we need to change this format in the | ||
235 | * future), the number of available resource entries, and their offsets | ||
236 | * in the table. | ||
237 | */ | ||
238 | struct resource_table { | ||
239 | u32 ver; | ||
240 | u32 num; | ||
241 | u32 reserved[2]; | ||
242 | u32 offset[0]; | ||
243 | } __packed; | ||
244 | |||
245 | Immediately following this header are the resource entries themselves, | ||
246 | each of which begins with the following resource entry header: | ||
247 | |||
248 | /** | ||
249 | * struct fw_rsc_hdr - firmware resource entry header | ||
228 | * @type: resource type | 250 | * @type: resource type |
229 | * @id: index number of the resource | 251 | * @data: resource data |
230 | * @da: device address of the resource | 252 | * |
231 | * @pa: physical address of the resource | 253 | * Every resource entry begins with a 'struct fw_rsc_hdr' header providing |
232 | * @len: size, in bytes, of the resource | 254 | * its @type. The content of the entry itself will immediately follow |
233 | * @flags: properties of the resource, e.g. iommu protection required | 255 | * this header, and it should be parsed according to the resource type. |
234 | * @reserved: must be 0 atm | ||
235 | * @name: name of resource | ||
236 | */ | 256 | */ |
237 | struct fw_resource { | 257 | struct fw_rsc_hdr { |
238 | u32 type; | 258 | u32 type; |
239 | u32 id; | 259 | u8 data[0]; |
240 | u64 da; | ||
241 | u64 pa; | ||
242 | u32 len; | ||
243 | u32 flags; | ||
244 | u8 reserved[16]; | ||
245 | u8 name[48]; | ||
246 | } __packed; | 260 | } __packed; |
247 | 261 | ||
248 | Some resources entries are mere announcements, where the host is informed | 262 | Some resources entries are mere announcements, where the host is informed |
249 | of specific remoteproc configuration. Other entries require the host to | 263 | of specific remoteproc configuration. Other entries require the host to |
250 | do something (e.g. reserve a requested resource) and possibly also reply | 264 | do something (e.g. allocate a system resource). Sometimes a negotiation |
251 | by overwriting a member inside 'struct fw_resource' with info about the | 265 | is expected, where the firmware requests a resource, and once allocated, |
252 | allocated resource. | 266 | the host should provide back its details (e.g. address of an allocated |
253 | 267 | memory region). | |
254 | Different resource entries use different members of this struct, | ||
255 | with different meanings. This is pretty limiting and error-prone, | ||
256 | so the plan is to move to variable-length TLV-based resource entries, | ||
257 | where each resource will begin with a type and length fields, followed by | ||
258 | its own specific structure. | ||
259 | 268 | ||
260 | Here are the resource types that are currently being used: | 269 | Here are the various resource types that are currently supported: |
261 | 270 | ||
262 | /** | 271 | /** |
263 | * enum fw_resource_type - types of resource entries | 272 | * enum fw_resource_type - types of resource entries |
@@ -266,59 +275,45 @@ Here are the resource types that are currently being used: | |||
266 | * memory region. | 275 | * memory region. |
267 | * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. | 276 | * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. |
268 | * @RSC_TRACE: announces the availability of a trace buffer into which | 277 | * @RSC_TRACE: announces the availability of a trace buffer into which |
269 | * the remote processor will be writing logs. In this case, | 278 | * the remote processor will be writing logs. |
270 | * 'da' indicates the device address where logs are written to, | 279 | * @RSC_VDEV: declare support for a virtio device, and serve as its |
271 | * and 'len' is the size of the trace buffer. | 280 | * virtio header. |
272 | * @RSC_VRING: request for allocation of a virtio vring (address should | 281 | * @RSC_LAST: just keep this one at the end |
273 | * be indicated in 'da', and 'len' should contain the number | 282 | * |
274 | * of buffers supported by the vring). | 283 | * Please note that these values are used as indices to the rproc_handle_rsc |
275 | * @RSC_VIRTIO_DEV: announces support for a virtio device, and serves as | 284 | * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to |
276 | * the virtio header. 'da' contains the virtio device | 285 | * check the validity of an index before the lookup table is accessed, so |
277 | * features, 'pa' holds the virtio guest features (host | 286 | * please update it as needed. |
278 | * will write them here after they're negotiated), 'len' | ||
279 | * holds the virtio status, and 'flags' holds the virtio | ||
280 | * device id (currently only VIRTIO_ID_RPMSG is supported). | ||
281 | */ | 287 | */ |
282 | enum fw_resource_type { | 288 | enum fw_resource_type { |
283 | RSC_CARVEOUT = 0, | 289 | RSC_CARVEOUT = 0, |
284 | RSC_DEVMEM = 1, | 290 | RSC_DEVMEM = 1, |
285 | RSC_TRACE = 2, | 291 | RSC_TRACE = 2, |
286 | RSC_VRING = 3, | 292 | RSC_VDEV = 3, |
287 | RSC_VIRTIO_DEV = 4, | 293 | RSC_LAST = 4, |
288 | RSC_VIRTIO_CFG = 5, | ||
289 | }; | 294 | }; |
290 | 295 | ||
291 | Most of the resource entries share the basic idea of address/length | 296 | For more details regarding a specific resource type, please see its |
292 | negotiation with the host: the firmware usually asks for memory | 297 | dedicated structure in include/linux/remoteproc.h. |
293 | of size 'len' bytes, and the host needs to allocate it and provide | ||
294 | the device/physical address (when relevant) in 'da'/'pa' respectively. | ||
295 | |||
296 | If the firmware is compiled with hard coded device addresses, and | ||
297 | can't handle dynamically allocated 'da' values, then the 'da' field | ||
298 | will contain the expected device addresses (today we actually only support | ||
299 | this scheme, as there aren't yet any use cases for dynamically allocated | ||
300 | device addresses). | ||
301 | 298 | ||
302 | We also expect that platform-specific resource entries will show up | 299 | We also expect that platform-specific resource entries will show up |
303 | at some point. When that happens, we could easily add a new RSC_PLAFORM | 300 | at some point. When that happens, we could easily add a new RSC_PLATFORM |
304 | type, and hand those resources to the platform-specific rproc driver to handle. | 301 | type, and hand those resources to the platform-specific rproc driver to handle. |
305 | 302 | ||
306 | 7. Virtio and remoteproc | 303 | 7. Virtio and remoteproc |
307 | 304 | ||
308 | The firmware should provide remoteproc information about virtio devices | 305 | The firmware should provide remoteproc information about virtio devices |
309 | that it supports, and their configurations: a RSC_VIRTIO_DEV resource entry | 306 | that it supports, and their configurations: a RSC_VDEV resource entry |
310 | should specify the virtio device id, and subsequent RSC_VRING resource entries | 307 | should specify the virtio device id (as in virtio_ids.h), virtio features, |
311 | should indicate the vring size (i.e. how many buffers do they support) and | 308 | virtio config space, vrings information, etc. |
312 | where should they be mapped (i.e. which device address). Note: the alignment | 309 | |
313 | between the consumer and producer parts of the vring is assumed to be 4096. | 310 | When a new remote processor is registered, the remoteproc framework |
314 | 311 | will look for its resource table and will register the virtio devices | |
315 | At this point we only support a single virtio rpmsg device per remote | 312 | it supports. A firmware may support any number of virtio devices, and |
316 | processor, but the plan is to remove this limitation. In addition, once we | 313 | of any type (a single remote processor can also easily support several |
317 | move to TLV-based resource table, the plan is to have a single RSC_VIRTIO | 314 | rpmsg virtio devices this way, if desired). |
318 | entry per supported virtio device, which will include the virtio header, | 315 | |
319 | the vrings information and the virtio config space. | 316 | Of course, RSC_VDEV resource entries are only good enough for static |
320 | |||
321 | Of course, RSC_VIRTIO resource entries are only good enough for static | ||
322 | allocation of virtio devices. Dynamic allocations will also be made possible | 317 | allocation of virtio devices. Dynamic allocations will also be made possible |
323 | using the rpmsg bus (similar to how we already do dynamic allocations of | 318 | using the rpmsg bus (similar to how we already do dynamic allocations of |
324 | rpmsg channels; read more about it in rpmsg.txt). | 319 | rpmsg channels; read more about it in rpmsg.txt). |
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 8990c51c16f0..10348451c6c9 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c | |||
@@ -63,9 +63,8 @@ static void klist_rproc_put(struct klist_node *n); | |||
63 | static DEFINE_KLIST(rprocs, klist_rproc_get, klist_rproc_put); | 63 | static DEFINE_KLIST(rprocs, klist_rproc_get, klist_rproc_put); |
64 | 64 | ||
65 | typedef int (*rproc_handle_resources_t)(struct rproc *rproc, | 65 | typedef int (*rproc_handle_resources_t)(struct rproc *rproc, |
66 | struct fw_resource *rsc, int len); | 66 | struct resource_table *table, int len); |
67 | typedef int (*rproc_handle_resource_t)(struct rproc *rproc, | 67 | typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail); |
68 | struct fw_resource *rsc); | ||
69 | 68 | ||
70 | /* | 69 | /* |
71 | * This is the IOMMU fault handler we register with the IOMMU API | 70 | * This is the IOMMU fault handler we register with the IOMMU API |
@@ -281,9 +280,10 @@ rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len) | |||
281 | } | 280 | } |
282 | 281 | ||
283 | /** | 282 | /** |
284 | * rproc_handle_virtio_hdr() - handle a virtio header resource | 283 | * rproc_handle_early_vdev() - early handle a virtio header resource |
285 | * @rproc: the remote processor | 284 | * @rproc: the remote processor |
286 | * @rsc: the resource descriptor | 285 | * @rsc: the resource descriptor |
286 | * @avail: size of available data (for sanity checking the image) | ||
287 | * | 287 | * |
288 | * The existence of this virtio hdr resource entry means that the firmware | 288 | * The existence of this virtio hdr resource entry means that the firmware |
289 | * of this @rproc supports this virtio device. | 289 | * of this @rproc supports this virtio device. |
@@ -291,37 +291,32 @@ rproc_load_segments(struct rproc *rproc, const u8 *elf_data, size_t len) | |||
291 | * Currently we support only a single virtio device of type VIRTIO_ID_RPMSG, | 291 | * Currently we support only a single virtio device of type VIRTIO_ID_RPMSG, |
292 | * but the plan is to remove this limitation and support any number | 292 | * but the plan is to remove this limitation and support any number |
293 | * of virtio devices (and of any type). We'll also add support for dynamically | 293 | * of virtio devices (and of any type). We'll also add support for dynamically |
294 | * adding (and removing) virtio devices over the rpmsg bus, but small | 294 | * adding (and removing) virtio devices over the rpmsg bus, but simple |
295 | * firmwares that doesn't want to get involved with rpmsg will be able | 295 | * firmwares that doesn't want to get involved with rpmsg will be able |
296 | * to simple use the resource table for this. | 296 | * to simply use the resource table for this. |
297 | * | ||
298 | * At this point this virtio header entry is rather simple: it just | ||
299 | * announces the virtio device id and the supported virtio device features. | ||
300 | * The plan though is to extend this to include the vring information and | ||
301 | * the virtio config space, too (but first, some resource table overhaul | ||
302 | * is needed: move from fixed-sized to variable-length TLV entries). | ||
303 | * | ||
304 | * For now, the 'flags' member of the resource entry contains the virtio | ||
305 | * device id, the 'da' member contains the device features, and 'pa' is | ||
306 | * where we need to store the guest features once negotiation completes. | ||
307 | * As usual, the 'id' member of this resource contains the index of this | ||
308 | * resource type (i.e. is this the first virtio hdr entry, the 2nd, ...). | ||
309 | * | 297 | * |
310 | * Returns 0 on success, or an appropriate error code otherwise | 298 | * Returns 0 on success, or an appropriate error code otherwise |
311 | */ | 299 | */ |
312 | static int rproc_handle_virtio_hdr(struct rproc *rproc, struct fw_resource *rsc) | 300 | static int rproc_handle_early_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, |
301 | int avail) | ||
313 | { | 302 | { |
314 | struct rproc_vdev *rvdev; | 303 | struct rproc_vdev *rvdev; |
315 | 304 | ||
305 | /* make sure resource isn't truncated */ | ||
306 | if (sizeof(*rsc) > avail) { | ||
307 | dev_err(rproc->dev, "vdev rsc is truncated\n"); | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | |||
316 | /* we only support VIRTIO_ID_RPMSG devices for now */ | 311 | /* we only support VIRTIO_ID_RPMSG devices for now */ |
317 | if (rsc->flags != VIRTIO_ID_RPMSG) { | 312 | if (rsc->id != VIRTIO_ID_RPMSG) { |
318 | dev_warn(rproc->dev, "unsupported vdev: %d\n", rsc->flags); | 313 | dev_warn(rproc->dev, "unsupported vdev: %d\n", rsc->id); |
319 | return -EINVAL; | 314 | return -EINVAL; |
320 | } | 315 | } |
321 | 316 | ||
322 | /* we only support a single vdev per rproc for now */ | 317 | /* we only support a single vdev per rproc for now */ |
323 | if (rsc->id || rproc->rvdev) { | 318 | if (rproc->rvdev) { |
324 | dev_warn(rproc->dev, "redundant vdev entry: %s\n", rsc->name); | 319 | dev_warn(rproc->dev, "redundant vdev entry\n"); |
325 | return -EINVAL; | 320 | return -EINVAL; |
326 | } | 321 | } |
327 | 322 | ||
@@ -330,7 +325,7 @@ static int rproc_handle_virtio_hdr(struct rproc *rproc, struct fw_resource *rsc) | |||
330 | return -ENOMEM; | 325 | return -ENOMEM; |
331 | 326 | ||
332 | /* remember the device features */ | 327 | /* remember the device features */ |
333 | rvdev->dfeatures = rsc->da; | 328 | rvdev->dfeatures = rsc->dfeatures; |
334 | 329 | ||
335 | rproc->rvdev = rvdev; | 330 | rproc->rvdev = rvdev; |
336 | rvdev->rproc = rproc; | 331 | rvdev->rproc = rproc; |
@@ -339,9 +334,10 @@ static int rproc_handle_virtio_hdr(struct rproc *rproc, struct fw_resource *rsc) | |||
339 | } | 334 | } |
340 | 335 | ||
341 | /** | 336 | /** |
342 | * rproc_handle_vring() - handle a vring fw resource | 337 | * rproc_handle_vdev() - handle a vdev fw resource |
343 | * @rproc: the remote processor | 338 | * @rproc: the remote processor |
344 | * @rsc: the vring resource descriptor | 339 | * @rsc: the vring resource descriptor |
340 | * @avail: size of available data (for sanity checking the image) | ||
345 | * | 341 | * |
346 | * This resource entry requires allocation of non-cacheable memory | 342 | * This resource entry requires allocation of non-cacheable memory |
347 | * for a virtio vring. Currently we only support two vrings per remote | 343 | * for a virtio vring. Currently we only support two vrings per remote |
@@ -360,57 +356,82 @@ static int rproc_handle_virtio_hdr(struct rproc *rproc, struct fw_resource *rsc) | |||
360 | * | 356 | * |
361 | * Returns 0 on success, or an appropriate error code otherwise | 357 | * Returns 0 on success, or an appropriate error code otherwise |
362 | */ | 358 | */ |
363 | static int rproc_handle_vring(struct rproc *rproc, struct fw_resource *rsc) | 359 | static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, |
360 | int avail) | ||
364 | { | 361 | { |
365 | struct device *dev = rproc->dev; | 362 | struct device *dev = rproc->dev; |
366 | struct rproc_vdev *rvdev = rproc->rvdev; | 363 | struct rproc_vdev *rvdev = rproc->rvdev; |
367 | dma_addr_t dma; | 364 | int i; |
368 | int size, id = rsc->id; | ||
369 | void *va; | ||
370 | 365 | ||
371 | /* no vdev is in place ? */ | 366 | /* make sure resource isn't truncated */ |
372 | if (!rvdev) { | 367 | if (sizeof(*rsc) + rsc->num_of_vrings * sizeof(struct fw_rsc_vdev_vring) |
373 | dev_err(dev, "vring requested without a virtio dev entry\n"); | 368 | + rsc->config_len > avail) { |
369 | dev_err(rproc->dev, "vdev rsc is truncated\n"); | ||
374 | return -EINVAL; | 370 | return -EINVAL; |
375 | } | 371 | } |
376 | 372 | ||
377 | /* the firmware must provide the expected queue size */ | 373 | /* make sure reserved bytes are zeroes */ |
378 | if (!rsc->len) { | 374 | if (rsc->reserved[0] || rsc->reserved[1]) { |
379 | dev_err(dev, "missing expected queue size\n"); | 375 | dev_err(dev, "vdev rsc has non zero reserved bytes\n"); |
380 | return -EINVAL; | 376 | return -EINVAL; |
381 | } | 377 | } |
382 | 378 | ||
383 | /* we currently support two vrings per rproc (for rx and tx) */ | 379 | dev_dbg(dev, "vdev rsc: id %d, dfeatures %x, cfg len %d, %d vrings\n", |
384 | if (id >= ARRAY_SIZE(rvdev->vring)) { | 380 | rsc->id, rsc->dfeatures, rsc->config_len, rsc->num_of_vrings); |
385 | dev_err(dev, "%s: invalid vring id %d\n", rsc->name, id); | 381 | |
382 | /* no vdev is in place ? */ | ||
383 | if (!rvdev) { | ||
384 | dev_err(dev, "vring requested without a virtio dev entry\n"); | ||
386 | return -EINVAL; | 385 | return -EINVAL; |
387 | } | 386 | } |
388 | 387 | ||
389 | /* have we already allocated this vring id ? */ | 388 | /* we currently support two vrings per rproc (for rx and tx) */ |
390 | if (rvdev->vring[id].len) { | 389 | if (rsc->num_of_vrings != ARRAY_SIZE(rvdev->vring)) { |
391 | dev_err(dev, "%s: duplicated id %d\n", rsc->name, id); | 390 | dev_err(dev, "too many vrings: %d\n", rsc->num_of_vrings); |
392 | return -EINVAL; | 391 | return -EINVAL; |
393 | } | 392 | } |
394 | 393 | ||
395 | /* actual size of vring (in bytes) */ | 394 | /* initialize the vrings */ |
396 | size = PAGE_ALIGN(vring_size(rsc->len, AMP_VRING_ALIGN)); | 395 | for (i = 0; i < rsc->num_of_vrings; i++) { |
396 | struct fw_rsc_vdev_vring *vring = &rsc->vring[i]; | ||
397 | dma_addr_t dma; | ||
398 | int size; | ||
399 | void *va; | ||
400 | |||
401 | /* make sure reserved bytes are zeroes */ | ||
402 | if (vring->reserved) { | ||
403 | dev_err(dev, "vring rsc has non zero reserved bytes\n"); | ||
404 | return -EINVAL; | ||
405 | } | ||
397 | 406 | ||
398 | /* | 407 | /* the firmware must provide the expected queue size */ |
399 | * Allocate non-cacheable memory for the vring. In the future | 408 | if (!vring->num) { |
400 | * this call will also configure the IOMMU for us | 409 | dev_err(dev, "missing expected queue size\n"); |
401 | */ | 410 | /* potential cleanups are taken care of later on */ |
402 | va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL); | 411 | return -EINVAL; |
403 | if (!va) { | 412 | } |
404 | dev_err(dev, "dma_alloc_coherent failed\n"); | ||
405 | return -ENOMEM; | ||
406 | } | ||
407 | 413 | ||
408 | dev_dbg(dev, "vring%d: va %p dma %x qsz %d ring size %x\n", id, va, | 414 | /* actual size of vring (in bytes) */ |
409 | dma, rsc->len, size); | 415 | size = PAGE_ALIGN(vring_size(vring->num, AMP_VRING_ALIGN)); |
410 | 416 | ||
411 | rvdev->vring[id].len = rsc->len; | 417 | /* |
412 | rvdev->vring[id].va = va; | 418 | * Allocate non-cacheable memory for the vring. In the future |
413 | rvdev->vring[id].dma = dma; | 419 | * this call will also configure the IOMMU for us |
420 | */ | ||
421 | va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL); | ||
422 | if (!va) { | ||
423 | dev_err(dev, "dma_alloc_coherent failed\n"); | ||
424 | /* potential cleanups are taken care of later on */ | ||
425 | return -EINVAL; | ||
426 | } | ||
427 | |||
428 | dev_dbg(dev, "vring%d: va %p dma %x qsz %d ring size %x\n", i, | ||
429 | va, dma, vring->num, size); | ||
430 | |||
431 | rvdev->vring[i].len = vring->num; | ||
432 | rvdev->vring[i].va = va; | ||
433 | rvdev->vring[i].dma = dma; | ||
434 | } | ||
414 | 435 | ||
415 | return 0; | 436 | return 0; |
416 | } | 437 | } |
@@ -419,6 +440,7 @@ static int rproc_handle_vring(struct rproc *rproc, struct fw_resource *rsc) | |||
419 | * rproc_handle_trace() - handle a shared trace buffer resource | 440 | * rproc_handle_trace() - handle a shared trace buffer resource |
420 | * @rproc: the remote processor | 441 | * @rproc: the remote processor |
421 | * @rsc: the trace resource descriptor | 442 | * @rsc: the trace resource descriptor |
443 | * @avail: size of available data (for sanity checking the image) | ||
422 | * | 444 | * |
423 | * In case the remote processor dumps trace logs into memory, | 445 | * In case the remote processor dumps trace logs into memory, |
424 | * export it via debugfs. | 446 | * export it via debugfs. |
@@ -430,13 +452,25 @@ static int rproc_handle_vring(struct rproc *rproc, struct fw_resource *rsc) | |||
430 | * | 452 | * |
431 | * Returns 0 on success, or an appropriate error code otherwise | 453 | * Returns 0 on success, or an appropriate error code otherwise |
432 | */ | 454 | */ |
433 | static int rproc_handle_trace(struct rproc *rproc, struct fw_resource *rsc) | 455 | static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, |
456 | int avail) | ||
434 | { | 457 | { |
435 | struct rproc_mem_entry *trace; | 458 | struct rproc_mem_entry *trace; |
436 | struct device *dev = rproc->dev; | 459 | struct device *dev = rproc->dev; |
437 | void *ptr; | 460 | void *ptr; |
438 | char name[15]; | 461 | char name[15]; |
439 | 462 | ||
463 | if (sizeof(*rsc) > avail) { | ||
464 | dev_err(rproc->dev, "trace rsc is truncated\n"); | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | |||
468 | /* make sure reserved bytes are zeroes */ | ||
469 | if (rsc->reserved) { | ||
470 | dev_err(dev, "trace rsc has non zero reserved bytes\n"); | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | |||
440 | /* what's the kernel address of this resource ? */ | 474 | /* what's the kernel address of this resource ? */ |
441 | ptr = rproc_da_to_va(rproc, rsc->da, rsc->len); | 475 | ptr = rproc_da_to_va(rproc, rsc->da, rsc->len); |
442 | if (!ptr) { | 476 | if (!ptr) { |
@@ -469,7 +503,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_resource *rsc) | |||
469 | 503 | ||
470 | rproc->num_traces++; | 504 | rproc->num_traces++; |
471 | 505 | ||
472 | dev_dbg(dev, "%s added: va %p, da 0x%llx, len 0x%x\n", name, ptr, | 506 | dev_dbg(dev, "%s added: va %p, da 0x%x, len 0x%x\n", name, ptr, |
473 | rsc->da, rsc->len); | 507 | rsc->da, rsc->len); |
474 | 508 | ||
475 | return 0; | 509 | return 0; |
@@ -479,6 +513,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_resource *rsc) | |||
479 | * rproc_handle_devmem() - handle devmem resource entry | 513 | * rproc_handle_devmem() - handle devmem resource entry |
480 | * @rproc: remote processor handle | 514 | * @rproc: remote processor handle |
481 | * @rsc: the devmem resource entry | 515 | * @rsc: the devmem resource entry |
516 | * @avail: size of available data (for sanity checking the image) | ||
482 | * | 517 | * |
483 | * Remote processors commonly need to access certain on-chip peripherals. | 518 | * Remote processors commonly need to access certain on-chip peripherals. |
484 | * | 519 | * |
@@ -499,7 +534,8 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_resource *rsc) | |||
499 | * and not allow firmwares to request access to physical addresses that | 534 | * and not allow firmwares to request access to physical addresses that |
500 | * are outside those ranges. | 535 | * are outside those ranges. |
501 | */ | 536 | */ |
502 | static int rproc_handle_devmem(struct rproc *rproc, struct fw_resource *rsc) | 537 | static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, |
538 | int avail) | ||
503 | { | 539 | { |
504 | struct rproc_mem_entry *mapping; | 540 | struct rproc_mem_entry *mapping; |
505 | int ret; | 541 | int ret; |
@@ -508,6 +544,17 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_resource *rsc) | |||
508 | if (!rproc->domain) | 544 | if (!rproc->domain) |
509 | return -EINVAL; | 545 | return -EINVAL; |
510 | 546 | ||
547 | if (sizeof(*rsc) > avail) { | ||
548 | dev_err(rproc->dev, "devmem rsc is truncated\n"); | ||
549 | return -EINVAL; | ||
550 | } | ||
551 | |||
552 | /* make sure reserved bytes are zeroes */ | ||
553 | if (rsc->reserved) { | ||
554 | dev_err(rproc->dev, "devmem rsc has non zero reserved bytes\n"); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
511 | mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); | 558 | mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); |
512 | if (!mapping) { | 559 | if (!mapping) { |
513 | dev_err(rproc->dev, "kzalloc mapping failed\n"); | 560 | dev_err(rproc->dev, "kzalloc mapping failed\n"); |
@@ -531,7 +578,7 @@ static int rproc_handle_devmem(struct rproc *rproc, struct fw_resource *rsc) | |||
531 | mapping->len = rsc->len; | 578 | mapping->len = rsc->len; |
532 | list_add_tail(&mapping->node, &rproc->mappings); | 579 | list_add_tail(&mapping->node, &rproc->mappings); |
533 | 580 | ||
534 | dev_dbg(rproc->dev, "mapped devmem pa 0x%llx, da 0x%llx, len 0x%x\n", | 581 | dev_dbg(rproc->dev, "mapped devmem pa 0x%x, da 0x%x, len 0x%x\n", |
535 | rsc->pa, rsc->da, rsc->len); | 582 | rsc->pa, rsc->da, rsc->len); |
536 | 583 | ||
537 | return 0; | 584 | return 0; |
@@ -545,6 +592,7 @@ out: | |||
545 | * rproc_handle_carveout() - handle phys contig memory allocation requests | 592 | * rproc_handle_carveout() - handle phys contig memory allocation requests |
546 | * @rproc: rproc handle | 593 | * @rproc: rproc handle |
547 | * @rsc: the resource entry | 594 | * @rsc: the resource entry |
595 | * @avail: size of available data (for image validation) | ||
548 | * | 596 | * |
549 | * This function will handle firmware requests for allocation of physically | 597 | * This function will handle firmware requests for allocation of physically |
550 | * contiguous memory regions. | 598 | * contiguous memory regions. |
@@ -558,7 +606,8 @@ out: | |||
558 | * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB | 606 | * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB |
559 | * pressure is important; it may have a substantial impact on performance. | 607 | * pressure is important; it may have a substantial impact on performance. |
560 | */ | 608 | */ |
561 | static int rproc_handle_carveout(struct rproc *rproc, struct fw_resource *rsc) | 609 | static int rproc_handle_carveout(struct rproc *rproc, |
610 | struct fw_rsc_carveout *rsc, int avail) | ||
562 | { | 611 | { |
563 | struct rproc_mem_entry *carveout, *mapping; | 612 | struct rproc_mem_entry *carveout, *mapping; |
564 | struct device *dev = rproc->dev; | 613 | struct device *dev = rproc->dev; |
@@ -566,6 +615,20 @@ static int rproc_handle_carveout(struct rproc *rproc, struct fw_resource *rsc) | |||
566 | void *va; | 615 | void *va; |
567 | int ret; | 616 | int ret; |
568 | 617 | ||
618 | if (sizeof(*rsc) > avail) { | ||
619 | dev_err(rproc->dev, "carveout rsc is truncated\n"); | ||
620 | return -EINVAL; | ||
621 | } | ||
622 | |||
623 | /* make sure reserved bytes are zeroes */ | ||
624 | if (rsc->reserved) { | ||
625 | dev_err(dev, "carveout rsc has non zero reserved bytes\n"); | ||
626 | return -EINVAL; | ||
627 | } | ||
628 | |||
629 | dev_dbg(dev, "carveout rsc: da %x, pa %x, len %x, flags %x\n", | ||
630 | rsc->da, rsc->pa, rsc->len, rsc->flags); | ||
631 | |||
569 | mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); | 632 | mapping = kzalloc(sizeof(*mapping), GFP_KERNEL); |
570 | if (!mapping) { | 633 | if (!mapping) { |
571 | dev_err(dev, "kzalloc mapping failed\n"); | 634 | dev_err(dev, "kzalloc mapping failed\n"); |
@@ -624,7 +687,7 @@ static int rproc_handle_carveout(struct rproc *rproc, struct fw_resource *rsc) | |||
624 | mapping->len = rsc->len; | 687 | mapping->len = rsc->len; |
625 | list_add_tail(&mapping->node, &rproc->mappings); | 688 | list_add_tail(&mapping->node, &rproc->mappings); |
626 | 689 | ||
627 | dev_dbg(dev, "carveout mapped 0x%llx to 0x%x\n", rsc->da, dma); | 690 | dev_dbg(dev, "carveout mapped 0x%x to 0x%x\n", rsc->da, dma); |
628 | 691 | ||
629 | /* | 692 | /* |
630 | * Some remote processors might need to know the pa | 693 | * Some remote processors might need to know the pa |
@@ -665,36 +728,44 @@ free_mapping: | |||
665 | * enum fw_resource_type. | 728 | * enum fw_resource_type. |
666 | */ | 729 | */ |
667 | static rproc_handle_resource_t rproc_handle_rsc[] = { | 730 | static rproc_handle_resource_t rproc_handle_rsc[] = { |
668 | [RSC_CARVEOUT] = rproc_handle_carveout, | 731 | [RSC_CARVEOUT] = (rproc_handle_resource_t)rproc_handle_carveout, |
669 | [RSC_DEVMEM] = rproc_handle_devmem, | 732 | [RSC_DEVMEM] = (rproc_handle_resource_t)rproc_handle_devmem, |
670 | [RSC_TRACE] = rproc_handle_trace, | 733 | [RSC_TRACE] = (rproc_handle_resource_t)rproc_handle_trace, |
671 | [RSC_VRING] = rproc_handle_vring, | 734 | [RSC_VDEV] = (rproc_handle_resource_t)rproc_handle_vdev, |
672 | [RSC_VIRTIO_DEV] = NULL, /* handled early upon registration */ | ||
673 | }; | 735 | }; |
674 | 736 | ||
675 | /* handle firmware resource entries before booting the remote processor */ | 737 | /* handle firmware resource entries before booting the remote processor */ |
676 | static int | 738 | static int |
677 | rproc_handle_boot_rsc(struct rproc *rproc, struct fw_resource *rsc, int len) | 739 | rproc_handle_boot_rsc(struct rproc *rproc, struct resource_table *table, int len) |
678 | { | 740 | { |
679 | struct device *dev = rproc->dev; | 741 | struct device *dev = rproc->dev; |
680 | rproc_handle_resource_t handler; | 742 | rproc_handle_resource_t handler; |
681 | int ret = 0; | 743 | int ret = 0, i; |
744 | |||
745 | for (i = 0; i < table->num; i++) { | ||
746 | int offset = table->offset[i]; | ||
747 | struct fw_rsc_hdr *hdr = (void *)table + offset; | ||
748 | int avail = len - offset - sizeof(*hdr); | ||
749 | void *rsc = (void *)hdr + sizeof(*hdr); | ||
750 | |||
751 | /* make sure table isn't truncated */ | ||
752 | if (avail < 0) { | ||
753 | dev_err(dev, "rsc table is truncated\n"); | ||
754 | return -EINVAL; | ||
755 | } | ||
682 | 756 | ||
683 | for (; len >= sizeof(*rsc); rsc++, len -= sizeof(*rsc)) { | 757 | dev_dbg(dev, "rsc: type %d\n", hdr->type); |
684 | dev_dbg(dev, "rsc: type %d, da 0x%llx, pa 0x%llx, len 0x%x, " | ||
685 | "id %d, name %s, flags %x\n", rsc->type, rsc->da, | ||
686 | rsc->pa, rsc->len, rsc->id, rsc->name, rsc->flags); | ||
687 | 758 | ||
688 | if (rsc->type >= RSC_LAST) { | 759 | if (hdr->type >= RSC_LAST) { |
689 | dev_warn(dev, "unsupported resource %d\n", rsc->type); | 760 | dev_warn(dev, "unsupported resource %d\n", hdr->type); |
690 | continue; | 761 | continue; |
691 | } | 762 | } |
692 | 763 | ||
693 | handler = rproc_handle_rsc[rsc->type]; | 764 | handler = rproc_handle_rsc[hdr->type]; |
694 | if (!handler) | 765 | if (!handler) |
695 | continue; | 766 | continue; |
696 | 767 | ||
697 | ret = handler(rproc, rsc); | 768 | ret = handler(rproc, rsc, avail); |
698 | if (ret) | 769 | if (ret) |
699 | break; | 770 | break; |
700 | } | 771 | } |
@@ -704,18 +775,31 @@ rproc_handle_boot_rsc(struct rproc *rproc, struct fw_resource *rsc, int len) | |||
704 | 775 | ||
705 | /* handle firmware resource entries while registering the remote processor */ | 776 | /* handle firmware resource entries while registering the remote processor */ |
706 | static int | 777 | static int |
707 | rproc_handle_virtio_rsc(struct rproc *rproc, struct fw_resource *rsc, int len) | 778 | rproc_handle_virtio_rsc(struct rproc *rproc, struct resource_table *table, int len) |
708 | { | 779 | { |
709 | struct device *dev = rproc->dev; | 780 | struct device *dev = rproc->dev; |
710 | int ret = -ENODEV; | 781 | int ret = 0, i; |
782 | |||
783 | for (i = 0; i < table->num; i++) { | ||
784 | int offset = table->offset[i]; | ||
785 | struct fw_rsc_hdr *hdr = (void *)table + offset; | ||
786 | int avail = len - offset - sizeof(*hdr); | ||
711 | 787 | ||
712 | for (; len >= sizeof(*rsc); rsc++, len -= sizeof(*rsc)) | 788 | /* make sure table isn't truncated */ |
713 | if (rsc->type == RSC_VIRTIO_DEV) { | 789 | if (avail < 0) { |
714 | dev_dbg(dev, "found vdev %d/%s features %llx\n", | 790 | dev_err(dev, "rsc table is truncated\n"); |
715 | rsc->flags, rsc->name, rsc->da); | 791 | return -EINVAL; |
716 | ret = rproc_handle_virtio_hdr(rproc, rsc); | 792 | } |
793 | |||
794 | dev_dbg(dev, "%s: rsc type %d\n", __func__, hdr->type); | ||
795 | |||
796 | if (hdr->type == RSC_VDEV) { | ||
797 | struct fw_rsc_vdev *vrsc = | ||
798 | (struct fw_rsc_vdev *)hdr->data; | ||
799 | ret = rproc_handle_early_vdev(rproc, vrsc, avail); | ||
717 | break; | 800 | break; |
718 | } | 801 | } |
802 | } | ||
719 | 803 | ||
720 | return ret; | 804 | return ret; |
721 | } | 805 | } |
@@ -744,7 +828,9 @@ static int rproc_handle_resources(struct rproc *rproc, const u8 *elf_data, | |||
744 | struct elf32_hdr *ehdr; | 828 | struct elf32_hdr *ehdr; |
745 | struct elf32_shdr *shdr; | 829 | struct elf32_shdr *shdr; |
746 | const char *name_table; | 830 | const char *name_table; |
831 | struct device *dev = rproc->dev; | ||
747 | int i, ret = -EINVAL; | 832 | int i, ret = -EINVAL; |
833 | struct resource_table *table; | ||
748 | 834 | ||
749 | ehdr = (struct elf32_hdr *)elf_data; | 835 | ehdr = (struct elf32_hdr *)elf_data; |
750 | shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff); | 836 | shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff); |
@@ -752,21 +838,47 @@ static int rproc_handle_resources(struct rproc *rproc, const u8 *elf_data, | |||
752 | 838 | ||
753 | /* look for the resource table and handle it */ | 839 | /* look for the resource table and handle it */ |
754 | for (i = 0; i < ehdr->e_shnum; i++, shdr++) { | 840 | for (i = 0; i < ehdr->e_shnum; i++, shdr++) { |
755 | if (!strcmp(name_table + shdr->sh_name, ".resource_table")) { | 841 | int size = shdr->sh_size; |
756 | struct fw_resource *table = (struct fw_resource *) | 842 | int offset = shdr->sh_offset; |
757 | (elf_data + shdr->sh_offset); | ||
758 | 843 | ||
759 | if (shdr->sh_offset + shdr->sh_size > len) { | 844 | if (strcmp(name_table + shdr->sh_name, ".resource_table")) |
760 | dev_err(rproc->dev, | 845 | continue; |
761 | "truncated fw: need 0x%x avail 0x%x\n", | ||
762 | shdr->sh_offset + shdr->sh_size, len); | ||
763 | ret = -EINVAL; | ||
764 | } | ||
765 | 846 | ||
766 | ret = handler(rproc, table, shdr->sh_size); | 847 | table = (struct resource_table *)(elf_data + offset); |
767 | 848 | ||
768 | break; | 849 | /* make sure we have the entire table */ |
850 | if (offset + size > len) { | ||
851 | dev_err(dev, "resource table truncated\n"); | ||
852 | return -EINVAL; | ||
853 | } | ||
854 | |||
855 | /* make sure table has at least the header */ | ||
856 | if (sizeof(struct resource_table) > size) { | ||
857 | dev_err(dev, "header-less resource table\n"); | ||
858 | return -EINVAL; | ||
769 | } | 859 | } |
860 | |||
861 | /* we don't support any version beyond the first */ | ||
862 | if (table->ver != 1) { | ||
863 | dev_err(dev, "unsupported fw ver: %d\n", table->ver); | ||
864 | return -EINVAL; | ||
865 | } | ||
866 | |||
867 | /* make sure reserved bytes are zeroes */ | ||
868 | if (table->reserved[0] || table->reserved[1]) { | ||
869 | dev_err(dev, "non zero reserved bytes\n"); | ||
870 | return -EINVAL; | ||
871 | } | ||
872 | |||
873 | /* make sure the offsets array isn't truncated */ | ||
874 | if (table->num * sizeof(table->offset[0]) + | ||
875 | sizeof(struct resource_table) > size) { | ||
876 | dev_err(dev, "resource table incomplete\n"); | ||
877 | return -EINVAL; | ||
878 | } | ||
879 | |||
880 | ret = handler(rproc, table, shdr->sh_size); | ||
881 | break; | ||
770 | } | 882 | } |
771 | 883 | ||
772 | return ret; | 884 | return ret; |
@@ -980,7 +1092,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context) | |||
980 | if (rproc_fw_sanity_check(rproc, fw) < 0) | 1092 | if (rproc_fw_sanity_check(rproc, fw) < 0) |
981 | goto out; | 1093 | goto out; |
982 | 1094 | ||
983 | /* does the fw supports any virtio devices ? */ | 1095 | /* does the fw support any virtio devices ? */ |
984 | ret = rproc_handle_resources(rproc, fw->data, fw->size, | 1096 | ret = rproc_handle_resources(rproc, fw->data, fw->size, |
985 | rproc_handle_virtio_rsc); | 1097 | rproc_handle_virtio_rsc); |
986 | if (ret) { | 1098 | if (ret) { |
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index ada4cb063dfe..6040f831f626 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h | |||
@@ -50,39 +50,51 @@ | |||
50 | #define AMP_VRING_ALIGN (4096) | 50 | #define AMP_VRING_ALIGN (4096) |
51 | 51 | ||
52 | /** | 52 | /** |
53 | * struct fw_resource - describes an entry from the resource section | 53 | * struct resource_table - firmware resource table header |
54 | * @type: resource type | 54 | * @ver: version number |
55 | * @id: index number of the resource | 55 | * @num: number of resource entries |
56 | * @da: device address of the resource | 56 | * @reserved: reserved (must be zero) |
57 | * @pa: physical address of the resource | 57 | * @offset: array of offsets pointing at the various resource entries |
58 | * @len: size, in bytes, of the resource | ||
59 | * @flags: properties of the resource, e.g. iommu protection required | ||
60 | * @reserved: must be 0 atm | ||
61 | * @name: name of resource | ||
62 | * | 58 | * |
63 | * The remote processor firmware should contain a "resource table": | 59 | * A resource table is essentially a list of system resources required |
64 | * array of 'struct fw_resource' entries. | 60 | * by the remote processor. It may also include configuration entries. |
61 | * If needed, the remote processor firmware should contain this table | ||
62 | * as a dedicated ".resource_table" ELF section. | ||
65 | * | 63 | * |
66 | * Some resources entries are mere announcements, where the host is informed | 64 | * Some resources entries are mere announcements, where the host is informed |
67 | * of specific remoteproc configuration. Other entries require the host to | 65 | * of specific remoteproc configuration. Other entries require the host to |
68 | * do something (e.g. reserve a requested resource) and possibly also reply | 66 | * do something (e.g. allocate a system resource). Sometimes a negotiation |
69 | * by overwriting a member inside 'struct fw_resource' with info about the | 67 | * is expected, where the firmware requests a resource, and once allocated, |
70 | * allocated resource. | 68 | * the host should provide back its details (e.g. address of an allocated |
71 | * | 69 | * memory region). |
72 | * Different resource entries use different members of this struct, | 70 | * |
73 | * with different meanings. This is pretty limiting and error-prone, | 71 | * The header of the resource table, as expressed by this structure, |
74 | * so the plan is to move to variable-length TLV-based resource entries, | 72 | * contains a version number (should we need to change this format in the |
75 | * where each resource type will have its own structure. | 73 | * future), the number of available resource entries, and their offsets |
74 | * in the table. | ||
75 | * | ||
76 | * Immediately following this header are the resource entries themselves, | ||
77 | * each of which begins with a resource entry header (as described below). | ||
78 | */ | ||
79 | struct resource_table { | ||
80 | u32 ver; | ||
81 | u32 num; | ||
82 | u32 reserved[2]; | ||
83 | u32 offset[0]; | ||
84 | } __packed; | ||
85 | |||
86 | /** | ||
87 | * struct fw_rsc_hdr - firmware resource entry header | ||
88 | * @type: resource type | ||
89 | * @data: resource data | ||
90 | * | ||
91 | * Every resource entry begins with a 'struct fw_rsc_hdr' header providing | ||
92 | * its @type. The content of the entry itself will immediately follow | ||
93 | * this header, and it should be parsed according to the resource type. | ||
76 | */ | 94 | */ |
77 | struct fw_resource { | 95 | struct fw_rsc_hdr { |
78 | u32 type; | 96 | u32 type; |
79 | u32 id; | 97 | u8 data[0]; |
80 | u64 da; | ||
81 | u64 pa; | ||
82 | u32 len; | ||
83 | u32 flags; | ||
84 | u8 reserved[16]; | ||
85 | u8 name[48]; | ||
86 | } __packed; | 98 | } __packed; |
87 | 99 | ||
88 | /** | 100 | /** |
@@ -92,30 +104,13 @@ struct fw_resource { | |||
92 | * memory region. | 104 | * memory region. |
93 | * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. | 105 | * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. |
94 | * @RSC_TRACE: announces the availability of a trace buffer into which | 106 | * @RSC_TRACE: announces the availability of a trace buffer into which |
95 | * the remote processor will be writing logs. In this case, | 107 | * the remote processor will be writing logs. |
96 | * 'da' indicates the device address where logs are written to, | 108 | * @RSC_VDEV: declare support for a virtio device, and serve as its |
97 | * and 'len' is the size of the trace buffer. | 109 | * virtio header. |
98 | * @RSC_VRING: request for allocation of a virtio vring (address should | ||
99 | * be indicated in 'da', and 'len' should contain the number | ||
100 | * of buffers supported by the vring). | ||
101 | * @RSC_VIRTIO_DEV: this entry declares about support for a virtio device, | ||
102 | * and serves as the virtio header. 'da' holds the | ||
103 | * the virtio device features, 'pa' holds the virtio guest | ||
104 | * features, 'len' holds the virtio status, and 'flags' holds | ||
105 | * the virtio id (currently only VIRTIO_ID_RPMSG is supported). | ||
106 | * @RSC_LAST: just keep this one at the end | 110 | * @RSC_LAST: just keep this one at the end |
107 | * | 111 | * |
108 | * Most of the resource entries share the basic idea of address/length | 112 | * For more details regarding a specific resource type, please see its |
109 | * negotiation with the host: the firmware usually asks (on behalf of the | 113 | * dedicated structure below. |
110 | * remote processor that will soon be booted with it) for memory | ||
111 | * of size 'len' bytes, and the host needs to allocate it and provide | ||
112 | * the device/physical address (when relevant) in 'da'/'pa' respectively. | ||
113 | * | ||
114 | * If the firmware is compiled with hard coded device addresses, and | ||
115 | * can't handle dynamically allocated 'da' values, then the 'da' field | ||
116 | * will contain the expected device addresses (today we actually only support | ||
117 | * this scheme, as there aren't yet any use cases for dynamically allocated | ||
118 | * device addresses). | ||
119 | * | 114 | * |
120 | * Please note that these values are used as indices to the rproc_handle_rsc | 115 | * Please note that these values are used as indices to the rproc_handle_rsc |
121 | * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to | 116 | * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to |
@@ -126,11 +121,197 @@ enum fw_resource_type { | |||
126 | RSC_CARVEOUT = 0, | 121 | RSC_CARVEOUT = 0, |
127 | RSC_DEVMEM = 1, | 122 | RSC_DEVMEM = 1, |
128 | RSC_TRACE = 2, | 123 | RSC_TRACE = 2, |
129 | RSC_VRING = 3, | 124 | RSC_VDEV = 3, |
130 | RSC_VIRTIO_DEV = 4, | 125 | RSC_LAST = 4, |
131 | RSC_LAST = 5, | ||
132 | }; | 126 | }; |
133 | 127 | ||
128 | #define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF) | ||
129 | |||
130 | /** | ||
131 | * struct fw_rsc_carveout - physically contiguous memory request | ||
132 | * @da: device address | ||
133 | * @pa: physical address | ||
134 | * @len: length (in bytes) | ||
135 | * @flags: iommu protection flags | ||
136 | * @reserved: reserved (must be zero) | ||
137 | * @name: human-readable name of the requested memory region | ||
138 | * | ||
139 | * This resource entry requests the host to allocate a physically contiguous | ||
140 | * memory region. | ||
141 | * | ||
142 | * These request entries should precede other firmware resource entries, | ||
143 | * as other entries might request placing other data objects inside | ||
144 | * these memory regions (e.g. data/code segments, trace resource entries, ...). | ||
145 | * | ||
146 | * Allocating memory this way helps utilizing the reserved physical memory | ||
147 | * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries | ||
148 | * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB | ||
149 | * pressure is important; it may have a substantial impact on performance. | ||
150 | * | ||
151 | * If the firmware is compiled with static addresses, then @da should specify | ||
152 | * the expected device address of this memory region. If @da is set to | ||
153 | * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then | ||
154 | * overwrite @da with the dynamically allocated address. | ||
155 | * | ||
156 | * We will always use @da to negotiate the device addresses, even if it | ||
157 | * isn't using an iommu. In that case, though, it will obviously contain | ||
158 | * physical addresses. | ||
159 | * | ||
160 | * Some remote processors needs to know the allocated physical address | ||
161 | * even if they do use an iommu. This is needed, e.g., if they control | ||
162 | * hardware accelerators which access the physical memory directly (this | ||
163 | * is the case with OMAP4 for instance). In that case, the host will | ||
164 | * overwrite @pa with the dynamically allocated physical address. | ||
165 | * Generally we don't want to expose physical addresses if we don't have to | ||
166 | * (remote processors are generally _not_ trusted), so we might want to | ||
167 | * change this to happen _only_ when explicitly required by the hardware. | ||
168 | * | ||
169 | * @flags is used to provide IOMMU protection flags, and @name should | ||
170 | * (optionally) contain a human readable name of this carveout region | ||
171 | * (mainly for debugging purposes). | ||
172 | */ | ||
173 | struct fw_rsc_carveout { | ||
174 | u32 da; | ||
175 | u32 pa; | ||
176 | u32 len; | ||
177 | u32 flags; | ||
178 | u32 reserved; | ||
179 | u8 name[32]; | ||
180 | } __packed; | ||
181 | |||
182 | /** | ||
183 | * struct fw_rsc_devmem - iommu mapping request | ||
184 | * @da: device address | ||
185 | * @pa: physical address | ||
186 | * @len: length (in bytes) | ||
187 | * @flags: iommu protection flags | ||
188 | * @reserved: reserved (must be zero) | ||
189 | * @name: human-readable name of the requested region to be mapped | ||
190 | * | ||
191 | * This resource entry requests the host to iommu map a physically contiguous | ||
192 | * memory region. This is needed in case the remote processor requires | ||
193 | * access to certain memory-based peripherals; _never_ use it to access | ||
194 | * regular memory. | ||
195 | * | ||
196 | * This is obviously only needed if the remote processor is accessing memory | ||
197 | * via an iommu. | ||
198 | * | ||
199 | * @da should specify the required device address, @pa should specify | ||
200 | * the physical address we want to map, @len should specify the size of | ||
201 | * the mapping and @flags is the IOMMU protection flags. As always, @name may | ||
202 | * (optionally) contain a human readable name of this mapping (mainly for | ||
203 | * debugging purposes). | ||
204 | * | ||
205 | * Note: at this point we just "trust" those devmem entries to contain valid | ||
206 | * physical addresses, but this isn't safe and will be changed: eventually we | ||
207 | * want remoteproc implementations to provide us ranges of physical addresses | ||
208 | * the firmware is allowed to request, and not allow firmwares to request | ||
209 | * access to physical addresses that are outside those ranges. | ||
210 | */ | ||
211 | struct fw_rsc_devmem { | ||
212 | u32 da; | ||
213 | u32 pa; | ||
214 | u32 len; | ||
215 | u32 flags; | ||
216 | u32 reserved; | ||
217 | u8 name[32]; | ||
218 | } __packed; | ||
219 | |||
220 | /** | ||
221 | * struct fw_rsc_trace - trace buffer declaration | ||
222 | * @da: device address | ||
223 | * @len: length (in bytes) | ||
224 | * @reserved: reserved (must be zero) | ||
225 | * @name: human-readable name of the trace buffer | ||
226 | * | ||
227 | * This resource entry provides the host information about a trace buffer | ||
228 | * into which the remote processor will write log messages. | ||
229 | * | ||
230 | * @da specifies the device address of the buffer, @len specifies | ||
231 | * its size, and @name may contain a human readable name of the trace buffer. | ||
232 | * | ||
233 | * After booting the remote processor, the trace buffers are exposed to the | ||
234 | * user via debugfs entries (called trace0, trace1, etc..). | ||
235 | */ | ||
236 | struct fw_rsc_trace { | ||
237 | u32 da; | ||
238 | u32 len; | ||
239 | u32 reserved; | ||
240 | u8 name[32]; | ||
241 | } __packed; | ||
242 | |||
243 | /** | ||
244 | * struct fw_rsc_vdev_vring - vring descriptor entry | ||
245 | * @da: device address | ||
246 | * @align: the alignment between the consumer and producer parts of the vring | ||
247 | * @num: num of buffers supported by this vring (must be power of two) | ||
248 | * @notifyid is a unique rproc-wide notify index for this vring. This notify | ||
249 | * index is used when kicking a remote processor, to let it know that this | ||
250 | * vring is triggered. | ||
251 | * @reserved: reserved (must be zero) | ||
252 | * | ||
253 | * This descriptor is not a resource entry by itself; it is part of the | ||
254 | * vdev resource type (see below). | ||
255 | * | ||
256 | * Note that @da should either contain the device address where | ||
257 | * the remote processor is expecting the vring, or indicate that | ||
258 | * dynamically allocation of the vring's device address is supported. | ||
259 | */ | ||
260 | struct fw_rsc_vdev_vring { | ||
261 | u32 da; | ||
262 | u32 align; | ||
263 | u32 num; | ||
264 | u32 notifyid; | ||
265 | u32 reserved; | ||
266 | } __packed; | ||
267 | |||
268 | /** | ||
269 | * struct fw_rsc_vdev - virtio device header | ||
270 | * @id: virtio device id (as in virtio_ids.h) | ||
271 | * @notifyid is a unique rproc-wide notify index for this vdev. This notify | ||
272 | * index is used when kicking a remote processor, to let it know that the | ||
273 | * status/features of this vdev have changes. | ||
274 | * @dfeatures specifies the virtio device features supported by the firmware | ||
275 | * @gfeatures is a place holder used by the host to write back the | ||
276 | * negotiated features that are supported by both sides. | ||
277 | * @config_len is the size of the virtio config space of this vdev. The config | ||
278 | * space lies in the resource table immediate after this vdev header. | ||
279 | * @status is a place holder where the host will indicate its virtio progress. | ||
280 | * @num_of_vrings indicates how many vrings are described in this vdev header | ||
281 | * @reserved: reserved (must be zero) | ||
282 | * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. | ||
283 | * | ||
284 | * This resource is a virtio device header: it provides information about | ||
285 | * the vdev, and is then used by the host and its peer remote processors | ||
286 | * to negotiate and share certain virtio properties. | ||
287 | * | ||
288 | * By providing this resource entry, the firmware essentially asks remoteproc | ||
289 | * to statically allocate a vdev upon registration of the rproc (dynamic vdev | ||
290 | * allocation is not yet supported). | ||
291 | * | ||
292 | * Note: unlike virtualization systems, the term 'host' here means | ||
293 | * the Linux side which is running remoteproc to control the remote | ||
294 | * processors. We use the name 'gfeatures' to comply with virtio's terms, | ||
295 | * though there isn't really any virtualized guest OS here: it's the host | ||
296 | * which is responsible for negotiating the final features. | ||
297 | * Yeah, it's a bit confusing. | ||
298 | * | ||
299 | * Note: immediately following this structure is the virtio config space for | ||
300 | * this vdev (which is specific to the vdev; for more info, read the virtio | ||
301 | * spec). the size of the config space is specified by @config_len. | ||
302 | */ | ||
303 | struct fw_rsc_vdev { | ||
304 | u32 id; | ||
305 | u32 notifyid; | ||
306 | u32 dfeatures; | ||
307 | u32 gfeatures; | ||
308 | u32 config_len; | ||
309 | u8 status; | ||
310 | u8 num_of_vrings; | ||
311 | u8 reserved[2]; | ||
312 | struct fw_rsc_vdev_vring vring[0]; | ||
313 | } __packed; | ||
314 | |||
134 | /** | 315 | /** |
135 | * struct rproc_mem_entry - memory entry descriptor | 316 | * struct rproc_mem_entry - memory entry descriptor |
136 | * @va: virtual address | 317 | * @va: virtual address |
@@ -144,7 +325,7 @@ struct rproc_mem_entry { | |||
144 | void *va; | 325 | void *va; |
145 | dma_addr_t dma; | 326 | dma_addr_t dma; |
146 | int len; | 327 | int len; |
147 | u64 da; | 328 | u32 da; |
148 | void *priv; | 329 | void *priv; |
149 | struct list_head node; | 330 | struct list_head node; |
150 | }; | 331 | }; |
@@ -226,7 +407,7 @@ struct rproc { | |||
226 | struct list_head carveouts; | 407 | struct list_head carveouts; |
227 | struct list_head mappings; | 408 | struct list_head mappings; |
228 | struct completion firmware_loading_complete; | 409 | struct completion firmware_loading_complete; |
229 | u64 bootaddr; | 410 | u32 bootaddr; |
230 | struct rproc_vdev *rvdev; | 411 | struct rproc_vdev *rvdev; |
231 | }; | 412 | }; |
232 | 413 | ||