Commit 7f594232 authored by Russ Anderson's avatar Russ Anderson Committed by Ingo Molnar
Browse files

x86: Add UV bios call infrastructure v4



Add the EFI callback function and associated wrapper code.
Initialize SAL system table entry info at boot time.

Signed-off-by: default avatarRuss Anderson <rja@sgi.com>
Signed-off-by: default avatarPaul Jackson <pj@sgi.com>
Acked-by: default avatarHuang Ying <ying.huang@intel.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent a50f70b1
Loading
Loading
Loading
Loading
+80 −21
Original line number Diff line number Diff line
/*
 * BIOS run time interface routines.
 *
 *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
@@ -16,33 +14,94 @@
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
 *  Copyright (c) Russ Anderson
 */

#include <linux/efi.h>
#include <asm/efi.h>
#include <linux/io.h>
#include <asm/uv/bios.h>

const char *
x86_bios_strerror(long status)
struct uv_systab uv_systab;

s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
{
	struct uv_systab *tab = &uv_systab;

	if (!tab->function)
		/*
		 * BIOS does not support UV systab
		 */
		return BIOS_STATUS_UNIMPLEMENTED;

	return efi_call6((void *)__va(tab->function),
					(u64)which, a1, a2, a3, a4, a5);
}

s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
					u64 a4, u64 a5)
{
	const char *str;
	switch (status) {
	case  0: str = "Call completed without error";	break;
	case -1: str = "Not implemented";		break;
	case -2: str = "Invalid argument";		break;
	case -3: str = "Call completed with error";	break;
	default: str = "Unknown BIOS status code";	break;
	unsigned long bios_flags;
	s64 ret;

	local_irq_save(bios_flags);
	ret = uv_bios_call(which, a1, a2, a3, a4, a5);
	local_irq_restore(bios_flags);

	return ret;
}
	return str;

s64 uv_bios_call_reentrant(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
					u64 a4, u64 a5)
{
	s64 ret;

	preempt_disable();
	ret = uv_bios_call(which, a1, a2, a3, a4, a5);
	preempt_enable();

	return ret;
}

long
x86_bios_freq_base(unsigned long which, unsigned long *ticks_per_second,
x86_bios_freq_base(unsigned long clock_type, unsigned long *ticks_per_second,
					unsigned long *drift_info)
{
	struct uv_bios_retval isrv;

	BIOS_CALL(isrv, BIOS_FREQ_BASE, which, 0, 0, 0, 0, 0, 0);
	*ticks_per_second = isrv.v0;
	*drift_info = isrv.v1;
	return isrv.status;
	return uv_bios_call(UV_BIOS_FREQ_BASE, clock_type,
				(u64)ticks_per_second, 0, 0, 0);
}
EXPORT_SYMBOL_GPL(x86_bios_freq_base);


#ifdef CONFIG_EFI
void uv_bios_init(void)
{
	struct uv_systab *tab;

	if ((efi.uv_systab == EFI_INVALID_TABLE_ADDR) ||
	    (efi.uv_systab == (unsigned long)NULL)) {
		printk(KERN_CRIT "No EFI UV System Table.\n");
		uv_systab.function = (unsigned long)NULL;
		return;
	}

	tab = (struct uv_systab *)ioremap(efi.uv_systab,
					sizeof(struct uv_systab));
	if (strncmp(tab->signature, "UVST", 4) != 0)
		printk(KERN_ERR "bad signature in UV system table!");

	/*
	 * Copy table to permanent spot for later use.
	 */
	memcpy(&uv_systab, tab, sizeof(struct uv_systab));
	iounmap(tab);

	printk(KERN_INFO "EFI UV System Table Revision %d\n", tab->revision);
}
#else	/* !CONFIG_EFI */

void uv_bios_init(void) { }
#endif
+1 −0
Original line number Diff line number Diff line
@@ -427,6 +427,7 @@ void __init uv_system_init(void)
	gnode_upper = (((unsigned long)node_id.s.node_id) &
		       ~((1 << n_val) - 1)) << m_val;

	uv_bios_init();
	uv_rtc_init();

	for_each_present_cpu(cpu) {
+13 −0
Original line number Diff line number Diff line
@@ -94,4 +94,17 @@ extern void efi_reserve_early(void);
extern void efi_call_phys_prelog(void);
extern void efi_call_phys_epilog(void);

#ifndef CONFIG_EFI
/*
 * IF EFI is not configured, have the EFI calls return -ENOSYS.
 */
#define efi_call0(_f)					(-ENOSYS)
#define efi_call1(_f, _a1)				(-ENOSYS)
#define efi_call2(_f, _a1, _a2)				(-ENOSYS)
#define efi_call3(_f, _a1, _a2, _a3)			(-ENOSYS)
#define efi_call4(_f, _a1, _a2, _a3, _a4)		(-ENOSYS)
#define efi_call5(_f, _a1, _a2, _a3, _a4, _a5)		(-ENOSYS)
#define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6)	(-ENOSYS)
#endif /* CONFIG_EFI */

#endif /* ASM_X86__EFI_H */
+41 −32
Original line number Diff line number Diff line
@@ -2,9 +2,7 @@
#define ASM_X86__UV__BIOS_H

/*
 * BIOS layer definitions.
 *
 *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
 * UV BIOS layer definitions.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
@@ -19,50 +17,61 @@
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
 *  Copyright (c) Russ Anderson
 */

#include <linux/rtc.h>

#define BIOS_FREQ_BASE			0x01000001
/*
 * Values for the BIOS calls.  It is passed as the first * argument in the
 * BIOS call.  Passing any other value in the first argument will result
 * in a BIOS_STATUS_UNIMPLEMENTED return status.
 */
enum uv_bios_cmd {
	UV_BIOS_COMMON,
	UV_BIOS_GET_SN_INFO,
	UV_BIOS_FREQ_BASE
};

/*
 * Status values returned from a BIOS call.
 */
enum {
	BIOS_FREQ_BASE_PLATFORM = 0,
	BIOS_FREQ_BASE_INTERVAL_TIMER = 1,
	BIOS_FREQ_BASE_REALTIME_CLOCK = 2
	BIOS_STATUS_SUCCESS		=  0,
	BIOS_STATUS_UNIMPLEMENTED	= -ENOSYS,
	BIOS_STATUS_EINVAL		= -EINVAL,
	BIOS_STATUS_UNAVAIL		= -EBUSY
};

# define BIOS_CALL(result, a0, a1, a2, a3, a4, a5, a6, a7)		\
	do {								\
		/* XXX - the real call goes here */			\
		result.status = BIOS_STATUS_UNIMPLEMENTED;		\
		isrv.v0 = 0;						\
		isrv.v1 = 0;						\
	} while (0)
/*
 * The UV system table describes specific firmware
 * capabilities available to the Linux kernel at runtime.
 */
struct uv_systab {
	char signature[4];	/* must be "UVST" */
	u32 revision;		/* distinguish different firmware revs */
	u64 function;		/* BIOS runtime callback function ptr */
};

enum {
	BIOS_STATUS_SUCCESS		=  0,
	BIOS_STATUS_UNIMPLEMENTED	= -1,
	BIOS_STATUS_EINVAL		= -2,
	BIOS_STATUS_ERROR		= -3
	BIOS_FREQ_BASE_PLATFORM = 0,
	BIOS_FREQ_BASE_INTERVAL_TIMER = 1,
	BIOS_FREQ_BASE_REALTIME_CLOCK = 2
};

struct uv_bios_retval {
/*
	 * A zero status value indicates call completed without error.
	 * A negative status value indicates reason of call failure.
	 * A positive status value indicates success but an
	 * informational value should be printed (e.g., "reboot for
	 * change to take effect").
 * bios calls have 6 parameters
 */
	s64 status;
	u64 v0;
	u64 v1;
	u64 v2;
};
extern s64 uv_bios_call(enum uv_bios_cmd, u64, u64, u64, u64, u64);
extern s64 uv_bios_call_irqsave(enum uv_bios_cmd, u64, u64, u64, u64, u64);
extern s64 uv_bios_call_reentrant(enum uv_bios_cmd, u64, u64, u64, u64, u64);

extern void uv_bios_init(void);

extern long
x86_bios_freq_base(unsigned long which, unsigned long *ticks_per_second,
		   unsigned long *drift_info);
extern const char *x86_bios_strerror(long status);

#endif /* ASM_X86__UV__BIOS_H */