diff options
Diffstat (limited to 'arch/s390/hypfs')
| -rw-r--r-- | arch/s390/hypfs/Makefile | 2 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs.h | 7 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_dbfs.c | 16 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_sprp.c | 141 | ||||
| -rw-r--r-- | arch/s390/hypfs/hypfs_vm.c | 9 | ||||
| -rw-r--r-- | arch/s390/hypfs/inode.c | 15 | 
6 files changed, 183 insertions, 7 deletions
diff --git a/arch/s390/hypfs/Makefile b/arch/s390/hypfs/Makefile index 2e671d5004c..06f8d95a16c 100644 --- a/arch/s390/hypfs/Makefile +++ b/arch/s390/hypfs/Makefile @@ -4,4 +4,4 @@  obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o -s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o +s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index 79f2ac55253..b34b5ab90a3 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -13,6 +13,7 @@  #include <linux/debugfs.h>  #include <linux/workqueue.h>  #include <linux/kref.h> +#include <asm/hypfs.h>  #define REG_FILE_MODE    0440  #define UPDATE_FILE_MODE 0220 @@ -36,6 +37,10 @@ extern int hypfs_vm_init(void);  extern void hypfs_vm_exit(void);  extern int hypfs_vm_create_files(struct dentry *root); +/* Set Partition-Resource Parameter */ +int hypfs_sprp_init(void); +void hypfs_sprp_exit(void); +  /* debugfs interface */  struct hypfs_dbfs_file; @@ -52,6 +57,8 @@ struct hypfs_dbfs_file {  	int		(*data_create)(void **data, void **data_free_ptr,  				       size_t *size);  	void		(*data_free)(const void *buf_free_ptr); +	long		(*unlocked_ioctl) (struct file *, unsigned int, +					   unsigned long);  	/* Private data for hypfs_dbfs.c */  	struct hypfs_dbfs_data	*data; diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c index 17ab8b7b53c..2badf2bf9cd 100644 --- a/arch/s390/hypfs/hypfs_dbfs.c +++ b/arch/s390/hypfs/hypfs_dbfs.c @@ -81,9 +81,25 @@ static ssize_t dbfs_read(struct file *file, char __user *buf,  	return rc;  } +static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ +	struct hypfs_dbfs_file *df; +	long rc; + +	df = file->f_path.dentry->d_inode->i_private; +	mutex_lock(&df->lock); +	if (df->unlocked_ioctl) +		rc = df->unlocked_ioctl(file, cmd, arg); +	else +		rc = -ENOTTY; +	mutex_unlock(&df->lock); +	return rc; +} +  static const struct file_operations dbfs_ops = {  	.read		= dbfs_read,  	.llseek		= no_llseek, +	.unlocked_ioctl = dbfs_ioctl,  };  int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c new file mode 100644 index 00000000000..f043c3c7e73 --- /dev/null +++ b/arch/s390/hypfs/hypfs_sprp.c @@ -0,0 +1,141 @@ +/* + *    Hypervisor filesystem for Linux on s390. + *    Set Partition-Resource Parameter interface. + * + *    Copyright IBM Corp. 2013 + *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> + */ + +#include <linux/compat.h> +#include <linux/errno.h> +#include <linux/gfp.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/uaccess.h> +#include <asm/compat.h> +#include <asm/sclp.h> +#include "hypfs.h" + +#define DIAG304_SET_WEIGHTS	0 +#define DIAG304_QUERY_PRP	1 +#define DIAG304_SET_CAPPING	2 + +#define DIAG304_CMD_MAX		2 + +static unsigned long hypfs_sprp_diag304(void *data, unsigned long cmd) +{ +	register unsigned long _data asm("2") = (unsigned long) data; +	register unsigned long _rc asm("3"); +	register unsigned long _cmd asm("4") = cmd; + +	asm volatile("diag %1,%2,0x304\n" +		     : "=d" (_rc) : "d" (_data), "d" (_cmd) : "memory"); + +	return _rc; +} + +static void hypfs_sprp_free(const void *data) +{ +	free_page((unsigned long) data); +} + +static int hypfs_sprp_create(void **data_ptr, void **free_ptr, size_t *size) +{ +	unsigned long rc; +	void *data; + +	data = (void *) get_zeroed_page(GFP_KERNEL); +	if (!data) +		return -ENOMEM; +	rc = hypfs_sprp_diag304(data, DIAG304_QUERY_PRP); +	if (rc != 1) { +		*data_ptr = *free_ptr = NULL; +		*size = 0; +		free_page((unsigned long) data); +		return -EIO; +	} +	*data_ptr = *free_ptr = data; +	*size = PAGE_SIZE; +	return 0; +} + +static int __hypfs_sprp_ioctl(void __user *user_area) +{ +	struct hypfs_diag304 diag304; +	unsigned long cmd; +	void __user *udata; +	void *data; +	int rc; + +	if (copy_from_user(&diag304, user_area, sizeof(diag304))) +		return -EFAULT; +	if ((diag304.args[0] >> 8) != 0 || diag304.args[1] > DIAG304_CMD_MAX) +		return -EINVAL; + +	data = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); +	if (!data) +		return -ENOMEM; + +	udata = (void __user *)(unsigned long) diag304.data; +	if (diag304.args[1] == DIAG304_SET_WEIGHTS || +	    diag304.args[1] == DIAG304_SET_CAPPING) +		if (copy_from_user(data, udata, PAGE_SIZE)) { +			rc = -EFAULT; +			goto out; +		} + +	cmd = *(unsigned long *) &diag304.args[0]; +	diag304.rc = hypfs_sprp_diag304(data, cmd); + +	if (diag304.args[1] == DIAG304_QUERY_PRP) +		if (copy_to_user(udata, data, PAGE_SIZE)) { +			rc = -EFAULT; +			goto out; +		} + +	rc = copy_to_user(user_area, &diag304, sizeof(diag304)) ? -EFAULT : 0; +out: +	free_page((unsigned long) data); +	return rc; +} + +static long hypfs_sprp_ioctl(struct file *file, unsigned int cmd, +			       unsigned long arg) +{ +	void __user *argp; + +	if (!capable(CAP_SYS_ADMIN)) +		return -EACCES; +	if (is_compat_task()) +		argp = compat_ptr(arg); +	else +		argp = (void __user *) arg; +	switch (cmd) { +	case HYPFS_DIAG304: +		return __hypfs_sprp_ioctl(argp); +	default: /* unknown ioctl number */ +		return -ENOTTY; +	} +	return 0; +} + +static struct hypfs_dbfs_file hypfs_sprp_file = { +	.name		= "diag_304", +	.data_create	= hypfs_sprp_create, +	.data_free	= hypfs_sprp_free, +	.unlocked_ioctl = hypfs_sprp_ioctl, +}; + +int hypfs_sprp_init(void) +{ +	if (!sclp_has_sprp()) +		return 0; +	return hypfs_dbfs_create_file(&hypfs_sprp_file); +} + +void hypfs_sprp_exit(void) +{ +	if (!sclp_has_sprp()) +		return; +	hypfs_dbfs_remove_file(&hypfs_sprp_file); +} diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c index 24908ce149f..32040ace00e 100644 --- a/arch/s390/hypfs/hypfs_vm.c +++ b/arch/s390/hypfs/hypfs_vm.c @@ -32,7 +32,7 @@ struct diag2fc_data {  	__u32 pcpus;  	__u32 lcpus;  	__u32 vcpus; -	__u32 cpu_min; +	__u32 ocpus;  	__u32 cpu_max;  	__u32 cpu_shares;  	__u32 cpu_use_samp; @@ -142,7 +142,12 @@ static int hpyfs_vm_create_guest(struct dentry *systems_dir,  	ATTRIBUTE(cpus_dir, "capped", capped_value);  	ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);  	ATTRIBUTE(cpus_dir, "count", data->vcpus); -	ATTRIBUTE(cpus_dir, "weight_min", data->cpu_min); +	/* +	 * Note: The "weight_min" attribute got the wrong name. +	 * The value represents the number of non-stopped (operating) +	 * CPUS. +	 */ +	ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);  	ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);  	ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares); diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index ddfe09b4513..c952b981e4f 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -478,10 +478,14 @@ static int __init hypfs_init(void)  		rc = -ENODATA;  		goto fail_hypfs_diag_exit;  	} +	if (hypfs_sprp_init()) { +		rc = -ENODATA; +		goto fail_hypfs_vm_exit; +	}  	s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);  	if (!s390_kobj) {  		rc = -ENOMEM; -		goto fail_hypfs_vm_exit; +		goto fail_hypfs_sprp_exit;  	}  	rc = register_filesystem(&hypfs_type);  	if (rc) @@ -490,6 +494,8 @@ static int __init hypfs_init(void)  fail_filesystem:  	kobject_put(s390_kobj); +fail_hypfs_sprp_exit: +	hypfs_sprp_exit();  fail_hypfs_vm_exit:  	hypfs_vm_exit();  fail_hypfs_diag_exit: @@ -502,11 +508,12 @@ fail_dbfs_exit:  static void __exit hypfs_exit(void)  { -	hypfs_diag_exit(); -	hypfs_vm_exit(); -	hypfs_dbfs_exit();  	unregister_filesystem(&hypfs_type);  	kobject_put(s390_kobj); +	hypfs_sprp_exit(); +	hypfs_vm_exit(); +	hypfs_diag_exit(); +	hypfs_dbfs_exit();  }  module_init(hypfs_init)  | 
