Commit 691ff791 authored by zhangshuowen's avatar zhangshuowen Committed by zhangshuowen96
Browse files

drivers:misc:sdma-dae: add fast mode

kunpeng inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IAQKTS


CVE: NA

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

1.add fast/safe mode switch function through module parameter
2.add mode verification while reading info/sending task, adding
authorities and so on
3.change mmap function for fast mode

Signed-off-by: default avatarzhangshuowen <zhangshuowen@hisilicon.com>
parent 9b3a6da2
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-or-later
MODULE_NAME := sdma-dae
MODULE_NAME := sdma_dae
ccflags-y += -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-sign-compare -Wno-type-limits

$(MODULE_NAME)-objs := sdma_main.o sdma_cdev.o sdma_umem.o sdma_irq.o sdma_auth.o sdma_dbg.o

obj-$(CONFIG_SDMA_DAE) += sdma-dae.o
 No newline at end of file
obj-$(CONFIG_SDMA_DAE) += sdma_dae.o
 No newline at end of file
+12 −7
Original line number Diff line number Diff line
@@ -15,15 +15,16 @@
#define HISI_SDMA_MMAP_IO			2
#define HISI_SDMA_MMAP_SHMEM			3
#define HISI_SDMA_FSM_INTERVAL			20
#define HISI_SDMA_FSM_TIMEOUT			10
#define HISI_SDMA_FSM_TIMEOUT			5
#define HISI_SDMA_LOW_ADDR_SHIFT		32

#define HISI_SDMA_MAX_BASE_ADDR_SIZE		0x100000
#define HISI_SDMA_MAX_COMMEN_BASE_ADDR_SIZE	0x10000
#define HISI_SDMA_CHANNEL_IOMEM_SIZE		0x1000
#define HISI_SDMA_SQ_ENTRY_SIZE			64UL
#define HISI_SDMA_CQ_ENTRY_SIZE			16UL
#define HISI_SDMA_SQ_LENGTH			(1U << 16)
#define HISI_SDMA_CQ_LENGTH			(1U << 16)
#define HISI_SDMA_SQ_LENGTH			(1U << 10)
#define HISI_SDMA_CQ_LENGTH			(1U << 10)

#define HISI_STARS_CHN_NUM			32
#define HISI_SDMA_DEFAULT_CHANNEL_NUM		(192 - HISI_STARS_CHN_NUM)
@@ -40,6 +41,9 @@
#define HISI_SDMA_CLR_NORMAL_SQE_CNT		1
#define HISI_SDMA_CLR_ERR_SQE_CNT		2

#define HISI_SDMA_FAST_MODE			0
#define HISI_SDMA_SAFE_MODE			1

#define HISI_SDMA_HBM_CACHE_PRELOAD_MODE	0x6
#define SDMA_UNUSED				__attribute__((__unused__))

@@ -112,10 +116,10 @@ struct hisi_sdma_cq_entry {
};

struct hisi_sdma_queue_info {
	u32    sq_head;
	u32    sq_tail;
	u32    cq_head;
	u32    cq_tail;
	u16    sq_head;
	u16    sq_tail;
	u16    cq_head;
	u16    cq_tail;
	u32    cq_vld;
	int    lock;
	u32    lock_pid;
@@ -203,5 +207,6 @@ struct hisi_sdma_ioctl_func_list {
#define IOCTL_SDMA_CQ_TAIL_REG		_IOWR('s', 17, struct hisi_sdma_reg_info)
#define IOCTL_SDMA_DFX_REG		_IOWR('s', 18, struct hisi_sdma_reg_info)
#define IOCTL_SDMA_SQE_CNT_REG		_IOW('s', 19, struct hisi_sdma_reg_info)
#define IOCTL_GET_SDMA_MODE			_IOR('s', 20, bool)

#endif
+62 −11
Original line number Diff line number Diff line
@@ -6,7 +6,6 @@
#include <linux/platform_device.h>
#include <linux/sort.h>
#include <linux/mm.h>
#include <linux/version.h>

#include "sdma_hal.h"
#include "sdma_umem.h"
@@ -133,7 +132,7 @@ static int __do_sdma_open(struct hisi_sdma_device *psdma_dev, struct file *file)
	handle = iommu_sva_bind_device(&psdma_dev->pdev->dev, current->mm, NULL);
	if (IS_ERR(handle)) {
		dev_err(&psdma_dev->pdev->dev, "failed to bind sva, %ld\n", PTR_ERR(handle));
		ret = PTR_ERR(handle);
		ret = (int)PTR_ERR(handle);
		goto free_privt_data;
	}

@@ -223,10 +222,17 @@ static int ioctl_sdma_pin_umem(struct file *file, unsigned long arg)

static int ioctl_sdma_get_process_id(struct file *file, unsigned long arg)
{
	struct file_open_data *data = file->private_data;
	u32 pid = (u32)current->tgid;
	u32 pasid = data->pasid;

	if (*(g_info.sdma_mode) == HISI_SDMA_FAST_MODE) {
		if (copy_to_user((u32 __user *)(uintptr_t)arg, &pasid, sizeof(u32)))
			return -EFAULT;
	} else {
		if (copy_to_user((u32 __user *)(uintptr_t)arg, &pid, sizeof(u32)))
			return -EFAULT;
	}

	return 0;
}
@@ -487,6 +493,9 @@ static int ioctl_sdma_add_authority_ht(struct file *file, unsigned long arg)
	u32 list_num;
	int ret;

	if (*(g_info.sdma_mode) == HISI_SDMA_FAST_MODE)
		return 0;

	if (copy_from_user(&pid_info, (struct hisi_sdma_pid_info __user *)(uintptr_t)arg,
			   sizeof(struct hisi_sdma_pid_info))) {
		dev_err(&pdev->pdev->dev, "get hisi_sdma_pid_info failed\n");
@@ -552,9 +561,9 @@ static void sdma_fill_sqe(struct hisi_sdma_sq_entry *sq_entry, struct hisi_sdma_
	sq_entry->src_streamid    = streamid;
	sq_entry->dst_streamid    = streamid;
	sq_entry->src_addr_l      = (u32)(task->src_addr & 0xffffffff);
	sq_entry->src_addr_h      = (u32)(task->src_addr >> 32);
	sq_entry->src_addr_h      = (u32)(task->src_addr >> HISI_SDMA_LOW_ADDR_SHIFT);
	sq_entry->dst_addr_l      = (u32)(task->dst_addr & 0xffffffff);
	sq_entry->dst_addr_h      = (u32)(task->dst_addr >> 32);
	sq_entry->dst_addr_h      = (u32)(task->dst_addr >> HISI_SDMA_LOW_ADDR_SHIFT);
	sq_entry->length_move     = task->length;
	sq_entry->sns             = 1;
	sq_entry->dns             = 1;
@@ -608,6 +617,7 @@ static int sdma_send_task_kernel(struct file_open_data *data,
	}
	sq_tail = pchannel->sync_info_base->sq_tail;
	if (sq_tail >= HISI_SDMA_SQ_LENGTH) {
		spin_unlock(&pchannel->owner_chn_lock);
		dev_err(&pdev->pdev->dev, "sq_tail in share mem wrong, sq_tail = %u\n", sq_tail);
		return -EINVAL;
	}
@@ -866,6 +876,16 @@ static int ioctl_sdma_sqe_cnt_reg(struct file *file, unsigned long arg)
	return 0;
}

static int ioctl_get_sdma_mode(struct file *file SDMA_UNUSED, unsigned long arg)
{
	bool mode = *(g_info.sdma_mode);

	if (copy_to_user((bool __user *)(uintptr_t)arg, &mode, sizeof(bool)))
		return -EFAULT;

	return 0;
}

struct hisi_sdma_ioctl_func_list g_ioctl_funcs[] = {
	{IOCTL_SDMA_GET_PROCESS_ID,		ioctl_sdma_get_process_id},
	{IOCTL_SDMA_GET_CHN,			ioctl_sdma_get_chn},
@@ -886,6 +906,7 @@ struct hisi_sdma_ioctl_func_list g_ioctl_funcs[] = {
	{IOCTL_SDMA_CQ_TAIL_REG,		ioctl_sdma_cq_tail_reg},
	{IOCTL_SDMA_DFX_REG,			ioctl_sdma_dfx_reg},
	{IOCTL_SDMA_SQE_CNT_REG,		ioctl_sdma_sqe_cnt_reg},
	{IOCTL_GET_SDMA_MODE,			ioctl_get_sdma_mode},
};

static long sdma_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -943,6 +964,12 @@ ssize_t sdma_read_info(struct file *file, char __user *buf SDMA_UNUSED, size_t s
	struct hisi_sdma_device *pdev = data->psdma_dev;
	struct device *dev = &pdev->pdev->dev;
	u32 share_chns = *(g_info.share_chns);
	bool mode = *(g_info.sdma_mode);

	if (mode == HISI_SDMA_FAST_MODE)
		dev_info(dev, "sdma is running unter fast mode\n");
	else
		dev_info(dev, "sdma is running unter safe mode\n");

	if (share_chns > pdev->nr_channel)
		share_chns = pdev->nr_channel;
@@ -997,11 +1024,13 @@ static int sdma_dev_release(struct inode *inode SDMA_UNUSED, struct file *file)
	ida_free(g_info.fd_ida, data->ida);

	kfree(file->private_data);
	file->private_data = NULL;
	return 0;
}

static int remap_addr_range(u32 chn_num, u64 offset, u64 size)
{
	bool mode = *(g_info.sdma_mode);
	u64 sync_size;

	sync_size = (u64)((sizeof(struct hisi_sdma_queue_info) + PAGE_SIZE - ALIGN_NUM) /
@@ -1013,8 +1042,11 @@ static int remap_addr_range(u32 chn_num, u64 offset, u64 size)
	}

	if (offset < chn_num * HISI_SDMA_MMAP_CQE) {
		pr_err("sdma not support sqe mmap\n");
		if (mode == HISI_SDMA_SAFE_MODE || size > HISI_SDMA_SQ_SIZE) {
			pr_err("sdma mmap size exceed sqe range\n");
			return -EINVAL;
		}
		return HISI_SDMA_MMAP_SQE;
	} else if (offset < chn_num * HISI_SDMA_MMAP_IO) {
		if (size > HISI_SDMA_CQ_SIZE) {
			pr_err("sdma mmap size exceed cqe range\n");
@@ -1022,8 +1054,11 @@ static int remap_addr_range(u32 chn_num, u64 offset, u64 size)
		}
		return HISI_SDMA_MMAP_CQE;
	} else if (offset < chn_num * HISI_SDMA_MMAP_SHMEM) {
		if (mode == HISI_SDMA_SAFE_MODE || size > HISI_SDMA_REG_SIZE) {
			pr_err("sdma not support io reg mmap\n");
			return -EINVAL;
		}
		return HISI_SDMA_MMAP_IO;
	} else {
		if (size > sync_size) {
			pr_err("sdma mmap size exceed share mem range\n");
@@ -1052,12 +1087,26 @@ static int sdma_dev_mmap(struct file *file, struct vm_area_struct *vma)

	dev_dbg(dev, "sdma total channel num = %u, user mmap offset = 0x%llx", chn_num, offset);
	switch (remap_addr_range(chn_num, offset, size)) {
	case HISI_SDMA_MMAP_SQE:
		pchan = chn_base + offset;
		pfn_start = virt_to_phys(pchan->sq_base) >> PAGE_SHIFT;
		ret = remap_pfn_range(vma, vma->vm_start, pfn_start, size, vma->vm_page_prot);
		break;

	case HISI_SDMA_MMAP_CQE:
		pchan = chn_base + offset - chn_num * HISI_SDMA_MMAP_CQE;
		pfn_start = virt_to_phys(pchan->cq_base) >> PAGE_SHIFT;
		ret = remap_pfn_range(vma, vma->vm_start, pfn_start, size, vma->vm_page_prot);
		break;

	case HISI_SDMA_MMAP_IO:
		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
		pfn_start = (io_base + HISI_SDMA_CH_OFFSET) >> PAGE_SHIFT;
		pfn_start += (offset - chn_num * HISI_SDMA_MMAP_IO) * HISI_SDMA_REG_SIZE /
			     PAGE_SIZE;
		ret = io_remap_pfn_range(vma, vma->vm_start, pfn_start, size, vma->vm_page_prot);
		break;

	case HISI_SDMA_MMAP_SHMEM:
		pchan = chn_base + offset - chn_num * HISI_SDMA_MMAP_SHMEM;
		pfn_start = virt_to_phys(pchan->sync_info_base) >> PAGE_SHIFT;
@@ -1088,9 +1137,11 @@ void sdma_cdev_init(struct cdev *cdev)
	cdev->owner = THIS_MODULE;
}

void sdma_info_sync_cdev(struct hisi_sdma_core_device *p, u32 *share_chns, struct ida *fd_ida)
void sdma_info_sync_cdev(struct hisi_sdma_core_device *p, u32 *share_chns, struct ida *fd_ida,
			 bool *safe_mode)
{
	g_info.core_dev = p;
	g_info.fd_ida = fd_ida;
	g_info.share_chns = share_chns;
	g_info.sdma_mode = safe_mode;
}
+3 −1
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ struct hisi_sdma_core_device {

struct hisi_sdma_global_info {
	u32 *share_chns;
	bool *sdma_mode;
	struct hisi_sdma_core_device *core_dev;
	struct ida *fd_ida;
};
@@ -104,7 +105,8 @@ struct hisi_sdma_global_info {
void sdma_clear_pid_ref(struct hisi_sdma_device *psdma_dev);
int sdma_create_dbg_node(struct dentry *sdma_dbgfs_dir);
void sdma_cdev_init(struct cdev *cdev);
void sdma_info_sync_cdev(struct hisi_sdma_core_device *p, u32 *share_chns, struct ida *fd_ida);
void sdma_info_sync_cdev(struct hisi_sdma_core_device *p, u32 *share_chns, struct ida *fd_ida,
			 bool *safe_mode);
void sdma_info_sync_dbg(struct hisi_sdma_core_device *p, u32 *share_chns);

static inline void chn_set_val(struct hisi_sdma_channel *pchan, int reg, u32 val, u32 mask)
+6 −1
Original line number Diff line number Diff line
@@ -23,6 +23,10 @@ u32 share_chns = 16;
module_param(share_chns, uint, RW_R_R);
MODULE_PARM_DESC(share_chns, "num of share channels, 16 by default");

static bool safe_mode = true; /* fast mode by default */
module_param(safe_mode, bool, RW_R_R);
MODULE_PARM_DESC(safe_mode, "| 0 - fast_mode| 1 - safe_mode(default)|");

struct ida fd_ida;
struct hisi_sdma_core_device hisi_sdma_core_device = {0};
static struct class *sdma_class;
@@ -159,6 +163,7 @@ void sdma_destroy_channels(struct hisi_sdma_device *psdma_dev)

	sdma_free_all_sq_cq(psdma_dev);
	kfree(psdma_dev->channels);
	psdma_dev->channels = NULL;
}

int sdma_init_channels(struct hisi_sdma_device *psdma_dev)
@@ -501,7 +506,7 @@ static int __init sdma_driver_init(void)
	long ret;

	ida_init(&fd_ida);
	sdma_info_sync_cdev(&hisi_sdma_core_device, &share_chns, &fd_ida);
	sdma_info_sync_cdev(&hisi_sdma_core_device, &share_chns, &fd_ida, &safe_mode);
	sdma_info_sync_dbg(&hisi_sdma_core_device, &share_chns);

	sdma_class = class_create(THIS_MODULE, "sdma");