1 // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
2 /* Copyright(c) 2022 Intel Corporation */
3 #include <linux/device.h>
4 #include <linux/errno.h>
5 #include <linux/pci.h>
6 #include "adf_accel_devices.h"
7 #include "adf_cfg.h"
8 #include "adf_common_drv.h"
9
10 static const char * const state_operations[] = {
11 [DEV_DOWN] = "down",
12 [DEV_UP] = "up",
13 };
14
state_show(struct device * dev,struct device_attribute * attr,char * buf)15 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
16 char *buf)
17 {
18 struct adf_accel_dev *accel_dev;
19 char *state;
20
21 accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
22 if (!accel_dev)
23 return -EINVAL;
24
25 state = adf_dev_started(accel_dev) ? "up" : "down";
26 return sysfs_emit(buf, "%s\n", state);
27 }
28
state_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)29 static ssize_t state_store(struct device *dev, struct device_attribute *attr,
30 const char *buf, size_t count)
31 {
32 struct adf_accel_dev *accel_dev;
33 u32 accel_id;
34 int ret;
35
36 accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
37 if (!accel_dev)
38 return -EINVAL;
39
40 accel_id = accel_dev->accel_id;
41
42 if (adf_devmgr_in_reset(accel_dev) || adf_dev_in_use(accel_dev)) {
43 dev_info(dev, "Device qat_dev%d is busy\n", accel_id);
44 return -EBUSY;
45 }
46
47 ret = sysfs_match_string(state_operations, buf);
48 if (ret < 0)
49 return ret;
50
51 switch (ret) {
52 case DEV_DOWN:
53 if (!adf_dev_started(accel_dev)) {
54 dev_info(dev, "Device qat_dev%d already down\n",
55 accel_id);
56 return -EINVAL;
57 }
58
59 dev_info(dev, "Stopping device qat_dev%d\n", accel_id);
60
61 ret = adf_dev_shutdown_cache_cfg(accel_dev);
62 if (ret < 0)
63 return -EINVAL;
64
65 break;
66 case DEV_UP:
67 if (adf_dev_started(accel_dev)) {
68 dev_info(dev, "Device qat_dev%d already up\n",
69 accel_id);
70 return -EINVAL;
71 }
72
73 dev_info(dev, "Starting device qat_dev%d\n", accel_id);
74
75 ret = GET_HW_DATA(accel_dev)->dev_config(accel_dev);
76 if (!ret)
77 ret = adf_dev_init(accel_dev);
78 if (!ret)
79 ret = adf_dev_start(accel_dev);
80
81 if (ret < 0) {
82 dev_err(dev, "Failed to start device qat_dev%d\n",
83 accel_id);
84 adf_dev_shutdown_cache_cfg(accel_dev);
85 return ret;
86 }
87 break;
88 default:
89 return -EINVAL;
90 }
91
92 return count;
93 }
94
95 static const char * const services_operations[] = {
96 ADF_CFG_CY,
97 ADF_CFG_DC,
98 };
99
cfg_services_show(struct device * dev,struct device_attribute * attr,char * buf)100 static ssize_t cfg_services_show(struct device *dev, struct device_attribute *attr,
101 char *buf)
102 {
103 char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
104 struct adf_accel_dev *accel_dev;
105 int ret;
106
107 accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
108 if (!accel_dev)
109 return -EINVAL;
110
111 ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
112 ADF_SERVICES_ENABLED, services);
113 if (ret)
114 return ret;
115
116 return sysfs_emit(buf, "%s\n", services);
117 }
118
adf_sysfs_update_dev_config(struct adf_accel_dev * accel_dev,const char * services)119 static int adf_sysfs_update_dev_config(struct adf_accel_dev *accel_dev,
120 const char *services)
121 {
122 return adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
123 ADF_SERVICES_ENABLED, services,
124 ADF_STR);
125 }
126
cfg_services_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)127 static ssize_t cfg_services_store(struct device *dev, struct device_attribute *attr,
128 const char *buf, size_t count)
129 {
130 struct adf_hw_device_data *hw_data;
131 struct adf_accel_dev *accel_dev;
132 int ret;
133
134 ret = sysfs_match_string(services_operations, buf);
135 if (ret < 0)
136 return ret;
137
138 accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
139 if (!accel_dev)
140 return -EINVAL;
141
142 if (adf_dev_started(accel_dev)) {
143 dev_info(dev, "Device qat_dev%d must be down to reconfigure the service.\n",
144 accel_dev->accel_id);
145 return -EINVAL;
146 }
147
148 ret = adf_sysfs_update_dev_config(accel_dev, services_operations[ret]);
149 if (ret < 0)
150 return ret;
151
152 hw_data = GET_HW_DATA(accel_dev);
153
154 /* Update capabilities mask after change in configuration.
155 * A call to this function is required as capabilities are, at the
156 * moment, tied to configuration
157 */
158 hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev);
159 if (!hw_data->accel_capabilities_mask)
160 return -EINVAL;
161
162 return count;
163 }
164
165 static DEVICE_ATTR_RW(state);
166 static DEVICE_ATTR_RW(cfg_services);
167
168 static struct attribute *qat_attrs[] = {
169 &dev_attr_state.attr,
170 &dev_attr_cfg_services.attr,
171 NULL,
172 };
173
174 static struct attribute_group qat_group = {
175 .attrs = qat_attrs,
176 .name = "qat",
177 };
178
adf_sysfs_init(struct adf_accel_dev * accel_dev)179 int adf_sysfs_init(struct adf_accel_dev *accel_dev)
180 {
181 int ret;
182
183 ret = devm_device_add_group(&GET_DEV(accel_dev), &qat_group);
184 if (ret) {
185 dev_err(&GET_DEV(accel_dev),
186 "Failed to create qat attribute group: %d\n", ret);
187 }
188
189 return ret;
190 }
191 EXPORT_SYMBOL_GPL(adf_sysfs_init);
192