ipath_file_ops.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,915 行 · 第 1/4 页
C
1,915 行
done: return ret;}static int ipath_open(struct inode *in, struct file *fp){ int ret, minor; mutex_lock(&ipath_mutex); minor = iminor(in); ipath_cdbg(VERBOSE, "open on dev %lx (minor %d)\n", (long)in->i_rdev, minor); if (minor) ret = find_free_port(minor - 1, fp); else ret = find_best_unit(fp); mutex_unlock(&ipath_mutex); return ret;}/** * unlock_exptid - unlock any expected TID entries port still had in use * @pd: port * * We don't actually update the chip here, because we do a bulk update * below, using ipath_f_clear_tids. */static void unlock_expected_tids(struct ipath_portdata *pd){ struct ipath_devdata *dd = pd->port_dd; int port_tidbase = pd->port_port * dd->ipath_rcvtidcnt; int i, cnt = 0, maxtid = port_tidbase + dd->ipath_rcvtidcnt; ipath_cdbg(VERBOSE, "Port %u unlocking any locked expTID pages\n", pd->port_port); for (i = port_tidbase; i < maxtid; i++) { if (!dd->ipath_pageshadow[i]) continue; ipath_release_user_pages_on_close(&dd->ipath_pageshadow[i], 1); dd->ipath_pageshadow[i] = NULL; cnt++; ipath_stats.sps_pageunlocks++; } if (cnt) ipath_cdbg(VERBOSE, "Port %u locked %u expTID entries\n", pd->port_port, cnt); if (ipath_stats.sps_pagelocks || ipath_stats.sps_pageunlocks) ipath_cdbg(VERBOSE, "%llu pages locked, %llu unlocked\n", (unsigned long long) ipath_stats.sps_pagelocks, (unsigned long long) ipath_stats.sps_pageunlocks);}static int ipath_close(struct inode *in, struct file *fp){ int ret = 0; struct ipath_portdata *pd; struct ipath_devdata *dd; unsigned port; ipath_cdbg(VERBOSE, "close on dev %lx, private data %p\n", (long)in->i_rdev, fp->private_data); mutex_lock(&ipath_mutex); pd = port_fp(fp); port = pd->port_port; fp->private_data = NULL; dd = pd->port_dd; if (pd->port_hdrqfull) { ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors " "during run\n", pd->port_comm, pd->port_pid, pd->port_hdrqfull); pd->port_hdrqfull = 0; } if (pd->port_rcvwait_to || pd->port_piowait_to || pd->port_rcvnowait || pd->port_pionowait) { ipath_cdbg(VERBOSE, "port%u, %u rcv, %u pio wait timeo; " "%u rcv %u, pio already\n", pd->port_port, pd->port_rcvwait_to, pd->port_piowait_to, pd->port_rcvnowait, pd->port_pionowait); pd->port_rcvwait_to = pd->port_piowait_to = pd->port_rcvnowait = pd->port_pionowait = 0; } if (pd->port_flag) { ipath_dbg("port %u port_flag still set to 0x%lx\n", pd->port_port, pd->port_flag); pd->port_flag = 0; } if (dd->ipath_kregbase) { if (pd->port_rcvhdrtail_uaddr) { pd->port_rcvhdrtail_uaddr = 0; pd->port_rcvhdrtail_kvaddr = NULL; ipath_release_user_pages_on_close( &pd->port_rcvhdrtail_pagep, 1); pd->port_rcvhdrtail_pagep = NULL; ipath_stats.sps_pageunlocks++; } ipath_write_kreg_port( dd, dd->ipath_kregs->kr_rcvhdrtailaddr, port, 0ULL); ipath_write_kreg_port( dd, dd->ipath_kregs->kr_rcvhdraddr, pd->port_port, 0); /* clean up the pkeys for this port user */ ipath_clean_part_key(pd, dd); if (port < dd->ipath_cfgports) { int i = dd->ipath_pbufsport * (port - 1); ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport); /* atomically clear receive enable port. */ clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port, &dd->ipath_rcvctrl); ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); if (dd->ipath_pageshadow) unlock_expected_tids(pd); ipath_stats.sps_ports--; ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n", pd->port_comm, pd->port_pid, dd->ipath_unit, port); } } pd->port_cnt = 0; pd->port_pid = 0; dd->ipath_f_clear_tids(dd, pd->port_port); ipath_free_pddata(dd, pd->port_port, 0); mutex_unlock(&ipath_mutex); return ret;}static int ipath_port_info(struct ipath_portdata *pd, struct ipath_port_info __user *uinfo){ struct ipath_port_info info; int nup; int ret; (void) ipath_count_units(NULL, &nup, NULL); info.num_active = nup; info.unit = pd->port_dd->ipath_unit; info.port = pd->port_port; if (copy_to_user(uinfo, &info, sizeof(info))) { ret = -EFAULT; goto bail; } ret = 0;bail: return ret;}static ssize_t ipath_write(struct file *fp, const char __user *data, size_t count, loff_t *off){ const struct ipath_cmd __user *ucmd; struct ipath_portdata *pd; const void __user *src; size_t consumed, copy; struct ipath_cmd cmd; ssize_t ret = 0; void *dest; if (count < sizeof(cmd.type)) { ret = -EINVAL; goto bail; } ucmd = (const struct ipath_cmd __user *) data; if (copy_from_user(&cmd.type, &ucmd->type, sizeof(cmd.type))) { ret = -EFAULT; goto bail; } consumed = sizeof(cmd.type); switch (cmd.type) { case IPATH_CMD_USER_INIT: copy = sizeof(cmd.cmd.user_info); dest = &cmd.cmd.user_info; src = &ucmd->cmd.user_info; break; case IPATH_CMD_RECV_CTRL: copy = sizeof(cmd.cmd.recv_ctrl); dest = &cmd.cmd.recv_ctrl; src = &ucmd->cmd.recv_ctrl; break; case IPATH_CMD_PORT_INFO: copy = sizeof(cmd.cmd.port_info); dest = &cmd.cmd.port_info; src = &ucmd->cmd.port_info; break; case IPATH_CMD_TID_UPDATE: case IPATH_CMD_TID_FREE: copy = sizeof(cmd.cmd.tid_info); dest = &cmd.cmd.tid_info; src = &ucmd->cmd.tid_info; break; case IPATH_CMD_SET_PART_KEY: copy = sizeof(cmd.cmd.part_key); dest = &cmd.cmd.part_key; src = &ucmd->cmd.part_key; break; default: ret = -EINVAL; goto bail; } if ((count - consumed) < copy) { ret = -EINVAL; goto bail; } if (copy_from_user(dest, src, copy)) { ret = -EFAULT; goto bail; } consumed += copy; pd = port_fp(fp); switch (cmd.type) { case IPATH_CMD_USER_INIT: ret = ipath_do_user_init(pd, &cmd.cmd.user_info); if (ret < 0) goto bail; ret = ipath_get_base_info( pd, (void __user *) (unsigned long) cmd.cmd.user_info.spu_base_info, cmd.cmd.user_info.spu_base_info_size); break; case IPATH_CMD_RECV_CTRL: ret = ipath_manage_rcvq(pd, cmd.cmd.recv_ctrl); break; case IPATH_CMD_PORT_INFO: ret = ipath_port_info(pd, (struct ipath_port_info __user *) (unsigned long) cmd.cmd.port_info); break; case IPATH_CMD_TID_UPDATE: ret = ipath_tid_update(pd, &cmd.cmd.tid_info); break; case IPATH_CMD_TID_FREE: ret = ipath_tid_free(pd, &cmd.cmd.tid_info); break; case IPATH_CMD_SET_PART_KEY: ret = ipath_set_part_key(pd, cmd.cmd.part_key); break; } if (ret >= 0) ret = consumed;bail: return ret;}static struct class *ipath_class;static int init_cdev(int minor, char *name, struct file_operations *fops, struct cdev **cdevp, struct class_device **class_devp){ const dev_t dev = MKDEV(IPATH_MAJOR, minor); struct cdev *cdev = NULL; struct class_device *class_dev = NULL; int ret; cdev = cdev_alloc(); if (!cdev) { printk(KERN_ERR IPATH_DRV_NAME ": Could not allocate cdev for minor %d, %s\n", minor, name); ret = -ENOMEM; goto done; } cdev->owner = THIS_MODULE; cdev->ops = fops; kobject_set_name(&cdev->kobj, name); ret = cdev_add(cdev, dev, 1); if (ret < 0) { printk(KERN_ERR IPATH_DRV_NAME ": Could not add cdev for minor %d, %s (err %d)\n", minor, name, -ret); goto err_cdev; } class_dev = class_device_create(ipath_class, NULL, dev, NULL, name); if (IS_ERR(class_dev)) { ret = PTR_ERR(class_dev); printk(KERN_ERR IPATH_DRV_NAME ": Could not create " "class_dev for minor %d, %s (err %d)\n", minor, name, -ret); goto err_cdev; } goto done;err_cdev: cdev_del(cdev); cdev = NULL;done: if (ret >= 0) { *cdevp = cdev; *class_devp = class_dev; } else { *cdevp = NULL; *class_devp = NULL; } return ret;}int ipath_cdev_init(int minor, char *name, struct file_operations *fops, struct cdev **cdevp, struct class_device **class_devp){ return init_cdev(minor, name, fops, cdevp, class_devp);}static void cleanup_cdev(struct cdev **cdevp, struct class_device **class_devp){ struct class_device *class_dev = *class_devp; if (class_dev) { class_device_unregister(class_dev); *class_devp = NULL; } if (*cdevp) { cdev_del(*cdevp); *cdevp = NULL; }}void ipath_cdev_cleanup(struct cdev **cdevp, struct class_device **class_devp){ cleanup_cdev(cdevp, class_devp);}static struct cdev *wildcard_cdev;static struct class_device *wildcard_class_dev;static const dev_t dev = MKDEV(IPATH_MAJOR, 0);static int user_init(void){ int ret; ret = register_chrdev_region(dev, IPATH_NMINORS, IPATH_DRV_NAME); if (ret < 0) { printk(KERN_ERR IPATH_DRV_NAME ": Could not register " "chrdev region (err %d)\n", -ret); goto done; } ipath_class = class_create(THIS_MODULE, IPATH_DRV_NAME); if (IS_ERR(ipath_class)) { ret = PTR_ERR(ipath_class); printk(KERN_ERR IPATH_DRV_NAME ": Could not create " "device class (err %d)\n", -ret); goto bail; } goto done;bail: unregister_chrdev_region(dev, IPATH_NMINORS);done: return ret;}static void user_cleanup(void){ if (ipath_class) { class_destroy(ipath_class); ipath_class = NULL; } unregister_chrdev_region(dev, IPATH_NMINORS);}static atomic_t user_count = ATOMIC_INIT(0);static atomic_t user_setup = ATOMIC_INIT(0);int ipath_user_add(struct ipath_devdata *dd){ char name[10]; int ret; if (atomic_inc_return(&user_count) == 1) { ret = user_init(); if (ret < 0) { ipath_dev_err(dd, "Unable to set up user support: " "error %d\n", -ret); goto bail; } ret = ipath_diag_init(); if (ret < 0) { ipath_dev_err(dd, "Unable to set up diag support: " "error %d\n", -ret); goto bail_sma; } ret = init_cdev(0, "ipath", &ipath_file_ops, &wildcard_cdev, &wildcard_class_dev); if (ret < 0) { ipath_dev_err(dd, "Could not create wildcard " "minor: error %d\n", -ret); goto bail_diag; } atomic_set(&user_setup, 1); } snprintf(name, sizeof(name), "ipath%d", dd->ipath_unit); ret = init_cdev(dd->ipath_unit + 1, name, &ipath_file_ops, &dd->cdev, &dd->class_dev); if (ret < 0) ipath_dev_err(dd, "Could not create user minor %d, %s\n", dd->ipath_unit + 1, name); goto bail;bail_diag: ipath_diag_cleanup();bail_sma: user_cleanup();bail: return ret;}void ipath_user_del(struct ipath_devdata *dd){ cleanup_cdev(&dd->cdev, &dd->class_dev); if (atomic_dec_return(&user_count) == 0) { if (atomic_read(&user_setup) == 0) goto bail; cleanup_cdev(&wildcard_cdev, &wildcard_class_dev); ipath_diag_cleanup(); user_cleanup(); atomic_set(&user_setup, 0); }bail: return;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?