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 
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 
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 		dev_info(dev, "Stopping device qat_dev%d\n", accel_id);
54 
55 		if (!adf_dev_started(accel_dev)) {
56 			dev_info(&GET_DEV(accel_dev), "Device qat_dev%d already down\n",
57 				 accel_id);
58 
59 			break;
60 		}
61 
62 		ret = adf_dev_down(accel_dev, true);
63 		if (ret < 0)
64 			return -EINVAL;
65 
66 		break;
67 	case DEV_UP:
68 		dev_info(dev, "Starting device qat_dev%d\n", accel_id);
69 
70 		ret = adf_dev_up(accel_dev, true);
71 		if (ret < 0) {
72 			dev_err(dev, "Failed to start device qat_dev%d\n",
73 				accel_id);
74 			adf_dev_down(accel_dev, true);
75 			return ret;
76 		}
77 		break;
78 	default:
79 		return -EINVAL;
80 	}
81 
82 	return count;
83 }
84 
85 static const char * const services_operations[] = {
86 	ADF_CFG_CY,
87 	ADF_CFG_DC,
88 	ADF_CFG_SYM,
89 	ADF_CFG_ASYM,
90 	ADF_CFG_ASYM_SYM,
91 	ADF_CFG_ASYM_DC,
92 	ADF_CFG_DC_ASYM,
93 	ADF_CFG_SYM_DC,
94 	ADF_CFG_DC_SYM,
95 };
96 
97 static ssize_t cfg_services_show(struct device *dev, struct device_attribute *attr,
98 				 char *buf)
99 {
100 	char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
101 	struct adf_accel_dev *accel_dev;
102 	int ret;
103 
104 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
105 	if (!accel_dev)
106 		return -EINVAL;
107 
108 	ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
109 				      ADF_SERVICES_ENABLED, services);
110 	if (ret)
111 		return ret;
112 
113 	return sysfs_emit(buf, "%s\n", services);
114 }
115 
116 static int adf_sysfs_update_dev_config(struct adf_accel_dev *accel_dev,
117 				       const char *services)
118 {
119 	return adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
120 					   ADF_SERVICES_ENABLED, services,
121 					   ADF_STR);
122 }
123 
124 static ssize_t cfg_services_store(struct device *dev, struct device_attribute *attr,
125 				  const char *buf, size_t count)
126 {
127 	struct adf_hw_device_data *hw_data;
128 	struct adf_accel_dev *accel_dev;
129 	int ret;
130 
131 	ret = sysfs_match_string(services_operations, buf);
132 	if (ret < 0)
133 		return ret;
134 
135 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
136 	if (!accel_dev)
137 		return -EINVAL;
138 
139 	if (adf_dev_started(accel_dev)) {
140 		dev_info(dev, "Device qat_dev%d must be down to reconfigure the service.\n",
141 			 accel_dev->accel_id);
142 		return -EINVAL;
143 	}
144 
145 	ret = adf_sysfs_update_dev_config(accel_dev, services_operations[ret]);
146 	if (ret < 0)
147 		return ret;
148 
149 	hw_data = GET_HW_DATA(accel_dev);
150 
151 	/* Update capabilities mask after change in configuration.
152 	 * A call to this function is required as capabilities are, at the
153 	 * moment, tied to configuration
154 	 */
155 	hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev);
156 	if (!hw_data->accel_capabilities_mask)
157 		return -EINVAL;
158 
159 	return count;
160 }
161 
162 static ssize_t pm_idle_enabled_show(struct device *dev, struct device_attribute *attr,
163 				    char *buf)
164 {
165 	char pm_idle_enabled[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {};
166 	struct adf_accel_dev *accel_dev;
167 	int ret;
168 
169 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
170 	if (!accel_dev)
171 		return -EINVAL;
172 
173 	ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
174 				      ADF_PM_IDLE_SUPPORT, pm_idle_enabled);
175 	if (ret)
176 		return sysfs_emit(buf, "1\n");
177 
178 	return sysfs_emit(buf, "%s\n", pm_idle_enabled);
179 }
180 
181 static ssize_t pm_idle_enabled_store(struct device *dev, struct device_attribute *attr,
182 				     const char *buf, size_t count)
183 {
184 	unsigned long pm_idle_enabled_cfg_val;
185 	struct adf_accel_dev *accel_dev;
186 	bool pm_idle_enabled;
187 	int ret;
188 
189 	ret = kstrtobool(buf, &pm_idle_enabled);
190 	if (ret)
191 		return ret;
192 
193 	pm_idle_enabled_cfg_val = pm_idle_enabled;
194 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
195 	if (!accel_dev)
196 		return -EINVAL;
197 
198 	if (adf_dev_started(accel_dev)) {
199 		dev_info(dev, "Device qat_dev%d must be down to set pm_idle_enabled.\n",
200 			 accel_dev->accel_id);
201 		return -EINVAL;
202 	}
203 
204 	ret = adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
205 					  ADF_PM_IDLE_SUPPORT, &pm_idle_enabled_cfg_val,
206 					  ADF_DEC);
207 	if (ret)
208 		return ret;
209 
210 	return count;
211 }
212 static DEVICE_ATTR_RW(pm_idle_enabled);
213 
214 static DEVICE_ATTR_RW(state);
215 static DEVICE_ATTR_RW(cfg_services);
216 
217 static struct attribute *qat_attrs[] = {
218 	&dev_attr_state.attr,
219 	&dev_attr_cfg_services.attr,
220 	&dev_attr_pm_idle_enabled.attr,
221 	NULL,
222 };
223 
224 static struct attribute_group qat_group = {
225 	.attrs = qat_attrs,
226 	.name = "qat",
227 };
228 
229 int adf_sysfs_init(struct adf_accel_dev *accel_dev)
230 {
231 	int ret;
232 
233 	ret = devm_device_add_group(&GET_DEV(accel_dev), &qat_group);
234 	if (ret) {
235 		dev_err(&GET_DEV(accel_dev),
236 			"Failed to create qat attribute group: %d\n", ret);
237 	}
238 
239 	return ret;
240 }
241 EXPORT_SYMBOL_GPL(adf_sysfs_init);
242