#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#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 <sys/mutex.h>
#include <sys/sbuf.h>
#include <sys/priv.h>
#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;
if (priv_check(curthread, PRIV_DRIVER) != 0)
return EPERM;
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;
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;
if (priv_check(curthread, PRIV_DRIVER) != 0)
return EPERM;
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;
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;
if (priv_check(curthread, PRIV_DRIVER) != 0)
return EPERM;
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;
if (priv_check(curthread, PRIV_DRIVER) != 0)
return EPERM;
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)
{
}