From 3ea97358bbe4301ab1c0c0035aaa6e6a649a94f4 Mon Sep 17 00:00:00 2001 From: std Date: Tue, 13 May 2025 13:08:27 +0530 Subject: [PATCH] virt oops: Establish IVC channel on LCPU-2 The IVC channel establishment has to be done on LCPU-2 to avoid timeouts during boot. Jira SSV-13035 Signed-off-by: Sanjith T D Change-Id: Ib647c318621a1b4435909d8a76f25f341bdb2c95 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3366612 Reviewed-by: Sreenivas Velpula GVS: buildbot_gerritrpt Reviewed-by: svcacv Reviewed-by: Vipin Kumar --- .../tegra_hv_vblk_oops.c | 47 +++++++++++++++---- .../tegra_oops_virt_storage/tegra_vblk_oops.h | 6 ++- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/drivers/block/tegra_oops_virt_storage/tegra_hv_vblk_oops.c b/drivers/block/tegra_oops_virt_storage/tegra_hv_vblk_oops.c index 170f7f43..4041bb39 100644 --- a/drivers/block/tegra_oops_virt_storage/tegra_hv_vblk_oops.c +++ b/drivers/block/tegra_oops_virt_storage/tegra_hv_vblk_oops.c @@ -181,7 +181,8 @@ static ssize_t vblk_oops_read(char *buf, size_t bytes, loff_t pos) */ if (in_atomic()) { dev_warn(vblkdev_oops->device, - "%s invoked in atomic context..aborting\n", __func__); + "%s invoked in atomic context..returning EBUSY to retry from workqueue\n", + __func__); return -EBUSY; } @@ -768,6 +769,7 @@ static int vblk_oops_get_configinfo(struct vblk_dev *vblkdev) } memset(vblkdev->ufs_buf, 0, PAGE_SIZE << (get_order(vblkdev_oops->pstore_kmsg_size))); + vblkdev->ufs_iova = dma_map_single(vblkdev->device, vblkdev->ufs_buf, vblkdev_oops->pstore_kmsg_size, DMA_BIDIRECTIONAL); if (dma_mapping_error(vblkdev->device, vblkdev->ufs_iova)) { @@ -822,8 +824,10 @@ static void vblk_oops_init_device(struct work_struct *ws) if (tegra_hv_ivc_channel_notified(vblkdev->ivck) != 0) { dev_warn(vblkdev->device, "%s: IVC channel reset not complete...retry\n", __func__); - schedule_delayed_work(&vblkdev->init, - msecs_to_jiffies(VSC_RESPONSE_WAIT_MS)); + schedule_delayed_work_on(((vblkdev->is_cpu_bound == false) ? DEFAULT_INIT_VCPU : + vblkdev_oops->schedulable_vcpu_number), + &vblkdev_oops->init, + msecs_to_jiffies(VSC_RESPONSE_WAIT_MS)); return; } @@ -877,6 +881,8 @@ static int tegra_hv_vblk_oops_probe(struct platform_device *pdev) static struct device_node *vblk_node; struct device *dev = &pdev->dev; int ret; + struct device_node *schedulable_vcpu_number_node; + bool is_cpu_bound = true; if (!is_tegra_hypervisor_mode()) { dev_err(dev, "Hypervisor is not present\n"); @@ -937,6 +943,30 @@ static int tegra_hv_vblk_oops_probe(struct platform_device *pdev) /* defer alignment and minimum size check for later */ } + schedulable_vcpu_number_node = of_find_node_by_name(NULL, + "virt-storage-request-submit-cpu-mapping"); + /* read lcpu_affinity from dts */ + if (schedulable_vcpu_number_node == NULL) { + dev_err(dev, "%s: virt-storage-request-submit-cpu-mapping DT not found\n", + __func__); + is_cpu_bound = false; + } else if (of_property_read_u32(schedulable_vcpu_number_node, "lcpu2tovcpu", + &(vblkdev_oops->schedulable_vcpu_number)) != 0) { + dev_err(dev, "%s: lcpu2tovcpu affinity is not found\n", __func__); + is_cpu_bound = false; + } + if (vblkdev_oops->schedulable_vcpu_number >= num_online_cpus()) { + dev_err(dev, "%s: cpu affinity (%d) > online cpus (%d)\n", __func__, + vblkdev_oops->schedulable_vcpu_number, num_online_cpus()); + is_cpu_bound = false; + } + if (false == is_cpu_bound) { + dev_err(dev, "%s: WARN: CPU is unbound\n", __func__); + vblkdev_oops->schedulable_vcpu_number = num_possible_cpus(); + } + + vblkdev_oops->is_cpu_bound = is_cpu_bound; + vblkdev_oops->ivck = tegra_hv_ivc_reserve(NULL, vblkdev_oops->ivc_id, NULL); if (IS_ERR_OR_NULL(vblkdev_oops->ivck)) { dev_err(dev, "Failed to reserve IVC channel %d\n", @@ -958,7 +988,8 @@ static int tegra_hv_vblk_oops_probe(struct platform_device *pdev) } /* postpone init work that needs response */ - schedule_delayed_work(&vblkdev_oops->init, + schedule_delayed_work_on(((is_cpu_bound == false) ? DEFAULT_INIT_VCPU : + vblkdev_oops->schedulable_vcpu_number), &vblkdev_oops->init, msecs_to_jiffies(VSC_RESPONSE_WAIT_MS)); return 0; @@ -991,7 +1022,7 @@ static int tegra_hv_vblk_oops_remove(struct platform_device *pdev) /** * @brief Suspend the OOPS storage device * - * Resets the IVC channel during system suspend. + * No Operation is done during system suspend. * * @param[in] dev Device structure pointer * @return 0 on success @@ -1012,11 +1043,7 @@ static int tegra_hv_vblk_oops_remove(struct platform_device *pdev) */ static int tegra_hv_vblk_oops_suspend(struct device *dev) { - /* Reset the channel */ - mutex_lock(&vblkdev_oops->ivc_lock); - tegra_hv_ivc_channel_reset(vblkdev_oops->ivck); - mutex_unlock(&vblkdev_oops->ivc_lock); - + /* No Op */ return 0; } diff --git a/drivers/block/tegra_oops_virt_storage/tegra_vblk_oops.h b/drivers/block/tegra_oops_virt_storage/tegra_vblk_oops.h index 699c537c..83a31dfb 100644 --- a/drivers/block/tegra_oops_virt_storage/tegra_vblk_oops.h +++ b/drivers/block/tegra_oops_virt_storage/tegra_vblk_oops.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ #ifndef _TEGRA_VBLK_H_ @@ -31,6 +31,8 @@ /* PSTORE defaults */ #define PSTORE_KMSG_RECORD_SIZE (64*1024) +/* Default VCPU to run the init work */ +#define DEFAULT_INIT_VCPU (0U) struct vsc_request { struct vs_request vs_req; @@ -71,6 +73,8 @@ struct vblk_dev { bool use_vm_address; /* whether it's on UFS */ void *ufs_buf; /* buffer used for UFS DMA, size equals pstore_kmsg_size */ dma_addr_t ufs_iova; /* IOVA of ufs_buf */ + uint32_t schedulable_vcpu_number; + bool is_cpu_bound; }; #endif