Pull esi-support into release branch
This commit is contained in:
Коммит
a4b47ab946
|
@ -429,6 +429,14 @@ config IA64_PALINFO
|
|||
config SGI_SN
|
||||
def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
|
||||
|
||||
config IA64_ESI
|
||||
bool "ESI (Extensible SAL Interface) support"
|
||||
help
|
||||
If you say Y here, support is built into the kernel to
|
||||
make ESI calls. ESI calls are used to support vendor-specific
|
||||
firmware extensions, such as the ability to inject memory-errors
|
||||
for test-purposes. If you're unsure, say N.
|
||||
|
||||
source "drivers/sn/Kconfig"
|
||||
|
||||
source "drivers/firmware/Kconfig"
|
||||
|
|
|
@ -32,6 +32,11 @@ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
|
|||
obj-$(CONFIG_AUDIT) += audit.o
|
||||
mca_recovery-y += mca_drv.o mca_drv_asm.o
|
||||
|
||||
obj-$(CONFIG_IA64_ESI) += esi.o
|
||||
ifneq ($(CONFIG_IA64_ESI),)
|
||||
obj-y += esi_stub.o # must be in kernel proper
|
||||
endif
|
||||
|
||||
# The gate DSO image is built using a special linker script.
|
||||
targets += gate.so gate-syms.o
|
||||
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Extensible SAL Interface (ESI) support routines.
|
||||
*
|
||||
* Copyright (C) 2006 Hewlett-Packard Co
|
||||
* Alex Williamson <alex.williamson@hp.com>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/esi.h>
|
||||
#include <asm/sal.h>
|
||||
|
||||
MODULE_AUTHOR("Alex Williamson <alex.williamson@hp.com>");
|
||||
MODULE_DESCRIPTION("Extensible SAL Interface (ESI) support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define MODULE_NAME "esi"
|
||||
|
||||
#define ESI_TABLE_GUID \
|
||||
EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3, \
|
||||
0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
|
||||
|
||||
enum esi_systab_entry_type {
|
||||
ESI_DESC_ENTRY_POINT = 0
|
||||
};
|
||||
|
||||
/*
|
||||
* Entry type: Size:
|
||||
* 0 48
|
||||
*/
|
||||
#define ESI_DESC_SIZE(type) "\060"[(unsigned) (type)]
|
||||
|
||||
typedef struct ia64_esi_desc_entry_point {
|
||||
u8 type;
|
||||
u8 reserved1[15];
|
||||
u64 esi_proc;
|
||||
u64 gp;
|
||||
efi_guid_t guid;
|
||||
} ia64_esi_desc_entry_point_t;
|
||||
|
||||
struct pdesc {
|
||||
void *addr;
|
||||
void *gp;
|
||||
};
|
||||
|
||||
static struct ia64_sal_systab *esi_systab;
|
||||
|
||||
static int __init esi_init (void)
|
||||
{
|
||||
efi_config_table_t *config_tables;
|
||||
struct ia64_sal_systab *systab;
|
||||
unsigned long esi = 0;
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
config_tables = __va(efi.systab->tables);
|
||||
|
||||
for (i = 0; i < (int) efi.systab->nr_tables; ++i) {
|
||||
if (efi_guidcmp(config_tables[i].guid, ESI_TABLE_GUID) == 0) {
|
||||
esi = config_tables[i].table;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!esi)
|
||||
return -ENODEV;;
|
||||
|
||||
systab = __va(esi);
|
||||
|
||||
if (strncmp(systab->signature, "ESIT", 4) != 0) {
|
||||
printk(KERN_ERR "bad signature in ESI system table!");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
p = (char *) (systab + 1);
|
||||
for (i = 0; i < systab->entry_count; i++) {
|
||||
/*
|
||||
* The first byte of each entry type contains the type
|
||||
* descriptor.
|
||||
*/
|
||||
switch (*p) {
|
||||
case ESI_DESC_ENTRY_POINT:
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "Unkown table type %d found in "
|
||||
"ESI table, ignoring rest of table\n", *p);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
p += ESI_DESC_SIZE(*p);
|
||||
}
|
||||
|
||||
esi_systab = systab;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ia64_esi_call (efi_guid_t guid, struct ia64_sal_retval *isrvp,
|
||||
enum esi_proc_type proc_type, u64 func,
|
||||
u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6,
|
||||
u64 arg7)
|
||||
{
|
||||
struct ia64_fpreg fr[6];
|
||||
unsigned long flags = 0;
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
if (!esi_systab)
|
||||
return -1;
|
||||
|
||||
p = (char *) (esi_systab + 1);
|
||||
for (i = 0; i < esi_systab->entry_count; i++) {
|
||||
if (*p == ESI_DESC_ENTRY_POINT) {
|
||||
ia64_esi_desc_entry_point_t *esi = (void *)p;
|
||||
if (!efi_guidcmp(guid, esi->guid)) {
|
||||
ia64_sal_handler esi_proc;
|
||||
struct pdesc pdesc;
|
||||
|
||||
pdesc.addr = __va(esi->esi_proc);
|
||||
pdesc.gp = __va(esi->gp);
|
||||
|
||||
esi_proc = (ia64_sal_handler) &pdesc;
|
||||
|
||||
ia64_save_scratch_fpregs(fr);
|
||||
if (proc_type == ESI_PROC_SERIALIZED)
|
||||
spin_lock_irqsave(&sal_lock, flags);
|
||||
else if (proc_type == ESI_PROC_MP_SAFE)
|
||||
local_irq_save(flags);
|
||||
else
|
||||
preempt_disable();
|
||||
*isrvp = (*esi_proc)(func, arg1, arg2, arg3,
|
||||
arg4, arg5, arg6, arg7);
|
||||
if (proc_type == ESI_PROC_SERIALIZED)
|
||||
spin_unlock_irqrestore(&sal_lock,
|
||||
flags);
|
||||
else if (proc_type == ESI_PROC_MP_SAFE)
|
||||
local_irq_restore(flags);
|
||||
else
|
||||
preempt_enable();
|
||||
ia64_load_scratch_fpregs(fr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
p += ESI_DESC_SIZE(*p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ia64_esi_call);
|
||||
|
||||
int ia64_esi_call_phys (efi_guid_t guid, struct ia64_sal_retval *isrvp,
|
||||
u64 func, u64 arg1, u64 arg2, u64 arg3, u64 arg4,
|
||||
u64 arg5, u64 arg6, u64 arg7)
|
||||
{
|
||||
struct ia64_fpreg fr[6];
|
||||
unsigned long flags;
|
||||
u64 esi_params[8];
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
if (!esi_systab)
|
||||
return -1;
|
||||
|
||||
p = (char *) (esi_systab + 1);
|
||||
for (i = 0; i < esi_systab->entry_count; i++) {
|
||||
if (*p == ESI_DESC_ENTRY_POINT) {
|
||||
ia64_esi_desc_entry_point_t *esi = (void *)p;
|
||||
if (!efi_guidcmp(guid, esi->guid)) {
|
||||
ia64_sal_handler esi_proc;
|
||||
struct pdesc pdesc;
|
||||
|
||||
pdesc.addr = (void *)esi->esi_proc;
|
||||
pdesc.gp = (void *)esi->gp;
|
||||
|
||||
esi_proc = (ia64_sal_handler) &pdesc;
|
||||
|
||||
esi_params[0] = func;
|
||||
esi_params[1] = arg1;
|
||||
esi_params[2] = arg2;
|
||||
esi_params[3] = arg3;
|
||||
esi_params[4] = arg4;
|
||||
esi_params[5] = arg5;
|
||||
esi_params[6] = arg6;
|
||||
esi_params[7] = arg7;
|
||||
ia64_save_scratch_fpregs(fr);
|
||||
spin_lock_irqsave(&sal_lock, flags);
|
||||
*isrvp = esi_call_phys(esi_proc, esi_params);
|
||||
spin_unlock_irqrestore(&sal_lock, flags);
|
||||
ia64_load_scratch_fpregs(fr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
p += ESI_DESC_SIZE(*p);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ia64_esi_call_phys);
|
||||
|
||||
static void __exit esi_exit (void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(esi_init);
|
||||
module_exit(esi_exit); /* makes module removable... */
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* ESI call stub.
|
||||
*
|
||||
* Copyright (C) 2005 Hewlett-Packard Co
|
||||
* Alex Williamson <alex.williamson@hp.com>
|
||||
*
|
||||
* Based on EFI call stub by David Mosberger. The stub is virtually
|
||||
* identical to the one for EFI phys-mode calls, except that ESI
|
||||
* calls may have up to 8 arguments, so they get passed to this routine
|
||||
* through memory.
|
||||
*
|
||||
* This stub allows us to make ESI calls in physical mode with interrupts
|
||||
* turned off. ESI calls may not support calling from virtual mode.
|
||||
*
|
||||
* Google for "Extensible SAL specification" for a document describing the
|
||||
* ESI standard.
|
||||
*/
|
||||
|
||||
/*
|
||||
* PSR settings as per SAL spec (Chapter 8 in the "IA-64 System
|
||||
* Abstraction Layer Specification", revision 2.6e). Note that
|
||||
* psr.dfl and psr.dfh MUST be cleared, despite what this manual says.
|
||||
* Otherwise, SAL dies whenever it's trying to do an IA-32 BIOS call
|
||||
* (the br.ia instruction fails unless psr.dfl and psr.dfh are
|
||||
* cleared). Fortunately, SAL promises not to touch the floating
|
||||
* point regs, so at least we don't have to save f2-f127.
|
||||
*/
|
||||
#define PSR_BITS_TO_CLEAR \
|
||||
(IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \
|
||||
IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
|
||||
IA64_PSR_DFL | IA64_PSR_DFH)
|
||||
|
||||
#define PSR_BITS_TO_SET \
|
||||
(IA64_PSR_BN)
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/asmmacro.h>
|
||||
|
||||
/*
|
||||
* Inputs:
|
||||
* in0 = address of function descriptor of ESI routine to call
|
||||
* in1 = address of array of ESI parameters
|
||||
*
|
||||
* Outputs:
|
||||
* r8 = result returned by called function
|
||||
*/
|
||||
GLOBAL_ENTRY(esi_call_phys)
|
||||
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
|
||||
alloc loc1=ar.pfs,2,7,8,0
|
||||
ld8 r2=[in0],8 // load ESI function's entry point
|
||||
mov loc0=rp
|
||||
.body
|
||||
;;
|
||||
ld8 out0=[in1],8 // ESI params loaded from array
|
||||
;; // passing all as inputs doesn't work
|
||||
ld8 out1=[in1],8
|
||||
;;
|
||||
ld8 out2=[in1],8
|
||||
;;
|
||||
ld8 out3=[in1],8
|
||||
;;
|
||||
ld8 out4=[in1],8
|
||||
;;
|
||||
ld8 out5=[in1],8
|
||||
;;
|
||||
ld8 out6=[in1],8
|
||||
;;
|
||||
ld8 out7=[in1]
|
||||
mov loc2=gp // save global pointer
|
||||
mov loc4=ar.rsc // save RSE configuration
|
||||
mov ar.rsc=0 // put RSE in enforced lazy, LE mode
|
||||
;;
|
||||
ld8 gp=[in0] // load ESI function's global pointer
|
||||
movl r16=PSR_BITS_TO_CLEAR
|
||||
mov loc3=psr // save processor status word
|
||||
movl r17=PSR_BITS_TO_SET
|
||||
;;
|
||||
or loc3=loc3,r17
|
||||
mov b6=r2
|
||||
;;
|
||||
andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared
|
||||
br.call.sptk.many rp=ia64_switch_mode_phys
|
||||
.ret0: mov loc5=r19 // old ar.bsp
|
||||
mov loc6=r20 // old sp
|
||||
br.call.sptk.many rp=b6 // call the ESI function
|
||||
.ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode
|
||||
mov r16=loc3 // save virtual mode psr
|
||||
mov r19=loc5 // save virtual mode bspstore
|
||||
mov r20=loc6 // save virtual mode sp
|
||||
br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
|
||||
.ret2: mov ar.rsc=loc4 // restore RSE configuration
|
||||
mov ar.pfs=loc1
|
||||
mov rp=loc0
|
||||
mov gp=loc2
|
||||
br.ret.sptk.many rp
|
||||
END(esi_call_phys)
|
|
@ -105,5 +105,9 @@ EXPORT_SYMBOL(ia64_spinlock_contention);
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_IA64_ESI) || defined(CONFIG_IA64_ESI_MODULE)
|
||||
extern void esi_call_phys (void);
|
||||
EXPORT_SYMBOL_GPL(esi_call_phys);
|
||||
#endif
|
||||
extern char ia64_ivt[];
|
||||
EXPORT_SYMBOL(ia64_ivt);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* ESI service calls.
|
||||
*
|
||||
* Copyright (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P.
|
||||
* Alex Williamson <alex.williamson@hp.com>
|
||||
*/
|
||||
#ifndef esi_h
|
||||
#define esi_h
|
||||
|
||||
#include <linux/efi.h>
|
||||
|
||||
#define ESI_QUERY 0x00000001
|
||||
#define ESI_OPEN_HANDLE 0x02000000
|
||||
#define ESI_CLOSE_HANDLE 0x02000001
|
||||
|
||||
enum esi_proc_type {
|
||||
ESI_PROC_SERIALIZED, /* calls need to be serialized */
|
||||
ESI_PROC_MP_SAFE, /* MP-safe, but not reentrant */
|
||||
ESI_PROC_REENTRANT /* MP-safe and reentrant */
|
||||
};
|
||||
|
||||
extern int ia64_esi_init (void);
|
||||
extern struct ia64_sal_retval esi_call_phys (void *, u64 *);
|
||||
extern int ia64_esi_call(efi_guid_t, struct ia64_sal_retval *,
|
||||
enum esi_proc_type,
|
||||
u64, u64, u64, u64, u64, u64, u64, u64);
|
||||
extern int ia64_esi_call_phys(efi_guid_t, struct ia64_sal_retval *, u64, u64,
|
||||
u64, u64, u64, u64, u64, u64);
|
||||
|
||||
#endif /* esi_h */
|
Загрузка…
Ссылка в новой задаче