| // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) |
| /* Copyright(c) 2022 Intel Corporation */ |
| #include <linux/device.h> |
| #include <linux/errno.h> |
| #include <linux/pci.h> |
| #include "adf_accel_devices.h" |
| #include "adf_cfg.h" |
| #include "adf_common_drv.h" |
| |
| static const char * const state_operations[] = { |
| [DEV_DOWN] = "down", |
| [DEV_UP] = "up", |
| }; |
| |
| static ssize_t state_show(struct device *dev, struct device_attribute *attr, |
| char *buf) |
| { |
| struct adf_accel_dev *accel_dev; |
| char *state; |
| |
| accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); |
| if (!accel_dev) |
| return -EINVAL; |
| |
| state = adf_dev_started(accel_dev) ? "up" : "down"; |
| return sysfs_emit(buf, "%s\n", state); |
| } |
| |
| static ssize_t state_store(struct device *dev, struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| struct adf_accel_dev *accel_dev; |
| u32 accel_id; |
| int ret; |
| |
| accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); |
| if (!accel_dev) |
| return -EINVAL; |
| |
| accel_id = accel_dev->accel_id; |
| |
| if (adf_devmgr_in_reset(accel_dev) || adf_dev_in_use(accel_dev)) { |
| dev_info(dev, "Device qat_dev%d is busy\n", accel_id); |
| return -EBUSY; |
| } |
| |
| ret = sysfs_match_string(state_operations, buf); |
| if (ret < 0) |
| return ret; |
| |
| switch (ret) { |
| case DEV_DOWN: |
| if (!adf_dev_started(accel_dev)) { |
| dev_info(dev, "Device qat_dev%d already down\n", |
| accel_id); |
| return -EINVAL; |
| } |
| |
| dev_info(dev, "Stopping device qat_dev%d\n", accel_id); |
| |
| ret = adf_dev_shutdown_cache_cfg(accel_dev); |
| if (ret < 0) |
| return -EINVAL; |
| |
| break; |
| case DEV_UP: |
| if (adf_dev_started(accel_dev)) { |
| dev_info(dev, "Device qat_dev%d already up\n", |
| accel_id); |
| return -EINVAL; |
| } |
| |
| dev_info(dev, "Starting device qat_dev%d\n", accel_id); |
| |
| ret = GET_HW_DATA(accel_dev)->dev_config(accel_dev); |
| if (!ret) |
| ret = adf_dev_init(accel_dev); |
| if (!ret) |
| ret = adf_dev_start(accel_dev); |
| |
| if (ret < 0) { |
| dev_err(dev, "Failed to start device qat_dev%d\n", |
| accel_id); |
| adf_dev_shutdown_cache_cfg(accel_dev); |
| return ret; |
| } |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| return count; |
| } |
| |
| static const char * const services_operations[] = { |
| ADF_CFG_CY, |
| ADF_CFG_DC, |
| }; |
| |
| static ssize_t cfg_services_show(struct device *dev, struct device_attribute *attr, |
| char *buf) |
| { |
| char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; |
| struct adf_accel_dev *accel_dev; |
| int ret; |
| |
| accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); |
| if (!accel_dev) |
| return -EINVAL; |
| |
| ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, |
| ADF_SERVICES_ENABLED, services); |
| if (ret) |
| return ret; |
| |
| return sysfs_emit(buf, "%s\n", services); |
| } |
| |
| static int adf_sysfs_update_dev_config(struct adf_accel_dev *accel_dev, |
| const char *services) |
| { |
| return adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC, |
| ADF_SERVICES_ENABLED, services, |
| ADF_STR); |
| } |
| |
| static ssize_t cfg_services_store(struct device *dev, struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| struct adf_hw_device_data *hw_data; |
| struct adf_accel_dev *accel_dev; |
| int ret; |
| |
| ret = sysfs_match_string(services_operations, buf); |
| if (ret < 0) |
| return ret; |
| |
| accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); |
| if (!accel_dev) |
| return -EINVAL; |
| |
| if (adf_dev_started(accel_dev)) { |
| dev_info(dev, "Device qat_dev%d must be down to reconfigure the service.\n", |
| accel_dev->accel_id); |
| return -EINVAL; |
| } |
| |
| ret = adf_sysfs_update_dev_config(accel_dev, services_operations[ret]); |
| if (ret < 0) |
| return ret; |
| |
| hw_data = GET_HW_DATA(accel_dev); |
| |
| /* Update capabilities mask after change in configuration. |
| * A call to this function is required as capabilities are, at the |
| * moment, tied to configuration |
| */ |
| hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev); |
| if (!hw_data->accel_capabilities_mask) |
| return -EINVAL; |
| |
| return count; |
| } |
| |
| static DEVICE_ATTR_RW(state); |
| static DEVICE_ATTR_RW(cfg_services); |
| |
| static struct attribute *qat_attrs[] = { |
| &dev_attr_state.attr, |
| &dev_attr_cfg_services.attr, |
| NULL, |
| }; |
| |
| static struct attribute_group qat_group = { |
| .attrs = qat_attrs, |
| .name = "qat", |
| }; |
| |
| int adf_sysfs_init(struct adf_accel_dev *accel_dev) |
| { |
| int ret; |
| |
| ret = devm_device_add_group(&GET_DEV(accel_dev), &qat_group); |
| if (ret) { |
| dev_err(&GET_DEV(accel_dev), |
| "Failed to create qat attribute group: %d\n", ret); |
| } |
| |
| return ret; |
| } |
| EXPORT_SYMBOL_GPL(adf_sysfs_init); |