xref: /linux/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c (revision b8ea7da314c2efcb9c2f559ed65b7a36c869d68e)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2023 Intel Corporation */
3 
4 #include <linux/array_size.h>
5 #include <linux/bitops.h>
6 #include <linux/export.h>
7 #include <linux/pci.h>
8 #include <linux/string.h>
9 #include "adf_cfg.h"
10 #include "adf_cfg_common.h"
11 #include "adf_cfg_services.h"
12 #include "adf_cfg_strings.h"
13 
14 static const char *const adf_cfg_services[] = {
15 	[SVC_ASYM] = ADF_CFG_ASYM,
16 	[SVC_SYM] = ADF_CFG_SYM,
17 	[SVC_DC] = ADF_CFG_DC,
18 	[SVC_DCC] = ADF_CFG_DCC,
19 	[SVC_DECOMP] = ADF_CFG_DECOMP,
20 };
21 
22 /*
23  * Ensure that the size of the array matches the number of services,
24  * SVC_COUNT, that is used to size the bitmap.
25  */
26 static_assert(ARRAY_SIZE(adf_cfg_services) == SVC_COUNT);
27 
28 /*
29  * Ensure that the maximum number of concurrent services that can be
30  * enabled on a device is less than or equal to the number of total
31  * supported services.
32  */
33 static_assert(ARRAY_SIZE(adf_cfg_services) >= MAX_NUM_CONCURR_SVC);
34 
35 /*
36  * Ensure that the number of services fit a single unsigned long, as each
37  * service is represented by a bit in the mask.
38  */
39 static_assert(BITS_PER_LONG >= SVC_COUNT);
40 
41 /*
42  * Ensure that size of the concatenation of all service strings is smaller
43  * than the size of the buffer that will contain them.
44  */
45 static_assert(sizeof(ADF_CFG_SYM ADF_SERVICES_DELIMITER
46 		     ADF_CFG_ASYM ADF_SERVICES_DELIMITER
47 		     ADF_CFG_DC ADF_SERVICES_DELIMITER
48 		     ADF_CFG_DECOMP ADF_SERVICES_DELIMITER
49 		     ADF_CFG_DCC) < ADF_CFG_MAX_VAL_LEN_IN_BYTES);
50 
51 static int adf_service_string_to_mask(struct adf_accel_dev *accel_dev, const char *buf,
52 				      size_t len, unsigned long *out_mask)
53 {
54 	struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
55 	char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { };
56 	unsigned long mask = 0;
57 	char *substr, *token;
58 	int id, num_svc = 0;
59 
60 	if (len > ADF_CFG_MAX_VAL_LEN_IN_BYTES - 1)
61 		return -EINVAL;
62 
63 	strscpy(services, buf, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
64 	substr = services;
65 
66 	while ((token = strsep(&substr, ADF_SERVICES_DELIMITER))) {
67 		id = sysfs_match_string(adf_cfg_services, token);
68 		if (id < 0)
69 			return id;
70 
71 		if (test_and_set_bit(id, &mask))
72 			return -EINVAL;
73 
74 		if (num_svc++ == MAX_NUM_CONCURR_SVC)
75 			return -EINVAL;
76 	}
77 
78 	if (hw_data->services_supported && !hw_data->services_supported(mask))
79 		return -EINVAL;
80 
81 	*out_mask = mask;
82 
83 	return 0;
84 }
85 
86 static int adf_service_mask_to_string(unsigned long mask, char *buf, size_t len)
87 {
88 	int offset = 0;
89 	int bit;
90 
91 	if (len < ADF_CFG_MAX_VAL_LEN_IN_BYTES)
92 		return -ENOSPC;
93 
94 	for_each_set_bit(bit, &mask, SVC_COUNT) {
95 		if (offset)
96 			offset += scnprintf(buf + offset, len - offset,
97 				ADF_SERVICES_DELIMITER "%s", adf_cfg_services[bit]);
98 		else
99 			offset += scnprintf(buf, len, "%s", adf_cfg_services[bit]);
100 	}
101 
102 	return 0;
103 }
104 
105 int adf_parse_service_string(struct adf_accel_dev *accel_dev, const char *in,
106 			     size_t in_len, char *out, size_t out_len)
107 {
108 	unsigned long mask;
109 	int ret;
110 
111 	ret = adf_service_string_to_mask(accel_dev, in, in_len, &mask);
112 	if (ret)
113 		return ret;
114 
115 	if (!mask)
116 		return -EINVAL;
117 
118 	return adf_service_mask_to_string(mask, out, out_len);
119 }
120 
121 int adf_get_service_mask(struct adf_accel_dev *accel_dev, unsigned long *mask)
122 {
123 	char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { };
124 	size_t len;
125 	int ret;
126 
127 	ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
128 				      ADF_SERVICES_ENABLED, services);
129 	if (ret) {
130 		dev_err(&GET_DEV(accel_dev), "%s param not found\n",
131 			ADF_SERVICES_ENABLED);
132 		return ret;
133 	}
134 
135 	len = strnlen(services, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
136 	ret = adf_service_string_to_mask(accel_dev, services, len, mask);
137 	if (ret)
138 		dev_err(&GET_DEV(accel_dev), "Invalid value of %s param: %s\n",
139 			ADF_SERVICES_ENABLED, services);
140 
141 	return ret;
142 }
143 EXPORT_SYMBOL_GPL(adf_get_service_mask);
144 
145 int adf_get_service_enabled(struct adf_accel_dev *accel_dev)
146 {
147 	unsigned long mask;
148 	int ret;
149 
150 	ret = adf_get_service_mask(accel_dev, &mask);
151 	if (ret)
152 		return ret;
153 
154 	if (test_bit(SVC_SYM, &mask) && test_bit(SVC_ASYM, &mask))
155 		return SVC_SYM_ASYM;
156 
157 	if (test_bit(SVC_SYM, &mask) && test_bit(SVC_DC, &mask))
158 		return SVC_SYM_DC;
159 
160 	if (test_bit(SVC_ASYM, &mask) && test_bit(SVC_DC, &mask))
161 		return SVC_ASYM_DC;
162 
163 	if (test_bit(SVC_SYM, &mask))
164 		return SVC_SYM;
165 
166 	if (test_bit(SVC_ASYM, &mask))
167 		return SVC_ASYM;
168 
169 	if (test_bit(SVC_DC, &mask))
170 		return SVC_DC;
171 
172 	if (test_bit(SVC_DECOMP, &mask))
173 		return SVC_DECOMP;
174 
175 	if (test_bit(SVC_DCC, &mask))
176 		return SVC_DCC;
177 
178 	return -EINVAL;
179 }
180 EXPORT_SYMBOL_GPL(adf_get_service_enabled);
181 
182 enum adf_cfg_service_type adf_srv_to_cfg_svc_type(enum adf_base_services svc)
183 {
184 	switch (svc) {
185 	case SVC_ASYM:
186 		return ASYM;
187 	case SVC_SYM:
188 		return SYM;
189 	case SVC_DC:
190 		return COMP;
191 	case SVC_DECOMP:
192 		return DECOMP;
193 	default:
194 		return UNUSED;
195 	}
196 }
197 
198 bool adf_is_service_enabled(struct adf_accel_dev *accel_dev, enum adf_base_services svc)
199 {
200 	enum adf_cfg_service_type arb_srv = adf_srv_to_cfg_svc_type(svc);
201 	struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
202 	u8 rps_per_bundle = hw_data->num_banks_per_vf;
203 	int i;
204 
205 	for (i = 0; i < rps_per_bundle; i++) {
206 		if (GET_SRV_TYPE(accel_dev, i) == arb_srv)
207 			return true;
208 	}
209 
210 	return false;
211 }
212