mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
misc: rockchip: pcie-rkep: Support adding virtual id by ioctl
Change-Id: I020ca781ac684caa5fe1c066c1e4b2a65d4891a5 Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user