Unverified Commit 08c8dd14 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!5045 [OLK-6.6] Add support for Mont-TSSE firmware update and fix 0day bugs

Merge Pull Request from: @carriercai 
 
- supported using sysfs to update firmware
- optimized communication with devices
- fixed 0 day bugs
- Update files:
  driver folder:drivers/crypto/montage/
 
 
Link:https://gitee.com/openeuler/kernel/pulls/5045

 

Reviewed-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parents 4214ed2e 77956232
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#define TSSE_PCI_MAX_BARS 4
#define TSSE_FW_VERSION_LEN 32

struct tsse_bar {
	void __iomem *virt_addr;
	resource_size_t addr;
@@ -58,6 +59,7 @@ struct tsse_dev {
	void *mbx_hw;
	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)
@@ -72,7 +74,6 @@ 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 *get_tssedev(int id);

static inline struct tsse_dev *pci_to_tsse_dev(struct pci_dev *pci_dev)
{
+59 −5
Original line number Diff line number Diff line
@@ -11,18 +11,25 @@
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/pci-ats.h>
#include <linux/sysfs.h>

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

#define CLUSTER_SLOT_CONFIG_OFFSET 0x5780000
#define QPAIR_SETTING_OFFSET 0x50000
#define BAR_START 2
#define BAR_END 4

static DEFINE_IDA(tsse_ida);

static inline void tsse_qpair_enable_pf(struct tsse_dev *tdev, bool enable)
{
	writel(enable ? 1 : 0,
	       TSSE_DEV_BARS(tdev)[2].virt_addr + 0x5780000 + 0x50000);
	       TSSE_DEV_BARS(tdev)[2].virt_addr +
		   CLUSTER_SLOT_CONFIG_OFFSET + QPAIR_SETTING_OFFSET);
}
static int tsse_sriov_disable(struct tsse_dev *tdev)
{
@@ -107,6 +114,39 @@ static int tsse_sriov_configure(struct pci_dev *pdev, int num_vfs_param)
	return num_vfs_param;
}

/**
 * This function will be called when user writes string to /sys/bus/pci/devices/.../tsse_image_load.
 * Driver will always loads /lib/firmware/tsse_firmware.bin.
 * @dev: device
 * @attr: device attribute
 * @buf: string that user writes
 * @count: string length that user writes
 * Return: the number of bytes used from the buffer, here it is just the count argument.
*/
static ssize_t tsse_image_load_store(struct device *dev, struct device_attribute *attr,
	const char *buf, size_t count)
{
	struct pci_dev *pdev = NULL;
	struct tsse_dev *tdev = NULL;

	pdev = container_of(dev, struct pci_dev, dev);
	if (pdev)
		tdev = pci_to_tsse_dev(pdev);
	if (buf && count && tdev) {
		tsse_dev_info(tdev, "receive command to load firmware %s\n", TSSE_FIRMWARE);
		if (!tsse_fw_load(pdev, TSSE_FIRMWARE, &tdev->fw)) {
			if (!get_firmware_version(tdev->fw, tdev->fw_version))
				tdev->fw_version_exist = true;
			if (tsse_fw_manual_load_ipc(pdev))
				dev_err(&pdev->dev, "%s %d: firmware update failed\n",
					__func__, __LINE__);
		}
	}
	return count;
}

DEVICE_ATTR_WO(tsse_image_load);

static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	int status = 0;
@@ -163,7 +203,7 @@ static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		goto out_err;
	}

	for (bar = 2; bar < 4;) {
	for (bar = BAR_START; bar < BAR_END;) {
		TSSE_DEV_BARS(tdev)[bar].addr = pci_resource_start(pdev, bar);
		TSSE_DEV_BARS(tdev)[bar].size = pci_resource_len(pdev, bar);
		TSSE_DEV_BARS(tdev)
@@ -219,9 +259,13 @@ static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		status = -EFAULT;
		goto out_err_port_init;
	}

	tdev->fw_version_exist = false;
	/* Its result not break driver init process */
	if (!tsse_fw_load(pdev))
		get_firmware_version((char *)tdev->fw->data, tdev->fw->size, tdev->fw_version);
	if (!tsse_fw_load(pdev, TSSE_FIRMWARE, &tdev->fw)) {
		if (!get_firmware_version(tdev->fw, tdev->fw_version))
			tdev->fw_version_exist = true;
	}

	if (tsse_ipc_init(pdev)) {
		dev_err(&pdev->dev,
@@ -231,13 +275,22 @@ static int device_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		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;
	}

	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:
	vuart_uninit_port(pdev);
out_err_port_init:
@@ -261,6 +314,7 @@ static void device_remove(struct pci_dev *pdev)
		release_firmware(tdev->fw);
		tdev->fw = NULL;
	}
	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_tsse_image_load.attr);
	tsse_ipc_deinit(tdev);
	vuart_uninit_port(pdev);
	tsse_devmgr_rm_dev(tdev);
+1 −29
Original line number Diff line number Diff line
@@ -34,12 +34,6 @@ static inline void tsse_list_add(struct list_head *new, struct list_head *prev,
	WRITE_ONCE(prev->next, new);
}

static inline void tsse_list_add_tail(struct list_head *new,
				      struct list_head *head)
{
	tsse_list_add(new, head->prev, head);
}

static int tsse_dev_pf_get(struct tsse_dev *vf_tsse_dev)
{
	int ret = 0;
@@ -104,7 +98,7 @@ void tsse_dev_put(struct tsse_dev *tdev)
	}
}

int tsse_stop_dev(struct tsse_dev *tdev, bool busy_exit)
static int tsse_stop_dev(struct tsse_dev *tdev, bool busy_exit)
{
	int times, max_retry = 150;

@@ -172,13 +166,11 @@ int tsse_start_dev(struct tsse_dev *tdev)
	clear_bit(TSSE_DEV_STATUS_STARTED, &tdev->status);
	return ret;
}
EXPORT_SYMBOL_GPL(tsse_start_dev);

int tsse_prepare_restart_dev(struct tsse_dev *tdev)
{
	return tsse_stop_dev(tdev, false);
}
EXPORT_SYMBOL_GPL(tsse_prepare_restart_dev);

void tsse_devmgr_rm_dev(struct tsse_dev *tdev)
{
@@ -186,7 +178,6 @@ void tsse_devmgr_rm_dev(struct tsse_dev *tdev)
	tsse_dev_free_irq_vectors(tdev);
	msleep(300);
}
EXPORT_SYMBOL_GPL(tsse_devmgr_rm_dev);

int tsse_devmgr_add_dev(struct tsse_dev *tdev)
{
@@ -203,27 +194,8 @@ int tsse_devmgr_add_dev(struct tsse_dev *tdev)
	}
	return ret;
}
EXPORT_SYMBOL_GPL(tsse_devmgr_add_dev);

struct list_head *tsse_devmgr_get_head(void)
{
	return &tsse_dev_table;
}

struct tsse_dev *get_tssedev(int id)
{
	struct list_head *itr;
	struct tsse_dev *ptr;

	mutex_lock(&tsse_dev_table_lock);

	list_for_each(itr, &tsse_dev_table) {
		ptr = list_entry(itr, struct tsse_dev, list);
		break;
	}

	mutex_unlock(&tsse_dev_table_lock);

	return ptr;
}
EXPORT_SYMBOL_GPL(get_tssedev);
+54 −48
Original line number Diff line number Diff line
@@ -21,25 +21,28 @@
#include "tsse_service.h"

#define SEARCH_PATTERN "MT_CFG_BUILD_VERSION_DETAIL"
#define SEARCH_PATTERN_LEN 28
#define SPACE_CH ' '

int fw_send_msg(struct tsse_ipc *tsseipc, struct ipc_msg *msg)
static int fw_send_msg(struct tsse_ipc *tsseipc, struct ipc_msg *msg)
{
	u8 *h2d;
	u32 int_reg;
	u32 rc;

	mutex_lock(&tsseipc->list_lock);

	int_reg = readl(tsseipc->virt_addr + HOST2MAIN_INTR_SET_OFFSET);
	if ((int_reg & IPC_REGISTER_INT_SET) != 0) {
		rc = -1;
		mutex_unlock(&tsseipc->list_lock);
		return rc;
		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), (u32 *)msg->i_data,
	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);

@@ -48,41 +51,30 @@ int fw_send_msg(struct tsse_ipc *tsseipc, struct ipc_msg *msg)
	return 0;
}

void fw_free(void *msg_t)
{
	struct tsse_msg *tssemsg;
	struct ipc_msg *payload;

	payload = (struct ipc_msg *)msg_t;
	tssemsg = container_of(payload, struct tsse_msg, ipc_payload);

	kvfree(tssemsg);
}

int get_firmware_version(char *fw_buffer, uint32_t buffer_len, char *fw_version)
/**
 * Get version information from firmware
 * @fw: firmware pointer
 * @fw_version_out: firmware version string output
 * Return: 0 on success, error code otherwise
*/
int get_firmware_version(const struct firmware *fw, char *fw_version_out)
{
	char *pattern;
	char *space_ch = " ";
	const char *pattern = SEARCH_PATTERN;
	const uint8_t *fw_buffer = fw->data;
	uint32_t pattern_i = 0, buffer_i = 0;
	uint32_t pattern_len = SEARCH_PATTERN_LEN - 1; // Not include "\0"
	uint32_t pattern_len = strlen(pattern); // Not include "\0"
	uint32_t version_start = 0;
	uint32_t version_len = 0;

	pattern = kzalloc(SEARCH_PATTERN_LEN, GFP_KERNEL);
	if (!pattern)
		return -1;

	snprintf(pattern, SEARCH_PATTERN_LEN, SEARCH_PATTERN);

	while (buffer_i < buffer_len) {
		if (pattern[pattern_i] == fw_buffer[buffer_i]) {
	while (buffer_i < fw->size) {
		if (pattern[pattern_i] == (char) fw_buffer[buffer_i]) {
			buffer_i++;
			pattern_i++;
		}
		if (pattern_i == pattern_len) {
			break;	// pattern found
		} else if ((buffer_i < buffer_len) &&
			 (pattern[pattern_i] != fw_buffer[buffer_i])) {
		} else if ((buffer_i < fw->size) &&
			 (pattern[pattern_i] != (char) fw_buffer[buffer_i])) {
			// mismatch after pattern_i matches
			if (pattern_i != 0) {
				// since the pattern has no common prefix, when mismatch,
@@ -93,22 +85,28 @@ int get_firmware_version(char *fw_buffer, uint32_t buffer_len, char *fw_version)
			}
		}
	}
	kfree(pattern);
	if (pattern_i == pattern_len) {
		buffer_i++;
		version_start = buffer_i;
		while (buffer_i < buffer_len) {
			if (fw_buffer[buffer_i] == space_ch[0]) {
		while (buffer_i < fw->size) {
			if (fw_buffer[buffer_i] == SPACE_CH) {
				version_len = buffer_i - version_start;
				strscpy(fw_version, fw_buffer + version_start, version_len + 1);
				if (version_len >= TSSE_FW_VERSION_LEN - 1)
					version_len = TSSE_FW_VERSION_LEN - 2;
				strscpy(fw_version_out, fw_buffer + version_start, version_len + 1);
				return 0;
			}
			buffer_i++;
		}
	}
	return -1;
	return -EINVAL;
}

/**
 * Firmware service to handle IPC message from mainCPU.
 * It will write init or manual load firmware to PCIe BAR and send message back.
 * No return value.
*/
void fw_service(void *tsseipc_t, void *msg_t)
{
	void __iomem *fw;
@@ -120,16 +118,15 @@ void fw_service(void *tsseipc_t, void *msg_t)
	struct ipc_msg *msg = (struct ipc_msg *)msg_t;

	task_offset = sizeof(struct msg_info);
	fw_task = (struct fw_load *)(msg->i_data +
				     task_offset / sizeof(uint32_t));

	fw_task = (struct fw_load *)((uint8_t *)msg->i_data + task_offset);
	tdev = pci_to_tsse_dev(tsseipc->pdev);

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

@@ -140,24 +137,33 @@ void fw_service(void *tsseipc_t, void *msg_t)

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

	if (tdev->fw_version_exist)
		dev_info(tsseipc->dev, "firmware version: %s\n", tdev->fw_version);

	if (tdev->fw) {
		release_firmware(tdev->fw);
		tdev->fw = NULL;
		memset(tdev->fw_version, 0, TSSE_FW_VERSION_LEN);
		tdev->fw_version_exist = false;
	}
}

int tsse_fw_load(struct pci_dev *pdev)
/**
 * Load firmware from /lib/firmware
 * @pdev: pci device
 * @name: firmware file name
 * @fw: pointer to firmware pointer
 * Return: 0 on success, error code otherwise
*/
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(&tdev->fw, TSSE_FIRMWARE, &pdev->dev);
	result = request_firmware(fw, name, &pdev->dev);
	if (result)
		dev_err(&pdev->dev, "%s failed\n", __func__);
		dev_err(&pdev->dev, "%s failed for %s\n", __func__, name);
	return result;
}
+4 −2
Original line number Diff line number Diff line
@@ -8,10 +8,12 @@
#ifndef __TSSE_FW_SERVICE_H__
#define __TSSE_FW_SERVICE_H__

#include <linux/firmware.h>

#define FW_BASE 0x7000000
#define TSSE_FIRMWARE "tsse_firmware.bin"

void fw_service(void *tsseipc_t, void *msg_t);
int tsse_fw_load(struct pci_dev *pdev);
int get_firmware_version(char *fw_buffer, uint32_t buffer_len, char *fw_version);
int tsse_fw_load(struct pci_dev *pdev, const char *name, const struct firmware **fw);
int get_firmware_version(const struct firmware *fw, char *fw_version_out);
#endif
Loading