diff options
Diffstat (limited to 'drivers/misc/mic/cosm/cosm_main.c')
| -rw-r--r-- | drivers/misc/mic/cosm/cosm_main.c | 382 | 
1 files changed, 0 insertions, 382 deletions
| diff --git a/drivers/misc/mic/cosm/cosm_main.c b/drivers/misc/mic/cosm/cosm_main.c deleted file mode 100644 index ebb0eac43754..000000000000 --- a/drivers/misc/mic/cosm/cosm_main.c +++ /dev/null @@ -1,382 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel MIC Platform Software Stack (MPSS) - * - * Copyright(c) 2015 Intel Corporation. - * - * Intel MIC Coprocessor State Management (COSM) Driver - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/idr.h> -#include <linux/slab.h> -#include <linux/cred.h> -#include "cosm_main.h" - -static const char cosm_driver_name[] = "mic"; - -/* COSM ID allocator */ -static struct ida g_cosm_ida; -/* Class of MIC devices for sysfs accessibility. */ -static struct class *g_cosm_class; -/* Number of MIC devices */ -static atomic_t g_num_dev; - -/** - * cosm_hw_reset - Issue a HW reset for the MIC device - * @cdev: pointer to cosm_device instance - * @force: force a MIC to reset even if it is already reset and ready - */ -static void cosm_hw_reset(struct cosm_device *cdev, bool force) -{ -	int i; - -#define MIC_RESET_TO (45) -	if (force && cdev->hw_ops->force_reset) -		cdev->hw_ops->force_reset(cdev); -	else -		cdev->hw_ops->reset(cdev); - -	for (i = 0; i < MIC_RESET_TO; i++) { -		if (cdev->hw_ops->ready(cdev)) { -			cosm_set_state(cdev, MIC_READY); -			return; -		} -		/* -		 * Resets typically take 10s of seconds to complete. -		 * Since an MMIO read is required to check if the -		 * firmware is ready or not, a 1 second delay works nicely. -		 */ -		msleep(1000); -	} -	cosm_set_state(cdev, MIC_RESET_FAILED); -} - -/** - * cosm_start - Start the MIC - * @cdev: pointer to cosm_device instance - * - * This function prepares an MIC for boot and initiates boot. - * RETURNS: An appropriate -ERRNO error value on error, or 0 for success. - */ -int cosm_start(struct cosm_device *cdev) -{ -	const struct cred *orig_cred; -	struct cred *override_cred; -	int rc; - -	mutex_lock(&cdev->cosm_mutex); -	if (!cdev->bootmode) { -		dev_err(&cdev->dev, "%s %d bootmode not set\n", -			__func__, __LINE__); -		rc = -EINVAL; -		goto unlock_ret; -	} -retry: -	if (cdev->state != MIC_READY) { -		dev_err(&cdev->dev, "%s %d MIC state not READY\n", -			__func__, __LINE__); -		rc = -EINVAL; -		goto unlock_ret; -	} -	if (!cdev->hw_ops->ready(cdev)) { -		cosm_hw_reset(cdev, false); -		/* -		 * The state will either be MIC_READY if the reset succeeded -		 * or MIC_RESET_FAILED if the firmware reset failed. -		 */ -		goto retry; -	} - -	/* -	 * Set credentials to root to allow non-root user to download initramsfs -	 * with 600 permissions -	 */ -	override_cred = prepare_creds(); -	if (!override_cred) { -		dev_err(&cdev->dev, "%s %d prepare_creds failed\n", -			__func__, __LINE__); -		rc = -ENOMEM; -		goto unlock_ret; -	} -	override_cred->fsuid = GLOBAL_ROOT_UID; -	orig_cred = override_creds(override_cred); - -	rc = cdev->hw_ops->start(cdev, cdev->index); - -	revert_creds(orig_cred); -	put_cred(override_cred); -	if (rc) -		goto unlock_ret; - -	/* -	 * If linux is being booted, card is treated 'online' only -	 * when the scif interface in the card is up. If anything else -	 * is booted, we set card to 'online' immediately. -	 */ -	if (!strcmp(cdev->bootmode, "linux")) -		cosm_set_state(cdev, MIC_BOOTING); -	else -		cosm_set_state(cdev, MIC_ONLINE); -unlock_ret: -	mutex_unlock(&cdev->cosm_mutex); -	if (rc) -		dev_err(&cdev->dev, "cosm_start failed rc %d\n", rc); -	return rc; -} - -/** - * cosm_stop - Prepare the MIC for reset and trigger reset - * @cdev: pointer to cosm_device instance - * @force: force a MIC to reset even if it is already reset and ready. - * - * RETURNS: None - */ -void cosm_stop(struct cosm_device *cdev, bool force) -{ -	mutex_lock(&cdev->cosm_mutex); -	if (cdev->state != MIC_READY || force) { -		/* -		 * Don't call hw_ops if they have been called previously. -		 * stop(..) calls device_unregister and will crash the system if -		 * called multiple times. -		 */ -		u8 state = cdev->state == MIC_RESETTING ? -					cdev->prev_state : cdev->state; -		bool call_hw_ops = state != MIC_RESET_FAILED && -					state != MIC_READY; - -		if (cdev->state != MIC_RESETTING) -			cosm_set_state(cdev, MIC_RESETTING); -		cdev->heartbeat_watchdog_enable = false; -		if (call_hw_ops) -			cdev->hw_ops->stop(cdev, force); -		cosm_hw_reset(cdev, force); -		cosm_set_shutdown_status(cdev, MIC_NOP); -		if (call_hw_ops && cdev->hw_ops->post_reset) -			cdev->hw_ops->post_reset(cdev, cdev->state); -	} -	mutex_unlock(&cdev->cosm_mutex); -	flush_work(&cdev->scif_work); -} - -/** - * cosm_reset_trigger_work - Trigger MIC reset - * @work: The work structure - * - * This work is scheduled whenever the host wants to reset the MIC. - */ -static void cosm_reset_trigger_work(struct work_struct *work) -{ -	struct cosm_device *cdev = container_of(work, struct cosm_device, -						reset_trigger_work); -	cosm_stop(cdev, false); -} - -/** - * cosm_reset - Schedule MIC reset - * @cdev: pointer to cosm_device instance - * - * RETURNS: An -EINVAL if the card is already READY or 0 for success. - */ -int cosm_reset(struct cosm_device *cdev) -{ -	int rc = 0; - -	mutex_lock(&cdev->cosm_mutex); -	if (cdev->state != MIC_READY) { -		if (cdev->state != MIC_RESETTING) { -			cdev->prev_state = cdev->state; -			cosm_set_state(cdev, MIC_RESETTING); -			schedule_work(&cdev->reset_trigger_work); -		} -	} else { -		dev_err(&cdev->dev, "%s %d MIC is READY\n", __func__, __LINE__); -		rc = -EINVAL; -	} -	mutex_unlock(&cdev->cosm_mutex); -	return rc; -} - -/** - * cosm_shutdown - Initiate MIC shutdown. - * @cdev: pointer to cosm_device instance - * - * RETURNS: None - */ -int cosm_shutdown(struct cosm_device *cdev) -{ -	struct cosm_msg msg = { .id = COSM_MSG_SHUTDOWN }; -	int rc = 0; - -	mutex_lock(&cdev->cosm_mutex); -	if (cdev->state != MIC_ONLINE) { -		rc = -EINVAL; -		dev_err(&cdev->dev, "%s %d skipping shutdown in state: %s\n", -			__func__, __LINE__, cosm_state_string[cdev->state]); -		goto err; -	} - -	if (!cdev->epd) { -		rc = -ENOTCONN; -		dev_err(&cdev->dev, "%s %d scif endpoint not connected rc %d\n", -			__func__, __LINE__, rc); -		goto err; -	} - -	rc = scif_send(cdev->epd, &msg, sizeof(msg), SCIF_SEND_BLOCK); -	if (rc < 0) { -		dev_err(&cdev->dev, "%s %d scif_send failed rc %d\n", -			__func__, __LINE__, rc); -		goto err; -	} -	cdev->heartbeat_watchdog_enable = false; -	cosm_set_state(cdev, MIC_SHUTTING_DOWN); -	rc = 0; -err: -	mutex_unlock(&cdev->cosm_mutex); -	return rc; -} - -static int cosm_driver_probe(struct cosm_device *cdev) -{ -	int rc; - -	/* Initialize SCIF server at first probe */ -	if (atomic_add_return(1, &g_num_dev) == 1) { -		rc = cosm_scif_init(); -		if (rc) -			goto scif_exit; -	} -	mutex_init(&cdev->cosm_mutex); -	INIT_WORK(&cdev->reset_trigger_work, cosm_reset_trigger_work); -	INIT_WORK(&cdev->scif_work, cosm_scif_work); -	cdev->sysfs_heartbeat_enable = true; -	cosm_sysfs_init(cdev); -	cdev->sdev = device_create_with_groups(g_cosm_class, cdev->dev.parent, -			       MKDEV(0, cdev->index), cdev, cdev->attr_group, -			       "mic%d", cdev->index); -	if (IS_ERR(cdev->sdev)) { -		rc = PTR_ERR(cdev->sdev); -		dev_err(&cdev->dev, "device_create_with_groups failed rc %d\n", -			rc); -		goto scif_exit; -	} - -	cdev->state_sysfs = sysfs_get_dirent(cdev->sdev->kobj.sd, -		"state"); -	if (!cdev->state_sysfs) { -		rc = -ENODEV; -		dev_err(&cdev->dev, "sysfs_get_dirent failed rc %d\n", rc); -		goto destroy_device; -	} -	cosm_create_debug_dir(cdev); -	return 0; -destroy_device: -	device_destroy(g_cosm_class, MKDEV(0, cdev->index)); -scif_exit: -	if (atomic_dec_and_test(&g_num_dev)) -		cosm_scif_exit(); -	return rc; -} - -static void cosm_driver_remove(struct cosm_device *cdev) -{ -	cosm_delete_debug_dir(cdev); -	sysfs_put(cdev->state_sysfs); -	device_destroy(g_cosm_class, MKDEV(0, cdev->index)); -	flush_work(&cdev->reset_trigger_work); -	cosm_stop(cdev, false); -	if (atomic_dec_and_test(&g_num_dev)) -		cosm_scif_exit(); - -	/* These sysfs entries might have allocated */ -	kfree(cdev->cmdline); -	kfree(cdev->firmware); -	kfree(cdev->ramdisk); -	kfree(cdev->bootmode); -} - -static int cosm_suspend(struct device *dev) -{ -	struct cosm_device *cdev = dev_to_cosm(dev); - -	mutex_lock(&cdev->cosm_mutex); -	switch (cdev->state) { -	/** -	 * Suspend/freeze hooks in userspace have already shutdown the card. -	 * Card should be 'ready' in most cases. It is however possible that -	 * some userspace application initiated a boot. In those cases, we -	 * simply reset the card. -	 */ -	case MIC_ONLINE: -	case MIC_BOOTING: -	case MIC_SHUTTING_DOWN: -		mutex_unlock(&cdev->cosm_mutex); -		cosm_stop(cdev, false); -		break; -	default: -		mutex_unlock(&cdev->cosm_mutex); -		break; -	} -	return 0; -} - -static const struct dev_pm_ops cosm_pm_ops = { -	.suspend = cosm_suspend, -	.freeze = cosm_suspend -}; - -static struct cosm_driver cosm_driver = { -	.driver = { -		.name =  KBUILD_MODNAME, -		.owner = THIS_MODULE, -		.pm = &cosm_pm_ops, -	}, -	.probe = cosm_driver_probe, -	.remove = cosm_driver_remove -}; - -static int __init cosm_init(void) -{ -	int ret; - -	cosm_init_debugfs(); - -	g_cosm_class = class_create(THIS_MODULE, cosm_driver_name); -	if (IS_ERR(g_cosm_class)) { -		ret = PTR_ERR(g_cosm_class); -		pr_err("class_create failed ret %d\n", ret); -		goto cleanup_debugfs; -	} - -	ida_init(&g_cosm_ida); -	ret = cosm_register_driver(&cosm_driver); -	if (ret) { -		pr_err("cosm_register_driver failed ret %d\n", ret); -		goto ida_destroy; -	} -	return 0; -ida_destroy: -	ida_destroy(&g_cosm_ida); -	class_destroy(g_cosm_class); -cleanup_debugfs: -	cosm_exit_debugfs(); -	return ret; -} - -static void __exit cosm_exit(void) -{ -	cosm_unregister_driver(&cosm_driver); -	ida_destroy(&g_cosm_ida); -	class_destroy(g_cosm_class); -	cosm_exit_debugfs(); -} - -module_init(cosm_init); -module_exit(cosm_exit); - -MODULE_AUTHOR("Intel Corporation"); -MODULE_DESCRIPTION("Intel(R) MIC Coprocessor State Management (COSM) Driver"); -MODULE_LICENSE("GPL v2"); |