Merge branch 'drm-forlinus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / arch / s390 / kernel / setup.c
index 5ba5a54..b03847d 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/console.h>
 #include <linux/seq_file.h>
 #include <linux/kernel_stat.h>
+#include <linux/device.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -261,8 +262,11 @@ void (*_machine_power_off)(void) = machine_power_off_smp;
  * Reboot, halt and power_off routines for non SMP.
  */
 extern void reipl(unsigned long devno);
+extern void reipl_diag(void);
 static void do_machine_restart_nonsmp(char * __unused)
 {
+       reipl_diag();
+
        if (MACHINE_IS_VM)
                cpcmd ("IPL", NULL, 0);
        else
@@ -423,7 +427,7 @@ setup_lowcore(void)
                __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
        lc->current_task = (unsigned long) init_thread_union.thread_info.task;
        lc->thread_info = (unsigned long) &init_thread_union;
-#ifndef CONFIG_ARCH_S390X
+#ifndef CONFIG_64BIT
        if (MACHINE_HAS_IEEE) {
                lc->extended_save_area_addr = (__u32)
                        __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
@@ -558,21 +562,21 @@ setup_arch(char **cmdline_p)
         /*
          * print what head.S has found out about the machine
          */
-#ifndef CONFIG_ARCH_S390X
+#ifndef CONFIG_64BIT
        printk((MACHINE_IS_VM) ?
               "We are running under VM (31 bit mode)\n" :
               "We are running native (31 bit mode)\n");
        printk((MACHINE_HAS_IEEE) ?
               "This machine has an IEEE fpu\n" :
               "This machine has no IEEE fpu\n");
-#else /* CONFIG_ARCH_S390X */
+#else /* CONFIG_64BIT */
        printk((MACHINE_IS_VM) ?
               "We are running under VM (64 bit mode)\n" :
               "We are running native (64 bit mode)\n");
-#endif /* CONFIG_ARCH_S390X */
+#endif /* CONFIG_64BIT */
 
         ROOT_DEV = Root_RAM0;
-#ifndef CONFIG_ARCH_S390X
+#ifndef CONFIG_64BIT
        memory_end = memory_size & ~0x400000UL;  /* align memory end to 4MB */
         /*
          * We need some free virtual space to be able to do vmalloc.
@@ -581,9 +585,9 @@ setup_arch(char **cmdline_p)
          */
         if (memory_end > 1920*1024*1024)
                 memory_end = 1920*1024*1024;
-#else /* CONFIG_ARCH_S390X */
+#else /* CONFIG_64BIT */
        memory_end = memory_size & ~0x200000UL;  /* detected in head.s */
-#endif /* CONFIG_ARCH_S390X */
+#endif /* CONFIG_64BIT */
 
        init_mm.start_code = PAGE_OFFSET;
        init_mm.end_code = (unsigned long) &_etext;
@@ -634,6 +638,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
         struct cpuinfo_S390 *cpuinfo;
        unsigned long n = (unsigned long) v - 1;
 
+       preempt_disable();
        if (!n) {
                seq_printf(m, "vendor_id       : IBM/S390\n"
                               "# processors    : %i\n"
@@ -658,6 +663,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                               cpuinfo->cpu_id.ident,
                               cpuinfo->cpu_id.machine);
        }
+       preempt_enable();
         return 0;
 }
 
@@ -680,3 +686,188 @@ struct seq_operations cpuinfo_op = {
        .show   = show_cpuinfo,
 };
 
+#define DEFINE_IPL_ATTR(_name, _format, _value)                        \
+static ssize_t ipl_##_name##_show(struct subsystem *subsys,    \
+               char *page)                                     \
+{                                                              \
+       return sprintf(page, _format, _value);                  \
+}                                                              \
+static struct subsys_attribute ipl_##_name##_attr =            \
+       __ATTR(_name, S_IRUGO, ipl_##_name##_show, NULL);
+
+DEFINE_IPL_ATTR(wwpn, "0x%016llx\n", (unsigned long long)
+               IPL_PARMBLOCK_START->fcp.wwpn);
+DEFINE_IPL_ATTR(lun, "0x%016llx\n", (unsigned long long)
+               IPL_PARMBLOCK_START->fcp.lun);
+DEFINE_IPL_ATTR(bootprog, "%lld\n", (unsigned long long)
+               IPL_PARMBLOCK_START->fcp.bootprog);
+DEFINE_IPL_ATTR(br_lba, "%lld\n", (unsigned long long)
+               IPL_PARMBLOCK_START->fcp.br_lba);
+
+enum ipl_type_type {
+       ipl_type_unknown,
+       ipl_type_ccw,
+       ipl_type_fcp,
+};
+
+static enum ipl_type_type
+get_ipl_type(void)
+{
+       struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
+
+       if (!IPL_DEVNO_VALID)
+               return ipl_type_unknown;
+       if (!IPL_PARMBLOCK_VALID)
+               return ipl_type_ccw;
+       if (ipl->hdr.header.version > IPL_MAX_SUPPORTED_VERSION)
+               return ipl_type_unknown;
+       if (ipl->fcp.pbt != IPL_TYPE_FCP)
+               return ipl_type_unknown;
+       return ipl_type_fcp;
+}
+
+static ssize_t
+ipl_type_show(struct subsystem *subsys, char *page)
+{
+       switch (get_ipl_type()) {
+       case ipl_type_ccw:
+               return sprintf(page, "ccw\n");
+       case ipl_type_fcp:
+               return sprintf(page, "fcp\n");
+       default:
+               return sprintf(page, "unknown\n");
+       }
+}
+
+static struct subsys_attribute ipl_type_attr = __ATTR_RO(ipl_type);
+
+static ssize_t
+ipl_device_show(struct subsystem *subsys, char *page)
+{
+       struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
+
+       switch (get_ipl_type()) {
+       case ipl_type_ccw:
+               return sprintf(page, "0.0.%04x\n", ipl_devno);
+       case ipl_type_fcp:
+               return sprintf(page, "0.0.%04x\n", ipl->fcp.devno);
+       default:
+               return 0;
+       }
+}
+
+static struct subsys_attribute ipl_device_attr =
+       __ATTR(device, S_IRUGO, ipl_device_show, NULL);
+
+static struct attribute *ipl_fcp_attrs[] = {
+       &ipl_type_attr.attr,
+       &ipl_device_attr.attr,
+       &ipl_wwpn_attr.attr,
+       &ipl_lun_attr.attr,
+       &ipl_bootprog_attr.attr,
+       &ipl_br_lba_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ipl_fcp_attr_group = {
+       .attrs = ipl_fcp_attrs,
+};
+
+static struct attribute *ipl_ccw_attrs[] = {
+       &ipl_type_attr.attr,
+       &ipl_device_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ipl_ccw_attr_group = {
+       .attrs = ipl_ccw_attrs,
+};
+
+static struct attribute *ipl_unknown_attrs[] = {
+       &ipl_type_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ipl_unknown_attr_group = {
+       .attrs = ipl_unknown_attrs,
+};
+
+static ssize_t
+ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       unsigned int size = IPL_PARMBLOCK_SIZE;
+
+       if (off > size)
+               return 0;
+       if (off + count > size)
+               count = size - off;
+
+       memcpy(buf, (void *) IPL_PARMBLOCK_START + off, count);
+       return count;
+}
+
+static struct bin_attribute ipl_parameter_attr = {
+       .attr = {
+               .name = "binary_parameter",
+               .mode = S_IRUGO,
+               .owner = THIS_MODULE,
+       },
+       .size = PAGE_SIZE,
+       .read = &ipl_parameter_read,
+};
+
+static ssize_t
+ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+       unsigned int size =  IPL_PARMBLOCK_START->fcp.scp_data_len;
+       void *scp_data = &IPL_PARMBLOCK_START->fcp.scp_data;
+
+       if (off > size)
+               return 0;
+       if (off + count > size)
+               count = size - off;
+
+       memcpy(buf, scp_data + off, count);
+       return count;
+}
+
+static struct bin_attribute ipl_scp_data_attr = {
+       .attr = {
+               .name = "scp_data",
+               .mode = S_IRUGO,
+               .owner = THIS_MODULE,
+       },
+       .size = PAGE_SIZE,
+       .read = &ipl_scp_data_read,
+};
+
+static decl_subsys(ipl, NULL, NULL);
+
+static int __init
+ipl_device_sysfs_register(void) {
+       int rc;
+
+       rc = firmware_register(&ipl_subsys);
+       if (rc)
+               return rc;
+
+       switch (get_ipl_type()) {
+       case ipl_type_ccw:
+               sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_ccw_attr_group);
+               break;
+       case ipl_type_fcp:
+               sysfs_create_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
+               sysfs_create_bin_file(&ipl_subsys.kset.kobj,
+                                     &ipl_parameter_attr);
+               sysfs_create_bin_file(&ipl_subsys.kset.kobj,
+                                     &ipl_scp_data_attr);
+               break;
+       default:
+               sysfs_create_group(&ipl_subsys.kset.kobj,
+                                  &ipl_unknown_attr_group);
+               break;
+       }
+       return 0;
+}
+
+__initcall(ipl_device_sysfs_register);