// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2023 AVM GmbH */ #define pr_fmt(fmt) "mrpc dtbo client: " fmt #include #include #include #include #include #include #include #include "avm_dtbo_mrpc.h" struct dtb_overlay { u8 *overlay; u32 size; }; #define MRPC_CALL_TIMEOUT 60000 /* defined in CONFIG_AVM_OF_OVERLAY_CMDLINE_MAX */ #define MAX_DT_OVERLAYS 8 static int __init mrpc_avm_client_get_dtbo(struct mrpc_client *client, struct dtb_overlay *dtbo, u32 index) { struct avm_dtbo_read_request request; struct avm_dtbo_read_reply reply; int ret, errcode; u32 offset = 0, len, data_len; request.dtbo_index = cpu_to_be32(index); len = AVM_MRPC_MAX_PAYLOAD; do { request.offset = cpu_to_be32(offset); request.len = cpu_to_be32(len); ret = mrpc_call(client, MRPC_AVM_DTBO_READ, &request, sizeof(request), &reply, sizeof(reply), MRPC_CALL_TIMEOUT, &errcode); if (ret) { pr_err("mrpc call failed. Errorcode: %i\n" "dtbo will not be loaded!\n", errcode); kfree(dtbo->overlay); return -EIO; } if (!dtbo->overlay) { dtbo->size = be32_to_cpu(reply.dtbo_size); dtbo->overlay = kmalloc(dtbo->size, GFP_KERNEL); if (dtbo->overlay == NULL) { pr_err("Could not allocate memory\n"); return -ENOMEM; } } data_len = be32_to_cpu(reply.data_len); memcpy(dtbo->overlay + offset, reply.data, data_len); offset += len; } while ((offset < dtbo->size) && (data_len != 0)); if (dtbo->size > 0) pr_info("Successfully read dtbo\n"); return 0; } static int __init avm_dtbo_client_init(void) { int ret = 0, i, ovcs_id; struct dtb_overlay dtbo; struct mrpc_client *client; client = mrpc_client_register(MRPC_RESERVED_ID_AVM_DTBO, "AVM dtbo client"); if (!client) return -ENODEV; for (i = 0; i < MAX_DT_OVERLAYS; i++) { dtbo.overlay = NULL; ret = mrpc_avm_client_get_dtbo(client, &dtbo, i); if (ret < 0 || dtbo.size == 0) break; ret = of_overlay_fdt_apply(dtbo.overlay, dtbo.size, &ovcs_id); if (ret < 0) { pr_err("Could not apply the DT overlay: %d\n", ret); kfree(dtbo.overlay); break; } kfree(dtbo.overlay); } mrpc_client_unregister(client); return ret; } late_initcall(avm_dtbo_client_init);