From 60c4612d62f753bb195176fd8439957144fcac0d Mon Sep 17 00:00:00 2001 From: Jon Lin Date: Tue, 19 Sep 2023 11:41:55 +0800 Subject: [PATCH] misc: rockchip: pcie-rkep: Support adding virtual id by ioctl Change-Id: I020ca781ac684caa5fe1c066c1e4b2a65d4891a5 Signed-off-by: Jon Lin --- drivers/misc/rockchip/pcie-rkep.c | 84 ++++++++++++++++++++++++++++--- include/uapi/linux/rk-pcie-ep.h | 2 + 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/drivers/misc/rockchip/pcie-rkep.c b/drivers/misc/rockchip/pcie-rkep.c index 8ad5a9b55272..f91dbc7aacb6 100644 --- a/drivers/misc/rockchip/pcie-rkep.c +++ b/drivers/misc/rockchip/pcie-rkep.c @@ -87,6 +87,8 @@ static DEFINE_MUTEX(rkep_mutex); #define PCIE_CFG_ELBI_APP_OFFSET 0xe00 #define PCIE_ELBI_REG_NUM 0x2 +#define RKEP_EP_VIRTUAL_ID_MAX (8 * 4096) + struct pcie_rkep_msix_context { struct pci_dev *dev; u16 msg_id; @@ -109,6 +111,8 @@ struct pcie_rkep { struct pcie_ep_obj_info *obj_info; struct page *user_pages; /* Allocated physical memory for user space */ struct fasync_struct *async; + struct mutex dev_lock_mutex; + DECLARE_BITMAP(virtual_id_bitmap, RKEP_EP_VIRTUAL_ID_MAX); }; static int rkep_ep_dma_xfer(struct pcie_rkep *pcie_rkep, struct pcie_ep_dma_block_req *dma) @@ -123,6 +127,43 @@ static int rkep_ep_dma_xfer(struct pcie_rkep *pcie_rkep, struct pcie_ep_dma_bloc return ret; } +static int rkep_ep_request_virtual_id(struct pcie_rkep *pcie_rkep) +{ + int index; + + mutex_lock(&pcie_rkep->dev_lock_mutex); + index = find_first_zero_bit(pcie_rkep->virtual_id_bitmap, RKEP_EP_VIRTUAL_ID_MAX); + if (index > RKEP_EP_VIRTUAL_ID_MAX) { + dev_err(&pcie_rkep->pdev->dev, "request virtual id %d is invalid\n", index); + mutex_unlock(&pcie_rkep->dev_lock_mutex); + return -EINVAL; + } + __set_bit(index, pcie_rkep->virtual_id_bitmap); + mutex_unlock(&pcie_rkep->dev_lock_mutex); + + dev_dbg(&pcie_rkep->pdev->dev, "request virtual id %d\n", index); + + return index; +} + +static int rkep_ep_release_virtual_id(struct pcie_rkep *pcie_rkep, int index) +{ + if (index > RKEP_EP_VIRTUAL_ID_MAX) { + dev_err(&pcie_rkep->pdev->dev, "release virtual id %d out of range\n", index); + + return -EINVAL; + } + + if (!test_bit(index, pcie_rkep->virtual_id_bitmap)) + dev_err(&pcie_rkep->pdev->dev, "release virtual id %d is already free\n", index); + + mutex_lock(&pcie_rkep->dev_lock_mutex); + __clear_bit(index, pcie_rkep->virtual_id_bitmap); + mutex_unlock(&pcie_rkep->dev_lock_mutex); + + return 0; +} + static int pcie_rkep_fasync(int fd, struct file *file, int mode) { struct miscdevice *miscdev = file->private_data; @@ -267,7 +308,7 @@ static long pcie_rkep_ioctl(struct file *file, unsigned int cmd, unsigned long a struct pcie_ep_dma_cache_cfg cfg; struct pcie_ep_dma_block_req dma; void __user *uarg = (void __user *)args; - int ret; + int ret, index; u64 addr; argp = (void __user *)args; @@ -313,6 +354,32 @@ static long pcie_rkep_ioctl(struct file *file, unsigned int cmd, unsigned long a dev_err(&pcie_rkep->pdev->dev, "failed to transfer dma, ret=%d\n", ret); return -EFAULT; } + break; + case PCIE_EP_REQUEST_VIRTUAL_ID: + index = rkep_ep_request_virtual_id(pcie_rkep); + if (index < 0) { + dev_err(&pcie_rkep->pdev->dev, + "request virtual id failed, ret=%d\n", index); + + return -EFAULT; + } + if (copy_to_user(argp, &index, sizeof(index))) + return -EFAULT; + break; + case PCIE_EP_RELEASE_VIRTUAL_ID: + ret = copy_from_user(&index, uarg, sizeof(index)); + if (ret) { + dev_err(&pcie_rkep->pdev->dev, "failed to get dma_data copy from userspace\n"); + return -EFAULT; + } + ret = rkep_ep_release_virtual_id(pcie_rkep, index); + if (ret < 0) { + dev_err(&pcie_rkep->pdev->dev, + "release virtual id %d failed, ret=%d\n", index, ret); + + return -EFAULT; + } + break; default: break; } @@ -758,6 +825,12 @@ static int pcie_rkep_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!pcie_rkep) return -ENOMEM; + name = devm_kzalloc(&pdev->dev, MISC_DEV_NAME_MAX_LENGTH, GFP_KERNEL); + if (!name) + return -ENOMEM; + + __set_bit(0, pcie_rkep->virtual_id_bitmap); + ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "pci_enable_device failed %d\n", ret); @@ -796,17 +869,14 @@ static int pcie_rkep_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev_dbg(&pdev->dev, "get bar4 address is %p\n", pcie_rkep->bar4); - name = devm_kzalloc(&pdev->dev, MISC_DEV_NAME_MAX_LENGTH, GFP_KERNEL); - if (!name) { - ret = -ENOMEM; - goto err_pci_iomap; - } sprintf(name, "%s-%s", DRV_NAME, dev_name(&pdev->dev)); pcie_rkep->dev.minor = MISC_DYNAMIC_MINOR; pcie_rkep->dev.name = name; pcie_rkep->dev.fops = &pcie_rkep_fops; pcie_rkep->dev.parent = NULL; + mutex_init(&pcie_rkep->dev_lock_mutex); + ret = misc_register(&pcie_rkep->dev); if (ret) { dev_err(&pdev->dev, "failed to register misc device.\n"); @@ -839,8 +909,6 @@ static int pcie_rkep_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } - - #if IS_ENABLED(CONFIG_PCIE_FUNC_RKEP_USERPAGES) pcie_rkep->user_pages = alloc_contig_pages(RKEP_USER_MEM_SIZE >> PAGE_SHIFT, GFP_KERNEL, 0, NULL); diff --git a/include/uapi/linux/rk-pcie-ep.h b/include/uapi/linux/rk-pcie-ep.h index c5c42507f7b5..8997b3991e30 100644 --- a/include/uapi/linux/rk-pcie-ep.h +++ b/include/uapi/linux/rk-pcie-ep.h @@ -104,6 +104,8 @@ struct pcie_ep_obj_info { #define PCIE_DMA_RAISE_MSI_OBJ_IRQ_USER _IOW(PCIE_BASE, 4, int) #define PCIE_EP_GET_USER_INFO _IOR(PCIE_BASE, 5, struct pcie_ep_user_data) #define PCIE_EP_SET_MMAP_RESOURCE _IOW(PCIE_BASE, 6, enum pcie_ep_mmap_resource) +#define PCIE_EP_REQUEST_VIRTUAL_ID _IOR(PCIE_BASE, 16, int) +#define PCIE_EP_RELEASE_VIRTUAL_ID _IOW(PCIE_BASE, 17, int) #define PCIE_EP_DMA_XFER_BLOCK _IOW(PCIE_BASE, 32, struct pcie_ep_dma_block_req) #endif