1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* Copyright(c) 2007-2025 Intel Corporation */ 3 #include <sys/types.h> 4 #include <sys/sysctl.h> 5 #include <sys/systm.h> 6 #include "adf_accel_devices.h" 7 #include "adf_cfg.h" 8 #include "adf_cfg_sysctl.h" 9 #include "adf_cfg_device.h" 10 #include "adf_common_drv.h" 11 #include <sys/mutex.h> 12 #include <sys/sbuf.h> 13 #include <sys/priv.h> 14 15 #define ADF_CFG_SYSCTL_BUF_SZ ADF_CFG_MAX_VAL 16 #define ADF_CFG_UP_STR "up" 17 #define ADF_CFG_DOWN_STR "down" 18 19 #define ADF_CFG_MAX_USER_PROCESSES 64 20 21 static int 22 adf_cfg_down(struct adf_accel_dev *accel_dev) 23 { 24 int ret = 0; 25 26 if (!adf_dev_started(accel_dev)) { 27 device_printf(GET_DEV(accel_dev), 28 "Device qat_dev%d already down\n", 29 accel_dev->accel_id); 30 return 0; 31 } 32 33 if (adf_dev_in_use(accel_dev)) { 34 pr_err("QAT: Device %d in use\n", accel_dev->accel_id); 35 goto out; 36 } 37 38 if (adf_dev_stop(accel_dev)) { 39 device_printf(GET_DEV(accel_dev), 40 "Failed to stop qat_dev%d\n", 41 accel_dev->accel_id); 42 ret = EFAULT; 43 goto out; 44 } 45 46 adf_dev_shutdown(accel_dev); 47 48 out: 49 return ret; 50 } 51 52 static int 53 adf_cfg_up(struct adf_accel_dev *accel_dev) 54 { 55 int ret; 56 57 if (adf_dev_started(accel_dev)) 58 return 0; 59 60 if (NULL == accel_dev->hw_device->config_device) 61 return ENXIO; 62 63 ret = accel_dev->hw_device->config_device(accel_dev); 64 if (ret) { 65 device_printf(GET_DEV(accel_dev), 66 "Failed to start qat_dev%d\n", 67 accel_dev->accel_id); 68 return ret; 69 } 70 71 ret = adf_dev_init(accel_dev); 72 if (!ret) 73 ret = adf_dev_start(accel_dev); 74 75 if (ret) { 76 device_printf(GET_DEV(accel_dev), 77 "Failed to start qat_dev%d\n", 78 accel_dev->accel_id); 79 adf_dev_stop(accel_dev); 80 adf_dev_shutdown(accel_dev); 81 } 82 83 if (!ret) { 84 struct adf_cfg_device *cfg_dev = NULL; 85 86 cfg_dev = accel_dev->cfg->dev; 87 adf_cfg_device_clear(cfg_dev, accel_dev); 88 free(cfg_dev, M_QAT); 89 accel_dev->cfg->dev = NULL; 90 } 91 92 return 0; 93 } 94 95 static const char *const cfg_serv[] = 96 { "sym;asym", "sym", "asym", "dc", "sym;dc", "asym;dc", "cy", "cy;dc" }; 97 98 static const char *const cfg_mode[] = { "ks;us", "us", "ks" }; 99 100 static int adf_cfg_sysctl_services_handle(SYSCTL_HANDLER_ARGS) 101 { 102 struct adf_cfg_device_data *dev_cfg_data; 103 struct adf_accel_dev *accel_dev; 104 char buf[ADF_CFG_SYSCTL_BUF_SZ]; 105 unsigned int len; 106 int ret = 0; 107 int i = 0; 108 109 if (priv_check(curthread, PRIV_DRIVER) != 0) 110 return EPERM; 111 112 accel_dev = arg1; 113 if (!accel_dev) 114 return ENXIO; 115 116 dev_cfg_data = accel_dev->cfg; 117 if (!dev_cfg_data) 118 return ENXIO; 119 120 strlcpy(buf, dev_cfg_data->cfg_services, sizeof(buf)); 121 122 ret = sysctl_handle_string(oidp, buf, sizeof(buf), req); 123 if (ret != 0 || req->newptr == NULL) 124 return ret; 125 126 /* Handle config change */ 127 if (adf_dev_started(accel_dev)) { 128 device_printf( 129 GET_DEV(accel_dev), 130 "QAT: configuration could be changed in down state only\n"); 131 return EINVAL; 132 } 133 134 len = strlen(buf); 135 136 for (i = 0; i < ARRAY_SIZE(cfg_serv); i++) { 137 if ((len > 0 && strncasecmp(cfg_serv[i], buf, len) == 0)) { 138 strlcpy(dev_cfg_data->cfg_services, 139 buf, 140 ADF_CFG_MAX_VAL); 141 break; 142 } 143 } 144 145 if (i == ARRAY_SIZE(cfg_serv)) { 146 device_printf(GET_DEV(accel_dev), 147 "Unknown service configuration\n"); 148 ret = EINVAL; 149 } 150 151 return ret; 152 } 153 154 static int adf_cfg_sysctl_mode_handle(SYSCTL_HANDLER_ARGS) 155 { 156 struct adf_cfg_device_data *dev_cfg_data; 157 struct adf_accel_dev *accel_dev; 158 char buf[ADF_CFG_SYSCTL_BUF_SZ]; 159 unsigned int len; 160 int ret = 0; 161 int i = 0; 162 163 if (priv_check(curthread, PRIV_DRIVER) != 0) 164 return EPERM; 165 166 accel_dev = arg1; 167 if (!accel_dev) 168 return ENXIO; 169 170 dev_cfg_data = accel_dev->cfg; 171 if (!dev_cfg_data) 172 return ENXIO; 173 174 strlcpy(buf, dev_cfg_data->cfg_mode, sizeof(buf)); 175 176 ret = sysctl_handle_string(oidp, buf, sizeof(buf), req); 177 if (ret != 0 || req->newptr == NULL) 178 return ret; 179 180 /* Handle config change */ 181 if (adf_dev_started(accel_dev)) { 182 device_printf( 183 GET_DEV(accel_dev), 184 "QAT: configuration could be changed in down state only\n"); 185 return EBUSY; 186 } 187 188 len = strlen(buf); 189 190 for (i = 0; i < ARRAY_SIZE(cfg_mode); i++) { 191 if ((len > 0 && strncasecmp(cfg_mode[i], buf, len) == 0)) { 192 strlcpy(dev_cfg_data->cfg_mode, buf, ADF_CFG_MAX_VAL); 193 break; 194 } 195 } 196 197 if (i == ARRAY_SIZE(cfg_mode)) { 198 device_printf(GET_DEV(accel_dev), 199 "Unknown configuration mode\n"); 200 ret = EINVAL; 201 } 202 203 return ret; 204 } 205 206 static int adf_cfg_sysctl_handle(SYSCTL_HANDLER_ARGS) 207 { 208 struct adf_cfg_device_data *dev_cfg_data; 209 struct adf_accel_dev *accel_dev; 210 char buf[ADF_CFG_SYSCTL_BUF_SZ] = { 0 }; 211 unsigned int len; 212 int ret = 0; 213 214 if (priv_check(curthread, PRIV_DRIVER) != 0) 215 return EPERM; 216 217 accel_dev = arg1; 218 if (!accel_dev) 219 return ENXIO; 220 221 dev_cfg_data = accel_dev->cfg; 222 if (!dev_cfg_data) 223 return ENXIO; 224 225 if (adf_dev_started(accel_dev)) { 226 strlcpy(buf, ADF_CFG_UP_STR, sizeof(buf)); 227 } else { 228 strlcpy(buf, ADF_CFG_DOWN_STR, sizeof(buf)); 229 } 230 231 ret = sysctl_handle_string(oidp, buf, sizeof(buf), req); 232 if (ret != 0 || req->newptr == NULL) 233 return ret; 234 235 len = strlen(buf); 236 237 if ((len > 0 && strncasecmp(ADF_CFG_UP_STR, buf, len) == 0)) { 238 ret = adf_cfg_up(accel_dev); 239 240 } else if (len > 0 && strncasecmp(ADF_CFG_DOWN_STR, buf, len) == 0) { 241 ret = adf_cfg_down(accel_dev); 242 243 } else { 244 device_printf(GET_DEV(accel_dev), "QAT: Invalid operation\n"); 245 ret = EINVAL; 246 } 247 248 return ret; 249 } 250 251 static int adf_cfg_sysctl_num_processes_handle(SYSCTL_HANDLER_ARGS) 252 { 253 struct adf_cfg_device_data *dev_cfg_data; 254 struct adf_accel_dev *accel_dev; 255 uint32_t num_user_processes = 0; 256 int ret = 0; 257 258 if (priv_check(curthread, PRIV_DRIVER) != 0) 259 return EPERM; 260 261 accel_dev = arg1; 262 if (!accel_dev) 263 return ENXIO; 264 265 dev_cfg_data = accel_dev->cfg; 266 if (!dev_cfg_data) 267 return ENXIO; 268 269 num_user_processes = dev_cfg_data->num_user_processes; 270 271 ret = sysctl_handle_int(oidp, &num_user_processes, 0, req); 272 if (ret != 0 || req->newptr == NULL) 273 return ret; 274 275 if (adf_dev_started(accel_dev)) { 276 device_printf( 277 GET_DEV(accel_dev), 278 "QAT: configuration could be changed in down state only\n"); 279 return EBUSY; 280 } 281 282 if (num_user_processes > ADF_CFG_MAX_USER_PROCESSES) { 283 return EINVAL; 284 } 285 286 dev_cfg_data->num_user_processes = num_user_processes; 287 288 return ret; 289 } 290 291 int 292 adf_cfg_sysctl_add(struct adf_accel_dev *accel_dev) 293 { 294 struct sysctl_ctx_list *qat_sysctl_ctx; 295 struct sysctl_oid *qat_sysctl_tree; 296 297 if (!accel_dev) 298 return EINVAL; 299 300 qat_sysctl_ctx = 301 device_get_sysctl_ctx(accel_dev->accel_pci_dev.pci_dev); 302 qat_sysctl_tree = 303 device_get_sysctl_tree(accel_dev->accel_pci_dev.pci_dev); 304 305 SYSCTL_ADD_PROC(qat_sysctl_ctx, 306 SYSCTL_CHILDREN(qat_sysctl_tree), 307 OID_AUTO, 308 "state", 309 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 310 accel_dev, 311 0, 312 adf_cfg_sysctl_handle, 313 "A", 314 "QAT State"); 315 316 SYSCTL_ADD_PROC(qat_sysctl_ctx, 317 SYSCTL_CHILDREN(qat_sysctl_tree), 318 OID_AUTO, 319 "cfg_services", 320 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 321 accel_dev, 322 0, 323 adf_cfg_sysctl_services_handle, 324 "A", 325 "QAT services confguration"); 326 327 SYSCTL_ADD_PROC(qat_sysctl_ctx, 328 SYSCTL_CHILDREN(qat_sysctl_tree), 329 OID_AUTO, 330 "cfg_mode", 331 CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 332 accel_dev, 333 0, 334 adf_cfg_sysctl_mode_handle, 335 "A", 336 "QAT mode configuration"); 337 338 SYSCTL_ADD_PROC(qat_sysctl_ctx, 339 SYSCTL_CHILDREN(qat_sysctl_tree), 340 OID_AUTO, 341 "num_user_processes", 342 CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 343 accel_dev, 344 0, 345 adf_cfg_sysctl_num_processes_handle, 346 "I", 347 "QAT user processes number "); 348 349 return 0; 350 } 351 352 void 353 adf_cfg_sysctl_remove(struct adf_accel_dev *accel_dev) 354 { 355 } 356