sclp_early.c 5.9 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * SCLP early driver
 *
 * Copyright IBM Corp. 2013
 */

#define KMSG_COMPONENT "sclp_early"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

10
#include <asm/ctl_reg.h>
11 12 13 14 15
#include <asm/sclp.h>
#include <asm/ipl.h>
#include "sclp_sdias.h"
#include "sclp.h"

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
#define SCLP_CMDW_READ_SCP_INFO		0x00020001
#define SCLP_CMDW_READ_SCP_INFO_FORCED	0x00120001

struct read_info_sccb {
	struct	sccb_header header;	/* 0-7 */
	u16	rnmax;			/* 8-9 */
	u8	rnsize;			/* 10 */
	u8	_reserved0[24 - 11];	/* 11-15 */
	u8	loadparm[8];		/* 24-31 */
	u8	_reserved1[48 - 32];	/* 32-47 */
	u64	facilities;		/* 48-55 */
	u8	_reserved2[84 - 56];	/* 56-83 */
	u8	fac84;			/* 84 */
	u8	fac85;			/* 85 */
	u8	_reserved3[91 - 86];	/* 86-90 */
	u8	flags;			/* 91 */
	u8	_reserved4[100 - 92];	/* 92-99 */
	u32	rnsize2;		/* 100-103 */
	u64	rnmax2;			/* 104-111 */
	u8	_reserved5[4096 - 112];	/* 112-4095 */
} __packed __aligned(PAGE_SIZE);

static __initdata struct read_info_sccb early_read_info_sccb;
39 40
static __initdata char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE);
static unsigned long sclp_hsa_size;
41
static struct sclp_ipl_info sclp_ipl_info;
42

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
u64 sclp_facilities;
u8 sclp_fac84;
unsigned long long sclp_rzm;
unsigned long long sclp_rnmax;

static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
{
	int rc;

	__ctl_set_bit(0, 9);
	rc = sclp_service_call(cmd, sccb);
	if (rc)
		goto out;
	__load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA |
			PSW_MASK_BA | PSW_MASK_EXT | PSW_MASK_WAIT);
	local_irq_disable();
out:
	/* Contents of the sccb might have changed. */
	barrier();
	__ctl_clear_bit(0, 9);
	return rc;
}

66
static int __init sclp_read_info_early(void)
67
{
68
	int rc, i;
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
	struct read_info_sccb *sccb;
	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
				  SCLP_CMDW_READ_SCP_INFO};

	sccb = &early_read_info_sccb;
	for (i = 0; i < ARRAY_SIZE(commands); i++) {
		do {
			memset(sccb, 0, sizeof(*sccb));
			sccb->header.length = sizeof(*sccb);
			sccb->header.function_code = 0x80;
			sccb->header.control_mask[2] = 0x80;
			rc = sclp_cmd_sync_early(commands[i], sccb);
		} while (rc == -EBUSY);

		if (rc)
			break;
85 86
		if (sccb->header.response_code == 0x10)
			return 0;
87 88 89
		if (sccb->header.response_code != 0x1f0)
			break;
	}
90
	return -EIO;
91 92
}

93
static void __init sclp_facilities_detect(void)
94 95 96
{
	struct read_info_sccb *sccb;

97
	if (sclp_read_info_early())
98 99 100 101 102 103 104 105 106 107
		return;

	sccb = &early_read_info_sccb;
	sclp_facilities = sccb->facilities;
	sclp_fac84 = sccb->fac84;
	if (sccb->fac85 & 0x02)
		S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
	sclp_rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
	sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
	sclp_rzm <<= 20;
108 109 110 111 112 113

	/* Save IPL information */
	sclp_ipl_info.is_valid = 1;
	if (sccb->flags & 0x2)
		sclp_ipl_info.has_dump = 1;
	memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
114 115 116 117
}

bool __init sclp_has_linemode(void)
{
118
	struct init_sccb *sccb = (void *) &sccb_early;
119 120 121 122 123 124 125 126 127 128 129 130

	if (sccb->header.response_code != 0x20)
		return 0;
	if (!(sccb->sclp_send_mask & (EVTYP_OPCMD_MASK | EVTYP_PMSGCMD_MASK)))
		return 0;
	if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
		return 0;
	return 1;
}

bool __init sclp_has_vt220(void)
{
131
	struct init_sccb *sccb = (void *) &sccb_early;
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151

	if (sccb->header.response_code != 0x20)
		return 0;
	if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK)
		return 1;
	return 0;
}

unsigned long long sclp_get_rnmax(void)
{
	return sclp_rnmax;
}

unsigned long long sclp_get_rzm(void)
{
	return sclp_rzm;
}

/*
 * This function will be called after sclp_facilities_detect(), which gets
152 153
 * called from early.c code. The sclp_facilities_detect() function retrieves
 * and saves the IPL information.
154 155 156
 */
void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
{
157
	*info = sclp_ipl_info;
158 159
}

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb)
{
	int rc;

	do {
		rc = sclp_cmd_sync_early(cmd, sccb);
	} while (rc == -EBUSY);

	if (rc)
		return -EIO;
	if (((struct sccb_header *) sccb)->response_code != 0x0020)
		return -EIO;
	return 0;
}

static void __init sccb_init_eq_size(struct sdias_sccb *sccb)
{
	memset(sccb, 0, sizeof(*sccb));

	sccb->hdr.length = sizeof(*sccb);
	sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
	sccb->evbuf.hdr.type = EVTYP_SDIAS;
	sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
	sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
	sccb->evbuf.event_id = 4712;
	sccb->evbuf.dbs = 1;
}

static int __init sclp_set_event_mask(unsigned long receive_mask,
				      unsigned long send_mask)
{
	struct init_sccb *sccb = (void *) &sccb_early;

	memset(sccb, 0, sizeof(*sccb));
	sccb->header.length = sizeof(*sccb);
	sccb->mask_length = sizeof(sccb_mask_t);
	sccb->receive_mask = receive_mask;
	sccb->send_mask = send_mask;
	return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
}

static long __init sclp_hsa_size_init(void)
{
	struct sdias_sccb *sccb = (void *) &sccb_early;

	sccb_init_eq_size(sccb);
	if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
		return -EIO;
	if (sccb->evbuf.blk_cnt != 0)
		return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
	return 0;
}

static long __init sclp_hsa_copy_wait(void)
{
	struct sccb_header *sccb = (void *) &sccb_early;

	memset(sccb, 0, PAGE_SIZE);
	sccb->length = PAGE_SIZE;
	if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb))
		return -EIO;
	return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE;
}

unsigned long sclp_get_hsa_size(void)
{
	return sclp_hsa_size;
}

229
static void __init sclp_hsa_size_detect(void)
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
{
	long size;

	/* First try synchronous interface (LPAR) */
	if (sclp_set_event_mask(0, 0x40000010))
		return;
	size = sclp_hsa_size_init();
	if (size < 0)
		return;
	if (size != 0)
		goto out;
	/* Then try asynchronous interface (z/VM) */
	if (sclp_set_event_mask(0x00000010, 0x40000010))
		return;
	size = sclp_hsa_size_init();
	if (size < 0)
		return;
	size = sclp_hsa_copy_wait();
	if (size < 0)
		return;
out:
	sclp_hsa_size = size;
}
253 254 255 256 257 258 259

void __init sclp_early_detect(void)
{
	sclp_facilities_detect();
	sclp_hsa_size_detect();
	sclp_set_event_mask(0, 0);
}