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

📄 cmf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
}static int set_cmbe(struct ccw_device *cdev, u32 mme){	unsigned long mba;	struct cmb_data *cmb_data;	unsigned long flags;	spin_lock_irqsave(cdev->ccwlock, flags);	if (!cdev->private->cmb) {		spin_unlock_irqrestore(cdev->ccwlock, flags);		return -EINVAL;	}	cmb_data = cdev->private->cmb;	mba = mme ? (unsigned long) cmbe_align(cmb_data->hw_block) : 0;	spin_unlock_irqrestore(cdev->ccwlock, flags);	return set_schib_wait(cdev, mme, 1, mba);}static u64 read_cmbe(struct ccw_device *cdev, int index){	struct cmbe *cmb;	struct cmb_data *cmb_data;	u32 val;	int ret;	unsigned long flags;	ret = cmf_cmb_copy_wait(cdev);	if (ret < 0)		return 0;	spin_lock_irqsave(cdev->ccwlock, flags);	cmb_data = cdev->private->cmb;	if (!cmb_data) {		ret = 0;		goto out;	}	cmb = cmb_data->last_block;	switch (index) {	case cmb_ssch_rsch_count:		ret = cmb->ssch_rsch_count;		goto out;	case cmb_sample_count:		ret = cmb->sample_count;		goto out;	case cmb_device_connect_time:		val = cmb->device_connect_time;		break;	case cmb_function_pending_time:		val = cmb->function_pending_time;		break;	case cmb_device_disconnect_time:		val = cmb->device_disconnect_time;		break;	case cmb_control_unit_queuing_time:		val = cmb->control_unit_queuing_time;		break;	case cmb_device_active_only_time:		val = cmb->device_active_only_time;		break;	case cmb_device_busy_time:		val = cmb->device_busy_time;		break;	case cmb_initial_command_response_time:		val = cmb->initial_command_response_time;		break;	default:		ret = 0;		goto out;	}	ret = time_to_avg_nsec(val, cmb->sample_count);out:	spin_unlock_irqrestore(cdev->ccwlock, flags);	return ret;}static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data){	struct cmbe *cmb;	struct cmb_data *cmb_data;	u64 time;	unsigned long flags;	int ret;	ret = cmf_cmb_copy_wait(cdev);	if (ret < 0)		return ret;	spin_lock_irqsave(cdev->ccwlock, flags);	cmb_data = cdev->private->cmb;	if (!cmb_data) {		ret = -ENODEV;		goto out;	}	if (cmb_data->last_update == 0) {		ret = -EAGAIN;		goto out;	}	time = cmb_data->last_update - cdev->private->cmb_start_time;	memset (data, 0, sizeof(struct cmbdata));	/* we only know values before device_busy_time */	data->size = offsetof(struct cmbdata, device_busy_time);	/* conver to nanoseconds */	data->elapsed_time = (time * 1000) >> 12;	cmb = cmb_data->last_block;	/* copy data to new structure */	data->ssch_rsch_count = cmb->ssch_rsch_count;	data->sample_count = cmb->sample_count;	/* time fields are converted to nanoseconds while copying */	data->device_connect_time = time_to_nsec(cmb->device_connect_time);	data->function_pending_time = time_to_nsec(cmb->function_pending_time);	data->device_disconnect_time =		time_to_nsec(cmb->device_disconnect_time);	data->control_unit_queuing_time		= time_to_nsec(cmb->control_unit_queuing_time);	data->device_active_only_time		= time_to_nsec(cmb->device_active_only_time);	data->device_busy_time = time_to_nsec(cmb->device_busy_time);	data->initial_command_response_time		= time_to_nsec(cmb->initial_command_response_time);	ret = 0;out:	spin_unlock_irqrestore(cdev->ccwlock, flags);	return ret;}static void reset_cmbe(struct ccw_device *cdev){	cmf_generic_reset(cdev);}static void * align_cmbe(void *area){	return cmbe_align(area);}static struct attribute_group cmf_attr_group_ext;static struct cmb_operations cmbops_extended = {	.alloc	    = alloc_cmbe,	.free	    = free_cmbe,	.set	    = set_cmbe,	.read	    = read_cmbe,	.readall    = readall_cmbe,	.reset	    = reset_cmbe,	.align	    = align_cmbe,	.attr_group = &cmf_attr_group_ext,};static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx){	return sprintf(buf, "%lld\n",		(unsigned long long) cmf_read(to_ccwdev(dev), idx));}static ssize_t cmb_show_avg_sample_interval(struct device *dev,					    struct device_attribute *attr,					    char *buf){	struct ccw_device *cdev;	long interval;	unsigned long count;	struct cmb_data *cmb_data;	cdev = to_ccwdev(dev);	count = cmf_read(cdev, cmb_sample_count);	spin_lock_irq(cdev->ccwlock);	cmb_data = cdev->private->cmb;	if (count) {		interval = cmb_data->last_update -			cdev->private->cmb_start_time;		interval = (interval * 1000) >> 12;		interval /= count;	} else		interval = -1;	spin_unlock_irq(cdev->ccwlock);	return sprintf(buf, "%ld\n", interval);}static ssize_t cmb_show_avg_utilization(struct device *dev,					struct device_attribute *attr,					char *buf){	struct cmbdata data;	u64 utilization;	unsigned long t, u;	int ret;	ret = cmf_readall(to_ccwdev(dev), &data);	if (ret == -EAGAIN || ret == -ENODEV)		/* No data (yet/currently) available to use for calculation. */		return sprintf(buf, "n/a\n");	else if (ret)		return ret;	utilization = data.device_connect_time +		      data.function_pending_time +		      data.device_disconnect_time;	/* shift to avoid long long division */	while (-1ul < (data.elapsed_time | utilization)) {		utilization >>= 8;		data.elapsed_time >>= 8;	}	/* calculate value in 0.1 percent units */	t = (unsigned long) data.elapsed_time / 1000;	u = (unsigned long) utilization / t;	return sprintf(buf, "%02ld.%01ld%%\n", u/ 10, u - (u/ 10) * 10);}#define cmf_attr(name) \static ssize_t show_##name(struct device *dev, \			   struct device_attribute *attr, char *buf)	\{ return cmb_show_attr((dev), buf, cmb_##name); } \static DEVICE_ATTR(name, 0444, show_##name, NULL);#define cmf_attr_avg(name) \static ssize_t show_avg_##name(struct device *dev, \			       struct device_attribute *attr, char *buf) \{ return cmb_show_attr((dev), buf, cmb_##name); } \static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);cmf_attr(ssch_rsch_count);cmf_attr(sample_count);cmf_attr_avg(device_connect_time);cmf_attr_avg(function_pending_time);cmf_attr_avg(device_disconnect_time);cmf_attr_avg(control_unit_queuing_time);cmf_attr_avg(device_active_only_time);cmf_attr_avg(device_busy_time);cmf_attr_avg(initial_command_response_time);static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,		   NULL);static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);static struct attribute *cmf_attributes[] = {	&dev_attr_avg_sample_interval.attr,	&dev_attr_avg_utilization.attr,	&dev_attr_ssch_rsch_count.attr,	&dev_attr_sample_count.attr,	&dev_attr_avg_device_connect_time.attr,	&dev_attr_avg_function_pending_time.attr,	&dev_attr_avg_device_disconnect_time.attr,	&dev_attr_avg_control_unit_queuing_time.attr,	&dev_attr_avg_device_active_only_time.attr,	NULL,};static struct attribute_group cmf_attr_group = {	.name  = "cmf",	.attrs = cmf_attributes,};static struct attribute *cmf_attributes_ext[] = {	&dev_attr_avg_sample_interval.attr,	&dev_attr_avg_utilization.attr,	&dev_attr_ssch_rsch_count.attr,	&dev_attr_sample_count.attr,	&dev_attr_avg_device_connect_time.attr,	&dev_attr_avg_function_pending_time.attr,	&dev_attr_avg_device_disconnect_time.attr,	&dev_attr_avg_control_unit_queuing_time.attr,	&dev_attr_avg_device_active_only_time.attr,	&dev_attr_avg_device_busy_time.attr,	&dev_attr_avg_initial_command_response_time.attr,	NULL,};static struct attribute_group cmf_attr_group_ext = {	.name  = "cmf",	.attrs = cmf_attributes_ext,};static ssize_t cmb_enable_show(struct device *dev,			       struct device_attribute *attr,			       char *buf){	return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);}static ssize_t cmb_enable_store(struct device *dev,				struct device_attribute *attr, const char *buf,				size_t c){	struct ccw_device *cdev;	int ret;	cdev = to_ccwdev(dev);	switch (buf[0]) {	case '0':		ret = disable_cmf(cdev);		if (ret)			dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret);		break;	case '1':		ret = enable_cmf(cdev);		if (ret && ret != -EBUSY)			dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret);		break;	}	return c;}DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);/** * enable_cmf() - switch on the channel measurement for a specific device *  @cdev:	The ccw device to be enabled * *  Returns %0 for success or a negative error value. * *  Context: *    non-atomic */int enable_cmf(struct ccw_device *cdev){	int ret;	ret = cmbops->alloc(cdev);	cmbops->reset(cdev);	if (ret)		return ret;	ret = cmbops->set(cdev, 2);	if (ret) {		cmbops->free(cdev);		return ret;	}	ret = sysfs_create_group(&cdev->dev.kobj, cmbops->attr_group);	if (!ret)		return 0;	cmbops->set(cdev, 0);  //FIXME: this can fail	cmbops->free(cdev);	return ret;}/** * disable_cmf() - switch off the channel measurement for a specific device *  @cdev:	The ccw device to be disabled * *  Returns %0 for success or a negative error value. * *  Context: *    non-atomic */int disable_cmf(struct ccw_device *cdev){	int ret;	ret = cmbops->set(cdev, 0);	if (ret)		return ret;	cmbops->free(cdev);	sysfs_remove_group(&cdev->dev.kobj, cmbops->attr_group);	return ret;}/** * cmf_read() - read one value from the current channel measurement block * @cdev:	the channel to be read * @index:	the index of the value to be read * * Returns the value read or %0 if the value cannot be read. * *  Context: *    any */u64 cmf_read(struct ccw_device *cdev, int index){	return cmbops->read(cdev, index);}/** * cmf_readall() - read the current channel measurement block * @cdev:	the channel to be read * @data:	a pointer to a data block that will be filled * * Returns %0 on success, a negative error value otherwise. * *  Context: *    any */int cmf_readall(struct ccw_device *cdev, struct cmbdata *data){	return cmbops->readall(cdev, data);}/* Reenable cmf when a disconnected device becomes available again. */int cmf_reenable(struct ccw_device *cdev){	cmbops->reset(cdev);	return cmbops->set(cdev, 2);}static int __init init_cmf(void){	char *format_string;	char *detect_string = "parameter";	/*	 * If the user did not give a parameter, see if we are running on a	 * machine supporting extended measurement blocks, otherwise fall back	 * to basic mode.	 */	if (format == CMF_AUTODETECT) {		if (!css_characteristics_avail ||		    !css_general_characteristics.ext_mb) {			format = CMF_BASIC;		} else {			format = CMF_EXTENDED;		}		detect_string = "autodetected";	} else {		detect_string = "parameter";	}	switch (format) {	case CMF_BASIC:		format_string = "basic";		cmbops = &cmbops_basic;		break;	case CMF_EXTENDED:		format_string = "extended";		cmbops = &cmbops_extended;		break;	default:		printk(KERN_ERR "cio: Invalid format %d for channel "			"measurement facility\n", format);		return 1;	}	printk(KERN_INFO "cio: Channel measurement facility using %s "	       "format (%s)\n", format_string, detect_string);	return 0;}module_init(init_cmf);MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("channel measurement facility base driver\n"		   "Copyright 2003 IBM Corporation\n");EXPORT_SYMBOL_GPL(enable_cmf);EXPORT_SYMBOL_GPL(disable_cmf);EXPORT_SYMBOL_GPL(cmf_read);EXPORT_SYMBOL_GPL(cmf_readall);

⌨️ 快捷键说明

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