⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (chp->cmg == -1) /* channel measurements not available */		return sprintf(buf, "unknown\n");	return sprintf(buf, "%x\n", chp->cmg);}static DEVICE_ATTR(cmg, 0444, chp_cmg_show, NULL);static ssize_t chp_shared_show(struct device *dev,			       struct device_attribute *attr, char *buf){	struct channel_path *chp = to_channelpath(dev);	if (!chp)		return 0;	if (chp->shared == -1) /* channel measurements not available */		return sprintf(buf, "unknown\n");	return sprintf(buf, "%x\n", chp->shared);}static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);static struct attribute *chp_attrs[] = {	&dev_attr_status.attr,	&dev_attr_configure.attr,	&dev_attr_type.attr,	&dev_attr_cmg.attr,	&dev_attr_shared.attr,	NULL,};static struct attribute_group chp_attr_group = {	.attrs = chp_attrs,};static void chp_release(struct device *dev){	struct channel_path *cp;	cp = to_channelpath(dev);	kfree(cp);}/** * chp_new - register a new channel-path * @chpid - channel-path ID * * Create and register data structure representing new channel-path. Return * zero on success, non-zero otherwise. */int chp_new(struct chp_id chpid){	struct channel_path *chp;	int ret;	if (chp_is_registered(chpid))		return 0;	chp = kzalloc(sizeof(struct channel_path), GFP_KERNEL);	if (!chp)		return -ENOMEM;	/* fill in status, etc. */	chp->chpid = chpid;	chp->state = 1;	chp->dev.parent = &channel_subsystems[chpid.cssid]->device;	chp->dev.release = chp_release;	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,		 chpid.id);	/* Obtain channel path description and fill it in. */	ret = chsc_determine_channel_path_description(chpid, &chp->desc);	if (ret)		goto out_free;	if ((chp->desc.flags & 0x80) == 0) {		ret = -ENODEV;		goto out_free;	}	/* Get channel-measurement characteristics. */	if (css_characteristics_avail && css_chsc_characteristics.scmc	    && css_chsc_characteristics.secm) {		ret = chsc_get_channel_measurement_chars(chp);		if (ret)			goto out_free;	} else {		chp->cmg = -1;	}	/* make it known to the system */	ret = device_register(&chp->dev);	if (ret) {		CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n",			      chpid.cssid, chpid.id, ret);		goto out_free;	}	ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);	if (ret) {		device_unregister(&chp->dev);		goto out_free;	}	mutex_lock(&channel_subsystems[chpid.cssid]->mutex);	if (channel_subsystems[chpid.cssid]->cm_enabled) {		ret = chp_add_cmg_attr(chp);		if (ret) {			sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);			device_unregister(&chp->dev);			mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);			goto out_free;		}	}	channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;	mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);	return ret;out_free:	kfree(chp);	return ret;}/** * chp_get_chp_desc - return newly allocated channel-path description * @chpid: channel-path ID * * On success return a newly allocated copy of the channel-path description * data associated with the given channel-path ID. Return %NULL on error. */void *chp_get_chp_desc(struct chp_id chpid){	struct channel_path *chp;	struct channel_path_desc *desc;	chp = chpid_to_chp(chpid);	if (!chp)		return NULL;	desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL);	if (!desc)		return NULL;	memcpy(desc, &chp->desc, sizeof(struct channel_path_desc));	return desc;}/** * chp_process_crw - process channel-path status change * @id: channel-path ID number * @status: non-zero if channel-path has become available, zero otherwise * * Handle channel-report-words indicating that the status of a channel-path * has changed. */void chp_process_crw(int id, int status){	struct chp_id chpid;	chp_id_init(&chpid);	chpid.id = id;	if (status) {		if (!chp_is_registered(chpid))			chp_new(chpid);		chsc_chp_online(chpid);	} else		chsc_chp_offline(chpid);}static inline int info_bit_num(struct chp_id id){	return id.id + id.cssid * (__MAX_CHPID + 1);}/* Force chp_info refresh on next call to info_validate(). */static void info_expire(void){	mutex_lock(&info_lock);	chp_info_expires = jiffies - 1;	mutex_unlock(&info_lock);}/* Ensure that chp_info is up-to-date. */static int info_update(void){	int rc;	mutex_lock(&info_lock);	rc = 0;	if (time_after(jiffies, chp_info_expires)) {		/* Data is too old, update. */		rc = sclp_chp_read_info(&chp_info);		chp_info_expires = jiffies + CHP_INFO_UPDATE_INTERVAL ;	}	mutex_unlock(&info_lock);	return rc;}/** * chp_info_get_status - retrieve configure status of a channel-path * @chpid: channel-path ID * * On success, return 0 for standby, 1 for configured, 2 for reserved, * 3 for not recognized. Return negative error code on error. */int chp_info_get_status(struct chp_id chpid){	int rc;	int bit;	rc = info_update();	if (rc)		return rc;	bit = info_bit_num(chpid);	mutex_lock(&info_lock);	if (!chp_test_bit(chp_info.recognized, bit))		rc = CHP_STATUS_NOT_RECOGNIZED;	else if (chp_test_bit(chp_info.configured, bit))		rc = CHP_STATUS_CONFIGURED;	else if (chp_test_bit(chp_info.standby, bit))		rc = CHP_STATUS_STANDBY;	else		rc = CHP_STATUS_RESERVED;	mutex_unlock(&info_lock);	return rc;}/* Return configure task for chpid. */static enum cfg_task_t cfg_get_task(struct chp_id chpid){	return chp_cfg_task[chpid.cssid][chpid.id];}/* Set configure task for chpid. */static void cfg_set_task(struct chp_id chpid, enum cfg_task_t cfg){	chp_cfg_task[chpid.cssid][chpid.id] = cfg;}/* Perform one configure/deconfigure request. Reschedule work function until * last request. */static void cfg_func(struct work_struct *work){	struct chp_id chpid;	enum cfg_task_t t;	mutex_lock(&cfg_lock);	t = cfg_none;	chp_id_for_each(&chpid) {		t = cfg_get_task(chpid);		if (t != cfg_none) {			cfg_set_task(chpid, cfg_none);			break;		}	}	mutex_unlock(&cfg_lock);	switch (t) {	case cfg_configure:		sclp_chp_configure(chpid);		info_expire();		chsc_chp_online(chpid);		break;	case cfg_deconfigure:		sclp_chp_deconfigure(chpid);		info_expire();		chsc_chp_offline(chpid);		break;	case cfg_none:		/* Get updated information after last change. */		info_update();		mutex_lock(&cfg_lock);		cfg_busy = 0;		mutex_unlock(&cfg_lock);		wake_up_interruptible(&cfg_wait_queue);		return;	}	queue_work(chp_wq, &cfg_work);}/** * chp_cfg_schedule - schedule chpid configuration request * @chpid - channel-path ID * @configure - Non-zero for configure, zero for deconfigure * * Schedule a channel-path configuration/deconfiguration request. */void chp_cfg_schedule(struct chp_id chpid, int configure){	CIO_MSG_EVENT(2, "chp_cfg_sched%x.%02x=%d\n", chpid.cssid, chpid.id,		      configure);	mutex_lock(&cfg_lock);	cfg_set_task(chpid, configure ? cfg_configure : cfg_deconfigure);	cfg_busy = 1;	mutex_unlock(&cfg_lock);	queue_work(chp_wq, &cfg_work);}/** * chp_cfg_cancel_deconfigure - cancel chpid deconfiguration request * @chpid - channel-path ID * * Cancel an active channel-path deconfiguration request if it has not yet * been performed. */void chp_cfg_cancel_deconfigure(struct chp_id chpid){	CIO_MSG_EVENT(2, "chp_cfg_cancel:%x.%02x\n", chpid.cssid, chpid.id);	mutex_lock(&cfg_lock);	if (cfg_get_task(chpid) == cfg_deconfigure)		cfg_set_task(chpid, cfg_none);	mutex_unlock(&cfg_lock);}static int cfg_wait_idle(void){	if (wait_event_interruptible(cfg_wait_queue, !cfg_busy))		return -ERESTARTSYS;	return 0;}static int __init chp_init(void){	struct chp_id chpid;	chp_wq = create_singlethread_workqueue("cio_chp");	if (!chp_wq)		return -ENOMEM;	INIT_WORK(&cfg_work, cfg_func);	init_waitqueue_head(&cfg_wait_queue);	if (info_update())		return 0;	/* Register available channel-paths. */	chp_id_for_each(&chpid) {		if (chp_info_get_status(chpid) != CHP_STATUS_NOT_RECOGNIZED)			chp_new(chpid);	}	return 0;}subsys_initcall(chp_init);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -