aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOhad Ben-Cohen <ohad@wizery.com>2013-04-07 07:06:07 -0400
committerOhad Ben-Cohen <ohad@wizery.com>2013-04-07 07:06:07 -0400
commita2b950ac7b1e6442919ee9e79c4963e134698869 (patch)
tree7ecec79d66796b06db5c9d79144d17e1bc496bad
parentba7290e01663787fcfc2bedaff6232359d4ff248 (diff)
remoteproc: perserve resource table data
Copy resource table from first to second firmware loading. After firmware is loaded to memory, update the vdevs resource pointer to the resource table kept in device memory. Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com> Acked-by: Ido Yariv <ido@wizery.com> [rebase, terminology and style changes] Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
-rw-r--r--drivers/remoteproc/Kconfig1
-rw-r--r--drivers/remoteproc/remoteproc_core.c98
-rw-r--r--include/linux/remoteproc.h9
3 files changed, 88 insertions, 20 deletions
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index cc1f7bf53fd0..289e867a77dd 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -4,6 +4,7 @@ menu "Remoteproc drivers"
4config REMOTEPROC 4config REMOTEPROC
5 tristate 5 tristate
6 depends on HAS_DMA 6 depends on HAS_DMA
7 select CRC32
7 select FW_CONFIG 8 select FW_CONFIG
8 select VIRTIO 9 select VIRTIO
9 10
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 9d2a4ac6c706..617b825aa553 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -37,6 +37,7 @@
37#include <linux/iommu.h> 37#include <linux/iommu.h>
38#include <linux/idr.h> 38#include <linux/idr.h>
39#include <linux/elf.h> 39#include <linux/elf.h>
40#include <linux/crc32.h>
40#include <linux/virtio_ids.h> 41#include <linux/virtio_ids.h>
41#include <linux/virtio_ring.h> 42#include <linux/virtio_ring.h>
42#include <asm/byteorder.h> 43#include <asm/byteorder.h>
@@ -45,7 +46,8 @@
45 46
46typedef int (*rproc_handle_resources_t)(struct rproc *rproc, 47typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
47 struct resource_table *table, int len); 48 struct resource_table *table, int len);
48typedef int (*rproc_handle_resource_t)(struct rproc *rproc, void *, int avail); 49typedef int (*rproc_handle_resource_t)(struct rproc *rproc,
50 void *, int offset, int avail);
49 51
50/* Unique indices for remoteproc devices */ 52/* Unique indices for remoteproc devices */
51static DEFINE_IDA(rproc_dev_index); 53static DEFINE_IDA(rproc_dev_index);
@@ -302,7 +304,7 @@ void rproc_free_vring(struct rproc_vring *rvring)
302 * Returns 0 on success, or an appropriate error code otherwise 304 * Returns 0 on success, or an appropriate error code otherwise
303 */ 305 */
304static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, 306static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
305 int avail) 307 int offset, int avail)
306{ 308{
307 struct device *dev = &rproc->dev; 309 struct device *dev = &rproc->dev;
308 struct rproc_vdev *rvdev; 310 struct rproc_vdev *rvdev;
@@ -346,6 +348,9 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
346 /* remember the device features */ 348 /* remember the device features */
347 rvdev->dfeatures = rsc->dfeatures; 349 rvdev->dfeatures = rsc->dfeatures;
348 350
351 /* remember the resource offset*/
352 rvdev->rsc_offset = offset;
353
349 list_add_tail(&rvdev->node, &rproc->rvdevs); 354 list_add_tail(&rvdev->node, &rproc->rvdevs);
350 355
351 /* it is now safe to add the virtio device */ 356 /* it is now safe to add the virtio device */
@@ -377,7 +382,7 @@ free_rvdev:
377 * Returns 0 on success, or an appropriate error code otherwise 382 * Returns 0 on success, or an appropriate error code otherwise
378 */ 383 */
379static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc, 384static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
380 int avail) 385 int offset, int avail)
381{ 386{
382 struct rproc_mem_entry *trace; 387 struct rproc_mem_entry *trace;
383 struct device *dev = &rproc->dev; 388 struct device *dev = &rproc->dev;
@@ -459,7 +464,7 @@ static int rproc_handle_trace(struct rproc *rproc, struct fw_rsc_trace *rsc,
459 * are outside those ranges. 464 * are outside those ranges.
460 */ 465 */
461static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc, 466static int rproc_handle_devmem(struct rproc *rproc, struct fw_rsc_devmem *rsc,
462 int avail) 467 int offset, int avail)
463{ 468{
464 struct rproc_mem_entry *mapping; 469 struct rproc_mem_entry *mapping;
465 struct device *dev = &rproc->dev; 470 struct device *dev = &rproc->dev;
@@ -532,7 +537,9 @@ out:
532 * pressure is important; it may have a substantial impact on performance. 537 * pressure is important; it may have a substantial impact on performance.
533 */ 538 */
534static int rproc_handle_carveout(struct rproc *rproc, 539static int rproc_handle_carveout(struct rproc *rproc,
535 struct fw_rsc_carveout *rsc, int avail) 540 struct fw_rsc_carveout *rsc,
541 int offset, int avail)
542
536{ 543{
537 struct rproc_mem_entry *carveout, *mapping; 544 struct rproc_mem_entry *carveout, *mapping;
538 struct device *dev = &rproc->dev; 545 struct device *dev = &rproc->dev;
@@ -655,7 +662,7 @@ free_carv:
655} 662}
656 663
657static int rproc_count_vrings(struct rproc *rproc, struct fw_rsc_vdev *rsc, 664static int rproc_count_vrings(struct rproc *rproc, struct fw_rsc_vdev *rsc,
658 int avail) 665 int offset, int avail)
659{ 666{
660 /* Summarize the number of notification IDs */ 667 /* Summarize the number of notification IDs */
661 rproc->max_notifyid += rsc->num_of_vrings; 668 rproc->max_notifyid += rsc->num_of_vrings;
@@ -683,17 +690,16 @@ static rproc_handle_resource_t rproc_count_vrings_handler[RSC_LAST] = {
683}; 690};
684 691
685/* handle firmware resource entries before booting the remote processor */ 692/* handle firmware resource entries before booting the remote processor */
686static int rproc_handle_resources(struct rproc *rproc, 693static int rproc_handle_resources(struct rproc *rproc, int len,
687 struct resource_table *table, int len,
688 rproc_handle_resource_t handlers[RSC_LAST]) 694 rproc_handle_resource_t handlers[RSC_LAST])
689{ 695{
690 struct device *dev = &rproc->dev; 696 struct device *dev = &rproc->dev;
691 rproc_handle_resource_t handler; 697 rproc_handle_resource_t handler;
692 int ret = 0, i; 698 int ret = 0, i;
693 699
694 for (i = 0; i < table->num; i++) { 700 for (i = 0; i < rproc->table_ptr->num; i++) {
695 int offset = table->offset[i]; 701 int offset = rproc->table_ptr->offset[i];
696 struct fw_rsc_hdr *hdr = (void *)table + offset; 702 struct fw_rsc_hdr *hdr = (void *)rproc->table_ptr + offset;
697 int avail = len - offset - sizeof(*hdr); 703 int avail = len - offset - sizeof(*hdr);
698 void *rsc = (void *)hdr + sizeof(*hdr); 704 void *rsc = (void *)hdr + sizeof(*hdr);
699 705
@@ -714,7 +720,7 @@ static int rproc_handle_resources(struct rproc *rproc,
714 if (!handler) 720 if (!handler)
715 continue; 721 continue;
716 722
717 ret = handler(rproc, rsc, avail); 723 ret = handler(rproc, rsc, offset + sizeof(*hdr), avail);
718 if (ret) 724 if (ret)
719 break; 725 break;
720 } 726 }
@@ -772,9 +778,12 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
772{ 778{
773 struct device *dev = &rproc->dev; 779 struct device *dev = &rproc->dev;
774 const char *name = rproc->firmware; 780 const char *name = rproc->firmware;
775 struct resource_table *table; 781 struct resource_table *table, *loaded_table;
776 int ret, tablesz; 782 int ret, tablesz;
777 783
784 if (!rproc->table_ptr)
785 return -ENOMEM;
786
778 ret = rproc_fw_sanity_check(rproc, fw); 787 ret = rproc_fw_sanity_check(rproc, fw);
779 if (ret) 788 if (ret)
780 return ret; 789 return ret;
@@ -800,9 +809,15 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
800 goto clean_up; 809 goto clean_up;
801 } 810 }
802 811
812 /* Verify that resource table in loaded fw is unchanged */
813 if (rproc->table_csum != crc32(0, table, tablesz)) {
814 dev_err(dev, "resource checksum failed, fw changed?\n");
815 ret = -EINVAL;
816 goto clean_up;
817 }
818
803 /* handle fw resources which are required to boot rproc */ 819 /* handle fw resources which are required to boot rproc */
804 ret = rproc_handle_resources(rproc, table, tablesz, 820 ret = rproc_handle_resources(rproc, tablesz, rproc_loading_handlers);
805 rproc_loading_handlers);
806 if (ret) { 821 if (ret) {
807 dev_err(dev, "Failed to process resources: %d\n", ret); 822 dev_err(dev, "Failed to process resources: %d\n", ret);
808 goto clean_up; 823 goto clean_up;
@@ -815,6 +830,19 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
815 goto clean_up; 830 goto clean_up;
816 } 831 }
817 832
833 /*
834 * The starting device has been given the rproc->cached_table as the
835 * resource table. The address of the vring along with the other
836 * allocated resources (carveouts etc) is stored in cached_table.
837 * In order to pass this information to the remote device we must
838 * copy this information to device memory.
839 */
840 loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
841 if (!loaded_table)
842 goto clean_up;
843
844 memcpy(loaded_table, rproc->cached_table, tablesz);
845
818 /* power up the remote processor */ 846 /* power up the remote processor */
819 ret = rproc->ops->start(rproc); 847 ret = rproc->ops->start(rproc);
820 if (ret) { 848 if (ret) {
@@ -822,6 +850,13 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
822 goto clean_up; 850 goto clean_up;
823 } 851 }
824 852
853 /*
854 * Update table_ptr so that all subsequent vring allocations and
855 * virtio fields manipulation update the actual loaded resource table
856 * in device memory.
857 */
858 rproc->table_ptr = loaded_table;
859
825 rproc->state = RPROC_RUNNING; 860 rproc->state = RPROC_RUNNING;
826 861
827 dev_info(dev, "remote processor %s is now up\n", rproc->name); 862 dev_info(dev, "remote processor %s is now up\n", rproc->name);
@@ -856,16 +891,30 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
856 if (!table) 891 if (!table)
857 goto out; 892 goto out;
858 893
894 rproc->table_csum = crc32(0, table, tablesz);
895
896 /*
897 * Create a copy of the resource table. When a virtio device starts
898 * and calls vring_new_virtqueue() the address of the allocated vring
899 * will be stored in the cached_table. Before the device is started,
900 * cached_table will be copied into devic memory.
901 */
902 rproc->cached_table = kmalloc(tablesz, GFP_KERNEL);
903 if (!rproc->cached_table)
904 goto out;
905
906 memcpy(rproc->cached_table, table, tablesz);
907 rproc->table_ptr = rproc->cached_table;
908
859 /* count the number of notify-ids */ 909 /* count the number of notify-ids */
860 rproc->max_notifyid = -1; 910 rproc->max_notifyid = -1;
861 ret = rproc_handle_resources(rproc, table, tablesz, 911 ret = rproc_handle_resources(rproc, tablesz, rproc_count_vrings_handler);
862 rproc_count_vrings_handler);
863
864 /* look for virtio devices and register them */
865 ret = rproc_handle_resources(rproc, table, tablesz, rproc_vdev_handler);
866 if (ret) 912 if (ret)
867 goto out; 913 goto out;
868 914
915 /* look for virtio devices and register them */
916 ret = rproc_handle_resources(rproc, tablesz, rproc_vdev_handler);
917
869out: 918out:
870 release_firmware(fw); 919 release_firmware(fw);
871 /* allow rproc_del() contexts, if any, to proceed */ 920 /* allow rproc_del() contexts, if any, to proceed */
@@ -923,6 +972,9 @@ int rproc_trigger_recovery(struct rproc *rproc)
923 /* wait until there is no more rproc users */ 972 /* wait until there is no more rproc users */
924 wait_for_completion(&rproc->crash_comp); 973 wait_for_completion(&rproc->crash_comp);
925 974
975 /* Free the copy of the resource table */
976 kfree(rproc->cached_table);
977
926 return rproc_add_virtio_devices(rproc); 978 return rproc_add_virtio_devices(rproc);
927} 979}
928 980
@@ -1078,6 +1130,9 @@ void rproc_shutdown(struct rproc *rproc)
1078 1130
1079 rproc_disable_iommu(rproc); 1131 rproc_disable_iommu(rproc);
1080 1132
1133 /* Give the next start a clean resource table */
1134 rproc->table_ptr = rproc->cached_table;
1135
1081 /* if in crash state, unlock crash handler */ 1136 /* if in crash state, unlock crash handler */
1082 if (rproc->state == RPROC_CRASHED) 1137 if (rproc->state == RPROC_CRASHED)
1083 complete_all(&rproc->crash_comp); 1138 complete_all(&rproc->crash_comp);
@@ -1288,6 +1343,9 @@ int rproc_del(struct rproc *rproc)
1288 list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node) 1343 list_for_each_entry_safe(rvdev, tmp, &rproc->rvdevs, node)
1289 rproc_remove_virtio_dev(rvdev); 1344 rproc_remove_virtio_dev(rvdev);
1290 1345
1346 /* Free the copy of the resource table */
1347 kfree(rproc->cached_table);
1348
1291 device_del(&rproc->dev); 1349 device_del(&rproc->dev);
1292 1350
1293 return 0; 1351 return 0;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index faf33324c78f..b4cef16460f8 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -401,6 +401,9 @@ enum rproc_crash_type {
401 * @crash_comp: completion used to sync crash handler and the rproc reload 401 * @crash_comp: completion used to sync crash handler and the rproc reload
402 * @recovery_disabled: flag that state if recovery was disabled 402 * @recovery_disabled: flag that state if recovery was disabled
403 * @max_notifyid: largest allocated notify id. 403 * @max_notifyid: largest allocated notify id.
404 * @table_ptr: pointer to the resource table in effect
405 * @cached_table: copy of the resource table
406 * @table_csum: checksum of the resource table
404 */ 407 */
405struct rproc { 408struct rproc {
406 struct klist_node node; 409 struct klist_node node;
@@ -429,9 +432,13 @@ struct rproc {
429 struct completion crash_comp; 432 struct completion crash_comp;
430 bool recovery_disabled; 433 bool recovery_disabled;
431 int max_notifyid; 434 int max_notifyid;
435 struct resource_table *table_ptr;
436 struct resource_table *cached_table;
437 u32 table_csum;
432}; 438};
433 439
434/* we currently support only two vrings per rvdev */ 440/* we currently support only two vrings per rvdev */
441
435#define RVDEV_NUM_VRINGS 2 442#define RVDEV_NUM_VRINGS 2
436 443
437/** 444/**
@@ -464,6 +471,7 @@ struct rproc_vring {
464 * @vring: the vrings for this vdev 471 * @vring: the vrings for this vdev
465 * @dfeatures: virtio device features 472 * @dfeatures: virtio device features
466 * @gfeatures: virtio guest features 473 * @gfeatures: virtio guest features
474 * @rsc_offset: offset of the vdev's resource entry
467 */ 475 */
468struct rproc_vdev { 476struct rproc_vdev {
469 struct list_head node; 477 struct list_head node;
@@ -472,6 +480,7 @@ struct rproc_vdev {
472 struct rproc_vring vring[RVDEV_NUM_VRINGS]; 480 struct rproc_vring vring[RVDEV_NUM_VRINGS];
473 unsigned long dfeatures; 481 unsigned long dfeatures;
474 unsigned long gfeatures; 482 unsigned long gfeatures;
483 u32 rsc_offset;
475}; 484};
476 485
477struct rproc *rproc_alloc(struct device *dev, const char *name, 486struct rproc *rproc_alloc(struct device *dev, const char *name,