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_common.h" 11 #include "adf_cfg_services.h" 12 #include "adf_cfg_strings.h" 13 14 static const char *const adf_cfg_services[] = { 15 [SVC_ASYM] = ADF_CFG_ASYM, 16 [SVC_SYM] = ADF_CFG_SYM, 17 [SVC_DC] = ADF_CFG_DC, 18 [SVC_DCC] = ADF_CFG_DCC, 19 [SVC_DECOMP] = ADF_CFG_DECOMP, 20 }; 21 22 /* 23 * Ensure that the size of the array matches the number of services, 24 * SVC_COUNT, that is used to size the bitmap. 25 */ 26 static_assert(ARRAY_SIZE(adf_cfg_services) == SVC_COUNT); 27 28 /* 29 * Ensure that the maximum number of concurrent services that can be 30 * enabled on a device is less than or equal to the number of total 31 * supported services. 32 */ 33 static_assert(ARRAY_SIZE(adf_cfg_services) >= MAX_NUM_CONCURR_SVC); 34 35 /* 36 * Ensure that the number of services fit a single unsigned long, as each 37 * service is represented by a bit in the mask. 38 */ 39 static_assert(BITS_PER_LONG >= SVC_COUNT); 40 41 /* 42 * Ensure that size of the concatenation of all service strings is smaller 43 * than the size of the buffer that will contain them. 44 */ 45 static_assert(sizeof(ADF_CFG_SYM ADF_SERVICES_DELIMITER 46 ADF_CFG_ASYM ADF_SERVICES_DELIMITER 47 ADF_CFG_DC ADF_SERVICES_DELIMITER 48 ADF_CFG_DECOMP ADF_SERVICES_DELIMITER 49 ADF_CFG_DCC) < ADF_CFG_MAX_VAL_LEN_IN_BYTES); 50 51 static int adf_service_string_to_mask(struct adf_accel_dev *accel_dev, const char *buf, 52 size_t len, unsigned long *out_mask) 53 { 54 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); 55 char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { }; 56 unsigned long mask = 0; 57 char *substr, *token; 58 int id, num_svc = 0; 59 60 if (len > ADF_CFG_MAX_VAL_LEN_IN_BYTES - 1) 61 return -EINVAL; 62 63 strscpy(services, buf, ADF_CFG_MAX_VAL_LEN_IN_BYTES); 64 substr = services; 65 66 while ((token = strsep(&substr, ADF_SERVICES_DELIMITER))) { 67 id = sysfs_match_string(adf_cfg_services, token); 68 if (id < 0) 69 return id; 70 71 if (test_and_set_bit(id, &mask)) 72 return -EINVAL; 73 74 if (num_svc++ == MAX_NUM_CONCURR_SVC) 75 return -EINVAL; 76 } 77 78 if (hw_data->services_supported && !hw_data->services_supported(mask)) 79 return -EINVAL; 80 81 *out_mask = mask; 82 83 return 0; 84 } 85 86 static int adf_service_mask_to_string(unsigned long mask, char *buf, size_t len) 87 { 88 int offset = 0; 89 int bit; 90 91 if (len < ADF_CFG_MAX_VAL_LEN_IN_BYTES) 92 return -ENOSPC; 93 94 for_each_set_bit(bit, &mask, SVC_COUNT) { 95 if (offset) 96 offset += scnprintf(buf + offset, len - offset, 97 ADF_SERVICES_DELIMITER "%s", adf_cfg_services[bit]); 98 else 99 offset += scnprintf(buf, len, "%s", adf_cfg_services[bit]); 100 } 101 102 return 0; 103 } 104 105 int adf_parse_service_string(struct adf_accel_dev *accel_dev, const char *in, 106 size_t in_len, char *out, size_t out_len) 107 { 108 unsigned long mask; 109 int ret; 110 111 ret = adf_service_string_to_mask(accel_dev, in, in_len, &mask); 112 if (ret) 113 return ret; 114 115 if (!mask) 116 return -EINVAL; 117 118 return adf_service_mask_to_string(mask, out, out_len); 119 } 120 121 int adf_get_service_mask(struct adf_accel_dev *accel_dev, unsigned long *mask) 122 { 123 char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { }; 124 size_t len; 125 int ret; 126 127 ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, 128 ADF_SERVICES_ENABLED, services); 129 if (ret) { 130 dev_err(&GET_DEV(accel_dev), "%s param not found\n", 131 ADF_SERVICES_ENABLED); 132 return ret; 133 } 134 135 len = strnlen(services, ADF_CFG_MAX_VAL_LEN_IN_BYTES); 136 ret = adf_service_string_to_mask(accel_dev, services, len, mask); 137 if (ret) 138 dev_err(&GET_DEV(accel_dev), "Invalid value of %s param: %s\n", 139 ADF_SERVICES_ENABLED, services); 140 141 return ret; 142 } 143 EXPORT_SYMBOL_GPL(adf_get_service_mask); 144 145 int adf_get_service_enabled(struct adf_accel_dev *accel_dev) 146 { 147 unsigned long mask; 148 int ret; 149 150 ret = adf_get_service_mask(accel_dev, &mask); 151 if (ret) 152 return ret; 153 154 if (test_bit(SVC_SYM, &mask) && test_bit(SVC_ASYM, &mask)) 155 return SVC_SYM_ASYM; 156 157 if (test_bit(SVC_SYM, &mask) && test_bit(SVC_DC, &mask)) 158 return SVC_SYM_DC; 159 160 if (test_bit(SVC_ASYM, &mask) && test_bit(SVC_DC, &mask)) 161 return SVC_ASYM_DC; 162 163 if (test_bit(SVC_SYM, &mask)) 164 return SVC_SYM; 165 166 if (test_bit(SVC_ASYM, &mask)) 167 return SVC_ASYM; 168 169 if (test_bit(SVC_DC, &mask)) 170 return SVC_DC; 171 172 if (test_bit(SVC_DECOMP, &mask)) 173 return SVC_DECOMP; 174 175 if (test_bit(SVC_DCC, &mask)) 176 return SVC_DCC; 177 178 return -EINVAL; 179 } 180 EXPORT_SYMBOL_GPL(adf_get_service_enabled); 181 182 enum adf_cfg_service_type adf_srv_to_cfg_svc_type(enum adf_base_services svc) 183 { 184 switch (svc) { 185 case SVC_ASYM: 186 return ASYM; 187 case SVC_SYM: 188 return SYM; 189 case SVC_DC: 190 return COMP; 191 case SVC_DECOMP: 192 return DECOMP; 193 default: 194 return UNUSED; 195 } 196 } 197 198 bool adf_is_service_enabled(struct adf_accel_dev *accel_dev, enum adf_base_services svc) 199 { 200 enum adf_cfg_service_type arb_srv = adf_srv_to_cfg_svc_type(svc); 201 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); 202 u8 rps_per_bundle = hw_data->num_banks_per_vf; 203 int i; 204 205 for (i = 0; i < rps_per_bundle; i++) { 206 if (GET_SRV_TYPE(accel_dev, i) == arb_srv) 207 return true; 208 } 209 210 return false; 211 } 212