/* * drivers/s390/char/sclp_info.c * * Copyright IBM Corp. 2007 * Author(s): Heiko Carstens */ #include #include #include #include #include "sclp.h" struct sclp_readinfo_sccb { struct sccb_header header; /* 0-7 */ u16 rnmax; /* 8-9 */ u8 rnsize; /* 10 */ u8 _reserved0[24 - 11]; /* 11-23 */ u8 loadparm[8]; /* 24-31 */ u8 _reserved1[48 - 32]; /* 32-47 */ u64 facilities; /* 48-55 */ u8 _reserved2[91 - 56]; /* 56-90 */ u8 flags; /* 91 */ u8 _reserved3[100 - 92]; /* 92-99 */ u32 rnsize2; /* 100-103 */ u64 rnmax2; /* 104-111 */ u8 _reserved4[4096 - 112]; /* 112-4095 */ } __attribute__((packed, aligned(4096))); static struct sclp_readinfo_sccb __initdata early_readinfo_sccb; static int __initdata early_readinfo_sccb_valid; u64 sclp_facilities; void __init sclp_readinfo_early(void) { int ret; int i; struct sclp_readinfo_sccb *sccb; sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, SCLP_CMDW_READ_SCP_INFO}; /* Enable service signal subclass mask. */ __ctl_set_bit(0, 9); sccb = &early_readinfo_sccb; for (i = 0; i < ARRAY_SIZE(commands); i++) { do { memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb); sccb->header.control_mask[2] = 0x80; ret = sclp_service_call(commands[i], sccb); } while (ret == -EBUSY); if (ret) break; __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | PSW_MASK_WAIT | PSW_DEFAULT_KEY); local_irq_disable(); /* * Contents of the sccb might have changed * therefore a barrier is needed. */ barrier(); if (sccb->header.response_code == 0x10) { early_readinfo_sccb_valid = 1; break; } if (sccb->header.response_code != 0x1f0) break; } /* Disable service signal subclass mask again. */ __ctl_clear_bit(0, 9); } void __init sclp_facilities_detect(void) { if (!early_readinfo_sccb_valid) return; sclp_facilities = early_readinfo_sccb.facilities; } unsigned long long __init sclp_memory_detect(void) { unsigned long long memsize; struct sclp_readinfo_sccb *sccb; if (!early_readinfo_sccb_valid) return 0; sccb = &early_readinfo_sccb; if (sccb->rnsize) memsize = sccb->rnsize << 20; else memsize = sccb->rnsize2 << 20; if (sccb->rnmax) memsize *= sccb->rnmax; else memsize *= sccb->rnmax2; return memsize; } /* * This function will be called after sclp_memory_detect(), which gets called * early from early.c code. Therefore the sccb should have valid contents. */ void __init sclp_get_ipl_info(struct sclp_ipl_info *info) { struct sclp_readinfo_sccb *sccb; if (!early_readinfo_sccb_valid) return; sccb = &early_readinfo_sccb; info->is_valid = 1; if (sccb->flags & 0x2) info->has_dump = 1; memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN); }