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 + -
显示快捷键?