diff options
Diffstat (limited to 'arch/ia64/hp/common/aml_nfw.c')
-rw-r--r-- | arch/ia64/hp/common/aml_nfw.c | 232 |
1 files changed, 0 insertions, 232 deletions
diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c deleted file mode 100644 index 901df49461..0000000000 --- a/arch/ia64/hp/common/aml_nfw.c +++ /dev/null @@ -1,232 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * OpRegion handler to allow AML to call native firmware - * - * (c) Copyright 2007 Hewlett-Packard Development Company, L.P. - * Bjorn Helgaas <bjorn.helgaas@hp.com> - * - * This driver implements HP Open Source Review Board proposal 1842, - * which was approved on 9/20/2006. - * - * For technical documentation, see the HP SPPA Firmware EAS, Appendix F. - * - * ACPI does not define a mechanism for AML methods to call native firmware - * interfaces such as PAL or SAL. This OpRegion handler adds such a mechanism. - * After the handler is installed, an AML method can call native firmware by - * storing the arguments and firmware entry point to specific offsets in the - * OpRegion. When AML reads the "return value" offset from the OpRegion, this - * handler loads up the arguments, makes the firmware call, and returns the - * result. - */ - -#include <linux/module.h> -#include <linux/acpi.h> -#include <asm/sal.h> - -MODULE_AUTHOR("Bjorn Helgaas <bjorn.helgaas@hp.com>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ACPI opregion handler for native firmware calls"); - -static bool force_register; -module_param_named(force, force_register, bool, 0); -MODULE_PARM_DESC(force, "Install opregion handler even without HPQ5001 device"); - -#define AML_NFW_SPACE 0xA1 - -struct ia64_pdesc { - void *ip; - void *gp; -}; - -/* - * N.B. The layout of this structure is defined in the HP SPPA FW EAS, and - * the member offsets are embedded in AML methods. - */ -struct ia64_nfw_context { - u64 arg[8]; - struct ia64_sal_retval ret; - u64 ip; - u64 gp; - u64 pad[2]; -}; - -static void *virt_map(u64 address) -{ - if (address & (1UL << 63)) - return (void *) (__IA64_UNCACHED_OFFSET | address); - - return __va(address); -} - -static void aml_nfw_execute(struct ia64_nfw_context *c) -{ - struct ia64_pdesc virt_entry; - ia64_sal_handler entry; - - virt_entry.ip = virt_map(c->ip); - virt_entry.gp = virt_map(c->gp); - - entry = (ia64_sal_handler) &virt_entry; - - IA64_FW_CALL(entry, c->ret, - c->arg[0], c->arg[1], c->arg[2], c->arg[3], - c->arg[4], c->arg[5], c->arg[6], c->arg[7]); -} - -static void aml_nfw_read_arg(u8 *offset, u32 bit_width, u64 *value) -{ - switch (bit_width) { - case 8: - *value = *(u8 *)offset; - break; - case 16: - *value = *(u16 *)offset; - break; - case 32: - *value = *(u32 *)offset; - break; - case 64: - *value = *(u64 *)offset; - break; - } -} - -static void aml_nfw_write_arg(u8 *offset, u32 bit_width, u64 *value) -{ - switch (bit_width) { - case 8: - *(u8 *) offset = *value; - break; - case 16: - *(u16 *) offset = *value; - break; - case 32: - *(u32 *) offset = *value; - break; - case 64: - *(u64 *) offset = *value; - break; - } -} - -static acpi_status aml_nfw_handler(u32 function, acpi_physical_address address, - u32 bit_width, u64 *value, void *handler_context, - void *region_context) -{ - struct ia64_nfw_context *context = handler_context; - u8 *offset = (u8 *) context + address; - - if (bit_width != 8 && bit_width != 16 && - bit_width != 32 && bit_width != 64) - return AE_BAD_PARAMETER; - - if (address + (bit_width >> 3) > sizeof(struct ia64_nfw_context)) - return AE_BAD_PARAMETER; - - switch (function) { - case ACPI_READ: - if (address == offsetof(struct ia64_nfw_context, ret)) - aml_nfw_execute(context); - aml_nfw_read_arg(offset, bit_width, value); - break; - case ACPI_WRITE: - aml_nfw_write_arg(offset, bit_width, value); - break; - } - - return AE_OK; -} - -static struct ia64_nfw_context global_context; -static int global_handler_registered; - -static int aml_nfw_add_global_handler(void) -{ - acpi_status status; - - if (global_handler_registered) - return 0; - - status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, - AML_NFW_SPACE, aml_nfw_handler, NULL, &global_context); - if (ACPI_FAILURE(status)) - return -ENODEV; - - global_handler_registered = 1; - printk(KERN_INFO "Global 0x%02X opregion handler registered\n", - AML_NFW_SPACE); - return 0; -} - -static int aml_nfw_remove_global_handler(void) -{ - acpi_status status; - - if (!global_handler_registered) - return 0; - - status = acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, - AML_NFW_SPACE, aml_nfw_handler); - if (ACPI_FAILURE(status)) - return -ENODEV; - - global_handler_registered = 0; - printk(KERN_INFO "Global 0x%02X opregion handler removed\n", - AML_NFW_SPACE); - return 0; -} - -static int aml_nfw_add(struct acpi_device *device) -{ - /* - * We would normally allocate a new context structure and install - * the address space handler for the specific device we found. - * But the HP-UX implementation shares a single global context - * and always puts the handler at the root, so we'll do the same. - */ - return aml_nfw_add_global_handler(); -} - -static void aml_nfw_remove(struct acpi_device *device) -{ - aml_nfw_remove_global_handler(); -} - -static const struct acpi_device_id aml_nfw_ids[] = { - {"HPQ5001", 0}, - {"", 0} -}; - -static struct acpi_driver acpi_aml_nfw_driver = { - .name = "native firmware", - .ids = aml_nfw_ids, - .ops = { - .add = aml_nfw_add, - .remove = aml_nfw_remove, - }, -}; - -static int __init aml_nfw_init(void) -{ - int result; - - if (force_register) - aml_nfw_add_global_handler(); - - result = acpi_bus_register_driver(&acpi_aml_nfw_driver); - if (result < 0) { - aml_nfw_remove_global_handler(); - return result; - } - - return 0; -} - -static void __exit aml_nfw_exit(void) -{ - acpi_bus_unregister_driver(&acpi_aml_nfw_driver); - aml_nfw_remove_global_handler(); -} - -module_init(aml_nfw_init); -module_exit(aml_nfw_exit); |