diff options
Diffstat (limited to 'target/linux/layerscape/patches-4.4/7197-staging-fsl-mc-Management-Complex-restool-driver.patch')
-rw-r--r-- | target/linux/layerscape/patches-4.4/7197-staging-fsl-mc-Management-Complex-restool-driver.patch | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.4/7197-staging-fsl-mc-Management-Complex-restool-driver.patch b/target/linux/layerscape/patches-4.4/7197-staging-fsl-mc-Management-Complex-restool-driver.patch new file mode 100644 index 0000000000..2a5e5df2be --- /dev/null +++ b/target/linux/layerscape/patches-4.4/7197-staging-fsl-mc-Management-Complex-restool-driver.patch @@ -0,0 +1,489 @@ +From fb4881d149742e4c5595aca8bf86c99d2ea155ad Mon Sep 17 00:00:00 2001 +From: Lijun Pan <Lijun.Pan@freescale.com> +Date: Mon, 8 Feb 2016 17:40:18 -0600 +Subject: [PATCH 197/226] staging: fsl-mc: Management Complex restool driver + +The kernel support for the restool (a user space resource management +tool) is a driver for the /dev/dprc.N device file. +Its purpose is to provide an ioctl interface, +which the restool uses to interact with the MC bus driver +and with the MC firmware. +We allocate a dpmcp at driver initialization, +and keep that dpmcp until driver exit. +We use that dpmcp by default. +If that dpmcp is in use, we create another portal at run time +and destroy the newly created portal after use. +The ioctl RESTOOL_SEND_MC_COMMAND sends user space command to fsl-mc +bus and utilizes the fsl-mc bus to communicate with MC firmware. +The ioctl RESTOOL_DPRC_SYNC request the mc-bus launch +objects scan under root dprc. +In order to support multiple root dprc, we utilize the bus notify +mechanism to scan fsl_mc_bus_type for the newly added root dprc. +After discovering the root dprc, it creates a miscdevice +/dev/dprc.N to associate with this root dprc. + +Signed-off-by: Lijun Pan <Lijun.Pan@freescale.com> +[Stuart: minor fix to resolve compile error] +Signed-off-by: Stuart Yoder <stuart.yoder@nxp.com> +--- + Documentation/ioctl/ioctl-number.txt | 1 + + drivers/staging/fsl-mc/bus/Kconfig | 7 +- + drivers/staging/fsl-mc/bus/Makefile | 3 + + drivers/staging/fsl-mc/bus/mc-ioctl.h | 22 ++ + drivers/staging/fsl-mc/bus/mc-restool.c | 392 +++++++++++++++++++++++++++++++ + 5 files changed, 424 insertions(+), 1 deletion(-) + create mode 100644 drivers/staging/fsl-mc/bus/mc-ioctl.h + create mode 100644 drivers/staging/fsl-mc/bus/mc-restool.c + +--- a/Documentation/ioctl/ioctl-number.txt ++++ b/Documentation/ioctl/ioctl-number.txt +@@ -170,6 +170,7 @@ Code Seq#(hex) Include File Comments + 'R' 00-1F linux/random.h conflict! + 'R' 01 linux/rfkill.h conflict! + 'R' C0-DF net/bluetooth/rfcomm.h ++'R' E0-EF drivers/staging/fsl-mc/bus/mc-ioctl.h + 'S' all linux/cdrom.h conflict! + 'S' 80-81 scsi/scsi_ioctl.h conflict! + 'S' 82-FF scsi/scsi.h conflict! +--- a/drivers/staging/fsl-mc/bus/Kconfig ++++ b/drivers/staging/fsl-mc/bus/Kconfig +@@ -22,4 +22,9 @@ config FSL_MC_BUS + Only enable this option when building the kernel for + Freescale QorQIQ LS2xxxx SoCs. + +- ++config FSL_MC_RESTOOL ++ tristate "Freescale Management Complex (MC) restool driver" ++ depends on FSL_MC_BUS ++ help ++ Driver that provides kernel support for the Freescale Management ++ Complex resource manager user-space tool. +--- a/drivers/staging/fsl-mc/bus/Makefile ++++ b/drivers/staging/fsl-mc/bus/Makefile +@@ -18,3 +18,6 @@ mc-bus-driver-objs := mc-bus.o \ + dpmcp.o \ + dpbp.o \ + dpcon.o ++ ++# MC restool kernel support ++obj-$(CONFIG_FSL_MC_RESTOOL) += mc-restool.o +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/mc-ioctl.h +@@ -0,0 +1,22 @@ ++/* ++ * Freescale Management Complex (MC) ioclt interface ++ * ++ * Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * Author: Lijun Pan <Lijun.Pan@freescale.com> ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++#ifndef _FSL_MC_IOCTL_H_ ++#define _FSL_MC_IOCTL_H_ ++ ++#include <linux/ioctl.h> ++#include "../include/mc-sys.h" ++ ++#define RESTOOL_IOCTL_TYPE 'R' ++ ++#define RESTOOL_SEND_MC_COMMAND \ ++ _IOWR(RESTOOL_IOCTL_TYPE, 0xE0, struct mc_command) ++ ++#endif /* _FSL_MC_IOCTL_H_ */ +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/mc-restool.c +@@ -0,0 +1,392 @@ ++/* ++ * Freescale Management Complex (MC) restool driver ++ * ++ * Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * Author: Lijun Pan <Lijun.Pan@freescale.com> ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include "../include/mc-private.h" ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/uaccess.h> ++#include <linux/mutex.h> ++#include <linux/platform_device.h> ++#include "mc-ioctl.h" ++#include "../include/mc-sys.h" ++#include "../include/mc-cmd.h" ++#include "../include/dpmng.h" ++ ++/** ++ * Maximum number of DPRCs that can be opened at the same time ++ */ ++#define MAX_DPRC_HANDLES 64 ++ ++/** ++ * restool_misc - information associated with the newly added miscdevice ++ * @misc: newly created miscdevice associated with root dprc ++ * @miscdevt: device id of this miscdevice ++ * @list: a linked list node representing this miscdevcie ++ * @static_mc_io: pointer to the static MC I/O object used by the restool ++ * @dynamic_instance_count: number of dynamically created instances ++ * @static_instance_in_use: static instance is in use or not ++ * @mutex: mutex lock to serialze the open/release operations ++ * @dev: root dprc associated with this miscdevice ++ */ ++struct restool_misc { ++ struct miscdevice misc; ++ dev_t miscdevt; ++ struct list_head list; ++ struct fsl_mc_io *static_mc_io; ++ u32 dynamic_instance_count; ++ bool static_instance_in_use; ++ struct mutex mutex; /* serialze the open/release operations */ ++ struct device *dev; ++}; ++ ++/* ++ * initialize a global list to link all ++ * the miscdevice nodes (struct restool_misc) ++ */ ++static LIST_HEAD(misc_list); ++static DEFINE_MUTEX(misc_list_mutex); ++ ++static int fsl_mc_restool_dev_open(struct inode *inode, struct file *filep) ++{ ++ struct fsl_mc_device *root_mc_dev; ++ int error; ++ struct fsl_mc_io *dynamic_mc_io = NULL; ++ struct restool_misc *restool_misc = NULL; ++ struct restool_misc *restool_misc_cursor; ++ ++ mutex_lock(&misc_list_mutex); ++ ++ list_for_each_entry(restool_misc_cursor, &misc_list, list) { ++ if (restool_misc_cursor->miscdevt == inode->i_rdev) { ++ restool_misc = restool_misc_cursor; ++ break; ++ } ++ } ++ ++ mutex_unlock(&misc_list_mutex); ++ ++ if (!restool_misc) ++ return -EINVAL; ++ ++ if (WARN_ON(!restool_misc->dev)) ++ return -EINVAL; ++ ++ mutex_lock(&restool_misc->mutex); ++ ++ if (!restool_misc->static_instance_in_use) { ++ restool_misc->static_instance_in_use = true; ++ filep->private_data = restool_misc->static_mc_io; ++ } else { ++ dynamic_mc_io = kzalloc(sizeof(*dynamic_mc_io), GFP_KERNEL); ++ if (!dynamic_mc_io) { ++ error = -ENOMEM; ++ goto err_unlock; ++ } ++ ++ root_mc_dev = to_fsl_mc_device(restool_misc->dev); ++ error = fsl_mc_portal_allocate(root_mc_dev, 0, &dynamic_mc_io); ++ if (error < 0) { ++ pr_err("Not able to allocate MC portal\n"); ++ goto free_dynamic_mc_io; ++ } ++ ++restool_misc->dynamic_instance_count; ++ filep->private_data = dynamic_mc_io; ++ } ++ ++ mutex_unlock(&restool_misc->mutex); ++ ++ return 0; ++ ++free_dynamic_mc_io: ++ kfree(dynamic_mc_io); ++err_unlock: ++ mutex_unlock(&restool_misc->mutex); ++ ++ return error; ++} ++ ++static int fsl_mc_restool_dev_release(struct inode *inode, struct file *filep) ++{ ++ struct fsl_mc_io *local_mc_io = filep->private_data; ++ struct restool_misc *restool_misc = NULL; ++ struct restool_misc *restool_misc_cursor; ++ ++ if (WARN_ON(!filep->private_data)) ++ return -EINVAL; ++ ++ mutex_lock(&misc_list_mutex); ++ ++ list_for_each_entry(restool_misc_cursor, &misc_list, list) { ++ if (restool_misc_cursor->miscdevt == inode->i_rdev) { ++ restool_misc = restool_misc_cursor; ++ break; ++ } ++ } ++ ++ mutex_unlock(&misc_list_mutex); ++ ++ if (!restool_misc) ++ return -EINVAL; ++ ++ mutex_lock(&restool_misc->mutex); ++ ++ if (WARN_ON(restool_misc->dynamic_instance_count == 0 && ++ !restool_misc->static_instance_in_use)) { ++ mutex_unlock(&restool_misc->mutex); ++ return -EINVAL; ++ } ++ ++ /* Globally clean up opened/untracked handles */ ++ fsl_mc_portal_reset(local_mc_io); ++ ++ /* ++ * must check ++ * whether local_mc_io is dynamic or static instance ++ * Otherwise it will free up the reserved portal by accident ++ * or even not free up the dynamic allocated portal ++ * if 2 or more instances running concurrently ++ */ ++ if (local_mc_io == restool_misc->static_mc_io) { ++ restool_misc->static_instance_in_use = false; ++ } else { ++ fsl_mc_portal_free(local_mc_io); ++ kfree(filep->private_data); ++ --restool_misc->dynamic_instance_count; ++ } ++ ++ filep->private_data = NULL; ++ mutex_unlock(&restool_misc->mutex); ++ ++ return 0; ++} ++ ++static int restool_send_mc_command(unsigned long arg, ++ struct fsl_mc_io *local_mc_io) ++{ ++ int error; ++ struct mc_command mc_cmd; ++ ++ if (copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd))) ++ return -EFAULT; ++ ++ /* ++ * Send MC command to the MC: ++ */ ++ error = mc_send_command(local_mc_io, &mc_cmd); ++ if (error < 0) ++ return error; ++ ++ if (copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static long ++fsl_mc_restool_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int error; ++ ++ switch (cmd) { ++ case RESTOOL_SEND_MC_COMMAND: ++ error = restool_send_mc_command(arg, file->private_data); ++ break; ++ default: ++ pr_err("%s: unexpected ioctl call number\n", __func__); ++ error = -EINVAL; ++ } ++ ++ return error; ++} ++ ++static const struct file_operations fsl_mc_restool_dev_fops = { ++ .owner = THIS_MODULE, ++ .open = fsl_mc_restool_dev_open, ++ .release = fsl_mc_restool_dev_release, ++ .unlocked_ioctl = fsl_mc_restool_dev_ioctl, ++}; ++ ++static int restool_add_device_file(struct device *dev) ++{ ++ u32 name1 = 0; ++ char name2[20] = {0}; ++ int error; ++ struct fsl_mc_device *root_mc_dev; ++ struct restool_misc *restool_misc; ++ ++ if (dev->bus == &platform_bus_type && dev->driver_data) { ++ if (sscanf(dev_name(dev), "%x.%s", &name1, name2) != 2) ++ return -EINVAL; ++ ++ if (strcmp(name2, "fsl-mc") == 0) ++ pr_debug("platform's root dprc name is: %s\n", ++ dev_name(&(((struct fsl_mc *) ++ (dev->driver_data))->root_mc_bus_dev->dev))); ++ } ++ ++ if (!fsl_mc_is_root_dprc(dev)) ++ return 0; ++ ++ restool_misc = kzalloc(sizeof(*restool_misc), GFP_KERNEL); ++ if (!restool_misc) ++ return -ENOMEM; ++ ++ restool_misc->dev = dev; ++ root_mc_dev = to_fsl_mc_device(dev); ++ error = fsl_mc_portal_allocate(root_mc_dev, 0, ++ &restool_misc->static_mc_io); ++ if (error < 0) { ++ pr_err("Not able to allocate MC portal\n"); ++ goto free_restool_misc; ++ } ++ ++ restool_misc->misc.minor = MISC_DYNAMIC_MINOR; ++ restool_misc->misc.name = dev_name(dev); ++ restool_misc->misc.fops = &fsl_mc_restool_dev_fops; ++ ++ error = misc_register(&restool_misc->misc); ++ if (error < 0) { ++ pr_err("misc_register() failed: %d\n", error); ++ goto free_portal; ++ } ++ ++ restool_misc->miscdevt = restool_misc->misc.this_device->devt; ++ mutex_init(&restool_misc->mutex); ++ mutex_lock(&misc_list_mutex); ++ list_add(&restool_misc->list, &misc_list); ++ mutex_unlock(&misc_list_mutex); ++ ++ pr_info("/dev/%s driver registered\n", dev_name(dev)); ++ ++ return 0; ++ ++free_portal: ++ fsl_mc_portal_free(restool_misc->static_mc_io); ++free_restool_misc: ++ kfree(restool_misc); ++ ++ return error; ++} ++ ++static int restool_bus_notifier(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ int error; ++ struct device *dev = data; ++ ++ switch (action) { ++ case BUS_NOTIFY_ADD_DEVICE: ++ error = restool_add_device_file(dev); ++ if (error) ++ return error; ++ break; ++ case BUS_NOTIFY_DEL_DEVICE: ++ case BUS_NOTIFY_REMOVED_DEVICE: ++ case BUS_NOTIFY_BIND_DRIVER: ++ case BUS_NOTIFY_BOUND_DRIVER: ++ case BUS_NOTIFY_UNBIND_DRIVER: ++ case BUS_NOTIFY_UNBOUND_DRIVER: ++ break; ++ default: ++ pr_err("%s: unrecognized device action from %s\n", __func__, ++ dev_name(dev)); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int add_to_restool(struct device *dev, void *data) ++{ ++ return restool_add_device_file(dev); ++} ++ ++static int __init fsl_mc_restool_driver_init(void) ++{ ++ int error; ++ struct notifier_block *nb; ++ ++ nb = kzalloc(sizeof(*nb), GFP_KERNEL); ++ if (!nb) ++ return -ENOMEM; ++ ++ nb->notifier_call = restool_bus_notifier; ++ error = bus_register_notifier(&fsl_mc_bus_type, nb); ++ if (error) ++ goto free_nb; ++ ++ /* ++ * This driver runs after fsl-mc bus driver runs. ++ * Hence, many of the root dprcs are already attached to fsl-mc bus ++ * In order to make sure we find all the root dprcs, ++ * we need to scan the fsl_mc_bus_type. ++ */ ++ error = bus_for_each_dev(&fsl_mc_bus_type, NULL, NULL, add_to_restool); ++ if (error) { ++ bus_unregister_notifier(&fsl_mc_bus_type, nb); ++ kfree(nb); ++ pr_err("restool driver registration failure\n"); ++ return error; ++ } ++ ++ return 0; ++ ++free_nb: ++ kfree(nb); ++ return error; ++} ++ ++module_init(fsl_mc_restool_driver_init); ++ ++static void __exit fsl_mc_restool_driver_exit(void) ++{ ++ struct restool_misc *restool_misc; ++ struct restool_misc *restool_misc_tmp; ++ char name1[20] = {0}; ++ u32 name2 = 0; ++ ++ list_for_each_entry_safe(restool_misc, restool_misc_tmp, ++ &misc_list, list) { ++ if (sscanf(restool_misc->misc.name, "%4s.%u", name1, &name2) ++ != 2) ++ continue; ++ ++ pr_debug("name1=%s,name2=%u\n", name1, name2); ++ pr_debug("misc-device: %s\n", restool_misc->misc.name); ++ if (strcmp(name1, "dprc") != 0) ++ continue; ++ ++ if (WARN_ON(!restool_misc->static_mc_io)) ++ return; ++ ++ if (WARN_ON(restool_misc->dynamic_instance_count != 0)) ++ return; ++ ++ if (WARN_ON(restool_misc->static_instance_in_use)) ++ return; ++ ++ misc_deregister(&restool_misc->misc); ++ pr_info("/dev/%s driver unregistered\n", ++ restool_misc->misc.name); ++ fsl_mc_portal_free(restool_misc->static_mc_io); ++ list_del(&restool_misc->list); ++ kfree(restool_misc); ++ } ++} ++ ++module_exit(fsl_mc_restool_driver_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor Inc."); ++MODULE_DESCRIPTION("Freescale's MC restool driver"); ++MODULE_LICENSE("GPL"); |