Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit acf6a004 authored by Michael Holzheu's avatar Michael Holzheu Committed by Martin Schwidefsky
Browse files

s390/sclp: Move early code from sclp_cmd.c to sclp_early.c



The early SCLP driver code in sclp_cmd.c belongs to sclp_early.c
because it is independent from the 'normal' SCLP driver. So move
it to sclp_early.c

Reviewed-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent e657d8fe
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#ifndef __ASM_CTL_REG_H
#define __ASM_CTL_REG_H

#include <linux/bug.h>

#ifdef CONFIG_64BIT
# define __CTL_LOAD	"lctlg"
# define __CTL_STORE	"stctg"
+5 −1
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ struct init_sccb {
} __attribute__((packed));

extern u64 sclp_facilities;

#define SCLP_HAS_CHP_INFO	(sclp_facilities & 0x8000000000000000ULL)
#define SCLP_HAS_CHP_RECONFIG	(sclp_facilities & 0x2000000000000000ULL)
#define SCLP_HAS_CPU_INFO	(sclp_facilities & 0x0800000000000000ULL)
@@ -172,7 +173,6 @@ int sclp_deactivate(void);
int sclp_reactivate(void);
int sclp_service_call(sclp_cmdw_t command, void *sccb);
int sclp_sync_request(sclp_cmdw_t command, void *sccb);
int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb);

int sclp_sdias_init(void);
void sclp_sdias_exit(void);
@@ -180,6 +180,10 @@ void sclp_sdias_exit(void);
extern int sclp_console_pages;
extern int sclp_console_drop;
extern unsigned long sclp_console_full;
extern u8 sclp_fac84;
extern unsigned long long sclp_rzm;
extern unsigned long long sclp_rnmax;
extern __initdata int sclp_early_read_info_sccb_valid;

/* useful inlines */

+9 −171
Original line number Diff line number Diff line
@@ -28,168 +28,6 @@

#include "sclp.h"

#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 */
} __attribute__((packed, aligned(PAGE_SIZE)));

static struct init_sccb __initdata early_event_mask_sccb __aligned(PAGE_SIZE);
static struct read_info_sccb __initdata early_read_info_sccb;
static int __initdata early_read_info_sccb_valid;

u64 sclp_facilities;
static u8 sclp_fac84;
static unsigned long long rzm;
static unsigned long long rnmax;

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;
}

static void __init sclp_read_info_early(void)
{
	int rc;
	int i;
	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;
		if (sccb->header.response_code == 0x10) {
			early_read_info_sccb_valid = 1;
			break;
		}
		if (sccb->header.response_code != 0x1f0)
			break;
	}
}

static void __init sclp_event_mask_early(void)
{
	struct init_sccb *sccb = &early_event_mask_sccb;
	int rc;

	do {
		memset(sccb, 0, sizeof(*sccb));
		sccb->header.length = sizeof(*sccb);
		sccb->mask_length = sizeof(sccb_mask_t);
		rc = sclp_cmd_sync_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
	} while (rc == -EBUSY);
}

void __init sclp_facilities_detect(void)
{
	struct read_info_sccb *sccb;

	sclp_read_info_early();
	if (!early_read_info_sccb_valid)
		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;
	rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
	rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
	rzm <<= 20;

	sclp_event_mask_early();
}

bool __init sclp_has_linemode(void)
{
	struct init_sccb *sccb = &early_event_mask_sccb;

	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)
{
	struct init_sccb *sccb = &early_event_mask_sccb;

	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 rnmax;
}

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

/*
 * This function will be called after sclp_facilities_detect(), which gets
 * called from early.c code. Therefore the sccb should have valid contents.
 */
void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
{
	struct read_info_sccb *sccb;

	if (!early_read_info_sccb_valid)
		return;
	sccb = &early_read_info_sccb;
	info->is_valid = 1;
	if (sccb->flags & 0x2)
		info->has_dump = 1;
	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
}

static void sclp_sync_callback(struct sclp_req *req, void *data)
{
	struct completion *completion = data;
@@ -356,14 +194,14 @@ struct assign_storage_sccb {

int arch_get_memory_phys_device(unsigned long start_pfn)
{
	if (!rzm)
	if (!sclp_rzm)
		return 0;
	return PFN_PHYS(start_pfn) >> ilog2(rzm);
	return PFN_PHYS(start_pfn) >> ilog2(sclp_rzm);
}

static unsigned long long rn2addr(u16 rn)
{
	return (unsigned long long) (rn - 1) * rzm;
	return (unsigned long long) (rn - 1) * sclp_rzm;
}

static int do_assign_storage(sclp_cmdw_t cmd, u16 rn)
@@ -404,7 +242,7 @@ static int sclp_assign_storage(u16 rn)
	if (rc)
		return rc;
	start = rn2addr(rn);
	storage_key_init_range(start, start + rzm);
	storage_key_init_range(start, start + sclp_rzm);
	return 0;
}

@@ -462,7 +300,7 @@ static int sclp_mem_change_state(unsigned long start, unsigned long size,
		istart = rn2addr(incr->rn);
		if (start + size - 1 < istart)
			break;
		if (start > istart + rzm - 1)
		if (start > istart + sclp_rzm - 1)
			continue;
		if (online)
			rc |= sclp_assign_storage(incr->rn);
@@ -526,7 +364,7 @@ static void __init add_memory_merged(u16 rn)
	if (!first_rn)
		goto skip_add;
	start = rn2addr(first_rn);
	size = (unsigned long long ) num * rzm;
	size = (unsigned long long) num * sclp_rzm;
	if (start >= VMEM_MAX_PHYS)
		goto skip_add;
	if (start + size > VMEM_MAX_PHYS)
@@ -574,7 +412,7 @@ static void __init insert_increment(u16 rn, int standby, int assigned)
	}
	if (!assigned)
		new_incr->rn = last_rn + 1;
	if (new_incr->rn > rnmax) {
	if (new_incr->rn > sclp_rnmax) {
		kfree(new_incr);
		return;
	}
@@ -617,7 +455,7 @@ static int __init sclp_detect_standby_memory(void)

	if (OLDMEM_BASE) /* No standby memory in kdump mode */
		return 0;
	if (!early_read_info_sccb_valid)
	if (!sclp_early_read_info_sccb_valid)
		return 0;
	if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL)
		return 0;
@@ -661,7 +499,7 @@ static int __init sclp_detect_standby_memory(void)
	}
	if (rc || list_empty(&sclp_mem_list))
		goto out;
	for (i = 1; i <= rnmax - assigned; i++)
	for (i = 1; i <= sclp_rnmax - assigned; i++)
		insert_increment(0, 1, 0);
	rc = register_memory_notifier(&sclp_mem_nb);
	if (rc)
+162 −0
Original line number Diff line number Diff line
@@ -7,14 +7,176 @@
#define KMSG_COMPONENT "sclp_early"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <asm/ctl_reg.h>
#include <asm/sclp.h>
#include <asm/ipl.h>
#include "sclp_sdias.h"
#include "sclp.h"

#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 init_sccb early_event_mask_sccb __aligned(PAGE_SIZE);
static __initdata struct read_info_sccb early_read_info_sccb;
static __initdata char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE);
static unsigned long sclp_hsa_size;

__initdata int sclp_early_read_info_sccb_valid;
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;
}

static void __init sclp_read_info_early(void)
{
	int rc;
	int i;
	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;
		if (sccb->header.response_code == 0x10) {
			sclp_early_read_info_sccb_valid = 1;
			break;
		}
		if (sccb->header.response_code != 0x1f0)
			break;
	}
}

static void __init sclp_event_mask_early(void)
{
	struct init_sccb *sccb = &early_event_mask_sccb;
	int rc;

	do {
		memset(sccb, 0, sizeof(*sccb));
		sccb->header.length = sizeof(*sccb);
		sccb->mask_length = sizeof(sccb_mask_t);
		rc = sclp_cmd_sync_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
	} while (rc == -EBUSY);
}

void __init sclp_facilities_detect(void)
{
	struct read_info_sccb *sccb;

	sclp_read_info_early();
	if (!sclp_early_read_info_sccb_valid)
		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;

	sclp_event_mask_early();
}

bool __init sclp_has_linemode(void)
{
	struct init_sccb *sccb = &early_event_mask_sccb;

	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)
{
	struct init_sccb *sccb = &early_event_mask_sccb;

	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
 * called from early.c code. Therefore the sccb should have valid contents.
 */
void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
{
	struct read_info_sccb *sccb;

	if (!sclp_early_read_info_sccb_valid)
		return;
	sccb = &early_read_info_sccb;
	info->is_valid = 1;
	if (sccb->flags & 0x2)
		info->has_dump = 1;
	memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
}

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