diff --git a/drivers/block/tegra_virt_storage/Makefile b/drivers/block/tegra_virt_storage/Makefile index e2eb9184..e4eae6a7 100644 --- a/drivers/block/tegra_virt_storage/Makefile +++ b/drivers/block/tegra_virt_storage/Makefile @@ -1,21 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only -# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # # Makefile for Virtual Storage Driver # - -LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL)) -LINUX_VERSION_6_11 := $(shell expr 6 \* 256 + 11) - -# Use dummy driver for Kernel versions greater than or equal to Linux v6.11 -ifeq ($(shell test $(LINUX_VERSION) -ge $(LINUX_VERSION_6_11); echo $$?),0) -tegra_vblk-y += tegra_hv_vblk_dummy.o -else tegra_vblk-y += tegra_hv_vblk.o tegra_vblk-y += tegra_hv_ioctl.o tegra_vblk-y += tegra_hv_mmc.o tegra_vblk-y += tegra_hv_scsi.o tegra_vblk-y += tegra_hv_ufs.o -endif obj-m += tegra_vblk.o diff --git a/drivers/block/tegra_virt_storage/tegra_hv_vblk.c b/drivers/block/tegra_virt_storage/tegra_hv_vblk.c index ff5b415e..ee5fd8d8 100644 --- a/drivers/block/tegra_virt_storage/tegra_hv_vblk.c +++ b/drivers/block/tegra_virt_storage/tegra_hv_vblk.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -35,11 +34,17 @@ #include #include #include +#include #if (IS_ENABLED(CONFIG_TEGRA_HSIERRRPTINJ)) #include #endif #include "tegra_vblk.h" +#if defined(NV_QUEUE_LIMITS_STRUCT_HAS_FEATURES) \ + && (NV_IS_EXPORT_SYMBOL_PRESENT_queue_limits_set == 1) +#define NV_BLOCK_USE_QUEUE_LIMITS_SET +#endif + #define DISCARD_ERASE_SECERASE_MASK (VS_BLK_DISCARD_OP_F | \ VS_BLK_SECURE_ERASE_OP_F | \ VS_BLK_ERASE_OP_F) @@ -1103,14 +1108,18 @@ static void setup_ioctl_device(struct vblk_dev *vblkdev) { int ret; +#if defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) + struct queue_limits limits; +#endif memset(&vblkdev->ioctl_tag_set, 0, sizeof(vblkdev->tag_set)); vblkdev->ioctl_tag_set.ops = &vblk_mq_ops; vblkdev->ioctl_tag_set.nr_hw_queues = 1; vblkdev->ioctl_tag_set.nr_maps = 1; vblkdev->ioctl_tag_set.queue_depth = 16; vblkdev->ioctl_tag_set.numa_node = NUMA_NO_NODE; +#if defined(NV_BLK_MQ_F_SHOULD_MERGE) /* Linux 6.14 */ vblkdev->ioctl_tag_set.flags = BLK_MQ_F_SHOULD_MERGE; - +#endif ret = blk_mq_alloc_tag_set(&vblkdev->ioctl_tag_set); if (ret) { dev_err(vblkdev->device, "failed to allocate tag set\n"); @@ -1130,12 +1139,24 @@ static void setup_ioctl_device(struct vblk_dev *vblkdev) vblkdev->ioctl_queue->queuedata = vblkdev; +#if defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) + limits.physical_block_size = vblkdev->config.blk_config.hardblk_size; + limits.logical_block_size = vblkdev->config.blk_config.hardblk_size; + limits.io_min = vblkdev->config.blk_config.hardblk_size; + limits.io_opt = vblkdev->config.blk_config.hardblk_size; + + if (queue_limits_set(vblkdev->ioctl_queue, &limits) != 0) { + dev_err(vblkdev->device, "failed to set queue limits\n"); + blk_mq_free_tag_set(&vblkdev->ioctl_tag_set); + return; + } +#else blk_queue_logical_block_size(vblkdev->ioctl_queue, vblkdev->config.blk_config.hardblk_size); blk_queue_physical_block_size(vblkdev->ioctl_queue, vblkdev->config.blk_config.hardblk_size); - blk_queue_flag_set(QUEUE_FLAG_NONROT, vblkdev->ioctl_queue); +#endif /* And the gendisk structure. */ #if defined(NV_BLK_MQ_ALLOC_DISK_FOR_QUEUE_PRESENT) /* Linux v6.0 */ @@ -1179,6 +1200,10 @@ static void setup_ioctl_device(struct vblk_dev *vblkdev) /* Set up virtual device. */ static void setup_device(struct vblk_dev *vblkdev) { + +#if defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) + struct queue_limits limits; +#endif uint32_t max_io_bytes; uint32_t req_id; uint32_t max_requests; @@ -1200,8 +1225,9 @@ static void setup_device(struct vblk_dev *vblkdev) vblkdev->tag_set.nr_maps = 1; vblkdev->tag_set.queue_depth = 16; vblkdev->tag_set.numa_node = NUMA_NO_NODE; +#if defined(NV_BLK_MQ_F_SHOULD_MERGE) /* Linux 6.14 */ vblkdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; - +#endif ret = blk_mq_alloc_tag_set(&vblkdev->tag_set); if (ret) return; @@ -1219,13 +1245,26 @@ static void setup_device(struct vblk_dev *vblkdev) vblkdev->queue->queuedata = vblkdev; +#if defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) + limits.physical_block_size = vblkdev->config.blk_config.hardblk_size; + limits.logical_block_size = vblkdev->config.blk_config.hardblk_size; + limits.io_min = vblkdev->config.blk_config.hardblk_size; + limits.io_opt = vblkdev->config.blk_config.hardblk_size; +#else blk_queue_logical_block_size(vblkdev->queue, vblkdev->config.blk_config.hardblk_size); blk_queue_physical_block_size(vblkdev->queue, vblkdev->config.blk_config.hardblk_size); +#endif if (vblkdev->config.blk_config.req_ops_supported & VS_BLK_FLUSH_OP_F) { +#if defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) + limits.features |= (BLK_FEAT_WRITE_CACHE & + !(BLK_FLAG_WRITE_CACHE_DISABLED) & + !(BLK_FEAT_FUA)); +#else blk_queue_write_cache(vblkdev->queue, true, false); +#endif } if (vblkdev->config.blk_config.max_read_blks_per_io != @@ -1244,6 +1283,60 @@ static void setup_device(struct vblk_dev *vblkdev) return; } +#if defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) && defined(NV_BLK_QUEUE_MAX_HW_SECTORS_PRESENT) + limits.max_hw_sectors = max_io_bytes / SECTOR_SIZE; +#elif defined(NV_BLK_QUEUE_MAX_HW_SECTORS_PRESENT) /* Removed in Linux v6.10 */ + blk_queue_max_hw_sectors(vblkdev->queue, max_io_bytes / SECTOR_SIZE); +#endif + + if ((vblkdev->config.blk_config.req_ops_supported & VS_BLK_SECURE_ERASE_OP_F) + || (vblkdev->config.blk_config.req_ops_supported & VS_BLK_ERASE_OP_F)) { +#if defined(QUEUE_FLAG_SECERASE) /* Removed in Linux 5.19 */ + /* + * FIXME: Support for Linux v5.19+ kernels + */ + blk_queue_flag_set(QUEUE_FLAG_SECERASE, vblkdev->queue); +#elif defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) + limits.max_secure_erase_sectors = vblkdev->config.blk_config.max_erase_blks_per_io; +#else + blk_queue_max_secure_erase_sectors(vblkdev->queue, + vblkdev->config.blk_config.max_erase_blks_per_io); +#endif + } + + if ((vblkdev->config.blk_config.req_ops_supported & VS_BLK_DISCARD_OP_F) + || (((vblkdev->config.blk_config.req_ops_supported & VS_BLK_SECURE_ERASE_OP_F) + || (vblkdev->config.blk_config.req_ops_supported & VS_BLK_ERASE_OP_F)) + && vblkdev->config.phys_dev == VSC_DEV_UFS)) { +#if defined(QUEUE_FLAG_DISCARD) /* Removed in Linux v5.19 */ + /* + * FIXME: Support for Linux v5.19+ kernels + */ + blk_queue_flag_set(QUEUE_FLAG_DISCARD, vblkdev->queue); +#endif +#if defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) + limits.max_discard_segments = vblkdev->config.blk_config.max_erase_blks_per_io; + limits.discard_granularity = vblkdev->config.blk_config.hardblk_size; +#else + blk_queue_max_discard_sectors(vblkdev->queue, + vblkdev->config.blk_config.max_erase_blks_per_io); + vblkdev->queue->limits.discard_granularity = + vblkdev->config.blk_config.hardblk_size; +#endif + print_erase_op_supported(vblkdev->device, + vblkdev->config.blk_config.req_ops_supported); + + } +#if defined(NV_BLOCK_USE_QUEUE_LIMITS_SET) + if (queue_limits_set(vblkdev->queue, &limits) != 0) { + dev_err(vblkdev->device, "failed to set queue limits\n"); + blk_mq_free_tag_set(&vblkdev->tag_set); + return; + } +#else + blk_queue_flag_set(QUEUE_FLAG_NONROT, vblkdev->queue); +#endif + /* reserve mempool for eMMC device and for ufs device * with pass through support */ @@ -1394,40 +1487,6 @@ static void setup_device(struct vblk_dev *vblkdev) vblkdev->max_requests = max_requests; vblkdev->max_ioctl_requests = max_ioctl_requests; -#if defined(NV_BLK_QUEUE_MAX_HW_SECTORS_PRESENT) /* Removed in Linux v6.10 */ - blk_queue_max_hw_sectors(vblkdev->queue, max_io_bytes / SECTOR_SIZE); -#endif - blk_queue_flag_set(QUEUE_FLAG_NONROT, vblkdev->queue); - - if ((vblkdev->config.blk_config.req_ops_supported & VS_BLK_SECURE_ERASE_OP_F) - || (vblkdev->config.blk_config.req_ops_supported & VS_BLK_ERASE_OP_F)) -#if defined(QUEUE_FLAG_SECERASE) /* Removed in Linux 5.19 */ - /* - * FIXME: Support for Linux v5.19+ kernels - */ - blk_queue_flag_set(QUEUE_FLAG_SECERASE, vblkdev->queue); -#else - blk_queue_max_secure_erase_sectors(vblkdev->queue, - vblkdev->config.blk_config.max_erase_blks_per_io); -#endif - - if ((vblkdev->config.blk_config.req_ops_supported & VS_BLK_DISCARD_OP_F) - || (((vblkdev->config.blk_config.req_ops_supported & VS_BLK_SECURE_ERASE_OP_F) - || (vblkdev->config.blk_config.req_ops_supported & VS_BLK_ERASE_OP_F)) - && vblkdev->config.phys_dev == VSC_DEV_UFS)) { -#if defined(QUEUE_FLAG_DISCARD) /* Removed in Linux v5.19 */ - /* - * FIXME: Support for Linux v5.19+ kernels - */ - blk_queue_flag_set(QUEUE_FLAG_DISCARD, vblkdev->queue); -#endif - blk_queue_max_discard_sectors(vblkdev->queue, - vblkdev->config.blk_config.max_erase_blks_per_io); - vblkdev->queue->limits.discard_granularity = - vblkdev->config.blk_config.hardblk_size; - print_erase_op_supported(vblkdev->device, - vblkdev->config.blk_config.req_ops_supported); - } /* And the gendisk structure. */ #if defined(NV_BLK_MQ_ALLOC_DISK_FOR_QUEUE_PRESENT) /* Linux v6.0 */ diff --git a/scripts/conftest/Makefile b/scripts/conftest/Makefile index 045cb451..34bc81f9 100644 --- a/scripts/conftest/Makefile +++ b/scripts/conftest/Makefile @@ -100,6 +100,8 @@ NV_CONFTEST_FUNCTION_COMPILE_TESTS += blk_mq_destroy_queue NV_CONFTEST_FUNCTION_COMPILE_TESTS += blk_queue_max_hw_sectors NV_CONFTEST_FUNCTION_COMPILE_TESTS += block_device_operations_open_has_gendisk_arg NV_CONFTEST_FUNCTION_COMPILE_TESTS += block_device_operations_release_has_no_mode_arg +NV_CONFTEST_FUNCTION_COMPILE_TESTS += queue_limits_struct_has_features +NV_CONFTEST_FUNCTION_COMPILE_TESTS += blk_mq_f_should_merge NV_CONFTEST_FUNCTION_COMPILE_TESTS += bus_type_struct_match_has_const_drv_arg NV_CONFTEST_FUNCTION_COMPILE_TESTS += bus_type_struct_remove_has_int_return_type NV_CONFTEST_FUNCTION_COMPILE_TESTS += bus_type_struct_uevent_has_const_dev_arg @@ -224,6 +226,7 @@ NV_CONFTEST_FUNCTION_COMPILE_TESTS += vm_area_struct_has_const_vm_flags NV_CONFTEST_FUNCTION_COMPILE_TESTS += of_property_read_reg NV_CONFTEST_GENERIC_COMPILE_TESTS += is_export_symbol_present_drm_gem_prime_fd_to_handle NV_CONFTEST_GENERIC_COMPILE_TESTS += is_export_symbol_present_drm_gem_prime_handle_to_fd +NV_CONFTEST_GENERIC_COMPILE_TESTS += is_export_symbol_present_queue_limits_set NV_CONFTEST_FUNCTION_COMPILE_TESTS += crypto_engine_ctx_struct_removed_test NV_CONFTEST_MACRO_COMPILE_TESTS ?= NV_CONFTEST_SYMBOL_COMPILE_TESTS ?= diff --git a/scripts/conftest/conftest.sh b/scripts/conftest/conftest.sh index 0fb09a6d..02e8b835 100755 --- a/scripts/conftest/conftest.sh +++ b/scripts/conftest/conftest.sh @@ -6724,6 +6724,44 @@ compile_test() { "NV_BLOCK_DEVICE_OPERATIONS_RELEASE_HAS_NO_MODE_ARG" "" "types" ;; + blk_mq_f_should_merge) + # + # Determine if the BLK_MQ_F_SHOULD_MERGE is present. + # + # In Linux v6.14, commit cc76ace465d6 ("block: remove BLK_MQ_F_SHOULD_MERGE") + # removed the definition BLK_MQ_F_SHOULD_MERGE. + # + CODE=" + #include + int conftest_blk_mq_f_should_merge(void) { + return BLK_MQ_F_SHOULD_MERGE; + }" + + compile_check_conftest "$CODE" \ + "NV_BLK_MQ_F_SHOULD_MERGE" "" "types" + ;; + + queue_limits_struct_has_features) + # + # Determine if the 'queue_limits' needs to use + # the latest set of API's + # The queue_limit set has 2 situations: + # 1. The API queue_limits_set is present but + # queue_limits.features is not present. + # 2. Both the API and queue_limits.features + # are present. + # + # Another macro is derived from this macro + # in nv_hv_vblk.c + CODE=" + #include + int conftest_set_queue_limits(void) { + return offsetof(struct queue_limits, features); + }" + compile_check_conftest "$CODE" \ + "NV_QUEUE_LIMITS_STRUCT_HAS_FEATURES" "" "types" + ;; + bus_type_struct_match_has_const_drv_arg) # # Determine if the 'match' callback from the 'bus_type' structure