* [char-misc-next 1/6] mei: sperate interface and pci code into two files
2013-02-06 12:06 [char-misc-next 0/6] MEI and ME separation Tomas Winkler
@ 2013-02-06 12:06 ` Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 2/6] mei: initial extract of ME hw specifics from mei_device Tomas Winkler
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Tomas Winkler @ 2013-02-06 12:06 UTC (permalink / raw)
To: gregkh; +Cc: arnd, alan, linux-kernel, Tomas Winkler
leave misc file operations in the main
and move PCI related code into pci-me
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
drivers/misc/mei/Makefile | 1 +
drivers/misc/mei/main.c | 354 ++--------------------------------------
drivers/misc/mei/mei_dev.h | 3 +
drivers/misc/mei/pci-me.c | 393 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 409 insertions(+), 342 deletions(-)
create mode 100644 drivers/misc/mei/pci-me.c
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 9f71933..068f553 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -11,3 +11,4 @@ mei-objs += main.o
mei-objs += amthif.o
mei-objs += wd.o
mei-objs += client.o
+mei-objs += pci-me.o
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 123c663..018623c 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -43,54 +43,6 @@
#include "hw-me.h"
#include "client.h"
-/* AMT device is a singleton on the platform */
-static struct pci_dev *mei_pdev;
-
-/* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)},
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)},
-
- /* required last entry */
- {0, }
-};
-
-MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
-
-static DEFINE_MUTEX(mei_mutex);
-
-
/**
* mei_open - the open function
*
@@ -101,15 +53,20 @@ static DEFINE_MUTEX(mei_mutex);
*/
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;
+
int err;
err = -ENODEV;
- if (!mei_pdev)
+ if (!misc->parent)
goto out;
- dev = pci_get_drvdata(mei_pdev);
+ pdev = container_of(misc->parent, struct pci_dev, dev);
+
+ dev = pci_get_drvdata(pdev);
if (!dev)
goto out;
@@ -787,7 +744,6 @@ static const struct file_operations mei_fops = {
.llseek = no_llseek
};
-
/*
* Misc Device Struct
*/
@@ -797,302 +753,16 @@ static struct miscdevice mei_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
};
-/**
- * mei_quirk_probe - probe for devices that doesn't valid ME interface
- * @pdev: PCI device structure
- * @ent: entry into pci_device_table
- *
- * returns true if ME Interface is valid, false otherwise
- */
-static bool mei_quirk_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+int mei_register(struct device *dev)
{
- u32 reg;
- if (ent->device == MEI_DEV_ID_PBG_1) {
- pci_read_config_dword(pdev, 0x48, ®);
- /* make sure that bit 9 is up and bit 10 is down */
- if ((reg & 0x600) == 0x200) {
- dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
- return false;
- }
- }
- return true;
-}
-/**
- * mei_probe - Device Initialization Routine
- *
- * @pdev: PCI device structure
- * @ent: entry in kcs_pci_tbl
- *
- * returns 0 on success, <0 on failure.
- */
-static int mei_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct mei_device *dev;
- int err;
-
- mutex_lock(&mei_mutex);
-
- if (!mei_quirk_probe(pdev, ent)) {
- err = -ENODEV;
- goto end;
- }
-
- if (mei_pdev) {
- err = -EEXIST;
- goto end;
- }
- /* enable pci dev */
- err = pci_enable_device(pdev);
- if (err) {
- dev_err(&pdev->dev, "failed to enable pci device.\n");
- goto end;
- }
- /* set PCI host mastering */
- pci_set_master(pdev);
- /* pci request regions for mei driver */
- err = pci_request_regions(pdev, KBUILD_MODNAME);
- if (err) {
- dev_err(&pdev->dev, "failed to get pci regions.\n");
- goto disable_device;
- }
- /* allocates and initializes the mei dev structure */
- dev = mei_device_init(pdev);
- if (!dev) {
- err = -ENOMEM;
- goto release_regions;
- }
- /* mapping IO device memory */
- dev->mem_addr = pci_iomap(pdev, 0, 0);
- if (!dev->mem_addr) {
- dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
- err = -ENOMEM;
- goto free_device;
- }
- pci_enable_msi(pdev);
-
- /* request and enable interrupt */
- if (pci_dev_msi_enabled(pdev))
- err = request_threaded_irq(pdev->irq,
- NULL,
- mei_interrupt_thread_handler,
- IRQF_ONESHOT, KBUILD_MODNAME, dev);
- else
- err = request_threaded_irq(pdev->irq,
- mei_interrupt_quick_handler,
- mei_interrupt_thread_handler,
- IRQF_SHARED, KBUILD_MODNAME, dev);
-
- if (err) {
- dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
- pdev->irq);
- goto disable_msi;
- }
-
- if (mei_hw_init(dev)) {
- dev_err(&pdev->dev, "init hw failure.\n");
- err = -ENODEV;
- goto release_irq;
- }
-
- err = misc_register(&mei_misc_device);
- if (err)
- goto release_irq;
-
- mei_pdev = pdev;
- pci_set_drvdata(pdev, dev);
-
-
- schedule_delayed_work(&dev->timer_work, HZ);
-
- mutex_unlock(&mei_mutex);
-
- pr_debug("initialization successful.\n");
-
- return 0;
-
-release_irq:
- mei_disable_interrupts(dev);
- flush_scheduled_work();
- free_irq(pdev->irq, dev);
-disable_msi:
- pci_disable_msi(pdev);
- pci_iounmap(pdev, dev->mem_addr);
-free_device:
- kfree(dev);
-release_regions:
- pci_release_regions(pdev);
-disable_device:
- pci_disable_device(pdev);
-end:
- mutex_unlock(&mei_mutex);
- dev_err(&pdev->dev, "initialization failed.\n");
- return err;
+ mei_misc_device.parent = dev;
+ return misc_register(&mei_misc_device);
}
-/**
- * mei_remove - Device Removal Routine
- *
- * @pdev: PCI device structure
- *
- * mei_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.
- */
-static void mei_remove(struct pci_dev *pdev)
+void mei_deregister(void)
{
- struct mei_device *dev;
-
- if (mei_pdev != pdev)
- return;
-
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return;
-
- mutex_lock(&dev->device_lock);
-
- cancel_delayed_work(&dev->timer_work);
-
- mei_wd_stop(dev);
-
- mei_pdev = NULL;
-
- if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
- dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
- mei_cl_disconnect(&dev->iamthif_cl);
- }
- if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
- dev->wd_cl.state = MEI_FILE_DISCONNECTING;
- mei_cl_disconnect(&dev->wd_cl);
- }
-
- /* Unregistering watchdog device */
- mei_watchdog_unregister(dev);
-
- /* remove entry if already in list */
- dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
-
- if (dev->open_handle_count > 0)
- dev->open_handle_count--;
- mei_cl_unlink(&dev->wd_cl);
-
- if (dev->open_handle_count > 0)
- dev->open_handle_count--;
- mei_cl_unlink(&dev->iamthif_cl);
-
- dev->iamthif_current_cb = NULL;
- dev->me_clients_num = 0;
-
- mutex_unlock(&dev->device_lock);
-
- flush_scheduled_work();
-
- /* disable interrupts */
- mei_disable_interrupts(dev);
-
- free_irq(pdev->irq, dev);
- pci_disable_msi(pdev);
- pci_set_drvdata(pdev, NULL);
-
- if (dev->mem_addr)
- pci_iounmap(pdev, dev->mem_addr);
-
- kfree(dev);
-
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-
misc_deregister(&mei_misc_device);
+ mei_misc_device.parent = NULL;
}
-#ifdef CONFIG_PM
-static int mei_pci_suspend(struct device *device)
-{
- struct pci_dev *pdev = to_pci_dev(device);
- struct mei_device *dev = pci_get_drvdata(pdev);
- int err;
-
- if (!dev)
- return -ENODEV;
- mutex_lock(&dev->device_lock);
-
- cancel_delayed_work(&dev->timer_work);
-
- /* Stop watchdog if exists */
- err = mei_wd_stop(dev);
- /* Set new mei state */
- if (dev->dev_state == MEI_DEV_ENABLED ||
- dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
- dev->dev_state = MEI_DEV_POWER_DOWN;
- mei_reset(dev, 0);
- }
- mutex_unlock(&dev->device_lock);
-
- free_irq(pdev->irq, dev);
- pci_disable_msi(pdev);
-
- return err;
-}
-
-static int mei_pci_resume(struct device *device)
-{
- struct pci_dev *pdev = to_pci_dev(device);
- struct mei_device *dev;
- int err;
-
- dev = pci_get_drvdata(pdev);
- if (!dev)
- return -ENODEV;
-
- pci_enable_msi(pdev);
-
- /* request and enable interrupt */
- if (pci_dev_msi_enabled(pdev))
- err = request_threaded_irq(pdev->irq,
- NULL,
- mei_interrupt_thread_handler,
- IRQF_ONESHOT, KBUILD_MODNAME, dev);
- else
- err = request_threaded_irq(pdev->irq,
- mei_interrupt_quick_handler,
- mei_interrupt_thread_handler,
- IRQF_SHARED, KBUILD_MODNAME, dev);
-
- if (err) {
- dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
- pdev->irq);
- return err;
- }
-
- mutex_lock(&dev->device_lock);
- dev->dev_state = MEI_DEV_POWER_UP;
- mei_reset(dev, 1);
- mutex_unlock(&dev->device_lock);
-
- /* Start timer if stopped in suspend */
- schedule_delayed_work(&dev->timer_work, HZ);
-
- return err;
-}
-static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
-#define MEI_PM_OPS (&mei_pm_ops)
-#else
-#define MEI_PM_OPS NULL
-#endif /* CONFIG_PM */
-/*
- * PCI driver structure
- */
-static struct pci_driver mei_driver = {
- .name = KBUILD_MODNAME,
- .id_table = mei_pci_tbl,
- .probe = mei_probe,
- .remove = mei_remove,
- .shutdown = mei_remove,
- .driver.pm = MEI_PM_OPS,
-};
-module_pci_driver(mei_driver);
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index d6589d0..3b2bca3 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -401,6 +401,9 @@ bool mei_me_is_ready(struct mei_device *dev);
+int mei_register(struct device *dev);
+void mei_deregister(void);
+
#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d comp=%1d"
#define MEI_HDR_PRM(hdr) \
(hdr)->host_addr, (hdr)->me_addr, \
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
new file mode 100644
index 0000000..eaed398
--- /dev/null
+++ b/drivers/misc/mei/pci-me.c
@@ -0,0 +1,393 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2012, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/aio.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <linux/uuid.h>
+#include <linux/compat.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hw-me.h"
+#include "client.h"
+
+/* AMT device is a singleton on the platform */
+static struct pci_dev *mei_pdev;
+
+/* mei_pci_tbl - PCI Device ID Table */
+static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)},
+
+ /* required last entry */
+ {0, }
+};
+
+MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
+
+static DEFINE_MUTEX(mei_mutex);
+
+
+/**
+ * mei_quirk_probe - probe for devices that doesn't valid ME interface
+ * @pdev: PCI device structure
+ * @ent: entry into pci_device_table
+ *
+ * returns true if ME Interface is valid, false otherwise
+ */
+static bool mei_quirk_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ u32 reg;
+ if (ent->device == MEI_DEV_ID_PBG_1) {
+ pci_read_config_dword(pdev, 0x48, ®);
+ /* make sure that bit 9 is up and bit 10 is down */
+ if ((reg & 0x600) == 0x200) {
+ dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
+ return false;
+ }
+ }
+ return true;
+}
+/**
+ * mei_probe - Device Initialization Routine
+ *
+ * @pdev: PCI device structure
+ * @ent: entry in kcs_pci_tbl
+ *
+ * returns 0 on success, <0 on failure.
+ */
+static int mei_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct mei_device *dev;
+ int err;
+
+ mutex_lock(&mei_mutex);
+
+ if (!mei_quirk_probe(pdev, ent)) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ if (mei_pdev) {
+ err = -EEXIST;
+ goto end;
+ }
+ /* enable pci dev */
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to enable pci device.\n");
+ goto end;
+ }
+ /* set PCI host mastering */
+ pci_set_master(pdev);
+ /* pci request regions for mei driver */
+ err = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (err) {
+ dev_err(&pdev->dev, "failed to get pci regions.\n");
+ goto disable_device;
+ }
+ /* allocates and initializes the mei dev structure */
+ dev = mei_device_init(pdev);
+ if (!dev) {
+ err = -ENOMEM;
+ goto release_regions;
+ }
+ /* mapping IO device memory */
+ dev->mem_addr = pci_iomap(pdev, 0, 0);
+ if (!dev->mem_addr) {
+ dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
+ err = -ENOMEM;
+ goto free_device;
+ }
+ pci_enable_msi(pdev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_interrupt_thread_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
+ mei_interrupt_quick_handler,
+ mei_interrupt_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+
+ if (err) {
+ dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
+ pdev->irq);
+ goto disable_msi;
+ }
+
+ if (mei_hw_init(dev)) {
+ dev_err(&pdev->dev, "init hw failure.\n");
+ err = -ENODEV;
+ goto release_irq;
+ }
+
+ err = mei_register(&pdev->dev);
+ if (err)
+ goto release_irq;
+
+ mei_pdev = pdev;
+ pci_set_drvdata(pdev, dev);
+
+
+ schedule_delayed_work(&dev->timer_work, HZ);
+
+ mutex_unlock(&mei_mutex);
+
+ pr_debug("initialization successful.\n");
+
+ return 0;
+
+release_irq:
+ mei_disable_interrupts(dev);
+ flush_scheduled_work();
+ free_irq(pdev->irq, dev);
+disable_msi:
+ pci_disable_msi(pdev);
+ pci_iounmap(pdev, dev->mem_addr);
+free_device:
+ kfree(dev);
+release_regions:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+end:
+ mutex_unlock(&mei_mutex);
+ dev_err(&pdev->dev, "initialization failed.\n");
+ return err;
+}
+
+/**
+ * mei_remove - Device Removal Routine
+ *
+ * @pdev: PCI device structure
+ *
+ * mei_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+static void mei_remove(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+
+ if (mei_pdev != pdev)
+ return;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev)
+ return;
+
+ mutex_lock(&dev->device_lock);
+
+ cancel_delayed_work(&dev->timer_work);
+
+ mei_wd_stop(dev);
+
+ mei_pdev = NULL;
+
+ if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
+ dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
+ mei_cl_disconnect(&dev->iamthif_cl);
+ }
+ if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
+ dev->wd_cl.state = MEI_FILE_DISCONNECTING;
+ mei_cl_disconnect(&dev->wd_cl);
+ }
+
+ /* Unregistering watchdog device */
+ mei_watchdog_unregister(dev);
+
+ /* remove entry if already in list */
+ dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
+
+ if (dev->open_handle_count > 0)
+ dev->open_handle_count--;
+ mei_cl_unlink(&dev->wd_cl);
+
+ if (dev->open_handle_count > 0)
+ dev->open_handle_count--;
+ mei_cl_unlink(&dev->iamthif_cl);
+
+ dev->iamthif_current_cb = NULL;
+ dev->me_clients_num = 0;
+
+ mutex_unlock(&dev->device_lock);
+
+ flush_scheduled_work();
+
+ /* disable interrupts */
+ mei_disable_interrupts(dev);
+
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ if (dev->mem_addr)
+ pci_iounmap(pdev, dev->mem_addr);
+
+ kfree(dev);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ mei_deregister();
+
+}
+#ifdef CONFIG_PM
+static int mei_pci_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct mei_device *dev = pci_get_drvdata(pdev);
+ int err;
+
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&dev->device_lock);
+
+ cancel_delayed_work(&dev->timer_work);
+
+ /* Stop watchdog if exists */
+ err = mei_wd_stop(dev);
+ /* Set new mei state */
+ if (dev->dev_state == MEI_DEV_ENABLED ||
+ dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
+ dev->dev_state = MEI_DEV_POWER_DOWN;
+ mei_reset(dev, 0);
+ }
+ mutex_unlock(&dev->device_lock);
+
+ free_irq(pdev->irq, dev);
+ pci_disable_msi(pdev);
+
+ return err;
+}
+
+static int mei_pci_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct mei_device *dev;
+ int err;
+
+ dev = pci_get_drvdata(pdev);
+ if (!dev)
+ return -ENODEV;
+
+ pci_enable_msi(pdev);
+
+ /* request and enable interrupt */
+ if (pci_dev_msi_enabled(pdev))
+ err = request_threaded_irq(pdev->irq,
+ NULL,
+ mei_interrupt_thread_handler,
+ IRQF_ONESHOT, KBUILD_MODNAME, dev);
+ else
+ err = request_threaded_irq(pdev->irq,
+ mei_interrupt_quick_handler,
+ mei_interrupt_thread_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+
+ if (err) {
+ dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
+ pdev->irq);
+ return err;
+ }
+
+ mutex_lock(&dev->device_lock);
+ dev->dev_state = MEI_DEV_POWER_UP;
+ mei_reset(dev, 1);
+ mutex_unlock(&dev->device_lock);
+
+ /* Start timer if stopped in suspend */
+ schedule_delayed_work(&dev->timer_work, HZ);
+
+ return err;
+}
+static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
+#define MEI_PM_OPS (&mei_pm_ops)
+#else
+#define MEI_PM_OPS NULL
+#endif /* CONFIG_PM */
+/*
+ * PCI driver structure
+ */
+static struct pci_driver mei_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = mei_pci_tbl,
+ .probe = mei_probe,
+ .remove = mei_remove,
+ .shutdown = mei_remove,
+ .driver.pm = MEI_PM_OPS,
+};
+
+module_pci_driver(mei_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
+MODULE_LICENSE("GPL v2");
--
1.7.4.4
^ permalink raw reply [flat|nested] 7+ messages in thread* [char-misc-next 2/6] mei: initial extract of ME hw specifics from mei_device
2013-02-06 12:06 [char-misc-next 0/6] MEI and ME separation Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 1/6] mei: sperate interface and pci code into two files Tomas Winkler
@ 2013-02-06 12:06 ` Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 3/6] mei: separate compilation of the ME hardware specifics Tomas Winkler
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Tomas Winkler @ 2013-02-06 12:06 UTC (permalink / raw)
To: gregkh; +Cc: arnd, alan, linux-kernel, Tomas Winkler
This is initial step of move the ME hw specifics
out of mei_device structure into mei_me_hw
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
drivers/misc/mei/hw-me.c | 131 +++++++++++++++++++++++++++++---------------
drivers/misc/mei/hw-me.h | 12 ++++
drivers/misc/mei/init.c | 28 +---------
drivers/misc/mei/mei_dev.h | 10 +--
drivers/misc/mei/pci-me.c | 21 ++++---
5 files changed, 114 insertions(+), 88 deletions(-)
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 94b203e..3bdf228 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -28,10 +28,10 @@
*
* returns register value (u32)
*/
-static inline u32 mei_reg_read(const struct mei_device *dev,
+static inline u32 mei_reg_read(const struct mei_me_hw *hw,
unsigned long offset)
{
- return ioread32(dev->mem_addr + offset);
+ return ioread32(hw->mem_addr + offset);
}
@@ -42,10 +42,10 @@ static inline u32 mei_reg_read(const struct mei_device *dev,
* @offset: offset from which to write the data
* @value: register value to write (u32)
*/
-static inline void mei_reg_write(const struct mei_device *dev,
+static inline void mei_reg_write(const struct mei_me_hw *hw,
unsigned long offset, u32 value)
{
- iowrite32(value, dev->mem_addr + offset);
+ iowrite32(value, hw->mem_addr + offset);
}
/**
@@ -58,7 +58,7 @@ static inline void mei_reg_write(const struct mei_device *dev,
*/
u32 mei_mecbrw_read(const struct mei_device *dev)
{
- return mei_reg_read(dev, ME_CB_RW);
+ return mei_reg_read(to_me_hw(dev), ME_CB_RW);
}
/**
* mei_mecsr_read - Reads 32bit data from the ME CSR
@@ -67,9 +67,9 @@ u32 mei_mecbrw_read(const struct mei_device *dev)
*
* returns ME_CSR_HA register value (u32)
*/
-static inline u32 mei_mecsr_read(const struct mei_device *dev)
+static inline u32 mei_mecsr_read(const struct mei_me_hw *hw)
{
- return mei_reg_read(dev, ME_CSR_HA);
+ return mei_reg_read(hw, ME_CSR_HA);
}
/**
@@ -79,9 +79,9 @@ static inline u32 mei_mecsr_read(const struct mei_device *dev)
*
* returns H_CSR register value (u32)
*/
-static inline u32 mei_hcsr_read(const struct mei_device *dev)
+static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
{
- return mei_reg_read(dev, H_CSR);
+ return mei_reg_read(hw, H_CSR);
}
/**
@@ -90,10 +90,10 @@ static inline u32 mei_hcsr_read(const struct mei_device *dev)
*
* @dev: the device structure
*/
-static inline void mei_hcsr_set(struct mei_device *dev, u32 hcsr)
+static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
{
hcsr &= ~H_IS;
- mei_reg_write(dev, H_CSR, hcsr);
+ mei_reg_write(hw, H_CSR, hcsr);
}
@@ -104,7 +104,7 @@ static inline void mei_hcsr_set(struct mei_device *dev, u32 hcsr)
*/
void mei_hw_config(struct mei_device *dev)
{
- u32 hcsr = mei_hcsr_read(dev);
+ u32 hcsr = mei_hcsr_read(to_me_hw(dev));
/* Doesn't change in runtime */
dev->hbuf_depth = (hcsr & H_CBD) >> 24;
}
@@ -115,9 +115,10 @@ void mei_hw_config(struct mei_device *dev)
*/
void mei_clear_interrupts(struct mei_device *dev)
{
- u32 hcsr = mei_hcsr_read(dev);
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
if ((hcsr & H_IS) == H_IS)
- mei_reg_write(dev, H_CSR, hcsr);
+ mei_reg_write(hw, H_CSR, hcsr);
}
/**
@@ -127,9 +128,10 @@ void mei_clear_interrupts(struct mei_device *dev)
*/
void mei_enable_interrupts(struct mei_device *dev)
{
- u32 hcsr = mei_hcsr_read(dev);
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
hcsr |= H_IE;
- mei_hcsr_set(dev, hcsr);
+ mei_hcsr_set(hw, hcsr);
}
/**
@@ -139,9 +141,10 @@ void mei_enable_interrupts(struct mei_device *dev)
*/
void mei_disable_interrupts(struct mei_device *dev)
{
- u32 hcsr = mei_hcsr_read(dev);
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
hcsr &= ~H_IE;
- mei_hcsr_set(dev, hcsr);
+ mei_hcsr_set(hw, hcsr);
}
/**
@@ -152,7 +155,8 @@ void mei_disable_interrupts(struct mei_device *dev)
*/
void mei_hw_reset(struct mei_device *dev, bool intr_enable)
{
- u32 hcsr = mei_hcsr_read(dev);
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
dev_dbg(&dev->pdev->dev, "before reset HCSR = 0x%08x.\n", hcsr);
@@ -163,14 +167,14 @@ void mei_hw_reset(struct mei_device *dev, bool intr_enable)
else
hcsr &= ~H_IE;
- mei_hcsr_set(dev, hcsr);
+ mei_hcsr_set(hw, hcsr);
- hcsr = mei_hcsr_read(dev) | H_IG;
+ hcsr = mei_hcsr_read(hw) | H_IG;
hcsr &= ~H_RST;
- mei_hcsr_set(dev, hcsr);
+ mei_hcsr_set(hw, hcsr);
- hcsr = mei_hcsr_read(dev);
+ hcsr = mei_hcsr_read(hw);
dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr);
}
@@ -184,8 +188,9 @@ void mei_hw_reset(struct mei_device *dev, bool intr_enable)
void mei_host_set_ready(struct mei_device *dev)
{
- dev->host_hw_state |= H_IE | H_IG | H_RDY;
- mei_hcsr_set(dev, dev->host_hw_state);
+ struct mei_me_hw *hw = to_me_hw(dev);
+ hw->host_hw_state |= H_IE | H_IG | H_RDY;
+ mei_hcsr_set(hw, hw->host_hw_state);
}
/**
* mei_host_is_ready - check whether the host has turned ready
@@ -195,8 +200,9 @@ void mei_host_set_ready(struct mei_device *dev)
*/
bool mei_host_is_ready(struct mei_device *dev)
{
- dev->host_hw_state = mei_hcsr_read(dev);
- return (dev->host_hw_state & H_RDY) == H_RDY;
+ struct mei_me_hw *hw = to_me_hw(dev);
+ hw->host_hw_state = mei_hcsr_read(hw);
+ return (hw->host_hw_state & H_RDY) == H_RDY;
}
/**
@@ -207,8 +213,9 @@ bool mei_host_is_ready(struct mei_device *dev)
*/
bool mei_me_is_ready(struct mei_device *dev)
{
- dev->me_hw_state = mei_mecsr_read(dev);
- return (dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
+ struct mei_me_hw *hw = to_me_hw(dev);
+ hw->me_hw_state = mei_mecsr_read(hw);
+ return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
}
/**
@@ -222,13 +229,14 @@ bool mei_me_is_ready(struct mei_device *dev)
irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
{
struct mei_device *dev = (struct mei_device *) dev_id;
- u32 csr_reg = mei_hcsr_read(dev);
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 csr_reg = mei_hcsr_read(hw);
if ((csr_reg & H_IS) != H_IS)
return IRQ_NONE;
/* clear H_IS bit in H_CSR */
- mei_reg_write(dev, H_CSR, csr_reg);
+ mei_reg_write(hw, H_CSR, csr_reg);
return IRQ_WAKE_THREAD;
}
@@ -242,12 +250,13 @@ irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
*/
static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
{
+ struct mei_me_hw *hw = to_me_hw(dev);
char read_ptr, write_ptr;
- dev->host_hw_state = mei_hcsr_read(dev);
+ hw->host_hw_state = mei_hcsr_read(hw);
- read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
- write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);
+ read_ptr = (char) ((hw->host_hw_state & H_CBRP) >> 8);
+ write_ptr = (char) ((hw->host_hw_state & H_CBWP) >> 16);
return (unsigned char) (write_ptr - read_ptr);
}
@@ -297,6 +306,7 @@ int mei_hbuf_empty_slots(struct mei_device *dev)
int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
unsigned char *buf)
{
+ struct mei_me_hw *hw = to_me_hw(dev);
unsigned long rem, dw_cnt;
unsigned long length = header->length;
u32 *reg_buf = (u32 *)buf;
@@ -313,20 +323,20 @@ int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
if (empty_slots < 0 || dw_cnt > empty_slots)
return -EIO;
- mei_reg_write(dev, H_CB_WW, *((u32 *) header));
+ mei_reg_write(hw, H_CB_WW, *((u32 *) header));
for (i = 0; i < length / 4; i++)
- mei_reg_write(dev, H_CB_WW, reg_buf[i]);
+ mei_reg_write(hw, H_CB_WW, reg_buf[i]);
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
memcpy(®, &buf[length - rem], rem);
- mei_reg_write(dev, H_CB_WW, reg);
+ mei_reg_write(hw, H_CB_WW, reg);
}
- hcsr = mei_hcsr_read(dev) | H_IG;
- mei_hcsr_set(dev, hcsr);
+ hcsr = mei_hcsr_read(hw) | H_IG;
+ mei_hcsr_set(hw, hcsr);
if (!mei_me_is_ready(dev))
return -EIO;
@@ -342,13 +352,14 @@ int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
*/
int mei_count_full_read_slots(struct mei_device *dev)
{
+ struct mei_me_hw *hw = to_me_hw(dev);
char read_ptr, write_ptr;
unsigned char buffer_depth, filled_slots;
- dev->me_hw_state = mei_mecsr_read(dev);
- buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24);
- read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8);
- write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16);
+ hw->me_hw_state = mei_mecsr_read(hw);
+ buffer_depth = (unsigned char)((hw->me_hw_state & ME_CBD_HRA) >> 24);
+ read_ptr = (char) ((hw->me_hw_state & ME_CBRP_HRA) >> 8);
+ write_ptr = (char) ((hw->me_hw_state & ME_CBWP_HRA) >> 16);
filled_slots = (unsigned char) (write_ptr - read_ptr);
/* check for overflow */
@@ -369,6 +380,7 @@ int mei_count_full_read_slots(struct mei_device *dev)
void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
unsigned long buffer_length)
{
+ struct mei_me_hw *hw = to_me_hw(dev);
u32 *reg_buf = (u32 *)buffer;
u32 hcsr;
@@ -380,7 +392,36 @@ void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
memcpy(reg_buf, ®, buffer_length);
}
- hcsr = mei_hcsr_read(dev) | H_IG;
- mei_hcsr_set(dev, hcsr);
+ hcsr = mei_hcsr_read(hw) | H_IG;
+ mei_hcsr_set(hw, hcsr);
}
+/**
+ * init_mei_device - allocates and initializes the mei device structure
+ *
+ * @pdev: The pci device structure
+ *
+ * returns The mei_device_device pointer on success, NULL on failure.
+ */
+struct mei_device *mei_me_dev_init(struct pci_dev *pdev)
+{
+ struct mei_device *dev;
+
+ dev = kzalloc(sizeof(struct mei_device) +
+ sizeof(struct mei_me_hw), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ mei_device_init(dev);
+
+ INIT_LIST_HEAD(&dev->wd_cl.link);
+ INIT_LIST_HEAD(&dev->iamthif_cl.link);
+ mei_io_list_init(&dev->amthif_cmd_list);
+ mei_io_list_init(&dev->amthif_rd_complete_list);
+
+ INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
+ INIT_WORK(&dev->init_work, mei_host_client_init);
+
+ dev->pdev = pdev;
+ return dev;
+}
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 73bef54..53bcc00 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -21,8 +21,20 @@
#include <linux/mei.h>
#include "mei_dev.h"
+#include "client.h"
+struct mei_me_hw {
+ void __iomem *mem_addr;
+ /*
+ * hw states of host and fw(ME)
+ */
+ u32 host_hw_state;
+ u32 me_hw_state;
+};
+#define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw)
+
+struct mei_device *mei_me_dev_init(struct pci_dev *pdev);
void mei_read_slots(struct mei_device *dev,
unsigned char *buffer,
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 5d08db5..1e1876f 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -42,28 +42,10 @@ const char *mei_dev_state_str(int state)
#undef MEI_DEV_STATE
}
-
-
-
-/**
- * init_mei_device - allocates and initializes the mei device structure
- *
- * @pdev: The pci device structure
- *
- * returns The mei_device_device pointer on success, NULL on failure.
- */
-struct mei_device *mei_device_init(struct pci_dev *pdev)
+void mei_device_init(struct mei_device *dev)
{
- struct mei_device *dev;
-
- dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
- if (!dev)
- return NULL;
-
/* setup our list array */
INIT_LIST_HEAD(&dev->file_list);
- INIT_LIST_HEAD(&dev->wd_cl.link);
- INIT_LIST_HEAD(&dev->iamthif_cl.link);
mutex_init(&dev->device_lock);
init_waitqueue_head(&dev->wait_recvd_msg);
init_waitqueue_head(&dev->wait_stop_wd);
@@ -74,14 +56,6 @@ struct mei_device *mei_device_init(struct pci_dev *pdev)
mei_io_list_init(&dev->write_waiting_list);
mei_io_list_init(&dev->ctrl_wr_list);
mei_io_list_init(&dev->ctrl_rd_list);
- mei_io_list_init(&dev->amthif_cmd_list);
- mei_io_list_init(&dev->amthif_rd_complete_list);
-
- INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
- INIT_WORK(&dev->init_work, mei_host_client_init);
-
- dev->pdev = pdev;
- return dev;
}
/**
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 3b2bca3..bb759fd 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -235,18 +235,13 @@ struct mei_device {
struct list_head file_list;
long open_handle_count;
- void __iomem *mem_addr;
/*
* lock for the device
*/
struct mutex device_lock; /* device lock */
struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
bool recvd_msg;
- /*
- * hw states of host and fw(ME)
- */
- u32 host_hw_state;
- u32 me_hw_state;
+
u8 hbuf_depth;
/*
* waiting queue for receive message from FW
@@ -311,6 +306,7 @@ struct mei_device {
bool iamthif_canceled;
struct work_struct init_work;
+ char hw[0] __aligned(sizeof(void *));
};
static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
@@ -322,7 +318,7 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
/*
* mei init function prototypes
*/
-struct mei_device *mei_device_init(struct pci_dev *pdev);
+void mei_device_init(struct mei_device *dev);
void mei_reset(struct mei_device *dev, int interrupts);
int mei_hw_init(struct mei_device *dev);
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index eaed398..27ac717 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -90,7 +90,6 @@ MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
static DEFINE_MUTEX(mei_mutex);
-
/**
* mei_quirk_probe - probe for devices that doesn't valid ME interface
* @pdev: PCI device structure
@@ -120,10 +119,10 @@ static bool mei_quirk_probe(struct pci_dev *pdev,
*
* returns 0 on success, <0 on failure.
*/
-static int mei_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct mei_device *dev;
+ struct mei_me_hw *hw;
int err;
mutex_lock(&mei_mutex);
@@ -152,14 +151,15 @@ static int mei_probe(struct pci_dev *pdev,
goto disable_device;
}
/* allocates and initializes the mei dev structure */
- dev = mei_device_init(pdev);
+ dev = mei_me_dev_init(pdev);
if (!dev) {
err = -ENOMEM;
goto release_regions;
}
+ hw = to_me_hw(dev);
/* mapping IO device memory */
- dev->mem_addr = pci_iomap(pdev, 0, 0);
- if (!dev->mem_addr) {
+ hw->mem_addr = pci_iomap(pdev, 0, 0);
+ if (!hw->mem_addr) {
dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
err = -ENOMEM;
goto free_device;
@@ -212,7 +212,7 @@ release_irq:
free_irq(pdev->irq, dev);
disable_msi:
pci_disable_msi(pdev);
- pci_iounmap(pdev, dev->mem_addr);
+ pci_iounmap(pdev, hw->mem_addr);
free_device:
kfree(dev);
release_regions:
@@ -236,6 +236,7 @@ end:
static void mei_remove(struct pci_dev *pdev)
{
struct mei_device *dev;
+ struct mei_me_hw *hw;
if (mei_pdev != pdev)
return;
@@ -244,6 +245,8 @@ static void mei_remove(struct pci_dev *pdev)
if (!dev)
return;
+ hw = to_me_hw(dev);
+
mutex_lock(&dev->device_lock);
cancel_delayed_work(&dev->timer_work);
@@ -289,8 +292,8 @@ static void mei_remove(struct pci_dev *pdev)
pci_disable_msi(pdev);
pci_set_drvdata(pdev, NULL);
- if (dev->mem_addr)
- pci_iounmap(pdev, dev->mem_addr);
+ if (hw->mem_addr)
+ pci_iounmap(pdev, hw->mem_addr);
kfree(dev);
--
1.7.4.4
^ permalink raw reply [flat|nested] 7+ messages in thread* [char-misc-next 3/6] mei: separate compilation of the ME hardware specifics
2013-02-06 12:06 [char-misc-next 0/6] MEI and ME separation Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 1/6] mei: sperate interface and pci code into two files Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 2/6] mei: initial extract of ME hw specifics from mei_device Tomas Winkler
@ 2013-02-06 12:06 ` Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 4/6] mei: move interrupt handlers to be me hw specific Tomas Winkler
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Tomas Winkler @ 2013-02-06 12:06 UTC (permalink / raw)
To: gregkh; +Cc: arnd, alan, linux-kernel, Tomas Winkler
We add struct mei_hw_ops to virtualize access to hw specific
configurations. This allows us to separate the compilation
of the ME interface from the ME hardware specifics
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
drivers/misc/mei/Kconfig | 17 ++++-
drivers/misc/mei/Makefile | 6 +-
drivers/misc/mei/amthif.c | 6 +-
drivers/misc/mei/hw-me.c | 87 +++++++++++++++++++---------
drivers/misc/mei/hw-me.h | 19 ------
drivers/misc/mei/init.c | 2 +-
drivers/misc/mei/interrupt.c | 10 ++--
drivers/misc/mei/main.c | 5 +-
drivers/misc/mei/mei_dev.h | 132 ++++++++++++++++++++++++++++++++++++++---
9 files changed, 210 insertions(+), 74 deletions(-)
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index 5a79ccd..fa5c249 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -1,11 +1,22 @@
config INTEL_MEI
- tristate "Intel Management Engine Interface (Intel MEI)"
- depends on X86 && PCI && WATCHDOG_CORE
+ tristate "Intel Management Engine Interface"
+ depends on X86 && PCI
help
The Intel Management Engine (Intel ME) provides Manageability,
Security and Media services for system containing Intel chipsets.
if selected /dev/mei misc device will be created.
+ For more information see
+ <http://software.intel.com/en-us/manageability/>
+
+config INTEL_MEI_ME
+ bool "ME Enabled Intel Chipsets"
+ depends on INTEL_MEI
+ depends on X86 && PCI && WATCHDOG_CORE
+ default y
+ help
+ MEI support for ME Enabled Intel chipsets.
+
Supported Chipsets are:
7 Series Chipset Family
6 Series Chipset Family
@@ -24,5 +35,3 @@ config INTEL_MEI
82Q33 Express
82X38/X48 Express
- For more information see
- <http://software.intel.com/en-us/manageability/>
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 068f553..040af6c 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -6,9 +6,9 @@ obj-$(CONFIG_INTEL_MEI) += mei.o
mei-objs := init.o
mei-objs += hbm.o
mei-objs += interrupt.o
-mei-objs += hw-me.o
+mei-objs += client.o
mei-objs += main.o
mei-objs += amthif.o
mei-objs += wd.o
-mei-objs += client.o
-mei-objs += pci-me.o
+mei-$(CONFIG_INTEL_MEI_ME) += pci-me.o
+mei-$(CONFIG_INTEL_MEI_ME) += hw-me.o
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 263ed4c..a7c4838 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -300,8 +300,8 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
if (ret && dev->mei_host_buffer_is_empty) {
ret = 0;
dev->mei_host_buffer_is_empty = false;
- if (cb->request_buffer.size > mei_hbuf_max_data(dev)) {
- mei_hdr.length = mei_hbuf_max_data(dev);
+ if (cb->request_buffer.size > mei_hbuf_max_len(dev)) {
+ mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
} else {
mei_hdr.length = cb->request_buffer.size;
@@ -583,7 +583,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
dev->iamthif_msg_buf_index = 0;
dev->iamthif_msg_buf_size = 0;
dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
- dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
+ dev->mei_host_buffer_is_empty = mei_hbuf_is_ready(dev);
return 0;
}
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 3bdf228..6300943 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -56,7 +56,7 @@ static inline void mei_reg_write(const struct mei_me_hw *hw,
*
* returns ME_CB_RW register value (u32)
*/
-u32 mei_mecbrw_read(const struct mei_device *dev)
+static u32 mei_me_mecbrw_read(const struct mei_device *dev)
{
return mei_reg_read(to_me_hw(dev), ME_CB_RW);
}
@@ -102,7 +102,7 @@ static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
*
* @dev: mei device
*/
-void mei_hw_config(struct mei_device *dev)
+static void mei_me_hw_config(struct mei_device *dev)
{
u32 hcsr = mei_hcsr_read(to_me_hw(dev));
/* Doesn't change in runtime */
@@ -113,20 +113,19 @@ void mei_hw_config(struct mei_device *dev)
*
* @dev: the device structure
*/
-void mei_clear_interrupts(struct mei_device *dev)
+static void mei_me_intr_clear(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
if ((hcsr & H_IS) == H_IS)
mei_reg_write(hw, H_CSR, hcsr);
}
-
/**
- * mei_enable_interrupts - enables mei device interrupts
+ * mei_me_intr_enable - enables mei device interrupts
*
* @dev: the device structure
*/
-void mei_enable_interrupts(struct mei_device *dev)
+static void mei_me_intr_enable(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
@@ -139,7 +138,7 @@ void mei_enable_interrupts(struct mei_device *dev)
*
* @dev: the device structure
*/
-void mei_disable_interrupts(struct mei_device *dev)
+static void mei_me_intr_disable(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
@@ -148,12 +147,12 @@ void mei_disable_interrupts(struct mei_device *dev)
}
/**
- * mei_hw_reset - resets fw via mei csr register.
+ * mei_me_hw_reset - resets fw via mei csr register.
*
* @dev: the device structure
* @interrupts_enabled: if interrupt should be enabled after reset.
*/
-void mei_hw_reset(struct mei_device *dev, bool intr_enable)
+static void mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
{
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
@@ -180,25 +179,25 @@ void mei_hw_reset(struct mei_device *dev, bool intr_enable)
}
/**
- * mei_host_set_ready - enable device
+ * mei_me_host_set_ready - enable device
*
* @dev - mei device
* returns bool
*/
-void mei_host_set_ready(struct mei_device *dev)
+static void mei_me_host_set_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->host_hw_state |= H_IE | H_IG | H_RDY;
mei_hcsr_set(hw, hw->host_hw_state);
}
/**
- * mei_host_is_ready - check whether the host has turned ready
+ * mei_me_host_is_ready - check whether the host has turned ready
*
* @dev - mei device
* returns bool
*/
-bool mei_host_is_ready(struct mei_device *dev)
+static bool mei_me_host_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->host_hw_state = mei_hcsr_read(hw);
@@ -206,12 +205,12 @@ bool mei_host_is_ready(struct mei_device *dev)
}
/**
- * mei_me_is_ready - check whether the me has turned ready
+ * mei_me_hw_is_ready - check whether the me(hw) has turned ready
*
* @dev - mei device
* returns bool
*/
-bool mei_me_is_ready(struct mei_device *dev)
+static bool mei_me_hw_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
hw->me_hw_state = mei_mecsr_read(hw);
@@ -268,19 +267,19 @@ static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
*
* returns true if empty, false - otherwise.
*/
-bool mei_hbuf_is_empty(struct mei_device *dev)
+static bool mei_me_hbuf_is_empty(struct mei_device *dev)
{
return mei_hbuf_filled_slots(dev) == 0;
}
/**
- * mei_hbuf_empty_slots - counts write empty slots.
+ * mei_me_hbuf_empty_slots - counts write empty slots.
*
* @dev: the device structure
*
* returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
*/
-int mei_hbuf_empty_slots(struct mei_device *dev)
+static int mei_me_hbuf_empty_slots(struct mei_device *dev)
{
unsigned char filled_slots, empty_slots;
@@ -294,6 +293,12 @@ int mei_hbuf_empty_slots(struct mei_device *dev)
return empty_slots;
}
+static size_t mei_me_hbuf_max_len(const struct mei_device *dev)
+{
+ return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
+}
+
+
/**
* mei_write_message - writes a message to mei device.
*
@@ -303,8 +308,9 @@ int mei_hbuf_empty_slots(struct mei_device *dev)
*
* This function returns -EIO if write has failed
*/
-int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
- unsigned char *buf)
+static int mei_me_write_message(struct mei_device *dev,
+ struct mei_msg_hdr *header,
+ unsigned char *buf)
{
struct mei_me_hw *hw = to_me_hw(dev);
unsigned long rem, dw_cnt;
@@ -337,20 +343,20 @@ int mei_write_message(struct mei_device *dev, struct mei_msg_hdr *header,
hcsr = mei_hcsr_read(hw) | H_IG;
mei_hcsr_set(hw, hcsr);
- if (!mei_me_is_ready(dev))
+ if (!mei_me_hw_is_ready(dev))
return -EIO;
return 0;
}
/**
- * mei_count_full_read_slots - counts read full slots.
+ * mei_me_count_full_read_slots - counts read full slots.
*
* @dev: the device structure
*
* returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
*/
-int mei_count_full_read_slots(struct mei_device *dev)
+static int mei_me_count_full_read_slots(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
char read_ptr, write_ptr;
@@ -371,13 +377,13 @@ int mei_count_full_read_slots(struct mei_device *dev)
}
/**
- * mei_read_slots - reads a message from mei device.
+ * mei_me_read_slots - reads a message from mei device.
*
* @dev: the device structure
* @buffer: message buffer will be written
* @buffer_length: message size will be read
*/
-void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
+static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
unsigned long buffer_length)
{
struct mei_me_hw *hw = to_me_hw(dev);
@@ -385,17 +391,42 @@ void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
u32 hcsr;
for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
- *reg_buf++ = mei_mecbrw_read(dev);
+ *reg_buf++ = mei_me_mecbrw_read(dev);
if (buffer_length > 0) {
- u32 reg = mei_mecbrw_read(dev);
+ u32 reg = mei_me_mecbrw_read(dev);
memcpy(reg_buf, ®, buffer_length);
}
hcsr = mei_hcsr_read(hw) | H_IG;
mei_hcsr_set(hw, hcsr);
+ return 0;
}
+static const struct mei_hw_ops mei_me_hw_ops = {
+
+ .host_set_ready = mei_me_host_set_ready,
+ .host_is_ready = mei_me_host_is_ready,
+
+ .hw_is_ready = mei_me_hw_is_ready,
+ .hw_reset = mei_me_hw_reset,
+ .hw_config = mei_me_hw_config,
+
+ .intr_clear = mei_me_intr_clear,
+ .intr_enable = mei_me_intr_enable,
+ .intr_disable = mei_me_intr_disable,
+
+ .hbuf_free_slots = mei_me_hbuf_empty_slots,
+ .hbuf_is_ready = mei_me_hbuf_is_empty,
+ .hbuf_max_len = mei_me_hbuf_max_len,
+
+ .write = mei_me_write_message,
+
+ .rdbuf_full_slots = mei_me_count_full_read_slots,
+ .read_hdr = mei_me_mecbrw_read,
+ .read = mei_me_read_slots
+};
+
/**
* init_mei_device - allocates and initializes the mei device structure
*
@@ -422,6 +453,8 @@ struct mei_device *mei_me_dev_init(struct pci_dev *pdev)
INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
INIT_WORK(&dev->init_work, mei_host_client_init);
+ dev->ops = &mei_me_hw_ops;
+
dev->pdev = pdev;
return dev;
}
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 53bcc00..9a3aaab 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -36,29 +36,10 @@ struct mei_me_hw {
struct mei_device *mei_me_dev_init(struct pci_dev *pdev);
-void mei_read_slots(struct mei_device *dev,
- unsigned char *buffer,
- unsigned long buffer_length);
-
-int mei_write_message(struct mei_device *dev,
- struct mei_msg_hdr *header,
- unsigned char *buf);
-
-bool mei_hbuf_is_empty(struct mei_device *dev);
-
-int mei_hbuf_empty_slots(struct mei_device *dev);
-
-static inline size_t mei_hbuf_max_data(const struct mei_device *dev)
-{
- return dev->hbuf_depth * sizeof(u32) - sizeof(struct mei_msg_hdr);
-}
-
/* get slots (dwords) from a message length + header (bytes) */
static inline unsigned char mei_data2slots(size_t length)
{
return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
}
-int mei_count_full_read_slots(struct mei_device *dev);
-
#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 1e1876f..51a005e 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -104,7 +104,7 @@ int mei_hw_init(struct mei_device *dev)
goto err;
}
- if (!mei_me_is_ready(dev)) {
+ if (!mei_hw_is_ready(dev)) {
dev_err(&dev->pdev->dev, "ME is not ready.\n");
goto err;
}
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index b04ed9b..431aa91 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -329,7 +329,7 @@ static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list,
int ret = 0;
if (!dev->rd_msg_hdr) {
- dev->rd_msg_hdr = mei_mecbrw_read(dev);
+ dev->rd_msg_hdr = mei_read_hdr(dev);
dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
(*slots)--;
dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
@@ -430,7 +430,7 @@ static int mei_irq_thread_write_handler(struct mei_device *dev,
s32 slots;
int ret;
- if (!mei_hbuf_is_empty(dev)) {
+ if (!mei_hbuf_is_ready(dev)) {
dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
return 0;
}
@@ -698,7 +698,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
mei_clear_interrupts(dev);
/* check if ME wants a reset */
- if (!mei_me_is_ready(dev) &&
+ if (!mei_hw_is_ready(dev) &&
dev->dev_state != MEI_DEV_RESETING &&
dev->dev_state != MEI_DEV_INITIALIZING) {
dev_dbg(&dev->pdev->dev, "FW not ready.\n");
@@ -709,7 +709,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
/* check if we need to start the dev */
if (!mei_host_is_ready(dev)) {
- if (mei_me_is_ready(dev)) {
+ if (mei_hw_is_ready(dev)) {
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
mei_host_set_ready(dev);
@@ -743,7 +743,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
rets = mei_irq_thread_write_handler(dev, &complete_list);
end:
dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
- dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev);
+ dev->mei_host_buffer_is_empty = mei_hbuf_is_ready(dev);
bus_message_received = false;
if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 018623c..843ae2f 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -462,8 +462,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
}
dev->mei_host_buffer_is_empty = false;
- if (length > mei_hbuf_max_data(dev)) {
- mei_hdr.length = mei_hbuf_max_data(dev);
+ if (length > mei_hbuf_max_len(dev)) {
+ mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
} else {
mei_hdr.length = length;
@@ -765,4 +765,5 @@ void mei_deregister(void)
mei_misc_device.parent = NULL;
}
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index bb759fd..c974292 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -211,6 +211,58 @@ struct mei_cl {
struct mei_cl_cb *read_cb;
};
+/** struct mei_hw_ops
+ *
+ * @host_set_ready - notify FW that host side is ready
+ * @host_is_ready - query for host readiness
+
+ * @hw_is_ready - query if hw is ready
+ * @hw_reset - reset hw
+ * @hw_config - configure hw
+
+ * @intr_clear - clear pending interrupts
+ * @intr_enable - enable interrupts
+ * @intr_disable - disable interrupts
+
+ * @hbuf_free_slots - query for write buffer empty slots
+ * @hbuf_is_ready - query if write buffer is empty
+ * @hbuf_max_len - query for write buffer max len
+
+ * @write - write a message to FW
+
+ * @rdbuf_full_slots - query how many slots are filled
+
+ * @read_hdr - get first 4 bytes (header)
+ * @read - read a buffer from the FW
+ */
+struct mei_hw_ops {
+
+ void (*host_set_ready) (struct mei_device *dev);
+ bool (*host_is_ready) (struct mei_device *dev);
+
+ bool (*hw_is_ready) (struct mei_device *dev);
+ void (*hw_reset) (struct mei_device *dev, bool enable);
+ void (*hw_config) (struct mei_device *dev);
+
+ void (*intr_clear) (struct mei_device *dev);
+ void (*intr_enable) (struct mei_device *dev);
+ void (*intr_disable) (struct mei_device *dev);
+
+ int (*hbuf_free_slots) (struct mei_device *dev);
+ bool (*hbuf_is_ready) (struct mei_device *dev);
+ size_t (*hbuf_max_len) (const struct mei_device *dev);
+
+ int (*write)(struct mei_device *dev,
+ struct mei_msg_hdr *hdr,
+ unsigned char *buf);
+
+ int (*rdbuf_full_slots)(struct mei_device *dev);
+
+ u32 (*read_hdr)(const struct mei_device *dev);
+ int (*read) (struct mei_device *dev,
+ unsigned char *buf, unsigned long len);
+};
+
/**
* struct mei_device - MEI private device struct
* @mem_addr - mem mapped base register address
@@ -306,6 +358,8 @@ struct mei_device {
bool iamthif_canceled;
struct work_struct init_work;
+
+ const struct mei_hw_ops *ops;
char hw[0] __aligned(sizeof(void *));
};
@@ -376,26 +430,84 @@ void mei_watchdog_register(struct mei_device *dev);
*/
void mei_watchdog_unregister(struct mei_device *dev);
-
/*
* Register Access Function
*/
-void mei_hw_config(struct mei_device *dev);
-void mei_hw_reset(struct mei_device *dev, bool intr_enable);
-u32 mei_mecbrw_read(const struct mei_device *dev);
+static inline void mei_hw_config(struct mei_device *dev)
+{
+ dev->ops->hw_config(dev);
+}
+static inline void mei_hw_reset(struct mei_device *dev, bool enable)
+{
+ dev->ops->hw_reset(dev, enable);
+}
+
+static inline void mei_clear_interrupts(struct mei_device *dev)
+{
+ dev->ops->intr_clear(dev);
+}
+
+static inline void mei_enable_interrupts(struct mei_device *dev)
+{
+ dev->ops->intr_enable(dev);
+}
+static inline void mei_disable_interrupts(struct mei_device *dev)
+{
+ dev->ops->intr_disable(dev);
+}
+static inline void mei_host_set_ready(struct mei_device *dev)
+{
+ dev->ops->host_set_ready(dev);
+}
+static inline bool mei_host_is_ready(struct mei_device *dev)
+{
+ return dev->ops->host_is_ready(dev);
+}
+static inline bool mei_hw_is_ready(struct mei_device *dev)
+{
+ return dev->ops->hw_is_ready(dev);
+}
-void mei_clear_interrupts(struct mei_device *dev);
-void mei_enable_interrupts(struct mei_device *dev);
-void mei_disable_interrupts(struct mei_device *dev);
+static inline bool mei_hbuf_is_ready(struct mei_device *dev)
+{
+ return dev->ops->hbuf_is_ready(dev);
+}
-void mei_host_set_ready(struct mei_device *dev);
-bool mei_host_is_ready(struct mei_device *dev);
-bool mei_me_is_ready(struct mei_device *dev);
+static inline int mei_hbuf_empty_slots(struct mei_device *dev)
+{
+ return dev->ops->hbuf_free_slots(dev);
+}
+static inline size_t mei_hbuf_max_len(const struct mei_device *dev)
+{
+ return dev->ops->hbuf_max_len(dev);
+}
+static inline int mei_write_message(struct mei_device *dev,
+ struct mei_msg_hdr *hdr,
+ unsigned char *buf)
+{
+ return dev->ops->write(dev, hdr, buf);
+}
+
+static inline u32 mei_read_hdr(const struct mei_device *dev)
+{
+ return dev->ops->read_hdr(dev);
+}
+
+static inline void mei_read_slots(struct mei_device *dev,
+ unsigned char *buf, unsigned long len)
+{
+ dev->ops->read(dev, buf, len);
+}
+
+static inline int mei_count_full_read_slots(struct mei_device *dev)
+{
+ return dev->ops->rdbuf_full_slots(dev);
+}
int mei_register(struct device *dev);
void mei_deregister(void);
--
1.7.4.4
^ permalink raw reply [flat|nested] 7+ messages in thread* [char-misc-next 4/6] mei: move interrupt handlers to be me hw specific
2013-02-06 12:06 [char-misc-next 0/6] MEI and ME separation Tomas Winkler
` (2 preceding siblings ...)
2013-02-06 12:06 ` [char-misc-next 3/6] mei: separate compilation of the ME hardware specifics Tomas Winkler
@ 2013-02-06 12:06 ` Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 5/6] mei: rename to mei_host_buffer_is_empty to hbuf_is_ready Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 6/6] mei: move clients cleanup code from init.c to client.c Tomas Winkler
5 siblings, 0 replies; 7+ messages in thread
From: Tomas Winkler @ 2013-02-06 12:06 UTC (permalink / raw)
To: gregkh; +Cc: arnd, alan, linux-kernel, Tomas Winkler
interrupt handler are platform specifics so we move
them to hw-mei.c. For sake of that we need to export
write, read, and complete handlers from the interrupt.c
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
drivers/misc/mei/hw-me.c | 164 +++++++++++++++++++++++++++++++++++------
drivers/misc/mei/hw-me.h | 3 +
drivers/misc/mei/interrupt.c | 126 ++------------------------------
drivers/misc/mei/mei_dev.h | 9 ++-
drivers/misc/mei/pci-me.c | 12 ++--
5 files changed, 164 insertions(+), 150 deletions(-)
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 6300943..3bebf8d 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -15,11 +15,16 @@
*/
#include <linux/pci.h>
-#include <linux/mei.h>
+
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
#include "mei_dev.h"
#include "hw-me.h"
+#include "hbm.h"
+
+
/**
* mei_reg_read - Reads 32bit data from the mei device
*
@@ -218,29 +223,6 @@ static bool mei_me_hw_is_ready(struct mei_device *dev)
}
/**
- * mei_interrupt_quick_handler - The ISR of the MEI device
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- */
-irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
-{
- struct mei_device *dev = (struct mei_device *) dev_id;
- struct mei_me_hw *hw = to_me_hw(dev);
- u32 csr_reg = mei_hcsr_read(hw);
-
- if ((csr_reg & H_IS) != H_IS)
- return IRQ_NONE;
-
- /* clear H_IS bit in H_CSR */
- mei_reg_write(hw, H_CSR, csr_reg);
-
- return IRQ_WAKE_THREAD;
-}
-
-/**
* mei_hbuf_filled_slots - gets number of device filled buffer slots
*
* @dev: the device structure
@@ -403,6 +385,139 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer,
return 0;
}
+/**
+ * mei_me_irq_quick_handler - The ISR of the MEI device
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ */
+
+irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
+{
+ struct mei_device *dev = (struct mei_device *) dev_id;
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 csr_reg = mei_hcsr_read(hw);
+
+ if ((csr_reg & H_IS) != H_IS)
+ return IRQ_NONE;
+
+ /* clear H_IS bit in H_CSR */
+ mei_reg_write(hw, H_CSR, csr_reg);
+
+ return IRQ_WAKE_THREAD;
+}
+
+/**
+ * mei_me_irq_thread_handler - function called after ISR to handle the interrupt
+ * processing.
+ *
+ * @irq: The irq number
+ * @dev_id: pointer to the device structure
+ *
+ * returns irqreturn_t
+ *
+ */
+irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
+{
+ struct mei_device *dev = (struct mei_device *) dev_id;
+ struct mei_cl_cb complete_list;
+ struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+ struct mei_cl *cl;
+ s32 slots;
+ int rets;
+ bool bus_message_received;
+
+
+ dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
+ /* initialize our complete list */
+ mutex_lock(&dev->device_lock);
+ mei_io_list_init(&complete_list);
+
+ /* Ack the interrupt here
+ * In case of MSI we don't go through the quick handler */
+ if (pci_dev_msi_enabled(dev->pdev))
+ mei_clear_interrupts(dev);
+
+ /* check if ME wants a reset */
+ if (!mei_hw_is_ready(dev) &&
+ dev->dev_state != MEI_DEV_RESETING &&
+ dev->dev_state != MEI_DEV_INITIALIZING) {
+ dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+ mei_reset(dev, 1);
+ mutex_unlock(&dev->device_lock);
+ return IRQ_HANDLED;
+ }
+
+ /* check if we need to start the dev */
+ if (!mei_host_is_ready(dev)) {
+ if (mei_hw_is_ready(dev)) {
+ dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
+
+ mei_host_set_ready(dev);
+
+ dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
+ /* link is established * start sending messages. */
+
+ dev->dev_state = MEI_DEV_INIT_CLIENTS;
+
+ mei_hbm_start_req(dev);
+ mutex_unlock(&dev->device_lock);
+ return IRQ_HANDLED;
+ } else {
+ dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+ mutex_unlock(&dev->device_lock);
+ return IRQ_HANDLED;
+ }
+ }
+ /* check slots available for reading */
+ slots = mei_count_full_read_slots(dev);
+ while (slots > 0) {
+ /* we have urgent data to send so break the read */
+ if (dev->wr_ext_msg.hdr.length)
+ break;
+ dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots);
+ dev_dbg(&dev->pdev->dev, "call mei_irq_read_handler.\n");
+ rets = mei_irq_read_handler(dev, &complete_list, &slots);
+ if (rets)
+ goto end;
+ }
+ rets = mei_irq_write_handler(dev, &complete_list);
+end:
+ dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
+ dev->mei_host_buffer_is_empty = mei_hbuf_is_ready(dev);
+
+ bus_message_received = false;
+ if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
+ dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
+ bus_message_received = true;
+ }
+ mutex_unlock(&dev->device_lock);
+ if (bus_message_received) {
+ dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
+ wake_up_interruptible(&dev->wait_recvd_msg);
+ bus_message_received = false;
+ }
+ if (list_empty(&complete_list.list))
+ return IRQ_HANDLED;
+
+
+ list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
+ cl = cb_pos->cl;
+ list_del(&cb_pos->list);
+ if (cl) {
+ if (cl != &dev->iamthif_cl) {
+ dev_dbg(&dev->pdev->dev, "completing call back.\n");
+ mei_irq_complete_handler(cl, cb_pos);
+ cb_pos = NULL;
+ } else if (cl == &dev->iamthif_cl) {
+ mei_amthif_complete(dev, cb_pos);
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
static const struct mei_hw_ops mei_me_hw_ops = {
.host_set_ready = mei_me_host_set_ready,
@@ -458,3 +573,4 @@ struct mei_device *mei_me_dev_init(struct pci_dev *pdev)
dev->pdev = pdev;
return dev;
}
+
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 9a3aaab..8518d3e 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -42,4 +42,7 @@ static inline unsigned char mei_data2slots(size_t length)
return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
}
+irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id);
+irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id);
+
#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 431aa91..3535b26 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -30,12 +30,12 @@
/**
- * _mei_cmpl - processes completed operation.
+ * mei_complete_handler - processes completed operation.
*
* @cl: private data of the file object.
* @cb_pos: callback block.
*/
-static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
+void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
{
if (cb_pos->fop_type == MEI_FOP_WRITE) {
mei_io_cb_free(cb_pos);
@@ -313,15 +313,14 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
* mei_irq_thread_read_handler - bottom half read routine after ISR to
* handle the read processing.
*
- * @cmpl_list: An instance of our list structure
* @dev: the device structure
+ * @cmpl_list: An instance of our list structure
* @slots: slots to read.
*
* returns 0 on success, <0 on failure.
*/
-static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list,
- struct mei_device *dev,
- s32 *slots)
+int mei_irq_read_handler(struct mei_device *dev,
+ struct mei_cl_cb *cmpl_list, s32 *slots)
{
struct mei_msg_hdr *mei_hdr;
struct mei_cl *cl_pos = NULL;
@@ -412,15 +411,15 @@ end:
/**
- * mei_irq_thread_write_handler - bottom half write routine after
- * ISR to handle the write processing.
+ * mei_irq_write_handler - dispatch write requests
+ * after irq received
*
* @dev: the device structure
* @cmpl_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
*/
-static int mei_irq_thread_write_handler(struct mei_device *dev,
+int mei_irq_write_handler(struct mei_device *dev,
struct mei_cl_cb *cmpl_list)
{
@@ -666,112 +665,3 @@ out:
mutex_unlock(&dev->device_lock);
}
-/**
- * mei_interrupt_thread_handler - function called after ISR to handle the interrupt
- * processing.
- *
- * @irq: The irq number
- * @dev_id: pointer to the device structure
- *
- * returns irqreturn_t
- *
- */
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
-{
- struct mei_device *dev = (struct mei_device *) dev_id;
- struct mei_cl_cb complete_list;
- struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
- struct mei_cl *cl;
- s32 slots;
- int rets;
- bool bus_message_received;
-
-
- dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
- /* initialize our complete list */
- mutex_lock(&dev->device_lock);
- mei_io_list_init(&complete_list);
-
- /* Ack the interrupt here
- * In case of MSI we don't go through the quick handler */
- if (pci_dev_msi_enabled(dev->pdev))
- mei_clear_interrupts(dev);
-
- /* check if ME wants a reset */
- if (!mei_hw_is_ready(dev) &&
- dev->dev_state != MEI_DEV_RESETING &&
- dev->dev_state != MEI_DEV_INITIALIZING) {
- dev_dbg(&dev->pdev->dev, "FW not ready.\n");
- mei_reset(dev, 1);
- mutex_unlock(&dev->device_lock);
- return IRQ_HANDLED;
- }
-
- /* check if we need to start the dev */
- if (!mei_host_is_ready(dev)) {
- if (mei_hw_is_ready(dev)) {
- dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
-
- mei_host_set_ready(dev);
-
- dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
- /* link is established * start sending messages. */
-
- dev->dev_state = MEI_DEV_INIT_CLIENTS;
-
- mei_hbm_start_req(dev);
- mutex_unlock(&dev->device_lock);
- return IRQ_HANDLED;
- } else {
- dev_dbg(&dev->pdev->dev, "FW not ready.\n");
- mutex_unlock(&dev->device_lock);
- return IRQ_HANDLED;
- }
- }
- /* check slots available for reading */
- slots = mei_count_full_read_slots(dev);
- while (slots > 0) {
- /* we have urgent data to send so break the read */
- if (dev->wr_ext_msg.hdr.length)
- break;
- dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots);
- dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
- rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
- if (rets)
- goto end;
- }
- rets = mei_irq_thread_write_handler(dev, &complete_list);
-end:
- dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
- dev->mei_host_buffer_is_empty = mei_hbuf_is_ready(dev);
-
- bus_message_received = false;
- if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
- dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
- bus_message_received = true;
- }
- mutex_unlock(&dev->device_lock);
- if (bus_message_received) {
- dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
- wake_up_interruptible(&dev->wait_recvd_msg);
- bus_message_received = false;
- }
- if (list_empty(&complete_list.list))
- return IRQ_HANDLED;
-
-
- list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
- cl = cb_pos->cl;
- list_del(&cb_pos->list);
- if (cl) {
- if (cl != &dev->iamthif_cl) {
- dev_dbg(&dev->pdev->dev, "completing call back.\n");
- _mei_cmpl(cl, cb_pos);
- cb_pos = NULL;
- } else if (cl == &dev->iamthif_cl) {
- mei_amthif_complete(dev, cb_pos);
- }
- }
- }
- return IRQ_HANDLED;
-}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index c974292..7d07cef 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -379,9 +379,14 @@ int mei_hw_init(struct mei_device *dev);
/*
* MEI interrupt functions prototype
*/
-irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id);
-irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
+
void mei_timer(struct work_struct *work);
+int mei_irq_read_handler(struct mei_device *dev,
+ struct mei_cl_cb *cmpl_list, s32 *slots);
+
+int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
+
+void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos);
/*
* AMTHIF - AMT Host Interface Functions
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 27ac717..b40ec06 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -170,12 +170,12 @@ static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_dev_msi_enabled(pdev))
err = request_threaded_irq(pdev->irq,
NULL,
- mei_interrupt_thread_handler,
+ mei_me_irq_thread_handler,
IRQF_ONESHOT, KBUILD_MODNAME, dev);
else
err = request_threaded_irq(pdev->irq,
- mei_interrupt_quick_handler,
- mei_interrupt_thread_handler,
+ mei_me_irq_quick_handler,
+ mei_me_irq_thread_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (err) {
@@ -348,12 +348,12 @@ static int mei_pci_resume(struct device *device)
if (pci_dev_msi_enabled(pdev))
err = request_threaded_irq(pdev->irq,
NULL,
- mei_interrupt_thread_handler,
+ mei_me_irq_thread_handler,
IRQF_ONESHOT, KBUILD_MODNAME, dev);
else
err = request_threaded_irq(pdev->irq,
- mei_interrupt_quick_handler,
- mei_interrupt_thread_handler,
+ mei_me_irq_quick_handler,
+ mei_me_irq_thread_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (err) {
--
1.7.4.4
^ permalink raw reply [flat|nested] 7+ messages in thread* [char-misc-next 5/6] mei: rename to mei_host_buffer_is_empty to hbuf_is_ready
2013-02-06 12:06 [char-misc-next 0/6] MEI and ME separation Tomas Winkler
` (3 preceding siblings ...)
2013-02-06 12:06 ` [char-misc-next 4/6] mei: move interrupt handlers to be me hw specific Tomas Winkler
@ 2013-02-06 12:06 ` Tomas Winkler
2013-02-06 12:06 ` [char-misc-next 6/6] mei: move clients cleanup code from init.c to client.c Tomas Winkler
5 siblings, 0 replies; 7+ messages in thread
From: Tomas Winkler @ 2013-02-06 12:06 UTC (permalink / raw)
To: gregkh; +Cc: arnd, alan, linux-kernel, Tomas Winkler
we rename the mei_host_buffer_is_empty to keep naming
convention of hbuf and also make the query more generic
to be correct also for other under laying hardware
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
drivers/misc/mei/amthif.c | 8 ++++----
drivers/misc/mei/client.c | 13 ++++++-------
drivers/misc/mei/hw-me.c | 2 +-
drivers/misc/mei/main.c | 4 ++--
drivers/misc/mei/mei_dev.h | 14 ++++++++++----
drivers/misc/mei/wd.c | 9 ++++-----
6 files changed, 27 insertions(+), 23 deletions(-)
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index a7c4838..c86d7e3 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -297,9 +297,9 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
if (ret < 0)
return ret;
- if (ret && dev->mei_host_buffer_is_empty) {
+ if (ret && dev->hbuf_is_ready) {
ret = 0;
- dev->mei_host_buffer_is_empty = false;
+ dev->hbuf_is_ready = false;
if (cb->request_buffer.size > mei_hbuf_max_len(dev)) {
mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
@@ -330,7 +330,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
list_add_tail(&cb->list, &dev->write_list.list);
}
} else {
- if (!(dev->mei_host_buffer_is_empty))
+ if (!dev->hbuf_is_ready)
dev_dbg(&dev->pdev->dev, "host buffer is not empty");
dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n");
@@ -583,7 +583,7 @@ int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
dev->iamthif_msg_buf_index = 0;
dev->iamthif_msg_buf_size = 0;
dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
- dev->mei_host_buffer_is_empty = mei_hbuf_is_ready(dev);
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
return 0;
}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index a921001..e46663e 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -393,8 +393,8 @@ int mei_cl_disconnect(struct mei_cl *cl)
return -ENOMEM;
cb->fop_type = MEI_FOP_CLOSE;
- if (dev->mei_host_buffer_is_empty) {
- dev->mei_host_buffer_is_empty = false;
+ if (dev->hbuf_is_ready) {
+ dev->hbuf_is_ready = false;
if (mei_hbm_cl_disconnect_req(dev, cl)) {
rets = -ENODEV;
dev_err(&dev->pdev->dev, "failed to disconnect.\n");
@@ -496,9 +496,8 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
cb->fop_type = MEI_FOP_IOCTL;
- if (dev->mei_host_buffer_is_empty &&
- !mei_cl_is_other_connecting(cl)) {
- dev->mei_host_buffer_is_empty = false;
+ if (dev->hbuf_is_ready && !mei_cl_is_other_connecting(cl)) {
+ dev->hbuf_is_ready = false;
if (mei_hbm_cl_connect_req(dev, cl)) {
rets = -ENODEV;
@@ -661,8 +660,8 @@ int mei_cl_read_start(struct mei_cl *cl)
cb->fop_type = MEI_FOP_READ;
cl->read_cb = cb;
- if (dev->mei_host_buffer_is_empty) {
- dev->mei_host_buffer_is_empty = false;
+ if (dev->hbuf_is_ready) {
+ dev->hbuf_is_ready = false;
if (mei_hbm_cl_flow_control_req(dev, cl)) {
rets = -ENODEV;
goto err;
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 3bebf8d..45ea718 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -486,7 +486,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
rets = mei_irq_write_handler(dev, &complete_list);
end:
dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
- dev->mei_host_buffer_is_empty = mei_hbuf_is_ready(dev);
+ dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
bus_message_received = false;
if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 843ae2f..903f809 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -454,14 +454,14 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
if (rets < 0)
goto err;
- if (rets == 0 || dev->mei_host_buffer_is_empty == false) {
+ if (rets == 0 || !dev->hbuf_is_ready) {
write_cb->buf_idx = 0;
mei_hdr.msg_complete = 0;
cl->writing_state = MEI_WRITING;
goto out;
}
- dev->mei_host_buffer_is_empty = false;
+ dev->hbuf_is_ready = false;
if (length > mei_hbuf_max_len(dev)) {
mei_hdr.length = mei_hbuf_max_len(dev);
mei_hdr.msg_complete = 0;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 7d07cef..cb80166 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -265,9 +265,13 @@ struct mei_hw_ops {
/**
* struct mei_device - MEI private device struct
+
* @mem_addr - mem mapped base register address
- * @hbuf_depth - depth of host(write) buffer
- * @wr_ext_msg - buffer for hbm control responses (set in read cycle)
+
+ * @hbuf_depth - depth of hardware host/write buffer is slots
+ * @hbuf_is_ready - query if the host host/write buffer is ready
+ * @wr_msg - the buffer for hbm control messages
+ * @wr_ext_msg - the buffer for hbm control responses (set in read cycle)
*/
struct mei_device {
struct pci_dev *pdev; /* pointer to pci device struct */
@@ -294,7 +298,6 @@ struct mei_device {
struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
bool recvd_msg;
- u8 hbuf_depth;
/*
* waiting queue for receive message from FW
*/
@@ -311,6 +314,10 @@ struct mei_device {
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
u32 rd_msg_hdr;
+ /* write buffer */
+ u8 hbuf_depth;
+ bool hbuf_is_ready;
+
/* used for control messages */
struct {
struct mei_msg_hdr hdr;
@@ -330,7 +337,6 @@ struct mei_device {
u8 me_clients_num;
u8 me_client_presentation_num;
u8 me_client_index;
- bool mei_host_buffer_is_empty;
struct mei_cl wd_cl;
enum mei_wd_states wd_state;
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 77b3820..2413247 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -157,9 +157,9 @@ int mei_wd_stop(struct mei_device *dev)
if (ret < 0)
goto out;
- if (ret && dev->mei_host_buffer_is_empty) {
+ if (ret && dev->hbuf_is_ready) {
ret = 0;
- dev->mei_host_buffer_is_empty = false;
+ dev->hbuf_is_ready = false;
if (!mei_wd_send(dev)) {
ret = mei_cl_flow_ctrl_reduce(&dev->wd_cl);
@@ -282,10 +282,9 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
dev->wd_state = MEI_WD_RUNNING;
/* Check if we can send the ping to HW*/
- if (dev->mei_host_buffer_is_empty &&
- mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
+ if (dev->hbuf_is_ready && mei_cl_flow_ctrl_creds(&dev->wd_cl) > 0) {
- dev->mei_host_buffer_is_empty = false;
+ dev->hbuf_is_ready = false;
dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
if (mei_wd_send(dev)) {
--
1.7.4.4
^ permalink raw reply [flat|nested] 7+ messages in thread* [char-misc-next 6/6] mei: move clients cleanup code from init.c to client.c
2013-02-06 12:06 [char-misc-next 0/6] MEI and ME separation Tomas Winkler
` (4 preceding siblings ...)
2013-02-06 12:06 ` [char-misc-next 5/6] mei: rename to mei_host_buffer_is_empty to hbuf_is_ready Tomas Winkler
@ 2013-02-06 12:06 ` Tomas Winkler
5 siblings, 0 replies; 7+ messages in thread
From: Tomas Winkler @ 2013-02-06 12:06 UTC (permalink / raw)
To: gregkh; +Cc: arnd, alan, linux-kernel, Tomas Winkler
during reset we clean up client data structures
we move that code into wrappers in client
and call the wrappers
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
drivers/misc/mei/client.c | 51 +++++++++++++++++++++++++++++++++++++++++++++
drivers/misc/mei/client.h | 5 ++++
drivers/misc/mei/init.c | 28 +++++-------------------
3 files changed, 62 insertions(+), 22 deletions(-)
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index e46663e..1569afe 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -676,3 +676,54 @@ err:
return rets;
}
+/**
+ * mei_cl_all_disconnect - disconnect forcefully all connected clients
+ *
+ * @dev - mei device
+ */
+
+void mei_cl_all_disconnect(struct mei_device *dev)
+{
+ struct mei_cl *cl, *next;
+
+ list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ cl->state = MEI_FILE_DISCONNECTED;
+ cl->mei_flow_ctrl_creds = 0;
+ cl->read_cb = NULL;
+ cl->timer_count = 0;
+ }
+}
+
+
+/**
+ * mei_cl_all_read_wakeup - wake up all readings so they can be interrupted
+ *
+ * @dev - mei device
+ */
+void mei_cl_all_read_wakeup(struct mei_device *dev)
+{
+ struct mei_cl *cl, *next;
+ list_for_each_entry_safe(cl, next, &dev->file_list, link) {
+ if (waitqueue_active(&cl->rx_wait)) {
+ dev_dbg(&dev->pdev->dev, "Waking up client!\n");
+ wake_up_interruptible(&cl->rx_wait);
+ }
+ }
+}
+
+/**
+ * mei_cl_all_write_clear - clear all pending writes
+
+ * @dev - mei device
+ */
+void mei_cl_all_write_clear(struct mei_device *dev)
+{
+ struct mei_cl_cb *cb, *next;
+
+ list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
+ list_del(&cb->list);
+ mei_io_cb_free(cb);
+ }
+}
+
+
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 240a1f3..214b239 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -94,4 +94,9 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file);
void mei_host_client_init(struct work_struct *work);
+void mei_cl_all_disconnect(struct mei_device *dev);
+void mei_cl_all_read_wakeup(struct mei_device *dev);
+void mei_cl_all_write_clear(struct mei_device *dev);
+
+
#endif /* _MEI_CLIENT_H_ */
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 51a005e..6ec5301 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -135,10 +135,6 @@ err:
*/
void mei_reset(struct mei_device *dev, int interrupts_enabled)
{
- struct mei_cl *cl_pos = NULL;
- struct mei_cl *cl_next = NULL;
- struct mei_cl_cb *cb_pos = NULL;
- struct mei_cl_cb *cb_next = NULL;
bool unexpected;
if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET)
@@ -157,13 +153,8 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev->dev_state != MEI_DEV_POWER_DOWN)
dev->dev_state = MEI_DEV_RESETING;
- list_for_each_entry_safe(cl_pos,
- cl_next, &dev->file_list, link) {
- cl_pos->state = MEI_FILE_DISCONNECTED;
- cl_pos->mei_flow_ctrl_creds = 0;
- cl_pos->read_cb = NULL;
- cl_pos->timer_count = 0;
- }
+ mei_cl_all_disconnect(dev);
+
/* remove entry if already in list */
dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n");
mei_cl_unlink(&dev->wd_cl);
@@ -185,18 +176,11 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
- /* Wake up all readings so they can be interrupted */
- list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
- if (waitqueue_active(&cl_pos->rx_wait)) {
- dev_dbg(&dev->pdev->dev, "Waking up client!\n");
- wake_up_interruptible(&cl_pos->rx_wait);
- }
- }
+ /* wake up all readings so they can be interrupted */
+ mei_cl_all_read_wakeup(dev);
+
/* remove all waiting requests */
- list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) {
- list_del(&cb_pos->list);
- mei_io_cb_free(cb_pos);
- }
+ mei_cl_all_write_clear(dev);
}
--
1.7.4.4
^ permalink raw reply [flat|nested] 7+ messages in thread