/* SPDX-License-Identifier: BSD-3-Clause */ /* Copyright(c) 2007-2022 Intel Corporation */ #include #include #include #include "adf_accel_devices.h" #include "adf_cfg.h" #include "adf_cfg_sysctl.h" #include "adf_cfg_device.h" #include "adf_common_drv.h" #include #include #define ADF_CFG_SYSCTL_BUF_SZ ADF_CFG_MAX_VAL #define ADF_CFG_UP_STR "up" #define ADF_CFG_DOWN_STR "down" #define ADF_CFG_MAX_USER_PROCESSES 64 static int adf_cfg_down(struct adf_accel_dev *accel_dev) { int ret = 0; if (!adf_dev_started(accel_dev)) { device_printf(GET_DEV(accel_dev), "Device qat_dev%d already down\n", accel_dev->accel_id); return 0; } if (adf_dev_in_use(accel_dev)) { pr_err("QAT: Device %d in use\n", accel_dev->accel_id); goto out; } if (adf_dev_stop(accel_dev)) { device_printf(GET_DEV(accel_dev), "Failed to stop qat_dev%d\n", accel_dev->accel_id); ret = EFAULT; goto out; } adf_dev_shutdown(accel_dev); out: return ret; } static int adf_cfg_up(struct adf_accel_dev *accel_dev) { int ret; if (adf_dev_started(accel_dev)) return 0; if (NULL == accel_dev->hw_device->config_device) return ENXIO; ret = accel_dev->hw_device->config_device(accel_dev); if (ret) { device_printf(GET_DEV(accel_dev), "Failed to start qat_dev%d\n", accel_dev->accel_id); return ret; } ret = adf_dev_init(accel_dev); if (!ret) ret = adf_dev_start(accel_dev); if (ret) { device_printf(GET_DEV(accel_dev), "Failed to start qat_dev%d\n", accel_dev->accel_id); adf_dev_stop(accel_dev); adf_dev_shutdown(accel_dev); } if (!ret) { struct adf_cfg_device *cfg_dev = NULL; cfg_dev = accel_dev->cfg->dev; adf_cfg_device_clear(cfg_dev, accel_dev); free(cfg_dev, M_QAT); accel_dev->cfg->dev = NULL; } return 0; } static const char *const cfg_serv[] = { "sym;asym", "sym", "asym", "dc", "sym;dc", "asym;dc", "cy", "cy;dc" }; static const char *const cfg_mode[] = { "ks;us", "us", "ks" }; static int adf_cfg_sysctl_services_handle(SYSCTL_HANDLER_ARGS) { struct adf_cfg_device_data *dev_cfg_data; struct adf_accel_dev *accel_dev; char buf[ADF_CFG_SYSCTL_BUF_SZ]; unsigned int len; int ret = 0; int i = 0; accel_dev = arg1; if (!accel_dev) return ENXIO; dev_cfg_data = accel_dev->cfg; if (!dev_cfg_data) return ENXIO; strlcpy(buf, dev_cfg_data->cfg_services, sizeof(buf)); ret = sysctl_handle_string(oidp, buf, sizeof(buf), req); if (ret != 0 || req->newptr == NULL) return ret; /* Handle config change */ if (adf_dev_started(accel_dev)) { device_printf( GET_DEV(accel_dev), "QAT: configuration could be changed in down state only\n"); return EINVAL; } len = strlen(buf); for (i = 0; i < ARRAY_SIZE(cfg_serv); i++) { if ((len > 0 && strncasecmp(cfg_serv[i], buf, len) == 0)) { strlcpy(dev_cfg_data->cfg_services, buf, ADF_CFG_MAX_VAL); break; } } if (i == ARRAY_SIZE(cfg_serv)) { device_printf(GET_DEV(accel_dev), "Unknown service configuration\n"); ret = EINVAL; } return ret; } static int adf_cfg_sysctl_mode_handle(SYSCTL_HANDLER_ARGS) { struct adf_cfg_device_data *dev_cfg_data; struct adf_accel_dev *accel_dev; char buf[ADF_CFG_SYSCTL_BUF_SZ]; unsigned int len; int ret = 0; int i = 0; accel_dev = arg1; if (!accel_dev) return ENXIO; dev_cfg_data = accel_dev->cfg; if (!dev_cfg_data) return ENXIO; strlcpy(buf, dev_cfg_data->cfg_mode, sizeof(buf)); ret = sysctl_handle_string(oidp, buf, sizeof(buf), req); if (ret != 0 || req->newptr == NULL) return ret; /* Handle config change */ if (adf_dev_started(accel_dev)) { device_printf( GET_DEV(accel_dev), "QAT: configuration could be changed in down state only\n"); return EBUSY; } len = strlen(buf); for (i = 0; i < ARRAY_SIZE(cfg_mode); i++) { if ((len > 0 && strncasecmp(cfg_mode[i], buf, len) == 0)) { strlcpy(dev_cfg_data->cfg_mode, buf, ADF_CFG_MAX_VAL); break; } } if (i == ARRAY_SIZE(cfg_mode)) { device_printf(GET_DEV(accel_dev), "Unknown configuration mode\n"); ret = EINVAL; } return ret; } static int adf_cfg_sysctl_handle(SYSCTL_HANDLER_ARGS) { struct adf_cfg_device_data *dev_cfg_data; struct adf_accel_dev *accel_dev; char buf[ADF_CFG_SYSCTL_BUF_SZ] = { 0 }; unsigned int len; int ret = 0; accel_dev = arg1; if (!accel_dev) return ENXIO; dev_cfg_data = accel_dev->cfg; if (!dev_cfg_data) return ENXIO; if (adf_dev_started(accel_dev)) { strlcpy(buf, ADF_CFG_UP_STR, sizeof(buf)); } else { strlcpy(buf, ADF_CFG_DOWN_STR, sizeof(buf)); } ret = sysctl_handle_string(oidp, buf, sizeof(buf), req); if (ret != 0 || req->newptr == NULL) return ret; len = strlen(buf); if ((len > 0 && strncasecmp(ADF_CFG_UP_STR, buf, len) == 0)) { ret = adf_cfg_up(accel_dev); } else if (len > 0 && strncasecmp(ADF_CFG_DOWN_STR, buf, len) == 0) { ret = adf_cfg_down(accel_dev); } else { device_printf(GET_DEV(accel_dev), "QAT: Invalid operation\n"); ret = EINVAL; } return ret; } static int adf_cfg_sysctl_num_processes_handle(SYSCTL_HANDLER_ARGS) { struct adf_cfg_device_data *dev_cfg_data; struct adf_accel_dev *accel_dev; uint32_t num_user_processes = 0; int ret = 0; accel_dev = arg1; if (!accel_dev) return ENXIO; dev_cfg_data = accel_dev->cfg; if (!dev_cfg_data) return ENXIO; num_user_processes = dev_cfg_data->num_user_processes; ret = sysctl_handle_int(oidp, &num_user_processes, 0, req); if (ret != 0 || req->newptr == NULL) return ret; if (adf_dev_started(accel_dev)) { device_printf( GET_DEV(accel_dev), "QAT: configuration could be changed in down state only\n"); return EBUSY; } if (num_user_processes > ADF_CFG_MAX_USER_PROCESSES) { return EINVAL; } dev_cfg_data->num_user_processes = num_user_processes; return ret; } int adf_cfg_sysctl_add(struct adf_accel_dev *accel_dev) { struct sysctl_ctx_list *qat_sysctl_ctx; struct sysctl_oid *qat_sysctl_tree; if (!accel_dev) return EINVAL; qat_sysctl_ctx = device_get_sysctl_ctx(accel_dev->accel_pci_dev.pci_dev); qat_sysctl_tree = device_get_sysctl_tree(accel_dev->accel_pci_dev.pci_dev); SYSCTL_ADD_PROC(qat_sysctl_ctx, SYSCTL_CHILDREN(qat_sysctl_tree), OID_AUTO, "state", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, accel_dev, 0, adf_cfg_sysctl_handle, "A", "QAT State"); SYSCTL_ADD_PROC(qat_sysctl_ctx, SYSCTL_CHILDREN(qat_sysctl_tree), OID_AUTO, "cfg_services", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, accel_dev, 0, adf_cfg_sysctl_services_handle, "A", "QAT services confguration"); SYSCTL_ADD_PROC(qat_sysctl_ctx, SYSCTL_CHILDREN(qat_sysctl_tree), OID_AUTO, "cfg_mode", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, accel_dev, 0, adf_cfg_sysctl_mode_handle, "A", "QAT mode configuration"); SYSCTL_ADD_PROC(qat_sysctl_ctx, SYSCTL_CHILDREN(qat_sysctl_tree), OID_AUTO, "num_user_processes", CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, accel_dev, 0, adf_cfg_sysctl_num_processes_handle, "I", "QAT user processes number "); return 0; } void adf_cfg_sysctl_remove(struct adf_accel_dev *accel_dev) { }