diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/habanalabs/device.c | 53 | ||||
-rw-r--r-- | drivers/misc/habanalabs/habanalabs.h | 14 | ||||
-rw-r--r-- | drivers/misc/habanalabs/habanalabs_drv.c | 89 | ||||
-rw-r--r-- | drivers/misc/habanalabs/habanalabs_ioctl.c | 95 |
4 files changed, 199 insertions, 52 deletions
diff --git a/drivers/misc/habanalabs/device.c b/drivers/misc/habanalabs/device.c index 204930607720..b90ba3b789eb 100644 --- a/drivers/misc/habanalabs/device.c +++ b/drivers/misc/habanalabs/device.c @@ -95,6 +95,24 @@ static int hl_device_release(struct inode *inode, struct file *filp) return 0; } +static int hl_device_release_ctrl(struct inode *inode, struct file *filp) +{ + struct hl_fpriv *hpriv = filp->private_data; + struct hl_device *hdev; + + filp->private_data = NULL; + + hdev = hpriv->hdev; + + mutex_lock(&hdev->fpriv_list_lock); + list_del(&hpriv->dev_node); + mutex_unlock(&hdev->fpriv_list_lock); + + kfree(hpriv); + + return 0; +} + /* * hl_mmap - mmap function for habanalabs device * @@ -125,6 +143,14 @@ static const struct file_operations hl_ops = { .compat_ioctl = hl_ioctl }; +static const struct file_operations hl_ctrl_ops = { + .owner = THIS_MODULE, + .open = hl_device_open_ctrl, + .release = hl_device_release_ctrl, + .unlocked_ioctl = hl_ioctl_control, + .compat_ioctl = hl_ioctl_control +}; + /* * device_setup_cdev - setup cdev and device for habanalabs device * @@ -567,7 +593,8 @@ static void device_kill_open_processes(struct hl_device *hdev) list_for_each_entry(hpriv, &hdev->fpriv_list, dev_node) { task = get_pid_task(hpriv->taskpid, PIDTYPE_PID); if (task) { - dev_info(hdev->dev, "Killing user process\n"); + dev_info(hdev->dev, "Killing user process pid=%d\n", + task_pid_nr(task)); send_sig(SIGKILL, task, 1); usleep_range(1000, 10000); @@ -872,7 +899,7 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) int i, rc, cq_ready_cnt; char *name; - name = kasprintf(GFP_KERNEL, "hl%d", hdev->id); + name = kasprintf(GFP_KERNEL, "hl%d", hdev->id / 2); if (!name) return -ENOMEM; @@ -885,10 +912,25 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) if (rc) goto out_disabled; + name = kasprintf(GFP_KERNEL, "hl_controlD%d", hdev->id / 2); + if (!name) { + rc = -ENOMEM; + goto release_device; + } + + /* Create control device */ + rc = device_setup_cdev(hdev, hclass, hdev->id_control, &hl_ctrl_ops, + name, &hdev->cdev_ctrl, &hdev->dev_ctrl); + + kfree(name); + + if (rc) + goto release_device; + /* Initialize ASIC function pointers and perform early init */ rc = device_early_init(hdev); if (rc) - goto release_device; + goto release_control_device; /* * Start calling ASIC initialization. First S/W then H/W and finally @@ -1063,6 +1105,9 @@ sw_fini: hdev->asic_funcs->sw_fini(hdev); early_fini: device_early_fini(hdev); +release_control_device: + device_destroy(hclass, hdev->dev_ctrl->devt); + cdev_del(&hdev->cdev_ctrl); release_device: device_destroy(hclass, hdev->dev->devt); cdev_del(&hdev->cdev); @@ -1178,6 +1223,8 @@ void hl_device_fini(struct hl_device *hdev) device_early_fini(hdev); /* Hide device from user */ + device_destroy(hdev->dev_ctrl->class, hdev->dev_ctrl->devt); + cdev_del(&hdev->cdev_ctrl); device_destroy(hdev->dev->class, hdev->dev->devt); cdev_del(&hdev->cdev); diff --git a/drivers/misc/habanalabs/habanalabs.h b/drivers/misc/habanalabs/habanalabs.h index 0602d62f1127..774d56630334 100644 --- a/drivers/misc/habanalabs/habanalabs.h +++ b/drivers/misc/habanalabs/habanalabs.h @@ -917,6 +917,7 @@ struct hl_debug_params { * @dev_node: node in the device list of file private data * @refcount: number of related contexts. * @restore_phase_mutex: lock for context switch and restore phase. + * @is_control: true for control device, false otherwise */ struct hl_fpriv { struct hl_device *hdev; @@ -929,6 +930,7 @@ struct hl_fpriv { struct list_head dev_node; struct kref refcount; struct mutex restore_phase_mutex; + u8 is_control; }; @@ -1015,7 +1017,7 @@ struct hl_dbg_device_entry { */ /* Theoretical limit only. A single host can only contain up to 4 or 8 PCIe - * x16 cards. In extereme cases, there are hosts that can accommodate 16 cards + * x16 cards. In extreme cases, there are hosts that can accommodate 16 cards. */ #define HL_MAX_MINORS 256 @@ -1160,7 +1162,9 @@ struct hl_device_reset_work { * @pcie_bar: array of available PCIe bars. * @rmmio: configuration area address on SRAM. * @cdev: related char device. - * @dev: realted kernel basic device structure. + * @cdev_ctrl: char device for control operations only (INFO IOCTL) + * @dev: related kernel basic device structure. + * @dev_ctrl: related kernel device structure for the control device * @work_freq: delayed work to lower device frequency if possible. * @work_heartbeat: delayed work for ArmCP is-alive check. * @asic_name: ASIC specific nmae. @@ -1213,6 +1217,7 @@ struct hl_device_reset_work { * @soft_reset_cnt: number of soft reset since KMD loading. * @hard_reset_cnt: number of hard reset since KMD loading. * @id: device minor. + * @id_control: minor of the control device * @disabled: is device disabled. * @late_init_done: is late init stage was done during initialization. * @hwmon_initialized: is H/W monitor sensors was initialized. @@ -1234,7 +1239,9 @@ struct hl_device { void __iomem *pcie_bar[6]; void __iomem *rmmio; struct cdev cdev; + struct cdev cdev_ctrl; struct device *dev; + struct device *dev_ctrl; struct delayed_work work_freq; struct delayed_work work_heartbeat; char asic_name[16]; @@ -1288,6 +1295,7 @@ struct hl_device { u32 soft_reset_cnt; u32 hard_reset_cnt; u16 id; + u16 id_control; u8 disabled; u8 late_init_done; u8 hwmon_initialized; @@ -1393,6 +1401,7 @@ static inline bool hl_mem_area_crosses_range(u64 address, u32 size, } int hl_device_open(struct inode *inode, struct file *filp); +int hl_device_open_ctrl(struct inode *inode, struct file *filp); bool hl_device_disabled_or_in_reset(struct hl_device *hdev); enum hl_device_status hl_device_status(struct hl_device *hdev); int hl_device_set_debug_mode(struct hl_device *hdev, bool enable); @@ -1632,6 +1641,7 @@ static inline void hl_debugfs_remove_ctx_mem_hash(struct hl_device *hdev, /* IOCTLs */ long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); +long hl_ioctl_control(struct file *filep, unsigned int cmd, unsigned long arg); int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data); int hl_cs_ioctl(struct hl_fpriv *hpriv, void *data); int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data); diff --git a/drivers/misc/habanalabs/habanalabs_drv.c b/drivers/misc/habanalabs/habanalabs_drv.c index 802c6ca7c604..8c342fb499ca 100644 --- a/drivers/misc/habanalabs/habanalabs_drv.c +++ b/drivers/misc/habanalabs/habanalabs_drv.c @@ -130,7 +130,7 @@ int hl_device_open(struct inode *inode, struct file *filp) } if (hdev->compute_ctx) { - dev_info_ratelimited(hdev->dev, + dev_dbg_ratelimited(hdev->dev, "Can't open %s because another user is working on it\n", dev_name(hdev->dev)); rc = -EBUSY; @@ -170,6 +170,55 @@ out_err: return rc; } +int hl_device_open_ctrl(struct inode *inode, struct file *filp) +{ + struct hl_device *hdev; + struct hl_fpriv *hpriv; + int rc; + + mutex_lock(&hl_devs_idr_lock); + hdev = idr_find(&hl_devs_idr, iminor(inode)); + mutex_unlock(&hl_devs_idr_lock); + + if (!hdev) { + pr_err("Couldn't find device %d:%d\n", + imajor(inode), iminor(inode)); + return -ENXIO; + } + + hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + + mutex_lock(&hdev->fpriv_list_lock); + + if (hl_device_disabled_or_in_reset(hdev)) { + dev_err_ratelimited(hdev->dev_ctrl, + "Can't open %s because it is disabled or in reset\n", + dev_name(hdev->dev_ctrl)); + rc = -EPERM; + goto out_err; + } + + list_add(&hpriv->dev_node, &hdev->fpriv_list); + mutex_unlock(&hdev->fpriv_list_lock); + + hpriv->hdev = hdev; + filp->private_data = hpriv; + hpriv->filp = filp; + hpriv->is_control = true; + nonseekable_open(inode, filp); + + hpriv->taskpid = find_get_pid(current->pid); + + return 0; + +out_err: + mutex_unlock(&hdev->fpriv_list_lock); + kfree(hpriv); + return rc; +} + static void set_driver_behavior_per_device(struct hl_device *hdev) { hdev->mmu_enable = 1; @@ -197,7 +246,7 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev, enum hl_asic_type asic_type, int minor) { struct hl_device *hdev; - int rc; + int rc, main_id, ctrl_id = 0; *dev = NULL; @@ -238,33 +287,34 @@ int create_hdev(struct hl_device **dev, struct pci_dev *pdev, mutex_lock(&hl_devs_idr_lock); - if (minor == -1) { - rc = idr_alloc(&hl_devs_idr, hdev, 0, HL_MAX_MINORS, + /* Always save 2 numbers, 1 for main device and 1 for control. + * They must be consecutive + */ + main_id = idr_alloc(&hl_devs_idr, hdev, 0, HL_MAX_MINORS, GFP_KERNEL); - } else { - void *old_idr = idr_replace(&hl_devs_idr, hdev, minor); - if (IS_ERR_VALUE(old_idr)) { - rc = PTR_ERR(old_idr); - pr_err("Error %d when trying to replace minor %d\n", - rc, minor); - mutex_unlock(&hl_devs_idr_lock); - goto free_hdev; - } - rc = minor; - } + if (main_id >= 0) + ctrl_id = idr_alloc(&hl_devs_idr, hdev, main_id + 1, + main_id + 2, GFP_KERNEL); mutex_unlock(&hl_devs_idr_lock); - if (rc < 0) { - if (rc == -ENOSPC) { + if ((main_id < 0) || (ctrl_id < 0)) { + if ((main_id == -ENOSPC) || (ctrl_id == -ENOSPC)) pr_err("too many devices in the system\n"); - rc = -EBUSY; + + if (main_id >= 0) { + mutex_lock(&hl_devs_idr_lock); + idr_remove(&hl_devs_idr, main_id); + mutex_unlock(&hl_devs_idr_lock); } + + rc = -EBUSY; goto free_hdev; } - hdev->id = rc; + hdev->id = main_id; + hdev->id_control = ctrl_id; *dev = hdev; @@ -286,6 +336,7 @@ void destroy_hdev(struct hl_device *hdev) /* Remove device from the device list */ mutex_lock(&hl_devs_idr_lock); idr_remove(&hl_devs_idr, hdev->id); + idr_remove(&hl_devs_idr, hdev->id_control); mutex_unlock(&hl_devs_idr_lock); kfree(hdev); diff --git a/drivers/misc/habanalabs/habanalabs_ioctl.c b/drivers/misc/habanalabs/habanalabs_ioctl.c index c9a4799eb251..9deb02b18eb2 100644 --- a/drivers/misc/habanalabs/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/habanalabs_ioctl.c @@ -194,7 +194,8 @@ out: return rc; } -static int hl_info_ioctl(struct hl_fpriv *hpriv, void *data) +static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, + struct device *dev) { struct hl_info_args *args = data; struct hl_device *hdev = hpriv->hdev; @@ -205,7 +206,7 @@ static int hl_info_ioctl(struct hl_fpriv *hpriv, void *data) return device_status_info(hdev, args); if (hl_device_disabled_or_in_reset(hdev)) { - dev_warn_ratelimited(hdev->dev, + dev_warn_ratelimited(dev, "Device is %s. Can't execute INFO IOCTL\n", atomic_read(&hdev->in_reset) ? "in_reset" : "disabled"); return -EBUSY; @@ -229,7 +230,7 @@ static int hl_info_ioctl(struct hl_fpriv *hpriv, void *data) break; default: - dev_err(hdev->dev, "Invalid request %d\n", args->op); + dev_err(dev, "Invalid request %d\n", args->op); rc = -ENOTTY; break; } @@ -237,6 +238,16 @@ static int hl_info_ioctl(struct hl_fpriv *hpriv, void *data) return rc; } +static int hl_info_ioctl(struct hl_fpriv *hpriv, void *data) +{ + return _hl_info_ioctl(hpriv, data, hpriv->hdev->dev); +} + +static int hl_info_ioctl_control(struct hl_fpriv *hpriv, void *data) +{ + return _hl_info_ioctl(hpriv, data, hpriv->hdev->dev_ctrl); +} + static int hl_debug_ioctl(struct hl_fpriv *hpriv, void *data) { struct hl_debug_args *args = data; @@ -291,52 +302,45 @@ static const struct hl_ioctl_desc hl_ioctls[] = { HL_IOCTL_DEF(HL_IOCTL_DEBUG, hl_debug_ioctl) }; -#define HL_CORE_IOCTL_COUNT ARRAY_SIZE(hl_ioctls) +static const struct hl_ioctl_desc hl_ioctls_control[] = { + HL_IOCTL_DEF(HL_IOCTL_INFO, hl_info_ioctl_control) +}; -long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +static long _hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg, + const struct hl_ioctl_desc *ioctl, struct device *dev) { struct hl_fpriv *hpriv = filep->private_data; struct hl_device *hdev = hpriv->hdev; - hl_ioctl_t *func; - const struct hl_ioctl_desc *ioctl = NULL; unsigned int nr = _IOC_NR(cmd); char stack_kdata[128] = {0}; char *kdata = NULL; unsigned int usize, asize; + hl_ioctl_t *func; + u32 hl_size; int retcode; if (hdev->hard_reset_pending) { - dev_crit_ratelimited(hdev->dev, + dev_crit_ratelimited(hdev->dev_ctrl, "Device HARD reset pending! Please close FD\n"); return -ENODEV; } - if ((nr >= HL_COMMAND_START) && (nr < HL_COMMAND_END)) { - u32 hl_size; - - ioctl = &hl_ioctls[nr]; - - hl_size = _IOC_SIZE(ioctl->cmd); - usize = asize = _IOC_SIZE(cmd); - if (hl_size > asize) - asize = hl_size; - - cmd = ioctl->cmd; - } else { - dev_err(hdev->dev, "invalid ioctl: pid=%d, nr=0x%02x\n", - task_pid_nr(current), nr); - return -ENOTTY; - } - /* Do not trust userspace, use our own definition */ func = ioctl->func; if (unlikely(!func)) { - dev_dbg(hdev->dev, "no function\n"); + dev_dbg(dev, "no function\n"); retcode = -ENOTTY; goto out_err; } + hl_size = _IOC_SIZE(ioctl->cmd); + usize = asize = _IOC_SIZE(cmd); + if (hl_size > asize) + asize = hl_size; + + cmd = ioctl->cmd; + if (cmd & (IOC_IN | IOC_OUT)) { if (asize <= sizeof(stack_kdata)) { kdata = stack_kdata; @@ -366,8 +370,7 @@ long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) out_err: if (retcode) - dev_dbg(hdev->dev, - "error in ioctl: pid=%d, cmd=0x%02x, nr=0x%02x\n", + dev_dbg(dev, "error in ioctl: pid=%d, cmd=0x%02x, nr=0x%02x\n", task_pid_nr(current), cmd, nr); if (kdata != stack_kdata) @@ -375,3 +378,39 @@ out_err: return retcode; } + +long hl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +{ + struct hl_fpriv *hpriv = filep->private_data; + struct hl_device *hdev = hpriv->hdev; + const struct hl_ioctl_desc *ioctl = NULL; + unsigned int nr = _IOC_NR(cmd); + + if ((nr >= HL_COMMAND_START) && (nr < HL_COMMAND_END)) { + ioctl = &hl_ioctls[nr]; + } else { + dev_err(hdev->dev, "invalid ioctl: pid=%d, nr=0x%02x\n", + task_pid_nr(current), nr); + return -ENOTTY; + } + + return _hl_ioctl(filep, cmd, arg, ioctl, hdev->dev); +} + +long hl_ioctl_control(struct file *filep, unsigned int cmd, unsigned long arg) +{ + struct hl_fpriv *hpriv = filep->private_data; + struct hl_device *hdev = hpriv->hdev; + const struct hl_ioctl_desc *ioctl = NULL; + unsigned int nr = _IOC_NR(cmd); + + if (nr == _IOC_NR(HL_IOCTL_INFO)) { + ioctl = &hl_ioctls_control[nr]; + } else { + dev_err(hdev->dev_ctrl, "invalid ioctl: pid=%d, nr=0x%02x\n", + task_pid_nr(current), nr); + return -ENOTTY; + } + + return _hl_ioctl(filep, cmd, arg, ioctl, hdev->dev_ctrl); +} |