in google/gsmi.c [888:1054]
static __init int gsmi_init(void)
{
unsigned long flags;
int ret;
ret = gsmi_system_valid();
if (ret)
return ret;
gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command;
#ifdef CONFIG_PM
ret = platform_driver_register(&gsmi_driver_info);
if (unlikely(ret)) {
printk(KERN_ERR "gsmi: unable to register platform driver\n");
return ret;
}
#endif
/* register device */
gsmi_dev.pdev = platform_device_register_full(&gsmi_dev_info);
if (IS_ERR(gsmi_dev.pdev)) {
printk(KERN_ERR "gsmi: unable to register platform device\n");
return PTR_ERR(gsmi_dev.pdev);
}
/* SMI access needs to be serialized */
spin_lock_init(&gsmi_dev.lock);
ret = -ENOMEM;
/*
* SLAB cache is created using SLAB_CACHE_DMA32 to ensure that the
* allocations for gsmi_buf come from the DMA32 memory zone. These
* buffers have nothing to do with DMA. They are required for
* communication with firmware executing in SMI mode which can only
* access the bottom 4GiB of physical memory. Since DMA32 memory zone
* guarantees allocation under the 4GiB boundary, this driver creates
* a SLAB cache with SLAB_CACHE_DMA32 flag.
*/
gsmi_dev.mem_pool = kmem_cache_create("gsmi", GSMI_BUF_SIZE,
GSMI_BUF_ALIGN,
SLAB_CACHE_DMA32, NULL);
if (!gsmi_dev.mem_pool)
goto out_err;
/*
* pre-allocate buffers because sometimes we are called when
* this is not feasible: oops, panic, die, mce, etc
*/
gsmi_dev.name_buf = gsmi_buf_alloc();
if (!gsmi_dev.name_buf) {
printk(KERN_ERR "gsmi: failed to allocate name buffer\n");
goto out_err;
}
gsmi_dev.data_buf = gsmi_buf_alloc();
if (!gsmi_dev.data_buf) {
printk(KERN_ERR "gsmi: failed to allocate data buffer\n");
goto out_err;
}
gsmi_dev.param_buf = gsmi_buf_alloc();
if (!gsmi_dev.param_buf) {
printk(KERN_ERR "gsmi: failed to allocate param buffer\n");
goto out_err;
}
/*
* Determine type of handshake used to serialize the SMI
* entry. See also gsmi_exec().
*
* There's a "behavior" present on some chipsets where writing the
* SMI trigger register in the southbridge doesn't result in an
* immediate SMI. Rather, the processor can execute "a few" more
* instructions before the SMI takes effect. To ensure synchronous
* behavior, implement a handshake between the kernel driver and the
* firmware handler to spin until released. This ioctl determines
* the type of handshake.
*
* NONE: The firmware handler does not implement any
* handshake. Either it doesn't need to, or it's legacy firmware
* that doesn't know it needs to and never will.
*
* CF: The firmware handler will clear the CF in the saved
* state before returning. The driver may set the CF and test for
* it to clear before proceeding.
*
* SPIN: The firmware handler does not implement any handshake
* but the driver should spin for a hundred or so microseconds
* to ensure the SMI has triggered.
*
* Finally, the handler will return -ENOSYS if
* GSMI_CMD_HANDSHAKE_TYPE is unimplemented, which implies
* HANDSHAKE_NONE.
*/
spin_lock_irqsave(&gsmi_dev.lock, flags);
gsmi_dev.handshake_type = GSMI_HANDSHAKE_SPIN;
gsmi_dev.handshake_type =
gsmi_exec(GSMI_CALLBACK, GSMI_CMD_HANDSHAKE_TYPE);
if (gsmi_dev.handshake_type == -ENOSYS)
gsmi_dev.handshake_type = GSMI_HANDSHAKE_NONE;
spin_unlock_irqrestore(&gsmi_dev.lock, flags);
/* Remove and clean up gsmi if the handshake could not complete. */
if (gsmi_dev.handshake_type == -ENXIO) {
printk(KERN_INFO "gsmi version " DRIVER_VERSION
" failed to load\n");
ret = -ENODEV;
goto out_err;
}
/* Register in the firmware directory */
ret = -ENOMEM;
gsmi_kobj = kobject_create_and_add("gsmi", firmware_kobj);
if (!gsmi_kobj) {
printk(KERN_INFO "gsmi: Failed to create firmware kobj\n");
goto out_err;
}
/* Setup eventlog access */
ret = sysfs_create_bin_file(gsmi_kobj, &eventlog_bin_attr);
if (ret) {
printk(KERN_INFO "gsmi: Failed to setup eventlog");
goto out_err;
}
/* Other attributes */
ret = sysfs_create_files(gsmi_kobj, gsmi_attrs);
if (ret) {
printk(KERN_INFO "gsmi: Failed to add attrs");
goto out_remove_bin_file;
}
#ifdef CONFIG_EFI
ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj);
if (ret) {
printk(KERN_INFO "gsmi: Failed to register efivars\n");
sysfs_remove_files(gsmi_kobj, gsmi_attrs);
goto out_remove_bin_file;
}
#endif
register_reboot_notifier(&gsmi_reboot_notifier);
register_die_notifier(&gsmi_die_notifier);
atomic_notifier_chain_register(&panic_notifier_list,
&gsmi_panic_notifier);
printk(KERN_INFO "gsmi version " DRIVER_VERSION " loaded\n");
return 0;
out_remove_bin_file:
sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr);
out_err:
kobject_put(gsmi_kobj);
gsmi_buf_free(gsmi_dev.param_buf);
gsmi_buf_free(gsmi_dev.data_buf);
gsmi_buf_free(gsmi_dev.name_buf);
kmem_cache_destroy(gsmi_dev.mem_pool);
platform_device_unregister(gsmi_dev.pdev);
pr_info("gsmi: failed to load: %d\n", ret);
#ifdef CONFIG_PM
platform_driver_unregister(&gsmi_driver_info);
#endif
return ret;
}