Commit 914854f2 authored by Carrie.Cai's avatar Carrie.Cai
Browse files

driver: crypto - update support for Mont-TSSE Driver

Montage inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IAXCFU


CVE: NA

----------------------------------------------------------

Mont-TSSE(R) is a high speed crypto algorithm accelerator
The Mont-TSSE(R) Driver Features are
1.SR-IOV
2.IPC feature

Signed-off-by: default avatarCarrie.Cai <carrie.cai@montage-tech.com>
parent 30113d28
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -8,6 +8,12 @@ obj-m += tsse.o

tsse-objs := tsse_dev_mgr.o \
	tsse_ipc.o \
	tsse_ipc_epid.o \
	tsse_ipc_api.o \
	tsse_ipc_setup.o \
	tsse_ipc_drv.o \
	tsse_ipc_service.o \
	tsse_ipc_hash.o \
	tsse_fw_service.o \
	tsse_service.o \
	tsse_irq.o \
+23 −4
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * This file is part of tsse driver for Linux
 *
 * Copyright © 2023 Montage Technology. All rights reserved.
 * Copyright © 2023-2024 Montage Technology. All rights reserved.
 */

#ifndef __TSSE_DEV_H__
@@ -14,7 +14,7 @@
#include <linux/pci-ats.h>
#include <linux/serial_core.h>
#include <linux/firmware.h>
#include "tsse_ipc.h"
#include "tsse_ipc_setup.h"

#define TSSE_PCI_MAX_BARS 4
#define TSSE_FW_VERSION_LEN 32
@@ -37,8 +37,6 @@ enum tsse_dev_status_bit {
struct tsse_qpairs_bank {
	struct tsse_dev *tsse_dev;
	void __iomem *reg_base;

	u32 num_qparis;
	u32 irq_vec;
};
struct tsse_dev {
@@ -57,10 +55,12 @@ struct tsse_dev {
	struct tsse_ipc *ipc;
	void *adi;
	void *mbx_hw;
	void *fw_data;
	const struct firmware *fw;
	char fw_version[TSSE_FW_VERSION_LEN];
	bool fw_version_exist;
};

#define TSSEDEV_TO_DEV(tssedev) (&((tssedev)->tsse_pci_dev.pci_dev->dev))
#define TSSE_DEV_BARS(tssedev) ((tssedev)->tsse_pci_dev.bars)

@@ -74,6 +74,10 @@ int tsse_devmgr_add_dev(struct tsse_dev *tsse_dev);
void tsse_devmgr_rm_dev(struct tsse_dev *tdev);
int tsse_prepare_restart_dev(struct tsse_dev *tdev);
int tsse_start_dev(struct tsse_dev *tdev);
struct tsse_dev *tsse_get_dev_by_handle(int handle);

typedef int (*tsse_dev_process_func)(struct tsse_dev *tdev);
int tsse_process_for_all(tsse_dev_process_func func);

static inline struct tsse_dev *pci_to_tsse_dev(struct pci_dev *pci_dev)
{
@@ -99,4 +103,19 @@ static inline int tsse_dev_in_use(struct tsse_dev *tdev)
{
	return atomic_read(&tdev->ref_count) != 0;
}

static inline void tsse_list_del(struct list_head *entry)
{
	WRITE_ONCE(entry->next->prev, entry->prev);
	WRITE_ONCE(entry->prev->next, entry->next);
}
static inline void tsse_list_add(struct list_head *new, struct list_head *prev,
				 struct list_head *next)
{
	WRITE_ONCE(new->next, next);
	WRITE_ONCE(new->prev, prev);
	mb();  /* Make sure new node updates first */
	WRITE_ONCE(next->prev, new);
	WRITE_ONCE(prev->next, new);
}
#endif
+45 −27
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * This file is part of tsse driver for Linux
 *
 * Copyright © 2023 Montage Technology. All rights reserved.
 * Copyright © 2023-2024 Montage Technology. All rights reserved.
 */

#include <linux/kernel.h>
@@ -15,7 +15,7 @@

#include "tsse_dev_drv.h"
#include "tsse_vuart.h"
#include "tsse_ipc.h"
#include "tsse_ipc_setup.h"
#include "tsse_fw_service.h"

#define CLUSTER_SLOT_CONFIG_OFFSET 0x5780000
@@ -87,22 +87,20 @@ static int tsse_sriov_configure(struct pci_dev *pdev, int num_vfs_param)

	if (tdev->num_vfs > 0) {
		tdev->num_irqs = TSSE_SRIOV_PF_MAX_IRQ_NUM;
		tdev->qpairs_bank.num_qparis = TSSE_SRIOV_PF_MAX_QPAIR_NUM;
	} else {
		tdev->num_irqs = TSSE_PF_MAX_IRQ_NUM;
		tdev->qpairs_bank.num_qparis = TSSE_PF_MAX_QPAIR_NUM;
	}

	tsse_dev_info(
		tdev,
		"num_irqs:%u num_qparis:%u qpairs' start irq vector index:%u qpairs' reg base:0x%lx\n",
		tdev->num_irqs, tdev->qpairs_bank.num_qparis,
		"num_irqs:%u, qpair start irq vector index:%u, qpair reg base:0x%lx\n",
		tdev->num_irqs,
		tdev->qpairs_bank.irq_vec, (ulong)tdev->qpairs_bank.reg_base);

	ret = tsse_start_dev(tdev);
	if (ret) {
		dev_err(&pdev->dev, "%s %d: failed to start the device\n",
			__func__, __LINE__);
		dev_err(&pdev->dev, "%s %d: failed to start the device: %d\n",
			__func__, __LINE__, ret);
		return ret;
	}

@@ -168,15 +166,31 @@ static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		return -EINVAL;
	}

	/* Disable ASPM completely as that cause device performence low */
	status = pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S |
					  PCIE_LINK_STATE_L1);
	if (status) {
		dev_info(&pdev->dev,
			"%s %d: Disable ASPM failed(%d), may cause device performence low.\n",
			__func__, __LINE__, status);
	}

	tdev = kzalloc_node(sizeof(*tdev), GFP_KERNEL, dev_to_node(&pdev->dev));

	if (!tdev)
		return -ENOMEM;

	tdev->fw_data = kzalloc_node(TSSE_FIRMWARE_MAX_LENGTH, GFP_KERNEL, dev_to_node(&pdev->dev));

	if (!tdev->fw_data) {
		kfree(tdev);
		return -ENOMEM;
	}

	status = pcim_enable_device(pdev);

	if (status) {
		dev_err(&pdev->dev, "pcim_enable_device failed\n");
		dev_err(&pdev->dev, "pcim_enable_device failed: %d\n", status);
		goto out_err;
	}

@@ -200,7 +214,7 @@ static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)

	status = pcim_iomap_regions(pdev, BIT(0) | BIT(2), TSSE_DEV_NAME);
	if (status) {
		dev_err(&pdev->dev, "I/O memory remapping failed\n");
		dev_err(&pdev->dev, "I/O memory remapping failed: %d\n", status);
		goto out_err;
	}

@@ -232,7 +246,6 @@ static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	pci_set_drvdata(pdev, tdev);

	tdev->num_irqs = TSSE_PF_MAX_IRQ_NUM;
	tdev->qpairs_bank.num_qparis = TSSE_PF_MAX_QPAIR_NUM;
	tdev->qpairs_bank.irq_vec = TSSE_PF_QPAIR_START_IRQ_VECTOR;
	tdev->qpairs_bank.reg_base =
		TSSE_DEV_BARS(tdev)[2].virt_addr + TSSE_PF_QPAIR_REG_BASE;
@@ -241,8 +254,8 @@ static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)

	tsse_dev_info(
		tdev,
		"num_irqs:%u num_qparis:%u qpairs' start irq vector index:%u qpairs' reg base:0x%lx\n",
		tdev->num_irqs, tdev->qpairs_bank.num_qparis,
		"num_irqs:%u, qpair start irq vector index:%u, qpair reg base:0x%lx\n",
		tdev->num_irqs,
		tdev->qpairs_bank.irq_vec, (ulong)tdev->qpairs_bank.reg_base);

	if (tsse_devmgr_add_dev(tdev)) {
@@ -268,37 +281,41 @@ static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)
			tdev->fw_version_exist = true;
	}

	if (tsse_ipc_init(pdev)) {
		dev_err(&pdev->dev,
			"%s %d: tsse_ipc_init failed to tsse_ipc.\n", __func__,
			__LINE__);
		status = -EFAULT;
		goto out_err_ipc;
	}

	if (sysfs_create_file(&pdev->dev.kobj, &dev_attr_tsse_image_load.attr)) {
		dev_err(&pdev->dev,
			"%s %d: sysfs_create_file failed for tsse image load.\n",
			__func__, __LINE__);
		status = -EFAULT;
		goto out_err_image_load;
		goto out_err_sysfs;
	}

	if (tsse_ipc_init(pdev)) {
		dev_err(&pdev->dev,
			"%s %d: tsse_ipc_init failed.\n", __func__,
			__LINE__);
		status = -EFAULT;
		goto out_err_ipc;
	}
	tsse_dev_info(tdev, "successful\n");

	pci_read_config_dword(pdev, 0x720, &tmp_val);
	tsse_dev_dbg(tdev, "the value of FILTER_MASK_2_REG is 0x%x\n", tmp_val);

	return 0;
out_err_image_load:
	tsse_ipc_deinit(tdev);
out_err_ipc:
	if (tdev->fw) {
		release_firmware(tdev->fw);
		tdev->fw = NULL;
	}
	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tsse_image_load.attr);
out_err_sysfs:
	vuart_uninit_port(pdev);
out_err_port_init:
	tsse_devmgr_rm_dev(tdev);
out_err_ida_free:
	ida_free(&tsse_ida, tdev->id);
out_err:
	kfree(tdev->fw_data);
	kfree(tdev);
	return status;
}
@@ -311,12 +328,13 @@ static void device_remove(struct pci_dev *pdev)
		(ulong)pdev, (ulong)tdev);

	tsse_sriov_disable(tdev);
	tsse_ipc_deinit(tdev);
	if (tdev->fw) {
		release_firmware(tdev->fw);
		tdev->fw = NULL;
	}
	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tsse_image_load.attr);
	tsse_ipc_deinit(tdev);
	kfree(tdev->fw_data);
	vuart_uninit_port(pdev);
	tsse_devmgr_rm_dev(tdev);
	ida_free(&tsse_ida, tdev->id);
@@ -378,6 +396,6 @@ module_exit(tsse_exit);

MODULE_AUTHOR("montage-tech.com");
MODULE_DESCRIPTION("TSSE device driver");
MODULE_VERSION("1.0.0");
MODULE_VERSION("1.1.2");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(TSSE_FIRMWARE);
+99 −30
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * This file is part of tsse driver for Linux
 *
 * Copyright © 2023 Montage Technology. All rights reserved.
 * Copyright © 2023-2024 Montage Technology. All rights reserved.
 */

#include <linux/types.h>
@@ -14,26 +14,12 @@
#include <linux/delay.h>
#include "tsse_dev.h"
#include "tsse_irq.h"
#include "tsse_handle.h"
static DEFINE_MUTEX(tsse_dev_table_lock);
static LIST_HEAD(tsse_dev_table);

static DEFINE_MUTEX(algs_lock);

static inline void tsse_list_del(struct list_head *entry)
{
	WRITE_ONCE(entry->next->prev, entry->prev);
	WRITE_ONCE(entry->prev->next, entry->next);
}
static inline void tsse_list_add(struct list_head *new, struct list_head *prev,
				 struct list_head *next)
{
	WRITE_ONCE(new->next, next);
	WRITE_ONCE(new->prev, prev);
	mb();  /* Make sure new node updates first */
	WRITE_ONCE(next->prev, new);
	WRITE_ONCE(prev->next, new);
}

static int tsse_dev_pf_get(struct tsse_dev *vf_tsse_dev)
{
	int ret = 0;
@@ -116,12 +102,10 @@ static int tsse_stop_dev(struct tsse_dev *tdev, bool busy_exit)
		if (busy_exit)
			return -EBUSY;
	}
	if (tdev->qpairs_bank.num_qparis != 0) {
	mutex_lock(&tsse_dev_table_lock);
	tsse_list_del(&tdev->list);
	mutex_unlock(&tsse_dev_table_lock);
	tsse_dev_info(tdev, "removed from active dev table list\n");
	}

	tsse_dev_info(tdev, "device stopped\n");

@@ -134,12 +118,6 @@ int tsse_start_dev(struct tsse_dev *tdev)
	struct list_head *prev_node = &tsse_dev_table;
	int ret = 0;

	if (tdev->qpairs_bank.num_qparis == 0) {
		set_bit(TSSE_DEV_STATUS_STARTED, &tdev->status);
		tsse_dev_info(tdev, "device started\n");
		return 0;
	}

	set_bit(TSSE_DEV_STATUS_STARTING, &tdev->status);

	mutex_lock(&tsse_dev_table_lock);
@@ -156,9 +134,9 @@ int tsse_start_dev(struct tsse_dev *tdev)
	set_bit(TSSE_DEV_STATUS_STARTED, &tdev->status);
	tsse_list_add(&tdev->list, prev_node, prev_node->next);

	tsse_dev_info(tdev, "device started\n");
	mutex_unlock(&tsse_dev_table_lock);

	tsse_dev_info(tdev, "device started\n");
	return 0;
clear_status:
	mutex_unlock(&tsse_dev_table_lock);
@@ -199,3 +177,94 @@ struct list_head *tsse_devmgr_get_head(void)
{
	return &tsse_dev_table;
}

/**
 * tsse_get_dev_by_handle() - Get TSSE device by its handle
 * @handle: handle to TSSE device
 * Return: pointer to TSSE device structure if found, otherwise NULL
 */
struct tsse_dev *tsse_get_dev_by_handle(int handle)
{
	struct list_head *itr = NULL;
	struct tsse_dev *ptr = NULL;
	struct tsse_dev *tdev = NULL;

	mutex_lock(&tsse_dev_table_lock);
	list_for_each(itr, &tsse_dev_table) {
		ptr = list_entry(itr, struct tsse_dev, list);
		if (handle == ptr->id) {
			tdev = ptr;
			break;
		}
	}
	mutex_unlock(&tsse_dev_table_lock);

	if (!tdev) {
		pr_err("%s %d: no such device: %d\n", __func__, __LINE__, handle);
		return NULL;
	}
	return tdev;
}

/**
 * tsse_get_available_handle() - get handle from available device.
 * Return: -1 if no available device, otherwise the handle id.
 */
int tsse_get_available_handle(void)
{
	struct list_head *itr = NULL;
	struct tsse_dev *tdev = NULL;

	mutex_lock(&tsse_dev_table_lock);
	list_for_each(itr, &tsse_dev_table) {
		tdev = list_entry(itr, struct tsse_dev, list);
		break;
	}
	mutex_unlock(&tsse_dev_table_lock);

	if (!tdev) {
		pr_err("%s(): device not ready\n", __func__);
		return -1;
	}
	return tdev->id;
}
EXPORT_SYMBOL_GPL(tsse_get_available_handle);

/**
 * tsse_get_domain_by_handle() - get IOMMU domain from the handle of device.
 * @handle: handle of a TSSE device
 * Return: pointer to IOMMU domain of the device if the handle is correct
 * and IOMMU enabled, otherwise NULL.
 */
struct iommu_domain *tsse_get_domain_by_handle(int handle)
{
	struct tsse_dev *tdev;
	struct pci_dev *pdev;

	if (!iommu_present(&pci_bus_type)) {
		pr_err("%s(): IOMMU is not enabled\n", __func__);
		return NULL;
	}
	tdev = tsse_get_dev_by_handle(handle);
	if (!tdev)
		return NULL;

	pdev = tdev->tsse_pci_dev.pci_dev;
	return iommu_get_domain_for_dev(&pdev->dev);
}
EXPORT_SYMBOL_GPL(tsse_get_domain_by_handle);

int tsse_process_for_all(tsse_dev_process_func func)
{
	struct list_head *itr = NULL;
	struct tsse_dev *tdev = NULL;
	int rc = 0;

	list_for_each(itr, &tsse_dev_table) {
		tdev = list_entry(itr, struct tsse_dev, list);
		rc = func(tdev);
		if (rc)
			break;
	}
	return rc;
}
+37 −48
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * This file is part of tsse driver for Linux
 *
 * Copyright © 2023 Montage Technology. All rights reserved.
 * Copyright © 2023-2024 Montage Technology. All rights reserved.
 */

#include <linux/types.h>
@@ -18,37 +18,19 @@
#include <linux/firmware.h>

#include "tsse_dev.h"
#include "tsse_ipc.h"
#include "tsse_service.h"
#include "tsse_fw_service.h"

#define SEARCH_PATTERN "MT_CFG_BUILD_VERSION_DETAIL"
#define SPACE_CH ' '

static int fw_send_msg(struct tsse_ipc *tsseipc, struct ipc_msg *msg)
static int fw_send_msg(struct tsse_dev *tdev, struct fw_load *fw_task)
{
	u8 *h2d;
	u32 int_reg;
	struct tsse_ipc *tsseipc = tdev->ipc;

	mutex_lock(&tsseipc->list_lock);

	int_reg = readl(tsseipc->virt_addr + HOST2MAIN_INTR_SET_OFFSET);
	if ((int_reg & IPC_REGISTER_INT_SET) != 0) {
		mutex_unlock(&tsseipc->list_lock);
		return -EFAULT;
	}
	if (msg->header.i_len < sizeof(struct ipc_header) +
		sizeof(struct msg_info) + sizeof(struct fw_load)) {
		dev_err(tsseipc->dev, "msg format error\n");
		return -EFAULT;
	}
	h2d = (u8 *)(tsseipc->virt_addr + HOST2MAIN_IPC_OFFSET);
	memcpy_toio(h2d, msg, sizeof(struct ipc_header));
	memcpy_toio(h2d + sizeof(struct ipc_header), (u8 *)msg->i_data,
		    msg->header.i_len - sizeof(struct ipc_header));
	writel(0x1, tsseipc->virt_addr + HOST2MAIN_INTR_SET_OFFSET);

	dev_info(tsseipc->dev, "notify device to get firmware\n");
	mutex_unlock(&tsseipc->list_lock);
	return 0;
	dev_dbg(tsseipc->dev, "notify device\n");
	return ipc_h2d_msg_send_legacy(tdev->id, IPC_MESSAGE_BOOT, fw_task, sizeof(struct fw_load));
}

/**
@@ -103,42 +85,46 @@ int get_firmware_version(const struct firmware *fw, char *fw_version_out)
}

/**
 * fw_service() - Firmware service to handle IPC message from mainCPU.
 * fw_service() - Firmware service to handle IPC message from device.
 * It will write init or manual load firmware to PCIe BAR and send message back.
 * @tsseipc_t: pointer to a structure used for IPC
 * @msg_t: pointer to IPC message
 * @handle: handle to TSSE device
 * @msg_payload: pointer to IPC message payload
 * @length: length of the msg_payload
 * Return: 0 on success, error code otherwise
 */
void fw_service(void *tsseipc_t, void *msg_t)
int fw_service(int handle, void *msg_payload, uint32_t length)
{
	void __iomem *fw;
	uint32_t size;
	uint32_t task_offset;
	struct fw_load *fw_task;
	struct tsse_dev *tdev;
	struct tsse_ipc *tsseipc = (struct tsse_ipc *)tsseipc_t;
	struct ipc_msg *msg = (struct ipc_msg *)msg_t;
	struct tsse_ipc *tsseipc;
	struct fw_load *fw_task;

	task_offset = sizeof(struct msg_info);
	fw_task = (struct fw_load *)((uint8_t *)msg->i_data + task_offset);
	tdev = pci_to_tsse_dev(tsseipc->pdev);
	if (!msg_payload || !length) {
		pr_err("%s %d: invalid input parameter\n", __func__, __LINE__);
		return -EINVAL;
	}
	tdev = tsse_get_dev_by_handle(handle);
	if (!tdev)
		return -ENODEV;

	if (!tdev || !tdev->fw) {
	tsseipc = tdev->ipc;
	fw_task = (struct fw_load *) msg_payload;
	if (!tdev->fw) {
		fw_task->result = 1;
		fw_task->size = 0;
		dev_info(tsseipc->dev, "firmware loading failed\n");
		if (fw_send_msg(tsseipc, msg))
		if (fw_send_msg(tdev, fw_task))
			dev_err(tsseipc->dev, "notify device failed\n");
		return;
		return -ENOENT;
	}

	fw_task->result = 0;
	fw_task->size = tdev->fw->size;
	size = tdev->fw->size;
	fw = tsseipc->virt_addr + fw_task->offset + FW_BASE;

	memcpy_toio((u8 *)fw, tdev->fw->data, size);
	memcpy_toio((u8 *)fw, tdev->fw->data, tdev->fw->size);
	dev_info(tsseipc->dev, "firmware loading done\n");
	if (fw_send_msg(tsseipc, msg))
	if (fw_send_msg(tdev, fw_task))
		dev_err(tsseipc->dev, "notify device failed\n");

	if (tdev->fw_version_exist)
@@ -150,6 +136,7 @@ void fw_service(void *tsseipc_t, void *msg_t)
		memset(tdev->fw_version, 0, TSSE_FW_VERSION_LEN);
		tdev->fw_version_exist = false;
	}
	return 0;
}

/**
@@ -162,9 +149,11 @@ void fw_service(void *tsseipc_t, void *msg_t)
int tsse_fw_load(struct pci_dev *pdev, const char *name, const struct firmware **fw)
{
	int result;
	struct tsse_dev *tdev = pci_to_tsse_dev(pdev);

	result = request_firmware(fw, name, &pdev->dev);
	result = request_firmware_into_buf(fw, name, &pdev->dev,
		tdev->fw_data, TSSE_FIRMWARE_MAX_LENGTH);
	if (result)
		dev_err(&pdev->dev, "%s failed for %s\n", __func__, name);
		dev_err(&pdev->dev, "%s failed for %s: %d\n", __func__, name, result);
	return result;
}
Loading