Skip to content

Commit

Permalink
x86: Add UV bios call infrastructure v4
Browse files Browse the repository at this point in the history
Add the EFI callback function and associated wrapper code.
Initialize SAL system table entry info at boot time.

Signed-off-by: Russ Anderson <rja@sgi.com>
Signed-off-by: Paul Jackson <pj@sgi.com>
Acked-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Russ Anderson authored and Ingo Molnar committed Oct 16, 2008
1 parent a50f70b commit 7f59423
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 53 deletions.
101 changes: 80 additions & 21 deletions arch/x86/kernel/bios_uv.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/*
* 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
Expand All @@ -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)
{
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;
}
return str;
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);
}

long
x86_bios_freq_base(unsigned long which, unsigned long *ticks_per_second,
unsigned long *drift_info)
s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
u64 a4, u64 a5)
{
struct uv_bios_retval isrv;
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;
}

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();

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

long
x86_bios_freq_base(unsigned long clock_type, unsigned long *ticks_per_second,
unsigned long *drift_info)
{
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 change: 1 addition & 0 deletions arch/x86/kernel/genx2apic_uv_x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
13 changes: 13 additions & 0 deletions include/asm-x86/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
73 changes: 41 additions & 32 deletions include/asm-x86/uv/bios.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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").
*/
s64 status;
u64 v0;
u64 v1;
u64 v2;
};
/*
* bios calls have 6 parameters
*/
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 */

0 comments on commit 7f59423

Please sign in to comment.