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_cfg_services.h"
9 #include "adf_common_drv.h"
10 
11 static const char * const state_operations[] = {
12 	[DEV_DOWN] = "down",
13 	[DEV_UP] = "up",
14 };
15 
16 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
17 			  char *buf)
18 {
19 	struct adf_accel_dev *accel_dev;
20 	char *state;
21 
22 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
23 	if (!accel_dev)
24 		return -EINVAL;
25 
26 	state = adf_dev_started(accel_dev) ? "up" : "down";
27 	return sysfs_emit(buf, "%s\n", state);
28 }
29 
30 static ssize_t state_store(struct device *dev, struct device_attribute *attr,
31 			   const char *buf, size_t count)
32 {
33 	struct adf_accel_dev *accel_dev;
34 	u32 accel_id;
35 	int ret;
36 
37 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
38 	if (!accel_dev)
39 		return -EINVAL;
40 
41 	accel_id = accel_dev->accel_id;
42 
43 	if (adf_devmgr_in_reset(accel_dev) || adf_dev_in_use(accel_dev)) {
44 		dev_info(dev, "Device qat_dev%d is busy\n", accel_id);
45 		return -EBUSY;
46 	}
47 
48 	ret = sysfs_match_string(state_operations, buf);
49 	if (ret < 0)
50 		return ret;
51 
52 	switch (ret) {
53 	case DEV_DOWN:
54 		dev_info(dev, "Stopping device qat_dev%d\n", accel_id);
55 
56 		if (!adf_dev_started(accel_dev)) {
57 			dev_info(&GET_DEV(accel_dev), "Device qat_dev%d already down\n",
58 				 accel_id);
59 
60 			break;
61 		}
62 
63 		ret = adf_dev_down(accel_dev, true);
64 		if (ret < 0)
65 			return -EINVAL;
66 
67 		break;
68 	case DEV_UP:
69 		dev_info(dev, "Starting device qat_dev%d\n", accel_id);
70 
71 		ret = adf_dev_up(accel_dev, true);
72 		if (ret == -EALREADY) {
73 			break;
74 		} else if (ret) {
75 			dev_err(dev, "Failed to start device qat_dev%d\n",
76 				accel_id);
77 			adf_dev_down(accel_dev, true);
78 			return ret;
79 		}
80 		break;
81 	default:
82 		return -EINVAL;
83 	}
84 
85 	return count;
86 }
87 
88 static ssize_t cfg_services_show(struct device *dev, struct device_attribute *attr,
89 				 char *buf)
90 {
91 	char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0};
92 	struct adf_accel_dev *accel_dev;
93 	int ret;
94 
95 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
96 	if (!accel_dev)
97 		return -EINVAL;
98 
99 	ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
100 				      ADF_SERVICES_ENABLED, services);
101 	if (ret)
102 		return ret;
103 
104 	return sysfs_emit(buf, "%s\n", services);
105 }
106 
107 static int adf_sysfs_update_dev_config(struct adf_accel_dev *accel_dev,
108 				       const char *services)
109 {
110 	return adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
111 					   ADF_SERVICES_ENABLED, services,
112 					   ADF_STR);
113 }
114 
115 static ssize_t cfg_services_store(struct device *dev, struct device_attribute *attr,
116 				  const char *buf, size_t count)
117 {
118 	struct adf_hw_device_data *hw_data;
119 	struct adf_accel_dev *accel_dev;
120 	int ret;
121 
122 	ret = sysfs_match_string(adf_cfg_services, buf);
123 	if (ret < 0)
124 		return ret;
125 
126 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
127 	if (!accel_dev)
128 		return -EINVAL;
129 
130 	if (adf_dev_started(accel_dev)) {
131 		dev_info(dev, "Device qat_dev%d must be down to reconfigure the service.\n",
132 			 accel_dev->accel_id);
133 		return -EINVAL;
134 	}
135 
136 	ret = adf_sysfs_update_dev_config(accel_dev, adf_cfg_services[ret]);
137 	if (ret < 0)
138 		return ret;
139 
140 	hw_data = GET_HW_DATA(accel_dev);
141 
142 	/* Update capabilities mask after change in configuration.
143 	 * A call to this function is required as capabilities are, at the
144 	 * moment, tied to configuration
145 	 */
146 	hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev);
147 	if (!hw_data->accel_capabilities_mask)
148 		return -EINVAL;
149 
150 	return count;
151 }
152 
153 static ssize_t pm_idle_enabled_show(struct device *dev, struct device_attribute *attr,
154 				    char *buf)
155 {
156 	char pm_idle_enabled[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {};
157 	struct adf_accel_dev *accel_dev;
158 	int ret;
159 
160 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
161 	if (!accel_dev)
162 		return -EINVAL;
163 
164 	ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
165 				      ADF_PM_IDLE_SUPPORT, pm_idle_enabled);
166 	if (ret)
167 		return sysfs_emit(buf, "1\n");
168 
169 	return sysfs_emit(buf, "%s\n", pm_idle_enabled);
170 }
171 
172 static ssize_t pm_idle_enabled_store(struct device *dev, struct device_attribute *attr,
173 				     const char *buf, size_t count)
174 {
175 	unsigned long pm_idle_enabled_cfg_val;
176 	struct adf_accel_dev *accel_dev;
177 	bool pm_idle_enabled;
178 	int ret;
179 
180 	ret = kstrtobool(buf, &pm_idle_enabled);
181 	if (ret)
182 		return ret;
183 
184 	pm_idle_enabled_cfg_val = pm_idle_enabled;
185 	accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev));
186 	if (!accel_dev)
187 		return -EINVAL;
188 
189 	if (adf_dev_started(accel_dev)) {
190 		dev_info(dev, "Device qat_dev%d must be down to set pm_idle_enabled.\n",
191 			 accel_dev->accel_id);
192 		return -EINVAL;
193 	}
194 
195 	ret = adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC,
196 					  ADF_PM_IDLE_SUPPORT, &pm_idle_enabled_cfg_val,
197 					  ADF_DEC);
198 	if (ret)
199 		return ret;
200 
201 	return count;
202 }
203 static DEVICE_ATTR_RW(pm_idle_enabled);
204 
205 static DEVICE_ATTR_RW(state);
206 static DEVICE_ATTR_RW(cfg_services);
207 
208 static struct attribute *qat_attrs[] = {
209 	&dev_attr_state.attr,
210 	&dev_attr_cfg_services.attr,
211 	&dev_attr_pm_idle_enabled.attr,
212 	NULL,
213 };
214 
215 static struct attribute_group qat_group = {
216 	.attrs = qat_attrs,
217 	.name = "qat",
218 };
219 
220 int adf_sysfs_init(struct adf_accel_dev *accel_dev)
221 {
222 	int ret;
223 
224 	ret = devm_device_add_group(&GET_DEV(accel_dev), &qat_group);
225 	if (ret) {
226 		dev_err(&GET_DEV(accel_dev),
227 			"Failed to create qat attribute group: %d\n", ret);
228 	}
229 
230 	return ret;
231 }
232 EXPORT_SYMBOL_GPL(adf_sysfs_init);
233