2018-09-26 18:27:40 +03:00
// SPDX-License-Identifier: GPL-2.0
2010-10-22 18:43:55 +04:00
/*
2018-09-26 18:27:40 +03:00
* Driver for the Intel SCU IPC mechanism
2010-10-22 18:43:55 +04:00
*
* ( C ) Copyright 2008 - 2010 Intel Corporation
* Author : Sreedhara DS ( sreedhara . ds @ intel . com )
*
2018-09-26 18:27:40 +03:00
* This driver provides IOCTL interfaces to call Intel SCU IPC driver API .
2010-10-22 18:43:55 +04:00
*/
# include <linux/errno.h>
# include <linux/fcntl.h>
2018-09-26 18:27:14 +03:00
# include <linux/fs.h>
# include <linux/kernel.h>
# include <linux/module.h>
2010-10-22 18:43:55 +04:00
# include <linux/sched.h>
# include <linux/slab.h>
2018-09-26 18:27:14 +03:00
# include <linux/types.h>
# include <linux/uaccess.h>
2010-10-22 18:43:55 +04:00
# include <asm/intel_scu_ipc.h>
2011-08-26 14:55:46 +04:00
static int major ;
2010-10-22 18:43:55 +04:00
2020-04-16 11:15:39 +03:00
struct intel_scu_ipc_dev * scu ;
static DEFINE_MUTEX ( scu_lock ) ;
2018-09-26 18:27:40 +03:00
/* IOCTL commands */
2010-10-22 18:43:55 +04:00
# define INTE_SCU_IPC_REGISTER_READ 0
# define INTE_SCU_IPC_REGISTER_WRITE 1
# define INTE_SCU_IPC_REGISTER_UPDATE 2
struct scu_ipc_data {
u32 count ; /* No. of registers */
u16 addr [ 5 ] ; /* Register addresses */
u8 data [ 5 ] ; /* Register data */
u8 mask ; /* Valid for read-modify-write */
} ;
/**
* scu_reg_access - implement register access ioctls
* @ cmd : command we are doing ( read / write / update )
* @ data : kernel copy of ioctl data
*
* Allow the user to perform register accesses on the SCU via the
* kernel interface
*/
static int scu_reg_access ( u32 cmd , struct scu_ipc_data * data )
{
2016-01-26 12:24:25 +03:00
unsigned int count = data - > count ;
2010-10-22 18:43:55 +04:00
if ( count = = 0 | | count = = 3 | | count > 4 )
return - EINVAL ;
switch ( cmd ) {
case INTE_SCU_IPC_REGISTER_READ :
2020-04-16 11:15:39 +03:00
return intel_scu_ipc_dev_readv ( scu , data - > addr , data - > data , count ) ;
2010-10-22 18:43:55 +04:00
case INTE_SCU_IPC_REGISTER_WRITE :
2020-04-16 11:15:39 +03:00
return intel_scu_ipc_dev_writev ( scu , data - > addr , data - > data , count ) ;
2010-10-22 18:43:55 +04:00
case INTE_SCU_IPC_REGISTER_UPDATE :
2020-04-16 11:15:39 +03:00
return intel_scu_ipc_dev_update ( scu , data - > addr [ 0 ] , data - > data [ 0 ] ,
data - > mask ) ;
2010-10-22 18:43:55 +04:00
default :
return - ENOTTY ;
}
}
/**
* scu_ipc_ioctl - control ioctls for the SCU
* @ fp : file handle of the SCU device
* @ cmd : ioctl coce
* @ arg : pointer to user passed structure
*
* Support the I / O and firmware flashing interfaces of the SCU
*/
static long scu_ipc_ioctl ( struct file * fp , unsigned int cmd ,
unsigned long arg )
{
int ret ;
struct scu_ipc_data data ;
void __user * argp = ( void __user * ) arg ;
if ( ! capable ( CAP_SYS_RAWIO ) )
return - EPERM ;
2012-03-06 03:01:02 +04:00
if ( copy_from_user ( & data , argp , sizeof ( struct scu_ipc_data ) ) )
return - EFAULT ;
ret = scu_reg_access ( cmd , & data ) ;
if ( ret < 0 )
return ret ;
if ( copy_to_user ( argp , & data , sizeof ( struct scu_ipc_data ) ) )
return - EFAULT ;
return 0 ;
2010-10-22 18:43:55 +04:00
}
2020-04-16 11:15:39 +03:00
static int scu_ipc_open ( struct inode * inode , struct file * file )
{
int ret = 0 ;
/* Only single open at the time */
mutex_lock ( & scu_lock ) ;
if ( scu ) {
ret = - EBUSY ;
goto unlock ;
}
scu = intel_scu_ipc_dev_get ( ) ;
if ( ! scu )
ret = - ENODEV ;
unlock :
mutex_unlock ( & scu_lock ) ;
return ret ;
}
static int scu_ipc_release ( struct inode * inode , struct file * file )
{
mutex_lock ( & scu_lock ) ;
intel_scu_ipc_dev_put ( scu ) ;
scu = NULL ;
mutex_unlock ( & scu_lock ) ;
return 0 ;
}
2010-10-22 18:43:55 +04:00
static const struct file_operations scu_ipc_fops = {
. unlocked_ioctl = scu_ipc_ioctl ,
2020-04-16 11:15:39 +03:00
. open = scu_ipc_open ,
. release = scu_ipc_release ,
2010-10-22 18:43:55 +04:00
} ;
static int __init ipc_module_init ( void )
{
2011-08-26 14:55:46 +04:00
major = register_chrdev ( 0 , " intel_mid_scu " , & scu_ipc_fops ) ;
if ( major < 0 )
return major ;
return 0 ;
2010-10-22 18:43:55 +04:00
}
static void __exit ipc_module_exit ( void )
{
unregister_chrdev ( major , " intel_mid_scu " ) ;
}
module_init ( ipc_module_init ) ;
module_exit ( ipc_module_exit ) ;
2011-01-25 17:33:36 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
2010-10-22 18:43:55 +04:00
MODULE_DESCRIPTION ( " Utility driver for intel scu ipc " ) ;
MODULE_AUTHOR ( " Sreedhara <sreedhara.ds@intel.com> " ) ;