// SPDX-License-Identifier: GPL-2.0-only
/*
* AMD Cryptographic Coprocessor (CCP) driver
*
* Copyright (C) 2016,2019 Advanced Micro Devices, Inc.
*
* Author: Gary R Hook <gary.hook@amd.com>
*/
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/compiler.h>
#include <linux/ccp.h>
#include "ccp-dev.h"
/* Allocate the requested number of contiguous LSB slots
* from the LSB bitmap. Look in the private range for this
* queue first; failing that, check the public area.
* If no space is available, wait around.
* Return: first slot number
*/
static u32 ccp_lsb_alloc(struct ccp_cmd_queue *cmd_q, unsigned int count)
{
struct ccp_device *ccp;
int start;
/* First look at the map for the queue */
if (cmd_q->lsb >= 0) {
start = (u32)bitmap_find_next_zero_area(cmd_q->lsbmap,
LSB_SIZE,
0, count, 0);
if (start < LSB_SIZE) {
bitmap_set(cmd_q->lsbmap, start, count);
return start + cmd_q->lsb * LSB_SIZE;
}
}
/* No joy; try to get an entry from the shared blocks */
ccp = cmd_q->ccp;
for (;;) {
mutex_lock(&ccp->sb_mutex);
start = (u32)bitmap_find_next_zero_area(ccp->lsbmap,
MAX_LSB_CNT * LSB_SIZE,
0,
count, 0);
if (start <= MAX_LSB_CNT * LSB_SIZE) {
bitmap_set(ccp->lsbmap, start, count);
mutex_unlock(&ccp->sb_mutex);
return start;
}
ccp->sb_avail = 0;
mutex_unlock(&ccp->sb_mutex);
/* Wait for KSB entries to become available */
if (wait_event_interruptible(ccp->sb_queue, ccp->sb_avail))
return 0;
}
}
/* Free a number of LSB slots from the bitmap, starting at
* the indicated starting slot number.
*/
static void ccp_lsb_free(struct ccp_cmd_queue *cmd_q, unsigned int start,
unsigned int count)
{
if (!start)
return;
if (cmd_q->lsb == start) {
/* An entry from the private LSB */
bitmap_clear(cmd_q->lsbmap, start, count);
} else {
/* From the shared LSBs */
struct ccp_device *ccp = cmd_q->ccp;
mutex_lock(&ccp->sb_mutex);
bitmap_clear(ccp->lsbmap, start, count);
ccp->sb_avail = 1;
mutex_unlock(&ccp->sb_mutex);
wake_up_interruptible_all(&ccp->sb_queue);
}
}
/* CCP version 5: Union to define the function field (cmd_reg1/dword0) */
union ccp_function {
struct {
u16 size:7;
u16 encrypt:1;
u16 mode:5;
u16 type:2;
} aes;
struct {
u16 size:7;
u16 encrypt:1;
u16 rsvd:5;
u16 type:2;
} aes_xts;
struct {
u16 size:7;
u16 encrypt:1;
u16 mode:5;
u16 type:2;
} des3;
struct {
u16 rsvd1:10;
u16 type:4;
u16 rsvd2:1;
} sha;
struct {
u16 mode:3;
u16 size:12;
} rsa;
struct {
u16 byteswap:2;
u16 bitwise:3;
u16 reflect:2;
u16 rsvd:8;
} pt;
struct {
u16 rsvd:13;
}