summaryrefslogtreecommitdiff
path: root/drivers/s390/char/sclp_early.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char/sclp_early.c')
-rw-r--r--drivers/s390/char/sclp_early.c97
1 files changed, 63 insertions, 34 deletions
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index e792cee3b51c..6bf501ad8ff0 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -5,13 +5,16 @@
* Copyright IBM Corp. 2013
*/
-#define KMSG_COMPONENT "sclp_early"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+#define pr_fmt(fmt) "sclp_early: " fmt
+#include <linux/export.h>
#include <linux/errno.h>
-#include <asm/ctl_reg.h>
+#include <linux/memblock.h>
+#include <asm/ctlreg.h>
#include <asm/sclp.h>
#include <asm/ipl.h>
+#include <asm/setup.h>
+#include <asm/facility.h>
#include "sclp_sdias.h"
#include "sclp.h"
@@ -20,12 +23,14 @@ static struct sclp_ipl_info sclp_ipl_info;
struct sclp_info sclp;
EXPORT_SYMBOL(sclp);
-static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
+static void __init sclp_early_facilities_detect(void)
{
struct sclp_core_entry *cpue;
+ struct read_info_sccb *sccb;
u16 boot_cpu_address, cpu;
- if (sclp_early_get_info(sccb))
+ sccb = sclp_early_get_info();
+ if (!sccb)
return;
sclp.facilities = sccb->facilities;
@@ -39,11 +44,25 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp.has_ibs = !!(sccb->fac117 & 0x20);
sclp.has_gisaf = !!(sccb->fac118 & 0x08);
sclp.has_hvs = !!(sccb->fac119 & 0x80);
+ sclp.has_wti = !!(sccb->fac119 & 0x40);
sclp.has_kss = !!(sccb->fac98 & 0x01);
- if (sccb->fac85 & 0x02)
- S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
- if (sccb->fac91 & 0x40)
- S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_GUEST;
+ sclp.has_aisii = !!(sccb->fac118 & 0x40);
+ sclp.has_aeni = !!(sccb->fac118 & 0x20);
+ sclp.has_aisi = !!(sccb->fac118 & 0x10);
+ sclp.has_zpci_lsi = !!(sccb->fac118 & 0x01);
+ sclp.has_diag204_bif = !!(sccb->fac98 & 0x80);
+ sclp.has_diag310 = !!(sccb->fac91 & 0x80);
+ if (sccb->cpuoff > 134) {
+ sclp.has_diag318 = !!(sccb->byte_134 & 0x80);
+ sclp.has_diag320 = !!(sccb->byte_134 & 0x04);
+ sclp.has_iplcc = !!(sccb->byte_134 & 0x02);
+ }
+ if (sccb->cpuoff > 137) {
+ sclp.has_sipl = !!(sccb->cbl & 0x4000);
+ sclp.has_sipl_eckd = !!(sccb->cbl & 0x2000);
+ }
+ if (sccb->cpuoff > 139)
+ sclp.has_diag324 = !!(sccb->byte_139 & 0x80);
sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
sclp.rzm <<= 20;
@@ -55,7 +74,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp.hamax = U64_MAX;
if (!sccb->hcpua) {
- if (MACHINE_IS_VM)
+ if (machine_is_vm())
sclp.max_cores = 64;
else
sclp.max_cores = sccb->ncpurl;
@@ -91,6 +110,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
sclp.hmfai = sccb->hmfai;
+ sclp.has_dirq = !!(sccb->cpudirq & 0x80);
}
/*
@@ -103,29 +123,34 @@ void __init sclp_early_get_ipl_info(struct sclp_ipl_info *info)
*info = sclp_ipl_info;
}
-static struct sclp_core_info sclp_early_core_info __initdata;
-static int sclp_early_core_info_valid __initdata;
-
-static void __init sclp_early_init_core_info(struct read_cpu_info_sccb *sccb)
-{
- if (!SCLP_HAS_CPU_INFO)
- return;
- memset(sccb, 0, sizeof(*sccb));
- sccb->header.length = sizeof(*sccb);
- if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO, sccb))
- return;
- if (sccb->header.response_code != 0x0010)
- return;
- sclp_fill_core_info(&sclp_early_core_info, sccb);
- sclp_early_core_info_valid = 1;
-}
-
int __init sclp_early_get_core_info(struct sclp_core_info *info)
{
- if (!sclp_early_core_info_valid)
- return -EIO;
- *info = sclp_early_core_info;
- return 0;
+ struct read_cpu_info_sccb *sccb;
+ int length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE;
+ int rc = 0;
+
+ if (!SCLP_HAS_CPU_INFO)
+ return -EOPNOTSUPP;
+
+ sccb = memblock_alloc_low(length, PAGE_SIZE);
+ if (!sccb)
+ return -ENOMEM;
+
+ memset(sccb, 0, length);
+ sccb->header.length = length;
+ sccb->header.control_mask[2] = 0x80;
+ if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO, sccb)) {
+ rc = -EIO;
+ goto out;
+ }
+ if (sccb->header.response_code != 0x0010) {
+ rc = -EIO;
+ goto out;
+ }
+ sclp_fill_core_info(info, sccb);
+out:
+ memblock_free(sccb, length);
+ return rc;
}
static void __init sclp_early_console_detect(struct init_sccb *sccb)
@@ -140,12 +165,16 @@ static void __init sclp_early_console_detect(struct init_sccb *sccb)
sclp.has_linemode = 1;
}
+void __init __no_sanitize_address sclp_early_adjust_va(void)
+{
+ sclp_early_sccb = __va((unsigned long)sclp_early_sccb);
+}
+
void __init sclp_early_detect(void)
{
- void *sccb = &sclp_early_sccb;
+ void *sccb = sclp_early_sccb;
- sclp_early_facilities_detect(sccb);
- sclp_early_init_core_info(sccb);
+ sclp_early_facilities_detect();
/*
* Turn off SCLP event notifications. Also save remote masks in the