s390/sclp: provide extended sccb support
authorSumanth Korikkar <sumanthk@linux.ibm.com>
Wed, 11 Nov 2020 07:03:02 +0000 (01:03 -0600)
committerHeiko Carstens <hca@linux.ibm.com>
Wed, 18 Nov 2020 11:16:02 +0000 (12:16 +0100)
As the number of cpus increases, the sccb response can exceed 4k for
read cpu and read scp info sclp commands. Hence, all cpu info entries
cant be embedded within a sccb response

Solution:
To overcome this limitation, extended sccb facility is provided by sclp.

1. Check if the extended sccb facility is installed.
2. If extended sccb is installed, perform the read scp and read cpu
   command considering a max sccb length of three page size. This max
   length is based on factors like max cpus, sccb header.
3. If extended sccb is not installed, perform the read scp and read cpu
   sclp command considering a max sccb length of one page size.

Signed-off-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/sclp.h
arch/s390/include/asm/setup.h
drivers/s390/char/sclp.h
drivers/s390/char/sclp_cmd.c
drivers/s390/char/sclp_early.c
drivers/s390/char/sclp_early_core.c

index a7bdd12..5763769 100644 (file)
 #include <asm/cpu.h>
 
 #define SCLP_CHP_INFO_MASK_SIZE                32
-#define SCLP_MAX_CORES                 256
+#define EARLY_SCCB_SIZE                PAGE_SIZE
+#define SCLP_MAX_CORES         512
+/* 144 + 16 * SCLP_MAX_CORES + 2 * (SCLP_MAX_CORES - 1) */
+#define EXT_SCCB_READ_SCP      (3 * PAGE_SIZE)
+/* 24 + 16 * SCLP_MAX_CORES */
+#define EXT_SCCB_READ_CPU      (3 * PAGE_SIZE)
 
 struct sclp_chp_info {
        u8 recognized[SCLP_CHP_INFO_MASK_SIZE];
index bdb242a..1be6a06 100644 (file)
@@ -16,8 +16,6 @@
 #define EARLY_SCCB_OFFSET      0x11000
 #define HEAD_END               0x12000
 
-#define EARLY_SCCB_SIZE                PAGE_SIZE
-
 /*
  * Machine features detected in early.c
  */
index 448ed25..6de9199 100644 (file)
@@ -156,7 +156,11 @@ struct read_cpu_info_sccb {
        u16     offset_configured;
        u16     nr_standby;
        u16     offset_standby;
-       u8      reserved[4096 - 16];
+       /*
+        * Without ext sccb, struct size is PAGE_SIZE.
+        * With ext sccb, struct size is EXT_SCCB_READ_CPU.
+        */
+       u8      reserved[];
 } __attribute__((packed, aligned(PAGE_SIZE)));
 
 struct read_info_sccb {
@@ -199,7 +203,7 @@ struct read_info_sccb {
        u8      byte_134;                       /* 134 */
        u8      cpudirq;                /* 135 */
        u16     cbl;                    /* 136-137 */
-       u8      _pad_138[4096 - 138];   /* 138-4095 */
+       u8      _pad_138[EXT_SCCB_READ_SCP - 138];
 } __packed __aligned(PAGE_SIZE);
 
 struct read_storage_sccb {
index f6e97f0..7ebe898 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/page.h>
 #include <asm/sclp.h>
 #include <asm/numa.h>
+#include <asm/facility.h>
 
 #include "sclp.h"
 
@@ -87,14 +88,17 @@ out:
 int _sclp_get_core_info(struct sclp_core_info *info)
 {
        int rc;
+       int length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE;
        struct read_cpu_info_sccb *sccb;
 
        if (!SCLP_HAS_CPU_INFO)
                return -EOPNOTSUPP;
-       sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+
+       sccb = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA | __GFP_ZERO, get_order(length));
        if (!sccb)
                return -ENOMEM;
-       sccb->header.length = sizeof(*sccb);
+       sccb->header.length = length;
+       sccb->header.control_mask[2] = 0x80;
        rc = sclp_sync_request_timeout(SCLP_CMDW_READ_CPU_INFO, sccb,
                                       SCLP_QUEUE_INTERVAL);
        if (rc)
@@ -107,7 +111,7 @@ int _sclp_get_core_info(struct sclp_core_info *info)
        }
        sclp_fill_core_info(info, sccb);
 out:
-       free_page((unsigned long) sccb);
+       free_pages((unsigned long) sccb, get_order(length));
        return rc;
 }
 
index cc78b53..2f3515f 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/sclp.h>
 #include <asm/ipl.h>
 #include <asm/setup.h>
+#include <asm/facility.h>
 #include "sclp_sdias.h"
 #include "sclp.h"
 
@@ -114,7 +115,7 @@ void __init sclp_early_get_ipl_info(struct sclp_ipl_info *info)
 int __init sclp_early_get_core_info(struct sclp_core_info *info)
 {
        struct read_cpu_info_sccb *sccb;
-       int length = PAGE_SIZE;
+       int length = test_facility(140) ? EXT_SCCB_READ_CPU : PAGE_SIZE;
        int rc = 0;
 
        if (!SCLP_HAS_CPU_INFO)
index d4fb61c..ec9f8ad 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/irq.h>
 #include <asm/sections.h>
 #include <asm/mem_detect.h>
+#include <asm/facility.h>
 #include "sclp.h"
 #include "sclp_rw.h"
 
@@ -237,13 +238,14 @@ void sclp_early_printk(const char *str)
 int __init sclp_early_read_info(void)
 {
        int i;
+       int length = test_facility(140) ? EXT_SCCB_READ_SCP : PAGE_SIZE;
        struct read_info_sccb *sccb = &sclp_info_sccb;
        sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
                                  SCLP_CMDW_READ_SCP_INFO};
 
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
-               memset(sccb, 0, sizeof(*sccb));
-               sccb->header.length = sizeof(*sccb);
+               memset(sccb, 0, length);
+               sccb->header.length = length;
                sccb->header.function_code = 0x80;
                sccb->header.control_mask[2] = 0x80;
                if (sclp_early_cmd(commands[i], sccb))