// SPDX-License-Identifier: GPL-2.0+ /* Copyright (C) 2022 AVM GmbH */ #define pr_fmt(fmt) "mrpc fwinfo client: " fmt #include #include #include "avm_fw_info.h" static char __avm_kernel_config_buf[2 * sizeof(struct _avm_kernel_config) + sizeof(struct avm_firmware_build_info)]; /* Define the base pointer used by the fwinfo logic */ struct _avm_kernel_config *__avm_kernel_config_start = (void *)__avm_kernel_config_buf; static void __init handover_fwinfo(const struct avm_firmware_build_info_be *bibe) { struct _avm_kernel_config *c = __avm_kernel_config_start; struct avm_firmware_build_info *bi; /* Build the kernel config array */ c[0] = (struct _avm_kernel_config) { .tag = avm_kernel_config_tags_version_info, .config = c + 2, /* Data follows this array */ }; c[1] = (struct _avm_kernel_config) { .tag = avm_kernel_config_tags_last, }; /* Fill in build info */ bi = c[0].config; strscpy(bi->buildnumber, bibe->buildnumber, sizeof(bi->buildnumber)); strscpy(bi->firmwarestring, bibe->firmwarestring, sizeof(bi->firmwarestring)); bi->buildtype = be32_to_cpu(bibe->buildtype); bi->builddirty = be32_to_cpu(bibe->builddirty); } static int __init avm_fw_info_pltfm_init(void) { struct avm_firmware_build_info_be build_info_be; struct mrpc_client *client; int ret, errcode; client = mrpc_client_register(MRPC_RESERVED_ID_AVM_FWINFO, "AVM fwinfo client"); if (!client) return -ENODEV; errcode = 0; ret = mrpc_call(client, MRPC_AVM_FWINFO_GET_BUILDINFO, NULL, 0, &build_info_be, sizeof(build_info_be), 0, &errcode); if (ret) { BUG_ON(ret == MRPC_ERR_MSG_TOO_BIG); pr_err("mrpc call failed: %d (errcode=%d)\n", ret, errcode); /* Don't pass on mrpc internal error codes */ if (ret > 0) ret = -EIO; goto out; } handover_fwinfo(&build_info_be); avm_fw_info_init(); out: /* We're done, there's no point in keeping the client around */ mrpc_client_unregister(client); return ret; } late_initcall(avm_fw_info_pltfm_init);