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 a7bdd128d85b3e4ef475fa38337fda1190b1629a..5763769a39b65fddbd25af5d8ad5a9af00f2f2f7 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 bdb242a1544ebea726ffc3bc47d9ca4999cad635..1be6a064f3176b6c99e0b52d4844cec590544340 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 448ed25bf6b895a36994d100a281caf8da2245d5..6de919944a39ff89ba82210fca2f5ec9fa73f8a7 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 f6e97f0830f64c04306f6cd8d3ae23cbc960876d..7ebe89890a9be33dce02188a574e2529ae9dd01c 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 cc78b538acbf3ee66da41b5d623f9b9c93959a59..2f3515fa242a3dc18284bd2b321c7b76ae679ad6 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 d4fb61c10d7cec57b7a7c1a66b4133a98cab5efc..ec9f8ad5341c5b8af0b465f95ea897add5e6061d 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))