linux/arch/ia64/kernel/esi.c
<<
>>
Prefs
   1/*
   2 * Extensible SAL Interface (ESI) support routines.
   3 *
   4 * Copyright (C) 2006 Hewlett-Packard Co
   5 *      Alex Williamson <alex.williamson@hp.com>
   6 */
   7#include <linux/kernel.h>
   8#include <linux/init.h>
   9#include <linux/module.h>
  10#include <linux/string.h>
  11
  12#include <asm/esi.h>
  13#include <asm/sal.h>
  14
  15MODULE_AUTHOR("Alex Williamson <alex.williamson@hp.com>");
  16MODULE_DESCRIPTION("Extensible SAL Interface (ESI) support");
  17MODULE_LICENSE("GPL");
  18
  19#define MODULE_NAME     "esi"
  20
  21#define ESI_TABLE_GUID                                  \
  22    EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3,          \
  23             0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
  24
  25enum esi_systab_entry_type {
  26        ESI_DESC_ENTRY_POINT = 0
  27};
  28
  29/*
  30 * Entry type:  Size:
  31 *      0       48
  32 */
  33#define ESI_DESC_SIZE(type)     "\060"[(unsigned) (type)]
  34
  35typedef struct ia64_esi_desc_entry_point {
  36        u8 type;
  37        u8 reserved1[15];
  38        u64 esi_proc;
  39        u64 gp;
  40        efi_guid_t guid;
  41} ia64_esi_desc_entry_point_t;
  42
  43struct pdesc {
  44        void *addr;
  45        void *gp;
  46};
  47
  48static struct ia64_sal_systab *esi_systab;
  49
  50static int __init esi_init (void)
  51{
  52        efi_config_table_t *config_tables;
  53        struct ia64_sal_systab *systab;
  54        unsigned long esi = 0;
  55        char *p;
  56        int i;
  57
  58        config_tables = __va(efi.systab->tables);
  59
  60        for (i = 0; i < (int) efi.systab->nr_tables; ++i) {
  61                if (efi_guidcmp(config_tables[i].guid, ESI_TABLE_GUID) == 0) {
  62                        esi = config_tables[i].table;
  63                        break;
  64                }
  65        }
  66
  67        if (!esi)
  68                return -ENODEV;
  69
  70        systab = __va(esi);
  71
  72        if (strncmp(systab->signature, "ESIT", 4) != 0) {
  73                printk(KERN_ERR "bad signature in ESI system table!");
  74                return -ENODEV;
  75        }
  76
  77        p = (char *) (systab + 1);
  78        for (i = 0; i < systab->entry_count; i++) {
  79                /*
  80                 * The first byte of each entry type contains the type
  81                 * descriptor.
  82                 */
  83                switch (*p) {
  84                      case ESI_DESC_ENTRY_POINT:
  85                        break;
  86                      default:
  87                        printk(KERN_WARNING "Unknown table type %d found in "
  88                               "ESI table, ignoring rest of table\n", *p);
  89                        return -ENODEV;
  90                }
  91
  92                p += ESI_DESC_SIZE(*p);
  93        }
  94
  95        esi_systab = systab;
  96        return 0;
  97}
  98
  99
 100int ia64_esi_call (efi_guid_t guid, struct ia64_sal_retval *isrvp,
 101                   enum esi_proc_type proc_type, u64 func,
 102                   u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6,
 103                   u64 arg7)
 104{
 105        struct ia64_fpreg fr[6];
 106        unsigned long flags = 0;
 107        int i;
 108        char *p;
 109
 110        if (!esi_systab)
 111                return -1;
 112
 113        p = (char *) (esi_systab + 1);
 114        for (i = 0; i < esi_systab->entry_count; i++) {
 115                if (*p == ESI_DESC_ENTRY_POINT) {
 116                        ia64_esi_desc_entry_point_t *esi = (void *)p;
 117                        if (!efi_guidcmp(guid, esi->guid)) {
 118                                ia64_sal_handler esi_proc;
 119                                struct pdesc pdesc;
 120
 121                                pdesc.addr = __va(esi->esi_proc);
 122                                pdesc.gp = __va(esi->gp);
 123
 124                                esi_proc = (ia64_sal_handler) &pdesc;
 125
 126                                ia64_save_scratch_fpregs(fr);
 127                                if (proc_type == ESI_PROC_SERIALIZED)
 128                                        spin_lock_irqsave(&sal_lock, flags);
 129                                else if (proc_type == ESI_PROC_MP_SAFE)
 130                                        local_irq_save(flags);
 131                                else
 132                                        preempt_disable();
 133                                *isrvp = (*esi_proc)(func, arg1, arg2, arg3,
 134                                                     arg4, arg5, arg6, arg7);
 135                                if (proc_type == ESI_PROC_SERIALIZED)
 136                                        spin_unlock_irqrestore(&sal_lock,
 137                                                               flags);
 138                                else if (proc_type == ESI_PROC_MP_SAFE)
 139                                        local_irq_restore(flags);
 140                                else
 141                                        preempt_enable();
 142                                ia64_load_scratch_fpregs(fr);
 143                                return 0;
 144                        }
 145                }
 146                p += ESI_DESC_SIZE(*p);
 147        }
 148        return -1;
 149}
 150EXPORT_SYMBOL_GPL(ia64_esi_call);
 151
 152int ia64_esi_call_phys (efi_guid_t guid, struct ia64_sal_retval *isrvp,
 153                        u64 func, u64 arg1, u64 arg2, u64 arg3, u64 arg4,
 154                        u64 arg5, u64 arg6, u64 arg7)
 155{
 156        struct ia64_fpreg fr[6];
 157        unsigned long flags;
 158        u64 esi_params[8];
 159        char *p;
 160        int i;
 161
 162        if (!esi_systab)
 163                return -1;
 164
 165        p = (char *) (esi_systab + 1);
 166        for (i = 0; i < esi_systab->entry_count; i++) {
 167                if (*p == ESI_DESC_ENTRY_POINT) {
 168                        ia64_esi_desc_entry_point_t *esi = (void *)p;
 169                        if (!efi_guidcmp(guid, esi->guid)) {
 170                                ia64_sal_handler esi_proc;
 171                                struct pdesc pdesc;
 172
 173                                pdesc.addr = (void *)esi->esi_proc;
 174                                pdesc.gp = (void *)esi->gp;
 175
 176                                esi_proc = (ia64_sal_handler) &pdesc;
 177
 178                                esi_params[0] = func;
 179                                esi_params[1] = arg1;
 180                                esi_params[2] = arg2;
 181                                esi_params[3] = arg3;
 182                                esi_params[4] = arg4;
 183                                esi_params[5] = arg5;
 184                                esi_params[6] = arg6;
 185                                esi_params[7] = arg7;
 186                                ia64_save_scratch_fpregs(fr);
 187                                spin_lock_irqsave(&sal_lock, flags);
 188                                *isrvp = esi_call_phys(esi_proc, esi_params);
 189                                spin_unlock_irqrestore(&sal_lock, flags);
 190                                ia64_load_scratch_fpregs(fr);
 191                                return 0;
 192                        }
 193                }
 194                p += ESI_DESC_SIZE(*p);
 195        }
 196        return -1;
 197}
 198EXPORT_SYMBOL_GPL(ia64_esi_call_phys);
 199
 200static void __exit esi_exit (void)
 201{
 202}
 203
 204module_init(esi_init);
 205module_exit(esi_exit);  /* makes module removable... */
 206