diff --git a/drivers/misc/sdma-dae/hisi_sdma.h b/drivers/misc/sdma-dae/hisi_sdma.h index 0be85d35f9f19bbe721e89c10125c86509b339e0..ac94147a30aa8048a5ff2c698031403fc57379cb 100644 --- a/drivers/misc/sdma-dae/hisi_sdma.h +++ b/drivers/misc/sdma-dae/hisi_sdma.h @@ -14,8 +14,11 @@ #define HISI_SDMA_MMAP_CQE 1 #define HISI_SDMA_MMAP_IO 2 #define HISI_SDMA_MMAP_SHMEM 3 -#define HISI_SDMA_FSM_TIMEOUT 100 +#define HISI_SDMA_FSM_INTERVAL 20 +#define HISI_SDMA_FSM_TIMEOUT 10 +#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 @@ -135,7 +138,7 @@ struct hisi_sdma_share_chn { }; struct hisi_sdma_reg_info { - int chn; + u32 chn; int type; u32 reg_value; }; @@ -168,7 +171,7 @@ struct hisi_sdma_sqe_task { }; struct hisi_sdma_task_info { - int chn; + u32 chn; u32 req_cnt; u32 task_cnt; uintptr_t task_addr; @@ -181,8 +184,8 @@ struct hisi_sdma_ioctl_func_list { }; #define IOCTL_SDMA_GET_PROCESS_ID _IOR('s', 1, u32) -#define IOCTL_SDMA_GET_CHN _IOR('s', 2, int) -#define IOCTL_SDMA_PUT_CHN _IOW('s', 3, int) +#define IOCTL_SDMA_GET_CHN _IOR('s', 2, u32) +#define IOCTL_SDMA_PUT_CHN _IOW('s', 3, u32) #define IOCTL_SDMA_GET_STREAMID _IOR('s', 4, u32) #define IOCTL_SDMA_PIN_UMEM _IOWR('s', 5, struct hisi_sdma_umem_info) #define IOCTL_SDMA_UNPIN_UMEM _IOW('s', 6, u64) diff --git a/drivers/misc/sdma-dae/sdma_auth.c b/drivers/misc/sdma-dae/sdma_auth.c index 6f674e2a386f637f7b5c8dcc24c412c775cd520a..161042c2578d3ab1db93333cda1ffff5c47ed871 100644 --- a/drivers/misc/sdma-dae/sdma_auth.c +++ b/drivers/misc/sdma-dae/sdma_auth.c @@ -17,12 +17,11 @@ struct hisi_sdma_own_pid_hte { u32 pasid; struct hlist_node node; DECLARE_HASHTABLE(sdma_submitter_pid_ht, HISI_SDMA_AUTH_HASH_BUCKETS_BITS); - spinlock_t submitter_pid_lock; }; struct hisi_sdma_auth_ht { DECLARE_HASHTABLE(sdma_owner_pid_ht, HISI_SDMA_AUTH_HASH_BUCKETS_BITS); - spinlock_t owner_pid_lock; + rwlock_t owner_pid_lock; }; static struct hisi_sdma_auth_ht *g_authority; @@ -34,7 +33,7 @@ int sdma_authority_hash_init(void) return -ENOMEM; hash_init(g_authority->sdma_owner_pid_ht); - spin_lock_init(&g_authority->owner_pid_lock); + rwlock_init(&g_authority->owner_pid_lock); return 0; } @@ -45,13 +44,10 @@ static void entry_free_pid_ht(struct hisi_sdma_own_pid_hte *entry) struct hlist_node *tmp; u32 bkt; - spin_lock(&entry->submitter_pid_lock); hash_for_each_safe(entry->sdma_submitter_pid_ht, bkt, tmp, sub_entry, pnode) { hash_del(&sub_entry->pnode); kfree(sub_entry); - sub_entry = NULL; } - spin_unlock(&entry->submitter_pid_lock); hash_del(&entry->node); kfree(entry); } @@ -62,11 +58,11 @@ void sdma_authority_ht_free(void) struct hlist_node *tmp; u32 bkt; - spin_lock(&g_authority->owner_pid_lock); + write_lock(&g_authority->owner_pid_lock); hash_for_each_safe(g_authority->sdma_owner_pid_ht, bkt, tmp, entry, node) entry_free_pid_ht(entry); - spin_unlock(&g_authority->owner_pid_lock); + write_unlock(&g_authority->owner_pid_lock); kfree(g_authority); g_authority = NULL; @@ -91,22 +87,19 @@ void sdma_free_authority_ht_with_pid(u32 pid) struct hlist_node *tmp; u32 bkt; - spin_lock(&g_authority->owner_pid_lock); + write_lock(&g_authority->owner_pid_lock); hash_for_each_safe(g_authority->sdma_owner_pid_ht, bkt, tmp, entry, node) { if (entry->pid == pid) entry_free_pid_ht(entry); else { - spin_lock(&entry->submitter_pid_lock); sub_entry = sdma_search_submitter_pid(entry, pid); if (sub_entry) { hash_del(&sub_entry->pnode); kfree(sub_entry); - sub_entry = NULL; } - spin_unlock(&entry->submitter_pid_lock); } } - spin_unlock(&g_authority->owner_pid_lock); + write_unlock(&g_authority->owner_pid_lock); } static struct hisi_sdma_own_pid_hte *sdma_search_owner_pid_ht(u32 pid) @@ -120,24 +113,52 @@ static struct hisi_sdma_own_pid_hte *sdma_search_owner_pid_ht(u32 pid) return NULL; } +static void sdma_clear_residual_auth_ht(struct hisi_sdma_own_pid_hte *entry, u32 *list, u32 pos, + bool *stored_info) +{ + struct hisi_sdma_sub_pid_hte *sub_entry; + u32 i = pos; + + while (i > 0) { + i--; + if (stored_info[i]) { + sub_entry = sdma_search_submitter_pid(entry, list[i]); + if (sub_entry) { + hash_del(&sub_entry->pnode); + kfree(sub_entry); + } + } + } +} + static int sdma_add_authority_ht(struct hisi_sdma_own_pid_hte *entry, u32 count, u32 *list) { struct hisi_sdma_sub_pid_hte *sub_entry; + bool *stored; u32 i; + stored = kcalloc(count, sizeof(bool), GFP_KERNEL); + if (!stored) + return -ENOMEM; + for (i = 0; i < count; i++) { sub_entry = sdma_search_submitter_pid(entry, list[i]); if (sub_entry) continue; sub_entry = kzalloc(sizeof(struct hisi_sdma_sub_pid_hte), GFP_KERNEL); - if (!sub_entry) + if (!sub_entry) { + sdma_clear_residual_auth_ht(entry, list, i, stored); + kfree(stored); return -ENOMEM; + } sub_entry->pid = list[i]; hash_add(entry->sdma_submitter_pid_ht, &sub_entry->pnode, sub_entry->pid); + stored[i] = true; } + kfree(stored); return 0; } @@ -152,7 +173,6 @@ static int sdma_create_authority_ht(u32 pid, u32 pasid, u32 num, u32 *list) entry->pid = pid; entry->pasid = pasid; - spin_lock_init(&entry->submitter_pid_lock); hash_init(entry->sdma_submitter_pid_ht); ret = sdma_add_authority_ht(entry, num, list); hash_add(g_authority->sdma_owner_pid_ht, &entry->node, entry->pid); @@ -164,22 +184,20 @@ int sdma_auth_add(u32 pasid, u32 num, u32 *pid_list) { struct hisi_sdma_own_pid_hte *owner; u32 pid = (u32)current->tgid; - int ret = 0; + int ret; + write_lock(&g_authority->owner_pid_lock); owner = sdma_search_owner_pid_ht(pid); if (owner) { - spin_lock(&owner->submitter_pid_lock); ret = sdma_add_authority_ht(owner, num, pid_list); - spin_unlock(&owner->submitter_pid_lock); if (ret < 0) pr_err("add_pid_ht failed\n"); } else { - spin_lock(&g_authority->owner_pid_lock); ret = sdma_create_authority_ht(pid, pasid, num, pid_list); - spin_unlock(&g_authority->owner_pid_lock); if (ret < 0) pr_err("create_pid_ht failed\n"); } + write_unlock(&g_authority->owner_pid_lock); return ret; } @@ -193,16 +211,20 @@ int sdma_check_authority(u32 pasid, u32 owner_pid, u32 submitter_pid, u32 *owner *owner_pasid = pasid; return 0; } + read_lock(&g_authority->owner_pid_lock); entry = sdma_search_owner_pid_ht(owner_pid); if (!entry) { pr_err("the owner_pid_ht[%u] not exist\n", owner_pid); + read_unlock(&g_authority->owner_pid_lock); return -ENODATA; } sub_entry = sdma_search_submitter_pid(entry, submitter_pid); if (!sub_entry) { pr_err("the submitter[%u] not authorithed\n", submitter_pid); + read_unlock(&g_authority->owner_pid_lock); return -ENODATA; } + read_unlock(&g_authority->owner_pid_lock); *owner_pasid = entry->pasid; return 0; diff --git a/drivers/misc/sdma-dae/sdma_cdev.c b/drivers/misc/sdma-dae/sdma_cdev.c index 27dba051ffc40a887d4ca5e10374edfb470fb723..ffc51922514b947853c4b5a53bbf183c13ffb1ba 100644 --- a/drivers/misc/sdma-dae/sdma_cdev.c +++ b/drivers/misc/sdma-dae/sdma_cdev.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "sdma_hal.h" #include "sdma_umem.h" @@ -14,7 +16,7 @@ static struct hisi_sdma_global_info g_info; struct hisi_sdma_channel_list { struct list_head chn_list; - int chn_idx; + u32 chn_idx; }; struct file_open_data { @@ -103,13 +105,13 @@ static int ioctl_sdma_unpin_umem(struct file *file, unsigned long arg) int ret; int ida; + if (copy_from_user(&cookie, (u64 __user *)(uintptr_t)arg, sizeof(u64))) + return -EFAULT; + ida = (int)(cookie >> COOKIE_IDA_SHIFT); if (ida != data->ida) return -EPERM; - if (copy_from_user(&cookie, (u64 __user *)(uintptr_t)arg, sizeof(u64))) - return -EFAULT; - ret = sdma_umem_release(cookie); if (ret) dev_err(&data->psdma_dev->pdev->dev, "umem release fail!\n"); @@ -124,8 +126,10 @@ static int ioctl_sdma_pin_umem(struct file *file, unsigned long arg) int ret; if (copy_from_user(&umemInfo, (struct hisi_sdma_umem_info __user *)(uintptr_t)arg, - sizeof(struct hisi_sdma_umem_info))) + sizeof(struct hisi_sdma_umem_info))) { + dev_dbg(&data->psdma_dev->pdev->dev, "umem_info copy from user failed!\n"); return -EFAULT; + } ret = sdma_umem_get((u64)umemInfo.vma, umemInfo.size, data->ida, &umemInfo.cookie); if (ret < 0) @@ -134,6 +138,7 @@ static int ioctl_sdma_pin_umem(struct file *file, unsigned long arg) if (copy_to_user((struct hisi_sdma_umem_info __user *)(uintptr_t)arg, &umemInfo, sizeof(struct hisi_sdma_umem_info))) { sdma_umem_release(umemInfo.cookie); + dev_dbg(&data->psdma_dev->pdev->dev, "umem_info copy to user failed!\n"); return -EFAULT; } @@ -187,14 +192,14 @@ static int ioctl_sdma_get_chn(struct file *file, unsigned long arg) } idx += share_chns; - list_node->chn_idx = (int)idx; + list_node->chn_idx = idx; list_add(&list_node->chn_list, &data->non_share_chn_list); pchannel = pdev->channels + idx; - pchannel->cnt_used++; + pchannel->ida = (u32)data->ida; spin_unlock(&pdev->channel_lock); dev_dbg(&pdev->pdev->dev, "sdma get chn %u\n", idx); - if (copy_to_user((int __user *)(uintptr_t)arg, &idx, sizeof(int))) { + if (copy_to_user((u32 __user *)(uintptr_t)arg, &idx, sizeof(u32))) { ret = -EFAULT; goto put_chn; } @@ -206,7 +211,7 @@ static int ioctl_sdma_get_chn(struct file *file, unsigned long arg) list_del(&list_node->chn_list); bitmap_set(pdev->channel_map, idx - share_chns, 1); pdev->nr_channel_used--; - pchannel->cnt_used--; + pchannel->ida = 0; unlock: spin_unlock(&pdev->channel_lock); kfree(list_node); @@ -221,31 +226,29 @@ static int ioctl_sdma_put_chn(struct file *file, unsigned long arg) struct device *dev = &pdev->pdev->dev; u32 share_chns = *(g_info.share_chns); struct hisi_sdma_channel_list *c, *n; - int idx; + u32 idx; - if (copy_from_user(&idx, (int __user *)(uintptr_t)arg, sizeof(int))) { + if (copy_from_user(&idx, (u32 __user *)(uintptr_t)arg, sizeof(u32))) { dev_err(dev, "put user chn failed\n"); return -EFAULT; } - if (idx < (int)share_chns || idx >= (int)pdev->nr_channel) { - dev_err(dev, "put idx = %d is err\n", idx); + if (idx < share_chns || idx >= pdev->nr_channel) { + dev_err(dev, "put idx = %u is err\n", idx); return -EFAULT; } spin_lock(&pdev->channel_lock); - bitmap_set(pdev->channel_map, idx - share_chns, 1); - pdev->nr_channel_used--; - list_for_each_entry_safe(c, n, &data->non_share_chn_list, chn_list) { if (c->chn_idx == idx) { - dev_dbg(dev, "sdma put chn %d\n", idx); + bitmap_set(pdev->channel_map, idx - share_chns, 1); + pdev->nr_channel_used--; + dev_dbg(dev, "sdma put chn %u\n", idx); list_del(&c->chn_list); kfree(c); break; } } - spin_unlock(&pdev->channel_lock); return 0; @@ -264,8 +267,8 @@ static int cmp(const void *a, const void *b) static int ioctl_get_near_sdmaid(struct file *file, unsigned long arg) { + struct hisi_sdma_numa_domain sdma_numa[HISI_SDMA_MAX_DEVS]; u32 num = g_info.core_dev->sdma_device_num; - struct hisi_sdma_numa_domain *sdma_numa; struct hisi_sdma_device *sdma_dev; struct device *dev; int sdma_id = -1; @@ -274,38 +277,40 @@ static int ioctl_get_near_sdmaid(struct file *file, unsigned long arg) nid = numa_node_id(); if (nid < 0) { - pr_err("numa_node not reported!\n"); - return 0; + pr_err("sdma numa_node not reported!\n"); + return -EINVAL; + } + if (num <= 0 || num > HISI_SDMA_MAX_DEVS) { + pr_err("device num wrong, cannot use sdma!\n"); + return -ENOENT; } - - sdma_numa = kcalloc(num, sizeof(struct hisi_sdma_numa_domain), GFP_KERNEL); - if (!sdma_numa) - return -ENOMEM; for (i = 0; i < num; i++) { + spin_lock(&g_info.core_dev->device_lock); sdma_dev = g_info.core_dev->sdma_devices[i]; dev = &sdma_dev->pdev->dev; sdma_numa[i].idx = sdma_dev->idx; sdma_numa[i].pxm = sdma_dev->node_idx; if (sdma_numa[i].pxm < 0) { + spin_unlock(&g_info.core_dev->device_lock); dev_err(dev, "sdma%d PXM domain not reported!\n", sdma_numa[i].idx); - goto ret_idx; + return -ENODATA; } + spin_unlock(&g_info.core_dev->device_lock); dev_dbg(dev, "sdma%d PXM = %d\n", sdma_numa[i].idx, sdma_numa[i].pxm); } sort(sdma_numa, num, sizeof(struct hisi_sdma_numa_domain), cmp, NULL); - for (i = 0; i < num; i++) { if (nid >= sdma_numa[i].pxm) { sdma_id = sdma_numa[i].idx; - goto ret_idx; + break; } } - pr_err("Nearest sdma not found! process nid = %d\n", nid); - -ret_idx: - kfree(sdma_numa); + if (sdma_id < 0) { + pr_err("Nearest sdma not found! process nid = %d, sdmaid = %d\n", nid, sdma_id); + return -ENODATA; + } if (copy_to_user((int __user *)(uintptr_t)arg, &sdma_id, sizeof(int))) return -EFAULT; @@ -333,8 +338,7 @@ static int ioctl_sdma_mpamcfg(struct file *file, unsigned long arg) struct hisi_sdma_device *pdev = data->psdma_dev; struct hisi_sdma_mpamcfg cfg; - if (copy_from_user(&cfg, - (struct hisi_sdma_mpamcfg __user *)(uintptr_t)arg, + if (copy_from_user(&cfg, (struct hisi_sdma_mpamcfg __user *)(uintptr_t)arg, sizeof(struct hisi_sdma_mpamcfg))) return -EFAULT; @@ -378,16 +382,19 @@ static int ioctl_sdma_chn_used_refcount(struct file *file, unsigned long arg) list_add(&list_node->chn_list, &data->share_chn_list); pchannel->cnt_used++; } + if (!share_chn.init_flag && pchannel->cnt_used > 0) { list_for_each_entry_safe(c, n, &data->share_chn_list, chn_list) { if (c->chn_idx == share_chn.chn_idx) { - dev_dbg(dev, "release share_chn%d\n", c->chn_idx); + pchannel->cnt_used--; + if (pchannel->cnt_used == 0) + pchannel->sync_info_base->err_cnt = 0; + dev_dbg(dev, "release share_chn%u\n", c->chn_idx); list_del(&c->chn_list); kfree(c); break; } } - pchannel->cnt_used--; } spin_unlock(&pdev->channel_lock); @@ -413,7 +420,7 @@ static int ioctl_sdma_add_authority_ht(struct file *file, unsigned long arg) dev_err(&pdev->pdev->dev, "Invalid pid_list num:%u\n", list_num); return -EINVAL; } - pid_list = kmalloc_node(list_num * sizeof(int), GFP_KERNEL, pdev->node_idx); + pid_list = kmalloc_node(list_num * sizeof(u32), GFP_KERNEL, pdev->node_idx); if (!pid_list) return -ENOMEM; @@ -435,7 +442,7 @@ static int sdma_verify_src_dst(struct file_open_data *data, struct pasid_info *p { struct device *dev = &data->psdma_dev->pdev->dev; u32 pid = (u32)current->tgid; - int ret = -1; + int ret = -EPERM; if (task_list.opcode == HISI_SDMA_HBM_CACHE_PRELOAD_MODE) { pasid->src_pasid = data->pasid; @@ -490,6 +497,20 @@ static void sdma_fill_sqe(struct hisi_sdma_sq_entry *sq_entry, struct hisi_sdma_ sq_entry->qos = task->qos; } +static bool sdma_check_channel_permission(struct hisi_sdma_channel *pchannel, u32 ida, u32 chn) +{ + u32 share_chns = *(g_info.share_chns); + + if (chn < share_chns) { + return true; + } else if (chn < HISI_SDMA_DEFAULT_CHANNEL_NUM && pchannel->ida != ida) { + pr_err("invalid process send task by sdma exclusive channel%u\n", chn); + return false; + } + + return true; +} + static int sdma_send_task_kernel(struct file_open_data *data, struct hisi_sdma_task_info *task_info, struct hisi_sdma_sqe_task *task_list) { @@ -502,9 +523,15 @@ static int sdma_send_task_kernel(struct file_open_data *data, struct hisi_sdma_t u32 i; pchannel = pdev->channels + task_info->chn; + spin_lock(&pchannel->owner_chn_lock); + if (!sdma_check_channel_permission(pchannel, (u32)data->ida, task_info->chn)) { + spin_unlock(&pchannel->owner_chn_lock); + return -EPERM; + } sq_tail = pchannel->sync_info_base->sq_tail; for (i = 0; i < task_info->task_cnt; i++) { if (task_info->req_cnt != 0) { + /* not send/record tasks whose length == 0 */ if (task_list[i].length == 0) { task_info->req_cnt--; continue; @@ -512,6 +539,7 @@ static int sdma_send_task_kernel(struct file_open_data *data, struct hisi_sdma_t } ret = sdma_verify_src_dst(data, &pasid, task_list[i]); if (ret < 0) { + spin_unlock(&pchannel->owner_chn_lock); dev_err(&pdev->pdev->dev, "no correct pid\n"); return ret; } @@ -521,6 +549,43 @@ static int sdma_send_task_kernel(struct file_open_data *data, struct hisi_sdma_t } sdma_channel_set_sq_tail(pchannel, sq_tail); pchannel->sync_info_base->sq_tail = sq_tail; + spin_unlock(&pchannel->owner_chn_lock); + + return 0; +} + +static u32 sdma_channel_free_sqe_cnt(struct hisi_sdma_channel *pchannel) +{ + u32 head = sdma_channel_get_sq_head(pchannel); + u32 tail = sdma_channel_get_sq_tail(pchannel); + u32 res_cnt; + + if (tail >= head) + res_cnt = HISI_SDMA_SQ_LENGTH - (tail - head) - 1; + else + res_cnt = head - tail - 1; + + return res_cnt; +} + +static int sdma_task_info_validate(struct file_open_data *data, + struct hisi_sdma_task_info *task_info) +{ + struct hisi_sdma_channel *pchannel; + u32 free_sqe_cnt; + + if (task_info->chn >= data->psdma_dev->nr_channel) { + dev_err(&data->psdma_dev->pdev->dev, "Invalid channel num:%u!\n", task_info->chn); + return -EINVAL; + } + pchannel = data->psdma_dev->channels + task_info->chn; + free_sqe_cnt = sdma_channel_free_sqe_cnt(pchannel); + if (task_info->task_cnt > HISI_SDMA_MAX_ALLOC_SIZE / sizeof(struct hisi_sdma_sqe_task) || + task_info->task_cnt > free_sqe_cnt || task_info->task_cnt == 0) { + dev_err(&data->psdma_dev->pdev->dev, "Invalid send task cnt:%u!\n", + task_info->task_cnt); + return -EINVAL; + } return 0; } @@ -528,25 +593,20 @@ static int sdma_send_task_kernel(struct file_open_data *data, struct hisi_sdma_t static int ioctl_sdma_send_task(struct file *file, unsigned long arg) { struct file_open_data *data = file->private_data; + struct device *dev = &data->psdma_dev->pdev->dev; struct hisi_sdma_task_info task_info; struct hisi_sdma_sqe_task *task_list; int ret; if (copy_from_user(&task_info, (struct hisi_sdma_task_info __user *)(uintptr_t)arg, sizeof(struct hisi_sdma_task_info))) { - dev_err(&data->psdma_dev->pdev->dev, "get hisi_sdma_task_info failed\n"); + dev_err(dev, "get hisi_sdma_task_info failed\n"); return -EFAULT; } - if (task_info.chn < 0 || (u32)task_info.chn >= data->psdma_dev->nr_channel) { - dev_err(&data->psdma_dev->pdev->dev, "Invalid channel num:%d!\n", task_info.chn); - return -EINVAL; - } - if (task_info.task_cnt > HISI_SDMA_MAX_ALLOC_SIZE / sizeof(struct hisi_sdma_sqe_task) || - task_info.task_cnt == 0) { - dev_err(&data->psdma_dev->pdev->dev, "Invalid send task cnt:%u!\n", - task_info.task_cnt); - return -EINVAL; - } + ret = sdma_task_info_validate(data, &task_info); + if (ret != 0) + return ret; + task_list = kcalloc_node(task_info.task_cnt, sizeof(struct hisi_sdma_sqe_task), GFP_KERNEL, data->psdma_dev->node_idx); if (!task_list) @@ -554,17 +614,19 @@ static int ioctl_sdma_send_task(struct file *file, unsigned long arg) if (copy_from_user(task_list, (void __user *)task_info.task_addr, task_info.task_cnt * sizeof(struct hisi_sdma_sqe_task))) { - dev_err(&data->psdma_dev->pdev->dev, "get hisi_sdma_sqe_task failed\n"); + dev_err(dev, "get hisi_sdma_sqe_task failed\n"); ret = -EFAULT; goto free_list; } ret = sdma_send_task_kernel(data, &task_info, task_list); - if (ret < 0) - dev_err(&data->psdma_dev->pdev->dev, "exec sdma_send_task_kernel failed\n"); + if (ret < 0) { + dev_err(dev, "exec sdma_send_task_kernel failed\n"); + goto free_list; + } if (copy_to_user((struct hisi_sdma_task_info __user *)(uintptr_t)arg, &task_info, sizeof(struct hisi_sdma_task_info))) { - dev_err(&data->psdma_dev->pdev->dev, "set hisi_sdma_task_info failed\n"); + dev_err(dev, "set hisi_sdma_task_info failed\n"); ret = -EFAULT; } @@ -587,8 +649,8 @@ static int sdma_operation_reg(struct hisi_sdma_device *pdev, unsigned long arg, return -EFAULT; } - if (reg_info.chn < 0 || (u32)reg_info.chn >= pdev->nr_channel) { - dev_err(dev, "Invalid channel num:%d!\n", reg_info.chn); + if (reg_info.chn >= pdev->nr_channel) { + dev_err(dev, "Invalid channel num:%u!\n", reg_info.chn); return -EINVAL; } pchannel = pdev->channels + reg_info.chn; @@ -650,19 +712,21 @@ static int ioctl_sdma_dfx_reg(struct file *file, unsigned long arg) dev = &pdev->pdev->dev; if (copy_from_user(®_info, (struct hisi_sdma_reg_info __user *)(uintptr_t)arg, sizeof(struct hisi_sdma_reg_info))) { - dev_err(dev, "get hisi_sdma_dfx_reg failed\n"); + dev_err(dev, "dfx_reg copy from user failed\n"); return -EFAULT; } - if (reg_info.chn < 0 || (u32)reg_info.chn >= pdev->nr_channel) { - dev_err(dev, "Invalid channel num:%d!\n", reg_info.chn); + if (reg_info.chn >= pdev->nr_channel) { + dev_err(dev, "Invalid channel num:%u!\n", reg_info.chn); return -EINVAL; } pchannel = pdev->channels + reg_info.chn; reg_info.reg_value = sdma_channel_get_dfx(pchannel); if (copy_to_user((struct hisi_sdma_reg_info __user *)(uintptr_t)arg, ®_info, - sizeof(struct hisi_sdma_reg_info))) + sizeof(struct hisi_sdma_reg_info))) { + dev_err(dev, "dfx_reg copy to user failed\n"); return -EFAULT; + } return 0; } @@ -675,16 +739,16 @@ static int ioctl_sdma_sqe_cnt_reg(struct file *file, unsigned long arg) struct hisi_sdma_channel *pchannel; struct device *dev; - if (reg_info.chn < 0 || (u32)reg_info.chn >= pdev->nr_channel) { - dev_err(dev, "Invalid channel num:%d!\n", reg_info.chn); - return -EINVAL; - } dev = &pdev->pdev->dev; if (copy_from_user(®_info, (struct hisi_sdma_reg_info __user *)(uintptr_t)arg, sizeof(struct hisi_sdma_reg_info))) { dev_err(dev, "get hisi_sdma_reg_info failed\n"); return -EFAULT; } + if (reg_info.chn >= pdev->nr_channel) { + dev_err(dev, "Invalid channel num:%u!\n", reg_info.chn); + return -EINVAL; + } pchannel = pdev->channels + reg_info.chn; if (reg_info.type == HISI_SDMA_CLR_NORMAL_SQE_CNT) @@ -722,7 +786,7 @@ static long sdma_dev_ioctl(struct file *file, unsigned int cmd, unsigned long ar int cmd_num; int i; - cmd_num = sizeof(g_ioctl_funcs) / sizeof(struct hisi_sdma_ioctl_func_list); + cmd_num = ARRAY_SIZE(g_ioctl_funcs); for (i = 0; i < cmd_num; i++) { if (g_ioctl_funcs[i].cmd == cmd) return g_ioctl_funcs[i].ioctl_func(file, arg); @@ -736,6 +800,7 @@ static int sdma_core_open(struct inode *inode, struct file *file) struct hisi_sdma_device *psdma_dev; dev_t sdma_dev; u32 sdma_idx; + int ret; if (g_info.core_dev->sdma_device_num == 0) { pr_err("cannot find a sdma device\n"); @@ -744,11 +809,24 @@ static int sdma_core_open(struct inode *inode, struct file *file) sdma_dev = inode->i_rdev; sdma_idx = MINOR(sdma_dev); if (sdma_idx >= HISI_SDMA_MAX_DEVS) { - pr_err("secondary device number overflow\n"); + pr_err("wrong id of sdma device\n"); return -ENODEV; } + spin_lock(&g_info.core_dev->device_lock); psdma_dev = g_info.core_dev->sdma_devices[sdma_idx]; - return __do_sdma_open(psdma_dev, file); + if (!psdma_dev) { + spin_unlock(&g_info.core_dev->device_lock); + pr_err("cannot find sdma%u\n", sdma_idx); + return -ENODEV; + } + ret = __do_sdma_open(psdma_dev, file); + spin_unlock(&g_info.core_dev->device_lock); + if (ret != 0) { + pr_err("open sdma failed\n"); + return ret; + } + + return 0; } ssize_t sdma_read_info(struct file *file, char __user *buf, size_t size, loff_t *ppos) @@ -779,7 +857,7 @@ static int sdma_dev_release(struct inode *inode, struct file *file) spin_lock(&pdev->channel_lock); list_for_each_entry_safe(c, n, &data->non_share_chn_list, chn_list) { - dev_dbg(dev, "release non_share_chn%d\n", c->chn_idx); + dev_dbg(dev, "release non_share_chn%u\n", c->chn_idx); bitmap_set(pdev->channel_map, c->chn_idx - share_chns, 1); list_del(&c->chn_list); kfree(c); @@ -787,7 +865,7 @@ static int sdma_dev_release(struct inode *inode, struct file *file) } list_for_each_entry_safe(c, n, &data->share_chn_list, chn_list) { - dev_dbg(dev, "release share_chn%d\n", c->chn_idx); + dev_dbg(dev, "release share_chn%u\n", c->chn_idx); pchannel = pdev->channels + c->chn_idx; pchannel->cnt_used--; if (pchannel->sync_info_base->lock != 0 && @@ -796,15 +874,15 @@ static int sdma_dev_release(struct inode *inode, struct file *file) pchannel->sync_info_base->lock = 0; pchannel->sync_info_base->lock_pid = 0; } + if (pchannel->cnt_used == 0) + pchannel->sync_info_base->err_cnt = 0; list_del(&c->chn_list); kfree(c); } spin_unlock(&pdev->channel_lock); - if (data->handle) { + if (data->handle) iommu_sva_unbind_device(data->handle); - data->handle = NULL; - } sdma_hash_free_entry(data->ida); sdma_free_authority_ht_with_pid(pid); @@ -814,27 +892,37 @@ static int sdma_dev_release(struct inode *inode, struct file *file) return 0; } -static int remap_addr_range(struct hisi_sdma_device *psdma_dev, u32 chn_num, u64 offset, u64 size) +static int remap_addr_range(u32 chn_num, u64 offset, u64 size) { u64 sync_size; sync_size = (u64)((sizeof(struct hisi_sdma_queue_info) + PAGE_SIZE - ALIGN_NUM) / PAGE_SIZE * PAGE_SIZE); - if (offset >= chn_num * (HISI_SDMA_MMAP_SHMEM + 1)) + if (offset >= chn_num * (HISI_SDMA_MMAP_SHMEM + 1)) { + pr_err("sdma mmap offset exceed range\n"); return -EINVAL; + } if (offset < chn_num * HISI_SDMA_MMAP_CQE) { + pr_err("sdma not support sqe mmap\n"); return -EINVAL; } else if (offset < chn_num * HISI_SDMA_MMAP_IO) { - if (size > HISI_SDMA_CQ_SIZE) + if (size > HISI_SDMA_CQ_SIZE) { + pr_err("sdma mmap size exceed cqe range\n"); return -EINVAL; + } return HISI_SDMA_MMAP_CQE; - } else if (offset < chn_num * HISI_SDMA_MMAP_SHMEM) + } else if (offset < chn_num * HISI_SDMA_MMAP_SHMEM) { + pr_err("sdma not support io reg mmap\n"); return -EINVAL; - if (size > sync_size) - return -EINVAL; - return HISI_SDMA_MMAP_SHMEM; + } else { + if (size > sync_size) { + pr_err("sdma mmap size exceed share mem range\n"); + return -EINVAL; + } + return HISI_SDMA_MMAP_SHMEM; + } } static int sdma_dev_mmap(struct file *file, struct vm_area_struct *vma) @@ -852,10 +940,10 @@ static int sdma_dev_mmap(struct file *file, struct vm_area_struct *vma) io_base = data->psdma_dev->base_addr; size = vma->vm_end - vma->vm_start; offset = vma->vm_pgoff; + vma->vm_flags |= VM_DONTEXPAND | VM_WIPEONFORK | VM_DONTCOPY; dev_dbg(dev, "sdma total channel num = %u, user mmap offset = 0x%llx", chn_num, offset); - - switch (remap_addr_range(data->psdma_dev, chn_num, offset, size)) { + switch (remap_addr_range(chn_num, offset, size)) { 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; @@ -871,9 +959,8 @@ static int sdma_dev_mmap(struct file *file, struct vm_area_struct *vma) default: return -EINVAL; } - if (ret) - dev_err(&data->psdma_dev->pdev->dev, "sdma mmap failed!\n"); + dev_err(dev, "sdma mmap failed!\n"); return ret; } @@ -893,9 +980,9 @@ void sdma_cdev_init(struct cdev *cdev) cdev->owner = THIS_MODULE; } -void sdma_info_sync_cdev(struct hisi_sdma_global_info *g_info_input) +void sdma_info_sync_cdev(struct hisi_sdma_core_device *p, u32 *share_chns, struct ida *fd_ida) { - g_info.core_dev = g_info_input->core_dev; - g_info.fd_ida = g_info_input->fd_ida; - g_info.share_chns = g_info_input->share_chns; + g_info.core_dev = p; + g_info.fd_ida = fd_ida; + g_info.share_chns = share_chns; } diff --git a/drivers/misc/sdma-dae/sdma_hal.h b/drivers/misc/sdma-dae/sdma_hal.h index b26f03c75f45283e2b6c5d17a43170a47bd6ba97..d3dec7c7ba30501c97740fba2fa25fa79c623360 100644 --- a/drivers/misc/sdma-dae/sdma_hal.h +++ b/drivers/misc/sdma-dae/sdma_hal.h @@ -29,6 +29,9 @@ struct hisi_sdma_channel { u16 idx; struct hisi_sdma_device *pdev; + u32 ida; + spinlock_t owner_chn_lock; + /* must be page-aligned and continuous physical memory */ struct hisi_sdma_sq_entry *sq_base; struct hisi_sdma_cq_entry *cq_base; @@ -79,6 +82,7 @@ struct hisi_sdma_device { struct hisi_sdma_core_device { u32 sdma_major; u32 sdma_device_num; + spinlock_t device_lock; struct hisi_sdma_device *sdma_devices[HISI_SDMA_MAX_DEVS]; }; @@ -89,7 +93,7 @@ struct hisi_sdma_global_info { }; void sdma_cdev_init(struct cdev *cdev); -void sdma_info_sync_cdev(struct hisi_sdma_global_info *g_info); +void sdma_info_sync_cdev(struct hisi_sdma_core_device *p, u32 *share_chns, struct ida *fd_ida); static inline void chn_set_val(struct hisi_sdma_channel *pchan, int reg, u32 val, u32 mask) { diff --git a/drivers/misc/sdma-dae/sdma_irq.c b/drivers/misc/sdma-dae/sdma_irq.c index 4c10de23c042ef53ae7615b6cf12c131e8f17f89..3ab70780618cf7aaf2a642c14729d3615d360d85 100644 --- a/drivers/misc/sdma-dae/sdma_irq.c +++ b/drivers/misc/sdma-dae/sdma_irq.c @@ -52,7 +52,7 @@ irqreturn_t sdma_chn_ioe_irq_handle(int irq, void *psdma_dev) return IRQ_HANDLED; } -void sdma_irq_init(struct hisi_sdma_device *sdma) +int sdma_irq_init(struct hisi_sdma_device *sdma) { struct platform_device *pdev; void __iomem *io_addr; @@ -61,7 +61,7 @@ void sdma_irq_init(struct hisi_sdma_device *sdma) u32 i; pdev = sdma->pdev; - for (i = 0; i < sdma->nr_channel + HISI_STARS_CHN_NUM; i++) { + for (i = HISI_STARS_CHN_NUM; i < sdma->nr_channel + HISI_STARS_CHN_NUM; i++) { io_addr = sdma->io_orig_base + i * HISI_SDMA_CHANNEL_IOMEM_SIZE; sdma_channel_set_irq_mask(io_addr, SDMA_IOC_MASKED_STATUS); } @@ -72,27 +72,29 @@ void sdma_irq_init(struct hisi_sdma_device *sdma) for (i = 0; i < irq_cnt; i++) { vir_irq = platform_get_irq(pdev, i); if (vir_irq < 0) { - dev_err(&pdev->dev, "get vir_irq[idx:%d] failed:%d!\n", i, vir_irq); + dev_err(&pdev->dev, "get vir_irq[idx:%u] failed:%d!\n", i, vir_irq); sdma->irq[i] = -1; continue; } sdma->irq[i] = vir_irq; } - for (i = INT_CH_IOE_SDMAM_0 + HISI_STARS_CHN_NUM; i <= INT_CH_IOE_SDMAM_255; i++) { - if (sdma->irq[i] == -1) + for (i = INT_CH_IOE_SDMAM_0 + HISI_STARS_CHN_NUM; i <= INT_CH_IOE_SDMAM_191; i++) { + if (sdma->irq[i] == -1 || sdma->irq[i] == 0) continue; ret = devm_request_irq(&sdma->pdev->dev, sdma->irq[i], sdma_chn_ioe_irq_handle, IRQF_ONESHOT, HISI_SDMA_IRQ_FUNC_NAME, sdma); if (ret != 0) { dev_err(&pdev->dev, "request_irq failed, ret=%d", ret); - continue; + return ret; } } for (i = 0; i < SDMA_IOE_NUM_MAX; i++) spin_lock_init(&err_set_lock[i]); + + return 0; } void sdma_irq_deinit(struct hisi_sdma_device *sdma) diff --git a/drivers/misc/sdma-dae/sdma_irq.h b/drivers/misc/sdma-dae/sdma_irq.h index ea868242dc0e87f2b359fbbc886a0cc3e4c68bc1..6243df6c7317d64631b24ba7afa2a082d13faffc 100644 --- a/drivers/misc/sdma-dae/sdma_irq.h +++ b/drivers/misc/sdma-dae/sdma_irq.h @@ -139,7 +139,7 @@ enum sdma_irq_type { INT_CH_IOE_SDMAM_252, INT_CH_IOE_SDMAM_253, INT_CH_IOE_SDMAM_254, INT_CH_IOE_SDMAM_255, }; -void sdma_irq_init(struct hisi_sdma_device *sdma); +int sdma_irq_init(struct hisi_sdma_device *sdma); void sdma_irq_deinit(struct hisi_sdma_device *sdma); #endif diff --git a/drivers/misc/sdma-dae/sdma_main.c b/drivers/misc/sdma-dae/sdma_main.c index 1b2c4ac491cad237107757ce3453a8447f8df02a..8ae9ab39c888e28f8abd6c0a4b0c28dd9e76af18 100644 --- a/drivers/misc/sdma-dae/sdma_main.c +++ b/drivers/misc/sdma-dae/sdma_main.c @@ -36,21 +36,21 @@ static bool sdma_channel_alloc_sq_cq(struct hisi_sdma_channel *pchan, u32 idx) } page_list = alloc_pages_node(idx, GFP_KERNEL | __GFP_ZERO, get_order(HISI_SDMA_SQ_SIZE)); if (!page_list) { - pr_err("channel%u: alloc sq page_list failed\n", pchan->idx); + pr_err("sdma channel%u: alloc sq page_list failed\n", pchan->idx); return false; } pchan->sq_base = (struct hisi_sdma_sq_entry *)page_to_virt(page_list); page_list = alloc_pages_node(idx, GFP_KERNEL | __GFP_ZERO, get_order(HISI_SDMA_CQ_SIZE)); if (!page_list) { - pr_err("channel%u: alloc cq page_list failed\n", pchan->idx); + pr_err("sdma channel%u: alloc cq page_list failed\n", pchan->idx); return false; } pchan->cq_base = (struct hisi_sdma_cq_entry *)page_to_virt(page_list); page_list = alloc_pages_node(idx, GFP_KERNEL | __GFP_ZERO, get_order(sync_size)); if (!page_list) { - pr_err("channel%u: alloc sync_info page_list failed\n", pchan->idx); + pr_err("sdma channel%u: alloc sync_info page_list failed\n", pchan->idx); return false; } pchan->sync_info_base = (struct hisi_sdma_queue_info *)page_to_virt(page_list); @@ -101,7 +101,7 @@ static void sdma_channel_reset(struct hisi_sdma_channel *pchan) sdma_channel_reset_sq_cq(pchan); sdma_channel_set_pause(pchan); while (!sdma_channel_is_paused(pchan)) { - mdelay(1); + msleep(HISI_SDMA_FSM_INTERVAL); if (++i > HISI_SDMA_FSM_TIMEOUT) { pr_warn("chn%u cannot get paused\n", pchan->idx); return; @@ -109,7 +109,7 @@ static void sdma_channel_reset(struct hisi_sdma_channel *pchan) } i = 0; while (!sdma_channel_is_quiescent(pchan)) { - mdelay(1); + msleep(HISI_SDMA_FSM_INTERVAL); if (++i > HISI_SDMA_FSM_TIMEOUT) { pr_warn("chn%u cannot get quiescent\n", pchan->idx); return; @@ -118,7 +118,7 @@ static void sdma_channel_reset(struct hisi_sdma_channel *pchan) i = 0; sdma_channel_write_reset(pchan); while (!sdma_channel_is_idle(pchan)) { - mdelay(1); + msleep(HISI_SDMA_FSM_INTERVAL); if (++i > HISI_SDMA_FSM_TIMEOUT) { pr_warn("chn%u cannot get idle\n", pchan->idx); return; @@ -171,6 +171,8 @@ int sdma_init_channels(struct hisi_sdma_device *psdma_dev) pchan = psdma_dev->channels + i; pchan->idx = i; pchan->pdev = psdma_dev; + pchan->ida = 0; + spin_lock_init(&pchan->owner_chn_lock); if (sdma_channel_alloc_sq_cq(pchan, psdma_dev->node_idx) == false) goto err_out; @@ -181,7 +183,6 @@ int sdma_init_channels(struct hisi_sdma_device *psdma_dev) sdma_channel_init(pchan); } - bitmap_set(psdma_dev->channel_map, 0, chn_num); if (share_chns > chn_num) { dev_warn(&psdma_dev->pdev->dev, "share_chns max val = %u!\n", chn_num); share_chns = chn_num; @@ -204,10 +205,11 @@ static int sdma_device_add(struct hisi_sdma_device *psdma_dev) int ret; if (idx >= HISI_SDMA_MAX_DEVS) { - pr_err("Exceeded the maximum number of devices\n"); - goto out_err; + dev_err(&psdma_dev->pdev->dev, "Exceeded the maximum number of devices\n"); + return -ENODEV; } + spin_lock(&hisi_sdma_core_device.device_lock); sdma_minor = idx; hisi_sdma_core_device.sdma_devices[idx] = psdma_dev; cdev = &hisi_sdma_core_device.sdma_devices[idx]->cdev; @@ -216,22 +218,22 @@ static int sdma_device_add(struct hisi_sdma_device *psdma_dev) sdma_cdev_init(cdev); ret = cdev_add(cdev, devno, 1); if (ret) { - pr_err("Error %d adding sdma", ret); - goto out_err; + spin_unlock(&hisi_sdma_core_device.device_lock); + dev_err(&psdma_dev->pdev->dev, "Error %d adding sdma\n", ret); + return -ENODEV; } if (IS_ERR(device_create(sdma_class, NULL, devno, NULL, "sdma%u", idx))) { - pr_err("device_create failed\n"); + spin_unlock(&hisi_sdma_core_device.device_lock); + dev_err(&psdma_dev->pdev->dev, "device_create failed\n"); cdev_del(cdev); - goto out_err; + return -ENODEV; } hisi_sdma_core_device.sdma_device_num++; + spin_unlock(&hisi_sdma_core_device.device_lock); return 0; - -out_err: - return -ENODEV; } static void sdma_device_delete(struct hisi_sdma_device *psdma_dev) @@ -239,8 +241,12 @@ static void sdma_device_delete(struct hisi_sdma_device *psdma_dev) if (hisi_sdma_core_device.sdma_device_num == 0) return; + spin_lock(&hisi_sdma_core_device.device_lock); + device_destroy(sdma_class, MKDEV(hisi_sdma_core_device.sdma_major, psdma_dev->idx)); + cdev_del(&psdma_dev->cdev); hisi_sdma_core_device.sdma_device_num--; hisi_sdma_core_device.sdma_devices[psdma_dev->idx] = NULL; + spin_unlock(&hisi_sdma_core_device.device_lock); } static int of_sdma_collect_info(struct platform_device *pdev, struct hisi_sdma_device *psdma_dev) @@ -249,26 +255,35 @@ static int of_sdma_collect_info(struct platform_device *pdev, struct hisi_sdma_d res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { - pr_err("get io_base info from dtb failed\n"); + dev_err(&pdev->dev, "get io_base info from dtb failed\n"); return -ENOMEM; } psdma_dev->base_addr = res->start; psdma_dev->base_addr_size = resource_size(res); + if (psdma_dev->base_addr_size < psdma_dev->nr_channel * HISI_SDMA_CHANNEL_IOMEM_SIZE || + psdma_dev->base_addr_size > HISI_SDMA_MAX_BASE_ADDR_SIZE) { + dev_err(&pdev->dev, "io reg size wrong!\n"); + return -EFAULT; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res == NULL) { - pr_err("get common reg info from dtb failed\n"); + dev_err(&pdev->dev, "get common reg info from dtb failed\n"); return -ENOMEM; } psdma_dev->common_base_addr = res->start; psdma_dev->common_base_addr_size = resource_size(res); + if (psdma_dev->common_base_addr_size != HISI_SDMA_MAX_COMMEN_BASE_ADDR_SIZE) { + dev_err(&pdev->dev, "global io reg size wrong!\n"); + return -EFAULT; + } psdma_dev->irq_cnt = platform_irq_count(pdev); - if (psdma_dev->irq_cnt < 0) { + if (psdma_dev->irq_cnt < 0 || psdma_dev->irq_cnt > SDMA_IRQ_NUM_MAX) { dev_err(&pdev->dev, "Get irq_cnt failed!\n"); - return psdma_dev->irq_cnt; + return -EINVAL; } - dev_info(&pdev->dev, "get irq_cnt:%d\n", psdma_dev->irq_cnt); + dev_dbg(&pdev->dev, "get irq_cnt:%d\n", psdma_dev->irq_cnt); return 0; } @@ -279,11 +294,12 @@ static int parse_sdma(struct hisi_sdma_device *psdma_dev, struct platform_device if (device_property_read_u32(&pdev->dev, "sdma-chn-num", &nr_channel)) { pr_err("ACPI sdma-chn-num get failed!\n"); - psdma_dev->nr_channel = HISI_SDMA_DEFAULT_CHANNEL_NUM; + return -EINVAL; } else { - if (nr_channel <= HISI_STARS_CHN_NUM) { - pr_err("ACPI sdma-chn-num = %u is insufficient\n", nr_channel); - return -1; + if (nr_channel <= HISI_STARS_CHN_NUM || nr_channel > + HISI_SDMA_DEFAULT_CHANNEL_NUM + HISI_STARS_CHN_NUM) { + pr_err("ACPI sdma-chn-num = %u not as required\n", nr_channel); + return -EINVAL; } psdma_dev->nr_channel = (u16)(nr_channel - HISI_STARS_CHN_NUM); } @@ -296,14 +312,17 @@ static int sdma_init_device_info(struct hisi_sdma_device *psdma_dev) int ret; psdma_dev->io_orig_base = ioremap(psdma_dev->base_addr, psdma_dev->base_addr_size); - if (!psdma_dev->io_orig_base) - return -ENOMEM; + if (!psdma_dev->io_orig_base) { + dev_err(&psdma_dev->pdev->dev, "remap io reg failed!\n"); + return -EFAULT; + } psdma_dev->common_base = ioremap(psdma_dev->common_base_addr, psdma_dev->common_base_addr_size); if (!psdma_dev->common_base) { iounmap(psdma_dev->io_orig_base); - return -ENOMEM; + dev_err(&psdma_dev->pdev->dev, "remap io common base failed!\n"); + return -EFAULT; } psdma_dev->io_base = psdma_dev->io_orig_base + HISI_SDMA_CH_OFFSET; ret = sdma_init_channels(psdma_dev); @@ -313,24 +332,38 @@ static int sdma_init_device_info(struct hisi_sdma_device *psdma_dev) return ret; } - sdma_irq_init(psdma_dev); + ret = sdma_irq_init(psdma_dev); + if (ret < 0) { + sdma_destroy_channels(psdma_dev); + iounmap(psdma_dev->common_base); + iounmap(psdma_dev->io_orig_base); + return ret; + } return 0; } +static void sdma_deinit_device_info(struct hisi_sdma_device *psdma_dev) +{ + sdma_irq_deinit(psdma_dev); + sdma_destroy_channels(psdma_dev); + iounmap(psdma_dev->common_base); + iounmap(psdma_dev->io_orig_base); +} + static int sdma_smmu_enable(struct device *dev) { int ret; ret = iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_IOPF); if (ret) { - pr_err("failed to enable IOPF feature! ret = %p\n", ERR_PTR(ret)); + dev_err(dev, "failed to enable IOPF feature! ret = %d\n", ret); return ret; } ret = iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA); if (ret) { - pr_err("failed to enable SVA feature! ret = %p\n", ERR_PTR(ret)); + dev_err(dev, "failed to enable SVA feature! ret = %d\n", ret); iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_IOPF); return ret; } @@ -347,7 +380,7 @@ static int sdma_device_probe(struct platform_device *pdev) device_num = hisi_sdma_core_device.sdma_device_num; if (!node_online(pdev->dev.numa_node)) { - pr_info("numa_node %d not online, register sdma%d failed\n", pdev->dev.numa_node, + pr_info("numa_node %d not online, register sdma%u failed\n", pdev->dev.numa_node, device_num); node_id = 0; } else @@ -368,7 +401,7 @@ static int sdma_device_probe(struct platform_device *pdev) ret = of_sdma_collect_info(pdev, psdma_dev); if (ret < 0) { - pr_err("collect device info failed, %d\n", ret); + dev_err(&psdma_dev->pdev->dev, "collect device info failed, %d\n", ret); goto free_dev; } @@ -395,10 +428,7 @@ static int sdma_device_probe(struct platform_device *pdev) iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF); deinit_device: - sdma_irq_deinit(psdma_dev); - sdma_destroy_channels(psdma_dev); - iounmap(psdma_dev->common_base); - iounmap(psdma_dev->io_orig_base); + sdma_deinit_device_info(psdma_dev); free_dev: kfree(psdma_dev); @@ -410,16 +440,9 @@ static int sdma_device_remove(struct platform_device *pdev) struct hisi_sdma_device *psdma_dev = dev_get_drvdata(&pdev->dev); sdma_device_delete(psdma_dev); - device_destroy(sdma_class, MKDEV(hisi_sdma_core_device.sdma_major, psdma_dev->idx)); - cdev_del(&psdma_dev->cdev); - - sdma_irq_deinit(psdma_dev); - sdma_destroy_channels(psdma_dev); iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_IOPF); - iounmap(psdma_dev->io_orig_base); - iounmap(psdma_dev->common_base); - + sdma_deinit_device_info(psdma_dev); kfree(psdma_dev); return 0; @@ -440,31 +463,17 @@ static struct platform_driver sdma_driver = { }, }; -static void global_var_init(struct hisi_sdma_global_info *g_info) -{ - ida_init(&fd_ida); - - g_info->core_dev = &hisi_sdma_core_device; - g_info->share_chns = &share_chns; - g_info->fd_ida = &fd_ida; -} - static int __init sdma_driver_init(void) { - struct hisi_sdma_global_info *g_info = NULL; dev_t sdma_dev; int ret; - g_info = kcalloc(1, sizeof(struct hisi_sdma_global_info), GFP_KERNEL); - if (!g_info) - return -ENOMEM; - - global_var_init(g_info); - sdma_info_sync_cdev(g_info); + ida_init(&fd_ida); + sdma_info_sync_cdev(&hisi_sdma_core_device, &share_chns, &fd_ida); sdma_class = class_create(THIS_MODULE, "sdma"); if (IS_ERR(sdma_class)) { - pr_err("class_create() failed for sdma_class: %lu\n", PTR_ERR(sdma_class)); + pr_err("class_create() failed for sdma_class: %ld\n", PTR_ERR(sdma_class)); goto destroy_ida; } ret = alloc_chrdev_region(&sdma_dev, 0, HISI_SDMA_MAX_DEVS, "sdma"); @@ -472,18 +481,23 @@ static int __init sdma_driver_init(void) pr_err("alloc_chrdev_region() failed for sdma\n"); goto destroy_class; } + spin_lock_init(&hisi_sdma_core_device.device_lock); hisi_sdma_core_device.sdma_major = MAJOR(sdma_dev); ret = platform_driver_register(&sdma_driver); - if (ret) + if (ret) { + pr_err("sdma platform_driver_register failed!\n"); goto unregister_chrdev; + } - if (sdma_hash_init()) + if (sdma_hash_init()) { + pr_err("sdma_hash alloc failed!\n"); goto unregister_driver; + } - if (sdma_authority_hash_init()) + if (sdma_authority_hash_init()) { + pr_err("sdma_authority_hash alloc failed!\n"); goto umem_hash_free; - - kfree(g_info); + } return 0; @@ -497,7 +511,6 @@ static int __init sdma_driver_init(void) class_destroy(sdma_class); destroy_ida: ida_destroy(&fd_ida); - kfree(g_info); return -ENODEV; } diff --git a/drivers/misc/sdma-dae/sdma_umem.c b/drivers/misc/sdma-dae/sdma_umem.c index 74a57ea310740783edffb4726dd4dbc655b8315f..43e079209ee0998ad928ebbc474362d4794bce29 100644 --- a/drivers/misc/sdma-dae/sdma_umem.c +++ b/drivers/misc/sdma-dae/sdma_umem.c @@ -44,10 +44,8 @@ static int region_cleanup(int id, void *p, void *data) static void entry_free_idr(struct hash_entry *entry) { - spin_lock(&entry->idr_lock); idr_for_each(&entry->pin_mem_region, region_cleanup, &entry->pin_mem_region); idr_destroy(&entry->pin_mem_region); - spin_unlock(&entry->idr_lock); hash_del(&entry->node); kfree(entry); @@ -99,6 +97,7 @@ void sdma_hash_free(void) static int record_umem(u64 addr, struct list_head *list_head, int ida, u64 *cookie) { struct hash_entry *entry; + bool entry_find = true; struct pin_mem *pmem; int ret, idr; @@ -116,28 +115,30 @@ static int record_umem(u64 addr, struct list_head *list_head, int ida, u64 *cook if (!entry) { ret = -ENOMEM; spin_unlock(&g_hash_table->hash_lock); + pr_err("Sdma failed to alloc hash_entry!\n"); goto free_pmem; } - + entry_find = false; entry->ida = ida; idr_init(&entry->pin_mem_region); - spin_lock_init(&entry->idr_lock); - hash_add(g_hash_table->sdma_fd_ht, &entry->node, ida); } - spin_unlock(&g_hash_table->hash_lock); - spin_lock(&entry->idr_lock); idr = idr_alloc(&entry->pin_mem_region, pmem, 0, 0, GFP_ATOMIC); - spin_unlock(&entry->idr_lock); if (idr < 0) { ret = idr; - goto free_entry; + spin_unlock(&g_hash_table->hash_lock); + pr_err("Sdma failed to alloc idr!\n"); + if (entry_find) + goto free_pmem; + else + goto free_entry; } - pr_debug("%s: idr alloc = %d\n", __func__, idr); pmem->idr = idr; + spin_unlock(&g_hash_table->hash_lock); *cookie = ((u64)ida << COOKIE_IDA_SHIFT) + idr; + pr_debug("record addr: ida = %d, idr = %d\n", ida, idr); return 0; @@ -162,17 +163,17 @@ static int pin_umem(u64 addr, int npages, struct list_head *p_head) page_list = (struct page **)(uintptr_t)__get_free_pages(GFP_KERNEL, get_order(to_pin_pages * sizeof(struct page *))); if (!page_list) { - pr_err("Failed to alloc page list!\n"); + pr_err("Sdma failed to alloc page list!\n"); return -ENOMEM; } pinned = pin_user_pages_fast(addr, to_pin_pages, FOLL_WRITE, page_list); if (pinned < 0) { - pr_err("Fall to pin user pages!\n"); + pr_err("Sdma failed to pin user pages!\n"); ret = pinned; goto free_pages; } else if (pinned != to_pin_pages) { - pr_err("Invalid number of pages. pinned %d pages, expect %d pages\n", + pr_err("Invalid number of pages. Sdma pinned %d pages, expect %d pages\n", pinned, to_pin_pages); ret = -EINVAL; goto unpin_page; @@ -207,7 +208,7 @@ int sdma_umem_get(u64 addr, u32 size, int ida, u64 *cookie) /* Check overflow */ if (((addr + size) < addr) || PAGE_ALIGN(addr + size) < (addr + size)) { - pr_err("Input size is overflow!"); + pr_err("Sdma input size is overflow!\n"); return -EINVAL; } @@ -219,7 +220,7 @@ int sdma_umem_get(u64 addr, u32 size, int ida, u64 *cookie) npages = (PAGE_ALIGN(addr + size) - ALIGN_DOWN(addr, PAGE_SIZE)) / PAGE_SIZE; ret = pin_umem(addr, npages, p_head); if (ret != 0) { - pr_err("Failed to pin_umem"); + pr_err("Sdma failed to pin_umem\n"); free_region(p_head); kfree(p_head); return ret; @@ -227,7 +228,7 @@ int sdma_umem_get(u64 addr, u32 size, int ida, u64 *cookie) ret = record_umem(addr, p_head, ida, cookie); if (ret) { - pr_err("Failed to record umem"); + pr_err("Sdma failed to record umem\n"); free_region(p_head); kfree(p_head); return ret; @@ -245,27 +246,26 @@ int sdma_umem_release(u64 cookie) fd_ida = (int)(cookie >> COOKIE_IDA_SHIFT); idr = (int)(cookie & COOKIE_IDA_MASK); - pr_debug("%s: fd_ida = %d, idr = %d\n", __func__, fd_ida, idr); + pr_debug("release addr: ida = %d, idr = %d\n", fd_ida, idr); spin_lock(&g_hash_table->hash_lock); entry = hash_lookup_entry(fd_ida); - spin_unlock(&g_hash_table->hash_lock); if (!entry) { - pr_err("sdma cookie_ida is invalid!\n"); + spin_unlock(&g_hash_table->hash_lock); + pr_err("Sdma cookie_ida is invalid!\n"); return -EFAULT; } - spin_lock(&entry->idr_lock); pmem = idr_find(&entry->pin_mem_region, idr); if (!pmem) { - pr_err("sdma cookie_idr is invalid!\n"); - spin_unlock(&entry->idr_lock); + spin_unlock(&g_hash_table->hash_lock); + pr_err("Sdma cookie_idr is invalid!\n"); return -EFAULT; } idr_remove(&entry->pin_mem_region, idr); - spin_unlock(&entry->idr_lock); - + spin_unlock(&g_hash_table->hash_lock); free_region(pmem->list_head); kfree((void *)pmem->list_head); + kfree(pmem); return 0; } diff --git a/drivers/misc/sdma-dae/sdma_umem.h b/drivers/misc/sdma-dae/sdma_umem.h index 997e97426647c62c61fc410a4021851309b3519c..fec7c70e80f38474f45dbab9c9053b01e5cb7b82 100644 --- a/drivers/misc/sdma-dae/sdma_umem.h +++ b/drivers/misc/sdma-dae/sdma_umem.h @@ -36,7 +36,6 @@ struct hash_entry { int ida; struct hlist_node node; struct idr pin_mem_region; - spinlock_t idr_lock; }; /* sdma_umem_get - Pin userspace memory.