| .. | .. |
|---|
| 38 | 38 | #include <linux/types.h> |
|---|
| 39 | 39 | #include <linux/mutex.h> |
|---|
| 40 | 40 | #include <linux/virtio.h> |
|---|
| 41 | +#include <linux/cdev.h> |
|---|
| 41 | 42 | #include <linux/completion.h> |
|---|
| 42 | 43 | #include <linux/idr.h> |
|---|
| 43 | 44 | #include <linux/of.h> |
|---|
| .. | .. |
|---|
| 73 | 74 | u32 ver; |
|---|
| 74 | 75 | u32 num; |
|---|
| 75 | 76 | u32 reserved[2]; |
|---|
| 76 | | - u32 offset[0]; |
|---|
| 77 | + u32 offset[]; |
|---|
| 77 | 78 | } __packed; |
|---|
| 78 | 79 | |
|---|
| 79 | 80 | /** |
|---|
| .. | .. |
|---|
| 87 | 88 | */ |
|---|
| 88 | 89 | struct fw_rsc_hdr { |
|---|
| 89 | 90 | u32 type; |
|---|
| 90 | | - u8 data[0]; |
|---|
| 91 | + u8 data[]; |
|---|
| 91 | 92 | } __packed; |
|---|
| 92 | 93 | |
|---|
| 93 | 94 | /** |
|---|
| .. | .. |
|---|
| 100 | 101 | * the remote processor will be writing logs. |
|---|
| 101 | 102 | * @RSC_VDEV: declare support for a virtio device, and serve as its |
|---|
| 102 | 103 | * virtio header. |
|---|
| 103 | | - * @RSC_LAST: just keep this one at the end |
|---|
| 104 | + * @RSC_LAST: just keep this one at the end of standard resources |
|---|
| 105 | + * @RSC_VENDOR_START: start of the vendor specific resource types range |
|---|
| 106 | + * @RSC_VENDOR_END: end of the vendor specific resource types range |
|---|
| 104 | 107 | * |
|---|
| 105 | 108 | * For more details regarding a specific resource type, please see its |
|---|
| 106 | 109 | * dedicated structure below. |
|---|
| .. | .. |
|---|
| 111 | 114 | * please update it as needed. |
|---|
| 112 | 115 | */ |
|---|
| 113 | 116 | enum fw_resource_type { |
|---|
| 114 | | - RSC_CARVEOUT = 0, |
|---|
| 115 | | - RSC_DEVMEM = 1, |
|---|
| 116 | | - RSC_TRACE = 2, |
|---|
| 117 | | - RSC_VDEV = 3, |
|---|
| 118 | | - RSC_LAST = 4, |
|---|
| 117 | + RSC_CARVEOUT = 0, |
|---|
| 118 | + RSC_DEVMEM = 1, |
|---|
| 119 | + RSC_TRACE = 2, |
|---|
| 120 | + RSC_VDEV = 3, |
|---|
| 121 | + RSC_LAST = 4, |
|---|
| 122 | + RSC_VENDOR_START = 128, |
|---|
| 123 | + RSC_VENDOR_END = 512, |
|---|
| 119 | 124 | }; |
|---|
| 120 | 125 | |
|---|
| 121 | 126 | #define FW_RSC_ADDR_ANY (-1) |
|---|
| .. | .. |
|---|
| 302 | 307 | u8 status; |
|---|
| 303 | 308 | u8 num_of_vrings; |
|---|
| 304 | 309 | u8 reserved[2]; |
|---|
| 305 | | - struct fw_rsc_vdev_vring vring[0]; |
|---|
| 310 | + struct fw_rsc_vdev_vring vring[]; |
|---|
| 306 | 311 | } __packed; |
|---|
| 312 | + |
|---|
| 313 | +struct rproc; |
|---|
| 307 | 314 | |
|---|
| 308 | 315 | /** |
|---|
| 309 | 316 | * struct rproc_mem_entry - memory entry descriptor |
|---|
| 310 | 317 | * @va: virtual address |
|---|
| 318 | + * @is_iomem: io memory |
|---|
| 311 | 319 | * @dma: dma address |
|---|
| 312 | 320 | * @len: length, in bytes |
|---|
| 313 | 321 | * @da: device address |
|---|
| 322 | + * @release: release associated memory |
|---|
| 314 | 323 | * @priv: associated data |
|---|
| 324 | + * @name: associated memory region name (optional) |
|---|
| 315 | 325 | * @node: list node |
|---|
| 326 | + * @rsc_offset: offset in resource table |
|---|
| 327 | + * @flags: iommu protection flags |
|---|
| 328 | + * @of_resm_idx: reserved memory phandle index |
|---|
| 329 | + * @alloc: specific memory allocator function |
|---|
| 316 | 330 | */ |
|---|
| 317 | 331 | struct rproc_mem_entry { |
|---|
| 318 | 332 | void *va; |
|---|
| 333 | + bool is_iomem; |
|---|
| 319 | 334 | dma_addr_t dma; |
|---|
| 320 | | - int len; |
|---|
| 335 | + size_t len; |
|---|
| 321 | 336 | u32 da; |
|---|
| 322 | 337 | void *priv; |
|---|
| 338 | + char name[32]; |
|---|
| 323 | 339 | struct list_head node; |
|---|
| 340 | + u32 rsc_offset; |
|---|
| 341 | + u32 flags; |
|---|
| 342 | + u32 of_resm_idx; |
|---|
| 343 | + int (*alloc)(struct rproc *rproc, struct rproc_mem_entry *mem); |
|---|
| 344 | + int (*release)(struct rproc *rproc, struct rproc_mem_entry *mem); |
|---|
| 324 | 345 | }; |
|---|
| 325 | 346 | |
|---|
| 326 | | -struct rproc; |
|---|
| 327 | 347 | struct firmware; |
|---|
| 328 | 348 | |
|---|
| 329 | 349 | /** |
|---|
| 350 | + * enum rsc_handling_status - return status of rproc_ops handle_rsc hook |
|---|
| 351 | + * @RSC_HANDLED: resource was handled |
|---|
| 352 | + * @RSC_IGNORED: resource was ignored |
|---|
| 353 | + */ |
|---|
| 354 | +enum rsc_handling_status { |
|---|
| 355 | + RSC_HANDLED = 0, |
|---|
| 356 | + RSC_IGNORED = 1, |
|---|
| 357 | +}; |
|---|
| 358 | + |
|---|
| 359 | +/** |
|---|
| 330 | 360 | * struct rproc_ops - platform-specific device handlers |
|---|
| 361 | + * @prepare: prepare device for code loading |
|---|
| 362 | + * @unprepare: unprepare device after stop |
|---|
| 331 | 363 | * @start: power on the device and boot it |
|---|
| 332 | 364 | * @stop: power off the device |
|---|
| 365 | + * @attach: attach to a device that his already powered up |
|---|
| 333 | 366 | * @kick: kick a virtqueue (virtqueue id given as a parameter) |
|---|
| 334 | 367 | * @da_to_va: optional platform hook to perform address translations |
|---|
| 368 | + * @parse_fw: parse firmware to extract information (e.g. resource table) |
|---|
| 369 | + * @handle_rsc: optional platform hook to handle vendor resources. Should return |
|---|
| 370 | + * RSC_HANDLED if resource was handled, RSC_IGNORED if not handled and a |
|---|
| 371 | + * negative value on error |
|---|
| 335 | 372 | * @load_rsc_table: load resource table from firmware image |
|---|
| 336 | 373 | * @find_loaded_rsc_table: find the loaded resouce table |
|---|
| 337 | | - * @load: load firmeware to memory, where the remote processor |
|---|
| 374 | + * @load: load firmware to memory, where the remote processor |
|---|
| 338 | 375 | * expects to find it |
|---|
| 339 | 376 | * @sanity_check: sanity check the fw image |
|---|
| 340 | 377 | * @get_boot_addr: get boot address to entry point specified in firmware |
|---|
| 378 | + * @panic: optional callback to react to system panic, core will delay |
|---|
| 379 | + * panic at least the returned number of milliseconds |
|---|
| 380 | + * @coredump: collect firmware dump after the subsystem is shutdown |
|---|
| 341 | 381 | */ |
|---|
| 342 | 382 | struct rproc_ops { |
|---|
| 383 | + int (*prepare)(struct rproc *rproc); |
|---|
| 384 | + int (*unprepare)(struct rproc *rproc); |
|---|
| 343 | 385 | int (*start)(struct rproc *rproc); |
|---|
| 344 | 386 | int (*stop)(struct rproc *rproc); |
|---|
| 387 | + int (*attach)(struct rproc *rproc); |
|---|
| 345 | 388 | void (*kick)(struct rproc *rproc, int vqid); |
|---|
| 346 | | - void * (*da_to_va)(struct rproc *rproc, u64 da, int len); |
|---|
| 389 | + void * (*da_to_va)(struct rproc *rproc, u64 da, size_t len, bool *is_iomem); |
|---|
| 347 | 390 | int (*parse_fw)(struct rproc *rproc, const struct firmware *fw); |
|---|
| 391 | + int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc, |
|---|
| 392 | + int offset, int avail); |
|---|
| 348 | 393 | struct resource_table *(*find_loaded_rsc_table)( |
|---|
| 349 | 394 | struct rproc *rproc, const struct firmware *fw); |
|---|
| 350 | 395 | int (*load)(struct rproc *rproc, const struct firmware *fw); |
|---|
| 351 | 396 | int (*sanity_check)(struct rproc *rproc, const struct firmware *fw); |
|---|
| 352 | | - u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw); |
|---|
| 397 | + u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw); |
|---|
| 398 | + unsigned long (*panic)(struct rproc *rproc); |
|---|
| 399 | + void (*coredump)(struct rproc *rproc); |
|---|
| 353 | 400 | }; |
|---|
| 354 | 401 | |
|---|
| 355 | 402 | /** |
|---|
| .. | .. |
|---|
| 360 | 407 | * @RPROC_RUNNING: device is up and running |
|---|
| 361 | 408 | * @RPROC_CRASHED: device has crashed; need to start recovery |
|---|
| 362 | 409 | * @RPROC_DELETED: device is deleted |
|---|
| 410 | + * @RPROC_DETACHED: device has been booted by another entity and waiting |
|---|
| 411 | + * for the core to attach to it |
|---|
| 363 | 412 | * @RPROC_LAST: just keep this one at the end |
|---|
| 364 | 413 | * |
|---|
| 365 | 414 | * Please note that the values of these states are used as indices |
|---|
| .. | .. |
|---|
| 374 | 423 | RPROC_RUNNING = 2, |
|---|
| 375 | 424 | RPROC_CRASHED = 3, |
|---|
| 376 | 425 | RPROC_DELETED = 4, |
|---|
| 377 | | - RPROC_LAST = 5, |
|---|
| 426 | + RPROC_DETACHED = 5, |
|---|
| 427 | + RPROC_LAST = 6, |
|---|
| 378 | 428 | }; |
|---|
| 379 | 429 | |
|---|
| 380 | 430 | /** |
|---|
| .. | .. |
|---|
| 395 | 445 | }; |
|---|
| 396 | 446 | |
|---|
| 397 | 447 | /** |
|---|
| 448 | + * enum rproc_dump_mechanism - Coredump options for core |
|---|
| 449 | + * @RPROC_COREDUMP_DISABLED: Don't perform any dump |
|---|
| 450 | + * @RPROC_COREDUMP_ENABLED: Copy dump to separate buffer and carry on with |
|---|
| 451 | + recovery |
|---|
| 452 | + * @RPROC_COREDUMP_INLINE: Read segments directly from device memory. Stall |
|---|
| 453 | + recovery until all segments are read |
|---|
| 454 | + */ |
|---|
| 455 | +enum rproc_dump_mechanism { |
|---|
| 456 | + RPROC_COREDUMP_DISABLED, |
|---|
| 457 | + RPROC_COREDUMP_ENABLED, |
|---|
| 458 | + RPROC_COREDUMP_INLINE, |
|---|
| 459 | +}; |
|---|
| 460 | + |
|---|
| 461 | +/** |
|---|
| 398 | 462 | * struct rproc_dump_segment - segment info from ELF header |
|---|
| 399 | 463 | * @node: list node related to the rproc segment list |
|---|
| 400 | 464 | * @da: device address of the segment |
|---|
| 401 | 465 | * @size: size of the segment |
|---|
| 466 | + * @priv: private data associated with the dump_segment |
|---|
| 467 | + * @dump: custom dump function to fill device memory segment associated |
|---|
| 468 | + * with coredump |
|---|
| 402 | 469 | */ |
|---|
| 403 | 470 | struct rproc_dump_segment { |
|---|
| 404 | 471 | struct list_head node; |
|---|
| .. | .. |
|---|
| 406 | 473 | dma_addr_t da; |
|---|
| 407 | 474 | size_t size; |
|---|
| 408 | 475 | |
|---|
| 476 | + void *priv; |
|---|
| 477 | + void (*dump)(struct rproc *rproc, struct rproc_dump_segment *segment, |
|---|
| 478 | + void *dest, size_t offset, size_t size); |
|---|
| 409 | 479 | loff_t offset; |
|---|
| 410 | 480 | }; |
|---|
| 411 | 481 | |
|---|
| .. | .. |
|---|
| 420 | 490 | * @dev: virtual device for refcounting and common remoteproc behavior |
|---|
| 421 | 491 | * @power: refcount of users who need this rproc powered up |
|---|
| 422 | 492 | * @state: state of the device |
|---|
| 493 | + * @dump_conf: Currently selected coredump configuration |
|---|
| 423 | 494 | * @lock: lock which protects concurrent manipulations of the rproc |
|---|
| 424 | 495 | * @dbg_dir: debugfs directory of this rproc device |
|---|
| 425 | 496 | * @traces: list of trace buffers |
|---|
| .. | .. |
|---|
| 439 | 510 | * @cached_table: copy of the resource table |
|---|
| 440 | 511 | * @table_sz: size of @cached_table |
|---|
| 441 | 512 | * @has_iommu: flag to indicate if remote processor is behind an MMU |
|---|
| 513 | + * @auto_boot: flag to indicate if remote processor should be auto-started |
|---|
| 514 | + * @autonomous: true if an external entity has booted the remote processor |
|---|
| 442 | 515 | * @dump_segments: list of segments in the firmware |
|---|
| 516 | + * @nb_vdev: number of vdev currently handled by rproc |
|---|
| 517 | + * @char_dev: character device of the rproc |
|---|
| 518 | + * @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release |
|---|
| 443 | 519 | */ |
|---|
| 444 | 520 | struct rproc { |
|---|
| 445 | 521 | struct list_head node; |
|---|
| 446 | 522 | struct iommu_domain *domain; |
|---|
| 447 | 523 | const char *name; |
|---|
| 448 | | - char *firmware; |
|---|
| 524 | + const char *firmware; |
|---|
| 449 | 525 | void *priv; |
|---|
| 450 | 526 | struct rproc_ops *ops; |
|---|
| 451 | 527 | struct device dev; |
|---|
| 452 | 528 | atomic_t power; |
|---|
| 453 | 529 | unsigned int state; |
|---|
| 530 | + enum rproc_dump_mechanism dump_conf; |
|---|
| 454 | 531 | struct mutex lock; |
|---|
| 455 | 532 | struct dentry *dbg_dir; |
|---|
| 456 | 533 | struct list_head traces; |
|---|
| 457 | 534 | int num_traces; |
|---|
| 458 | 535 | struct list_head carveouts; |
|---|
| 459 | 536 | struct list_head mappings; |
|---|
| 460 | | - u32 bootaddr; |
|---|
| 537 | + u64 bootaddr; |
|---|
| 461 | 538 | struct list_head rvdevs; |
|---|
| 462 | 539 | struct list_head subdevs; |
|---|
| 463 | 540 | struct idr notifyids; |
|---|
| .. | .. |
|---|
| 471 | 548 | size_t table_sz; |
|---|
| 472 | 549 | bool has_iommu; |
|---|
| 473 | 550 | bool auto_boot; |
|---|
| 551 | + bool autonomous; |
|---|
| 474 | 552 | struct list_head dump_segments; |
|---|
| 553 | + int nb_vdev; |
|---|
| 554 | + u8 elf_class; |
|---|
| 555 | + u16 elf_machine; |
|---|
| 556 | + struct cdev cdev; |
|---|
| 557 | + bool cdev_put_on_release; |
|---|
| 475 | 558 | }; |
|---|
| 476 | 559 | |
|---|
| 477 | 560 | /** |
|---|
| .. | .. |
|---|
| 499 | 582 | /** |
|---|
| 500 | 583 | * struct rproc_vring - remoteproc vring state |
|---|
| 501 | 584 | * @va: virtual address |
|---|
| 502 | | - * @dma: dma address |
|---|
| 503 | 585 | * @len: length, in bytes |
|---|
| 504 | 586 | * @da: device address |
|---|
| 505 | 587 | * @align: vring alignment |
|---|
| .. | .. |
|---|
| 509 | 591 | */ |
|---|
| 510 | 592 | struct rproc_vring { |
|---|
| 511 | 593 | void *va; |
|---|
| 512 | | - dma_addr_t dma; |
|---|
| 513 | 594 | int len; |
|---|
| 514 | 595 | u32 da; |
|---|
| 515 | 596 | u32 align; |
|---|
| .. | .. |
|---|
| 528 | 609 | * @vdev: the virio device |
|---|
| 529 | 610 | * @vring: the vrings for this vdev |
|---|
| 530 | 611 | * @rsc_offset: offset of the vdev's resource entry |
|---|
| 612 | + * @index: vdev position versus other vdev declared in resource table |
|---|
| 531 | 613 | */ |
|---|
| 532 | 614 | struct rproc_vdev { |
|---|
| 533 | 615 | struct kref refcount; |
|---|
| 534 | 616 | |
|---|
| 535 | 617 | struct rproc_subdev subdev; |
|---|
| 618 | + struct device dev; |
|---|
| 536 | 619 | |
|---|
| 537 | 620 | unsigned int id; |
|---|
| 538 | 621 | struct list_head node; |
|---|
| 539 | 622 | struct rproc *rproc; |
|---|
| 540 | | - struct virtio_device vdev; |
|---|
| 541 | 623 | struct rproc_vring vring[RVDEV_NUM_VRINGS]; |
|---|
| 542 | 624 | u32 rsc_offset; |
|---|
| 625 | + u32 index; |
|---|
| 543 | 626 | }; |
|---|
| 544 | 627 | |
|---|
| 545 | 628 | struct rproc *rproc_get_by_phandle(phandle phandle); |
|---|
| .. | .. |
|---|
| 552 | 635 | int rproc_add(struct rproc *rproc); |
|---|
| 553 | 636 | int rproc_del(struct rproc *rproc); |
|---|
| 554 | 637 | void rproc_free(struct rproc *rproc); |
|---|
| 638 | +void rproc_resource_cleanup(struct rproc *rproc); |
|---|
| 639 | + |
|---|
| 640 | +struct rproc *devm_rproc_alloc(struct device *dev, const char *name, |
|---|
| 641 | + const struct rproc_ops *ops, |
|---|
| 642 | + const char *firmware, int len); |
|---|
| 643 | +int devm_rproc_add(struct device *dev, struct rproc *rproc); |
|---|
| 644 | + |
|---|
| 645 | +void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem); |
|---|
| 646 | + |
|---|
| 647 | +struct rproc_mem_entry * |
|---|
| 648 | +rproc_mem_entry_init(struct device *dev, |
|---|
| 649 | + void *va, dma_addr_t dma, size_t len, u32 da, |
|---|
| 650 | + int (*alloc)(struct rproc *, struct rproc_mem_entry *), |
|---|
| 651 | + int (*release)(struct rproc *, struct rproc_mem_entry *), |
|---|
| 652 | + const char *name, ...); |
|---|
| 653 | + |
|---|
| 654 | +struct rproc_mem_entry * |
|---|
| 655 | +rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len, |
|---|
| 656 | + u32 da, const char *name, ...); |
|---|
| 555 | 657 | |
|---|
| 556 | 658 | int rproc_boot(struct rproc *rproc); |
|---|
| 557 | 659 | void rproc_shutdown(struct rproc *rproc); |
|---|
| 660 | +int rproc_set_firmware(struct rproc *rproc, const char *fw_name); |
|---|
| 558 | 661 | void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type); |
|---|
| 662 | + |
|---|
| 663 | +/* from remoteproc_coredump.c */ |
|---|
| 664 | +void rproc_coredump_cleanup(struct rproc *rproc); |
|---|
| 665 | +void rproc_coredump(struct rproc *rproc); |
|---|
| 666 | +void rproc_coredump_using_sections(struct rproc *rproc); |
|---|
| 559 | 667 | int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size); |
|---|
| 668 | +int rproc_coredump_add_custom_segment(struct rproc *rproc, |
|---|
| 669 | + dma_addr_t da, size_t size, |
|---|
| 670 | + void (*dumpfn)(struct rproc *rproc, |
|---|
| 671 | + struct rproc_dump_segment *segment, |
|---|
| 672 | + void *dest, size_t offset, |
|---|
| 673 | + size_t size), |
|---|
| 674 | + void *priv); |
|---|
| 675 | +int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine); |
|---|
| 560 | 676 | |
|---|
| 561 | 677 | static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev) |
|---|
| 562 | 678 | { |
|---|
| 563 | | - return container_of(vdev, struct rproc_vdev, vdev); |
|---|
| 679 | + return container_of(vdev->dev.parent, struct rproc_vdev, dev); |
|---|
| 564 | 680 | } |
|---|
| 565 | 681 | |
|---|
| 566 | 682 | static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev) |
|---|