blob: ac37a89965acb6afa936c4949eb84b81bdca9d74 [file] [log] [blame]
Tadeusz Strukd8cba252014-06-05 13:42:39 -07001/*
2 This file is provided under a dual BSD/GPLv2 license. When using or
3 redistributing this file, you may do so under either license.
4
5 GPL LICENSE SUMMARY
6 Copyright(c) 2014 Intel Corporation.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of version 2 of the GNU General Public License as
9 published by the Free Software Foundation.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 Contact Information:
17 qat-linux@intel.com
18
19 BSD LICENSE
20 Copyright(c) 2014 Intel Corporation.
21 Redistribution and use in source and binary forms, with or without
22 modification, are permitted provided that the following conditions
23 are met:
24
25 * Redistributions of source code must retain the above copyright
26 notice, this list of conditions and the following disclaimer.
27 * Redistributions in binary form must reproduce the above copyright
28 notice, this list of conditions and the following disclaimer in
29 the documentation and/or other materials provided with the
30 distribution.
31 * Neither the name of Intel Corporation nor the names of its
32 contributors may be used to endorse or promote products derived
33 from this software without specific prior written permission.
34
35 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46*/
47#include <linux/mutex.h>
48#include <linux/list.h>
49#include <linux/bitops.h>
50#include <linux/delay.h>
51#include "adf_accel_devices.h"
52#include "adf_cfg.h"
53#include "adf_common_drv.h"
54
55static LIST_HEAD(service_table);
56static DEFINE_MUTEX(service_lock);
57
58static void adf_service_add(struct service_hndl *service)
59{
60 mutex_lock(&service_lock);
61 list_add(&service->list, &service_table);
62 mutex_unlock(&service_lock);
63}
64
65/**
66 * adf_service_register() - Register acceleration service in the accel framework
67 * @service: Pointer to the service
68 *
69 * Function adds the acceleration service to the acceleration framework.
70 * To be used by QAT device specific drivers.
71 *
Ahsan Attaec0d6fa2015-07-24 13:18:26 -070072 * Return: 0 on success, error code otherwise.
Tadeusz Strukd8cba252014-06-05 13:42:39 -070073 */
74int adf_service_register(struct service_hndl *service)
75{
76 service->init_status = 0;
77 service->start_status = 0;
78 adf_service_add(service);
79 return 0;
80}
81EXPORT_SYMBOL_GPL(adf_service_register);
82
83static void adf_service_remove(struct service_hndl *service)
84{
85 mutex_lock(&service_lock);
86 list_del(&service->list);
87 mutex_unlock(&service_lock);
88}
89
90/**
91 * adf_service_unregister() - Unregister acceleration service from the framework
92 * @service: Pointer to the service
93 *
94 * Function remove the acceleration service from the acceleration framework.
95 * To be used by QAT device specific drivers.
96 *
Ahsan Attaec0d6fa2015-07-24 13:18:26 -070097 * Return: 0 on success, error code otherwise.
Tadeusz Strukd8cba252014-06-05 13:42:39 -070098 */
99int adf_service_unregister(struct service_hndl *service)
100{
101 if (service->init_status || service->start_status) {
102 pr_err("QAT: Could not remove active service\n");
103 return -EFAULT;
104 }
105 adf_service_remove(service);
106 return 0;
107}
108EXPORT_SYMBOL_GPL(adf_service_unregister);
109
110/**
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800111 * adf_dev_init() - Init data structures and services for the given accel device
112 * @accel_dev: Pointer to acceleration device.
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700113 *
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800114 * Initialize the ring data structures and the admin comms and arbitration
115 * services.
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700116 *
Ahsan Attaec0d6fa2015-07-24 13:18:26 -0700117 * Return: 0 on success, error code otherwise.
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700118 */
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800119int adf_dev_init(struct adf_accel_dev *accel_dev)
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700120{
121 struct service_hndl *service;
122 struct list_head *list_itr;
123 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
124
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800125 if (!hw_data) {
126 dev_err(&GET_DEV(accel_dev),
Allan, Bruce W66550302015-03-19 16:03:44 -0700127 "Failed to init device - hw_data not set\n");
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800128 return -EFAULT;
129 }
130
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700131 if (!test_bit(ADF_STATUS_CONFIGURED, &accel_dev->status)) {
Allan, Bruce W66550302015-03-19 16:03:44 -0700132 dev_err(&GET_DEV(accel_dev), "Device not configured\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700133 return -EFAULT;
134 }
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800135
136 if (adf_init_etr_data(accel_dev)) {
137 dev_err(&GET_DEV(accel_dev), "Failed initialize etr\n");
138 return -EFAULT;
139 }
140
141 if (hw_data->init_admin_comms && hw_data->init_admin_comms(accel_dev)) {
142 dev_err(&GET_DEV(accel_dev), "Failed initialize admin comms\n");
143 return -EFAULT;
144 }
145
146 if (hw_data->init_arb && hw_data->init_arb(accel_dev)) {
147 dev_err(&GET_DEV(accel_dev), "Failed initialize hw arbiter\n");
148 return -EFAULT;
149 }
150
151 hw_data->enable_ints(accel_dev);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700152
153 if (adf_ae_init(accel_dev)) {
Allan, Bruce W66550302015-03-19 16:03:44 -0700154 dev_err(&GET_DEV(accel_dev),
155 "Failed to initialise Acceleration Engine\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700156 return -EFAULT;
157 }
158 set_bit(ADF_STATUS_AE_INITIALISED, &accel_dev->status);
159
160 if (adf_ae_fw_load(accel_dev)) {
Allan, Bruce W66550302015-03-19 16:03:44 -0700161 dev_err(&GET_DEV(accel_dev),
162 "Failed to load acceleration FW\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700163 return -EFAULT;
164 }
165 set_bit(ADF_STATUS_AE_UCODE_LOADED, &accel_dev->status);
166
167 if (hw_data->alloc_irq(accel_dev)) {
Allan, Bruce W66550302015-03-19 16:03:44 -0700168 dev_err(&GET_DEV(accel_dev), "Failed to allocate interrupts\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700169 return -EFAULT;
170 }
171 set_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status);
172
173 /*
174 * Subservice initialisation is divided into two stages: init and start.
175 * This is to facilitate any ordering dependencies between services
176 * prior to starting any of the accelerators.
177 */
178 list_for_each(list_itr, &service_table) {
179 service = list_entry(list_itr, struct service_hndl, list);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700180 if (service->event_hld(accel_dev, ADF_EVENT_INIT)) {
Allan, Bruce W66550302015-03-19 16:03:44 -0700181 dev_err(&GET_DEV(accel_dev),
182 "Failed to initialise service %s\n",
183 service->name);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700184 return -EFAULT;
185 }
186 set_bit(accel_dev->accel_id, &service->init_status);
187 }
188
189 hw_data->enable_error_correction(accel_dev);
Tadeusz Struked8ccae2015-08-07 11:34:25 -0700190 hw_data->enable_vf2pf_comms(accel_dev);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700191
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800192 return 0;
193}
194EXPORT_SYMBOL_GPL(adf_dev_init);
195
196/**
197 * adf_dev_start() - Start acceleration service for the given accel device
198 * @accel_dev: Pointer to acceleration device.
199 *
200 * Function notifies all the registered services that the acceleration device
201 * is ready to be used.
202 * To be used by QAT device specific drivers.
203 *
Ahsan Attaec0d6fa2015-07-24 13:18:26 -0700204 * Return: 0 on success, error code otherwise.
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800205 */
206int adf_dev_start(struct adf_accel_dev *accel_dev)
207{
Tadeusz Struka5733132015-08-07 11:34:20 -0700208 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800209 struct service_hndl *service;
210 struct list_head *list_itr;
211
212 set_bit(ADF_STATUS_STARTING, &accel_dev->status);
213
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700214 if (adf_ae_start(accel_dev)) {
Allan, Bruce W66550302015-03-19 16:03:44 -0700215 dev_err(&GET_DEV(accel_dev), "AE Start Failed\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700216 return -EFAULT;
217 }
218 set_bit(ADF_STATUS_AE_STARTED, &accel_dev->status);
219
Tadeusz Struka5733132015-08-07 11:34:20 -0700220 if (hw_data->send_admin_init(accel_dev)) {
221 dev_err(&GET_DEV(accel_dev), "Failed to send init message\n");
222 return -EFAULT;
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700223 }
Tadeusz Struka5733132015-08-07 11:34:20 -0700224
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700225 list_for_each(list_itr, &service_table) {
226 service = list_entry(list_itr, struct service_hndl, list);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700227 if (service->event_hld(accel_dev, ADF_EVENT_START)) {
Allan, Bruce W66550302015-03-19 16:03:44 -0700228 dev_err(&GET_DEV(accel_dev),
229 "Failed to start service %s\n",
230 service->name);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700231 return -EFAULT;
232 }
233 set_bit(accel_dev->accel_id, &service->start_status);
234 }
235
236 clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
237 set_bit(ADF_STATUS_STARTED, &accel_dev->status);
238
Tadeusz Struked8ccae2015-08-07 11:34:25 -0700239 if (!list_empty(&accel_dev->crypto_list) &&
240 (qat_algs_register() || qat_asym_algs_register())) {
Allan, Bruce W66550302015-03-19 16:03:44 -0700241 dev_err(&GET_DEV(accel_dev),
242 "Failed to register crypto algs\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700243 set_bit(ADF_STATUS_STARTING, &accel_dev->status);
244 clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
245 return -EFAULT;
246 }
247 return 0;
248}
249EXPORT_SYMBOL_GPL(adf_dev_start);
250
251/**
252 * adf_dev_stop() - Stop acceleration service for the given accel device
253 * @accel_dev: Pointer to acceleration device.
254 *
255 * Function notifies all the registered services that the acceleration device
256 * is shuting down.
257 * To be used by QAT device specific drivers.
258 *
Ahsan Attaec0d6fa2015-07-24 13:18:26 -0700259 * Return: 0 on success, error code otherwise.
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700260 */
261int adf_dev_stop(struct adf_accel_dev *accel_dev)
262{
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700263 struct service_hndl *service;
264 struct list_head *list_itr;
Allan, Bruce W53bc02512015-01-09 11:55:04 -0800265 bool wait = false;
266 int ret;
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700267
268 if (!adf_dev_started(accel_dev) &&
269 !test_bit(ADF_STATUS_STARTING, &accel_dev->status)) {
270 return 0;
271 }
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700272 clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
273 clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
274
Tadeusz Struked8ccae2015-08-07 11:34:25 -0700275 if (!list_empty(&accel_dev->crypto_list) && qat_algs_unregister())
Allan, Bruce W66550302015-03-19 16:03:44 -0700276 dev_err(&GET_DEV(accel_dev),
277 "Failed to unregister crypto algs\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700278
Tadeusz Struked8ccae2015-08-07 11:34:25 -0700279 if (!list_empty(&accel_dev->crypto_list))
280 qat_asym_algs_unregister();
Tadeusz Struka9905322015-07-15 15:28:38 -0700281
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700282 list_for_each(list_itr, &service_table) {
283 service = list_entry(list_itr, struct service_hndl, list);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700284 if (!test_bit(accel_dev->accel_id, &service->start_status))
285 continue;
286 ret = service->event_hld(accel_dev, ADF_EVENT_STOP);
287 if (!ret) {
288 clear_bit(accel_dev->accel_id, &service->start_status);
289 } else if (ret == -EAGAIN) {
Allan, Bruce W53bc02512015-01-09 11:55:04 -0800290 wait = true;
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700291 clear_bit(accel_dev->accel_id, &service->start_status);
292 }
293 }
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700294
295 if (wait)
296 msleep(100);
297
Allan, Bruce Wfd98d692015-01-09 11:55:09 -0800298 if (test_bit(ADF_STATUS_AE_STARTED, &accel_dev->status)) {
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700299 if (adf_ae_stop(accel_dev))
Allan, Bruce W66550302015-03-19 16:03:44 -0700300 dev_err(&GET_DEV(accel_dev), "failed to stop AE\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700301 else
302 clear_bit(ADF_STATUS_AE_STARTED, &accel_dev->status);
303 }
304
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800305 return 0;
306}
307EXPORT_SYMBOL_GPL(adf_dev_stop);
308
309/**
310 * adf_dev_shutdown() - shutdown acceleration services and data strucutures
311 * @accel_dev: Pointer to acceleration device
312 *
313 * Cleanup the ring data structures and the admin comms and arbitration
314 * services.
315 */
316void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
317{
318 struct adf_hw_device_data *hw_data = accel_dev->hw_device;
319 struct service_hndl *service;
320 struct list_head *list_itr;
321
322 if (!hw_data) {
323 dev_err(&GET_DEV(accel_dev),
324 "QAT: Failed to shutdown device - hw_data not set\n");
325 return;
326 }
327
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700328 if (test_bit(ADF_STATUS_AE_UCODE_LOADED, &accel_dev->status)) {
Tadeusz Strukb4e97052015-04-03 08:41:17 -0700329 adf_ae_fw_release(accel_dev);
330 clear_bit(ADF_STATUS_AE_UCODE_LOADED, &accel_dev->status);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700331 }
332
333 if (test_bit(ADF_STATUS_AE_INITIALISED, &accel_dev->status)) {
334 if (adf_ae_shutdown(accel_dev))
Allan, Bruce W66550302015-03-19 16:03:44 -0700335 dev_err(&GET_DEV(accel_dev),
336 "Failed to shutdown Accel Engine\n");
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700337 else
338 clear_bit(ADF_STATUS_AE_INITIALISED,
339 &accel_dev->status);
340 }
341
342 list_for_each(list_itr, &service_table) {
343 service = list_entry(list_itr, struct service_hndl, list);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700344 if (!test_bit(accel_dev->accel_id, &service->init_status))
345 continue;
346 if (service->event_hld(accel_dev, ADF_EVENT_SHUTDOWN))
Allan, Bruce W66550302015-03-19 16:03:44 -0700347 dev_err(&GET_DEV(accel_dev),
348 "Failed to shutdown service %s\n",
349 service->name);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700350 else
351 clear_bit(accel_dev->accel_id, &service->init_status);
352 }
353
354 if (test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status)) {
355 hw_data->free_irq(accel_dev);
356 clear_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status);
357 }
358
359 /* Delete configuration only if not restarting */
360 if (!test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
361 adf_cfg_del_all(accel_dev);
362
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800363 if (hw_data->exit_arb)
364 hw_data->exit_arb(accel_dev);
365
366 if (hw_data->exit_admin_comms)
367 hw_data->exit_admin_comms(accel_dev);
368
Tadeusz Struked8ccae2015-08-07 11:34:25 -0700369 hw_data->disable_iov(accel_dev);
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800370 adf_cleanup_etr_data(accel_dev);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700371}
Allan, Bruce W22e4dda2015-01-09 11:54:58 -0800372EXPORT_SYMBOL_GPL(adf_dev_shutdown);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700373
374int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev)
375{
376 struct service_hndl *service;
377 struct list_head *list_itr;
378
379 list_for_each(list_itr, &service_table) {
380 service = list_entry(list_itr, struct service_hndl, list);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700381 if (service->event_hld(accel_dev, ADF_EVENT_RESTARTING))
Allan, Bruce W66550302015-03-19 16:03:44 -0700382 dev_err(&GET_DEV(accel_dev),
383 "Failed to restart service %s.\n",
384 service->name);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700385 }
386 return 0;
387}
388
389int adf_dev_restarted_notify(struct adf_accel_dev *accel_dev)
390{
391 struct service_hndl *service;
392 struct list_head *list_itr;
393
394 list_for_each(list_itr, &service_table) {
395 service = list_entry(list_itr, struct service_hndl, list);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700396 if (service->event_hld(accel_dev, ADF_EVENT_RESTARTED))
Allan, Bruce W66550302015-03-19 16:03:44 -0700397 dev_err(&GET_DEV(accel_dev),
398 "Failed to restart service %s.\n",
399 service->name);
Tadeusz Strukd8cba252014-06-05 13:42:39 -0700400 }
401 return 0;
402}