Commit f3d8e878 authored by Alexander Usyskin's avatar Alexander Usyskin Committed by Greg Kroah-Hartman

mei: move from misc to char device

We need to support more then one mei interface
hence the simple misc devices is not longer an option

In order not break the user space a device with pci function 0
need to be linked to /dev/mei
Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7276883f
......@@ -32,7 +32,6 @@
#include <linux/compat.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/mei.h>
......@@ -49,19 +48,12 @@
*/
static int mei_open(struct inode *inode, struct file *file)
{
struct miscdevice *misc = file->private_data;
struct pci_dev *pdev;
struct mei_cl *cl;
struct mei_device *dev;
struct mei_cl *cl;
int err;
if (!misc->parent)
return -ENODEV;
pdev = container_of(misc->parent, struct pci_dev, dev);
dev = pci_get_drvdata(pdev);
dev = container_of(inode->i_cdev, struct mei_device, cdev);
if (!dev)
return -ENODEV;
......@@ -667,46 +659,148 @@ static const struct file_operations mei_fops = {
.llseek = no_llseek
};
/*
* Misc Device Struct
static struct class *mei_class;
static dev_t mei_devt;
#define MEI_MAX_DEVS MINORMASK
static DEFINE_MUTEX(mei_minor_lock);
static DEFINE_IDR(mei_idr);
/**
* mei_minor_get - obtain next free device minor number
*
* @dev: device pointer
*
* returns allocated minor, or -ENOSPC if no free minor left
*/
static struct miscdevice mei_misc_device = {
.name = "mei",
.fops = &mei_fops,
.minor = MISC_DYNAMIC_MINOR,
};
static int mei_minor_get(struct mei_device *dev)
{
int ret;
mutex_lock(&mei_minor_lock);
ret = idr_alloc(&mei_idr, dev, 0, MEI_MAX_DEVS, GFP_KERNEL);
if (ret >= 0)
dev->minor = ret;
else if (ret == -ENOSPC)
dev_err(&dev->pdev->dev, "too many mei devices\n");
mutex_unlock(&mei_minor_lock);
return ret;
}
int mei_register(struct mei_device *dev)
/**
* mei_minor_free - mark device minor number as free
*
* @dev: device pointer
*/
static void mei_minor_free(struct mei_device *dev)
{
int ret;
mei_misc_device.parent = &dev->pdev->dev;
ret = misc_register(&mei_misc_device);
if (ret)
mutex_lock(&mei_minor_lock);
idr_remove(&mei_idr, dev->minor);
mutex_unlock(&mei_minor_lock);
}
int mei_register(struct mei_device *dev, struct device *parent)
{
struct device *clsdev; /* class device */
int ret, devno;
ret = mei_minor_get(dev);
if (ret < 0)
return ret;
if (mei_dbgfs_register(dev, mei_misc_device.name))
dev_err(&dev->pdev->dev, "cannot register debugfs\n");
/* Fill in the data structures */
devno = MKDEV(MAJOR(mei_devt), dev->minor);
cdev_init(&dev->cdev, &mei_fops);
dev->cdev.owner = mei_fops.owner;
/* Add the device */
ret = cdev_add(&dev->cdev, devno, 1);
if (ret) {
dev_err(parent, "unable to add device %d:%d\n",
MAJOR(mei_devt), dev->minor);
goto err_dev_add;
}
clsdev = device_create(mei_class, parent, devno,
NULL, "mei%d", dev->minor);
if (IS_ERR(clsdev)) {
dev_err(parent, "unable to create device %d:%d\n",
MAJOR(mei_devt), dev->minor);
ret = PTR_ERR(clsdev);
goto err_dev_create;
}
ret = mei_dbgfs_register(dev, dev_name(clsdev));
if (ret) {
dev_err(clsdev, "cannot register debugfs ret = %d\n", ret);
goto err_dev_dbgfs;
}
return 0;
err_dev_dbgfs:
device_destroy(mei_class, devno);
err_dev_create:
cdev_del(&dev->cdev);
err_dev_add:
mei_minor_free(dev);
return ret;
}
EXPORT_SYMBOL_GPL(mei_register);
void mei_deregister(struct mei_device *dev)
{
int devno;
devno = dev->cdev.dev;
cdev_del(&dev->cdev);
mei_dbgfs_deregister(dev);
misc_deregister(&mei_misc_device);
mei_misc_device.parent = NULL;
device_destroy(mei_class, devno);
mei_minor_free(dev);
}
EXPORT_SYMBOL_GPL(mei_deregister);
static int __init mei_init(void)
{
return mei_cl_bus_init();
int ret;
mei_class = class_create(THIS_MODULE, "mei");
if (IS_ERR(mei_class)) {
pr_err("couldn't create class\n");
ret = PTR_ERR(mei_class);
goto err;
}
ret = alloc_chrdev_region(&mei_devt, 0, MEI_MAX_DEVS, "mei");
if (ret < 0) {
pr_err("unable to allocate char dev region\n");
goto err_class;
}
ret = mei_cl_bus_init();
if (ret < 0) {
pr_err("unable to initialize bus\n");
goto err_chrdev;
}
return 0;
err_chrdev:
unregister_chrdev_region(mei_devt, MEI_MAX_DEVS);
err_class:
class_destroy(mei_class);
err:
return ret;
}
static void __exit mei_exit(void)
{
unregister_chrdev_region(mei_devt, MEI_MAX_DEVS);
class_destroy(mei_class);
mei_cl_bus_exit();
}
......
......@@ -400,6 +400,10 @@ struct mei_cfg {
/**
* struct mei_device - MEI private device struct
* @pdev - pointer to pci device struct
* @cdev - character device
* @minor - minor number allocated for device
*
* @reset_count - limits the number of consecutive resets
* @hbm_state - state of host bus message protocol
* @pg_event - power gating event
......@@ -412,6 +416,9 @@ struct mei_cfg {
*/
struct mei_device {
struct pci_dev *pdev; /* pointer to pci device struct */
struct cdev cdev;
int minor;
/*
* lists of queues
*/
......@@ -741,7 +748,7 @@ static inline int mei_dbgfs_register(struct mei_device *dev, const char *name)
static inline void mei_dbgfs_deregister(struct mei_device *dev) {}
#endif /* CONFIG_DEBUG_FS */
int mei_register(struct mei_device *dev);
int mei_register(struct mei_device *dev, struct device *parent);
void mei_deregister(struct mei_device *dev);
#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d internal=%1d comp=%1d"
......
......@@ -31,7 +31,6 @@
#include <linux/compat.h>
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <linux/pm_runtime.h>
......@@ -207,7 +206,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
err = mei_register(dev);
err = mei_register(dev, &pdev->dev);
if (err)
goto release_irq;
......
......@@ -149,7 +149,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
err = mei_register(dev);
err = mei_register(dev, &pdev->dev);
if (err)
goto release_irq;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment