diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-22 19:54:53 (GMT) |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-22 20:01:40 (GMT) |
commit | ae19ffbadc1b2100285a5b5b3d0a4e0a11390904 (patch) | |
tree | 3c2086ab67398a019089a47ca3f362a4bc6db74f /drivers/staging/heci/heci_main.c | |
parent | 34e84f39a27d059a3e6ec6e8b94aafa702e6f220 (diff) | |
parent | 9173a8ef24a6b1b8031507b35b8ffe5f85a87692 (diff) | |
download | linux-fsl-qoriq-ae19ffbadc1b2100285a5b5b3d0a4e0a11390904.tar.xz |
Merge branch 'master' into for-linus
Diffstat (limited to 'drivers/staging/heci/heci_main.c')
-rw-r--r-- | drivers/staging/heci/heci_main.c | 1576 |
1 files changed, 0 insertions, 1576 deletions
diff --git a/drivers/staging/heci/heci_main.c b/drivers/staging/heci/heci_main.c deleted file mode 100644 index ddf4822..0000000 --- a/drivers/staging/heci/heci_main.c +++ /dev/null @@ -1,1576 +0,0 @@ -/* - * Part of Intel(R) Manageability Engine Interface Linux driver - * - * Copyright (c) 2003 - 2008 Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ - - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/kernel.h> -#include <linux/slab.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/reboot.h> -#include <linux/poll.h> -#include <linux/init.h> -#include <linux/kdev_t.h> -#include <linux/ioctl.h> -#include <linux/cdev.h> -#include <linux/device.h> -#include <linux/unistd.h> -#include <linux/kthread.h> - -#include "heci.h" -#include "heci_interface.h" -#include "heci_version.h" - - -#define HECI_READ_TIMEOUT 45 - -#define HECI_DRIVER_NAME "heci" - -/* - * heci driver strings - */ -static char heci_driver_name[] = HECI_DRIVER_NAME; -static char heci_driver_string[] = "Intel(R) Management Engine Interface"; -static char heci_driver_version[] = HECI_DRIVER_VERSION; -static char heci_copyright[] = "Copyright (c) 2003 - 2008 Intel Corporation."; - - -#ifdef HECI_DEBUG -int heci_debug = 1; -#else -int heci_debug; -#endif -MODULE_PARM_DESC(heci_debug, "Debug enabled or not"); -module_param(heci_debug, int, 0644); - - -#define HECI_DEV_NAME "heci" - -/* heci char device for registration */ -static struct cdev heci_cdev; - -/* major number for device */ -static int heci_major; -/* The device pointer */ -static struct pci_dev *heci_device; - -static struct class *heci_class; - - -/* heci_pci_tbl - PCI Device ID Table */ -static struct pci_device_id heci_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82946GZ)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82G35)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82Q965)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82G965)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82GM965)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82GME965)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82Q35)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82G33)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82Q33)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82X38)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_3200)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_6)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_7)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_8)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_9)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_10)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_3)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_4)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_3)}, - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_4)}, - /* required last entry */ - {0, } -}; - -MODULE_DEVICE_TABLE(pci, heci_pci_tbl); - -/* - * Local Function Prototypes - */ -static int __init heci_init_module(void); -static void __exit heci_exit_module(void); -static int __devinit heci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent); -static void __devexit heci_remove(struct pci_dev *pdev); -static int heci_open(struct inode *inode, struct file *file); -static int heci_release(struct inode *inode, struct file *file); -static ssize_t heci_read(struct file *file, char __user *ubuf, - size_t length, loff_t *offset); -static int heci_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long data); -static ssize_t heci_write(struct file *file, const char __user *ubuf, - size_t length, loff_t *offset); -static unsigned int heci_poll(struct file *file, poll_table *wait); -static struct heci_cb_private *find_read_list_entry( - struct iamt_heci_device *dev, - struct heci_file_private *file_ext); -#ifdef CONFIG_PM -static int heci_suspend(struct pci_dev *pdev, pm_message_t state); -static int heci_resume(struct pci_dev *pdev); -static __u16 g_sus_wd_timeout; -#else -#define heci_suspend NULL -#define heci_resume NULL -#endif -/* - * PCI driver structure - */ -static struct pci_driver heci_driver = { - .name = heci_driver_name, - .id_table = heci_pci_tbl, - .probe = heci_probe, - .remove = __devexit_p(heci_remove), - .shutdown = __devexit_p(heci_remove), - .suspend = heci_suspend, - .resume = heci_resume -}; - -/* - * file operations structure will be use heci char device. - */ -static const struct file_operations heci_fops = { - .owner = THIS_MODULE, - .read = heci_read, - .ioctl = heci_ioctl, - .open = heci_open, - .release = heci_release, - .write = heci_write, - .poll = heci_poll, -}; - -/** - * heci_registration_cdev - set up the cdev structure for heci device. - * - * @dev: char device struct - * @hminor: minor number for registration char device - * @fops: file operations structure - * - * returns 0 on success, <0 on failure. - */ -static int heci_registration_cdev(struct cdev *dev, int hminor, - const struct file_operations *fops) -{ - int ret, devno = MKDEV(heci_major, hminor); - - cdev_init(dev, fops); - dev->owner = THIS_MODULE; - ret = cdev_add(dev, devno, 1); - /* Fail gracefully if need be */ - if (ret) { - printk(KERN_ERR "heci: Error %d registering heci device %d\n", - ret, hminor); - } - return ret; -} - -/* Display the version of heci driver. */ -static ssize_t version_show(struct class *dev, char *buf) -{ - return sprintf(buf, "%s %s.\n", - heci_driver_string, heci_driver_version); -} - -static CLASS_ATTR(version, S_IRUGO, version_show, NULL); - -/** - * heci_register_cdev - registers heci char device - * - * returns 0 on success, <0 on failure. - */ -static int heci_register_cdev(void) -{ - int ret; - dev_t dev; - - /* registration of char devices */ - ret = alloc_chrdev_region(&dev, HECI_MINORS_BASE, HECI_MINORS_COUNT, - HECI_DRIVER_NAME); - if (ret) { - printk(KERN_ERR "heci: Error allocating char device region.\n"); - return ret; - } - - heci_major = MAJOR(dev); - - ret = heci_registration_cdev(&heci_cdev, HECI_MINOR_NUMBER, - &heci_fops); - if (ret) - unregister_chrdev_region(MKDEV(heci_major, HECI_MINORS_BASE), - HECI_MINORS_COUNT); - - return ret; -} - -/** - * heci_unregister_cdev - unregisters heci char device - */ -static void heci_unregister_cdev(void) -{ - cdev_del(&heci_cdev); - unregister_chrdev_region(MKDEV(heci_major, HECI_MINORS_BASE), - HECI_MINORS_COUNT); -} - -#ifndef HECI_DEVICE_CREATE -#define HECI_DEVICE_CREATE device_create -#endif -/** - * heci_sysfs_device_create - adds device entry to sysfs - * - * returns 0 on success, <0 on failure. - */ -static int heci_sysfs_device_create(void) -{ - struct class *class; - void *tmphdev; - int err = 0; - - class = class_create(THIS_MODULE, HECI_DRIVER_NAME); - if (IS_ERR(class)) { - err = PTR_ERR(class); - printk(KERN_ERR "heci: Error creating heci class.\n"); - goto err_out; - } - - err = class_create_file(class, &class_attr_version); - if (err) { - class_destroy(class); - printk(KERN_ERR "heci: Error creating heci class file.\n"); - goto err_out; - } - - tmphdev = HECI_DEVICE_CREATE(class, NULL, heci_cdev.dev, NULL, - HECI_DEV_NAME); - if (IS_ERR(tmphdev)) { - err = PTR_ERR(tmphdev); - class_remove_file(class, &class_attr_version); - class_destroy(class); - goto err_out; - } - - heci_class = class; -err_out: - return err; -} - -/** - * heci_sysfs_device_remove - unregisters the device entry on sysfs - */ -static void heci_sysfs_device_remove(void) -{ - if ((heci_class == NULL) || (IS_ERR(heci_class))) - return; - - device_destroy(heci_class, heci_cdev.dev); - class_remove_file(heci_class, &class_attr_version); - class_destroy(heci_class); -} - -/** - * heci_init_module - Driver Registration Routine - * - * heci_init_module is the first routine called when the driver is - * loaded. All it does is register with the PCI subsystem. - * - * returns 0 on success, <0 on failure. - */ -static int __init heci_init_module(void) -{ - int ret = 0; - - printk(KERN_INFO "heci: %s - version %s\n", heci_driver_string, - heci_driver_version); - printk(KERN_INFO "heci: %s\n", heci_copyright); - - /* init pci module */ - ret = pci_register_driver(&heci_driver); - if (ret < 0) { - printk(KERN_ERR "heci: Error registering driver.\n"); - goto end; - } - - ret = heci_register_cdev(); - if (ret) - goto unregister_pci; - - ret = heci_sysfs_device_create(); - if (ret) - goto unregister_cdev; - - return ret; - -unregister_cdev: - heci_unregister_cdev(); -unregister_pci: - pci_unregister_driver(&heci_driver); -end: - return ret; -} - -module_init(heci_init_module); - - -/** - * heci_exit_module - Driver Exit Cleanup Routine - * - * heci_exit_module is called just before the driver is removed - * from memory. - */ -static void __exit heci_exit_module(void) -{ - pci_unregister_driver(&heci_driver); - heci_sysfs_device_remove(); - heci_unregister_cdev(); -} - -module_exit(heci_exit_module); - - -/** - * heci_probe - Device Initialization Routine - * - * @pdev: PCI device information struct - * @ent: entry in kcs_pci_tbl - * - * returns 0 on success, <0 on failure. - */ -static int __devinit heci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct iamt_heci_device *dev = NULL; - int i, err = 0; - - if (heci_device) { - err = -EEXIST; - goto end; - } - /* enable pci dev */ - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "heci: Failed to enable pci device.\n"); - goto end; - } - /* set PCI host mastering */ - pci_set_master(pdev); - /* pci request regions for heci driver */ - err = pci_request_regions(pdev, heci_driver_name); - if (err) { - printk(KERN_ERR "heci: Failed to get pci regions.\n"); - goto disable_device; - } - /* allocates and initializes the heci dev structure */ - dev = init_heci_device(pdev); - if (!dev) { - err = -ENOMEM; - goto release_regions; - } - /* mapping IO device memory */ - for (i = 0; i <= 5; i++) { - if (pci_resource_len(pdev, i) == 0) - continue; - if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { - printk(KERN_ERR "heci: heci has IO ports.\n"); - goto free_device; - } else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { - if (dev->mem_base) { - printk(KERN_ERR - "heci: Too many mem addresses.\n"); - goto free_device; - } - dev->mem_base = pci_resource_start(pdev, i); - dev->mem_length = pci_resource_len(pdev, i); - } - } - if (!dev->mem_base) { - printk(KERN_ERR "heci: No address to use.\n"); - err = -ENODEV; - goto free_device; - } - dev->mem_addr = ioremap_nocache(dev->mem_base, - dev->mem_length); - if (!dev->mem_addr) { - printk(KERN_ERR "heci: Remap IO device memory failure.\n"); - err = -ENOMEM; - goto free_device; - } - /* request and enable interrupt */ - err = request_irq(pdev->irq, heci_isr_interrupt, IRQF_SHARED, - heci_driver_name, dev); - if (err) { - printk(KERN_ERR "heci: Request_irq failure. irq = %d \n", - pdev->irq); - goto unmap_memory; - } - - if (heci_hw_init(dev)) { - printk(KERN_ERR "heci: Init hw failure.\n"); - err = -ENODEV; - goto release_irq; - } - init_timer(&dev->wd_timer); - - heci_initialize_clients(dev); - if (dev->heci_state != HECI_ENABLED) { - err = -ENODEV; - goto release_hw; - } - - spin_lock_bh(&dev->device_lock); - heci_device = pdev; - pci_set_drvdata(pdev, dev); - spin_unlock_bh(&dev->device_lock); - - if (dev->wd_timeout) - mod_timer(&dev->wd_timer, jiffies); - -#ifdef CONFIG_PM - g_sus_wd_timeout = 0; -#endif - printk(KERN_INFO "heci driver initialization successful.\n"); - return 0; - -release_hw: - /* disable interrupts */ - dev->host_hw_state = read_heci_register(dev, H_CSR); - heci_csr_disable_interrupts(dev); - - del_timer_sync(&dev->wd_timer); - - flush_scheduled_work(); - -release_irq: - free_irq(pdev->irq, dev); -unmap_memory: - if (dev->mem_addr) - iounmap(dev->mem_addr); -free_device: - kfree(dev); -release_regions: - pci_release_regions(pdev); -disable_device: - pci_disable_device(pdev); -end: - printk(KERN_ERR "heci driver initialization failed.\n"); - return err; -} - -/** - * heci_remove - Device Removal Routine - * - * @pdev: PCI device information struct - * - * heci_remove is called by the PCI subsystem to alert the driver - * that it should release a PCI device. - */ -static void __devexit heci_remove(struct pci_dev *pdev) -{ - struct iamt_heci_device *dev = pci_get_drvdata(pdev); - - if (heci_device != pdev) - return; - - if (dev == NULL) - return; - - spin_lock_bh(&dev->device_lock); - if (heci_device != pdev) { - spin_unlock_bh(&dev->device_lock); - return; - } - - if (dev->reinit_tsk != NULL) { - kthread_stop(dev->reinit_tsk); - dev->reinit_tsk = NULL; - } - - del_timer_sync(&dev->wd_timer); - if (dev->wd_file_ext.state == HECI_FILE_CONNECTED - && dev->wd_timeout) { - dev->wd_timeout = 0; - dev->wd_due_counter = 0; - memcpy(dev->wd_data, heci_stop_wd_params, HECI_WD_PARAMS_SIZE); - dev->stop = 1; - if (dev->host_buffer_is_empty && - flow_ctrl_creds(dev, &dev->wd_file_ext)) { - dev->host_buffer_is_empty = 0; - - if (!heci_send_wd(dev)) - DBG("send stop WD failed\n"); - else - flow_ctrl_reduce(dev, &dev->wd_file_ext); - - dev->wd_pending = 0; - } else { - dev->wd_pending = 1; - } - dev->wd_stoped = 0; - spin_unlock_bh(&dev->device_lock); - - wait_event_interruptible_timeout(dev->wait_stop_wd, - (dev->wd_stoped), 10 * HZ); - spin_lock_bh(&dev->device_lock); - if (!dev->wd_stoped) - DBG("stop wd failed to complete.\n"); - else - DBG("stop wd complete.\n"); - - } - - heci_device = NULL; - spin_unlock_bh(&dev->device_lock); - - if (dev->iamthif_file_ext.state == HECI_FILE_CONNECTED) { - dev->iamthif_file_ext.state = HECI_FILE_DISCONNECTING; - heci_disconnect_host_client(dev, - &dev->iamthif_file_ext); - } - if (dev->wd_file_ext.state == HECI_FILE_CONNECTED) { - dev->wd_file_ext.state = HECI_FILE_DISCONNECTING; - heci_disconnect_host_client(dev, - &dev->wd_file_ext); - } - - spin_lock_bh(&dev->device_lock); - - /* remove entry if already in list */ - DBG("list del iamthif and wd file list.\n"); - heci_remove_client_from_file_list(dev, dev->wd_file_ext. - host_client_id); - heci_remove_client_from_file_list(dev, - dev->iamthif_file_ext.host_client_id); - - dev->iamthif_current_cb = NULL; - dev->iamthif_file_ext.file = NULL; - dev->num_heci_me_clients = 0; - - spin_unlock_bh(&dev->device_lock); - - flush_scheduled_work(); - - /* disable interrupts */ - heci_csr_disable_interrupts(dev); - - free_irq(pdev->irq, dev); - pci_set_drvdata(pdev, NULL); - - if (dev->mem_addr) - iounmap(dev->mem_addr); - - kfree(dev); - - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -/** - * heci_clear_list - remove all callbacks associated with file - * from heci_cb_list - * - * @file: file information struct - * @heci_cb_list: callbacks list - * - * heci_clear_list is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns 1 if callback removed from the list, 0 otherwise - */ -static int heci_clear_list(struct iamt_heci_device *dev, - struct file *file, struct list_head *heci_cb_list) -{ - struct heci_cb_private *priv_cb_pos = NULL; - struct heci_cb_private *priv_cb_next = NULL; - struct file *file_temp; - int rets = 0; - - /* list all list member */ - list_for_each_entry_safe(priv_cb_pos, priv_cb_next, - heci_cb_list, cb_list) { - file_temp = (struct file *)priv_cb_pos->file_object; - /* check if list member associated with a file */ - if (file_temp == file) { - /* remove member from the list */ - list_del(&priv_cb_pos->cb_list); - /* check if cb equal to current iamthif cb */ - if (dev->iamthif_current_cb == priv_cb_pos) { - dev->iamthif_current_cb = NULL; - /* send flow control to iamthif client */ - heci_send_flow_control(dev, - &dev->iamthif_file_ext); - } - /* free all allocated buffers */ - heci_free_cb_private(priv_cb_pos); - rets = 1; - } - } - return rets; -} - -/** - * heci_clear_lists - remove all callbacks associated with file - * - * @dev: device information struct - * @file: file information struct - * - * heci_clear_lists is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns 1 if callback removed from the list, 0 otherwise - */ -static int heci_clear_lists(struct iamt_heci_device *dev, struct file *file) -{ - int rets = 0; - - /* remove callbacks associated with a file */ - heci_clear_list(dev, file, &dev->pthi_cmd_list.heci_cb.cb_list); - if (heci_clear_list(dev, file, - &dev->pthi_read_complete_list.heci_cb.cb_list)) - rets = 1; - - heci_clear_list(dev, file, &dev->ctrl_rd_list.heci_cb.cb_list); - - if (heci_clear_list(dev, file, &dev->ctrl_wr_list.heci_cb.cb_list)) - rets = 1; - - if (heci_clear_list(dev, file, - &dev->write_waiting_list.heci_cb.cb_list)) - rets = 1; - - if (heci_clear_list(dev, file, &dev->write_list.heci_cb.cb_list)) - rets = 1; - - /* check if iamthif_current_cb not NULL */ - if (dev->iamthif_current_cb && (!rets)) { - /* check file and iamthif current cb association */ - if (dev->iamthif_current_cb->file_object == file) { - /* remove cb */ - heci_free_cb_private(dev->iamthif_current_cb); - dev->iamthif_current_cb = NULL; - rets = 1; - } - } - return rets; -} - -/** - * heci_open - the open function - * - * @inode: pointer to inode structure - * @file: pointer to file structure - * - * returns 0 on success, <0 on error - */ -static int heci_open(struct inode *inode, struct file *file) -{ - struct heci_file_private *file_ext; - int if_num = iminor(inode); - struct iamt_heci_device *dev; - - if (!heci_device) - return -ENODEV; - - dev = pci_get_drvdata(heci_device); - if ((if_num != HECI_MINOR_NUMBER) || (!dev)) - return -ENODEV; - - file_ext = heci_alloc_file_private(file); - if (file_ext == NULL) - return -ENOMEM; - - spin_lock_bh(&dev->device_lock); - if (dev->heci_state != HECI_ENABLED) { - spin_unlock_bh(&dev->device_lock); - kfree(file_ext); - return -ENODEV; - } - if (dev->open_handle_count >= HECI_MAX_OPEN_HANDLE_COUNT) { - spin_unlock_bh(&dev->device_lock); - kfree(file_ext); - return -ENFILE; - }; - dev->open_handle_count++; - list_add_tail(&file_ext->link, &dev->file_list); - while ((dev->heci_host_clients[dev->current_host_client_id / 8] - & (1 << (dev->current_host_client_id % 8))) != 0) { - - dev->current_host_client_id++; /* allow overflow */ - DBG("current_host_client_id = %d\n", - dev->current_host_client_id); - DBG("dev->open_handle_count = %lu\n", - dev->open_handle_count); - } - DBG("current_host_client_id = %d\n", dev->current_host_client_id); - file_ext->host_client_id = dev->current_host_client_id; - dev->heci_host_clients[file_ext->host_client_id / 8] |= - (1 << (file_ext->host_client_id % 8)); - spin_unlock_bh(&dev->device_lock); - spin_lock(&file_ext->file_lock); - spin_lock_bh(&dev->device_lock); - file_ext->state = HECI_FILE_INITIALIZING; - spin_unlock_bh(&dev->device_lock); - file_ext->sm_state = 0; - - file->private_data = file_ext; - spin_unlock(&file_ext->file_lock); - - return 0; -} - -/** - * heci_release - the release function - * - * @inode: pointer to inode structure - * @file: pointer to file structure - * - * returns 0 on success, <0 on error - */ -static int heci_release(struct inode *inode, struct file *file) -{ - int rets = 0; - int if_num = iminor(inode); - struct heci_file_private *file_ext = file->private_data; - struct heci_cb_private *priv_cb = NULL; - struct iamt_heci_device *dev; - - if (!heci_device) - return -ENODEV; - - dev = pci_get_drvdata(heci_device); - if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) - return -ENODEV; - - if (file_ext != &dev->iamthif_file_ext) { - spin_lock(&file_ext->file_lock); - spin_lock_bh(&dev->device_lock); - if (file_ext->state == HECI_FILE_CONNECTED) { - file_ext->state = HECI_FILE_DISCONNECTING; - spin_unlock_bh(&dev->device_lock); - spin_unlock(&file_ext->file_lock); - DBG("disconnecting client host client = %d, " - "ME client = %d\n", - file_ext->host_client_id, - file_ext->me_client_id); - rets = heci_disconnect_host_client(dev, file_ext); - spin_lock(&file_ext->file_lock); - spin_lock_bh(&dev->device_lock); - } - heci_flush_queues(dev, file_ext); - DBG("remove client host client = %d, ME client = %d\n", - file_ext->host_client_id, - file_ext->me_client_id); - - if (dev->open_handle_count > 0) { - dev->heci_host_clients[file_ext->host_client_id / 8] &= - ~(1 << (file_ext->host_client_id % 8)); - dev->open_handle_count--; - } - heci_remove_client_from_file_list(dev, - file_ext->host_client_id); - - /* free read cb */ - if (file_ext->read_cb != NULL) { - priv_cb = find_read_list_entry(dev, file_ext); - /* Remove entry from read list */ - if (priv_cb != NULL) - list_del(&priv_cb->cb_list); - - priv_cb = file_ext->read_cb; - file_ext->read_cb = NULL; - } - - spin_unlock_bh(&dev->device_lock); - file->private_data = NULL; - spin_unlock(&file_ext->file_lock); - - if (priv_cb != NULL) - heci_free_cb_private(priv_cb); - - kfree(file_ext); - } else { - spin_lock_bh(&dev->device_lock); - - if (dev->open_handle_count > 0) - dev->open_handle_count--; - - if (dev->iamthif_file_object == file - && dev->iamthif_state != HECI_IAMTHIF_IDLE) { - DBG("pthi canceled iamthif state %d\n", - dev->iamthif_state); - dev->iamthif_canceled = 1; - if (dev->iamthif_state == HECI_IAMTHIF_READ_COMPLETE) { - DBG("run next pthi iamthif cb\n"); - run_next_iamthif_cmd(dev); - } - } - - if (heci_clear_lists(dev, file)) - dev->iamthif_state = HECI_IAMTHIF_IDLE; - - spin_unlock_bh(&dev->device_lock); - } - return rets; -} - -static struct heci_cb_private *find_read_list_entry( - struct iamt_heci_device *dev, - struct heci_file_private *file_ext) -{ - struct heci_cb_private *priv_cb_pos = NULL; - struct heci_cb_private *priv_cb_next = NULL; - struct heci_file_private *file_ext_list_temp; - - if (dev->read_list.status == 0 - && !list_empty(&dev->read_list.heci_cb.cb_list)) { - DBG("remove read_list CB \n"); - list_for_each_entry_safe(priv_cb_pos, - priv_cb_next, - &dev->read_list.heci_cb.cb_list, cb_list) { - - file_ext_list_temp = (struct heci_file_private *) - priv_cb_pos->file_private; - - if ((file_ext_list_temp != NULL) && - heci_fe_same_id(file_ext, file_ext_list_temp)) - return priv_cb_pos; - - } - } - return NULL; -} - -/** - * heci_read - the read client message function. - * - * @file: pointer to file structure - * @ubuf: pointer to user buffer - * @length: buffer length - * @offset: data offset in buffer - * - * returns >=0 data length on success , <0 on error - */ -static ssize_t heci_read(struct file *file, char __user *ubuf, - size_t length, loff_t *offset) -{ - int i; - int rets = 0, err = 0; - int if_num = iminor(file->f_dentry->d_inode); - struct heci_file_private *file_ext = file->private_data; - struct heci_cb_private *priv_cb_pos = NULL; - struct heci_cb_private *priv_cb = NULL; - struct iamt_heci_device *dev; - - if (!heci_device) - return -ENODEV; - - dev = pci_get_drvdata(heci_device); - if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) - return -ENODEV; - - spin_lock_bh(&dev->device_lock); - if (dev->heci_state != HECI_ENABLED) { - spin_unlock_bh(&dev->device_lock); - return -ENODEV; - } - spin_unlock_bh(&dev->device_lock); - - spin_lock(&file_ext->file_lock); - if ((file_ext->sm_state & HECI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) { - spin_unlock(&file_ext->file_lock); - /* Do not allow to read watchdog client */ - for (i = 0; i < dev->num_heci_me_clients; i++) { - if (memcmp(&heci_wd_guid, - &dev->me_clients[i].props.protocol_name, - sizeof(struct guid)) == 0) { - if (file_ext->me_client_id == - dev->me_clients[i].client_id) - return -EBADF; - } - } - } else { - file_ext->sm_state &= ~HECI_WD_STATE_INDEPENDENCE_MSG_SENT; - spin_unlock(&file_ext->file_lock); - } - - if (file_ext == &dev->iamthif_file_ext) { - rets = pthi_read(dev, if_num, file, ubuf, length, offset); - goto out; - } - - if (file_ext->read_cb && file_ext->read_cb->information > *offset) { - priv_cb = file_ext->read_cb; - goto copy_buffer; - } else if (file_ext->read_cb && file_ext->read_cb->information > 0 && - file_ext->read_cb->information <= *offset) { - priv_cb = file_ext->read_cb; - rets = 0; - goto free; - } else if ((!file_ext->read_cb || file_ext->read_cb->information == 0) - && *offset > 0) { - /*Offset needs to be cleaned for contingous reads*/ - *offset = 0; - rets = 0; - goto out; - } - - err = heci_start_read(dev, if_num, file_ext); - spin_lock_bh(&file_ext->read_io_lock); - if (err != 0 && err != -EBUSY) { - DBG("heci start read failure with status = %d\n", err); - spin_unlock_bh(&file_ext->read_io_lock); - rets = err; - goto out; - } - if (HECI_READ_COMPLETE != file_ext->reading_state - && !waitqueue_active(&file_ext->rx_wait)) { - if (file->f_flags & O_NONBLOCK) { - rets = -EAGAIN; - spin_unlock_bh(&file_ext->read_io_lock); - goto out; - } - spin_unlock_bh(&file_ext->read_io_lock); - - if (wait_event_interruptible(file_ext->rx_wait, - (HECI_READ_COMPLETE == file_ext->reading_state - || HECI_FILE_INITIALIZING == file_ext->state - || HECI_FILE_DISCONNECTED == file_ext->state - || HECI_FILE_DISCONNECTING == file_ext->state))) { - if (signal_pending(current)) { - rets = -EINTR; - goto out; - } - return -ERESTARTSYS; - } - - spin_lock_bh(&dev->device_lock); - if (HECI_FILE_INITIALIZING == file_ext->state || - HECI_FILE_DISCONNECTED == file_ext->state || - HECI_FILE_DISCONNECTING == file_ext->state) { - spin_unlock_bh(&dev->device_lock); - rets = -EBUSY; - goto out; - } - spin_unlock_bh(&dev->device_lock); - spin_lock_bh(&file_ext->read_io_lock); - } - - priv_cb = file_ext->read_cb; - - if (!priv_cb) { - spin_unlock_bh(&file_ext->read_io_lock); - return -ENODEV; - } - if (file_ext->reading_state != HECI_READ_COMPLETE) { - spin_unlock_bh(&file_ext->read_io_lock); - return 0; - } - spin_unlock_bh(&file_ext->read_io_lock); - /* now copy the data to user space */ -copy_buffer: - DBG("priv_cb->response_buffer size - %d\n", - priv_cb->response_buffer.size); - DBG("priv_cb->information - %lu\n", - priv_cb->information); - if (length == 0 || ubuf == NULL || - *offset > priv_cb->information) { - rets = -EMSGSIZE; - goto free; - } - - /* length is being turncated to PAGE_SIZE, however, */ - /* information size may be longer */ - length = (length < (priv_cb->information - *offset) ? - length : (priv_cb->information - *offset)); - - if (copy_to_user(ubuf, - priv_cb->response_buffer.data + *offset, - length)) { - rets = -EFAULT; - goto free; - } - - rets = length; - *offset += length; - if ((unsigned long)*offset < priv_cb->information) - goto out; - -free: - spin_lock_bh(&dev->device_lock); - priv_cb_pos = find_read_list_entry(dev, file_ext); - /* Remove entry from read list */ - if (priv_cb_pos != NULL) - list_del(&priv_cb_pos->cb_list); - spin_unlock_bh(&dev->device_lock); - heci_free_cb_private(priv_cb); - spin_lock_bh(&file_ext->read_io_lock); - file_ext->reading_state = HECI_IDLE; - file_ext->read_cb = NULL; - file_ext->read_pending = 0; - spin_unlock_bh(&file_ext->read_io_lock); -out: DBG("end heci read rets= %d\n", rets); - return rets; -} - -/** - * heci_write - the write function. - * - * @file: pointer to file structure - * @ubuf: pointer to user buffer - * @length: buffer length - * @offset: data offset in buffer - * - * returns >=0 data length on success , <0 on error - */ -static ssize_t heci_write(struct file *file, const char __user *ubuf, - size_t length, loff_t *offset) -{ - int rets = 0; - __u8 i; - int if_num = iminor(file->f_dentry->d_inode); - struct heci_file_private *file_ext = file->private_data; - struct heci_cb_private *priv_write_cb = NULL; - struct heci_msg_hdr heci_hdr; - struct iamt_heci_device *dev; - unsigned long currtime = get_seconds(); - - if (!heci_device) - return -ENODEV; - - dev = pci_get_drvdata(heci_device); - - if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) - return -ENODEV; - - spin_lock_bh(&dev->device_lock); - - if (dev->heci_state != HECI_ENABLED) { - spin_unlock_bh(&dev->device_lock); - return -ENODEV; - } - if (file_ext == &dev->iamthif_file_ext) { - priv_write_cb = find_pthi_read_list_entry(dev, file); - if ((priv_write_cb != NULL) && - (((currtime - priv_write_cb->read_time) >= - IAMTHIF_READ_TIMER) || - (file_ext->reading_state == HECI_READ_COMPLETE))) { - (*offset) = 0; - list_del(&priv_write_cb->cb_list); - heci_free_cb_private(priv_write_cb); - priv_write_cb = NULL; - } - } - - /* free entry used in read */ - if (file_ext->reading_state == HECI_READ_COMPLETE) { - *offset = 0; - priv_write_cb = find_read_list_entry(dev, file_ext); - if (priv_write_cb != NULL) { - list_del(&priv_write_cb->cb_list); - heci_free_cb_private(priv_write_cb); - priv_write_cb = NULL; - spin_lock_bh(&file_ext->read_io_lock); - file_ext->reading_state = HECI_IDLE; - file_ext->read_cb = NULL; - file_ext->read_pending = 0; - spin_unlock_bh(&file_ext->read_io_lock); - } - } else if (file_ext->reading_state == HECI_IDLE && - file_ext->read_pending == 0) - (*offset) = 0; - - spin_unlock_bh(&dev->device_lock); - - priv_write_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL); - if (!priv_write_cb) - return -ENOMEM; - - priv_write_cb->file_object = file; - priv_write_cb->file_private = file_ext; - priv_write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - if (!priv_write_cb->request_buffer.data) { - kfree(priv_write_cb); - return -ENOMEM; - } - DBG("length =%d\n", (int) length); - - if (copy_from_user(priv_write_cb->request_buffer.data, - ubuf, length)) { - rets = -EFAULT; - goto fail; - } - - spin_lock(&file_ext->file_lock); - file_ext->sm_state = 0; - if ((length == 4) && - ((memcmp(heci_wd_state_independence_msg[0], - priv_write_cb->request_buffer.data, 4) == 0) || - (memcmp(heci_wd_state_independence_msg[1], - priv_write_cb->request_buffer.data, 4) == 0) || - (memcmp(heci_wd_state_independence_msg[2], - priv_write_cb->request_buffer.data, 4) == 0))) - file_ext->sm_state |= HECI_WD_STATE_INDEPENDENCE_MSG_SENT; - spin_unlock(&file_ext->file_lock); - - INIT_LIST_HEAD(&priv_write_cb->cb_list); - if (file_ext == &dev->iamthif_file_ext) { - priv_write_cb->response_buffer.data = - kmalloc(IAMTHIF_MTU, GFP_KERNEL); - if (!priv_write_cb->response_buffer.data) { - rets = -ENOMEM; - goto fail; - } - spin_lock_bh(&dev->device_lock); - if (dev->heci_state != HECI_ENABLED) { - spin_unlock_bh(&dev->device_lock); - rets = -ENODEV; - goto fail; - } - for (i = 0; i < dev->num_heci_me_clients; i++) { - if (dev->me_clients[i].client_id == - dev->iamthif_file_ext.me_client_id) - break; - } - - BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); - if ((i == dev->num_heci_me_clients) || - (dev->me_clients[i].client_id != - dev->iamthif_file_ext.me_client_id)) { - - spin_unlock_bh(&dev->device_lock); - rets = -ENODEV; - goto fail; - } else if ((length > dev->me_clients[i].props.max_msg_length) - || (length <= 0)) { - spin_unlock_bh(&dev->device_lock); - rets = -EMSGSIZE; - goto fail; - } - - - priv_write_cb->response_buffer.size = IAMTHIF_MTU; - priv_write_cb->major_file_operations = HECI_IOCTL; - priv_write_cb->information = 0; - priv_write_cb->request_buffer.size = length; - if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) { - spin_unlock_bh(&dev->device_lock); - rets = -ENODEV; - goto fail; - } - - if (!list_empty(&dev->pthi_cmd_list.heci_cb.cb_list) - || dev->iamthif_state != HECI_IAMTHIF_IDLE) { - DBG("pthi_state = %d\n", (int) dev->iamthif_state); - DBG("add PTHI cb to pthi cmd waiting list\n"); - list_add_tail(&priv_write_cb->cb_list, - &dev->pthi_cmd_list.heci_cb.cb_list); - rets = length; - } else { - DBG("call pthi write\n"); - rets = pthi_write(dev, priv_write_cb); - - if (rets != 0) { - DBG("pthi write failed with status = %d\n", - rets); - spin_unlock_bh(&dev->device_lock); - goto fail; - } - rets = length; - } - spin_unlock_bh(&dev->device_lock); - return rets; - } - - priv_write_cb->major_file_operations = HECI_WRITE; - /* make sure information is zero before we start */ - - priv_write_cb->information = 0; - priv_write_cb->request_buffer.size = length; - - spin_lock(&file_ext->write_io_lock); - spin_lock_bh(&dev->device_lock); - DBG("host client = %d, ME client = %d\n", - file_ext->host_client_id, file_ext->me_client_id); - if (file_ext->state != HECI_FILE_CONNECTED) { - rets = -ENODEV; - DBG("host client = %d, is not connected to ME client = %d", - file_ext->host_client_id, - file_ext->me_client_id); - spin_unlock_bh(&dev->device_lock); - goto unlock; - } - for (i = 0; i < dev->num_heci_me_clients; i++) { - if (dev->me_clients[i].client_id == - file_ext->me_client_id) - break; - } - BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); - if (i == dev->num_heci_me_clients) { - rets = -ENODEV; - spin_unlock_bh(&dev->device_lock); - goto unlock; - } - if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { - rets = -EINVAL; - spin_unlock_bh(&dev->device_lock); - goto unlock; - } - priv_write_cb->file_private = file_ext; - - if (flow_ctrl_creds(dev, file_ext) && - dev->host_buffer_is_empty) { - spin_unlock_bh(&dev->device_lock); - dev->host_buffer_is_empty = 0; - if (length > ((((dev->host_hw_state & H_CBD) >> 24) * - sizeof(__u32)) - sizeof(struct heci_msg_hdr))) { - - heci_hdr.length = - (((dev->host_hw_state & H_CBD) >> 24) * - sizeof(__u32)) - - sizeof(struct heci_msg_hdr); - heci_hdr.msg_complete = 0; - } else { - heci_hdr.length = length; - heci_hdr.msg_complete = 1; - } - heci_hdr.host_addr = file_ext->host_client_id; - heci_hdr.me_addr = file_ext->me_client_id; - heci_hdr.reserved = 0; - DBG("call heci_write_message header=%08x.\n", - *((__u32 *) &heci_hdr)); - spin_unlock(&file_ext->write_io_lock); - /* protect heci low level write */ - spin_lock_bh(&dev->device_lock); - if (!heci_write_message(dev, &heci_hdr, - (unsigned char *) (priv_write_cb->request_buffer.data), - heci_hdr.length)) { - - spin_unlock_bh(&dev->device_lock); - heci_free_cb_private(priv_write_cb); - rets = -ENODEV; - priv_write_cb->information = 0; - return rets; - } - file_ext->writing_state = HECI_WRITING; - priv_write_cb->information = heci_hdr.length; - if (heci_hdr.msg_complete) { - flow_ctrl_reduce(dev, file_ext); - list_add_tail(&priv_write_cb->cb_list, - &dev->write_waiting_list.heci_cb.cb_list); - } else { - list_add_tail(&priv_write_cb->cb_list, - &dev->write_list.heci_cb.cb_list); - } - spin_unlock_bh(&dev->device_lock); - - } else { - - spin_unlock_bh(&dev->device_lock); - priv_write_cb->information = 0; - file_ext->writing_state = HECI_WRITING; - spin_unlock(&file_ext->write_io_lock); - list_add_tail(&priv_write_cb->cb_list, - &dev->write_list.heci_cb.cb_list); - } - return length; - -unlock: - spin_unlock(&file_ext->write_io_lock); -fail: - heci_free_cb_private(priv_write_cb); - return rets; - -} - -/** - * heci_ioctl - the IOCTL function - * - * @inode: pointer to inode structure - * @file: pointer to file structure - * @cmd: ioctl command - * @data: pointer to heci message structure - * - * returns 0 on success , <0 on error - */ -static int heci_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long data) -{ - int rets = 0; - int if_num = iminor(inode); - struct heci_file_private *file_ext = file->private_data; - /* in user space */ - struct heci_message_data __user *u_msg; - struct heci_message_data k_msg; /* all in kernel on the stack */ - struct iamt_heci_device *dev; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!heci_device) - return -ENODEV; - - dev = pci_get_drvdata(heci_device); - if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) - return -ENODEV; - - spin_lock_bh(&dev->device_lock); - if (dev->heci_state != HECI_ENABLED) { - spin_unlock_bh(&dev->device_lock); - return -ENODEV; - } - spin_unlock_bh(&dev->device_lock); - - /* first copy from user all data needed */ - u_msg = (struct heci_message_data __user *)data; - if (copy_from_user(&k_msg, u_msg, sizeof(k_msg))) { - DBG("first copy from user all data needed filled\n"); - return -EFAULT; - } - DBG("user message size is %d\n", k_msg.size); - - switch (cmd) { - case IOCTL_HECI_GET_VERSION: - DBG(": IOCTL_HECI_GET_VERSION\n"); - rets = heci_ioctl_get_version(dev, if_num, u_msg, k_msg, - file_ext); - break; - - case IOCTL_HECI_CONNECT_CLIENT: - DBG(": IOCTL_HECI_CONNECT_CLIENT.\n"); - rets = heci_ioctl_connect_client(dev, if_num, u_msg, k_msg, - file); - break; - - case IOCTL_HECI_WD: - DBG(": IOCTL_HECI_WD.\n"); - rets = heci_ioctl_wd(dev, if_num, k_msg, file_ext); - break; - - case IOCTL_HECI_BYPASS_WD: - DBG(": IOCTL_HECI_BYPASS_WD.\n"); - rets = heci_ioctl_bypass_wd(dev, if_num, k_msg, file_ext); - break; - - default: - rets = -EINVAL; - break; - } - return rets; -} - -/** - * heci_poll - the poll function - * - * @file: pointer to file structure - * @wait: pointer to poll_table structure - * - * returns poll mask - */ -static unsigned int heci_poll(struct file *file, poll_table *wait) -{ - int if_num = iminor(file->f_dentry->d_inode); - unsigned int mask = 0; - struct heci_file_private *file_ext = file->private_data; - struct iamt_heci_device *dev; - - if (!heci_device) - return mask; - - dev = pci_get_drvdata(heci_device); - - if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) - return mask; - - spin_lock_bh(&dev->device_lock); - if (dev->heci_state != HECI_ENABLED) { - spin_unlock_bh(&dev->device_lock); - return mask; - } - spin_unlock_bh(&dev->device_lock); - - if (file_ext == &dev->iamthif_file_ext) { - poll_wait(file, &dev->iamthif_file_ext.wait, wait); - spin_lock(&dev->iamthif_file_ext.file_lock); - if (dev->iamthif_state == HECI_IAMTHIF_READ_COMPLETE - && dev->iamthif_file_object == file) { - mask |= (POLLIN | POLLRDNORM); - spin_lock_bh(&dev->device_lock); - DBG("run next pthi cb\n"); - run_next_iamthif_cmd(dev); - spin_unlock_bh(&dev->device_lock); - } - spin_unlock(&dev->iamthif_file_ext.file_lock); - - } else{ - poll_wait(file, &file_ext->tx_wait, wait); - spin_lock(&file_ext->write_io_lock); - if (HECI_WRITE_COMPLETE == file_ext->writing_state) - mask |= (POLLIN | POLLRDNORM); - - spin_unlock(&file_ext->write_io_lock); - } - - return mask; -} - -#ifdef CONFIG_PM -static int heci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct iamt_heci_device *dev = pci_get_drvdata(pdev); - int err = 0; - - spin_lock_bh(&dev->device_lock); - if (dev->reinit_tsk != NULL) { - kthread_stop(dev->reinit_tsk); - dev->reinit_tsk = NULL; - } - spin_unlock_bh(&dev->device_lock); - - /* Stop watchdog if exists */ - del_timer_sync(&dev->wd_timer); - if (dev->wd_file_ext.state == HECI_FILE_CONNECTED - && dev->wd_timeout) { - spin_lock_bh(&dev->device_lock); - g_sus_wd_timeout = dev->wd_timeout; - dev->wd_timeout = 0; - dev->wd_due_counter = 0; - memcpy(dev->wd_data, heci_stop_wd_params, - HECI_WD_PARAMS_SIZE); - dev->stop = 1; - if (dev->host_buffer_is_empty && - flow_ctrl_creds(dev, &dev->wd_file_ext)) { - dev->host_buffer_is_empty = 0; - if (!heci_send_wd(dev)) - DBG("send stop WD failed\n"); - else - flow_ctrl_reduce(dev, &dev->wd_file_ext); - - dev->wd_pending = 0; - } else { - dev->wd_pending = 1; - } - spin_unlock_bh(&dev->device_lock); - dev->wd_stoped = 0; - - err = wait_event_interruptible_timeout(dev->wait_stop_wd, - (dev->wd_stoped), - 10 * HZ); - if (!dev->wd_stoped) - DBG("stop wd failed to complete.\n"); - else { - DBG("stop wd complete %d.\n", err); - err = 0; - } - } - /* Set new heci state */ - spin_lock_bh(&dev->device_lock); - if (dev->heci_state == HECI_ENABLED || - dev->heci_state == HECI_RECOVERING_FROM_RESET) { - dev->heci_state = HECI_POWER_DOWN; - heci_reset(dev, 0); - } - spin_unlock_bh(&dev->device_lock); - - pci_save_state(pdev); - - pci_disable_device(pdev); - free_irq(pdev->irq, dev); - - pci_set_power_state(pdev, PCI_D3hot); - - return err; -} - -static int heci_resume(struct pci_dev *pdev) -{ - struct iamt_heci_device *dev; - int err = 0; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - dev = pci_get_drvdata(pdev); - if (!dev) - return -ENODEV; - - /* request and enable interrupt */ - err = request_irq(pdev->irq, heci_isr_interrupt, IRQF_SHARED, - heci_driver_name, dev); - if (err) { - printk(KERN_ERR "heci: Request_irq failure. irq = %d \n", - pdev->irq); - return err; - } - - spin_lock_bh(&dev->device_lock); - dev->heci_state = HECI_POWER_UP; - heci_reset(dev, 1); - spin_unlock_bh(&dev->device_lock); - - /* Start watchdog if stopped in suspend */ - if (g_sus_wd_timeout != 0) { - dev->wd_timeout = g_sus_wd_timeout; - - memcpy(dev->wd_data, heci_start_wd_params, - HECI_WD_PARAMS_SIZE); - memcpy(dev->wd_data + HECI_WD_PARAMS_SIZE, - &dev->wd_timeout, sizeof(__u16)); - dev->wd_due_counter = 1; - - if (dev->wd_timeout) - mod_timer(&dev->wd_timer, jiffies); - - g_sus_wd_timeout = 0; - } - return err; -} -#endif - -MODULE_AUTHOR("Intel Corporation"); -MODULE_DESCRIPTION("Intel(R) Management Engine Interface"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(HECI_DRIVER_VERSION); |