static __init int gsmi_init()

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