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
14static 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 */
26static_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 */
33static_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 */
39static_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 */
45static_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
51static 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(nr: id, addr: &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
86static 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: buf + offset, size: len - offset,
97 ADF_SERVICES_DELIMITER);
98
99 offset += scnprintf(buf: buf + offset, size: len - offset, fmt: "%s",
100 adf_cfg_services[bit]);
101 }
102
103 return 0;
104}
105
106int adf_parse_service_string(struct adf_accel_dev *accel_dev, const char *in,
107 size_t in_len, char *out, size_t out_len)
108{
109 unsigned long mask;
110 int ret;
111
112 ret = adf_service_string_to_mask(accel_dev, buf: in, len: in_len, out_mask: &mask);
113 if (ret)
114 return ret;
115
116 if (!mask)
117 return -EINVAL;
118
119 return adf_service_mask_to_string(mask, buf: out, len: out_len);
120}
121
122int adf_get_service_mask(struct adf_accel_dev *accel_dev, unsigned long *mask)
123{
124 char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { };
125 size_t len;
126 int ret;
127
128 ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC,
129 ADF_SERVICES_ENABLED, value: services);
130 if (ret) {
131 dev_err(&GET_DEV(accel_dev), "%s param not found\n",
132 ADF_SERVICES_ENABLED);
133 return ret;
134 }
135
136 len = strnlen(p: services, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
137 ret = adf_service_string_to_mask(accel_dev, buf: services, len, out_mask: mask);
138 if (ret)
139 dev_err(&GET_DEV(accel_dev), "Invalid value of %s param: %s\n",
140 ADF_SERVICES_ENABLED, services);
141
142 return ret;
143}
144EXPORT_SYMBOL_GPL(adf_get_service_mask);
145
146int adf_get_service_enabled(struct adf_accel_dev *accel_dev)
147{
148 unsigned long mask;
149 int ret;
150
151 ret = adf_get_service_mask(accel_dev, &mask);
152 if (ret)
153 return ret;
154
155 if (test_bit(SVC_SYM, &mask) && test_bit(SVC_ASYM, &mask))
156 return SVC_SYM_ASYM;
157
158 if (test_bit(SVC_SYM, &mask) && test_bit(SVC_DC, &mask))
159 return SVC_SYM_DC;
160
161 if (test_bit(SVC_ASYM, &mask) && test_bit(SVC_DC, &mask))
162 return SVC_ASYM_DC;
163
164 if (test_bit(SVC_SYM, &mask))
165 return SVC_SYM;
166
167 if (test_bit(SVC_ASYM, &mask))
168 return SVC_ASYM;
169
170 if (test_bit(SVC_DC, &mask))
171 return SVC_DC;
172
173 if (test_bit(SVC_DECOMP, &mask))
174 return SVC_DECOMP;
175
176 if (test_bit(SVC_DCC, &mask))
177 return SVC_DCC;
178
179 return -EINVAL;
180}
181EXPORT_SYMBOL_GPL(adf_get_service_enabled);
182
183enum adf_cfg_service_type adf_srv_to_cfg_svc_type(enum adf_base_services svc)
184{
185 switch (svc) {
186 case SVC_ASYM:
187 return ASYM;
188 case SVC_SYM:
189 return SYM;
190 case SVC_DC:
191 return COMP;
192 case SVC_DECOMP:
193 return DECOMP;
194 default:
195 return UNUSED;
196 }
197}
198
199bool adf_is_service_enabled(struct adf_accel_dev *accel_dev, enum adf_base_services svc)
200{
201 enum adf_cfg_service_type arb_srv = adf_srv_to_cfg_svc_type(svc);
202 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
203 u8 rps_per_bundle = hw_data->num_banks_per_vf;
204 int i;
205
206 for (i = 0; i < rps_per_bundle; i++) {
207 if (GET_SRV_TYPE(accel_dev, i) == arb_srv)
208 return true;
209 }
210
211 return false;
212}
213

source code of linux/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c