cregit-Linux how code gets into the kernel

Release 4.14 arch/ia64/hp/common/aml_nfw.c

/*
 * 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 program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * 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); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas37100.00%1100.00%
Total37100.00%1100.00%


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]); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas113100.00%1100.00%
Total113100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas7898.73%150.00%
Lin Ming11.27%150.00%
Total79100.00%2100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas7898.73%150.00%
Lin Ming11.27%150.00%
Total79100.00%2100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas13799.28%150.00%
Lin Ming10.72%150.00%
Total138100.00%2100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas60100.00%1100.00%
Total60100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas56100.00%1100.00%
Total56100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas16100.00%1100.00%
Total16100.00%1100.00%


static int aml_nfw_remove(struct acpi_device *device) { return aml_nfw_remove_global_handler(); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas15100.00%1100.00%
Total15100.00%1100.00%

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

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas44100.00%1100.00%
Total44100.00%1100.00%


static void __exit aml_nfw_exit(void) { acpi_bus_unregister_driver(&acpi_aml_nfw_driver); aml_nfw_remove_global_handler(); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas18100.00%1100.00%
Total18100.00%1100.00%

module_init(aml_nfw_init); module_exit(aml_nfw_exit);

Overall Contributors

PersonTokensPropCommitsCommitProp
Björn Helgaas81499.39%125.00%
Lin Ming30.37%125.00%
Rusty Russell10.12%125.00%
Lv Zheng10.12%125.00%
Total819100.00%4100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.