Commit ba0234ec authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6

* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (24 commits)
  [S390] drivers/s390/char: Use kmemdup
  [S390] drivers/s390/char: Use kstrdup
  [S390] debug: enable exception-trace debug facility
  [S390] s390_hypfs: Add new attributes
  [S390] qdio: remove API wrappers
  [S390] qdio: set correct bit in dsci
  [S390] qdio: dont convert timestamps to microseconds
  [S390] qdio: remove memset hack
  [S390] qdio: prevent starvation on PCI devices
  [S390] qdio: count number of qdio interrupts
  [S390] user space fault: report fault before calling do_exit
  [S390] topology: expose core identifier
  [S390] dasd: remove uid from devmap
  [S390] dasd: add dynamic pav toleration
  [S390] vdso: add missing vdso_install target
  [S390] vdso: remove redundant check for CONFIG_64BIT
  [S390] avoid default_llseek in s390 drivers
  [S390] vmcp: disallow modular build
  [S390] add breaking event address for user space
  [S390] virtualization aware cpu measurement
  ...
parents 537b60d1 939e379e
...@@ -444,13 +444,6 @@ config FORCE_MAX_ZONEORDER ...@@ -444,13 +444,6 @@ config FORCE_MAX_ZONEORDER
int int
default "9" default "9"
config PROCESS_DEBUG
bool "Show crashed user process info"
help
Say Y to print all process fault locations to the console. This is
a debugging option; you probably do not want to set it unless you
are an S390 port maintainer.
config PFAULT config PFAULT
bool "Pseudo page fault support" bool "Pseudo page fault support"
help help
......
...@@ -116,6 +116,12 @@ image bzImage: vmlinux ...@@ -116,6 +116,12 @@ image bzImage: vmlinux
zfcpdump: zfcpdump:
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
vdso_install:
ifeq ($(CONFIG_64BIT),y)
$(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@
endif
$(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso32 $@
archclean: archclean:
$(Q)$(MAKE) $(clean)=$(boot) $(Q)$(MAKE) $(clean)=$(boot)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/debugfs.h>
#define REG_FILE_MODE 0440 #define REG_FILE_MODE 0440
#define UPDATE_FILE_MODE 0220 #define UPDATE_FILE_MODE 0220
...@@ -34,6 +35,9 @@ extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); ...@@ -34,6 +35,9 @@ extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
/* VM Hypervisor */ /* VM Hypervisor */
extern int hypfs_vm_init(void); extern int hypfs_vm_init(void);
extern void hypfs_vm_exit(void);
extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
/* Directory for debugfs files */
extern struct dentry *hypfs_dbfs_dir;
#endif /* _HYPFS_H_ */ #endif /* _HYPFS_H_ */
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/mm.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include "hypfs.h" #include "hypfs.h"
...@@ -22,6 +23,8 @@ ...@@ -22,6 +23,8 @@
#define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */ #define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */
#define TMP_SIZE 64 /* size of temporary buffers */ #define TMP_SIZE 64 /* size of temporary buffers */
#define DBFS_D204_HDR_VERSION 0
/* diag 204 subcodes */ /* diag 204 subcodes */
enum diag204_sc { enum diag204_sc {
SUBC_STIB4 = 4, SUBC_STIB4 = 4,
...@@ -47,6 +50,8 @@ static void *diag204_buf; /* 4K aligned buffer for diag204 data */ ...@@ -47,6 +50,8 @@ static void *diag204_buf; /* 4K aligned buffer for diag204 data */
static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */ static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */
static int diag204_buf_pages; /* number of pages for diag204 data */ static int diag204_buf_pages; /* number of pages for diag204 data */
static struct dentry *dbfs_d204_file;
/* /*
* DIAG 204 data structures and member access functions. * DIAG 204 data structures and member access functions.
* *
...@@ -364,18 +369,21 @@ static void diag204_free_buffer(void) ...@@ -364,18 +369,21 @@ static void diag204_free_buffer(void)
} else { } else {
free_pages((unsigned long) diag204_buf, 0); free_pages((unsigned long) diag204_buf, 0);
} }
diag204_buf_pages = 0;
diag204_buf = NULL; diag204_buf = NULL;
} }
static void *page_align_ptr(void *ptr)
{
return (void *) PAGE_ALIGN((unsigned long) ptr);
}
static void *diag204_alloc_vbuf(int pages) static void *diag204_alloc_vbuf(int pages)
{ {
/* The buffer has to be page aligned! */ /* The buffer has to be page aligned! */
diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1)); diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1));
if (!diag204_buf_vmalloc) if (!diag204_buf_vmalloc)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc diag204_buf = page_align_ptr(diag204_buf_vmalloc);
& ~0xfffUL) + 0x1000;
diag204_buf_pages = pages; diag204_buf_pages = pages;
return diag204_buf; return diag204_buf;
} }
...@@ -468,17 +476,26 @@ fail_alloc: ...@@ -468,17 +476,26 @@ fail_alloc:
return rc; return rc;
} }
static int diag204_do_store(void *buf, int pages)
{
int rc;
rc = diag204((unsigned long) diag204_store_sc |
(unsigned long) diag204_info_type, pages, buf);
return rc < 0 ? -ENOSYS : 0;
}
static void *diag204_store(void) static void *diag204_store(void)
{ {
void *buf; void *buf;
int pages; int pages, rc;
buf = diag204_get_buffer(diag204_info_type, &pages); buf = diag204_get_buffer(diag204_info_type, &pages);
if (IS_ERR(buf)) if (IS_ERR(buf))
goto out; goto out;
if (diag204((unsigned long)diag204_store_sc | rc = diag204_do_store(buf, pages);
(unsigned long)diag204_info_type, pages, buf) < 0) if (rc)
return ERR_PTR(-ENOSYS); return ERR_PTR(rc);
out: out:
return buf; return buf;
} }
...@@ -526,6 +543,92 @@ static int diag224_idx2name(int index, char *name) ...@@ -526,6 +543,92 @@ static int diag224_idx2name(int index, char *name)
return 0; return 0;
} }
struct dbfs_d204_hdr {
u64 len; /* Length of d204 buffer without header */
u16 version; /* Version of header */
u8 sc; /* Used subcode */
char reserved[53];
} __attribute__ ((packed));
struct dbfs_d204 {
struct dbfs_d204_hdr hdr; /* 64 byte header */
char buf[]; /* d204 buffer */
} __attribute__ ((packed));
struct dbfs_d204_private {
struct dbfs_d204 *d204; /* Aligned d204 data with header */
void *base; /* Base pointer (needed for vfree) */
};
static int dbfs_d204_open(struct inode *inode, struct file *file)
{
struct dbfs_d204_private *data;
struct dbfs_d204 *d204;
int rc, buf_size;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
data->base = vmalloc(buf_size);
if (!data->base) {
rc = -ENOMEM;
goto fail_kfree_data;
}
memset(data->base, 0, buf_size);
d204 = page_align_ptr(data->base + sizeof(d204->hdr))
- sizeof(d204->hdr);
rc = diag204_do_store(&d204->buf, diag204_buf_pages);
if (rc)
goto fail_vfree_base;
d204->hdr.version = DBFS_D204_HDR_VERSION;
d204->hdr.len = PAGE_SIZE * diag204_buf_pages;
d204->hdr.sc = diag204_store_sc;
data->d204 = d204;
file->private_data = data;
return nonseekable_open(inode, file);
fail_vfree_base:
vfree(data->base);
fail_kfree_data:
kfree(data);
return rc;
}
static int dbfs_d204_release(struct inode *inode, struct file *file)
{
struct dbfs_d204_private *data = file->private_data;
vfree(data->base);
kfree(data);
return 0;
}
static ssize_t dbfs_d204_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
struct dbfs_d204_private *data = file->private_data;
return simple_read_from_buffer(buf, size, ppos, data->d204,
data->d204->hdr.len +
sizeof(data->d204->hdr));
}
static const struct file_operations dbfs_d204_ops = {
.open = dbfs_d204_open,
.read = dbfs_d204_read,
.release = dbfs_d204_release,
};
static int hypfs_dbfs_init(void)
{
dbfs_d204_file = debugfs_create_file("diag_204", 0400, hypfs_dbfs_dir,
NULL, &dbfs_d204_ops);
if (IS_ERR(dbfs_d204_file))
return PTR_ERR(dbfs_d204_file);
return 0;
}
__init int hypfs_diag_init(void) __init int hypfs_diag_init(void)
{ {
int rc; int rc;
...@@ -540,11 +643,17 @@ __init int hypfs_diag_init(void) ...@@ -540,11 +643,17 @@ __init int hypfs_diag_init(void)
pr_err("The hardware system does not provide all " pr_err("The hardware system does not provide all "
"functions required by hypfs\n"); "functions required by hypfs\n");
} }
if (diag204_info_type == INFO_EXT) {
rc = hypfs_dbfs_init();
if (rc)
diag204_free_buffer();
}
return rc; return rc;
} }
void hypfs_diag_exit(void) void hypfs_diag_exit(void)
{ {
debugfs_remove(dbfs_d204_file);
diag224_delete_name_table(); diag224_delete_name_table();
diag204_free_buffer(); diag204_free_buffer();
} }
......
...@@ -10,14 +10,18 @@ ...@@ -10,14 +10,18 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/timex.h>
#include "hypfs.h" #include "hypfs.h"
#define NAME_LEN 8 #define NAME_LEN 8
#define DBFS_D2FC_HDR_VERSION 0
static char local_guest[] = " "; static char local_guest[] = " ";
static char all_guests[] = "* "; static char all_guests[] = "* ";
static char *guest_query; static char *guest_query;
static struct dentry *dbfs_d2fc_file;
struct diag2fc_data { struct diag2fc_data {
__u32 version; __u32 version;
__u32 flags; __u32 flags;
...@@ -76,23 +80,26 @@ static int diag2fc(int size, char* query, void *addr) ...@@ -76,23 +80,26 @@ static int diag2fc(int size, char* query, void *addr)
return -residual_cnt; return -residual_cnt;
} }
static struct diag2fc_data *diag2fc_store(char *query, int *count) /*
* Allocate buffer for "query" and store diag 2fc at "offset"
*/
static void *diag2fc_store(char *query, unsigned int *count, int offset)
{ {
void *data;
int size; int size;
struct diag2fc_data *data;
do { do {
size = diag2fc(0, query, NULL); size = diag2fc(0, query, NULL);
if (size < 0) if (size < 0)
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
data = vmalloc(size); data = vmalloc(size + offset);
if (!data) if (!data)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (diag2fc(size, query, data) == 0) if (diag2fc(size, query, data + offset) == 0)
break; break;
vfree(data); vfree(data);
} while (1); } while (1);
*count = (size / sizeof(*data)); *count = (size / sizeof(struct diag2fc_data));
return data; return data;
} }
...@@ -168,9 +175,10 @@ int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) ...@@ -168,9 +175,10 @@ int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
{ {
struct dentry *dir, *file; struct dentry *dir, *file;
struct diag2fc_data *data; struct diag2fc_data *data;
int rc, i, count = 0; unsigned int count = 0;
int rc, i;
data = diag2fc_store(guest_query, &count); data = diag2fc_store(guest_query, &count, 0);
if (IS_ERR(data)) if (IS_ERR(data))
return PTR_ERR(data); return PTR_ERR(data);
...@@ -218,8 +226,61 @@ failed: ...@@ -218,8 +226,61 @@ failed:
return rc; return rc;
} }
struct dbfs_d2fc_hdr {
u64 len; /* Length of d2fc buffer without header */
u16 version; /* Version of header */
char tod_ext[16]; /* TOD clock for d2fc */
u64 count; /* Number of VM guests in d2fc buffer */
char reserved[30];
} __attribute__ ((packed));
struct dbfs_d2fc {
struct dbfs_d2fc_hdr hdr; /* 64 byte header */
char buf[]; /* d2fc buffer */
} __attribute__ ((packed));
static int dbfs_d2fc_open(struct inode *inode, struct file *file)
{
struct dbfs_d2fc *data;
unsigned int count;
data = diag2fc_store(guest_query, &count, sizeof(data->hdr));
if (IS_ERR(data))
return PTR_ERR(data);
get_clock_ext(data->hdr.tod_ext);
data->hdr.len = count * sizeof(struct diag2fc_data);
data->hdr.version = DBFS_D2FC_HDR_VERSION;
data->hdr.count = count;
memset(&data->hdr.reserved, 0, sizeof(data->hdr.reserved));
file->private_data = data;
return nonseekable_open(inode, file);
}
static int dbfs_d2fc_release(struct inode *inode, struct file *file)
{
diag2fc_free(file->private_data);
return 0;
}
static ssize_t dbfs_d2fc_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
struct dbfs_d2fc *data = file->private_data;
return simple_read_from_buffer(buf, size, ppos, data, data->hdr.len +
sizeof(struct dbfs_d2fc_hdr));
}
static const struct file_operations dbfs_d2fc_ops = {
.open = dbfs_d2fc_open,
.read = dbfs_d2fc_read,
.release = dbfs_d2fc_release,
};
int hypfs_vm_init(void) int hypfs_vm_init(void)
{ {
if (!MACHINE_IS_VM)
return 0;
if (diag2fc(0, all_guests, NULL) > 0) if (diag2fc(0, all_guests, NULL) > 0)
guest_query = all_guests; guest_query = all_guests;
else if (diag2fc(0, local_guest, NULL) > 0) else if (diag2fc(0, local_guest, NULL) > 0)
...@@ -227,5 +288,17 @@ int hypfs_vm_init(void) ...@@ -227,5 +288,17 @@ int hypfs_vm_init(void)
else else
return -EACCES; return -EACCES;
dbfs_d2fc_file = debugfs_create_file("diag_2fc", 0400, hypfs_dbfs_dir,
NULL, &dbfs_d2fc_ops);
if (IS_ERR(dbfs_d2fc_file))
return PTR_ERR(dbfs_d2fc_file);
return 0; return 0;
} }
void hypfs_vm_exit(void)
{
if (!MACHINE_IS_VM)
return;
debugfs_remove(dbfs_d2fc_file);
}
...@@ -46,6 +46,8 @@ static const struct super_operations hypfs_s_ops; ...@@ -46,6 +46,8 @@ static const struct super_operations hypfs_s_ops;
/* start of list of all dentries, which have to be deleted on update */ /* start of list of all dentries, which have to be deleted on update */
static struct dentry *hypfs_last_dentry; static struct dentry *hypfs_last_dentry;
struct dentry *hypfs_dbfs_dir;
static void hypfs_update_update(struct super_block *sb) static void hypfs_update_update(struct super_block *sb)
{ {
struct hypfs_sb_info *sb_info = sb->s_fs_info; struct hypfs_sb_info *sb_info = sb->s_fs_info;
...@@ -145,7 +147,7 @@ static int hypfs_open(struct inode *inode, struct file *filp) ...@@ -145,7 +147,7 @@ static int hypfs_open(struct inode *inode, struct file *filp)
} }
mutex_unlock(&fs_info->lock); mutex_unlock(&fs_info->lock);
} }
return 0; return nonseekable_open(inode, filp);
} }
static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
...@@ -468,20 +470,22 @@ static int __init hypfs_init(void) ...@@ -468,20 +470,22 @@ static int __init hypfs_init(void)
{ {
int rc; int rc;
if (MACHINE_IS_VM) { hypfs_dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
if (hypfs_vm_init()) if (IS_ERR(hypfs_dbfs_dir))
/* no diag 2fc, just exit */ return PTR_ERR(hypfs_dbfs_dir);
return -ENODATA;
} else { if (hypfs_diag_init()) {
if (hypfs_diag_init()) { rc = -ENODATA;
rc = -ENODATA; goto fail_debugfs_remove;
goto fail_diag; }
} if (hypfs_vm_init()) {
rc = -ENODATA;
goto fail_hypfs_diag_exit;
} }
s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
if (!s390_kobj) { if (!s390_kobj) {
rc = -ENOMEM; rc = -ENOMEM;
goto fail_sysfs; goto fail_hypfs_vm_exit;
} }
rc = register_filesystem(&hypfs_type); rc = register_filesystem(&hypfs_type);
if (rc) if (rc)
...@@ -490,18 +494,22 @@ static int __init hypfs_init(void) ...@@ -490,18 +494,22 @@ static int __init hypfs_init(void)
fail_filesystem: fail_filesystem:
kobject_put(s390_kobj); kobject_put(s390_kobj);
fail_sysfs: fail_hypfs_vm_exit:
if (!MACHINE_IS_VM) hypfs_vm_exit();
hypfs_diag_exit(); fail_hypfs_diag_exit:
fail_diag: hypfs_diag_exit();
fail_debugfs_remove:
debugfs_remove(hypfs_dbfs_dir);
pr_err("Initialization of hypfs failed with rc=%i\n", rc); pr_err("Initialization of hypfs failed with rc=%i\n", rc);
return rc; return rc;
} }
static void __exit hypfs_exit(void) static void __exit hypfs_exit(void)
{ {
if (!MACHINE_IS_VM) hypfs_diag_exit();
hypfs_diag_exit(); hypfs_vm_exit();
debugfs_remove(hypfs_dbfs_dir);
unregister_filesystem(&hypfs_type); unregister_filesystem(&hypfs_type);
kobject_put(s390_kobj); kobject_put(s390_kobj);
} }
......
...@@ -188,15 +188,16 @@ struct s390_idle_data { ...@@ -188,15 +188,16 @@ struct s390_idle_data {
DECLARE_PER_CPU(struct s390_idle_data, s390_idle); DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
void vtime_start_cpu(void); void vtime_start_cpu(__u64 int_clock, __u64 enter_timer);
cputime64_t s390_get_idle_time(int cpu); cputime64_t s390_get_idle_time(int cpu);
#define arch_idle_time(cpu) s390_get_idle_time(cpu) #define arch_idle_time(cpu) s390_get_idle_time(cpu)