blob: dd71e673a10949cfd5fe7314d624690a8bb3a82d [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/**
Tom Lendacky63b94502013-11-12 11:46:16 -0600153 * ccp_enqueue_cmd - queue an operation for processing by the CCP
154 *
155 * @cmd: ccp_cmd struct to be processed
156 *
157 * Queue a cmd to be processed by the CCP. If queueing the cmd
158 * would exceed the defined length of the cmd queue the cmd will
159 * only be queued if the CCP_CMD_MAY_BACKLOG flag is set and will
160 * result in a return code of -EBUSY.
161 *
162 * The callback routine specified in the ccp_cmd struct will be
163 * called to notify the caller of completion (if the cmd was not
164 * backlogged) or advancement out of the backlog. If the cmd has
165 * advanced out of the backlog the "err" value of the callback
166 * will be -EINPROGRESS. Any other "err" value during callback is
167 * the result of the operation.
168 *
169 * The cmd has been successfully queued if:
170 * the return code is -EINPROGRESS or
171 * the return code is -EBUSY and CCP_CMD_MAY_BACKLOG flag is set
172 */
173int ccp_enqueue_cmd(struct ccp_cmd *cmd)
174{
175 struct ccp_device *ccp = ccp_get_device();
176 unsigned long flags;
177 unsigned int i;
178 int ret;
179
180 if (!ccp)
181 return -ENODEV;
182
183 /* Caller must supply a callback routine */
184 if (!cmd->callback)
185 return -EINVAL;
186
187 cmd->ccp = ccp;
188
189 spin_lock_irqsave(&ccp->cmd_lock, flags);
190
191 i = ccp->cmd_q_count;
192
193 if (ccp->cmd_count >= MAX_CMD_QLEN) {
194 ret = -EBUSY;
195 if (cmd->flags & CCP_CMD_MAY_BACKLOG)
196 list_add_tail(&cmd->entry, &ccp->backlog);
197 } else {
198 ret = -EINPROGRESS;
199 ccp->cmd_count++;
200 list_add_tail(&cmd->entry, &ccp->cmd);
201
202 /* Find an idle queue */
203 if (!ccp->suspending) {
204 for (i = 0; i < ccp->cmd_q_count; i++) {
205 if (ccp->cmd_q[i].active)
206 continue;
207
208 break;
209 }
210 }
211 }
212
213 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
214
215 /* If we found an idle queue, wake it up */
216 if (i < ccp->cmd_q_count)
217 wake_up_process(ccp->cmd_q[i].kthread);
218
219 return ret;
220}
221EXPORT_SYMBOL_GPL(ccp_enqueue_cmd);
222
223static void ccp_do_cmd_backlog(struct work_struct *work)
224{
225 struct ccp_cmd *cmd = container_of(work, struct ccp_cmd, work);
226 struct ccp_device *ccp = cmd->ccp;
227 unsigned long flags;
228 unsigned int i;
229
230 cmd->callback(cmd->data, -EINPROGRESS);
231
232 spin_lock_irqsave(&ccp->cmd_lock, flags);
233
234 ccp->cmd_count++;
235 list_add_tail(&cmd->entry, &ccp->cmd);
236
237 /* Find an idle queue */
238 for (i = 0; i < ccp->cmd_q_count; i++) {
239 if (ccp->cmd_q[i].active)
240 continue;
241
242 break;
243 }
244
245 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
246
247 /* If we found an idle queue, wake it up */
248 if (i < ccp->cmd_q_count)
249 wake_up_process(ccp->cmd_q[i].kthread);
250}
251
252static struct ccp_cmd *ccp_dequeue_cmd(struct ccp_cmd_queue *cmd_q)
253{
254 struct ccp_device *ccp = cmd_q->ccp;
255 struct ccp_cmd *cmd = NULL;
256 struct ccp_cmd *backlog = NULL;
257 unsigned long flags;
258
259 spin_lock_irqsave(&ccp->cmd_lock, flags);
260
261 cmd_q->active = 0;
262
263 if (ccp->suspending) {
264 cmd_q->suspended = 1;
265
266 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
267 wake_up_interruptible(&ccp->suspend_queue);
268
269 return NULL;
270 }
271
272 if (ccp->cmd_count) {
273 cmd_q->active = 1;
274
275 cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
276 list_del(&cmd->entry);
277
278 ccp->cmd_count--;
279 }
280
281 if (!list_empty(&ccp->backlog)) {
282 backlog = list_first_entry(&ccp->backlog, struct ccp_cmd,
283 entry);
284 list_del(&backlog->entry);
285 }
286
287 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
288
289 if (backlog) {
290 INIT_WORK(&backlog->work, ccp_do_cmd_backlog);
291 schedule_work(&backlog->work);
292 }
293
294 return cmd;
295}
296
Tom Lendacky530abd82014-01-24 16:18:14 -0600297static void ccp_do_cmd_complete(unsigned long data)
Tom Lendacky63b94502013-11-12 11:46:16 -0600298{
Tom Lendacky530abd82014-01-24 16:18:14 -0600299 struct ccp_tasklet_data *tdata = (struct ccp_tasklet_data *)data;
300 struct ccp_cmd *cmd = tdata->cmd;
Tom Lendacky63b94502013-11-12 11:46:16 -0600301
302 cmd->callback(cmd->data, cmd->ret);
Tom Lendacky530abd82014-01-24 16:18:14 -0600303 complete(&tdata->completion);
Tom Lendacky63b94502013-11-12 11:46:16 -0600304}
305
306static int ccp_cmd_queue_thread(void *data)
307{
308 struct ccp_cmd_queue *cmd_q = (struct ccp_cmd_queue *)data;
309 struct ccp_cmd *cmd;
Tom Lendacky530abd82014-01-24 16:18:14 -0600310 struct ccp_tasklet_data tdata;
311 struct tasklet_struct tasklet;
312
313 tasklet_init(&tasklet, ccp_do_cmd_complete, (unsigned long)&tdata);
Tom Lendacky63b94502013-11-12 11:46:16 -0600314
315 set_current_state(TASK_INTERRUPTIBLE);
316 while (!kthread_should_stop()) {
317 schedule();
318
319 set_current_state(TASK_INTERRUPTIBLE);
320
321 cmd = ccp_dequeue_cmd(cmd_q);
322 if (!cmd)
323 continue;
324
325 __set_current_state(TASK_RUNNING);
326
327 /* Execute the command */
328 cmd->ret = ccp_run_cmd(cmd_q, cmd);
329
330 /* Schedule the completion callback */
Tom Lendacky530abd82014-01-24 16:18:14 -0600331 tdata.cmd = cmd;
332 init_completion(&tdata.completion);
333 tasklet_schedule(&tasklet);
334 wait_for_completion(&tdata.completion);
Tom Lendacky63b94502013-11-12 11:46:16 -0600335 }
336
337 __set_current_state(TASK_RUNNING);
338
339 return 0;
340}
341
342static int ccp_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
343{
344 struct ccp_device *ccp = container_of(rng, struct ccp_device, hwrng);
345 u32 trng_value;
346 int len = min_t(int, sizeof(trng_value), max);
347
348 /*
349 * Locking is provided by the caller so we can update device
350 * hwrng-related fields safely
351 */
352 trng_value = ioread32(ccp->io_regs + TRNG_OUT_REG);
353 if (!trng_value) {
354 /* Zero is returned if not data is available or if a
355 * bad-entropy error is present. Assume an error if
356 * we exceed TRNG_RETRIES reads of zero.
357 */
358 if (ccp->hwrng_retries++ > TRNG_RETRIES)
359 return -EIO;
360
361 return 0;
362 }
363
364 /* Reset the counter and save the rng value */
365 ccp->hwrng_retries = 0;
366 memcpy(data, &trng_value, len);
367
368 return len;
369}
370
371/**
372 * ccp_alloc_struct - allocate and initialize the ccp_device struct
373 *
374 * @dev: device struct of the CCP
375 */
376struct ccp_device *ccp_alloc_struct(struct device *dev)
377{
378 struct ccp_device *ccp;
379
Tom Lendackybe03a3a2015-02-03 13:07:23 -0600380 ccp = devm_kzalloc(dev, sizeof(*ccp), GFP_KERNEL);
Tom Lendacky8db88462015-02-03 13:07:05 -0600381 if (!ccp)
Tom Lendacky63b94502013-11-12 11:46:16 -0600382 return NULL;
Tom Lendacky63b94502013-11-12 11:46:16 -0600383 ccp->dev = dev;
384
385 INIT_LIST_HEAD(&ccp->cmd);
386 INIT_LIST_HEAD(&ccp->backlog);
387
388 spin_lock_init(&ccp->cmd_lock);
389 mutex_init(&ccp->req_mutex);
390 mutex_init(&ccp->ksb_mutex);
391 ccp->ksb_count = KSB_COUNT;
392 ccp->ksb_start = 0;
393
Gary R Hook553d2372016-03-01 13:49:04 -0600394 ccp->ord = ccp_increment_unit_ordinal();
395 snprintf(ccp->name, MAX_CCP_NAME_LEN, "ccp-%u", ccp->ord);
396 snprintf(ccp->rngname, MAX_CCP_NAME_LEN, "ccp-%u-rng", ccp->ord);
397
Tom Lendacky63b94502013-11-12 11:46:16 -0600398 return ccp;
399}
400
401/**
402 * ccp_init - initialize the CCP device
403 *
404 * @ccp: ccp_device struct
405 */
406int ccp_init(struct ccp_device *ccp)
407{
408 struct device *dev = ccp->dev;
409 struct ccp_cmd_queue *cmd_q;
410 struct dma_pool *dma_pool;
411 char dma_pool_name[MAX_DMAPOOL_NAME_LEN];
412 unsigned int qmr, qim, i;
413 int ret;
414
415 /* Find available queues */
416 qim = 0;
417 qmr = ioread32(ccp->io_regs + Q_MASK_REG);
418 for (i = 0; i < MAX_HW_QUEUES; i++) {
419 if (!(qmr & (1 << i)))
420 continue;
421
422 /* Allocate a dma pool for this queue */
Gary R Hook553d2372016-03-01 13:49:04 -0600423 snprintf(dma_pool_name, sizeof(dma_pool_name), "%s_q%d",
424 ccp->name, i);
Tom Lendacky63b94502013-11-12 11:46:16 -0600425 dma_pool = dma_pool_create(dma_pool_name, dev,
426 CCP_DMAPOOL_MAX_SIZE,
427 CCP_DMAPOOL_ALIGN, 0);
428 if (!dma_pool) {
429 dev_err(dev, "unable to allocate dma pool\n");
430 ret = -ENOMEM;
431 goto e_pool;
432 }
433
434 cmd_q = &ccp->cmd_q[ccp->cmd_q_count];
435 ccp->cmd_q_count++;
436
437 cmd_q->ccp = ccp;
438 cmd_q->id = i;
439 cmd_q->dma_pool = dma_pool;
440
441 /* Reserve 2 KSB regions for the queue */
442 cmd_q->ksb_key = KSB_START + ccp->ksb_start++;
443 cmd_q->ksb_ctx = KSB_START + ccp->ksb_start++;
444 ccp->ksb_count -= 2;
445
446 /* Preset some register values and masks that are queue
447 * number dependent
448 */
449 cmd_q->reg_status = ccp->io_regs + CMD_Q_STATUS_BASE +
450 (CMD_Q_STATUS_INCR * i);
451 cmd_q->reg_int_status = ccp->io_regs + CMD_Q_INT_STATUS_BASE +
452 (CMD_Q_STATUS_INCR * i);
453 cmd_q->int_ok = 1 << (i * 2);
454 cmd_q->int_err = 1 << ((i * 2) + 1);
455
456 cmd_q->free_slots = CMD_Q_DEPTH(ioread32(cmd_q->reg_status));
457
458 init_waitqueue_head(&cmd_q->int_queue);
459
460 /* Build queue interrupt mask (two interrupts per queue) */
461 qim |= cmd_q->int_ok | cmd_q->int_err;
462
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500463#ifdef CONFIG_ARM64
464 /* For arm64 set the recommended queue cache settings */
Tom Lendacky126ae9a2014-07-10 10:58:35 -0500465 iowrite32(ccp->axcache, ccp->io_regs + CMD_Q_CACHE_BASE +
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500466 (CMD_Q_CACHE_INC * i));
467#endif
468
Tom Lendacky63b94502013-11-12 11:46:16 -0600469 dev_dbg(dev, "queue #%u available\n", i);
470 }
471 if (ccp->cmd_q_count == 0) {
472 dev_notice(dev, "no command queues available\n");
473 ret = -EIO;
474 goto e_pool;
475 }
476 dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count);
477
478 /* Disable and clear interrupts until ready */
479 iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
480 for (i = 0; i < ccp->cmd_q_count; i++) {
481 cmd_q = &ccp->cmd_q[i];
482
483 ioread32(cmd_q->reg_int_status);
484 ioread32(cmd_q->reg_status);
485 }
486 iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
487
488 /* Request an irq */
489 ret = ccp->get_irq(ccp);
490 if (ret) {
491 dev_err(dev, "unable to allocate an IRQ\n");
492 goto e_pool;
493 }
494
495 /* Initialize the queues used to wait for KSB space and suspend */
496 init_waitqueue_head(&ccp->ksb_queue);
497 init_waitqueue_head(&ccp->suspend_queue);
498
499 /* Create a kthread for each queue */
500 for (i = 0; i < ccp->cmd_q_count; i++) {
501 struct task_struct *kthread;
502
503 cmd_q = &ccp->cmd_q[i];
504
505 kthread = kthread_create(ccp_cmd_queue_thread, cmd_q,
Gary R Hook553d2372016-03-01 13:49:04 -0600506 "%s-q%u", ccp->name, cmd_q->id);
Tom Lendacky63b94502013-11-12 11:46:16 -0600507 if (IS_ERR(kthread)) {
508 dev_err(dev, "error creating queue thread (%ld)\n",
509 PTR_ERR(kthread));
510 ret = PTR_ERR(kthread);
511 goto e_kthread;
512 }
513
514 cmd_q->kthread = kthread;
515 wake_up_process(kthread);
516 }
517
518 /* Register the RNG */
Gary R Hook553d2372016-03-01 13:49:04 -0600519 ccp->hwrng.name = ccp->rngname;
Tom Lendacky63b94502013-11-12 11:46:16 -0600520 ccp->hwrng.read = ccp_trng_read;
521 ret = hwrng_register(&ccp->hwrng);
522 if (ret) {
523 dev_err(dev, "error registering hwrng (%d)\n", ret);
524 goto e_kthread;
525 }
526
527 /* Make the device struct available before enabling interrupts */
528 ccp_add_device(ccp);
529
530 /* Enable interrupts */
531 iowrite32(qim, ccp->io_regs + IRQ_MASK_REG);
532
533 return 0;
534
535e_kthread:
536 for (i = 0; i < ccp->cmd_q_count; i++)
537 if (ccp->cmd_q[i].kthread)
538 kthread_stop(ccp->cmd_q[i].kthread);
539
540 ccp->free_irq(ccp);
541
542e_pool:
543 for (i = 0; i < ccp->cmd_q_count; i++)
544 dma_pool_destroy(ccp->cmd_q[i].dma_pool);
545
546 return ret;
547}
548
549/**
550 * ccp_destroy - tear down the CCP device
551 *
552 * @ccp: ccp_device struct
553 */
554void ccp_destroy(struct ccp_device *ccp)
555{
556 struct ccp_cmd_queue *cmd_q;
557 struct ccp_cmd *cmd;
558 unsigned int qim, i;
559
560 /* Remove general access to the device struct */
561 ccp_del_device(ccp);
562
563 /* Unregister the RNG */
564 hwrng_unregister(&ccp->hwrng);
565
566 /* Stop the queue kthreads */
567 for (i = 0; i < ccp->cmd_q_count; i++)
568 if (ccp->cmd_q[i].kthread)
569 kthread_stop(ccp->cmd_q[i].kthread);
570
571 /* Build queue interrupt mask (two interrupt masks per queue) */
572 qim = 0;
573 for (i = 0; i < ccp->cmd_q_count; i++) {
574 cmd_q = &ccp->cmd_q[i];
575 qim |= cmd_q->int_ok | cmd_q->int_err;
576 }
577
578 /* Disable and clear interrupts */
579 iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG);
580 for (i = 0; i < ccp->cmd_q_count; i++) {
581 cmd_q = &ccp->cmd_q[i];
582
583 ioread32(cmd_q->reg_int_status);
584 ioread32(cmd_q->reg_status);
585 }
586 iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG);
587
588 ccp->free_irq(ccp);
589
590 for (i = 0; i < ccp->cmd_q_count; i++)
591 dma_pool_destroy(ccp->cmd_q[i].dma_pool);
592
593 /* Flush the cmd and backlog queue */
594 while (!list_empty(&ccp->cmd)) {
595 /* Invoke the callback directly with an error code */
596 cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
597 list_del(&cmd->entry);
598 cmd->callback(cmd->data, -ENODEV);
599 }
600 while (!list_empty(&ccp->backlog)) {
601 /* Invoke the callback directly with an error code */
602 cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry);
603 list_del(&cmd->entry);
604 cmd->callback(cmd->data, -ENODEV);
605 }
606}
607
608/**
609 * ccp_irq_handler - handle interrupts generated by the CCP device
610 *
611 * @irq: the irq associated with the interrupt
612 * @data: the data value supplied when the irq was created
613 */
614irqreturn_t ccp_irq_handler(int irq, void *data)
615{
616 struct device *dev = data;
617 struct ccp_device *ccp = dev_get_drvdata(dev);
618 struct ccp_cmd_queue *cmd_q;
619 u32 q_int, status;
620 unsigned int i;
621
622 status = ioread32(ccp->io_regs + IRQ_STATUS_REG);
623
624 for (i = 0; i < ccp->cmd_q_count; i++) {
625 cmd_q = &ccp->cmd_q[i];
626
627 q_int = status & (cmd_q->int_ok | cmd_q->int_err);
628 if (q_int) {
629 cmd_q->int_status = status;
630 cmd_q->q_status = ioread32(cmd_q->reg_status);
631 cmd_q->q_int_status = ioread32(cmd_q->reg_int_status);
632
633 /* On error, only save the first error value */
634 if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error)
635 cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
636
637 cmd_q->int_rcvd = 1;
638
639 /* Acknowledge the interrupt and wake the kthread */
640 iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG);
641 wake_up_interruptible(&cmd_q->int_queue);
642 }
643 }
644
645 return IRQ_HANDLED;
646}
647
648#ifdef CONFIG_PM
649bool ccp_queues_suspended(struct ccp_device *ccp)
650{
651 unsigned int suspended = 0;
652 unsigned long flags;
653 unsigned int i;
654
655 spin_lock_irqsave(&ccp->cmd_lock, flags);
656
657 for (i = 0; i < ccp->cmd_q_count; i++)
658 if (ccp->cmd_q[i].suspended)
659 suspended++;
660
661 spin_unlock_irqrestore(&ccp->cmd_lock, flags);
662
663 return ccp->cmd_q_count == suspended;
664}
665#endif
666
Tom Lendacky63b94502013-11-12 11:46:16 -0600667static int __init ccp_mod_init(void)
668{
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500669#ifdef CONFIG_X86
Tom Lendackydb34cf92014-01-06 13:34:29 -0600670 int ret;
Tom Lendacky63b94502013-11-12 11:46:16 -0600671
Gary R Hook3f19ce22016-03-01 13:48:54 -0600672 ret = ccp_pci_init();
673 if (ret)
674 return ret;
675
676 /* Don't leave the driver loaded if init failed */
Gary R Hook553d2372016-03-01 13:49:04 -0600677 if (ccp_present() != 0) {
Gary R Hook3f19ce22016-03-01 13:48:54 -0600678 ccp_pci_exit();
Tom Lendacky63b94502013-11-12 11:46:16 -0600679 return -ENODEV;
Fengguang Wud1dd2062013-12-09 20:08:19 +0800680 }
Gary R Hook3f19ce22016-03-01 13:48:54 -0600681
682 return 0;
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500683#endif
684
685#ifdef CONFIG_ARM64
686 int ret;
687
688 ret = ccp_platform_init();
689 if (ret)
690 return ret;
691
692 /* Don't leave the driver loaded if init failed */
Gary R Hook553d2372016-03-01 13:49:04 -0600693 if (ccp_present() != 0) {
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500694 ccp_platform_exit();
695 return -ENODEV;
696 }
697
698 return 0;
699#endif
Tom Lendacky63b94502013-11-12 11:46:16 -0600700
701 return -ENODEV;
702}
703
704static void __exit ccp_mod_exit(void)
705{
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500706#ifdef CONFIG_X86
Gary R Hook3f19ce22016-03-01 13:48:54 -0600707 ccp_pci_exit();
Tom Lendackyc4f4b322014-06-05 10:17:57 -0500708#endif
709
710#ifdef CONFIG_ARM64
711 ccp_platform_exit();
712#endif
Tom Lendacky63b94502013-11-12 11:46:16 -0600713}
714
715module_init(ccp_mod_init);
716module_exit(ccp_mod_exit);