From: Wang Wensheng wangwensheng4@huawei.com
There are multiple sdma devices on board that contains multiple Parts. We supply an additional virtual device in /dev/sdma and the real sdma devices are named /dev/sdmaX where X is the index. When the user operate on /dev/sdma we choose a proper device for user.
Currently the index of the sdma device is defined according to the numa node it belongs to, so we select the device depending on the numa node of the cpus the user runs on. The device was decided during the open operation and would not change.
Signed-off-by: Wang Wensheng wangwensheng4@huawei.com Signed-off-by: Zhang Zekun zhangzekun11@huawei.com Reviewed-by: Weilong Chen chenweilong@huawei.com --- drivers/char/sdma.c | 91 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 5 deletions(-)
diff --git a/drivers/char/sdma.c b/drivers/char/sdma.c index a9525d3cbeb6..7076d65bdd7c 100644 --- a/drivers/char/sdma.c +++ b/drivers/char/sdma.c @@ -140,6 +140,7 @@ struct sdma_channel {
#define SDMA_DEVICE_NAME_LENGTH_MAX 20 struct sdma_device { + u16 idx; u16 nr_channel; spinlock_t channel_lock; struct sdma_channel *channels; @@ -154,6 +155,59 @@ struct sdma_device { char name[SDMA_DEVICE_NAME_LENGTH_MAX]; };
+#define MAX_SDMA_DEVICE_NR 4 +static struct file_operations sdma_core_fops; +static struct { + int sdma_device_num; + struct sdma_device *sdma_devices[MAX_SDMA_DEVICE_NR]; + struct miscdevice miscdev; +} sdma_core_device = { + .sdma_device_num = 0, + .sdma_devices = { + [0 ... MAX_SDMA_DEVICE_NR - 1] = NULL, + }, + + .miscdev.minor = MISC_DYNAMIC_MINOR, + .miscdev.fops = &sdma_core_fops, + .miscdev.name = "sdma", +}; + +static void sdma_device_add(struct sdma_device *psdma_dev) +{ + int ret; + if (!sdma_core_device.sdma_device_num) { + sdma_core_device.miscdev.minor = MISC_DYNAMIC_MINOR; + ret = misc_register(&sdma_core_device.miscdev); + if (ret) { + pr_err("register misc device for sdma core failed, %d\n", ret); + return; + } + } + + sdma_core_device.sdma_device_num++; + sdma_core_device.sdma_devices[psdma_dev->idx] = psdma_dev; +} + +static void sdma_device_delete(struct sdma_device *psdma_dev) +{ + if (!sdma_core_device.sdma_devices[psdma_dev->idx]) + return; + + sdma_core_device.sdma_device_num--; + sdma_core_device.sdma_devices[psdma_dev->idx] = NULL; + + if (!sdma_core_device.sdma_device_num) + misc_deregister(&sdma_core_device.miscdev); +} + +static struct sdma_device *sdma_device_select(void) +{ + int idx = numa_node_id(); + if (idx < 0 || idx >= MAX_SDMA_DEVICE_NR) + idx = 0; + return sdma_core_device.sdma_devices[idx]; +} + struct sdma_hardware_info { unsigned long channel_map; u64 base_addr; /* physical address */ @@ -432,7 +486,6 @@ static int sdma_init_channels(struct sdma_device *psdma_dev, struct sdma_hardwar }
static struct file_operations sdma_fops; -static struct sdma_device *g_sdma_device;
static int sdma_device_probe(struct platform_device *pdev) { @@ -481,10 +534,12 @@ static int sdma_device_probe(struct platform_device *pdev) goto disable_iopf; }
+ /* FIXME:the index of sdma_device should be set according to the numa ID */ + psdma_dev->idx = sdma_core_device.sdma_device_num; psdma_dev->miscdev.minor = MISC_DYNAMIC_MINOR; psdma_dev->miscdev.fops = &sdma_fops; psdma_dev->miscdev.name = psdma_dev->name; - snprintf(psdma_dev->name, SDMA_DEVICE_NAME_LENGTH_MAX, "sdma"); + snprintf(psdma_dev->name, SDMA_DEVICE_NAME_LENGTH_MAX, "sdma%d", psdma_dev->idx); ret = misc_register(&psdma_dev->miscdev); if (ret) { pr_err("register misc device failed, %d\n", ret); @@ -494,7 +549,7 @@ static int sdma_device_probe(struct platform_device *pdev) psdma_dev->streamid = pdev->dev.iommu->fwspec->ids[0]; spin_lock_init(&psdma_dev->channel_lock);
- g_sdma_device = psdma_dev; + sdma_device_add(psdma_dev); pr_info("%s device probe success\n", psdma_dev->name);
return 0; @@ -526,6 +581,8 @@ static int sdma_device_remove(struct platform_device *pdev)
iounmap(psdma_dev->io_base);
+ sdma_device_delete(psdma_dev); + kfree(psdma_dev);
return 0; @@ -729,11 +786,10 @@ struct file_open_data { struct iommu_sva *sva; };
-static int sdma_dev_open(struct inode *inode, struct file *file) +static int __do_sdma_open(struct sdma_device *psdma_dev, struct file *file) { void *ret; int pasid; - struct sdma_device *psdma_dev = container_of(file->private_data, struct sdma_device, miscdev); struct file_open_data *data;
data = kmalloc(sizeof(*data), GFP_KERNEL); @@ -755,6 +811,24 @@ static int sdma_dev_open(struct inode *inode, struct file *file) return 0; }
+static int sdma_dev_open(struct inode *inode, struct file *file) +{ + struct sdma_device *psdma_dev = container_of(file->private_data, struct sdma_device, miscdev); + + return __do_sdma_open(psdma_dev, file); +} + +static int sdma_core_open(struct inode *inode, struct file *file) +{ + struct sdma_device *psdma_dev = sdma_device_select(); + if (!psdma_dev) { + pr_err("cannot find a sdma device automatically\n"); + return -ENODEV; + } + + return __do_sdma_open(psdma_dev, file); +} + static int sdma_dev_release(struct inode *inode, struct file *file) { /* We don't unbind current process since other device may use it */ @@ -803,5 +877,12 @@ static struct file_operations sdma_fops = { .release = sdma_dev_release, };
+static struct file_operations sdma_core_fops = { + .owner = THIS_MODULE, + .open = sdma_core_open, + .unlocked_ioctl = sdma_dev_ioctl, + .release = sdma_dev_release, +}; + MODULE_AUTHOR("Wang Wensheng wangwensheng4@huawei.com"); MODULE_LICENSE("GPL v2");