linux/drivers/s390/char/sclp_early.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * SCLP early driver
   4 *
   5 * Copyright IBM Corp. 2013
   6 */
   7
   8#define KMSG_COMPONENT "sclp_early"
   9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  10
  11#include <linux/errno.h>
  12#include <asm/ctl_reg.h>
  13#include <asm/sclp.h>
  14#include <asm/ipl.h>
  15#include "sclp_sdias.h"
  16#include "sclp.h"
  17
  18#define SCLP_CMDW_READ_SCP_INFO         0x00020001
  19#define SCLP_CMDW_READ_SCP_INFO_FORCED  0x00120001
  20
  21struct read_info_sccb {
  22        struct  sccb_header header;     /* 0-7 */
  23        u16     rnmax;                  /* 8-9 */
  24        u8      rnsize;                 /* 10 */
  25        u8      _pad_11[16 - 11];       /* 11-15 */
  26        u16     ncpurl;                 /* 16-17 */
  27        u16     cpuoff;                 /* 18-19 */
  28        u8      _pad_20[24 - 20];       /* 20-23 */
  29        u8      loadparm[8];            /* 24-31 */
  30        u8      _pad_32[42 - 32];       /* 32-41 */
  31        u8      fac42;                  /* 42 */
  32        u8      fac43;                  /* 43 */
  33        u8      _pad_44[48 - 44];       /* 44-47 */
  34        u64     facilities;             /* 48-55 */
  35        u8      _pad_56[66 - 56];       /* 56-65 */
  36        u8      fac66;                  /* 66 */
  37        u8      _pad_67[76 - 67];       /* 67-83 */
  38        u32     ibc;                    /* 76-79 */
  39        u8      _pad80[84 - 80];        /* 80-83 */
  40        u8      fac84;                  /* 84 */
  41        u8      fac85;                  /* 85 */
  42        u8      _pad_86[91 - 86];       /* 86-90 */
  43        u8      fac91;                  /* 91 */
  44        u8      _pad_92[98 - 92];       /* 92-97 */
  45        u8      fac98;                  /* 98 */
  46        u8      hamaxpow;               /* 99 */
  47        u32     rnsize2;                /* 100-103 */
  48        u64     rnmax2;                 /* 104-111 */
  49        u8      _pad_112[116 - 112];    /* 112-115 */
  50        u8      fac116;                 /* 116 */
  51        u8      fac117;                 /* 117 */
  52        u8      fac118;                 /* 118 */
  53        u8      fac119;                 /* 119 */
  54        u16     hcpua;                  /* 120-121 */
  55        u8      _pad_122[124 - 122];    /* 122-123 */
  56        u32     hmfai;                  /* 124-127 */
  57        u8      _pad_128[4096 - 128];   /* 128-4095 */
  58} __packed __aligned(PAGE_SIZE);
  59
  60static struct sclp_ipl_info sclp_ipl_info;
  61
  62struct sclp_info sclp;
  63EXPORT_SYMBOL(sclp);
  64
  65static int __init sclp_early_read_info(struct read_info_sccb *sccb)
  66{
  67        int i;
  68        sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
  69                                  SCLP_CMDW_READ_SCP_INFO};
  70
  71        for (i = 0; i < ARRAY_SIZE(commands); i++) {
  72                memset(sccb, 0, sizeof(*sccb));
  73                sccb->header.length = sizeof(*sccb);
  74                sccb->header.function_code = 0x80;
  75                sccb->header.control_mask[2] = 0x80;
  76                if (sclp_early_cmd(commands[i], sccb))
  77                        break;
  78                if (sccb->header.response_code == 0x10)
  79                        return 0;
  80                if (sccb->header.response_code != 0x1f0)
  81                        break;
  82        }
  83        return -EIO;
  84}
  85
  86static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
  87{
  88        struct sclp_core_entry *cpue;
  89        u16 boot_cpu_address, cpu;
  90
  91        if (sclp_early_read_info(sccb))
  92                return;
  93
  94        sclp.facilities = sccb->facilities;
  95        sclp.has_sprp = !!(sccb->fac84 & 0x02);
  96        sclp.has_core_type = !!(sccb->fac84 & 0x01);
  97        sclp.has_gsls = !!(sccb->fac85 & 0x80);
  98        sclp.has_64bscao = !!(sccb->fac116 & 0x80);
  99        sclp.has_cmma = !!(sccb->fac116 & 0x40);
 100        sclp.has_esca = !!(sccb->fac116 & 0x08);
 101        sclp.has_pfmfi = !!(sccb->fac117 & 0x40);
 102        sclp.has_ibs = !!(sccb->fac117 & 0x20);
 103        sclp.has_gisaf = !!(sccb->fac118 & 0x08);
 104        sclp.has_hvs = !!(sccb->fac119 & 0x80);
 105        sclp.has_kss = !!(sccb->fac98 & 0x01);
 106        if (sccb->fac85 & 0x02)
 107                S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
 108        if (sccb->fac91 & 0x40)
 109                S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_GUEST;
 110        sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
 111        sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
 112        sclp.rzm <<= 20;
 113        sclp.ibc = sccb->ibc;
 114
 115        if (sccb->hamaxpow && sccb->hamaxpow < 64)
 116                sclp.hamax = (1UL << sccb->hamaxpow) - 1;
 117        else
 118                sclp.hamax = U64_MAX;
 119
 120        if (!sccb->hcpua) {
 121                if (MACHINE_IS_VM)
 122                        sclp.max_cores = 64;
 123                else
 124                        sclp.max_cores = sccb->ncpurl;
 125        } else {
 126                sclp.max_cores = sccb->hcpua + 1;
 127        }
 128
 129        boot_cpu_address = stap();
 130        cpue = (void *)sccb + sccb->cpuoff;
 131        for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
 132                if (boot_cpu_address != cpue->core_id)
 133                        continue;
 134                sclp.has_siif = cpue->siif;
 135                sclp.has_sigpif = cpue->sigpif;
 136                sclp.has_sief2 = cpue->sief2;
 137                sclp.has_gpere = cpue->gpere;
 138                sclp.has_ib = cpue->ib;
 139                sclp.has_cei = cpue->cei;
 140                sclp.has_skey = cpue->skey;
 141                break;
 142        }
 143
 144        /* Save IPL information */
 145        sclp_ipl_info.is_valid = 1;
 146        if (sccb->fac91 & 0x2)
 147                sclp_ipl_info.has_dump = 1;
 148        memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
 149
 150        sclp.mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
 151        sclp.mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
 152        sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
 153
 154        sclp.hmfai = sccb->hmfai;
 155}
 156
 157/*
 158 * This function will be called after sclp_early_facilities_detect(), which gets
 159 * called from early.c code. The sclp_early_facilities_detect() function retrieves
 160 * and saves the IPL information.
 161 */
 162void __init sclp_early_get_ipl_info(struct sclp_ipl_info *info)
 163{
 164        *info = sclp_ipl_info;
 165}
 166
 167static struct sclp_core_info sclp_early_core_info __initdata;
 168static int sclp_early_core_info_valid __initdata;
 169
 170static void __init sclp_early_init_core_info(struct read_cpu_info_sccb *sccb)
 171{
 172        if (!SCLP_HAS_CPU_INFO)
 173                return;
 174        memset(sccb, 0, sizeof(*sccb));
 175        sccb->header.length = sizeof(*sccb);
 176        if (sclp_early_cmd(SCLP_CMDW_READ_CPU_INFO, sccb))
 177                return;
 178        if (sccb->header.response_code != 0x0010)
 179                return;
 180        sclp_fill_core_info(&sclp_early_core_info, sccb);
 181        sclp_early_core_info_valid = 1;
 182}
 183
 184int __init sclp_early_get_core_info(struct sclp_core_info *info)
 185{
 186        if (!sclp_early_core_info_valid)
 187                return -EIO;
 188        *info = sclp_early_core_info;
 189        return 0;
 190}
 191
 192static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb)
 193{
 194        memset(sccb, 0, sizeof(*sccb));
 195        sccb->hdr.length = sizeof(*sccb);
 196        sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
 197        sccb->evbuf.hdr.type = EVTYP_SDIAS;
 198        sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
 199        sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
 200        sccb->evbuf.event_id = 4712;
 201        sccb->evbuf.dbs = 1;
 202        if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
 203                return -EIO;
 204        if (sccb->hdr.response_code != 0x20)
 205                return -EIO;
 206        if (sccb->evbuf.blk_cnt == 0)
 207                return 0;
 208        return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
 209}
 210
 211static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb)
 212{
 213        memset(sccb, 0, PAGE_SIZE);
 214        sccb->hdr.length = PAGE_SIZE;
 215        if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb))
 216                return -EIO;
 217        if ((sccb->hdr.response_code != 0x20) && (sccb->hdr.response_code != 0x220))
 218                return -EIO;
 219        if (sccb->evbuf.blk_cnt == 0)
 220                return 0;
 221        return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
 222}
 223
 224static void __init sclp_early_hsa_size_detect(void *sccb)
 225{
 226        unsigned long flags;
 227        long size = -EIO;
 228
 229        raw_local_irq_save(flags);
 230        if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK))
 231                goto out;
 232        size = sclp_early_hsa_size_init(sccb);
 233        /* First check for synchronous response (LPAR) */
 234        if (size)
 235                goto out_mask;
 236        if (!(S390_lowcore.ext_params & 1))
 237                sclp_early_wait_irq();
 238        size = sclp_early_hsa_copy_wait(sccb);
 239out_mask:
 240        sclp_early_set_event_mask(sccb, 0, 0);
 241out:
 242        raw_local_irq_restore(flags);
 243        if (size > 0)
 244                sclp.hsa_size = size;
 245}
 246
 247static void __init sclp_early_console_detect(struct init_sccb *sccb)
 248{
 249        if (sccb->header.response_code != 0x20)
 250                return;
 251
 252        if (sclp_early_con_check_vt220(sccb))
 253                sclp.has_vt220 = 1;
 254
 255        if (sclp_early_con_check_linemode(sccb))
 256                sclp.has_linemode = 1;
 257}
 258
 259void __init sclp_early_detect(void)
 260{
 261        void *sccb = &sclp_early_sccb;
 262
 263        sclp_early_facilities_detect(sccb);
 264        sclp_early_init_core_info(sccb);
 265        sclp_early_hsa_size_detect(sccb);
 266
 267        /*
 268         * Turn off SCLP event notifications.  Also save remote masks in the
 269         * sccb.  These are sufficient to detect sclp console capabilities.
 270         */
 271        sclp_early_set_event_mask(sccb, 0, 0);
 272        sclp_early_console_detect(sccb);
 273}
 274