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

📄 cmf.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
		spin_unlock_irqrestore(cdev->ccwlock, flags);		return -ENODEV;	}	cmb = *(struct cmb*)cdev->private->cmb;	time = get_clock() - cdev->private->cmb_start_time;	spin_unlock_irqrestore(cdev->ccwlock, flags);	memset(data, 0, sizeof(struct cmbdata));	/* we only know values before device_busy_time */	data->size = offsetof(struct cmbdata, device_busy_time);	/* convert to nanoseconds */	data->elapsed_time = (time * 1000) >> 12;	/* 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);	return 0;}static voidreset_cmb(struct ccw_device *cdev){	struct cmb *cmb;	spin_lock_irq(cdev->ccwlock);	cmb = cdev->private->cmb;	if (cmb)		memset (cmb, 0, sizeof (*cmb));	cdev->private->cmb_start_time = get_clock();	spin_unlock_irq(cdev->ccwlock);}static struct attribute_group cmf_attr_group;static struct cmb_operations cmbops_basic = {	.alloc	= alloc_cmb,	.free	= free_cmb,	.set	= set_cmb,	.read	= read_cmb,	.readall    = readall_cmb,	.reset	    = reset_cmb,	.attr_group = &cmf_attr_group,};/* ******** extended cmb handling ********//** * struct cmbe - extended channel measurement block * * cmb as used by the hardware, may be in any 64 bit physical location, * the fields are described in z/Architecture Principles of Operation, * third edition, chapter 17. */struct cmbe {	u32 ssch_rsch_count;	u32 sample_count;	u32 device_connect_time;	u32 function_pending_time;	u32 device_disconnect_time;	u32 control_unit_queuing_time;	u32 device_active_only_time;	u32 device_busy_time;	u32 initial_command_response_time;	u32 reserved[7];};/* kmalloc only guarantees 8 byte alignment, but we need cmbe * pointers to be naturally aligned. Make sure to allocate * enough space for two cmbes */static inline struct cmbe* cmbe_align(struct cmbe *c){	unsigned long addr;	addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &				 ~(sizeof (struct cmbe) - sizeof(long));	return (struct cmbe*)addr;}static intalloc_cmbe (struct ccw_device *cdev){	struct cmbe *cmbe;	cmbe = kmalloc (sizeof (*cmbe) * 2, GFP_KERNEL);	if (!cmbe)		return -ENOMEM;	spin_lock_irq(cdev->ccwlock);	if (cdev->private->cmb) {		kfree(cmbe);		spin_unlock_irq(cdev->ccwlock);		return -EBUSY;	}	cdev->private->cmb = cmbe;	spin_unlock_irq(cdev->ccwlock);	/* activate global measurement if this is the first channel */	spin_lock(&cmb_area.lock);	if (list_empty(&cmb_area.list))		cmf_activate(NULL, 1);	list_add_tail(&cdev->private->cmb_list, &cmb_area.list);	spin_unlock(&cmb_area.lock);	return 0;}static voidfree_cmbe (struct ccw_device *cdev){	spin_lock_irq(cdev->ccwlock);	kfree(cdev->private->cmb);	cdev->private->cmb = NULL;	spin_unlock_irq(cdev->ccwlock);	/* deactivate global measurement if this is the last channel */	spin_lock(&cmb_area.lock);	list_del_init(&cdev->private->cmb_list);	if (list_empty(&cmb_area.list))		cmf_activate(NULL, 0);	spin_unlock(&cmb_area.lock);}static intset_cmbe(struct ccw_device *cdev, u32 mme){	unsigned long mba;	if (!cdev->private->cmb)		return -EINVAL;	mba = mme ? (unsigned long) cmbe_align(cdev->private->cmb) : 0;	return set_schib_wait(cdev, mme, 1, mba);}u64read_cmbe (struct ccw_device *cdev, int index){	/* yes, we have to put it on the stack	 * because the cmb must only be accessed	 * atomically, e.g. with mvc */	struct cmbe cmb;	unsigned long flags;	u32 val;	spin_lock_irqsave(cdev->ccwlock, flags);	if (!cdev->private->cmb) {		spin_unlock_irqrestore(cdev->ccwlock, flags);		return 0;	}	cmb = *cmbe_align(cdev->private->cmb);	spin_unlock_irqrestore(cdev->ccwlock, flags);	switch (index) {	case cmb_ssch_rsch_count:		return cmb.ssch_rsch_count;	case cmb_sample_count:		return cmb.sample_count;	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:		return 0;	}	return time_to_avg_nsec(val, cmb.sample_count);}static intreadall_cmbe (struct ccw_device *cdev, struct cmbdata *data){	/* yes, we have to put it on the stack	 * because the cmb must only be accessed	 * atomically, e.g. with mvc */	struct cmbe cmb;	unsigned long flags;	u64 time;	spin_lock_irqsave(cdev->ccwlock, flags);	if (!cdev->private->cmb) {		spin_unlock_irqrestore(cdev->ccwlock, flags);		return -ENODEV;	}	cmb = *cmbe_align(cdev->private->cmb);	time = get_clock() - cdev->private->cmb_start_time;	spin_unlock_irqrestore(cdev->ccwlock, flags);	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;	/* 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);	return 0;}static voidreset_cmbe(struct ccw_device *cdev){	struct cmbe *cmb;	spin_lock_irq(cdev->ccwlock);	cmb = cmbe_align(cdev->private->cmb);	if (cmb)		memset (cmb, 0, sizeof (*cmb));	cdev->private->cmb_start_time = get_clock();	spin_unlock_irq(cdev->ccwlock);}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,	.attr_group = &cmf_attr_group_ext,};static ssize_tcmb_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_tcmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf){	struct ccw_device *cdev;	long interval;	unsigned long count;	cdev = to_ccwdev(dev);	interval  = get_clock() - cdev->private->cmb_start_time;	count = cmf_read(cdev, cmb_sample_count);	if (count)		interval /= count;	else		interval = -1;	return sprintf(buf, "%ld\n", interval);}static ssize_tcmb_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)		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,	0,};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,	0,};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)			printk(KERN_INFO "disable_cmf failed (%d)\n", ret);		break;	case '1':		ret = enable_cmf(cdev);		if (ret && ret != -EBUSY)			printk(KERN_INFO "enable_cmf failed (%d)\n", ret);		break;	}	return c;}DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);/* enable_cmf/disable_cmf: module interface for cmf (de)activation */intenable_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;}intdisable_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;}u64cmf_read(struct ccw_device *cdev, int index){	return cmbops->read(cdev, index);}intcmf_readall(struct ccw_device *cdev, struct cmbdata *data){	return cmbops->readall(cdev, data);}static int __initinit_cmf(void){	char *format_string;	char *detect_string = "parameter";	/* We cannot really autoprobe this. If the user did not give a parameter,	   see if we are running on z990 or up, 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;		if (cmb_area.num_channels > 4096 || cmb_area.num_channels < 1) {			printk(KERN_ERR "Basic channel measurement facility"					" can only use 1 to 4096 devices\n"			       KERN_ERR "when the cmf driver is built"					" as a loadable module\n");			return 1;		}		break;	case CMF_EXTENDED: 		format_string = "extended";		cmbops = &cmbops_extended;		break;	default:		printk(KERN_ERR "Invalid format %d for channel "			"measurement facility\n", format);		return 1;	}	printk(KERN_INFO "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 + -