Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for the Intel SCU IPC mechanism
0004  *
0005  * (C) Copyright 2008-2010 Intel Corporation
0006  * Author: Sreedhara DS (sreedhara.ds@intel.com)
0007  *
0008  * This driver provides IOCTL interfaces to call Intel SCU IPC driver API.
0009  */
0010 
0011 #include <linux/errno.h>
0012 #include <linux/fcntl.h>
0013 #include <linux/fs.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/sched.h>
0017 #include <linux/slab.h>
0018 #include <linux/types.h>
0019 #include <linux/uaccess.h>
0020 
0021 #include <asm/intel_scu_ipc.h>
0022 
0023 static int major;
0024 
0025 struct intel_scu_ipc_dev *scu;
0026 static DEFINE_MUTEX(scu_lock);
0027 
0028 /* IOCTL commands */
0029 #define INTE_SCU_IPC_REGISTER_READ  0
0030 #define INTE_SCU_IPC_REGISTER_WRITE 1
0031 #define INTE_SCU_IPC_REGISTER_UPDATE    2
0032 
0033 struct scu_ipc_data {
0034     u32     count;  /* No. of registers */
0035     u16     addr[5]; /* Register addresses */
0036     u8      data[5]; /* Register data */
0037     u8      mask; /* Valid for read-modify-write */
0038 };
0039 
0040 /**
0041  *  scu_reg_access      -   implement register access ioctls
0042  *  @cmd: command we are doing (read/write/update)
0043  *  @data: kernel copy of ioctl data
0044  *
0045  *  Allow the user to perform register accesses on the SCU via the
0046  *  kernel interface
0047  */
0048 
0049 static int scu_reg_access(u32 cmd, struct scu_ipc_data  *data)
0050 {
0051     unsigned int count = data->count;
0052 
0053     if (count == 0 || count == 3 || count > 4)
0054         return -EINVAL;
0055 
0056     switch (cmd) {
0057     case INTE_SCU_IPC_REGISTER_READ:
0058         return intel_scu_ipc_dev_readv(scu, data->addr, data->data, count);
0059     case INTE_SCU_IPC_REGISTER_WRITE:
0060         return intel_scu_ipc_dev_writev(scu, data->addr, data->data, count);
0061     case INTE_SCU_IPC_REGISTER_UPDATE:
0062         return intel_scu_ipc_dev_update(scu, data->addr[0], data->data[0],
0063                         data->mask);
0064     default:
0065         return -ENOTTY;
0066     }
0067 }
0068 
0069 /**
0070  *  scu_ipc_ioctl       -   control ioctls for the SCU
0071  *  @fp: file handle of the SCU device
0072  *  @cmd: ioctl coce
0073  *  @arg: pointer to user passed structure
0074  *
0075  *  Support the I/O and firmware flashing interfaces of the SCU
0076  */
0077 static long scu_ipc_ioctl(struct file *fp, unsigned int cmd,
0078                             unsigned long arg)
0079 {
0080     int ret;
0081     struct scu_ipc_data  data;
0082     void __user *argp = (void __user *)arg;
0083 
0084     if (!capable(CAP_SYS_RAWIO))
0085         return -EPERM;
0086 
0087     if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
0088         return -EFAULT;
0089     ret = scu_reg_access(cmd, &data);
0090     if (ret < 0)
0091         return ret;
0092     if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
0093         return -EFAULT;
0094     return 0;
0095 }
0096 
0097 static int scu_ipc_open(struct inode *inode, struct file *file)
0098 {
0099     int ret = 0;
0100 
0101     /* Only single open at the time */
0102     mutex_lock(&scu_lock);
0103     if (scu) {
0104         ret = -EBUSY;
0105         goto unlock;
0106     }
0107 
0108     scu = intel_scu_ipc_dev_get();
0109     if (!scu)
0110         ret = -ENODEV;
0111 
0112 unlock:
0113     mutex_unlock(&scu_lock);
0114     return ret;
0115 }
0116 
0117 static int scu_ipc_release(struct inode *inode, struct file *file)
0118 {
0119     mutex_lock(&scu_lock);
0120     intel_scu_ipc_dev_put(scu);
0121     scu = NULL;
0122     mutex_unlock(&scu_lock);
0123 
0124     return 0;
0125 }
0126 
0127 static const struct file_operations scu_ipc_fops = {
0128     .unlocked_ioctl = scu_ipc_ioctl,
0129     .open = scu_ipc_open,
0130     .release = scu_ipc_release,
0131 };
0132 
0133 static int __init ipc_module_init(void)
0134 {
0135     major = register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
0136     if (major < 0)
0137         return major;
0138 
0139     return 0;
0140 }
0141 
0142 static void __exit ipc_module_exit(void)
0143 {
0144     unregister_chrdev(major, "intel_mid_scu");
0145 }
0146 
0147 module_init(ipc_module_init);
0148 module_exit(ipc_module_exit);
0149 
0150 MODULE_LICENSE("GPL v2");
0151 MODULE_DESCRIPTION("Utility driver for intel scu ipc");
0152 MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>");