diff options
Diffstat (limited to 'drivers/staging/mei')
| -rw-r--r-- | drivers/staging/mei/Kconfig | 28 | ||||
| -rw-r--r-- | drivers/staging/mei/Makefile | 11 | ||||
| -rw-r--r-- | drivers/staging/mei/TODO | 17 | ||||
| -rw-r--r-- | drivers/staging/mei/hw.h | 333 | ||||
| -rw-r--r-- | drivers/staging/mei/init.c | 770 | ||||
| -rw-r--r-- | drivers/staging/mei/interface.c | 447 | ||||
| -rw-r--r-- | drivers/staging/mei/interface.h | 62 | ||||
| -rw-r--r-- | drivers/staging/mei/interrupt.c | 1624 | ||||
| -rw-r--r-- | drivers/staging/mei/iorw.c | 604 | ||||
| -rw-r--r-- | drivers/staging/mei/main.c | 1349 | ||||
| -rw-r--r-- | drivers/staging/mei/mei.h | 105 | ||||
| -rw-r--r-- | drivers/staging/mei/mei.txt | 189 | ||||
| -rw-r--r-- | drivers/staging/mei/mei_dev.h | 422 | ||||
| -rw-r--r-- | drivers/staging/mei/mei_version.h | 31 | ||||
| -rw-r--r-- | drivers/staging/mei/wd.c | 183 |
15 files changed, 0 insertions, 6175 deletions
diff --git a/drivers/staging/mei/Kconfig b/drivers/staging/mei/Kconfig deleted file mode 100644 index 3f3f170890e..00000000000 --- a/drivers/staging/mei/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -config INTEL_MEI - tristate "Intel Management Engine Interface (Intel MEI)" - depends on X86 && PCI && EXPERIMENTAL - 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. - - Supported Chipsets are: - 7 Series Chipset Family - 6 Series Chipset Family - 5 Series Chipset Family - 4 Series Chipset Family - Mobile 4 Series Chipset Family - ICH9 - 82946GZ/GL - 82G35 Express - 82Q963/Q965 - 82P965/G965 - Mobile PM965/GM965 - Mobile GME965/GLE960 - 82Q35 Express - 82G33/G31/P35/P31 Express - 82Q33 Express - 82X38/X48 Express - - For more information see - <http://software.intel.com/en-us/manageability/> diff --git a/drivers/staging/mei/Makefile b/drivers/staging/mei/Makefile deleted file mode 100644 index 57168db6c7e..00000000000 --- a/drivers/staging/mei/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile - Intel Management Engine Interface (Intel MEI) Linux driver -# Copyright (c) 2010-2011, Intel Corporation. -# -obj-$(CONFIG_INTEL_MEI) += mei.o -mei-objs := init.o -mei-objs += interrupt.o -mei-objs += interface.o -mei-objs += iorw.o -mei-objs += main.o -mei-objs += wd.o diff --git a/drivers/staging/mei/TODO b/drivers/staging/mei/TODO deleted file mode 100644 index 3b6a667a580..00000000000 --- a/drivers/staging/mei/TODO +++ /dev/null @@ -1,17 +0,0 @@ -TODO: - - Create in-kernel Client API. Examples of in-kernel clients are watchdog and AMTHI. - - ME Watchdog Driver to expose standard Linux watchdog interface - - Rewrite AMTHI to use in-kernel client interface - - Cleanup init and probe functions - - Review BUG/BUG_ON usage - - Cleanup and reorganize header files - - Rewrite client data structure - - Make state machine more readable - - Add mei.txt with driver explanation and it's driver - - Fix Kconfig - - Cleanup and split the timer function -Upon Unstaging: - - move mei.h to include/linux/mei.h - - Documentation/ioctl/ioctl-number.txt - - drop mei_version.h - - Updated MAINTAINERS diff --git a/drivers/staging/mei/hw.h b/drivers/staging/mei/hw.h deleted file mode 100644 index 9b9008cb693..00000000000 --- a/drivers/staging/mei/hw.h +++ /dev/null @@ -1,333 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - -#ifndef _MEI_HW_TYPES_H_ -#define _MEI_HW_TYPES_H_ - -#include <linux/uuid.h> - -/* - * Timeouts - */ -#define MEI_INTEROP_TIMEOUT (HZ * 7) -#define MEI_CONNECT_TIMEOUT 3 /* at least 2 seconds */ - -#define CONNECT_TIMEOUT 15 /* HPS definition */ -#define INIT_CLIENTS_TIMEOUT 15 /* HPS definition */ - -#define IAMTHIF_STALL_TIMER 12 /* seconds */ -#define IAMTHIF_READ_TIMER 10000 /* ms */ - -/* - * Internal Clients Number - */ -#define MEI_WD_HOST_CLIENT_ID 1 -#define MEI_IAMTHIF_HOST_CLIENT_ID 2 - -/* - * MEI device IDs - */ -#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */ -#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */ -#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */ -#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */ - -#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */ -#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */ - -#define MEI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */ -#define MEI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */ -#define MEI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */ -#define MEI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */ -#define MEI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */ - -#define MEI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */ -#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */ -#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */ -#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */ -#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */ - -#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */ -#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */ -#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */ -#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */ - -#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */ -#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */ -#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */ -#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */ - -#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */ -#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */ - -#define MEI_DEV_ID_CPT_1 0x1C3A /* Cougerpoint */ -#define MEI_DEV_ID_PBG_1 0x1D3A /* PBG */ - -#define MEI_DEV_ID_PPT_1 0x1E3A /* Pantherpoint PPT */ -#define MEI_DEV_ID_PPT_2 0x1CBA /* Pantherpoint PPT */ -#define MEI_DEV_ID_PPT_3 0x1DBA /* Pantherpoint PPT */ - - -/* - * MEI HW Section - */ - -/* MEI registers */ -/* H_CB_WW - Host Circular Buffer (CB) Write Window register */ -#define H_CB_WW 0 -/* H_CSR - Host Control Status register */ -#define H_CSR 4 -/* ME_CB_RW - ME Circular Buffer Read Window register (read only) */ -#define ME_CB_RW 8 -/* ME_CSR_HA - ME Control Status Host Access register (read only) */ -#define ME_CSR_HA 0xC - - -/* register bits of H_CSR (Host Control Status register) */ -/* Host Circular Buffer Depth - maximum number of 32-bit entries in CB */ -#define H_CBD 0xFF000000 -/* Host Circular Buffer Write Pointer */ -#define H_CBWP 0x00FF0000 -/* Host Circular Buffer Read Pointer */ -#define H_CBRP 0x0000FF00 -/* Host Reset */ -#define H_RST 0x00000010 -/* Host Ready */ -#define H_RDY 0x00000008 -/* Host Interrupt Generate */ -#define H_IG 0x00000004 -/* Host Interrupt Status */ -#define H_IS 0x00000002 -/* Host Interrupt Enable */ -#define H_IE 0x00000001 - - -/* register bits of ME_CSR_HA (ME Control Status Host Access register) */ -/* ME CB (Circular Buffer) Depth HRA (Host Read Access) - host read only -access to ME_CBD */ -#define ME_CBD_HRA 0xFF000000 -/* ME CB Write Pointer HRA - host read only access to ME_CBWP */ -#define ME_CBWP_HRA 0x00FF0000 -/* ME CB Read Pointer HRA - host read only access to ME_CBRP */ -#define ME_CBRP_HRA 0x0000FF00 -/* ME Reset HRA - host read only access to ME_RST */ -#define ME_RST_HRA 0x00000010 -/* ME Ready HRA - host read only access to ME_RDY */ -#define ME_RDY_HRA 0x00000008 -/* ME Interrupt Generate HRA - host read only access to ME_IG */ -#define ME_IG_HRA 0x00000004 -/* ME Interrupt Status HRA - host read only access to ME_IS */ -#define ME_IS_HRA 0x00000002 -/* ME Interrupt Enable HRA - host read only access to ME_IE */ -#define ME_IE_HRA 0x00000001 - -/* - * MEI Version - */ -#define HBM_MINOR_VERSION 0 -#define HBM_MAJOR_VERSION 1 -#define HBM_TIMEOUT 1 /* 1 second */ - -/* - * MEI Bus Message Command IDs - */ -#define HOST_START_REQ_CMD 0x01 -#define HOST_START_RES_CMD 0x81 - -#define HOST_STOP_REQ_CMD 0x02 -#define HOST_STOP_RES_CMD 0x82 - -#define ME_STOP_REQ_CMD 0x03 - -#define HOST_ENUM_REQ_CMD 0x04 -#define HOST_ENUM_RES_CMD 0x84 - -#define HOST_CLIENT_PROPERTIES_REQ_CMD 0x05 -#define HOST_CLIENT_PROPERTIES_RES_CMD 0x85 - -#define CLIENT_CONNECT_REQ_CMD 0x06 -#define CLIENT_CONNECT_RES_CMD 0x86 - -#define CLIENT_DISCONNECT_REQ_CMD 0x07 -#define CLIENT_DISCONNECT_RES_CMD 0x87 - -#define MEI_FLOW_CONTROL_CMD 0x08 - -/* - * MEI Stop Reason - * used by hbm_host_stop_request.reason - */ -enum mei_stop_reason_types { - DRIVER_STOP_REQUEST = 0x00, - DEVICE_D1_ENTRY = 0x01, - DEVICE_D2_ENTRY = 0x02, - DEVICE_D3_ENTRY = 0x03, - SYSTEM_S1_ENTRY = 0x04, - SYSTEM_S2_ENTRY = 0x05, - SYSTEM_S3_ENTRY = 0x06, - SYSTEM_S4_ENTRY = 0x07, - SYSTEM_S5_ENTRY = 0x08 -}; - -/* - * Client Connect Status - * used by hbm_client_connect_response.status - */ -enum client_connect_status_types { - CCS_SUCCESS = 0x00, - CCS_NOT_FOUND = 0x01, - CCS_ALREADY_STARTED = 0x02, - CCS_OUT_OF_RESOURCES = 0x03, - CCS_MESSAGE_SMALL = 0x04 -}; - -/* - * Client Disconnect Status - */ -enum client_disconnect_status_types { - CDS_SUCCESS = 0x00 -}; - -/* - * MEI BUS Interface Section - */ -struct mei_msg_hdr { - u32 me_addr:8; - u32 host_addr:8; - u32 length:9; - u32 reserved:6; - u32 msg_complete:1; -} __packed; - - -struct hbm_cmd { - u8 cmd:7; - u8 is_response:1; -} __packed; - - -struct mei_bus_message { - struct hbm_cmd cmd; - u8 command_specific_data[]; -} __packed; - -struct hbm_version { - u8 minor_version; - u8 major_version; -} __packed; - -struct hbm_host_version_request { - struct hbm_cmd cmd; - u8 reserved; - struct hbm_version host_version; -} __packed; - -struct hbm_host_version_response { - struct hbm_cmd cmd; - int host_version_supported; - struct hbm_version me_max_version; -} __packed; - -struct hbm_host_stop_request { - struct hbm_cmd cmd; - u8 reason; - u8 reserved[2]; -} __packed; - -struct hbm_host_stop_response { - struct hbm_cmd cmd; - u8 reserved[3]; -} __packed; - -struct hbm_me_stop_request { - struct hbm_cmd cmd; - u8 reason; - u8 reserved[2]; -} __packed; - -struct hbm_host_enum_request { - struct hbm_cmd cmd; - u8 reserved[3]; -} __packed; - -struct hbm_host_enum_response { - struct hbm_cmd cmd; - u8 reserved[3]; - u8 valid_addresses[32]; -} __packed; - -struct mei_client_properties { - uuid_le protocol_name; - u8 protocol_version; - u8 max_number_of_connections; - u8 fixed_address; - u8 single_recv_buf; - u32 max_msg_length; -} __packed; - -struct hbm_props_request { - struct hbm_cmd cmd; - u8 address; - u8 reserved[2]; -} __packed; - - -struct hbm_props_response { - struct hbm_cmd cmd; - u8 address; - u8 status; - u8 reserved[1]; - struct mei_client_properties client_properties; -} __packed; - -struct hbm_client_connect_request { - struct hbm_cmd cmd; - u8 me_addr; - u8 host_addr; - u8 reserved; -} __packed; - -struct hbm_client_connect_response { - struct hbm_cmd cmd; - u8 me_addr; - u8 host_addr; - u8 status; -} __packed; - -struct hbm_client_disconnect_request { - struct hbm_cmd cmd; - u8 me_addr; - u8 host_addr; - u8 reserved[1]; -} __packed; - -#define MEI_FC_MESSAGE_RESERVED_LENGTH 5 - -struct hbm_flow_control { - struct hbm_cmd cmd; - u8 me_addr; - u8 host_addr; - u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH]; -} __packed; - -struct mei_me_client { - struct mei_client_properties props; - u8 client_id; - u8 mei_flow_ctrl_creds; -} __packed; - - -#endif diff --git a/drivers/staging/mei/init.c b/drivers/staging/mei/init.c deleted file mode 100644 index 2818851c076..00000000000 --- a/drivers/staging/mei/init.c +++ /dev/null @@ -1,770 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/delay.h> - -#include "mei_dev.h" -#include "hw.h" -#include "interface.h" -#include "mei.h" - -const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, - 0xa8, 0x46, 0xe0, 0xff, 0x65, - 0x81, 0x4c); - -/** - * mei_initialize_list - Sets up a queue list. - * - * @list: An instance of our list structure - * @dev: the device structure - */ -void mei_initialize_list(struct mei_io_list *list, struct mei_device *dev) -{ - /* initialize our queue list */ - INIT_LIST_HEAD(&list->mei_cb.cb_list); - list->status = 0; - list->device_extension = dev; -} - -/** - * mei_flush_queues - flushes queue lists belonging to cl. - * - * @dev: the device structure - * @cl: private data of the file object - */ -void mei_flush_queues(struct mei_device *dev, struct mei_cl *cl) -{ - int i; - - if (!dev || !cl) - return; - - for (i = 0; i < MEI_IO_LISTS_NUMBER; i++) { - dev_dbg(&dev->pdev->dev, "remove list entry belonging to cl\n"); - mei_flush_list(dev->io_list_array[i], cl); - } -} - - -/** - * mei_flush_list - removes list entry belonging to cl. - * - * @list: An instance of our list structure - * @cl: private data of the file object - */ -void mei_flush_list(struct mei_io_list *list, struct mei_cl *cl) -{ - struct mei_cl *cl_tmp; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - - if (!list || !cl) - return; - - if (list->status != 0) - return; - - if (list_empty(&list->mei_cb.cb_list)) - return; - - list_for_each_entry_safe(cb_pos, cb_next, - &list->mei_cb.cb_list, cb_list) { - if (cb_pos) { - cl_tmp = (struct mei_cl *) - cb_pos->file_private; - if (cl_tmp && - mei_fe_same_id(cl, cl_tmp)) - list_del(&cb_pos->cb_list); - } - } -} - -/** - * mei_reset_iamthif_params - initializes mei device iamthif - * - * @dev: the device structure - */ -static void mei_reset_iamthif_params(struct mei_device *dev) -{ - /* reset iamthif parameters. */ - dev->iamthif_current_cb = NULL; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = 0; - dev->iamthif_ioctl = 0; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; -} - -/** - * 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 *init_mei_device(struct pci_dev *pdev) -{ - int i; - struct mei_device *dev; - - dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL); - if (!dev) - return NULL; - - /* setup our list array */ - dev->io_list_array[0] = &dev->read_list; - dev->io_list_array[1] = &dev->write_list; - dev->io_list_array[2] = &dev->write_waiting_list; - dev->io_list_array[3] = &dev->ctrl_wr_list; - dev->io_list_array[4] = &dev->ctrl_rd_list; - dev->io_list_array[5] = &dev->amthi_cmd_list; - dev->io_list_array[6] = &dev->amthi_read_complete_list; - 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); - dev->mei_state = MEI_INITIALIZING; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - for (i = 0; i < MEI_IO_LISTS_NUMBER; i++) - mei_initialize_list(dev->io_list_array[i], dev); - dev->pdev = pdev; - return dev; -} - -/** - * mei_hw_init - initializes host and fw to start work. - * - * @dev: the device structure - * - * returns 0 on success, <0 on failure. - */ -int mei_hw_init(struct mei_device *dev) -{ - int err = 0; - int ret; - - mutex_lock(&dev->device_lock); - - dev->host_hw_state = mei_hcsr_read(dev); - dev->me_hw_state = mei_mecsr_read(dev); - dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - - /* acknowledge interrupt and stop interupts */ - if ((dev->host_hw_state & H_IS) == H_IS) - mei_reg_write(dev, H_CSR, dev->host_hw_state); - - dev->recvd_msg = 0; - dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n"); - - mei_reset(dev, 1); - - dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - - /* wait for ME to turn on ME_RDY */ - if (!dev->recvd_msg) { - mutex_unlock(&dev->device_lock); - err = wait_event_interruptible_timeout(dev->wait_recvd_msg, - dev->recvd_msg, MEI_INTEROP_TIMEOUT); - mutex_lock(&dev->device_lock); - } - - if (!err && !dev->recvd_msg) { - dev->mei_state = MEI_DISABLED; - dev_dbg(&dev->pdev->dev, - "wait_event_interruptible_timeout failed" - "on wait for ME to turn on ME_RDY.\n"); - ret = -ENODEV; - goto out; - } - - if (!(((dev->host_hw_state & H_RDY) == H_RDY) && - ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) { - dev->mei_state = MEI_DISABLED; - dev_dbg(&dev->pdev->dev, - "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - - if (!(dev->host_hw_state & H_RDY) != H_RDY) - dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n"); - - if (!(dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) - dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n"); - - printk(KERN_ERR "mei: link layer initialization failed.\n"); - ret = -ENODEV; - goto out; - } - - if (dev->version.major_version != HBM_MAJOR_VERSION || - dev->version.minor_version != HBM_MINOR_VERSION) { - dev_dbg(&dev->pdev->dev, "MEI start failed.\n"); - ret = -ENODEV; - goto out; - } - - dev->recvd_msg = 0; - dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n"); - dev_dbg(&dev->pdev->dev, "link layer has been established.\n"); - dev_dbg(&dev->pdev->dev, "MEI start success.\n"); - ret = 0; - -out: - mutex_unlock(&dev->device_lock); - return ret; -} - -/** - * mei_hw_reset - resets fw via mei csr register. - * - * @dev: the device structure - * @interrupts_enabled: if interrupt should be enabled after reset. - */ -static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled) -{ - dev->host_hw_state |= (H_RST | H_IG); - - if (interrupts_enabled) - mei_enable_interrupts(dev); - else - mei_disable_interrupts(dev); -} - -/** - * mei_reset - resets host and fw. - * - * @dev: the device structure - * @interrupts_enabled: if interrupt should be enabled after reset. - */ -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->mei_state == MEI_RECOVERING_FROM_RESET) { - dev->need_reset = 1; - return; - } - - unexpected = (dev->mei_state != MEI_INITIALIZING && - dev->mei_state != MEI_DISABLED && - dev->mei_state != MEI_POWER_DOWN && - dev->mei_state != MEI_POWER_UP); - - dev->host_hw_state = mei_hcsr_read(dev); - - dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n", - dev->host_hw_state); - - mei_hw_reset(dev, interrupts_enabled); - - dev->host_hw_state &= ~H_RST; - dev->host_hw_state |= H_IG; - - mei_hcsr_set(dev); - - dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n", - dev->host_hw_state); - - dev->need_reset = 0; - - if (dev->mei_state != MEI_INITIALIZING) { - if (dev->mei_state != MEI_DISABLED && - dev->mei_state != MEI_POWER_DOWN) - dev->mei_state = MEI_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; - } - /* remove entry if already in list */ - dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, - dev->wd_cl.host_client_id); - - mei_remove_client_from_file_list(dev, - dev->iamthif_cl.host_client_id); - - mei_reset_iamthif_params(dev); - dev->wd_due_counter = 0; - dev->extra_write_index = 0; - } - - dev->num_mei_me_clients = 0; - dev->rd_msg_hdr = 0; - dev->stop = 0; - dev->wd_pending = 0; - - /* update the state of the registers after reset */ - dev->host_hw_state = mei_hcsr_read(dev); - dev->me_hw_state = mei_mecsr_read(dev); - - dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", - dev->host_hw_state, dev->me_hw_state); - - if (unexpected) - dev_warn(&dev->pdev->dev, "unexpected reset.\n"); - - /* 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); - } - } - /* remove all waiting requests */ - if (dev->write_list.status == 0 && - !list_empty(&dev->write_list.mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &dev->write_list.mei_cb.cb_list, cb_list) { - if (cb_pos) { - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb_pos); - cb_pos = NULL; - } - } - } -} - - - -/** - * host_start_message - mei host sends start message. - * - * @dev: the device structure - * - * returns none. - */ -void host_start_message(struct mei_device *dev) -{ - struct mei_msg_hdr *mei_hdr; - struct hbm_host_version_request *host_start_req; - - /* host start message */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_version_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_start_req = - (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; - memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); - host_start_req->cmd.cmd = HOST_START_REQ_CMD; - host_start_req->host_version.major_version = HBM_MAJOR_VERSION; - host_start_req->host_version.minor_version = HBM_MINOR_VERSION; - dev->recvd_msg = 0; - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) (host_start_req), - mei_hdr->length)) { - dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); - dev->mei_state = MEI_RESETING; - mei_reset(dev, 1); - } - dev->init_clients_state = MEI_START_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; - return ; -} - -/** - * host_enum_clients_message - host sends enumeration client request message. - * - * @dev: the device structure - * - * returns none. - */ -void host_enum_clients_message(struct mei_device *dev) -{ - struct mei_msg_hdr *mei_hdr; - struct hbm_host_enum_request *host_enum_req; - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - /* enumerate clients */ - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_enum_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; - memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); - host_enum_req->cmd.cmd = HOST_ENUM_REQ_CMD; - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) (host_enum_req), - mei_hdr->length)) { - dev->mei_state = MEI_RESETING; - dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); - mei_reset(dev, 1); - } - dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; - return ; -} - - -/** - * allocate_me_clients_storage - allocates storage for me clients - * - * @dev: the device structure - * - * returns none. - */ -void allocate_me_clients_storage(struct mei_device *dev) -{ - struct mei_me_client *clients; - int b; - - /* count how many ME clients we have */ - for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX) - dev->num_mei_me_clients++; - - if (dev->num_mei_me_clients <= 0) - return ; - - - if (dev->me_clients != NULL) { - kfree(dev->me_clients); - dev->me_clients = NULL; - } - dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n", - dev->num_mei_me_clients * sizeof(struct mei_me_client)); - /* allocate storage for ME clients representation */ - clients = kcalloc(dev->num_mei_me_clients, - sizeof(struct mei_me_client), GFP_KERNEL); - if (!clients) { - dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n"); - dev->mei_state = MEI_RESETING; - mei_reset(dev, 1); - return ; - } - dev->me_clients = clients; - return ; -} -/** - * host_client_properties - reads properties for client - * - * @dev: the device structure - * - * returns none. - */ -void host_client_properties(struct mei_device *dev) -{ - struct mei_msg_hdr *mei_header; - struct hbm_props_request *host_cli_req; - int b; - u8 client_num = dev->me_client_presentation_num; - - b = dev->me_client_index; - b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); - if (b < MEI_CLIENTS_MAX) { - dev->me_clients[client_num].client_id = b; - dev->me_clients[client_num].mei_flow_ctrl_creds = 0; - mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; - mei_header->host_addr = 0; - mei_header->me_addr = 0; - mei_header->length = sizeof(struct hbm_props_request); - mei_header->msg_complete = 1; - mei_header->reserved = 0; - - host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; - - memset(host_cli_req, 0, sizeof(struct hbm_props_request)); - - host_cli_req->cmd.cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; - host_cli_req->address = b; - - if (!mei_write_message(dev, mei_header, - (unsigned char *)host_cli_req, - mei_header->length)) { - dev->mei_state = MEI_RESETING; - dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); - mei_reset(dev, 1); - return; - } - - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; - dev->me_client_index = b; - return; - } - - - /* - * Clear Map for indicating now ME clients - * with associated host client - */ - bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); - dev->write_hang = -1; - dev->open_handle_count = 0; - bitmap_set(dev->host_clients_map, 0, 3); - dev->mei_state = MEI_ENABLED; - - mei_wd_host_init(dev); - return; -} - -/** - * mei_init_file_private - initializes private file structure. - * - * @priv: private file structure to be initialized - * @file: the file structure - */ -void mei_init_file_private(struct mei_cl *priv, struct mei_device *dev) -{ - memset(priv, 0, sizeof(struct mei_cl)); - init_waitqueue_head(&priv->wait); - init_waitqueue_head(&priv->rx_wait); - init_waitqueue_head(&priv->tx_wait); - INIT_LIST_HEAD(&priv->link); - priv->reading_state = MEI_IDLE; - priv->writing_state = MEI_IDLE; - priv->dev = dev; -} - -int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid) -{ - int i, res = -1; - - for (i = 0; i < dev->num_mei_me_clients; ++i) - if (uuid_le_cmp(cuuid, - dev->me_clients[i].props.protocol_name) == 0) { - res = i; - break; - } - - return res; -} - - -/** - * mei_find_me_client_update_filext - searches for ME client guid - * sets client_id in mei_file_private if found - * @dev: the device structure - * @priv: private file structure to set client_id in - * @cguid: searched guid of ME client - * @client_id: id of host client to be set in file private structure - * - * returns ME client index - */ -u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv, - const uuid_le *cguid, u8 client_id) -{ - int i; - - if (!dev || !priv || !cguid) - return 0; - - /* check for valid client id */ - i = mei_find_me_client_index(dev, *cguid); - if (i >= 0) { - priv->me_client_id = dev->me_clients[i].client_id; - priv->state = MEI_FILE_CONNECTING; - priv->host_client_id = client_id; - - list_add_tail(&priv->link, &dev->file_list); - return (u8)i; - } - - return 0; -} - -/** - * host_init_iamthif - mei initialization iamthif client. - * - * @dev: the device structure - * - */ -void host_init_iamthif(struct mei_device *dev) -{ - u8 i; - unsigned char *msg_buf; - - mei_init_file_private(&dev->iamthif_cl, dev); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - - /* find ME amthi client */ - i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl, - &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); - if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) { - dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); - return; - } - - /* Do not render the system unusable when iamthif_mtu is not equal to - the value received from ME. - Assign iamthif_mtu to the value received from ME in order to solve the - hardware macro incompatibility. */ - - dev_dbg(&dev->pdev->dev, "[DEFAULT] IAMTHIF = %d\n", dev->iamthif_mtu); - dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; - dev_dbg(&dev->pdev->dev, - "IAMTHIF = %d\n", - dev->me_clients[i].props.max_msg_length); - - kfree(dev->iamthif_msg_buf); - dev->iamthif_msg_buf = NULL; - - /* allocate storage for ME message buffer */ - msg_buf = kcalloc(dev->iamthif_mtu, - sizeof(unsigned char), GFP_KERNEL); - if (!msg_buf) { - dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); - return; - } - - dev->iamthif_msg_buf = msg_buf; - - if (!mei_connect(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - dev->iamthif_cl.host_client_id = 0; - } else { - dev->iamthif_cl.timer_count = CONNECT_TIMEOUT; - } -} - -/** - * mei_alloc_file_private - allocates a private file structure and sets it up. - * @file: the file structure - * - * returns The allocated file or NULL on failure - */ -struct mei_cl *mei_alloc_file_private(struct mei_device *dev) -{ - struct mei_cl *priv; - - priv = kmalloc(sizeof(struct mei_cl), GFP_KERNEL); - if (!priv) - return NULL; - - mei_init_file_private(priv, dev); - - return priv; -} - - - -/** - * mei_disconnect_host_client - sends disconnect message to fw from host client. - * - * @dev: the device structure - * @cl: private data of the file object - * - * Locking: called under "dev->device_lock" lock - * - * returns 0 on success, <0 on failure. - */ -int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) -{ - int rets, err; - long timeout = 15; /* 15 seconds */ - struct mei_cl_cb *cb; - - if (!dev || !cl) - return -ENODEV; - - if (cl->state != MEI_FILE_DISCONNECTING) - return 0; - - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!cb) - return -ENOMEM; - - INIT_LIST_HEAD(&cb->cb_list); - cb->file_private = cl; - cb->major_file_operations = MEI_CLOSE; - if (dev->mei_host_buffer_is_empty) { - dev->mei_host_buffer_is_empty = 0; - if (mei_disconnect(dev, cl)) { - mdelay(10); /* Wait for hardware disconnection ready */ - list_add_tail(&cb->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); - } else { - rets = -ENODEV; - dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n"); - goto free; - } - } else { - dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); - } - mutex_unlock(&dev->device_lock); - - err = wait_event_timeout(dev->wait_recvd_msg, - (MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); - - mutex_lock(&dev->device_lock); - if (MEI_FILE_DISCONNECTED == cl->state) { - rets = 0; - dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); - } else { - rets = -ENODEV; - if (MEI_FILE_DISCONNECTED != cl->state) - dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); - - if (err) - dev_dbg(&dev->pdev->dev, - "wait failed disconnect err=%08x\n", - err); - - dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); - } - - mei_flush_list(&dev->ctrl_rd_list, cl); - mei_flush_list(&dev->ctrl_wr_list, cl); -free: - mei_free_cb_private(cb); - return rets; -} - -/** - * mei_remove_client_from_file_list - - * removes file private data from device file list - * - * @dev: the device structure - * @host_client_id: host client id to be removed - */ -void mei_remove_client_from_file_list(struct mei_device *dev, - u8 host_client_id) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (host_client_id == cl_pos->host_client_id) { - dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del_init(&cl_pos->link); - break; - } - } -} diff --git a/drivers/staging/mei/interface.c b/drivers/staging/mei/interface.c deleted file mode 100644 index 4959aae37b8..00000000000 --- a/drivers/staging/mei/interface.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - -#include <linux/pci.h> -#include "mei_dev.h" -#include "mei.h" -#include "interface.h" - - - -/** - * mei_set_csr_register - writes H_CSR register to the mei device, - * and ignores the H_IS bit for it is write-one-to-zero. - * - * @dev: the device structure - */ -void mei_hcsr_set(struct mei_device *dev) -{ - if ((dev->host_hw_state & H_IS) == H_IS) - dev->host_hw_state &= ~H_IS; - mei_reg_write(dev, H_CSR, dev->host_hw_state); - dev->host_hw_state = mei_hcsr_read(dev); -} - -/** - * mei_csr_enable_interrupts - enables mei device interrupts - * - * @dev: the device structure - */ -void mei_enable_interrupts(struct mei_device *dev) -{ - dev->host_hw_state |= H_IE; - mei_hcsr_set(dev); -} - -/** - * mei_csr_disable_interrupts - disables mei device interrupts - * - * @dev: the device structure - */ -void mei_disable_interrupts(struct mei_device *dev) -{ - dev->host_hw_state &= ~H_IE; - mei_hcsr_set(dev); -} - -/** - * _host_get_filled_slots - gets number of device filled buffer slots - * - * @device: the device structure - * - * returns number of filled slots - */ -static unsigned char _host_get_filled_slots(const struct mei_device *dev) -{ - char read_ptr, write_ptr; - - read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8); - write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16); - - return (unsigned char) (write_ptr - read_ptr); -} - -/** - * mei_host_buffer_is_empty - checks if host buffer is empty. - * - * @dev: the device structure - * - * returns 1 if empty, 0 - otherwise. - */ -int mei_host_buffer_is_empty(struct mei_device *dev) -{ - unsigned char filled_slots; - - dev->host_hw_state = mei_hcsr_read(dev); - filled_slots = _host_get_filled_slots(dev); - - if (filled_slots == 0) - return 1; - - return 0; -} - -/** - * mei_count_empty_write_slots - counts write empty slots. - * - * @dev: the device structure - * - * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count - */ -int mei_count_empty_write_slots(struct mei_device *dev) -{ - unsigned char buffer_depth, filled_slots, empty_slots; - - dev->host_hw_state = mei_hcsr_read(dev); - buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24); - filled_slots = _host_get_filled_slots(dev); - empty_slots = buffer_depth - filled_slots; - - /* check for overflow */ - if (filled_slots > buffer_depth) - return -EOVERFLOW; - - return empty_slots; -} - -/** - * mei_write_message - writes a message to mei device. - * - * @dev: the device structure - * @header: header of message - * @write_buffer: message buffer will be written - * @write_length: message size will be written - * - * returns 1 if success, 0 - otherwise. - */ -int mei_write_message(struct mei_device *dev, - struct mei_msg_hdr *header, - unsigned char *write_buffer, - unsigned long write_length) -{ - u32 temp_msg = 0; - unsigned long bytes_written = 0; - unsigned char buffer_depth, filled_slots, empty_slots; - unsigned long dw_to_write; - - dev->host_hw_state = mei_hcsr_read(dev); - - dev_dbg(&dev->pdev->dev, - "host_hw_state = 0x%08x.\n", - dev->host_hw_state); - - dev_dbg(&dev->pdev->dev, - "mei_write_message header=%08x.\n", - *((u32 *) header)); - - buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24); - filled_slots = _host_get_filled_slots(dev); - empty_slots = buffer_depth - filled_slots; - dev_dbg(&dev->pdev->dev, - "filled = %hu, empty = %hu.\n", - filled_slots, empty_slots); - - dw_to_write = ((write_length + 3) / 4); - - if (dw_to_write > empty_slots) - return 0; - - mei_reg_write(dev, H_CB_WW, *((u32 *) header)); - - while (write_length >= 4) { - mei_reg_write(dev, H_CB_WW, - *(u32 *) (write_buffer + bytes_written)); - bytes_written += 4; - write_length -= 4; - } - - if (write_length > 0) { - memcpy(&temp_msg, &write_buffer[bytes_written], write_length); - mei_reg_write(dev, H_CB_WW, temp_msg); - } - - dev->host_hw_state |= H_IG; - mei_hcsr_set(dev); - dev->me_hw_state = mei_mecsr_read(dev); - if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) - return 0; - - dev->write_hang = 0; - return 1; -} - -/** - * mei_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) -{ - 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); - filled_slots = (unsigned char) (write_ptr - read_ptr); - - /* check for overflow */ - if (filled_slots > buffer_depth) - return -EOVERFLOW; - - dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots); - return (int)filled_slots; -} - -/** - * mei_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, unsigned long buffer_length) -{ - u32 i = 0; - unsigned char temp_buf[sizeof(u32)]; - - while (buffer_length >= sizeof(u32)) { - ((u32 *) buffer)[i] = mei_mecbrw_read(dev); - - dev_dbg(&dev->pdev->dev, - "buffer[%d]= %d\n", - i, ((u32 *) buffer)[i]); - - i++; - buffer_length -= sizeof(u32); - } - - if (buffer_length > 0) { - *((u32 *) &temp_buf) = mei_mecbrw_read(dev); - memcpy(&buffer[i * 4], temp_buf, buffer_length); - } - - dev->host_hw_state |= H_IG; - mei_hcsr_set(dev); -} - -/** - * mei_flow_ctrl_creds - checks flow_control credentials. - * - * @dev: the device structure - * @cl: private data of the file object - * - * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise. - * -ENOENT if mei_cl is not present - * -EINVAL if single_recv_buf == 0 - */ -int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl) -{ - int i; - - if (!dev->num_mei_me_clients) - return 0; - - if (cl->mei_flow_ctrl_creds > 0) - return 1; - - for (i = 0; i < dev->num_mei_me_clients; i++) { - struct mei_me_client *me_cl = &dev->me_clients[i]; - if (me_cl->client_id == cl->me_client_id) { - if (me_cl->mei_flow_ctrl_creds) { - if (WARN_ON(me_cl->props.single_recv_buf == 0)) - return -EINVAL; - return 1; - } else { - return 0; - } - } - } - return -ENOENT; -} - -/** - * mei_flow_ctrl_reduce - reduces flow_control. - * - * @dev: the device structure - * @cl: private data of the file object - * @returns - * 0 on success - * -ENOENT when me client is not found - * -EINVAL wehn ctrl credits are <= 0 - */ -int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) -{ - int i; - - if (!dev->num_mei_me_clients) - return -ENOENT; - - for (i = 0; i < dev->num_mei_me_clients; i++) { - struct mei_me_client *me_cl = &dev->me_clients[i]; - if (me_cl->client_id == cl->me_client_id) { - if (me_cl->props.single_recv_buf != 0) { - if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) - return -EINVAL; - dev->me_clients[i].mei_flow_ctrl_creds--; - } else { - if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) - return -EINVAL; - cl->mei_flow_ctrl_creds--; - } - return 0; - } - } - return -ENOENT; -} - -/** - * mei_send_flow_control - sends flow control to fw. - * - * @dev: the device structure - * @cl: private data of the file object - * - * returns 1 if success, 0 - otherwise. - */ -int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl) -{ - struct mei_msg_hdr *mei_hdr; - struct hbm_flow_control *mei_flow_control; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_flow_control); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1]; - memset(mei_flow_control, 0, sizeof(mei_flow_control)); - mei_flow_control->host_addr = cl->host_client_id; - mei_flow_control->me_addr = cl->me_client_id; - mei_flow_control->cmd.cmd = MEI_FLOW_CONTROL_CMD; - memset(mei_flow_control->reserved, 0, - sizeof(mei_flow_control->reserved)); - dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n", - cl->host_client_id, cl->me_client_id); - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) mei_flow_control, - sizeof(struct hbm_flow_control))) - return 0; - - return 1; - -} - -/** - * mei_other_client_is_connecting - checks if other - * client with the same client id is connected. - * - * @dev: the device structure - * @cl: private data of the file object - * - * returns 1 if other client is connected, 0 - otherwise. - */ -int mei_other_client_is_connecting(struct mei_device *dev, - struct mei_cl *cl) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if ((cl_pos->state == MEI_FILE_CONNECTING) && - (cl_pos != cl) && - cl->me_client_id == cl_pos->me_client_id) - return 1; - - } - return 0; -} - -/** - * mei_disconnect - sends disconnect message to fw. - * - * @dev: the device structure - * @cl: private data of the file object - * - * returns 1 if success, 0 - otherwise. - */ -int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) -{ - struct mei_msg_hdr *mei_hdr; - struct hbm_client_disconnect_request *mei_cli_disconnect; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_disconnect_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_cli_disconnect = - (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1]; - memset(mei_cli_disconnect, 0, sizeof(mei_cli_disconnect)); - mei_cli_disconnect->host_addr = cl->host_client_id; - mei_cli_disconnect->me_addr = cl->me_client_id; - mei_cli_disconnect->cmd.cmd = CLIENT_DISCONNECT_REQ_CMD; - mei_cli_disconnect->reserved[0] = 0; - - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) mei_cli_disconnect, - sizeof(struct hbm_client_disconnect_request))) - return 0; - - return 1; -} - -/** - * mei_connect - sends connect message to fw. - * - * @dev: the device structure - * @cl: private data of the file object - * - * returns 1 if success, 0 - otherwise. - */ -int mei_connect(struct mei_device *dev, struct mei_cl *cl) -{ - struct mei_msg_hdr *mei_hdr; - struct hbm_client_connect_request *mei_cli_connect; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_connect_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_cli_connect = - (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; - mei_cli_connect->host_addr = cl->host_client_id; - mei_cli_connect->me_addr = cl->me_client_id; - mei_cli_connect->cmd.cmd = CLIENT_CONNECT_REQ_CMD; - mei_cli_connect->reserved = 0; - - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) mei_cli_connect, - sizeof(struct hbm_client_connect_request))) - return 0; - - return 1; -} diff --git a/drivers/staging/mei/interface.h b/drivers/staging/mei/interface.h deleted file mode 100644 index d0bf5cf4f3e..00000000000 --- a/drivers/staging/mei/interface.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - - - -#ifndef _MEI_INTERFACE_H_ -#define _MEI_INTERFACE_H_ - -#include "mei.h" -#include "mei_dev.h" - - -#define AMT_WD_VALUE 120 /* seconds */ - -#define MEI_WATCHDOG_DATA_SIZE 16 -#define MEI_START_WD_DATA_SIZE 20 -#define MEI_WD_PARAMS_SIZE 4 - - -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 *write_buffer, - unsigned long write_length); - -int mei_host_buffer_is_empty(struct mei_device *dev); - -int mei_count_full_read_slots(struct mei_device *dev); - -int mei_count_empty_write_slots(struct mei_device *dev); - -int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl); - -int mei_wd_send(struct mei_device *dev); -int mei_wd_stop(struct mei_device *dev, bool preserve); -void mei_wd_host_init(struct mei_device *dev); -void mei_wd_start_setup(struct mei_device *dev); - -int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl); - -int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl); - -int mei_disconnect(struct mei_device *dev, struct mei_cl *cl); -int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl); -int mei_connect(struct mei_device *dev, struct mei_cl *cl); - -#endif /* _MEI_INTERFACE_H_ */ diff --git a/drivers/staging/mei/interrupt.c b/drivers/staging/mei/interrupt.c deleted file mode 100644 index d1b9214c10c..00000000000 --- a/drivers/staging/mei/interrupt.c +++ /dev/null @@ -1,1624 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - - -#include <linux/pci.h> -#include <linux/kthread.h> -#include <linux/interrupt.h> -#include <linux/fs.h> -#include <linux/jiffies.h> - -#include "mei_dev.h" -#include "mei.h" -#include "hw.h" -#include "interface.h" - - -/** - * 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; - u32 csr_reg = mei_hcsr_read(dev); - - 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); - - return IRQ_WAKE_THREAD; -} - -/** - * _mei_cmpl - 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) -{ - if (cb_pos->major_file_operations == MEI_WRITE) { - mei_free_cb_private(cb_pos); - cb_pos = NULL; - cl->writing_state = MEI_WRITE_COMPLETE; - if (waitqueue_active(&cl->tx_wait)) - wake_up_interruptible(&cl->tx_wait); - - } else if (cb_pos->major_file_operations == MEI_READ && - MEI_READING == cl->reading_state) { - cl->reading_state = MEI_READ_COMPLETE; - if (waitqueue_active(&cl->rx_wait)) - wake_up_interruptible(&cl->rx_wait); - - } -} - -/** - * _mei_cmpl_iamthif - processes completed iamthif operation. - * - * @dev: the device structure. - * @cb_pos: callback block. - */ -static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos) -{ - if (dev->iamthif_canceled != 1) { - dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; - dev->iamthif_stall_timer = 0; - memcpy(cb_pos->response_buffer.data, - dev->iamthif_msg_buf, - dev->iamthif_msg_buf_index); - list_add_tail(&cb_pos->cb_list, - &dev->amthi_read_complete_list.mei_cb.cb_list); - dev_dbg(&dev->pdev->dev, "amthi read completed.\n"); - dev->iamthif_timer = jiffies; - dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", - dev->iamthif_timer); - } else { - run_next_iamthif_cmd(dev); - } - - dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); - wake_up_interruptible(&dev->iamthif_cl.wait); -} - - -/** - * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to - * handle the read amthi message data processing. - * - * @complete_list: An instance of our list structure - * @dev: the device structure - * @mei_hdr: header of amthi message - * - * returns 0 on success, <0 on failure. - */ -static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list, - struct mei_device *dev, - struct mei_msg_hdr *mei_hdr) -{ - struct mei_cl *cl; - struct mei_cl_cb *cb; - unsigned char *buffer; - - BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); - BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); - - buffer = (unsigned char *) (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index); - BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); - - mei_read_slots(dev, buffer, mei_hdr->length); - - dev->iamthif_msg_buf_index += mei_hdr->length; - - if (!mei_hdr->msg_complete) - return 0; - - dev_dbg(&dev->pdev->dev, - "amthi_message_buffer_index =%d\n", - mei_hdr->length); - - dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); - if (!dev->iamthif_current_cb) - return -ENODEV; - - cb = dev->iamthif_current_cb; - dev->iamthif_current_cb = NULL; - - cl = (struct mei_cl *)cb->file_private; - if (!cl) - return -ENODEV; - - dev->iamthif_stall_timer = 0; - cb->information = dev->iamthif_msg_buf_index; - cb->read_time = jiffies; - if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) { - /* found the iamthif cb */ - dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); - dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); - list_add_tail(&cb->cb_list, - &complete_list->mei_cb.cb_list); - } - return 0; -} - -/** - * _mei_irq_thread_state_ok - checks if mei header matches file private data - * - * @cl: private data of the file object - * @mei_hdr: header of mei client message - * - * returns !=0 if matches, 0 if no match. - */ -static int _mei_irq_thread_state_ok(struct mei_cl *cl, - struct mei_msg_hdr *mei_hdr) -{ - return (cl->host_client_id == mei_hdr->host_addr && - cl->me_client_id == mei_hdr->me_addr && - cl->state == MEI_FILE_CONNECTED && - MEI_READ_COMPLETE != cl->reading_state); -} - -/** - * mei_irq_thread_read_client_message - bottom half read routine after ISR to - * handle the read mei client message data processing. - * - * @complete_list: An instance of our list structure - * @dev: the device structure - * @mei_hdr: header of mei client message - * - * returns 0 on success, <0 on failure. - */ -static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, - struct mei_device *dev, - struct mei_msg_hdr *mei_hdr) -{ - struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; - unsigned char *buffer; - - dev_dbg(&dev->pdev->dev, "start client msg\n"); - if (!(dev->read_list.status == 0 && - !list_empty(&dev->read_list.mei_cb.cb_list))) - goto quit; - - list_for_each_entry_safe(cb_pos, cb_next, - &dev->read_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { - cl->reading_state = MEI_READING; - buffer = (unsigned char *) - (cb_pos->response_buffer.data + - cb_pos->information); - BUG_ON(cb_pos->response_buffer.size < - mei_hdr->length + - cb_pos->information); - - if (cb_pos->response_buffer.size < - mei_hdr->length + cb_pos->information) { - dev_dbg(&dev->pdev->dev, "message overflow.\n"); - list_del(&cb_pos->cb_list); - return -ENOMEM; - } - if (buffer) - mei_read_slots(dev, buffer, mei_hdr->length); - - cb_pos->information += mei_hdr->length; - if (mei_hdr->msg_complete) { - cl->status = 0; - list_del(&cb_pos->cb_list); - dev_dbg(&dev->pdev->dev, - "completed read host client = %d," - "ME client = %d, " - "data length = %lu\n", - cl->host_client_id, - cl->me_client_id, - cb_pos->information); - - *(cb_pos->response_buffer.data + - cb_pos->information) = '\0'; - dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n", - cb_pos->response_buffer.data); - list_add_tail(&cb_pos->cb_list, - &complete_list->mei_cb.cb_list); - } - - break; - } - - } - -quit: - dev_dbg(&dev->pdev->dev, "message read\n"); - if (!buffer) { - mei_read_slots(dev, (unsigned char *) dev->rd_msg_buf, - mei_hdr->length); - dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n", - *(u32 *) dev->rd_msg_buf); - } - - return 0; -} - -/** - * _mei_irq_thread_iamthif_read - prepares to read iamthif data. - * - * @dev: the device structure. - * @slots: free slots. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) -{ - - if (((*slots) * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) - + sizeof(struct hbm_flow_control))) { - *slots -= (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_flow_control) + 3) / 4; - if (!mei_send_flow_control(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); - } else { - dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); - dev->iamthif_state = MEI_IAMTHIF_READING; - dev->iamthif_flow_control_pending = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER; - dev->mei_host_buffer_is_empty = - mei_host_buffer_is_empty(dev); - } - return 0; - } else { - return -EMSGSIZE; - } -} - -/** - * _mei_irq_thread_close - processes close related operation. - * - * @dev: the device structure. - * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. - * @cmpl_list: complete list. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) -{ - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_client_disconnect_request))) { - *slots -= (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_client_disconnect_request) + 3) / 4; - - if (!mei_disconnect(dev, cl)) { - cl->status = 0; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - return -EMSGSIZE; - } else { - cl->state = MEI_FILE_DISCONNECTING; - cl->status = 0; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); - cl->timer_count = MEI_CONNECT_TIMEOUT; - } - } else { - /* return the cancel routine */ - return -EBADMSG; - } - - return 0; -} - -/** - * is_treat_specially_client - checks if the message belongs - * to the file private data. - * - * @cl: private data of the file object - * @rs: connect response bus message - * - */ -static bool is_treat_specially_client(struct mei_cl *cl, - struct hbm_client_connect_response *rs) -{ - - if (cl->host_client_id == rs->host_addr && - cl->me_client_id == rs->me_addr) { - if (!rs->status) { - cl->state = MEI_FILE_CONNECTED; - cl->status = 0; - - } else { - cl->state = MEI_FILE_DISCONNECTED; - cl->status = -ENODEV; - } - cl->timer_count = 0; - - return true; - } - return false; -} - -/** - * mei_client_connect_response - connects to response irq routine - * - * @dev: the device structure - * @rs: connect response bus message - */ -static void mei_client_connect_response(struct mei_device *dev, - struct hbm_client_connect_response *rs) -{ - - struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; - - dev_dbg(&dev->pdev->dev, - "connect_response:\n" - "ME Client = %d\n" - "Host Client = %d\n" - "Status = %d\n", - rs->me_addr, - rs->host_addr, - rs->status); - - /* if WD or iamthif client treat specially */ - - if (is_treat_specially_client(&(dev->wd_cl), rs)) { - dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", - dev->wd_timeout); - - dev->wd_due_counter = (dev->wd_timeout) ? 1 : 0; - - dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); - host_init_iamthif(dev); - return; - } - - if (is_treat_specially_client(&(dev->iamthif_cl), rs)) { - dev->iamthif_state = MEI_IAMTHIF_IDLE; - return; - } - if (!dev->ctrl_rd_list.status && - !list_empty(&dev->ctrl_rd_list.mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - if (!cl) { - list_del(&cb_pos->cb_list); - return; - } - if (MEI_IOCTL == cb_pos->major_file_operations) { - if (is_treat_specially_client(cl, rs)) { - list_del(&cb_pos->cb_list); - cl->status = 0; - cl->timer_count = 0; - break; - } - } - } - } -} - -/** - * mei_client_disconnect_response - disconnects from response irq routine - * - * @dev: the device structure - * @rs: disconnect response bus message - */ -static void mei_client_disconnect_response(struct mei_device *dev, - struct hbm_client_connect_response *rs) -{ - struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; - - dev_dbg(&dev->pdev->dev, - "disconnect_response:\n" - "ME Client = %d\n" - "Host Client = %d\n" - "Status = %d\n", - rs->me_addr, - rs->host_addr, - rs->status); - - if (!dev->ctrl_rd_list.status && - !list_empty(&dev->ctrl_rd_list.mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - - if (!cl) { - list_del(&cb_pos->cb_list); - return; - } - - dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n"); - if (cl->host_client_id == rs->host_addr && - cl->me_client_id == rs->me_addr) { - - list_del(&cb_pos->cb_list); - if (!rs->status) - cl->state = MEI_FILE_DISCONNECTED; - - cl->status = 0; - cl->timer_count = 0; - break; - } - } - } -} - -/** - * same_flow_addr - tells if they have the same address. - * - * @file: private data of the file object. - * @flow: flow control. - * - * returns !=0, same; 0,not. - */ -static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow) -{ - return (cl->host_client_id == flow->host_addr && - cl->me_client_id == flow->me_addr); -} - -/** - * add_single_flow_creds - adds single buffer credentials. - * - * @file: private data ot the file object. - * @flow: flow control. - */ -static void add_single_flow_creds(struct mei_device *dev, - struct hbm_flow_control *flow) -{ - struct mei_me_client *client; - int i; - - for (i = 0; i < dev->num_mei_me_clients; i++) { - client = &dev->me_clients[i]; - if (client && flow->me_addr == client->client_id) { - if (client->props.single_recv_buf) { - client->mei_flow_ctrl_creds++; - dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n", - flow->me_addr); - dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n", - client->mei_flow_ctrl_creds); - } else { - BUG(); /* error in flow control */ - } - } - } -} - -/** - * mei_client_flow_control_response - flow control response irq routine - * - * @dev: the device structure - * @flow_control: flow control response bus message - */ -static void mei_client_flow_control_response(struct mei_device *dev, - struct hbm_flow_control *flow_control) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - - if (!flow_control->host_addr) { - /* single receive buffer */ - add_single_flow_creds(dev, flow_control); - } else { - /* normal connection */ - list_for_each_entry_safe(cl_pos, cl_next, - &dev->file_list, link) { - dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n"); - - dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n", - flow_control->host_addr, - flow_control->me_addr); - if (same_flow_addr(cl_pos, flow_control)) { - dev_dbg(&dev->pdev->dev, "recv ctrl msg for host %d ME %d.\n", - flow_control->host_addr, - flow_control->me_addr); - cl_pos->mei_flow_ctrl_creds++; - dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n", - cl_pos->mei_flow_ctrl_creds); - break; - } - } - } -} - -/** - * same_disconn_addr - tells if they have the same address - * - * @file: private data of the file object. - * @disconn: disconnection request. - * - * returns !=0, same; 0,not. - */ -static int same_disconn_addr(struct mei_cl *cl, - struct hbm_client_disconnect_request *disconn) -{ - return (cl->host_client_id == disconn->host_addr && - cl->me_client_id == disconn->me_addr); -} - -/** - * mei_client_disconnect_request - disconnects from request irq routine - * - * @dev: the device structure. - * @disconnect_req: disconnect request bus message. - */ -static void mei_client_disconnect_request(struct mei_device *dev, - struct hbm_client_disconnect_request *disconnect_req) -{ - struct mei_msg_hdr *mei_hdr; - struct hbm_client_connect_response *disconnect_res; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (same_disconn_addr(cl_pos, disconnect_req)) { - dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n", - disconnect_req->host_addr, - disconnect_req->me_addr); - cl_pos->state = MEI_FILE_DISCONNECTED; - cl_pos->timer_count = 0; - if (cl_pos == &dev->wd_cl) { - dev->wd_due_counter = 0; - dev->wd_pending = 0; - } else if (cl_pos == &dev->iamthif_cl) - dev->iamthif_timer = 0; - - /* prepare disconnect response */ - mei_hdr = - (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = - sizeof(struct hbm_client_connect_response); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - disconnect_res = - (struct hbm_client_connect_response *) - &dev->ext_msg_buf[1]; - disconnect_res->host_addr = cl_pos->host_client_id; - disconnect_res->me_addr = cl_pos->me_client_id; - *(u8 *) (&disconnect_res->cmd) = - CLIENT_DISCONNECT_RES_CMD; - disconnect_res->status = 0; - dev->extra_write_index = 2; - break; - } - } -} - - -/** - * mei_irq_thread_read_bus_message - bottom half read routine after ISR to - * handle the read bus message cmd processing. - * - * @dev: the device structure - * @mei_hdr: header of bus message - */ -static void mei_irq_thread_read_bus_message(struct mei_device *dev, - struct mei_msg_hdr *mei_hdr) -{ - struct mei_bus_message *mei_msg; - struct hbm_host_version_response *version_res; - struct hbm_client_connect_response *connect_res; - struct hbm_client_connect_response *disconnect_res; - struct hbm_flow_control *flow_control; - struct hbm_props_response *props_res; - struct hbm_host_enum_response *enum_res; - struct hbm_client_disconnect_request *disconnect_req; - struct hbm_host_stop_request *host_stop_req; - - unsigned char *buffer; - - /* read the message to our buffer */ - buffer = (unsigned char *) dev->rd_msg_buf; - BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf)); - mei_read_slots(dev, buffer, mei_hdr->length); - mei_msg = (struct mei_bus_message *) buffer; - - switch (*(u8 *) mei_msg) { - case HOST_START_RES_CMD: - version_res = (struct hbm_host_version_response *) mei_msg; - if (version_res->host_version_supported) { - dev->version.major_version = HBM_MAJOR_VERSION; - dev->version.minor_version = HBM_MINOR_VERSION; - if (dev->mei_state == MEI_INIT_CLIENTS && - dev->init_clients_state == MEI_START_MESSAGE) { - dev->init_clients_timer = 0; - host_enum_clients_message(dev); - } else { - dev->recvd_msg = 0; - dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n"); - mei_reset(dev, 1); - return; - } - } else { - dev->version = version_res->me_max_version; - /* send stop message */ - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_stop_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_stop_req = (struct hbm_host_stop_request *) - &dev->wr_msg_buf[1]; - - memset(host_stop_req, - 0, - sizeof(struct hbm_host_stop_request)); - host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD; - host_stop_req->reason = DRIVER_STOP_REQUEST; - mei_write_message(dev, mei_hdr, - (unsigned char *) (host_stop_req), - mei_hdr->length); - dev_dbg(&dev->pdev->dev, "version mismatch.\n"); - return; - } - - dev->recvd_msg = 1; - dev_dbg(&dev->pdev->dev, "host start response message received.\n"); - break; - - case CLIENT_CONNECT_RES_CMD: - connect_res = - (struct hbm_client_connect_response *) mei_msg; - mei_client_connect_response(dev, connect_res); - dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); - wake_up(&dev->wait_recvd_msg); - break; - - case CLIENT_DISCONNECT_RES_CMD: - disconnect_res = - (struct hbm_client_connect_response *) mei_msg; - mei_client_disconnect_response(dev, disconnect_res); - dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); - wake_up(&dev->wait_recvd_msg); - break; - - case MEI_FLOW_CONTROL_CMD: - flow_control = (struct hbm_flow_control *) mei_msg; - mei_client_flow_control_response(dev, flow_control); - dev_dbg(&dev->pdev->dev, "client flow control response message received.\n"); - break; - - case HOST_CLIENT_PROPERTIES_RES_CMD: - props_res = (struct hbm_props_response *)mei_msg; - if (props_res->status || !dev->me_clients) { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n"); - mei_reset(dev, 1); - return; - } - if (dev->me_clients[dev->me_client_presentation_num] - .client_id == props_res->address) { - - dev->me_clients[dev->me_client_presentation_num].props - = props_res->client_properties; - - if (dev->mei_state == MEI_INIT_CLIENTS && - dev->init_clients_state == - MEI_CLIENT_PROPERTIES_MESSAGE) { - dev->me_client_index++; - dev->me_client_presentation_num++; - host_client_properties(dev); - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message"); - mei_reset(dev, 1); - return; - } - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n"); - mei_reset(dev, 1); - return; - } - break; - - case HOST_ENUM_RES_CMD: - enum_res = (struct hbm_host_enum_response *) mei_msg; - memcpy(dev->me_clients_map, enum_res->valid_addresses, 32); - if (dev->mei_state == MEI_INIT_CLIENTS && - dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) { - dev->init_clients_timer = 0; - dev->me_client_presentation_num = 0; - dev->me_client_index = 0; - allocate_me_clients_storage(dev); - dev->init_clients_state = - MEI_CLIENT_PROPERTIES_MESSAGE; - host_client_properties(dev); - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); - mei_reset(dev, 1); - return; - } - break; - - case HOST_STOP_RES_CMD: - dev->mei_state = MEI_DISABLED; - dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n"); - mei_reset(dev, 1); - break; - - case CLIENT_DISCONNECT_REQ_CMD: - /* search for client */ - disconnect_req = - (struct hbm_client_disconnect_request *) mei_msg; - mei_client_disconnect_request(dev, disconnect_req); - break; - - case ME_STOP_REQ_CMD: - /* prepare stop request */ - mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_stop_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - host_stop_req = - (struct hbm_host_stop_request *) &dev->ext_msg_buf[1]; - memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request)); - host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD; - host_stop_req->reason = DRIVER_STOP_REQUEST; - host_stop_req->reserved[0] = 0; - host_stop_req->reserved[1] = 0; - dev->extra_write_index = 2; - break; - - default: - BUG(); - break; - - } -} - - -/** - * _mei_hb_read - processes read related operation. - * - * @dev: the device structure. - * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. - * @cmpl_list: complete list. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) -{ - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_flow_control))) { - *slots -= (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_flow_control) + 3) / 4; - if (!mei_send_flow_control(dev, cl)) { - cl->status = -ENODEV; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - return -ENODEV; - } else { - list_move_tail(&cb_pos->cb_list, - &dev->read_list.mei_cb.cb_list); - } - } else { - /* return the cancel routine */ - list_del(&cb_pos->cb_list); - return -EBADMSG; - } - - return 0; -} - - -/** - * _mei_irq_thread_ioctl - processes ioctl related operation. - * - * @dev: the device structure. - * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. - * @cmpl_list: complete list. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) -{ - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_client_connect_request))) { - cl->state = MEI_FILE_CONNECTING; - *slots -= (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_client_connect_request) + 3) / 4; - if (!mei_connect(dev, cl)) { - cl->status = -ENODEV; - cb_pos->information = 0; - list_del(&cb_pos->cb_list); - return -ENODEV; - } else { - list_move_tail(&cb_pos->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); - cl->timer_count = MEI_CONNECT_TIMEOUT; - } - } else { - /* return the cancel routine */ - list_del(&cb_pos->cb_list); - return -EBADMSG; - } - - return 0; -} - -/** - * _mei_irq_thread_cmpl - processes completed and no-iamthif operation. - * - * @dev: the device structure. - * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. - * @cmpl_list: complete list. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) -{ - struct mei_msg_hdr *mei_hdr; - - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - (cb_pos->request_buffer.size - - cb_pos->information))) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = cb_pos->request_buffer.size - - cb_pos->information; - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d" - "mei_hdr->msg_complete = %d\n", - cb_pos->request_buffer.size, - mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", - cb_pos->information); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - *slots -= (sizeof(struct mei_msg_hdr) + - mei_hdr->length + 3) / 4; - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) - (cb_pos->request_buffer.data + - cb_pos->information), - mei_hdr->length)) { - cl->status = -ENODEV; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - cl->status = 0; - cb_pos->information += mei_hdr->length; - list_move_tail(&cb_pos->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } - } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; - - (*slots) -= (sizeof(struct mei_msg_hdr) + - mei_hdr->length + 3) / 4; - if (!mei_write_message(dev, mei_hdr, - (unsigned char *) - (cb_pos->request_buffer.data + - cb_pos->information), - mei_hdr->length)) { - cl->status = -ENODEV; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - return -ENODEV; - } else { - cb_pos->information += mei_hdr->length; - dev_dbg(&dev->pdev->dev, - "cb_pos->request_buffer.size =%d" - " mei_hdr->msg_complete = %d\n", - cb_pos->request_buffer.size, - mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", - cb_pos->information); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - } - return -EMSGSIZE; - } else { - return -EBADMSG; - } - - return 0; -} - -/** - * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation. - * - * @dev: the device structure. - * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. - * @cmpl_list: complete list. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) -{ - struct mei_msg_hdr *mei_hdr; - - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index)) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index; - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - *slots -= (sizeof(struct mei_msg_hdr) + - mei_hdr->length + 3) / 4; - - if (!mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - dev->iamthif_state = MEI_IAMTHIF_IDLE; - cl->status = -ENODEV; - list_del(&cb_pos->cb_list); - return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - dev->iamthif_msg_buf_index += mei_hdr->length; - cb_pos->information = dev->iamthif_msg_buf_index; - cl->status = 0; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev->iamthif_flow_control_pending = 1; - /* save iamthif cb sent to amthi client */ - dev->iamthif_current_cb = cb_pos; - list_move_tail(&cb_pos->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - - } - } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; - - *slots -= (sizeof(struct mei_msg_hdr) + - mei_hdr->length + 3) / 4; - - if (!mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - cl->status = -ENODEV; - list_del(&cb_pos->cb_list); - } else { - dev->iamthif_msg_buf_index += mei_hdr->length; - } - return -EMSGSIZE; - } else { - return -EBADMSG; - } - - return 0; -} - -/** - * 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 - * @slots: slots to read. - * - * returns 0 on success, <0 on failure. - */ -static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list, - struct mei_device *dev, - s32 *slots) -{ - struct mei_msg_hdr *mei_hdr; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - int ret = 0; - - if (!dev->rd_msg_hdr) { - dev->rd_msg_hdr = mei_mecbrw_read(dev); - dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); - (*slots)--; - dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots); - } - mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr; - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length); - - if (mei_hdr->reserved || !dev->rd_msg_hdr) { - dev_dbg(&dev->pdev->dev, "corrupted message header.\n"); - ret = -EBADMSG; - goto end; - } - - if (mei_hdr->host_addr || mei_hdr->me_addr) { - list_for_each_entry_safe(cl_pos, cl_next, - &dev->file_list, link) { - dev_dbg(&dev->pdev->dev, - "list_for_each_entry_safe read host" - " client = %d, ME client = %d\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - if (cl_pos->host_client_id == mei_hdr->host_addr && - cl_pos->me_client_id == mei_hdr->me_addr) - break; - } - - if (&cl_pos->link == &dev->file_list) { - dev_dbg(&dev->pdev->dev, "corrupted message header\n"); - ret = -EBADMSG; - goto end; - } - } - if (((*slots) * sizeof(u32)) < mei_hdr->length) { - dev_dbg(&dev->pdev->dev, - "we can't read the message slots =%08x.\n", - *slots); - /* we can't read the message */ - ret = -ERANGE; - goto end; - } - - /* decide where to read the message too */ - if (!mei_hdr->host_addr) { - dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n"); - mei_irq_thread_read_bus_message(dev, mei_hdr); - dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n"); - } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id && - (MEI_FILE_CONNECTED == dev->iamthif_cl.state) && - (dev->iamthif_state == MEI_IAMTHIF_READING)) { - dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - ret = mei_irq_thread_read_amthi_message(cmpl_list, - dev, mei_hdr); - if (ret) - goto end; - - } else { - dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n"); - ret = mei_irq_thread_read_client_message(cmpl_list, - dev, mei_hdr); - if (ret) - goto end; - - } - - /* reset the number of slots and header */ - *slots = mei_count_full_read_slots(dev); - dev->rd_msg_hdr = 0; - - if (*slots == -EOVERFLOW) { - /* overflow - reset */ - dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n"); - /* set the event since message has been read */ - ret = -ERANGE; - goto end; - } -end: - return ret; -} - - -/** - * mei_irq_thread_write_handler - bottom half write routine after - * ISR to handle the write processing. - * - * @cmpl_list: An instance of our list structure - * @dev: the device structure - * @slots: slots to write. - * - * returns 0 on success, <0 on failure. - */ -static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, - struct mei_device *dev, - s32 *slots) -{ - - struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; - struct mei_io_list *list; - int ret; - - if (!mei_host_buffer_is_empty(dev)) { - dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n"); - return 0; - } - dev->write_hang = -1; - *slots = mei_count_empty_write_slots(dev); - /* complete all waiting for write CB */ - dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); - - list = &dev->write_waiting_list; - if (!list->status && !list_empty(&list->mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &list->mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - if (cl) { - cl->status = 0; - list_del(&cb_pos->cb_list); - if (MEI_WRITING == cl->writing_state && - (cb_pos->major_file_operations == - MEI_WRITE) && - (cl != &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, - "MEI WRITE COMPLETE\n"); - cl->writing_state = - MEI_WRITE_COMPLETE; - list_add_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - } - if (cl == &dev->iamthif_cl) { - dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); - if (dev->iamthif_flow_control_pending) { - ret = - _mei_irq_thread_iamthif_read( - dev, slots); - if (ret) - return ret; - } - } - } - - } - } - - if (dev->stop && !dev->wd_pending) { - dev->wd_stopped = 1; - wake_up_interruptible(&dev->wait_stop_wd); - return 0; - } - - if (dev->extra_write_index) { - dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n", - dev->extra_write_index); - mei_write_message(dev, - (struct mei_msg_hdr *) &dev->ext_msg_buf[0], - (unsigned char *) &dev->ext_msg_buf[1], - (dev->extra_write_index - 1) * sizeof(u32)); - *slots -= dev->extra_write_index; - dev->extra_write_index = 0; - } - if (dev->mei_state == MEI_ENABLED) { - if (dev->wd_pending && - mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) { - if (mei_wd_send(dev)) - dev_dbg(&dev->pdev->dev, "wd send failed.\n"); - else - if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) - return -ENODEV; - - dev->wd_pending = 0; - - if (dev->wd_timeout) { - *slots -= (sizeof(struct mei_msg_hdr) + - MEI_START_WD_DATA_SIZE + 3) / 4; - dev->wd_due_counter = 2; - } else { - *slots -= (sizeof(struct mei_msg_hdr) + - MEI_WD_PARAMS_SIZE + 3) / 4; - dev->wd_due_counter = 0; - } - - } - } - if (dev->stop) - return ~ENODEV; - - /* complete control write list CB */ - if (!dev->ctrl_wr_list.status) { - /* complete control write list CB */ - dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *) - cb_pos->file_private; - if (!cl) { - list_del(&cb_pos->cb_list); - return -ENODEV; - } - switch (cb_pos->major_file_operations) { - case MEI_CLOSE: - /* send disconnect message */ - ret = _mei_irq_thread_close(dev, slots, - cb_pos, cl, cmpl_list); - if (ret) - return ret; - - break; - case MEI_READ: - /* send flow control message */ - ret = _mei_irq_thread_read(dev, slots, - cb_pos, cl, cmpl_list); - if (ret) - return ret; - - break; - case MEI_IOCTL: - /* connect message */ - if (!mei_other_client_is_connecting(dev, - cl)) - continue; - ret = _mei_irq_thread_ioctl(dev, slots, - cb_pos, cl, cmpl_list); - if (ret) - return ret; - - break; - - default: - BUG(); - } - - } - } - /* complete write list CB */ - if (!dev->write_list.status && - !list_empty(&dev->write_list.mei_cb.cb_list)) { - dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); - list_for_each_entry_safe(cb_pos, cb_next, - &dev->write_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - - if (cl) { - if (cl != &dev->iamthif_cl) { - if (!mei_flow_ctrl_creds(dev, - cl)) { - dev_dbg(&dev->pdev->dev, - "No flow control" - " credentials for client" - " %d, not sending.\n", - cl->host_client_id); - continue; - } - ret = _mei_irq_thread_cmpl(dev, slots, - cb_pos, - cl, cmpl_list); - if (ret) - return ret; - - } else if (cl == &dev->iamthif_cl) { - /* IAMTHIF IOCTL */ - dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n"); - if (!mei_flow_ctrl_creds(dev, - cl)) { - dev_dbg(&dev->pdev->dev, - "No flow control" - " credentials for amthi" - " client %d.\n", - cl->host_client_id); - continue; - } - ret = _mei_irq_thread_cmpl_iamthif(dev, - slots, - cb_pos, - cl, - cmpl_list); - if (ret) - return ret; - - } - } - - } - } - return 0; -} - - - -/** - * mei_timer - timer function. - * - * @work: pointer to the work_struct structure - * - * NOTE: This function is called by timer interrupt work - */ -void mei_wd_timer(struct work_struct *work) -{ - unsigned long timeout; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - struct list_head *amthi_complete_list = NULL; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - - struct mei_device *dev = container_of(work, - struct mei_device, wd_work.work); - - - mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { - if (dev->mei_state == MEI_INIT_CLIENTS) { - if (dev->init_clients_timer) { - if (--dev->init_clients_timer == 0) { - dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n", - dev->init_clients_state); - mei_reset(dev, 1); - } - } - } - goto out; - } - /*** connect/disconnect timeouts ***/ - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (cl_pos->timer_count) { - if (--cl_pos->timer_count == 0) { - dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n"); - mei_reset(dev, 1); - goto out; - } - } - } - - if (dev->wd_cl.state != MEI_FILE_CONNECTED) - goto out; - - /* Watchdog */ - if (dev->wd_due_counter && !dev->wd_bypass) { - if (--dev->wd_due_counter == 0) { - if (dev->mei_host_buffer_is_empty && - mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) { - dev->mei_host_buffer_is_empty = 0; - dev_dbg(&dev->pdev->dev, "send watchdog.\n"); - - if (mei_wd_send(dev)) - dev_dbg(&dev->pdev->dev, "wd send failed.\n"); - else - if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) - goto out; - - if (dev->wd_timeout) - dev->wd_due_counter = 2; - else - dev->wd_due_counter = 0; - - } else - dev->wd_pending = 1; - - } - } - if (dev->iamthif_stall_timer) { - if (--dev->iamthif_stall_timer == 0) { - dev_dbg(&dev->pdev->dev, "reseting because of hang to amthi.\n"); - mei_reset(dev, 1); - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = 0; - dev->iamthif_ioctl = 1; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; - - if (dev->iamthif_current_cb) - mei_free_cb_private(dev->iamthif_current_cb); - - dev->iamthif_file_object = NULL; - dev->iamthif_current_cb = NULL; - run_next_iamthif_cmd(dev); - } - } - - if (dev->iamthif_timer) { - - timeout = dev->iamthif_timer + - msecs_to_jiffies(IAMTHIF_READ_TIMER); - - dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", - dev->iamthif_timer); - dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout); - dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies); - if (time_after(jiffies, timeout)) { - /* - * User didn't read the AMTHI data on time (15sec) - * freeing AMTHI for other requests - */ - - dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n"); - - amthi_complete_list = &dev->amthi_read_complete_list. - mei_cb.cb_list; - - if (!list_empty(amthi_complete_list)) { - - list_for_each_entry_safe(cb_pos, cb_next, - amthi_complete_list, - cb_list) { - - cl_pos = cb_pos->file_object->private_data; - - /* Finding the AMTHI entry. */ - if (cl_pos == &dev->iamthif_cl) - list_del(&cb_pos->cb_list); - } - } - if (dev->iamthif_current_cb) - mei_free_cb_private(dev->iamthif_current_cb); - - dev->iamthif_file_object->private_data = NULL; - dev->iamthif_file_object = NULL; - dev->iamthif_current_cb = NULL; - dev->iamthif_timer = 0; - run_next_iamthif_cmd(dev); - - } - } -out: - schedule_delayed_work(&dev->wd_work, 2 * HZ); - 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_io_list 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_initialize_list(&complete_list, dev); - dev->host_hw_state = mei_hcsr_read(dev); - dev->me_hw_state = mei_mecsr_read(dev); - - /* check if ME wants a reset */ - if ((dev->me_hw_state & ME_RDY_HRA) == 0 && - dev->mei_state != MEI_RESETING && - dev->mei_state != MEI_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 ((dev->host_hw_state & H_RDY) == 0) { - if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) { - dev_dbg(&dev->pdev->dev, "we need to start the dev.\n"); - dev->host_hw_state |= (H_IE | H_IG | H_RDY); - mei_hcsr_set(dev); - dev->mei_state = MEI_INIT_CLIENTS; - dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n"); - /* link is established - * start sending messages. - */ - host_start_message(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 avalable for reading */ - slots = mei_count_full_read_slots(dev); - dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", - slots, dev->extra_write_index); - while (slots > 0 && !dev->extra_write_index) { - dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", - slots, dev->extra_write_index); - 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(&complete_list, dev, &slots); -end: - dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); - dev->host_hw_state = mei_hcsr_read(dev); - dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(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 (complete_list.status || list_empty(&complete_list.mei_cb.cb_list)) - return IRQ_HANDLED; - - - list_for_each_entry_safe(cb_pos, cb_next, - &complete_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - list_del(&cb_pos->cb_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_cmpl_iamthif(dev, cb_pos); - } - } - } - return IRQ_HANDLED; -} diff --git a/drivers/staging/mei/iorw.c b/drivers/staging/mei/iorw.c deleted file mode 100644 index 697a2773d7c..00000000000 --- a/drivers/staging/mei/iorw.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - - -#include <linux/kernel.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/init.h> -#include <linux/ioctl.h> -#include <linux/cdev.h> -#include <linux/list.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/uuid.h> -#include <linux/jiffies.h> -#include <linux/uaccess.h> - - -#include "mei_dev.h" -#include "hw.h" -#include "mei.h" -#include "interface.h" -#include "mei_version.h" - - - -/** - * mei_ioctl_connect_client - the connect to fw client IOCTL function - * - * @dev: the device structure - * @data: IOCTL connect data, input and output parameters - * @file: private data of the file object - * - * Locking: called under "dev->device_lock" lock - * - * returns 0 on success, <0 on failure. - */ -int mei_ioctl_connect_client(struct file *file, - struct mei_connect_client_data *data) -{ - struct mei_device *dev; - struct mei_cl_cb *cb; - struct mei_client *client; - struct mei_cl *cl; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - long timeout = CONNECT_TIMEOUT; - int i; - int err; - int rets; - - cl = file->private_data; - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); - - - /* buffered ioctl cb */ - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!cb) { - rets = -ENOMEM; - goto end; - } - INIT_LIST_HEAD(&cb->cb_list); - - cb->major_file_operations = MEI_IOCTL; - - if (dev->mei_state != MEI_ENABLED) { - rets = -ENODEV; - goto end; - } - if (cl->state != MEI_FILE_INITIALIZING && - cl->state != MEI_FILE_DISCONNECTED) { - rets = -EBUSY; - goto end; - } - - /* find ME client we're trying to connect to */ - i = mei_find_me_client_index(dev, data->in_client_uuid); - if (i >= 0 && !dev->me_clients[i].props.fixed_address) { - cl->me_client_id = dev->me_clients[i].client_id; - cl->state = MEI_FILE_CONNECTING; - } - - dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", - cl->me_client_id); - dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n", - dev->me_clients[i].props.protocol_version); - dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n", - dev->me_clients[i].props.max_msg_length); - - /* if we're connecting to amthi client so we will use the exist - * connection - */ - if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) { - dev_dbg(&dev->pdev->dev, "FW Client is amthi\n"); - if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - goto end; - } - clear_bit(cl->host_client_id, dev->host_clients_map); - list_for_each_entry_safe(cl_pos, cl_next, - &dev->file_list, link) { - if (mei_fe_same_id(cl, cl_pos)) { - dev_dbg(&dev->pdev->dev, - "remove file private data node host" - " client = %d, ME client = %d.\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del(&cl_pos->link); - } - - } - dev_dbg(&dev->pdev->dev, "free file private data memory.\n"); - kfree(cl); - - cl = NULL; - file->private_data = &dev->iamthif_cl; - - client = &data->out_client_properties; - client->max_msg_length = - dev->me_clients[i].props.max_msg_length; - client->protocol_version = - dev->me_clients[i].props.protocol_version; - rets = dev->iamthif_cl.status; - - goto end; - } - - if (cl->state != MEI_FILE_CONNECTING) { - rets = -ENODEV; - goto end; - } - - - /* prepare the output buffer */ - client = &data->out_client_properties; - client->max_msg_length = dev->me_clients[i].props.max_msg_length; - client->protocol_version = dev->me_clients[i].props.protocol_version; - dev_dbg(&dev->pdev->dev, "Can connect?\n"); - if (dev->mei_host_buffer_is_empty - && !mei_other_client_is_connecting(dev, cl)) { - dev_dbg(&dev->pdev->dev, "Sending Connect Message\n"); - dev->mei_host_buffer_is_empty = 0; - if (!mei_connect(dev, cl)) { - dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n"); - rets = -ENODEV; - goto end; - } else { - dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); - cl->timer_count = MEI_CONNECT_TIMEOUT; - cb->file_private = cl; - list_add_tail(&cb->cb_list, - &dev->ctrl_rd_list.mei_cb. - cb_list); - } - - - } else { - dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); - cb->file_private = cl; - dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); - } - mutex_unlock(&dev->device_lock); - err = wait_event_timeout(dev->wait_recvd_msg, - (MEI_FILE_CONNECTED == cl->state || - MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); - - mutex_lock(&dev->device_lock); - if (MEI_FILE_CONNECTED == cl->state) { - dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n"); - rets = cl->status; - goto end; - } else { - dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n", - cl->state); - if (!err) { - dev_dbg(&dev->pdev->dev, - "wait_event_interruptible_timeout failed on client" - " connect message fw response message.\n"); - } - rets = -EFAULT; - - mei_flush_list(&dev->ctrl_rd_list, cl); - mei_flush_list(&dev->ctrl_wr_list, cl); - goto end; - } - rets = 0; -end: - dev_dbg(&dev->pdev->dev, "free connect cb memory."); - kfree(cb); - return rets; -} - -/** - * find_amthi_read_list_entry - finds a amthilist entry for current file - * - * @dev: the device structure - * @file: pointer to file object - * - * returns returned a list entry on success, NULL on failure. - */ -struct mei_cl_cb *find_amthi_read_list_entry( - struct mei_device *dev, - struct file *file) -{ - struct mei_cl *cl_temp; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - - if (!dev->amthi_read_complete_list.status && - !list_empty(&dev->amthi_read_complete_list.mei_cb.cb_list)) { - list_for_each_entry_safe(cb_pos, cb_next, - &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) { - cl_temp = (struct mei_cl *)cb_pos->file_private; - if (cl_temp && cl_temp == &dev->iamthif_cl && - cb_pos->file_object == file) - return cb_pos; - } - } - return NULL; -} - -/** - * amthi_read - read data from AMTHI client - * - * @dev: the device structure - * @if_num: minor number - * @file: pointer to file object - * @*ubuf: pointer to user data in user space - * @length: data length to read - * @offset: data read offset - * - * Locking: called under "dev->device_lock" lock - * - * returns - * returned data length on success, - * zero if no data to read, - * negative on failure. - */ -int amthi_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset) -{ - int rets; - int wait_ret; - struct mei_cl_cb *cb = NULL; - struct mei_cl *cl = file->private_data; - unsigned long timeout; - int i; - - /* Only Posible if we are in timeout */ - if (!cl || cl != &dev->iamthif_cl) { - dev_dbg(&dev->pdev->dev, "bad file ext.\n"); - return -ETIMEDOUT; - } - - for (i = 0; i < dev->num_mei_me_clients; i++) { - if (dev->me_clients[i].client_id == - dev->iamthif_cl.me_client_id) - break; - } - - if (i == dev->num_mei_me_clients) { - dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); - return -ENODEV; - } - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) - return -ENODEV; - - dev_dbg(&dev->pdev->dev, "checking amthi data\n"); - cb = find_amthi_read_list_entry(dev, file); - - /* Check for if we can block or not*/ - if (cb == NULL && file->f_flags & O_NONBLOCK) - return -EAGAIN; - - - dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); - while (cb == NULL) { - /* unlock the Mutex */ - mutex_unlock(&dev->device_lock); - - wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, - (cb = find_amthi_read_list_entry(dev, file))); - - if (wait_ret) - return -ERESTARTSYS; - - dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); - - /* Locking again the Mutex */ - mutex_lock(&dev->device_lock); - } - - - dev_dbg(&dev->pdev->dev, "Got amthi data\n"); - dev->iamthif_timer = 0; - - if (cb) { - timeout = cb->read_time + - msecs_to_jiffies(IAMTHIF_READ_TIMER); - dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", - timeout); - - if (time_after(jiffies, timeout)) { - dev_dbg(&dev->pdev->dev, "amthi Time out\n"); - /* 15 sec for the message has expired */ - list_del(&cb->cb_list); - rets = -ETIMEDOUT; - goto free; - } - } - /* if the whole message will fit remove it from the list */ - if (cb->information >= *offset && - length >= (cb->information - *offset)) - list_del(&cb->cb_list); - else if (cb->information > 0 && cb->information <= *offset) { - /* end of the message has been reached */ - list_del(&cb->cb_list); - rets = 0; - goto free; - } - /* else means that not full buffer will be read and do not - * remove message from deletion list - */ - - dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", - cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n", - cb->information); - - /* length is being turncated to PAGE_SIZE, however, - * the information may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); - - if (copy_to_user(ubuf, - cb->response_buffer.data + *offset, - length)) - rets = -EFAULT; - else { - rets = length; - if ((*offset + length) < cb->information) { - *offset += length; - goto out; - } - } -free: - dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); - *offset = 0; - mei_free_cb_private(cb); -out: - return rets; -} - -/** - * mei_start_read - the start read client message function. - * - * @dev: the device structure - * @if_num: minor number - * @cl: private data of the file object - * - * returns 0 on success, <0 on failure. - */ -int mei_start_read(struct mei_device *dev, struct mei_cl *cl) -{ - struct mei_cl_cb *cb; - int rets = 0; - int i; - - if (cl->state != MEI_FILE_CONNECTED) - return -ENODEV; - - if (dev->mei_state != MEI_ENABLED) - return -ENODEV; - - dev_dbg(&dev->pdev->dev, "check if read is pending.\n"); - if (cl->read_pending || cl->read_cb) { - dev_dbg(&dev->pdev->dev, "read is pending.\n"); - return -EBUSY; - } - - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!cb) - return -ENOMEM; - - dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n", - cl->host_client_id, cl->me_client_id); - - for (i = 0; i < dev->num_mei_me_clients; i++) { - if (dev->me_clients[i].client_id == cl->me_client_id) - break; - - } - - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) { - rets = -ENODEV; - goto unlock; - } - - if (i == dev->num_mei_me_clients) { - rets = -ENODEV; - goto unlock; - } - - cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; - cb->response_buffer.data = - kmalloc(cb->response_buffer.size, GFP_KERNEL); - if (!cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock; - } - dev_dbg(&dev->pdev->dev, "allocation call back data success.\n"); - cb->major_file_operations = MEI_READ; - /* make sure information is zero before we start */ - cb->information = 0; - cb->file_private = (void *) cl; - cl->read_cb = cb; - if (dev->mei_host_buffer_is_empty) { - dev->mei_host_buffer_is_empty = 0; - if (!mei_send_flow_control(dev, cl)) { - rets = -ENODEV; - goto unlock; - } else { - list_add_tail(&cb->cb_list, - &dev->read_list.mei_cb.cb_list); - } - } else { - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); - } - return rets; -unlock: - mei_free_cb_private(cb); - return rets; -} - -/** - * amthi_write - write iamthif data to amthi client - * - * @dev: the device structure - * @cb: mei call back struct - * - * returns 0 on success, <0 on failure. - */ -int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) -{ - struct mei_msg_hdr mei_hdr; - int ret; - - if (!dev || !cb) - return -ENODEV; - - dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); - - dev->iamthif_state = MEI_IAMTHIF_WRITING; - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; - dev->iamthif_canceled = 0; - dev->iamthif_ioctl = 1; - dev->iamthif_msg_buf_size = cb->request_buffer.size; - memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, - cb->request_buffer.size); - - ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); - if (ret < 0) - return ret; - - if (ret && dev->mei_host_buffer_is_empty) { - ret = 0; - dev->mei_host_buffer_is_empty = 0; - if (cb->request_buffer.size > - (((dev->host_hw_state & H_CBD) >> 24) * sizeof(u32)) - -sizeof(struct mei_msg_hdr)) { - mei_hdr.length = - (((dev->host_hw_state & H_CBD) >> 24) * - sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = cb->request_buffer.size; - mei_hdr.msg_complete = 1; - } - - mei_hdr.host_addr = dev->iamthif_cl.host_client_id; - mei_hdr.me_addr = dev->iamthif_cl.me_client_id; - mei_hdr.reserved = 0; - dev->iamthif_msg_buf_index += mei_hdr.length; - if (!mei_write_message(dev, &mei_hdr, - (unsigned char *)(dev->iamthif_msg_buf), - mei_hdr.length)) - return -ENODEV; - - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) - return -ENODEV; - dev->iamthif_flow_control_pending = 1; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; - list_add_tail(&cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } else { - dev_dbg(&dev->pdev->dev, "message does not complete, " - "so add amthi cb to write list.\n"); - list_add_tail(&cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } - } else { - if (!(dev->mei_host_buffer_is_empty)) - 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"); - list_add_tail(&cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } - return 0; -} - -/** - * iamthif_ioctl_send_msg - send cmd data to amthi client - * - * @dev: the device structure - * - * returns 0 on success, <0 on failure. - */ -void run_next_iamthif_cmd(struct mei_device *dev) -{ - struct mei_cl *cl_tmp; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - int status; - - if (!dev) - return; - - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = 0; - dev->iamthif_ioctl = 1; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; - dev->iamthif_file_object = NULL; - - if (dev->amthi_cmd_list.status == 0 && - !list_empty(&dev->amthi_cmd_list.mei_cb.cb_list)) { - dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); - - list_for_each_entry_safe(cb_pos, cb_next, - &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) { - list_del(&cb_pos->cb_list); - cl_tmp = (struct mei_cl *)cb_pos->file_private; - - if (cl_tmp && cl_tmp == &dev->iamthif_cl) { - status = amthi_write(dev, cb_pos); - if (status) { - dev_dbg(&dev->pdev->dev, - "amthi write failed status = %d\n", - status); - return; - } - break; - } - } - } -} - -/** - * mei_free_cb_private - free mei_cb_private related memory - * - * @cb: mei callback struct - */ -void mei_free_cb_private(struct mei_cl_cb *cb) -{ - if (cb == NULL) - return; - - kfree(cb->request_buffer.data); - kfree(cb->response_buffer.data); - kfree(cb); -} diff --git a/drivers/staging/mei/main.c b/drivers/staging/mei/main.c deleted file mode 100644 index bfd1b46ec74..00000000000 --- a/drivers/staging/mei/main.c +++ /dev/null @@ -1,1349 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - - - -#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/version.h> -#include <linux/sched.h> -#include <linux/uuid.h> -#include <linux/compat.h> -#include <linux/jiffies.h> -#include <linux/interrupt.h> - -#include "mei_dev.h" -#include "mei.h" -#include "interface.h" -#include "mei_version.h" - - -#define MEI_READ_TIMEOUT 45 -#define MEI_DRIVER_NAME "mei" -#define MEI_DEV_NAME "mei" - -/* - * mei driver strings - */ -static char mei_driver_name[] = MEI_DRIVER_NAME; -static const char mei_driver_string[] = "Intel(R) Management Engine Interface"; -static const char mei_driver_version[] = MEI_DRIVER_VERSION; - -/* mei char device for registration */ -static struct cdev mei_cdev; - -/* major number for device */ -static int mei_major; -/* The device pointer */ -/* Currently this driver works as long as there is only a single AMT device. */ -static struct pci_dev *mei_device; - -static struct class *mei_class; - - -/* 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)}, - - /* required last entry */ - {0, } -}; - -MODULE_DEVICE_TABLE(pci, mei_pci_tbl); - -static DEFINE_MUTEX(mei_mutex); - -/** - * mei_probe - Device Initialization Routine - * - * @pdev: PCI device structure - * @ent: entry in kcs_pci_tbl - * - * returns 0 on success, <0 on failure. - */ -static int __devinit mei_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct mei_device *dev; - int err; - - mutex_lock(&mei_mutex); - if (mei_device) { - err = -EEXIST; - goto end; - } - /* enable pci dev */ - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "mei: 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, mei_driver_name); - if (err) { - printk(KERN_ERR "mei: Failed to get pci regions.\n"); - goto disable_device; - } - /* allocates and initializes the mei dev structure */ - dev = init_mei_device(pdev); - if (!dev) { - err = -ENOMEM; - goto release_regions; - } - /* mapping IO device memory */ - dev->mem_addr = pci_iomap(pdev, 0, 0); - if (!dev->mem_addr) { - printk(KERN_ERR "mei: mapping I/O device memory failure.\n"); - err = -ENOMEM; - goto free_device; - } - /* request and enable interrupt */ - err = request_threaded_irq(pdev->irq, - mei_interrupt_quick_handler, - mei_interrupt_thread_handler, - IRQF_SHARED, mei_driver_name, dev); - if (err) { - printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n", - pdev->irq); - goto unmap_memory; - } - INIT_DELAYED_WORK(&dev->wd_work, mei_wd_timer); - if (mei_hw_init(dev)) { - printk(KERN_ERR "mei: Init hw failure.\n"); - err = -ENODEV; - goto release_irq; - } - mei_device = pdev; - pci_set_drvdata(pdev, dev); - schedule_delayed_work(&dev->wd_work, HZ); - - mutex_unlock(&mei_mutex); - - pr_debug("mei: Driver initialization successful.\n"); - - return 0; - -release_irq: - /* disable interrupts */ - dev->host_hw_state = mei_hcsr_read(dev); - mei_disable_interrupts(dev); - flush_scheduled_work(); - free_irq(pdev->irq, dev); -unmap_memory: - 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); - printk(KERN_ERR "mei: Driver 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 __devexit mei_remove(struct pci_dev *pdev) -{ - struct mei_device *dev; - - if (mei_device != pdev) - return; - - dev = pci_get_drvdata(pdev); - if (!dev) - return; - - mutex_lock(&dev->device_lock); - - mei_wd_stop(dev, false); - - mei_device = NULL; - - if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) { - dev->iamthif_cl.state = MEI_FILE_DISCONNECTING; - mei_disconnect_host_client(dev, &dev->iamthif_cl); - } - if (dev->wd_cl.state == MEI_FILE_CONNECTED) { - dev->wd_cl.state = MEI_FILE_DISCONNECTING; - mei_disconnect_host_client(dev, &dev->wd_cl); - } - - /* remove entry if already in list */ - dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id); - mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); - - dev->iamthif_current_cb = NULL; - dev->num_mei_me_clients = 0; - - mutex_unlock(&dev->device_lock); - - flush_scheduled_work(); - - /* disable interrupts */ - mei_disable_interrupts(dev); - - free_irq(pdev->irq, dev); - 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_clear_list - removes all callbacks associated with file - * from mei_cb_list - * - * @dev: device structure. - * @file: file structure - * @mei_cb_list: callbacks list - * - * mei_clear_list is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_list(struct mei_device *dev, - struct file *file, struct list_head *mei_cb_list) -{ - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - struct file *file_temp; - bool removed = false; - - /* list all list member */ - list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) { - file_temp = (struct file *)cb_pos->file_object; - /* check if list member associated with a file */ - if (file_temp == file) { - /* remove member from the list */ - list_del(&cb_pos->cb_list); - /* check if cb equal to current iamthif cb */ - if (dev->iamthif_current_cb == cb_pos) { - dev->iamthif_current_cb = NULL; - /* send flow control to iamthif client */ - mei_send_flow_control(dev, &dev->iamthif_cl); - } - /* free all allocated buffers */ - mei_free_cb_private(cb_pos); - cb_pos = NULL; - removed = true; - } - } - return removed; -} - -/** - * mei_clear_lists - removes all callbacks associated with file - * - * @dev: device structure - * @file: file structure - * - * mei_clear_lists is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_lists(struct mei_device *dev, struct file *file) -{ - bool removed = false; - - /* remove callbacks associated with a file */ - mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list); - if (mei_clear_list(dev, file, - &dev->amthi_read_complete_list.mei_cb.cb_list)) - removed = true; - - mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list); - - if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list)) - removed = true; - - /* check if iamthif_current_cb not NULL */ - if (dev->iamthif_current_cb && !removed) { - /* check file and iamthif current cb association */ - if (dev->iamthif_current_cb->file_object == file) { - /* remove cb */ - mei_free_cb_private(dev->iamthif_current_cb); - dev->iamthif_current_cb = NULL; - removed = true; - } - } - return removed; -} -/** - * find_read_list_entry - find read list entry - * - * @dev: device structure - * @file: pointer to file structure - * - * returns cb on success, NULL on error - */ -static struct mei_cl_cb *find_read_list_entry( - struct mei_device *dev, - struct mei_cl *cl) -{ - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - struct mei_cl *cl_list_temp; - - if (!dev->read_list.status && - !list_empty(&dev->read_list.mei_cb.cb_list)) { - - dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); - list_for_each_entry_safe(cb_pos, cb_next, - &dev->read_list.mei_cb.cb_list, cb_list) { - - cl_list_temp = (struct mei_cl *) - cb_pos->file_private; - - if (cl_list_temp && - mei_fe_same_id(cl, cl_list_temp)) - return cb_pos; - - } - } - return NULL; -} - -/** - * mei_open - the open function - * - * @inode: pointer to inode structure - * @file: pointer to file structure - * - * returns 0 on success, <0 on error - */ -static int mei_open(struct inode *inode, struct file *file) -{ - struct mei_cl *cl; - int if_num = iminor(inode), err; - struct mei_device *dev; - - err = -ENODEV; - if (!mei_device) - goto out; - - dev = pci_get_drvdata(mei_device); - if (if_num != MEI_MINOR_NUMBER || !dev) - goto out; - - mutex_lock(&dev->device_lock); - err = -ENOMEM; - cl = mei_alloc_file_private(dev); - if (!cl) - goto out; - - err = -ENODEV; - if (dev->mei_state != MEI_ENABLED) { - dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n", - dev->mei_state); - goto out_unlock; - } - err = -EMFILE; - if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) - goto out_unlock; - - cl->host_client_id = find_first_zero_bit(dev->host_clients_map, - MEI_CLIENTS_MAX); - if (cl->host_client_id > MEI_CLIENTS_MAX) - goto out_unlock; - - dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id); - - dev->open_handle_count++; - list_add_tail(&cl->link, &dev->file_list); - - set_bit(cl->host_client_id, dev->host_clients_map); - cl->state = MEI_FILE_INITIALIZING; - cl->sm_state = 0; - - file->private_data = cl; - mutex_unlock(&dev->device_lock); - - return 0; - -out_unlock: - mutex_unlock(&dev->device_lock); - kfree(cl); -out: - return err; -} - -/** - * mei_release - the release function - * - * @inode: pointer to inode structure - * @file: pointer to file structure - * - * returns 0 on success, <0 on error - */ -static int mei_release(struct inode *inode, struct file *file) -{ - struct mei_cl *cl = file->private_data; - struct mei_cl_cb *cb; - struct mei_device *dev; - int rets = 0; - - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - mutex_lock(&dev->device_lock); - if (cl != &dev->iamthif_cl) { - if (cl->state == MEI_FILE_CONNECTED) { - cl->state = MEI_FILE_DISCONNECTING; - dev_dbg(&dev->pdev->dev, - "disconnecting client host client = %d, " - "ME client = %d\n", - cl->host_client_id, - cl->me_client_id); - rets = mei_disconnect_host_client(dev, cl); - } - mei_flush_queues(dev, cl); - dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", - cl->host_client_id, - cl->me_client_id); - - if (dev->open_handle_count > 0) { - clear_bit(cl->host_client_id, - dev->host_clients_map); - dev->open_handle_count--; - } - mei_remove_client_from_file_list(dev, cl->host_client_id); - - /* free read cb */ - cb = NULL; - if (cl->read_cb) { - cb = find_read_list_entry(dev, cl); - /* Remove entry from read list */ - if (cb) - list_del(&cb->cb_list); - - cb = cl->read_cb; - cl->read_cb = NULL; - } - - file->private_data = NULL; - - if (cb) { - mei_free_cb_private(cb); - cb = NULL; - } - - kfree(cl); - } else { - if (dev->open_handle_count > 0) - dev->open_handle_count--; - - if (dev->iamthif_file_object == file && - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - - dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", - dev->iamthif_state); - dev->iamthif_canceled = 1; - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { - dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); - run_next_iamthif_cmd(dev); - } - } - - if (mei_clear_lists(dev, file)) - dev->iamthif_state = MEI_IAMTHIF_IDLE; - - } - mutex_unlock(&dev->device_lock); - return rets; -} - - -/** - * mei_read - the read 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 mei_read(struct file *file, char __user *ubuf, - size_t length, loff_t *offset) -{ - struct mei_cl *cl = file->private_data; - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb = NULL; - struct mei_device *dev; - int i; - int rets; - int err; - - - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { - rets = -ENODEV; - goto out; - } - - if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) { - /* Do not allow to read watchdog client */ - i = mei_find_me_client_index(dev, mei_wd_guid); - if (i >= 0) { - struct mei_me_client *me_client = &dev->me_clients[i]; - - if (cl->me_client_id == me_client->client_id) { - rets = -EBADF; - goto out; - } - } - } else { - cl->sm_state &= ~MEI_WD_STATE_INDEPENDENCE_MSG_SENT; - } - - if (cl == &dev->iamthif_cl) { - rets = amthi_read(dev, file, ubuf, length, offset); - goto out; - } - - if (cl->read_cb && cl->read_cb->information > *offset) { - cb = cl->read_cb; - goto copy_buffer; - } else if (cl->read_cb && cl->read_cb->information > 0 && - cl->read_cb->information <= *offset) { - cb = cl->read_cb; - rets = 0; - goto free; - } else if ((!cl->read_cb || !cl->read_cb->information) && - *offset > 0) { - /*Offset needs to be cleaned for contingous reads*/ - *offset = 0; - rets = 0; - goto out; - } - - err = mei_start_read(dev, cl); - if (err && err != -EBUSY) { - dev_dbg(&dev->pdev->dev, - "mei start read failure with status = %d\n", err); - rets = err; - goto out; - } - - if (MEI_READ_COMPLETE != cl->reading_state && - !waitqueue_active(&cl->rx_wait)) { - if (file->f_flags & O_NONBLOCK) { - rets = -EAGAIN; - goto out; - } - - mutex_unlock(&dev->device_lock); - - if (wait_event_interruptible(cl->rx_wait, - (MEI_READ_COMPLETE == cl->reading_state || - MEI_FILE_INITIALIZING == cl->state || - MEI_FILE_DISCONNECTED == cl->state || - MEI_FILE_DISCONNECTING == cl->state))) { - if (signal_pending(current)) - return -EINTR; - return -ERESTARTSYS; - } - - mutex_lock(&dev->device_lock); - if (MEI_FILE_INITIALIZING == cl->state || - MEI_FILE_DISCONNECTED == cl->state || - MEI_FILE_DISCONNECTING == cl->state) { - rets = -EBUSY; - goto out; - } - } - - cb = cl->read_cb; - - if (!cb) { - rets = -ENODEV; - goto out; - } - if (cl->reading_state != MEI_READ_COMPLETE) { - rets = 0; - goto out; - } - /* now copy the data to user space */ -copy_buffer: - dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n", - cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "cb->information - %lu\n", - cb->information); - if (length == 0 || ubuf == NULL || *offset > cb->information) { - rets = -EMSGSIZE; - goto free; - } - - /* length is being turncated to PAGE_SIZE, however, */ - /* information size may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); - - if (copy_to_user(ubuf, - cb->response_buffer.data + *offset, - length)) { - rets = -EFAULT; - goto free; - } - - rets = length; - *offset += length; - if ((unsigned long)*offset < cb->information) - goto out; - -free: - cb_pos = find_read_list_entry(dev, cl); - /* Remove entry from read list */ - if (cb_pos) - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb); - cl->reading_state = MEI_IDLE; - cl->read_cb = NULL; - cl->read_pending = 0; -out: - dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets); - mutex_unlock(&dev->device_lock); - return rets; -} - -/** - * mei_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 mei_write(struct file *file, const char __user *ubuf, - size_t length, loff_t *offset) -{ - struct mei_cl *cl = file->private_data; - struct mei_cl_cb *write_cb = NULL; - struct mei_msg_hdr mei_hdr; - struct mei_device *dev; - unsigned long timeout = 0; - int rets; - int i; - - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - mutex_lock(&dev->device_lock); - - if (dev->mei_state != MEI_ENABLED) { - mutex_unlock(&dev->device_lock); - return -ENODEV; - } - - if (cl == &dev->iamthif_cl) { - write_cb = find_amthi_read_list_entry(dev, file); - - if (write_cb) { - timeout = write_cb->read_time + - msecs_to_jiffies(IAMTHIF_READ_TIMER); - - if (time_after(jiffies, timeout) || - cl->reading_state == MEI_READ_COMPLETE) { - *offset = 0; - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); - write_cb = NULL; - } - } - } - - /* free entry used in read */ - if (cl->reading_state == MEI_READ_COMPLETE) { - *offset = 0; - write_cb = find_read_list_entry(dev, cl); - if (write_cb) { - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); - write_cb = NULL; - cl->reading_state = MEI_IDLE; - cl->read_cb = NULL; - cl->read_pending = 0; - } - } else if (cl->reading_state == MEI_IDLE && - !cl->read_pending) - *offset = 0; - - - write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); - if (!write_cb) { - mutex_unlock(&dev->device_lock); - return -ENOMEM; - } - - write_cb->file_object = file; - write_cb->file_private = cl; - write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - rets = -ENOMEM; - if (!write_cb->request_buffer.data) - goto unlock_dev; - - dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length); - - rets = -EFAULT; - if (copy_from_user(write_cb->request_buffer.data, ubuf, length)) - goto unlock_dev; - - cl->sm_state = 0; - if (length == 4 && - ((memcmp(mei_wd_state_independence_msg[0], - write_cb->request_buffer.data, 4) == 0) || - (memcmp(mei_wd_state_independence_msg[1], - write_cb->request_buffer.data, 4) == 0) || - (memcmp(mei_wd_state_independence_msg[2], - write_cb->request_buffer.data, 4) == 0))) - cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; - - INIT_LIST_HEAD(&write_cb->cb_list); - if (cl == &dev->iamthif_cl) { - write_cb->response_buffer.data = - kmalloc(dev->iamthif_mtu, GFP_KERNEL); - if (!write_cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock_dev; - } - if (dev->mei_state != MEI_ENABLED) { - rets = -ENODEV; - goto unlock_dev; - } - for (i = 0; i < dev->num_mei_me_clients; i++) { - if (dev->me_clients[i].client_id == - dev->iamthif_cl.me_client_id) - break; - } - - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) { - rets = -ENODEV; - goto unlock_dev; - } - if (i == dev->num_mei_me_clients || - (dev->me_clients[i].client_id != - dev->iamthif_cl.me_client_id)) { - rets = -ENODEV; - goto unlock_dev; - } else if (length > dev->me_clients[i].props.max_msg_length || - length <= 0) { - rets = -EMSGSIZE; - goto unlock_dev; - } - - write_cb->response_buffer.size = dev->iamthif_mtu; - write_cb->major_file_operations = MEI_IOCTL; - write_cb->information = 0; - write_cb->request_buffer.size = length; - if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - goto unlock_dev; - } - - if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) || - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - dev_dbg(&dev->pdev->dev, "amthi_state = %d\n", - (int) dev->iamthif_state); - dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n"); - list_add_tail(&write_cb->cb_list, - &dev->amthi_cmd_list.mei_cb.cb_list); - rets = length; - } else { - dev_dbg(&dev->pdev->dev, "call amthi write\n"); - rets = amthi_write(dev, write_cb); - - if (rets) { - dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n", - rets); - goto unlock_dev; - } - rets = length; - } - mutex_unlock(&dev->device_lock); - return rets; - } - - write_cb->major_file_operations = MEI_WRITE; - /* make sure information is zero before we start */ - - write_cb->information = 0; - write_cb->request_buffer.size = length; - - dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", - cl->host_client_id, cl->me_client_id); - if (cl->state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - dev_dbg(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", - cl->host_client_id, - cl->me_client_id); - goto unlock_dev; - } - for (i = 0; i < dev->num_mei_me_clients; i++) { - if (dev->me_clients[i].client_id == - cl->me_client_id) - break; - } - if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) { - rets = -ENODEV; - goto unlock_dev; - } - if (i == dev->num_mei_me_clients) { - rets = -ENODEV; - goto unlock_dev; - } - if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { - rets = -EINVAL; - goto unlock_dev; - } - write_cb->file_private = cl; - - rets = mei_flow_ctrl_creds(dev, cl); - if (rets < 0) - goto unlock_dev; - - if (rets && dev->mei_host_buffer_is_empty) { - rets = 0; - dev->mei_host_buffer_is_empty = 0; - if (length > ((((dev->host_hw_state & H_CBD) >> 24) * - sizeof(u32)) - sizeof(struct mei_msg_hdr))) { - - mei_hdr.length = - (((dev->host_hw_state & H_CBD) >> 24) * - sizeof(u32)) - - sizeof(struct mei_msg_hdr); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = length; - mei_hdr.msg_complete = 1; - } - mei_hdr.host_addr = cl->host_client_id; - mei_hdr.me_addr = cl->me_client_id; - mei_hdr.reserved = 0; - dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", - *((u32 *) &mei_hdr)); - if (!mei_write_message(dev, &mei_hdr, - (unsigned char *) (write_cb->request_buffer.data), - mei_hdr.length)) { - rets = -ENODEV; - goto unlock_dev; - } - cl->writing_state = MEI_WRITING; - write_cb->information = mei_hdr.length; - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, cl)) { - rets = -ENODEV; - goto unlock_dev; - } - list_add_tail(&write_cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } else { - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } - - } else { - - write_cb->information = 0; - cl->writing_state = MEI_WRITING; - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } - mutex_unlock(&dev->device_lock); - return length; - -unlock_dev: - mutex_unlock(&dev->device_lock); - mei_free_cb_private(write_cb); - return rets; -} - - -/** - * mei_ioctl - the IOCTL function - * - * @file: pointer to file structure - * @cmd: ioctl command - * @data: pointer to mei message structure - * - * returns 0 on success , <0 on error - */ -static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) -{ - struct mei_device *dev; - struct mei_cl *cl = file->private_data; - struct mei_connect_client_data *connect_data = NULL; - int rets; - - if (cmd != IOCTL_MEI_CONNECT_CLIENT) - return -EINVAL; - - if (WARN_ON(!cl || !cl->dev)) - return -ENODEV; - - dev = cl->dev; - - dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd); - - mutex_lock(&dev->device_lock); - if (dev->mei_state != MEI_ENABLED) { - rets = -ENODEV; - goto out; - } - - dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n"); - - connect_data = kzalloc(sizeof(struct mei_connect_client_data), - GFP_KERNEL); - if (!connect_data) { - rets = -ENOMEM; - goto out; - } - dev_dbg(&dev->pdev->dev, "copy connect data from user\n"); - if (copy_from_user(connect_data, (char __user *)data, - sizeof(struct mei_connect_client_data))) { - dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n"); - rets = -EFAULT; - goto out; - } - rets = mei_ioctl_connect_client(file, connect_data); - - /* if all is ok, copying the data back to user. */ - if (rets) - goto out; - - dev_dbg(&dev->pdev->dev, "copy connect data to user\n"); - if (copy_to_user((char __user *)data, connect_data, - sizeof(struct mei_connect_client_data))) { - dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n"); - rets = -EFAULT; - goto out; - } - -out: - kfree(connect_data); - mutex_unlock(&dev->device_lock); - return rets; -} - -/** - * mei_compat_ioctl - the compat IOCTL function - * - * @file: pointer to file structure - * @cmd: ioctl command - * @data: pointer to mei message structure - * - * returns 0 on success , <0 on error - */ -#ifdef CONFIG_COMPAT -static long mei_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long data) -{ - return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data)); -} -#endif - - -/** - * mei_poll - the poll function - * - * @file: pointer to file structure - * @wait: pointer to poll_table structure - * - * returns poll mask - */ -static unsigned int mei_poll(struct file *file, poll_table *wait) -{ - struct mei_cl *cl = file->private_data; - struct mei_device *dev; - unsigned int mask = 0; - - if (WARN_ON(!cl || !cl->dev)) - return mask; - - dev = cl->dev; - - mutex_lock(&dev->device_lock); - - if (dev->mei_state != MEI_ENABLED) - goto out; - - - if (cl == &dev->iamthif_cl) { - mutex_unlock(&dev->device_lock); - poll_wait(file, &dev->iamthif_cl.wait, wait); - mutex_lock(&dev->device_lock); - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && - dev->iamthif_file_object == file) { - mask |= (POLLIN | POLLRDNORM); - dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); - run_next_iamthif_cmd(dev); - } - goto out; - } - - mutex_unlock(&dev->device_lock); - poll_wait(file, &cl->tx_wait, wait); - mutex_lock(&dev->device_lock); - if (MEI_WRITE_COMPLETE == cl->writing_state) - mask |= (POLLIN | POLLRDNORM); - -out: - mutex_unlock(&dev->device_lock); - return mask; -} - -#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); - /* Stop watchdog if exists */ - err = mei_wd_stop(dev, true); - /* Set new mei state */ - if (dev->mei_state == MEI_ENABLED || - dev->mei_state == MEI_RECOVERING_FROM_RESET) { - dev->mei_state = MEI_POWER_DOWN; - mei_reset(dev, 0); - } - mutex_unlock(&dev->device_lock); - - free_irq(pdev->irq, dev); - - - 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; - - /* request and enable interrupt */ - err = request_threaded_irq(pdev->irq, - mei_interrupt_quick_handler, - mei_interrupt_thread_handler, - IRQF_SHARED, mei_driver_name, dev); - if (err) { - printk(KERN_ERR "mei: Request_irq failure. irq = %d\n", - pdev->irq); - return err; - } - - mutex_lock(&dev->device_lock); - dev->mei_state = MEI_POWER_UP; - mei_reset(dev, 1); - mutex_unlock(&dev->device_lock); - - /* Start watchdog if stopped in suspend */ - if (dev->wd_timeout) { - mei_wd_start_setup(dev); - dev->wd_due_counter = 1; - schedule_delayed_work(&dev->wd_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 = mei_driver_name, - .id_table = mei_pci_tbl, - .probe = mei_probe, - .remove = __devexit_p(mei_remove), - .shutdown = __devexit_p(mei_remove), - .driver.pm = MEI_PM_OPS, -}; - -/* - * file operations structure will be used for mei char device. - */ -static const struct file_operations mei_fops = { - .owner = THIS_MODULE, - .read = mei_read, - .unlocked_ioctl = mei_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = mei_compat_ioctl, -#endif - .open = mei_open, - .release = mei_release, - .write = mei_write, - .poll = mei_poll, -}; - -/** - * mei_registration_cdev - sets up the cdev structure for mei 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 mei_registration_cdev(struct cdev *dev, int hminor, - const struct file_operations *fops) -{ - int ret, devno = MKDEV(mei_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 "mei: Error %d registering mei device %d\n", - ret, hminor); - return ret; -} - -/** - * mei_register_cdev - registers mei char device - * - * returns 0 on success, <0 on failure. - */ -static int mei_register_cdev(void) -{ - int ret; - dev_t dev; - - /* registration of char devices */ - ret = alloc_chrdev_region(&dev, MEI_MINORS_BASE, MEI_MINORS_COUNT, - MEI_DRIVER_NAME); - if (ret) { - printk(KERN_ERR "mei: Error allocating char device region.\n"); - return ret; - } - - mei_major = MAJOR(dev); - - ret = mei_registration_cdev(&mei_cdev, MEI_MINOR_NUMBER, - &mei_fops); - if (ret) - unregister_chrdev_region(MKDEV(mei_major, MEI_MINORS_BASE), - MEI_MINORS_COUNT); - - return ret; -} - -/** - * mei_unregister_cdev - unregisters mei char device - */ -static void mei_unregister_cdev(void) -{ - cdev_del(&mei_cdev); - unregister_chrdev_region(MKDEV(mei_major, MEI_MINORS_BASE), - MEI_MINORS_COUNT); -} - -/** - * mei_sysfs_device_create - adds device entry to sysfs - * - * returns 0 on success, <0 on failure. - */ -static int mei_sysfs_device_create(void) -{ - struct class *class; - void *tmphdev; - int err; - - class = class_create(THIS_MODULE, MEI_DRIVER_NAME); - if (IS_ERR(class)) { - err = PTR_ERR(class); - printk(KERN_ERR "mei: Error creating mei class.\n"); - goto err_out; - } - - tmphdev = device_create(class, NULL, mei_cdev.dev, NULL, - MEI_DEV_NAME); - if (IS_ERR(tmphdev)) { - err = PTR_ERR(tmphdev); - goto err_destroy; - } - - mei_class = class; - return 0; - -err_destroy: - class_destroy(class); -err_out: - return err; -} - -/** - * mei_sysfs_device_remove - unregisters the device entry on sysfs - */ -static void mei_sysfs_device_remove(void) -{ - if (IS_ERR_OR_NULL(mei_class)) - return; - - device_destroy(mei_class, mei_cdev.dev); - class_destroy(mei_class); -} - -/** - * mei_init_module - Driver Registration Routine - * - * mei_init_module is the first routine called when the driver is - * loaded. All it does is to register with the PCI subsystem. - * - * returns 0 on success, <0 on failure. - */ -static int __init mei_init_module(void) -{ - int ret; - - pr_debug("mei: %s - version %s\n", - mei_driver_string, mei_driver_version); - /* init pci module */ - ret = pci_register_driver(&mei_driver); - if (ret < 0) { - printk(KERN_ERR "mei: Error registering driver.\n"); - goto end; - } - - ret = mei_register_cdev(); - if (ret) - goto unregister_pci; - - ret = mei_sysfs_device_create(); - if (ret) - goto unregister_cdev; - - return ret; - -unregister_cdev: - mei_unregister_cdev(); -unregister_pci: - pci_unregister_driver(&mei_driver); -end: - return ret; -} - -module_init(mei_init_module); - -/** - * mei_exit_module - Driver Exit Cleanup Routine - * - * mei_exit_module is called just before the driver is removed - * from memory. - */ -static void __exit mei_exit_module(void) -{ - pci_unregister_driver(&mei_driver); - mei_sysfs_device_remove(); - mei_unregister_cdev(); - - pr_debug("mei: Driver unloaded successfully.\n"); -} - -module_exit(mei_exit_module); - - -MODULE_AUTHOR("Intel Corporation"); -MODULE_DESCRIPTION("Intel(R) Management Engine Interface"); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(MEI_DRIVER_VERSION); diff --git a/drivers/staging/mei/mei.h b/drivers/staging/mei/mei.h deleted file mode 100644 index 6da7c4f33f9..00000000000 --- a/drivers/staging/mei/mei.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - - Intel Management Engine Interface (Intel MEI) Linux driver - Intel MEI Interface Header - - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. - - GPL LICENSE SUMMARY - - Copyright(c) 2003-2011 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that 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. - - Contact Information: - Intel Corporation. - linux-mei@linux.intel.com - http://www.intel.com - - - BSD LICENSE - - Copyright(c) 2003-2011 Intel Corporation. All rights reserved. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - 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 MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - 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 DAMAGE. - -*/ - - -#ifndef _LINUX_MEI_H -#define _LINUX_MEI_H - -#include <linux/uuid.h> - -/* - * This IOCTL is used to associate the current file descriptor with a - * FW Client (given by UUID). This opens a communication channel - * between a host client and a FW client. From this point every read and write - * will communicate with the associated FW client. - * Only in close() (file_operation release()) the communication between - * the clients is disconnected - * - * The IOCTL argument is a struct with a union the contains - * the input parameter and the output parameter for this IOCTL. - * - * The input parameter is UUID of the FW Client. - * The output parameter is the properties of the FW client - * (FW protocol version and max message size). - * - */ -#define IOCTL_MEI_CONNECT_CLIENT \ - _IOWR('H' , 0x01, struct mei_connect_client_data) - -/* - * Intel MEI client information struct - */ -struct mei_client { - __u32 max_msg_length; - __u8 protocol_version; - __u8 reserved[3]; -}; - -/* - * IOCTL Connect Client Data structure - */ -struct mei_connect_client_data { - union { - uuid_le in_client_uuid; - struct mei_client out_client_properties; - }; -}; - -#endif /* _LINUX_MEI_H */ diff --git a/drivers/staging/mei/mei.txt b/drivers/staging/mei/mei.txt deleted file mode 100644 index 17302ad2531..00000000000 --- a/drivers/staging/mei/mei.txt +++ /dev/null @@ -1,189 +0,0 @@ -Intel MEI -======================= - -Introduction -======================= - -The Intel Management Engine (Intel ME) is an isolated and -protected computing resource (Coprocessor) residing inside -Intel chipsets. The Intel ME provides support for computer/IT -management features. -The Feature set depends on the Intel chipset SKU. - -The Intel Management Engine Interface (Intel MEI, previously known -as HECI) is the interface between the Host and Intel ME. -This interface is exposed to the host as a PCI device. -The Intel MEI Driver is in charge of the communication channel -between a host application and the ME feature. - -Each Intel ME feature (Intel ME Client) is addressed by -GUID/UUID and each feature defines its own protocol. -The protocol is message-based with a header and payload up to -512 bytes. - -[place holder to URL to protocol definitions] - -Prominent usage of the Interface is to communicate with -Intel Active Management Technology (Intel AMT) -implemented in firmware running on the Intel ME. - -Intel AMT provides the ability to manage a host remotely out-of-band (OOB) -even when the host processor has crashed or is in a sleep state. - -Some examples of Intel AMT usage are: - - Monitoring hardware state and platform components - - Remote power off/on (useful for green computing or overnight IT maintenance) - - OS updates - - Storage of useful platform information such as software assets - - built-in hardware KVM - - selective network isolation of Ethernet and IP protocol flows based on - policies set by a remote management console - - IDE device redirection from remote management console - -Intel AMT (OOB) communication is based on SOAP (deprecated -starting with Release 6.0) over HTTP/HTTPS or WS-Management protocol -over HTTP and HTTPS that are received from a remote -management console application. - -For more information about Intel AMT: -http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/aboutintelamt.htm - - -MEI Driver -======================= - -The driver exposes a character device called /dev/mei. - -An application maintains communication with an ME feature while -/dev/mei is open. The binding to a specific features is performed -by calling MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID. -The number of instances of an ME feature that can be opened -at the same time depends on the ME feature, but most of the -features allow only a single instance. - - -The Intel AMT Host Interface (AMTHI) feature requires multiple -simultaneous user applications, therefore the MEI driver handles -this internally by maintaining request queues for the applications. - -The driver is oblivious to data that are passed between - -Because some of the ME features can change the system -configuration, the driver by default allows only privileged -user to access it. - -A Code snippet for application communicating with AMTHI client: - struct mei_connect_client_data data; - fd = open(MEI_DEVICE); - - data.d.in_client_uuid = AMTHI_UUID; - - ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &data); - - printf(“Ver=%d, MaxLen=%ld\n”, - data.d.in_client_uuid.protocol_version, - data.d.in_client_uuid.max_msg_length); - - [...] - - write(fd, amthi_req_data, amthi_req_data_len); - - [...] - - read(fd, &amthi_res_data, amthi_res_data_len); - - [...] - close(fd); - -ME Applications: -============== - -1) Intel Local Management Service (Intel LMS) - Applications running locally on the platform communicate with - Intel AMT Release 2.0 and later releases in the same way - that network applications do via SOAP over HTTP (deprecated - starting with Release 6.0) or with WS-Management over SOAP over - HTTP. which means that some Intel AMT feature can be access - from a local application using same Network interface as for - remote application. - - When a local application sends a message addressed to the local - Intel AMT host name, the Local Manageability Service (LMS), - which listens for traffic directed to the host name, intercepts - the message and routes it to the Intel Management Engine Interface. - For more information: - http://software.intel.com/sites/manageability/AMT_Implementation_and_ - Reference_Guide/WordDocuments/localaccess1.htm - - The LMS opens a connection using the MEI driver to the LMS - FW feature using a defined UUID and then communicates with the - feature using a protocol - called Intel(R) AMT Port Forwarding Protocol (APF protocol). - The protocol is used to maintain multiple sessions with - Intel AMT from a single application. - See the protocol specification in - the Intel(R) AMT Implementation and Reference Guide - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/HTMLDocuments/MPSDocuments/Intel%20AMT%20Port%20Forwarding%20Protocol%20Reference%20Manual.pdf - - 2) Intel AMT Remote configuration using a Local Agent: - A Local Agent enables IT personnel to configure Intel AMT out-of-the-box - without requiring installing additional data to enable setup. - The remote configuration process may involve an ISV-developed remote - configuration agent that runs on the host. - For more information: - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/remoteconfigurationwithalocalagent.htm - - How the Local Agent Works (including Command structs): - http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/howthelocalagentsampleworks.htm - -Intel AMT OS Health Watchdog: -============================= -The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog. -Whenever the OS hangs or crashes, Intel AMT will send an event -to whoever subscribed to this event. This mechanism means that -IT knows when a platform crashes even when there is a hard failure -on the host. -The AMT Watchdog is composed of two parts: - 1) FW Feature - that receives the heartbeats - and sends an event when the heartbeats stop. - 2) MEI driver – connects to the watchdog (WD) feature, - configures the watchdog and sends the heartbeats. - -The MEI driver configures the Watchdog to expire by default -every 120sec unless set by the user using module parameters. -The Driver then sends heartbeats every 2sec. - -If WD feature does not exist (i.e. the connection failed), -the MEI driver will disable the sending of heartbeats. - -Module Parameters -================= -watchdog_timeout - the user can use this module parameter -to change the watchdog timeout setting. - -This value sets the Intel AMT watchdog timeout interval in seconds; -the default value is 120sec. -in order to disable the watchdog activites set the value to 0. -Normal values should be between 120 and 65535 - -Supported Chipsets: -================== -7 Series Chipset Family -6 Series Chipset Family -5 Series Chipset Family -4 Series Chipset Family -Mobile 4 Series Chipset Family -ICH9 -82946GZ/GL -82G35 Express -82Q963/Q965 -82P965/G965 -Mobile PM965/GM965 -Mobile GME965/GLE960 -82Q35 Express -82G33/G31/P35/P31 Express -82Q33 Express -82X38/X48 Express - ---- -linux-mei@linux.intel.com diff --git a/drivers/staging/mei/mei_dev.h b/drivers/staging/mei/mei_dev.h deleted file mode 100644 index 6f3ec068ed6..00000000000 --- a/drivers/staging/mei/mei_dev.h +++ /dev/null @@ -1,422 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - -#ifndef _MEI_DEV_H_ -#define _MEI_DEV_H_ - -#include <linux/types.h> -#include "mei.h" -#include "hw.h" - -/* - * MEI Char Driver Minors - */ -#define MEI_MINORS_BASE 1 -#define MEI_MINORS_COUNT 1 -#define MEI_MINOR_NUMBER 1 - -/* - * watch dog definition - */ -#define MEI_WATCHDOG_DATA_SIZE 16 -#define MEI_START_WD_DATA_SIZE 20 -#define MEI_WD_PARAMS_SIZE 4 -#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0) - -/* - * AMTHI Client UUID - */ -extern const uuid_le mei_amthi_guid; - -/* - * Watchdog Client UUID - */ -extern const uuid_le mei_wd_guid; - -/* - * Watchdog independence state message - */ -extern const u8 mei_wd_state_independence_msg[3][4]; - -/* - * Number of File descriptors/handles - * that can be opened to the driver. - * - * Limit to 253: 255 Total Clients - * minus internal client for AMTHI - * minus internal client for Watchdog - */ -#define MEI_MAX_OPEN_HANDLE_COUNT 253 - -/* - * Number of queue lists used by this driver - */ -#define MEI_IO_LISTS_NUMBER 7 - -/* - * Number of Maximum MEI Clients - */ -#define MEI_CLIENTS_MAX 255 - -/* File state */ -enum file_state { - MEI_FILE_INITIALIZING = 0, - MEI_FILE_CONNECTING, - MEI_FILE_CONNECTED, - MEI_FILE_DISCONNECTING, - MEI_FILE_DISCONNECTED -}; - -/* MEI device states */ -enum mei_states { - MEI_INITIALIZING = 0, - MEI_INIT_CLIENTS, - MEI_ENABLED, - MEI_RESETING, - MEI_DISABLED, - MEI_RECOVERING_FROM_RESET, - MEI_POWER_DOWN, - MEI_POWER_UP -}; - -/* init clients states*/ -enum mei_init_clients_states { - MEI_START_MESSAGE = 0, - MEI_ENUM_CLIENTS_MESSAGE, - MEI_CLIENT_PROPERTIES_MESSAGE -}; - -enum iamthif_states { - MEI_IAMTHIF_IDLE, - MEI_IAMTHIF_WRITING, - MEI_IAMTHIF_FLOW_CONTROL, - MEI_IAMTHIF_READING, - MEI_IAMTHIF_READ_COMPLETE -}; - -enum mei_file_transaction_states { - MEI_IDLE, - MEI_WRITING, - MEI_WRITE_COMPLETE, - MEI_FLOW_CONTROL, - MEI_READING, - MEI_READ_COMPLETE -}; - -/* MEI CB */ -enum mei_cb_major_types { - MEI_READ = 0, - MEI_WRITE, - MEI_IOCTL, - MEI_OPEN, - MEI_CLOSE -}; - -/* - * Intel MEI message data struct - */ -struct mei_message_data { - u32 size; - char *data; -} __packed; - - -struct mei_cl_cb { - struct list_head cb_list; - enum mei_cb_major_types major_file_operations; - void *file_private; - struct mei_message_data request_buffer; - struct mei_message_data response_buffer; - unsigned long information; - unsigned long read_time; - struct file *file_object; -}; - -/* MEI client instance carried as file->pirvate_data*/ -struct mei_cl { - struct list_head link; - struct mei_device *dev; - enum file_state state; - wait_queue_head_t tx_wait; - wait_queue_head_t rx_wait; - wait_queue_head_t wait; - int read_pending; - int status; - /* ID of client connected */ - u8 host_client_id; - u8 me_client_id; - u8 mei_flow_ctrl_creds; - u8 timer_count; - enum mei_file_transaction_states reading_state; - enum mei_file_transaction_states writing_state; - int sm_state; - struct mei_cl_cb *read_cb; -}; - -struct mei_io_list { - struct mei_cl_cb mei_cb; - int status; - struct mei_device *device_extension; -}; - -/* MEI private device struct */ -struct mei_device { - struct pci_dev *pdev; /* pointer to pci device struct */ - /* - * lists of queues - */ - /* array of pointers to aio lists */ - struct mei_io_list *io_list_array[MEI_IO_LISTS_NUMBER]; - struct mei_io_list read_list; /* driver read queue */ - struct mei_io_list write_list; /* driver write queue */ - struct mei_io_list write_waiting_list; /* write waiting queue */ - struct mei_io_list ctrl_wr_list; /* managed write IOCTL list */ - struct mei_io_list ctrl_rd_list; /* managed read IOCTL list */ - struct mei_io_list amthi_cmd_list; /* amthi list for cmd waiting */ - - /* driver managed amthi list for reading completed amthi cmd data */ - struct mei_io_list amthi_read_complete_list; - /* - * list of files - */ - struct list_head file_list; - /* - * memory of device - */ - unsigned int mem_base; - unsigned int mem_length; - void __iomem *mem_addr; - /* - * lock for the device - */ - struct mutex device_lock; /* device lock */ - int recvd_msg; - struct delayed_work wd_work; /* watch dog deleye work */ - /* - * hw states of host and fw(ME) - */ - u32 host_hw_state; - u32 me_hw_state; - /* - * waiting queue for receive message from FW - */ - wait_queue_head_t wait_recvd_msg; - wait_queue_head_t wait_stop_wd; - - /* - * mei device states - */ - enum mei_states mei_state; - enum mei_init_clients_states init_clients_state; - u16 init_clients_timer; - int stop; - - u32 extra_write_index; - u32 rd_msg_buf[128]; /* used for control messages */ - u32 wr_msg_buf[128]; /* used for control messages */ - u32 ext_msg_buf[8]; /* for control responses */ - u32 rd_msg_hdr; - - struct hbm_version version; - - int mei_host_buffer_is_empty; - struct mei_cl wd_cl; - struct mei_me_client *me_clients; /* Note: memory has to be allocated */ - DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX); - DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX); - u8 num_mei_me_clients; - u8 me_client_presentation_num; - u8 me_client_index; - - int wd_pending; - int wd_stopped; - u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */ - unsigned char wd_data[MEI_START_WD_DATA_SIZE]; - - - u16 wd_due_counter; - bool wd_bypass; /* if false, don't refresh watchdog ME client */ - - struct file *iamthif_file_object; - struct mei_cl iamthif_cl; - int iamthif_ioctl; - int iamthif_canceled; - int iamthif_mtu; - unsigned long iamthif_timer; - u32 iamthif_stall_timer; - unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */ - u32 iamthif_msg_buf_size; - u32 iamthif_msg_buf_index; - int iamthif_flow_control_pending; - enum iamthif_states iamthif_state; - struct mei_cl_cb *iamthif_current_cb; - u8 write_hang; - int need_reset; - long open_handle_count; - -}; - - -/* - * mei init function prototypes - */ -struct mei_device *init_mei_device(struct pci_dev *pdev); -void mei_reset(struct mei_device *dev, int interrupts); -int mei_hw_init(struct mei_device *dev); -int mei_task_initialize_clients(void *data); -int mei_initialize_clients(struct mei_device *dev); -struct mei_cl *mei_alloc_file_private(struct mei_device *dev); -int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl); -void mei_initialize_list(struct mei_io_list *list, - struct mei_device *dev); -void mei_flush_list(struct mei_io_list *list, struct mei_cl *cl); -void mei_flush_queues(struct mei_device *dev, struct mei_cl *cl); -void mei_remove_client_from_file_list(struct mei_device *dev, - u8 host_client_id); -void host_init_iamthif(struct mei_device *dev); -void mei_init_file_private(struct mei_cl *priv, struct mei_device *dev); -void allocate_me_clients_storage(struct mei_device *dev); - -void host_start_message(struct mei_device *dev); -void host_enum_clients_message(struct mei_device *dev); -void host_client_properties(struct mei_device *dev); - -u8 mei_find_me_client_update_filext(struct mei_device *dev, - struct mei_cl *priv, - const uuid_le *cguid, u8 client_id); - -/* - * 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_wd_timer(struct work_struct *work); - -/* - * input output function prototype - */ -int mei_ioctl_connect_client(struct file *file, - struct mei_connect_client_data *data); - -int mei_start_read(struct mei_device *dev, struct mei_cl *cl); - -int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); - -int amthi_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset); - -struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev, - struct file *file); - -void run_next_iamthif_cmd(struct mei_device *dev); - -void mei_free_cb_private(struct mei_cl_cb *priv_cb); - -int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid); - -/* - * Register Access Function - */ - -/** - * mei_reg_read - Reads 32bit data from the mei device - * - * @dev: the device structure - * @offset: offset from which to read the data - * - * returns the byte read. - */ -static inline u32 mei_reg_read(struct mei_device *dev, - unsigned long offset) -{ - return ioread32(dev->mem_addr + offset); -} - -/** - * mei_reg_write - Writes 32bit data to the mei device - * - * @dev: the device structure - * @offset: offset from which to write the data - * @value: the byte to write - */ -static inline void mei_reg_write(struct mei_device *dev, - unsigned long offset, u32 value) -{ - iowrite32(value, dev->mem_addr + offset); -} - -/** - * mei_hcsr_read - Reads 32bit data from the host CSR - * - * @dev: the device structure - * - * returns the byte read. - */ -static inline u32 mei_hcsr_read(struct mei_device *dev) -{ - return mei_reg_read(dev, H_CSR); -} - -/** - * mei_mecsr_read - Reads 32bit data from the ME CSR - * - * @dev: the device structure - * - * returns ME_CSR_HA register value (u32) - */ -static inline u32 mei_mecsr_read(struct mei_device *dev) -{ - return mei_reg_read(dev, ME_CSR_HA); -} - -/** - * get_me_cb_rw - Reads 32bit data from the mei ME_CB_RW register - * - * @dev: the device structure - * - * returns ME_CB_RW register value (u32) - */ -static inline u32 mei_mecbrw_read(struct mei_device *dev) -{ - return mei_reg_read(dev, ME_CB_RW); -} - - -/* - * mei interface function prototypes - */ -void mei_hcsr_set(struct mei_device *dev); -void mei_csr_clear_his(struct mei_device *dev); - -void mei_enable_interrupts(struct mei_device *dev); -void mei_disable_interrupts(struct mei_device *dev); - -/** - * mei_fe_same_id - tells if file private data have same id - * - * @fe1: private data of 1. file object - * @fe2: private data of 2. file object - * - * returns !=0 - if ids are the same, 0 - if differ. - */ -static inline int mei_fe_same_id(const struct mei_cl *fe1, - const struct mei_cl *fe2) -{ - return ((fe1->host_client_id == fe2->host_client_id) && - (fe1->me_client_id == fe2->me_client_id)); -} - -#endif diff --git a/drivers/staging/mei/mei_version.h b/drivers/staging/mei/mei_version.h deleted file mode 100644 index 075bad8f0bf..00000000000 --- a/drivers/staging/mei/mei_version.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ - - -#ifndef MEI_VERSION_H -#define MEI_VERSION_H - -#define MAJOR_VERSION 7 -#define MINOR_VERSION 1 -#define QUICK_FIX_NUMBER 20 -#define VER_BUILD 1 - -#define MEI_DRV_VER1 __stringify(MAJOR_VERSION) "." __stringify(MINOR_VERSION) -#define MEI_DRV_VER2 __stringify(QUICK_FIX_NUMBER) "." __stringify(VER_BUILD) - -#define MEI_DRIVER_VERSION MEI_DRV_VER1 "." MEI_DRV_VER2 - -#endif diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c deleted file mode 100644 index 2564b038636..00000000000 --- a/drivers/staging/mei/wd.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * - * Intel Management Engine Interface (Intel MEI) Linux driver - * Copyright (c) 2003-2011, 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. - * - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/pci.h> -#include <linux/sched.h> - -#include "mei_dev.h" -#include "hw.h" -#include "interface.h" -#include "mei.h" - -/* - * MEI Watchdog Module Parameters - */ -static u16 watchdog_timeout = AMT_WD_VALUE; -module_param(watchdog_timeout, ushort, 0); -MODULE_PARM_DESC(watchdog_timeout, - "Intel(R) AMT Watchdog timeout value in seconds. (default=" - __MODULE_STRING(AMT_WD_VALUE) - ", disable=0)"); - -static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 }; -static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 }; - -const u8 mei_wd_state_independence_msg[3][4] = { - {0x05, 0x02, 0x51, 0x10}, - {0x05, 0x02, 0x52, 0x10}, - {0x07, 0x02, 0x01, 0x10} -}; - -/* UUIDs for AMT F/W clients */ -const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89, - 0x9D, 0xA9, 0x15, 0x14, 0xCB, - 0x32, 0xAB); - - -void mei_wd_start_setup(struct mei_device *dev) -{ - dev_dbg(&dev->pdev->dev, "dev->wd_timeout=%d.\n", dev->wd_timeout); - memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE); - memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, - &dev->wd_timeout, sizeof(u16)); -} - -/** - * host_init_wd - mei initialization wd. - * - * @dev: the device structure - */ -void mei_wd_host_init(struct mei_device *dev) -{ - mei_init_file_private(&dev->wd_cl, dev); - - /* look for WD client and connect to it */ - dev->wd_cl.state = MEI_FILE_DISCONNECTED; - dev->wd_timeout = watchdog_timeout; - - if (dev->wd_timeout > 0) { - mei_wd_start_setup(dev); - /* find ME WD client */ - mei_find_me_client_update_filext(dev, &dev->wd_cl, - &mei_wd_guid, MEI_WD_HOST_CLIENT_ID); - - dev_dbg(&dev->pdev->dev, "check wd_cl\n"); - if (MEI_FILE_CONNECTING == dev->wd_cl.state) { - if (!mei_connect(dev, &dev->wd_cl)) { - dev_dbg(&dev->pdev->dev, "Failed to connect to WD client\n"); - dev->wd_cl.state = MEI_FILE_DISCONNECTED; - dev->wd_cl.host_client_id = 0; - host_init_iamthif(dev) ; - } else { - dev->wd_cl.timer_count = CONNECT_TIMEOUT; - } - } else { - dev_dbg(&dev->pdev->dev, "Failed to find WD client\n"); - host_init_iamthif(dev) ; - } - } else { - dev->wd_bypass = true; - dev_dbg(&dev->pdev->dev, "WD requested to be disabled\n"); - host_init_iamthif(dev) ; - } -} - -/** - * mei_wd_send - sends watch dog message to fw. - * - * @dev: the device structure - * - * returns 0 if success, - * -EIO when message send fails - * -EINVAL when invalid message is to be sent - */ -int mei_wd_send(struct mei_device *dev) -{ - struct mei_msg_hdr *mei_hdr; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = dev->wd_cl.host_client_id; - mei_hdr->me_addr = dev->wd_cl.me_client_id; - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE)) - mei_hdr->length = MEI_START_WD_DATA_SIZE; - else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE)) - mei_hdr->length = MEI_WD_PARAMS_SIZE; - else - return -EINVAL; - - if (mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length)) - return 0; - return -EIO; -} - -int mei_wd_stop(struct mei_device *dev, bool preserve) -{ - int ret; - u16 wd_timeout = dev->wd_timeout; - - cancel_delayed_work(&dev->wd_work); - if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout) - return 0; - - dev->wd_timeout = 0; - dev->wd_due_counter = 0; - memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE); - dev->stop = 1; - - ret = mei_flow_ctrl_creds(dev, &dev->wd_cl); - if (ret < 0) - goto out; - - if (ret && dev->mei_host_buffer_is_empty) { - ret = 0; - dev->mei_host_buffer_is_empty = 0; - - if (!mei_wd_send(dev)) { - ret = mei_flow_ctrl_reduce(dev, &dev->wd_cl); - if (ret) - goto out; - } else { - dev_dbg(&dev->pdev->dev, "send stop WD failed\n"); - } - - dev->wd_pending = 0; - } else { - dev->wd_pending = 1; - } - dev->wd_stopped = 0; - mutex_unlock(&dev->device_lock); - - ret = wait_event_interruptible_timeout(dev->wait_stop_wd, - dev->wd_stopped, 10 * HZ); - mutex_lock(&dev->device_lock); - if (!dev->wd_stopped) - dev_dbg(&dev->pdev->dev, "stop wd failed to complete.\n"); - else - dev_dbg(&dev->pdev->dev, "stop wd complete.\n"); - - if (preserve) - dev->wd_timeout = wd_timeout; - -out: - return ret; -} - |
