1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright(c) 2023 Intel Corporation */ 3 4 #include <linux/array_size.h> 5 #include <linux/bitops.h> 6 #include <linux/export.h> 7 #include <linux/pci.h> 8 #include <linux/string.h> 9 #include "adf_cfg.h" 10 #include "adf_cfg_services.h" 11 #include "adf_cfg_strings.h" 12 13 static const char *const adf_cfg_services[] = { 14 [SVC_ASYM] = ADF_CFG_ASYM, 15 [SVC_SYM] = ADF_CFG_SYM, 16 [SVC_DC] = ADF_CFG_DC, 17 [SVC_DCC] = ADF_CFG_DCC, 18 }; 19 20 /* 21 * Ensure that the size of the array matches the number of services, 22 * SVC_BASE_COUNT, that is used to size the bitmap. 23 */ 24 static_assert(ARRAY_SIZE(adf_cfg_services) == SVC_BASE_COUNT); 25 26 /* 27 * Ensure that the maximum number of concurrent services that can be 28 * enabled on a device is less than or equal to the number of total 29 * supported services. 30 */ 31 static_assert(ARRAY_SIZE(adf_cfg_services) >= MAX_NUM_CONCURR_SVC); 32 33 /* 34 * Ensure that the number of services fit a single unsigned long, as each 35 * service is represented by a bit in the mask. 36 */ 37 static_assert(BITS_PER_LONG >= SVC_BASE_COUNT); 38 39 /* 40 * Ensure that size of the concatenation of all service strings is smaller 41 * than the size of the buffer that will contain them. 42 */ 43 static_assert(sizeof(ADF_CFG_SYM ADF_SERVICES_DELIMITER 44 ADF_CFG_ASYM ADF_SERVICES_DELIMITER 45 ADF_CFG_DC ADF_SERVICES_DELIMITER 46 ADF_CFG_DCC) < ADF_CFG_MAX_VAL_LEN_IN_BYTES); 47 48 static int adf_service_string_to_mask(struct adf_accel_dev *accel_dev, const char *buf, 49 size_t len, unsigned long *out_mask) 50 { 51 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); 52 char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { }; 53 unsigned long mask = 0; 54 char *substr, *token; 55 int id, num_svc = 0; 56 57 if (len > ADF_CFG_MAX_VAL_LEN_IN_BYTES - 1) 58 return -EINVAL; 59 60 strscpy(services, buf, ADF_CFG_MAX_VAL_LEN_IN_BYTES); 61 substr = services; 62 63 while ((token = strsep(&substr, ADF_SERVICES_DELIMITER))) { 64 id = sysfs_match_string(adf_cfg_services, token); 65 if (id < 0) 66 return id; 67 68 if (test_and_set_bit(id, &mask)) 69 return -EINVAL; 70 71 if (num_svc++ == MAX_NUM_CONCURR_SVC) 72 return -EINVAL; 73 } 74 75 if (hw_data->services_supported && !hw_data->services_supported(mask)) 76 return -EINVAL; 77 78 *out_mask = mask; 79 80 return 0; 81 } 82 83 static int adf_service_mask_to_string(unsigned long mask, char *buf, size_t len) 84 { 85 int offset = 0; 86 int bit; 87 88 if (len < ADF_CFG_MAX_VAL_LEN_IN_BYTES) 89 return -ENOSPC; 90 91 for_each_set_bit(bit, &mask, SVC_BASE_COUNT) { 92 if (offset) 93 offset += scnprintf(buf + offset, len - offset, 94 ADF_SERVICES_DELIMITER); 95 96 offset += scnprintf(buf + offset, len - offset, "%s", 97 adf_cfg_services[bit]); 98 } 99 100 return 0; 101 } 102 103 int adf_parse_service_string(struct adf_accel_dev *accel_dev, const char *in, 104 size_t in_len, char *out, size_t out_len) 105 { 106 unsigned long mask; 107 int ret; 108 109 ret = adf_service_string_to_mask(accel_dev, in, in_len, &mask); 110 if (ret) 111 return ret; 112 113 if (!mask) 114 return -EINVAL; 115 116 return adf_service_mask_to_string(mask, out, out_len); 117 } 118 119 static int adf_get_service_mask(struct adf_accel_dev *accel_dev, unsigned long *mask) 120 { 121 char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { }; 122 size_t len; 123 int ret; 124 125 ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, 126 ADF_SERVICES_ENABLED, services); 127 if (ret) { 128 dev_err(&GET_DEV(accel_dev), "%s param not found\n", 129 ADF_SERVICES_ENABLED); 130 return ret; 131 } 132 133 len = strnlen(services, ADF_CFG_MAX_VAL_LEN_IN_BYTES); 134 ret = adf_service_string_to_mask(accel_dev, services, len, mask); 135 if (ret) 136 dev_err(&GET_DEV(accel_dev), "Invalid value of %s param: %s\n", 137 ADF_SERVICES_ENABLED, services); 138 139 return ret; 140 } 141 142 int adf_get_service_enabled(struct adf_accel_dev *accel_dev) 143 { 144 unsigned long mask; 145 int ret; 146 147 ret = adf_get_service_mask(accel_dev, &mask); 148 if (ret) 149 return ret; 150 151 if (test_bit(SVC_SYM, &mask) && test_bit(SVC_ASYM, &mask)) 152 return SVC_SYM_ASYM; 153 154 if (test_bit(SVC_SYM, &mask) && test_bit(SVC_DC, &mask)) 155 return SVC_SYM_DC; 156 157 if (test_bit(SVC_ASYM, &mask) && test_bit(SVC_DC, &mask)) 158 return SVC_ASYM_DC; 159 160 if (test_bit(SVC_SYM, &mask)) 161 return SVC_SYM; 162 163 if (test_bit(SVC_ASYM, &mask)) 164 return SVC_ASYM; 165 166 if (test_bit(SVC_DC, &mask)) 167 return SVC_DC; 168 169 if (test_bit(SVC_DCC, &mask)) 170 return SVC_DCC; 171 172 return -EINVAL; 173 } 174 EXPORT_SYMBOL_GPL(adf_get_service_enabled); 175