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