blob: 5348512da643dd49df008cff3e67eee447c314a1 [file] [log] [blame]
Tom Lendacky63b94502013-11-12 11:46:16 -06001/*
2 * AMD Cryptographic Coprocessor (CCP) driver
3 *
Gary R Hook3f19ce22016-03-01 13:48:54 -06004 * Copyright (C) 2013,2016 Advanced Micro Devices, Inc.
Tom Lendacky63b94502013-11-12 11:46:16 -06005 *
6 * Author: Tom Lendacky <thomas.lendacky@amd.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/kthread.h>
16#include <linux/sched.h>
17#include <linux/interrupt.h>
18#include <linux/spinlock.h>
Gary R Hook553d2372016-03-01 13:49:04 -060019#include <linux/rwlock_types.h>
20#include <linux/types.h>
Tom Lendacky63b94502013-11-12 11:46:16 -060021#include <linux/mutex.h>
22#include <linux/delay.h>
23#include <linux/hw_random.h>
24#include <linux/cpu.h>
Tom Lendackyc4f4b322014-06-05 10:17:57 -050025#ifdef CONFIG_X86
Tom Lendacky63b94502013-11-12 11:46:16 -060026#include <asm/cpu_device_id.h>
Tom Lendackyc4f4b322014-06-05 10:17:57 -050027#endif
Tom Lendacky63b94502013-11-12 11:46:16 -060028#include <linux/ccp.h>
29
30#include "ccp-dev.h"
31
32MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
33MODULE_LICENSE("GPL");
34MODULE_VERSION("1.0.0");
35MODULE_DESCRIPTION("AMD Cryptographic Coprocessor driver");
36
Tom Lendacky530abd82014-01-24 16:18:14 -060037struct ccp_tasklet_data {
38 struct completion completion;
39 struct ccp_cmd *cmd;
40};
41
Gary R Hook553d2372016-03-01 13:49:04 -060042/* List of CCPs, CCP count, read-write access lock, and access functions
43 *
44 * Lock structure: get ccp_unit_lock for reading whenever we need to
45 * examine the CCP list. While holding it for reading we can acquire
46 * the RR lock to update the round-robin next-CCP pointer. The unit lock
47 * must be acquired before the RR lock.
48 *
49 * If the unit-lock is acquired for writing, we have total control over
50 * the list, so there's no value in getting the RR lock.
51 */
52static DEFINE_RWLOCK(ccp_unit_lock);
53static LIST_HEAD(ccp_units);
54
55/* Round-robin counter */
56static DEFINE_RWLOCK(ccp_rr_lock);
57static struct ccp_device *ccp_rr;
58
59/* Ever-increasing value to produce unique unit numbers */
60static atomic_t ccp_unit_ordinal;
61unsigned int ccp_increment_unit_ordinal(void)
Tom Lendacky63b94502013-11-12 11:46:16 -060062{
Gary R Hook553d2372016-03-01 13:49:04 -060063 return atomic_inc_return(&ccp_unit_ordinal);
Tom Lendacky63b94502013-11-12 11:46:16 -060064}
65
Gary R Hook553d2372016-03-01 13:49:04 -060066/*
67 * Put this CCP on the unit list, which makes it available
68 * for use.
69 */
Tom Lendacky63b94502013-11-12 11:46:16 -060070static inline void ccp_add_device(struct ccp_device *ccp)
71{
Gary R Hook553d2372016-03-01 13:49:04 -060072 unsigned long flags;
73
74 write_lock_irqsave(&ccp_unit_lock, flags);
75 list_add_tail(&ccp->entry, &ccp_units);
76 if (!ccp_rr)
77 /* We already have the list lock (we're first) so this
78 * pointer can't change on us. Set its initial value.
79 */
80 ccp_rr = ccp;
81 write_unlock_irqrestore(&ccp_unit_lock, flags);
Tom Lendacky63b94502013-11-12 11:46:16 -060082}
83
Gary R Hook553d2372016-03-01 13:49:04 -060084/* Remove this unit from the list of devices. If the next device
85 * up for use is this one, adjust the pointer. If this is the last
86 * device, NULL the pointer.
87 */
Tom Lendacky63b94502013-11-12 11:46:16 -060088static inline void ccp_del_device(struct ccp_device *ccp)
89{
Gary R Hook553d2372016-03-01 13:49:04 -060090 unsigned long flags;
91
92 write_lock_irqsave(&ccp_unit_lock, flags);
93 if (ccp_rr == ccp) {
94 /* ccp_unit_lock is read/write; any read access
95 * will be suspended while we make changes to the
96 * list and RR pointer.
97 */
98 if (list_is_last(&ccp_rr->entry, &ccp_units))
99 ccp_rr = list_first_entry(&ccp_units, struct ccp_device,
100 entry);
101 else
102 ccp_rr = list_next_entry(ccp_rr, entry);
103 }
104 list_del(&ccp->entry);
105 if (list_empty(&ccp_units))
106 ccp_rr = NULL;
107 write_unlock_irqrestore(&ccp_unit_lock, flags);
108}
109
110static struct ccp_device *ccp_get_device(void)
111{
112 unsigned long flags;
113 struct ccp_device *dp = NULL;
114
115 /* We round-robin through the unit list.
116 * The (ccp_rr) pointer refers to the next unit to use.
117 */
118 read_lock_irqsave(&ccp_unit_lock, flags);
119 if (!list_empty(&ccp_units)) {
120 write_lock_irqsave(&ccp_rr_lock, flags);
121 dp = ccp_rr;
122 if (list_is_last(&ccp_rr->entry, &ccp_units))
123 ccp_rr = list_first_entry(&ccp_units, struct ccp_device,
124 entry);
125 else
126 ccp_rr = list_next_entry(ccp_rr, entry);
127 write_unlock_irqrestore(&ccp_rr_lock, flags);
128 }
129 read_unlock_irqrestore(&ccp_unit_lock, flags);
130
131 return dp;
Tom Lendacky63b94502013-11-12 11:46:16 -0600132}
133
134/**
Tom Lendackyc9f21cb2014-09-05 10:31:09 -0500135 * ccp_present - check if a CCP device is present
136 *
137 * Returns zero if a CCP device is present, -ENODEV otherwise.
138 */
139int ccp_present(void)
140{
Gary R Hook553d2372016-03-01 13:49:04 -0600141 unsigned long flags;
142 int ret;
Tom Lendackyc9f21cb2014-09-05 10:31:09 -0500143
Gary R Hook553d2372016-03-01 13:49:04 -0600144 read_lock_irqsave(&ccp_unit_lock, flags);
145 ret = list_empty(&ccp_units);
146 read_unlock_irqrestore(&ccp_unit_lock, flags);
147
148 return ret ? -ENODEV : 0;
Tom Lendackyc9f21cb2014-09-05 10:31:09 -0500149}
150EXPORT_SYMBOL_GPL(ccp_present);
151
152/**
Gary R Hookc7019c42016-03-01 13:49:15 -0600153 * ccp_version - get the version of the CCP device
154 *
155 * Returns the version from the first unit on the list;
156 * otherwise a zero if no CCP device is present
157 */
158unsigned int ccp_version(void)
159{
160 struct ccp_device *dp;
161 unsigned long flags;
162 int ret = 0;
163
164 read_lock_irqsave(&ccp_unit_lock, flags);
165 if (!list_empty(&ccp_units)) {
166 dp = list_first_entry(&ccp_units, struct ccp_device, entry);
167 ret = dp->vdata->version;
168 }
169 read_unlock_irqrestore(&ccp_unit_lock, flags);
170
171 return ret;
172}
173EXPORT_SYMBOL_GPL(ccp_version);
174
175/**
Tom Lendacky63b94502013-11-12 11:46:16 -0600176 * ccp_enqueue_cmd - queue an operation for processing by the CCP
177 *
178 * @cmd: ccp_cmd struct to be processed
179 *
180 * Queue a cmd to be processed by the CCP. If queueing the cmd
181 * would exceed the defined length of the cmd queue the cmd will
182 * only be queued if the CCP_CMD_MAY_BACKLOG flag is set and will
183 * result in a return code of -EBUSY.
184 *
185 * The callback routine specified in the ccp_cmd struct will be
186 * called to notify the caller of completion (if the cmd was not
187 * backlogged) or advancement out of the backlog. If the cmd has
188 * advanced out of the backlog the "err" value of the callback
189 * will be -EINPROGRESS. Any other "err" value during callback is
190 * the result of the operation.
191 *
192 * The cmd has been successfully queued if:
193 * the return code is -EINPROGRESS or
194 * the return code is -EBUSY and CCP_CMD_MAY_BACKLOG flag is set
195 */
196int ccp_enqueue_cmd(struct ccp_cmd *cmd)
197{
198 struct ccp_device *ccp = ccp_get_device();
199 unsigned long flags;
200 unsigned int i;
201 int ret;
202
203 if (!ccp)
204 return -ENODEV;
205
206 /* Caller must supply a callback routine */
207 if (!cmd->callback)
208 return -EINVAL;
209
210 cmd->ccp = ccp;
211
212 spin_lock_irqsave(&ccp->cmd_lock, flags);
213
214 i = ccp->cmd_q_count;
215
216 if (ccp->cmd_count >= MAX_CMD_QLEN) {
217 ret = -EBUSY;
218 if (cmd->flags & CCP_CMD_MAY_BACKLOG)
219 list_add_tail(&cmd->entry, &ccp->backlog);
220 } else {
221 ret = -EINPROGRESS;
222 ccp->cmd_count++;
223 list_add_tail(&cmd->entry, &ccp->cmd);
224
225 /* Find an idle queue */
226 if (!ccp->suspending) {
227 for (i = 0; i < ccp->cmd_q_count; i++) {
228 if (ccp->cmd_q[i].active)
229 continue;
230
231 break;
232 }
233 }
234 }
235
236 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
237
238 /* If we found an idle queue, wake it up */
239 if (i < ccp->cmd_q_count)
240 wake_up_process(ccp->cmd_q[i].kthread);
241
242 return ret;
243}
244EXPORT_SYMBOL_GPL(ccp_enqueue_cmd);
245
246static void ccp_do_cmd_backlog(struct work_struct *work)
247{
248 struct ccp_cmd *cmd = container_of(work, struct ccp_cmd, work);
249 struct ccp_device *ccp = cmd->ccp;
250 unsigned long flags;
251 unsigned int i;
252
253 cmd->callback(cmd->data, -EINPROGRESS);
254
255 spin_lock_irqsave(&ccp->cmd_lock, flags);
256
257 ccp->cmd_count++;
258 list_add_tail(&cmd->entry, &ccp->cmd);
259
260 /* Find an idle queue */
261 for (i = 0; i < ccp->cmd_q_count; i++) {
262 if (ccp->cmd_q[i].active)
263 continue;
264
265 break;
266 }
267
268 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
269
270 /* If we found an idle queue, wake it up */
271 if (i < ccp->cmd_q_count)
272 wake_up_process(ccp->cmd_q[i].kthread);
273}
274
275static struct ccp_cmd *ccp_dequeue_cmd(struct ccp_cmd_queue *cmd_q)
276{
277 struct ccp_device *ccp = cmd_q->ccp;
278 struct ccp_cmd *cmd = NULL;
279 struct ccp_cmd *backlog = NULL;
280 unsigned long flags;
281
282 spin_lock_irqsave(&ccp->cmd_lock, flags);
283
284 cmd_q->active = 0;
285
286 if (ccp->suspending) {
287 cmd_q->suspended = 1;
288
289 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
290 wake_up_interruptible(&ccp->suspend_queue);
291
292 return NULL;
293 }
294
295 if (ccp->cmd_count) {
296 cmd_q->active = 1;
297
298 cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
299 list_del(&cmd->entry);
300
301 ccp->cmd_count--;
302 }
303
304 if (!list_empty(&ccp->backlog)) {
305 backlog = list_first_entry(&ccp->backlog, struct ccp_cmd,
306 entry);
307 list_del(&backlog->entry);
308 }
309
310 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
311
312 if (backlog) {
313 INIT_WORK(&backlog->work, ccp_do_cmd_backlog);
314 schedule_work(&backlog->work);
315 }
316
317 return cmd;
318}
319
Tom Lendacky530abd82014-01-24 16:18:14 -0600320static void ccp_do_cmd_complete(unsigned long data)
Tom Lendacky63b94502013-11-12 11:46:16 -0600321{
Tom Lendacky530abd82014-01-24 16:18:14 -0600322 struct ccp_tasklet_data *tdata = (struct ccp_tasklet_data *)data;
323 struct ccp_cmd *cmd = tdata->cmd;
Tom Lendacky63b94502013-11-12 11:46:16 -0600324
325 cmd->callback(cmd->data, cmd->ret);
Tom Lendacky530abd82014-01-24 16:18:14 -0600326 complete(&tdata->completion);
Tom Lendacky63b94502013-11-12 11:46:16 -0600327}
328
329static int ccp_cmd_queue_thread(void *data)
330{
331 struct ccp_cmd_queue *cmd_q = (struct ccp_cmd_queue *)data;
332 struct ccp_cmd *cmd;
Tom Lendacky530abd82014-01-24 16:18:14 -0600333 struct ccp_tasklet_data tdata;
334 struct tasklet_struct tasklet;
335
336 tasklet_init(&tasklet, ccp_do_cmd_complete, (unsigned long)&tdata);
Tom Lendacky63b94502013-11-12 11:46:16 -0600337
338 set_current_state(TASK_INTERRUPTIBLE);
339 while (!kthread_should_stop()) {
340 schedule();
341
342 set_current_state(TASK_INTERRUPTIBLE);
343
344 cmd = ccp_dequeue_cmd(cmd_q);
345 if (!cmd)
346 continue;
347
348 __set_current_state(TASK_RUNNING);
349
350 /* Execute the command */
351 cmd->ret = ccp_run_cmd(cmd_q, cmd);
352
353 /* Schedule the completion callback */
Tom Lendacky530abd82014-01-24 16:18:14 -0600354 tdata.cmd = cmd;
355 init_completion(&tdata.completion);
356 tasklet_schedule(&tasklet);
357 wait_for_completion(&tdata.completion);
Tom Lendacky63b94502013-11-12 11:46:16 -0600358 }
359
360 __set_current_state(TASK_RUNNING);
361
362 return 0;
363}
364
365static int ccp_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
366{
367 struct ccp_device *ccp = container_of(rng, struct ccp_device, hwrng);
368 u32 trng_value;
369 int len = min_t(int, sizeof(trng_value), max);
370
371 /*
372 * Locking is provided by the caller so we can update device
373 * hwrng-related fields safely
374 */
375 trng_value = ioread32(ccp->io_regs + TRNG_OUT_REG);
376 if (!trng_value) {
377 /* Zero is returned if not data is available or if a
378 * bad-entropy error is present. Assume an error if
379 * we exceed TRNG_RETRIES reads of zero.
380 */
381 if (ccp->hwrng_retries++ > TRNG_RETRIES)
382 return -EIO;
383
384 return 0;
385 }
386
387 /* Reset the counter and save the rng value */
388 ccp->hwrng_retries = 0;
389 memcpy(data, &trng_value, len);
390
391 return len;
392}
393
394/**
395 * ccp_alloc_struct - allocate and initialize the ccp_device struct
396 *
397 * @dev: device struct of the CCP
398 */
399struct ccp_device *ccp_alloc_struct(struct device *dev)
400{
401 struct ccp_device *ccp;
402
Tom Lendackybe03a3a2015-02-03 13:07:23 -0600403 ccp = devm_kzalloc(dev, sizeof(*ccp), GFP_KERNEL);
Tom Lendacky8db88462015-02-03 13:07:05 -0600404 if (!ccp)
Tom Lendacky63b94502013-11-12 11:46:16 -0600405 return NULL;
Tom Lendacky63b94502013-11-12 11:46:16 -0600406 ccp->dev = dev;
407
408 INIT_LIST_HEAD(&ccp->cmd);
409 INIT_LIST_HEAD(&ccp->backlog);
410
411 spin_lock_init(&ccp->cmd_lock);
412 mutex_init(&ccp->req_mutex);
413 mutex_init(&ccp->ksb_mutex);
414 ccp->ksb_count = KSB_COUNT;
415 ccp->ksb_start = 0;
416
Gary R Hook553d2372016-03-01 13:49:04 -0600417 ccp->ord = ccp_increment_unit_ordinal();
418 snprintf(ccp->name, MAX_CCP_NAME_LEN, "ccp-%u", ccp->ord);
419 snprintf(ccp->rngname, MAX_CCP_NAME_LEN, "ccp-%u-rng", ccp->ord);
420
Tom Lendacky63b94502013-11-12 11:46:16 -0600421 return ccp;
422}
423
424/**
425 * ccp_init - initialize the CCP device
426 *
427 * @ccp: ccp_device struct
428 */
429int ccp_init(struct ccp_device *ccp)
430{
431 struct device *dev = ccp->dev;
432 struct ccp_cmd_queue *cmd_q;
433 struct dma_pool *dma_pool;
434 char dma_pool_name[MAX_DMAPOOL_NAME_LEN];
435 unsigned int qmr, qim, i;
436 int ret;
437
438 /* Find available queues */
439 qim = 0;
440 qmr = ioread32(ccp->io_regs + Q_MASK_REG);
441 for (i = 0; i < MAX_HW_QUEUES; i++) {
442 if (!(qmr & (1 << i)))
443 continue;
444
445 /* Allocate a dma pool for this queue */
Gary R Hook553d2372016-03-01 13:49:04 -0600446 snprintf(dma_pool_name, sizeof(dma_pool_name), "%s_q%d",
447 ccp->name, i);
Tom Lendacky63b94502013-11-12 11:46:16 -0600448 dma_pool = dma_pool_create(dma_pool_name, dev,
449 CCP_DMAPOOL_MAX_SIZE,
450 CCP_DMAPOOL_ALIGN, 0);
451 if (!dma_pool) {
452 dev_err(dev, "unable to allocate dma pool\n");
453 ret = -ENOMEM;
454 goto e_pool;
455 }
456
457 cmd_q = &ccp->cmd_q[ccp->cmd_q_count];
458 ccp->cmd_q_count++;
459
460 cmd_q->ccp = ccp;
461 cmd_q->id = i;
462 cmd_q->dma_pool = dma_pool;
463
464 /* Reserve 2 KSB regions for the queue */
465 cmd_q->ksb_key = KSB_START + ccp->ksb_start++;
466 cmd_q->ksb_ctx = KSB_START + ccp->ksb_start++;
467 ccp->ksb_count -= 2;
468
469 /* Preset some register values and masks that are queue
470 * number dependent
471 */
472 cmd_q->reg_status = ccp->io_regs + CMD_Q_STATUS_BASE +
473 (CMD_Q_STATUS_INCR * i);
474 cmd_q->reg_int_status = ccp->io_regs + CMD_Q_INT_STATUS_BASE +
475 (CMD_Q_STATUS_INCR * i);
476 cmd_q->int_ok = 1 << (i * 2);
477 cmd_q->int_err = 1 << ((i * 2) + 1);
478
479 cmd_q->free_slots = CMD_Q_DEPTH(ioread32(cmd_q->reg_status));
480
481 init_waitqueue_head(&cmd_q->int_queue);
482
483 /* Build queue interrupt mask (two interrupts per queue) */
484 qim |= cmd_q->int_ok | cmd_q->int_err;
485
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500486#ifdef CONFIG_ARM64
487 /* For arm64 set the recommended queue cache settings */
Tom Lendacky126ae9a2014-07-10 10:58:35 -0500488 iowrite32(ccp->axcache, ccp->io_regs + CMD_Q_CACHE_BASE +
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500489 (CMD_Q_CACHE_INC * i));
490#endif
491
Tom Lendacky63b94502013-11-12 11:46:16 -0600492 dev_dbg(dev, "queue #%u available\n", i);
493 }
494 if (ccp->cmd_q_count == 0) {
495 dev_notice(dev, "no command queues available\n");
496 ret = -EIO;
497 goto e_pool;
498 }
499 dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count);
500
501 /* Disable and clear interrupts until ready */
502 iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
503 for (i = 0; i < ccp->cmd_q_count; i++) {
504 cmd_q = &ccp->cmd_q[i];
505
506 ioread32(cmd_q->reg_int_status);
507 ioread32(cmd_q->reg_status);
508 }
509 iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
510
511 /* Request an irq */
512 ret = ccp->get_irq(ccp);
513 if (ret) {
514 dev_err(dev, "unable to allocate an IRQ\n");
515 goto e_pool;
516 }
517
518 /* Initialize the queues used to wait for KSB space and suspend */
519 init_waitqueue_head(&ccp->ksb_queue);
520 init_waitqueue_head(&ccp->suspend_queue);
521
522 /* Create a kthread for each queue */
523 for (i = 0; i < ccp->cmd_q_count; i++) {
524 struct task_struct *kthread;
525
526 cmd_q = &ccp->cmd_q[i];
527
528 kthread = kthread_create(ccp_cmd_queue_thread, cmd_q,
Gary R Hook553d2372016-03-01 13:49:04 -0600529 "%s-q%u", ccp->name, cmd_q->id);
Tom Lendacky63b94502013-11-12 11:46:16 -0600530 if (IS_ERR(kthread)) {
531 dev_err(dev, "error creating queue thread (%ld)\n",
532 PTR_ERR(kthread));
533 ret = PTR_ERR(kthread);
534 goto e_kthread;
535 }
536
537 cmd_q->kthread = kthread;
538 wake_up_process(kthread);
539 }
540
541 /* Register the RNG */
Gary R Hook553d2372016-03-01 13:49:04 -0600542 ccp->hwrng.name = ccp->rngname;
Tom Lendacky63b94502013-11-12 11:46:16 -0600543 ccp->hwrng.read = ccp_trng_read;
544 ret = hwrng_register(&ccp->hwrng);
545 if (ret) {
546 dev_err(dev, "error registering hwrng (%d)\n", ret);
547 goto e_kthread;
548 }
549
550 /* Make the device struct available before enabling interrupts */
551 ccp_add_device(ccp);
552
553 /* Enable interrupts */
554 iowrite32(qim, ccp->io_regs + IRQ_MASK_REG);
555
556 return 0;
557
558e_kthread:
559 for (i = 0; i < ccp->cmd_q_count; i++)
560 if (ccp->cmd_q[i].kthread)
561 kthread_stop(ccp->cmd_q[i].kthread);
562
563 ccp->free_irq(ccp);
564
565e_pool:
566 for (i = 0; i < ccp->cmd_q_count; i++)
567 dma_pool_destroy(ccp->cmd_q[i].dma_pool);
568
569 return ret;
570}
571
572/**
573 * ccp_destroy - tear down the CCP device
574 *
575 * @ccp: ccp_device struct
576 */
577void ccp_destroy(struct ccp_device *ccp)
578{
579 struct ccp_cmd_queue *cmd_q;
580 struct ccp_cmd *cmd;
581 unsigned int qim, i;
582
583 /* Remove general access to the device struct */
584 ccp_del_device(ccp);
585
586 /* Unregister the RNG */
587 hwrng_unregister(&ccp->hwrng);
588
589 /* Stop the queue kthreads */
590 for (i = 0; i < ccp->cmd_q_count; i++)
591 if (ccp->cmd_q[i].kthread)
592 kthread_stop(ccp->cmd_q[i].kthread);
593
594 /* Build queue interrupt mask (two interrupt masks per queue) */
595 qim = 0;
596 for (i = 0; i < ccp->cmd_q_count; i++) {
597 cmd_q = &ccp->cmd_q[i];
598 qim |= cmd_q->int_ok | cmd_q->int_err;
599 }
600
601 /* Disable and clear interrupts */
602 iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
603 for (i = 0; i < ccp->cmd_q_count; i++) {
604 cmd_q = &ccp->cmd_q[i];
605
606 ioread32(cmd_q->reg_int_status);
607 ioread32(cmd_q->reg_status);
608 }
609 iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
610
611 ccp->free_irq(ccp);
612
613 for (i = 0; i < ccp->cmd_q_count; i++)
614 dma_pool_destroy(ccp->cmd_q[i].dma_pool);
615
616 /* Flush the cmd and backlog queue */
617 while (!list_empty(&ccp->cmd)) {
618 /* Invoke the callback directly with an error code */
619 cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
620 list_del(&cmd->entry);
621 cmd->callback(cmd->data, -ENODEV);
622 }
623 while (!list_empty(&ccp->backlog)) {
624 /* Invoke the callback directly with an error code */
625 cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry);
626 list_del(&cmd->entry);
627 cmd->callback(cmd->data, -ENODEV);
628 }
629}
630
631/**
632 * ccp_irq_handler - handle interrupts generated by the CCP device
633 *
634 * @irq: the irq associated with the interrupt
635 * @data: the data value supplied when the irq was created
636 */
637irqreturn_t ccp_irq_handler(int irq, void *data)
638{
639 struct device *dev = data;
640 struct ccp_device *ccp = dev_get_drvdata(dev);
641 struct ccp_cmd_queue *cmd_q;
642 u32 q_int, status;
643 unsigned int i;
644
645 status = ioread32(ccp->io_regs + IRQ_STATUS_REG);
646
647 for (i = 0; i < ccp->cmd_q_count; i++) {
648 cmd_q = &ccp->cmd_q[i];
649
650 q_int = status & (cmd_q->int_ok | cmd_q->int_err);
651 if (q_int) {
652 cmd_q->int_status = status;
653 cmd_q->q_status = ioread32(cmd_q->reg_status);
654 cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
655
656 /* On error, only save the first error value */
657 if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error)
658 cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
659
660 cmd_q->int_rcvd = 1;
661
662 /* Acknowledge the interrupt and wake the kthread */
663 iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG);
664 wake_up_interruptible(&cmd_q->int_queue);
665 }
666 }
667
668 return IRQ_HANDLED;
669}
670
671#ifdef CONFIG_PM
672bool ccp_queues_suspended(struct ccp_device *ccp)
673{
674 unsigned int suspended = 0;
675 unsigned long flags;
676 unsigned int i;
677
678 spin_lock_irqsave(&ccp->cmd_lock, flags);
679
680 for (i = 0; i < ccp->cmd_q_count; i++)
681 if (ccp->cmd_q[i].suspended)
682 suspended++;
683
684 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
685
686 return ccp->cmd_q_count == suspended;
687}
688#endif
689
Gary R Hookc7019c42016-03-01 13:49:15 -0600690struct ccp_vdata ccpv3 = {
691 .version = CCP_VERSION(3, 0),
692};
693
Tom Lendacky63b94502013-11-12 11:46:16 -0600694static int __init ccp_mod_init(void)
695{
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500696#ifdef CONFIG_X86
Tom Lendackydb34cf92014-01-06 13:34:29 -0600697 int ret;
Tom Lendacky63b94502013-11-12 11:46:16 -0600698
Gary R Hook3f19ce22016-03-01 13:48:54 -0600699 ret = ccp_pci_init();
700 if (ret)
701 return ret;
702
703 /* Don't leave the driver loaded if init failed */
Gary R Hook553d2372016-03-01 13:49:04 -0600704 if (ccp_present() != 0) {
Gary R Hook3f19ce22016-03-01 13:48:54 -0600705 ccp_pci_exit();
Tom Lendacky63b94502013-11-12 11:46:16 -0600706 return -ENODEV;
Fengguang Wud1dd2062013-12-09 20:08:19 +0800707 }
Gary R Hook3f19ce22016-03-01 13:48:54 -0600708
709 return 0;
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500710#endif
711
712#ifdef CONFIG_ARM64
713 int ret;
714
715 ret = ccp_platform_init();
716 if (ret)
717 return ret;
718
719 /* Don't leave the driver loaded if init failed */
Gary R Hook553d2372016-03-01 13:49:04 -0600720 if (ccp_present() != 0) {
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500721 ccp_platform_exit();
722 return -ENODEV;
723 }
724
725 return 0;
726#endif
Tom Lendacky63b94502013-11-12 11:46:16 -0600727
728 return -ENODEV;
729}
730
731static void __exit ccp_mod_exit(void)
732{
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500733#ifdef CONFIG_X86
Gary R Hook3f19ce22016-03-01 13:48:54 -0600734 ccp_pci_exit();
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500735#endif
736
737#ifdef CONFIG_ARM64
738 ccp_platform_exit();
739#endif
Tom Lendacky63b94502013-11-12 11:46:16 -0600740}
741
742module_init(ccp_mod_init);
743module_exit(ccp_mod_exit);