diff options
| -rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/staging/Makefile | 1 | ||||
| -rw-r--r-- | drivers/staging/heci/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/staging/heci/Makefile | 9 | ||||
| -rw-r--r-- | drivers/staging/heci/TODO | 6 | ||||
| -rw-r--r-- | drivers/staging/heci/heci.h | 175 | ||||
| -rw-r--r-- | drivers/staging/heci/heci_data_structures.h | 529 | ||||
| -rw-r--r-- | drivers/staging/heci/heci_init.c | 1083 | ||||
| -rw-r--r-- | drivers/staging/heci/heci_interface.c | 498 | ||||
| -rw-r--r-- | drivers/staging/heci/heci_interface.h | 170 | ||||
| -rw-r--r-- | drivers/staging/heci/heci_main.c | 1576 | ||||
| -rw-r--r-- | drivers/staging/heci/heci_version.h | 54 | ||||
| -rw-r--r-- | drivers/staging/heci/interrupt.c | 1555 | ||||
| -rw-r--r-- | drivers/staging/heci/io_heci.c | 872 |
14 files changed, 0 insertions, 6537 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 66188a5bf44b..e86a6716156c 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
| @@ -103,8 +103,6 @@ source "drivers/staging/phison/Kconfig" | |||
| 103 | 103 | ||
| 104 | source "drivers/staging/p9auth/Kconfig" | 104 | source "drivers/staging/p9auth/Kconfig" |
| 105 | 105 | ||
| 106 | source "drivers/staging/heci/Kconfig" | ||
| 107 | |||
| 108 | source "drivers/staging/line6/Kconfig" | 106 | source "drivers/staging/line6/Kconfig" |
| 109 | 107 | ||
| 110 | source "drivers/gpu/drm/radeon/Kconfig" | 108 | source "drivers/gpu/drm/radeon/Kconfig" |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 3c64d5fad655..fa5361664ba8 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
| @@ -34,7 +34,6 @@ obj-$(CONFIG_STLC45XX) += stlc45xx/ | |||
| 34 | obj-$(CONFIG_B3DFG) += b3dfg/ | 34 | obj-$(CONFIG_B3DFG) += b3dfg/ |
| 35 | obj-$(CONFIG_IDE_PHISON) += phison/ | 35 | obj-$(CONFIG_IDE_PHISON) += phison/ |
| 36 | obj-$(CONFIG_PLAN9AUTH) += p9auth/ | 36 | obj-$(CONFIG_PLAN9AUTH) += p9auth/ |
| 37 | obj-$(CONFIG_HECI) += heci/ | ||
| 38 | obj-$(CONFIG_LINE6_USB) += line6/ | 37 | obj-$(CONFIG_LINE6_USB) += line6/ |
| 39 | obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/ | 38 | obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/ |
| 40 | obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/ | 39 | obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/ |
diff --git a/drivers/staging/heci/Kconfig b/drivers/staging/heci/Kconfig deleted file mode 100644 index c7206f8bcd93..000000000000 --- a/drivers/staging/heci/Kconfig +++ /dev/null | |||
| @@ -1,7 +0,0 @@ | |||
| 1 | config HECI | ||
| 2 | tristate "Intel Management Engine Interface (MEI) Support" | ||
| 3 | depends on PCI | ||
| 4 | ---help--- | ||
| 5 | The Intel Management Engine Interface (Intel MEI) driver allows | ||
| 6 | applications to access the Active Management Technology | ||
| 7 | firmware and other Management Engine sub-systems. | ||
diff --git a/drivers/staging/heci/Makefile b/drivers/staging/heci/Makefile deleted file mode 100644 index 0524856fa3ab..000000000000 --- a/drivers/staging/heci/Makefile +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | obj-$(CONFIG_HECI) += heci.o | ||
| 2 | |||
| 3 | heci-objs := \ | ||
| 4 | heci_init.o \ | ||
| 5 | interrupt.o \ | ||
| 6 | heci_interface.o \ | ||
| 7 | io_heci.o \ | ||
| 8 | heci_main.o | ||
| 9 | |||
diff --git a/drivers/staging/heci/TODO b/drivers/staging/heci/TODO deleted file mode 100644 index f86715d631c4..000000000000 --- a/drivers/staging/heci/TODO +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | TODO: | ||
| 2 | - fix user/kernel pointer mess in the ioctl handlers as pointed | ||
| 3 | out by sparse. | ||
| 4 | - resolve the ioctls and see if most of them can just be simple | ||
| 5 | sysfs files | ||
| 6 | - fix locking issues that sparse points out at the least. | ||
diff --git a/drivers/staging/heci/heci.h b/drivers/staging/heci/heci.h deleted file mode 100644 index 48f120dc3b27..000000000000 --- a/drivers/staging/heci/heci.h +++ /dev/null | |||
| @@ -1,175 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | #ifndef _HECI_H_ | ||
| 42 | #define _HECI_H_ | ||
| 43 | |||
| 44 | #include <linux/spinlock.h> | ||
| 45 | #include <linux/list.h> | ||
| 46 | #include <linux/pci.h> | ||
| 47 | #include <linux/timer.h> | ||
| 48 | #include <linux/interrupt.h> | ||
| 49 | #include <linux/workqueue.h> | ||
| 50 | #include <linux/module.h> | ||
| 51 | #include <linux/aio.h> | ||
| 52 | #include <linux/types.h> | ||
| 53 | #include "heci_data_structures.h" | ||
| 54 | |||
| 55 | extern const struct guid heci_pthi_guid; | ||
| 56 | extern const struct guid heci_wd_guid; | ||
| 57 | extern const __u8 heci_start_wd_params[]; | ||
| 58 | extern const __u8 heci_stop_wd_params[]; | ||
| 59 | extern const __u8 heci_wd_state_independence_msg[3][4]; | ||
| 60 | |||
| 61 | /* | ||
| 62 | * heci device ID | ||
| 63 | */ | ||
| 64 | #define HECI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */ | ||
| 65 | #define HECI_DEV_ID_82G35 0x2984 /* 82G35 Express */ | ||
| 66 | #define HECI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */ | ||
| 67 | #define HECI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */ | ||
| 68 | |||
| 69 | #define HECI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */ | ||
| 70 | #define HECI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */ | ||
| 71 | |||
| 72 | #define HECI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */ | ||
| 73 | #define HECI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */ | ||
| 74 | #define HECI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */ | ||
| 75 | #define HECI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */ | ||
| 76 | #define HECI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */ | ||
| 77 | |||
| 78 | #define HECI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */ | ||
| 79 | #define HECI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */ | ||
| 80 | #define HECI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */ | ||
| 81 | #define HECI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */ | ||
| 82 | #define HECI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */ | ||
| 83 | |||
| 84 | #define HECI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */ | ||
| 85 | #define HECI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */ | ||
| 86 | #define HECI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */ | ||
| 87 | #define HECI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */ | ||
| 88 | |||
| 89 | #define HECI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */ | ||
| 90 | #define HECI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */ | ||
| 91 | #define HECI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */ | ||
| 92 | #define HECI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */ | ||
| 93 | |||
| 94 | /* | ||
| 95 | * heci init function prototypes | ||
| 96 | */ | ||
| 97 | struct iamt_heci_device *init_heci_device(struct pci_dev *pdev); | ||
| 98 | void heci_reset(struct iamt_heci_device *dev, int interrupts); | ||
| 99 | int heci_hw_init(struct iamt_heci_device *dev); | ||
| 100 | int heci_task_initialize_clients(void *data); | ||
| 101 | int heci_initialize_clients(struct iamt_heci_device *dev); | ||
| 102 | struct heci_file_private *heci_alloc_file_private(struct file *file); | ||
| 103 | int heci_disconnect_host_client(struct iamt_heci_device *dev, | ||
| 104 | struct heci_file_private *file_ext); | ||
| 105 | void heci_initialize_list(struct io_heci_list *list, | ||
| 106 | struct iamt_heci_device *dev); | ||
| 107 | void heci_flush_list(struct io_heci_list *list, | ||
| 108 | struct heci_file_private *file_ext); | ||
| 109 | void heci_flush_queues(struct iamt_heci_device *dev, | ||
| 110 | struct heci_file_private *file_ext); | ||
| 111 | |||
| 112 | void heci_remove_client_from_file_list(struct iamt_heci_device *dev, | ||
| 113 | __u8 host_client_id); | ||
| 114 | |||
| 115 | /* | ||
| 116 | * interrupt function prototype | ||
| 117 | */ | ||
| 118 | irqreturn_t heci_isr_interrupt(int irq, void *dev_id); | ||
| 119 | |||
| 120 | void heci_wd_timer(unsigned long data); | ||
| 121 | |||
| 122 | /* | ||
| 123 | * input output function prototype | ||
| 124 | */ | ||
| 125 | int heci_ioctl_get_version(struct iamt_heci_device *dev, int if_num, | ||
| 126 | struct heci_message_data __user *u_msg, | ||
| 127 | struct heci_message_data k_msg, | ||
| 128 | struct heci_file_private *file_ext); | ||
| 129 | |||
| 130 | int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, | ||
| 131 | struct heci_message_data __user *u_msg, | ||
| 132 | struct heci_message_data k_msg, | ||
| 133 | struct file *file); | ||
| 134 | |||
| 135 | int heci_ioctl_wd(struct iamt_heci_device *dev, int if_num, | ||
| 136 | struct heci_message_data k_msg, | ||
| 137 | struct heci_file_private *file_ext); | ||
| 138 | |||
| 139 | int heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num, | ||
| 140 | struct heci_message_data k_msg, | ||
| 141 | struct heci_file_private *file_ext); | ||
| 142 | |||
| 143 | int heci_start_read(struct iamt_heci_device *dev, int if_num, | ||
| 144 | struct heci_file_private *file_ext); | ||
| 145 | |||
| 146 | int pthi_write(struct iamt_heci_device *dev, | ||
| 147 | struct heci_cb_private *priv_cb); | ||
| 148 | |||
| 149 | int pthi_read(struct iamt_heci_device *dev, int if_num, struct file *file, | ||
| 150 | char __user *ubuf, size_t length, loff_t *offset); | ||
| 151 | |||
| 152 | struct heci_cb_private *find_pthi_read_list_entry( | ||
| 153 | struct iamt_heci_device *dev, | ||
| 154 | struct file *file); | ||
| 155 | |||
| 156 | void run_next_iamthif_cmd(struct iamt_heci_device *dev); | ||
| 157 | |||
| 158 | void heci_free_cb_private(struct heci_cb_private *priv_cb); | ||
| 159 | |||
| 160 | /** | ||
| 161 | * heci_fe_same_id - tell if file private data have same id | ||
| 162 | * | ||
| 163 | * @fe1: private data of 1. file object | ||
| 164 | * @fe2: private data of 2. file object | ||
| 165 | * | ||
| 166 | * returns !=0 - if ids are the same, 0 - if differ. | ||
| 167 | */ | ||
| 168 | static inline int heci_fe_same_id(const struct heci_file_private *fe1, | ||
| 169 | const struct heci_file_private *fe2) | ||
| 170 | { | ||
| 171 | return ((fe1->host_client_id == fe2->host_client_id) | ||
| 172 | && (fe1->me_client_id == fe2->me_client_id)); | ||
| 173 | } | ||
| 174 | |||
| 175 | #endif /* _HECI_H_ */ | ||
diff --git a/drivers/staging/heci/heci_data_structures.h b/drivers/staging/heci/heci_data_structures.h deleted file mode 100644 index ff30386d097a..000000000000 --- a/drivers/staging/heci/heci_data_structures.h +++ /dev/null | |||
| @@ -1,529 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | #ifndef _HECI_DATA_STRUCTURES_H_ | ||
| 42 | #define _HECI_DATA_STRUCTURES_H_ | ||
| 43 | |||
| 44 | #include <linux/spinlock.h> | ||
| 45 | #include <linux/list.h> | ||
| 46 | #include <linux/pci.h> | ||
| 47 | #include <linux/timer.h> | ||
| 48 | #include <linux/interrupt.h> | ||
| 49 | #include <linux/workqueue.h> | ||
| 50 | #include <linux/module.h> | ||
| 51 | #include <linux/aio.h> | ||
| 52 | #include <linux/types.h> | ||
| 53 | |||
| 54 | /* | ||
| 55 | * error code definition | ||
| 56 | */ | ||
| 57 | #define ESLOTS_OVERFLOW 1 | ||
| 58 | #define ECORRUPTED_MESSAGE_HEADER 1000 | ||
| 59 | #define ECOMPLETE_MESSAGE 1001 | ||
| 60 | |||
| 61 | #define HECI_FC_MESSAGE_RESERVED_LENGTH 5 | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Number of queue lists used by this driver | ||
| 65 | */ | ||
| 66 | #define HECI_IO_LISTS_NUMBER 7 | ||
| 67 | |||
| 68 | /* | ||
| 69 | * Maximum transmission unit (MTU) of heci messages | ||
| 70 | */ | ||
| 71 | #define IAMTHIF_MTU 4160 | ||
| 72 | |||
| 73 | |||
| 74 | /* | ||
| 75 | * HECI HW Section | ||
| 76 | */ | ||
| 77 | |||
| 78 | /* HECI registers */ | ||
| 79 | /* H_CB_WW - Host Circular Buffer (CB) Write Window register */ | ||
| 80 | #define H_CB_WW 0 | ||
| 81 | /* H_CSR - Host Control Status register */ | ||
| 82 | #define H_CSR 4 | ||
| 83 | /* ME_CB_RW - ME Circular Buffer Read Window register (read only) */ | ||
| 84 | #define ME_CB_RW 8 | ||
| 85 | /* ME_CSR_HA - ME Control Status Host Access register (read only) */ | ||
| 86 | #define ME_CSR_HA 0xC | ||
| 87 | |||
| 88 | |||
| 89 | /* register bits of H_CSR (Host Control Status register) */ | ||
| 90 | /* Host Circular Buffer Depth - maximum number of 32-bit entries in CB */ | ||
| 91 | #define H_CBD 0xFF000000 | ||
| 92 | /* Host Circular Buffer Write Pointer */ | ||
| 93 | #define H_CBWP 0x00FF0000 | ||
| 94 | /* Host Circular Buffer Read Pointer */ | ||
| 95 | #define H_CBRP 0x0000FF00 | ||
| 96 | /* Host Reset */ | ||
| 97 | #define H_RST 0x00000010 | ||
| 98 | /* Host Ready */ | ||
| 99 | #define H_RDY 0x00000008 | ||
| 100 | /* Host Interrupt Generate */ | ||
| 101 | #define H_IG 0x00000004 | ||
| 102 | /* Host Interrupt Status */ | ||
| 103 | #define H_IS 0x00000002 | ||
| 104 | /* Host Interrupt Enable */ | ||
| 105 | #define H_IE 0x00000001 | ||
| 106 | |||
| 107 | |||
| 108 | /* register bits of ME_CSR_HA (ME Control Status Host Access register) */ | ||
| 109 | /* ME CB (Circular Buffer) Depth HRA (Host Read Access) | ||
| 110 | * - host read only access to ME_CBD */ | ||
| 111 | #define ME_CBD_HRA 0xFF000000 | ||
| 112 | /* ME CB Write Pointer HRA - host read only access to ME_CBWP */ | ||
| 113 | #define ME_CBWP_HRA 0x00FF0000 | ||
| 114 | /* ME CB Read Pointer HRA - host read only access to ME_CBRP */ | ||
| 115 | #define ME_CBRP_HRA 0x0000FF00 | ||
| 116 | /* ME Reset HRA - host read only access to ME_RST */ | ||
| 117 | #define ME_RST_HRA 0x00000010 | ||
| 118 | /* ME Ready HRA - host read only access to ME_RDY */ | ||
| 119 | #define ME_RDY_HRA 0x00000008 | ||
| 120 | /* ME Interrupt Generate HRA - host read only access to ME_IG */ | ||
| 121 | #define ME_IG_HRA 0x00000004 | ||
| 122 | /* ME Interrupt Status HRA - host read only access to ME_IS */ | ||
| 123 | #define ME_IS_HRA 0x00000002 | ||
| 124 | /* ME Interrupt Enable HRA - host read only access to ME_IE */ | ||
| 125 | #define ME_IE_HRA 0x00000001 | ||
| 126 | |||
| 127 | #define HECI_MINORS_BASE 1 | ||
| 128 | #define HECI_MINORS_COUNT 1 | ||
| 129 | |||
| 130 | #define HECI_MINOR_NUMBER 1 | ||
| 131 | #define HECI_MAX_OPEN_HANDLE_COUNT 253 | ||
| 132 | |||
| 133 | /* | ||
| 134 | * debug kernel print macro define | ||
| 135 | */ | ||
| 136 | extern int heci_debug; | ||
| 137 | |||
| 138 | #define DBG(format, arg...) do { \ | ||
| 139 | if (heci_debug) \ | ||
| 140 | printk(KERN_INFO "heci: %s: " format, __func__, ## arg); \ | ||
| 141 | } while (0) | ||
| 142 | |||
| 143 | |||
| 144 | /* | ||
| 145 | * time to wait HECI become ready after init | ||
| 146 | */ | ||
| 147 | #define HECI_INTEROP_TIMEOUT (HZ * 7) | ||
| 148 | |||
| 149 | /* | ||
| 150 | * watch dog definition | ||
| 151 | */ | ||
| 152 | #define HECI_WATCHDOG_DATA_SIZE 16 | ||
| 153 | #define HECI_START_WD_DATA_SIZE 20 | ||
| 154 | #define HECI_WD_PARAMS_SIZE 4 | ||
| 155 | #define HECI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0) | ||
| 156 | |||
| 157 | #define HECI_WD_HOST_CLIENT_ID 1 | ||
| 158 | #define HECI_IAMTHIF_HOST_CLIENT_ID 2 | ||
| 159 | |||
| 160 | struct guid { | ||
| 161 | __u32 data1; | ||
| 162 | __u16 data2; | ||
| 163 | __u16 data3; | ||
| 164 | __u8 data4[8]; | ||
| 165 | }; | ||
| 166 | |||
| 167 | /* File state */ | ||
| 168 | enum file_state { | ||
| 169 | HECI_FILE_INITIALIZING = 0, | ||
| 170 | HECI_FILE_CONNECTING, | ||
| 171 | HECI_FILE_CONNECTED, | ||
| 172 | HECI_FILE_DISCONNECTING, | ||
| 173 | HECI_FILE_DISCONNECTED | ||
| 174 | }; | ||
| 175 | |||
| 176 | /* HECI device states */ | ||
| 177 | enum heci_states { | ||
| 178 | HECI_INITIALIZING = 0, | ||
| 179 | HECI_ENABLED, | ||
| 180 | HECI_RESETING, | ||
| 181 | HECI_DISABLED, | ||
| 182 | HECI_RECOVERING_FROM_RESET, | ||
| 183 | HECI_POWER_DOWN, | ||
| 184 | HECI_POWER_UP | ||
| 185 | }; | ||
| 186 | |||
| 187 | enum iamthif_states { | ||
| 188 | HECI_IAMTHIF_IDLE, | ||
| 189 | HECI_IAMTHIF_WRITING, | ||
| 190 | HECI_IAMTHIF_FLOW_CONTROL, | ||
| 191 | HECI_IAMTHIF_READING, | ||
| 192 | HECI_IAMTHIF_READ_COMPLETE | ||
| 193 | }; | ||
| 194 | |||
| 195 | enum heci_file_transaction_states { | ||
| 196 | HECI_IDLE, | ||
| 197 | HECI_WRITING, | ||
| 198 | HECI_WRITE_COMPLETE, | ||
| 199 | HECI_FLOW_CONTROL, | ||
| 200 | HECI_READING, | ||
| 201 | HECI_READ_COMPLETE | ||
| 202 | }; | ||
| 203 | |||
| 204 | /* HECI CB */ | ||
| 205 | enum heci_cb_major_types { | ||
| 206 | HECI_READ = 0, | ||
| 207 | HECI_WRITE, | ||
| 208 | HECI_IOCTL, | ||
| 209 | HECI_OPEN, | ||
| 210 | HECI_CLOSE | ||
| 211 | }; | ||
| 212 | |||
| 213 | /* HECI user data struct */ | ||
| 214 | struct heci_message_data { | ||
| 215 | __u32 size; | ||
| 216 | char *data; | ||
| 217 | } __attribute__((packed)); | ||
| 218 | |||
| 219 | #define HECI_CONNECT_TIMEOUT 3 /* at least 2 seconds */ | ||
| 220 | |||
| 221 | #define IAMTHIF_STALL_TIMER 12 /* seconds */ | ||
| 222 | #define IAMTHIF_READ_TIMER 15 /* seconds */ | ||
| 223 | |||
| 224 | struct heci_cb_private { | ||
| 225 | struct list_head cb_list; | ||
| 226 | enum heci_cb_major_types major_file_operations; | ||
| 227 | void *file_private; | ||
| 228 | struct heci_message_data request_buffer; | ||
| 229 | struct heci_message_data response_buffer; | ||
| 230 | unsigned long information; | ||
| 231 | unsigned long read_time; | ||
| 232 | struct file *file_object; | ||
| 233 | }; | ||
| 234 | |||
| 235 | /* Private file struct */ | ||
| 236 | struct heci_file_private { | ||
| 237 | struct list_head link; | ||
| 238 | struct file *file; | ||
| 239 | enum file_state state; | ||
| 240 | wait_queue_head_t tx_wait; | ||
| 241 | wait_queue_head_t rx_wait; | ||
| 242 | wait_queue_head_t wait; | ||
| 243 | spinlock_t file_lock; /* file lock */ | ||
| 244 | spinlock_t read_io_lock; /* read lock */ | ||
| 245 | spinlock_t write_io_lock; /* write lock */ | ||
| 246 | int read_pending; | ||
| 247 | int status; | ||
| 248 | /* ID of client connected */ | ||
| 249 | __u8 host_client_id; | ||
| 250 | __u8 me_client_id; | ||
| 251 | __u8 flow_ctrl_creds; | ||
| 252 | __u8 timer_count; | ||
| 253 | enum heci_file_transaction_states reading_state; | ||
| 254 | enum heci_file_transaction_states writing_state; | ||
| 255 | int sm_state; | ||
| 256 | struct heci_cb_private *read_cb; | ||
| 257 | }; | ||
| 258 | |||
| 259 | struct io_heci_list { | ||
| 260 | struct heci_cb_private heci_cb; | ||
| 261 | int status; | ||
| 262 | struct iamt_heci_device *device_extension; | ||
| 263 | }; | ||
| 264 | |||
| 265 | struct heci_driver_version { | ||
| 266 | __u8 major; | ||
| 267 | __u8 minor; | ||
| 268 | __u8 hotfix; | ||
| 269 | __u16 build; | ||
| 270 | } __attribute__((packed)); | ||
| 271 | |||
| 272 | |||
| 273 | struct heci_client { | ||
| 274 | __u32 max_msg_length; | ||
| 275 | __u8 protocol_version; | ||
| 276 | } __attribute__((packed)); | ||
| 277 | |||
| 278 | /* | ||
| 279 | * HECI BUS Interface Section | ||
| 280 | */ | ||
| 281 | struct heci_msg_hdr { | ||
| 282 | __u32 me_addr:8; | ||
| 283 | __u32 host_addr:8; | ||
| 284 | __u32 length:9; | ||
| 285 | __u32 reserved:6; | ||
| 286 | __u32 msg_complete:1; | ||
| 287 | } __attribute__((packed)); | ||
| 288 | |||
| 289 | |||
| 290 | struct hbm_cmd { | ||
| 291 | __u8 cmd:7; | ||
| 292 | __u8 is_response:1; | ||
| 293 | } __attribute__((packed)); | ||
| 294 | |||
| 295 | |||
| 296 | struct heci_bus_message { | ||
| 297 | struct hbm_cmd cmd; | ||
| 298 | __u8 command_specific_data[]; | ||
| 299 | } __attribute__((packed)); | ||
| 300 | |||
| 301 | struct hbm_version { | ||
| 302 | __u8 minor_version; | ||
| 303 | __u8 major_version; | ||
| 304 | } __attribute__((packed)); | ||
| 305 | |||
| 306 | struct hbm_host_version_request { | ||
| 307 | struct hbm_cmd cmd; | ||
| 308 | __u8 reserved; | ||
| 309 | struct hbm_version host_version; | ||
| 310 | } __attribute__((packed)); | ||
| 311 | |||
| 312 | struct hbm_host_version_response { | ||
| 313 | struct hbm_cmd cmd; | ||
| 314 | int host_version_supported; | ||
| 315 | struct hbm_version me_max_version; | ||
| 316 | } __attribute__((packed)); | ||
| 317 | |||
| 318 | struct hbm_host_stop_request { | ||
| 319 | struct hbm_cmd cmd; | ||
| 320 | __u8 reason; | ||
| 321 | __u8 reserved[2]; | ||
| 322 | } __attribute__((packed)); | ||
| 323 | |||
| 324 | struct hbm_host_stop_response { | ||
| 325 | struct hbm_cmd cmd; | ||
| 326 | __u8 reserved[3]; | ||
| 327 | } __attribute__((packed)); | ||
| 328 | |||
| 329 | struct hbm_me_stop_request { | ||
| 330 | struct hbm_cmd cmd; | ||
| 331 | __u8 reason; | ||
| 332 | __u8 reserved[2]; | ||
| 333 | } __attribute__((packed)); | ||
| 334 | |||
| 335 | struct hbm_host_enum_request { | ||
| 336 | struct hbm_cmd cmd; | ||
| 337 | __u8 reserved[3]; | ||
| 338 | } __attribute__((packed)); | ||
| 339 | |||
| 340 | struct hbm_host_enum_response { | ||
| 341 | struct hbm_cmd cmd; | ||
| 342 | __u8 reserved[3]; | ||
| 343 | __u8 valid_addresses[32]; | ||
| 344 | } __attribute__((packed)); | ||
| 345 | |||
| 346 | struct heci_client_properties { | ||
| 347 | struct guid protocol_name; | ||
| 348 | __u8 protocol_version; | ||
| 349 | __u8 max_number_of_connections; | ||
| 350 | __u8 fixed_address; | ||
| 351 | __u8 single_recv_buf; | ||
| 352 | __u32 max_msg_length; | ||
| 353 | } __attribute__((packed)); | ||
| 354 | |||
| 355 | struct hbm_props_request { | ||
| 356 | struct hbm_cmd cmd; | ||
| 357 | __u8 address; | ||
| 358 | __u8 reserved[2]; | ||
| 359 | } __attribute__((packed)); | ||
| 360 | |||
| 361 | |||
| 362 | struct hbm_props_response { | ||
| 363 | struct hbm_cmd cmd; | ||
| 364 | __u8 address; | ||
| 365 | __u8 status; | ||
| 366 | __u8 reserved[1]; | ||
| 367 | struct heci_client_properties client_properties; | ||
| 368 | } __attribute__((packed)); | ||
| 369 | |||
| 370 | struct hbm_client_connect_request { | ||
| 371 | struct hbm_cmd cmd; | ||
| 372 | __u8 me_addr; | ||
| 373 | __u8 host_addr; | ||
| 374 | __u8 reserved; | ||
| 375 | } __attribute__((packed)); | ||
| 376 | |||
| 377 | struct hbm_client_connect_response { | ||
| 378 | struct hbm_cmd cmd; | ||
| 379 | __u8 me_addr; | ||
| 380 | __u8 host_addr; | ||
| 381 | __u8 status; | ||
| 382 | } __attribute__((packed)); | ||
| 383 | |||
| 384 | struct hbm_client_disconnect_request { | ||
| 385 | struct hbm_cmd cmd; | ||
| 386 | __u8 me_addr; | ||
| 387 | __u8 host_addr; | ||
| 388 | __u8 reserved[1]; | ||
| 389 | } __attribute__((packed)); | ||
| 390 | |||
| 391 | struct hbm_flow_control { | ||
| 392 | struct hbm_cmd cmd; | ||
| 393 | __u8 me_addr; | ||
| 394 | __u8 host_addr; | ||
| 395 | __u8 reserved[HECI_FC_MESSAGE_RESERVED_LENGTH]; | ||
| 396 | } __attribute__((packed)); | ||
| 397 | |||
| 398 | struct heci_me_client { | ||
| 399 | struct heci_client_properties props; | ||
| 400 | __u8 client_id; | ||
| 401 | __u8 flow_ctrl_creds; | ||
| 402 | } __attribute__((packed)); | ||
| 403 | |||
| 404 | /* private device struct */ | ||
| 405 | struct iamt_heci_device { | ||
| 406 | struct pci_dev *pdev; /* pointer to pci device struct */ | ||
| 407 | /* | ||
| 408 | * lists of queues | ||
| 409 | */ | ||
| 410 | /* array of pointers to aio lists */ | ||
| 411 | struct io_heci_list *io_list_array[HECI_IO_LISTS_NUMBER]; | ||
| 412 | struct io_heci_list read_list; /* driver read queue */ | ||
| 413 | struct io_heci_list write_list; /* driver write queue */ | ||
| 414 | struct io_heci_list write_waiting_list; /* write waiting queue */ | ||
| 415 | struct io_heci_list ctrl_wr_list; /* managed write IOCTL list */ | ||
| 416 | struct io_heci_list ctrl_rd_list; /* managed read IOCTL list */ | ||
| 417 | struct io_heci_list pthi_cmd_list; /* PTHI list for cmd waiting */ | ||
| 418 | |||
| 419 | /* driver managed PTHI list for reading completed pthi cmd data */ | ||
| 420 | struct io_heci_list pthi_read_complete_list; | ||
| 421 | /* | ||
| 422 | * list of files | ||
| 423 | */ | ||
| 424 | struct list_head file_list; | ||
| 425 | /* | ||
| 426 | * memory of device | ||
| 427 | */ | ||
| 428 | unsigned int mem_base; | ||
| 429 | unsigned int mem_length; | ||
| 430 | void __iomem *mem_addr; | ||
| 431 | /* | ||
| 432 | * lock for the device | ||
| 433 | */ | ||
| 434 | spinlock_t device_lock; /* device lock*/ | ||
| 435 | struct work_struct work; | ||
| 436 | int recvd_msg; | ||
| 437 | |||
| 438 | struct task_struct *reinit_tsk; | ||
| 439 | |||
| 440 | struct timer_list wd_timer; | ||
| 441 | /* | ||
| 442 | * hw states of host and fw(ME) | ||
| 443 | */ | ||
| 444 | __u32 host_hw_state; | ||
| 445 | __u32 me_hw_state; | ||
| 446 | /* | ||
| 447 | * waiting queue for receive message from FW | ||
| 448 | */ | ||
| 449 | wait_queue_head_t wait_recvd_msg; | ||
| 450 | wait_queue_head_t wait_stop_wd; | ||
| 451 | /* | ||
| 452 | * heci device states | ||
| 453 | */ | ||
| 454 | enum heci_states heci_state; | ||
| 455 | int stop; | ||
| 456 | |||
| 457 | __u32 extra_write_index; | ||
| 458 | __u32 rd_msg_buf[128]; /* used for control messages */ | ||
| 459 | __u32 wr_msg_buf[128]; /* used for control messages */ | ||
| 460 | __u32 ext_msg_buf[8]; /* for control responses */ | ||
| 461 | __u32 rd_msg_hdr; | ||
| 462 | |||
| 463 | struct hbm_version version; | ||
| 464 | |||
| 465 | int host_buffer_is_empty; | ||
| 466 | struct heci_file_private wd_file_ext; | ||
| 467 | struct heci_me_client *me_clients; /* Note: memory has to be allocated*/ | ||
| 468 | __u8 heci_me_clients[32]; /* list of existing clients */ | ||
| 469 | __u8 num_heci_me_clients; | ||
| 470 | __u8 heci_host_clients[32]; /* list of existing clients */ | ||
| 471 | __u8 current_host_client_id; | ||
| 472 | |||
| 473 | int wd_pending; | ||
| 474 | int wd_stoped; | ||
| 475 | __u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */ | ||
| 476 | unsigned char wd_data[HECI_START_WD_DATA_SIZE]; | ||
| 477 | |||
| 478 | |||
| 479 | __u16 wd_due_counter; | ||
| 480 | int asf_mode; | ||
| 481 | int wd_bypass; /* if 1, don't refresh watchdog ME client */ | ||
| 482 | |||
| 483 | struct file *iamthif_file_object; | ||
| 484 | struct heci_file_private iamthif_file_ext; | ||
| 485 | int iamthif_ioctl; | ||
| 486 | int iamthif_canceled; | ||
| 487 | __u32 iamthif_timer; | ||
| 488 | __u32 iamthif_stall_timer; | ||
| 489 | unsigned char iamthif_msg_buf[IAMTHIF_MTU]; | ||
| 490 | __u32 iamthif_msg_buf_size; | ||
| 491 | __u32 iamthif_msg_buf_index; | ||
| 492 | int iamthif_flow_control_pending; | ||
| 493 | enum iamthif_states iamthif_state; | ||
| 494 | |||
| 495 | struct heci_cb_private *iamthif_current_cb; | ||
| 496 | __u8 write_hang; | ||
| 497 | int need_reset; | ||
| 498 | long open_handle_count; | ||
| 499 | |||
| 500 | }; | ||
| 501 | |||
| 502 | /** | ||
| 503 | * read_heci_register - Read a byte from the heci device | ||
| 504 | * | ||
| 505 | * @dev: the device structure | ||
| 506 | * @offset: offset from which to read the data | ||
| 507 | * | ||
| 508 | * returns the byte read. | ||
| 509 | */ | ||
| 510 | static inline __u32 read_heci_register(struct iamt_heci_device *dev, | ||
| 511 | unsigned long offset) | ||
| 512 | { | ||
| 513 | return readl(dev->mem_addr + offset); | ||
| 514 | } | ||
| 515 | |||
| 516 | /** | ||
| 517 | * write_heci_register - Write 4 bytes to the heci device | ||
| 518 | * | ||
| 519 | * @dev: the device structure | ||
| 520 | * @offset: offset from which to write the data | ||
| 521 | * @value: the byte to write | ||
| 522 | */ | ||
| 523 | static inline void write_heci_register(struct iamt_heci_device *dev, | ||
| 524 | unsigned long offset, __u32 value) | ||
| 525 | { | ||
| 526 | writel(value, dev->mem_addr + offset); | ||
| 527 | } | ||
| 528 | |||
| 529 | #endif /* _HECI_DATA_STRUCTURES_H_ */ | ||
diff --git a/drivers/staging/heci/heci_init.c b/drivers/staging/heci/heci_init.c deleted file mode 100644 index 31fd891c099d..000000000000 --- a/drivers/staging/heci/heci_init.c +++ /dev/null | |||
| @@ -1,1083 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | #include <linux/module.h> | ||
| 42 | #include <linux/pci.h> | ||
| 43 | #include <linux/reboot.h> | ||
| 44 | #include <linux/poll.h> | ||
| 45 | #include <linux/init.h> | ||
| 46 | #include <linux/kdev_t.h> | ||
| 47 | #include <linux/moduleparam.h> | ||
| 48 | #include <linux/wait.h> | ||
| 49 | #include <linux/delay.h> | ||
| 50 | #include <linux/kthread.h> | ||
| 51 | |||
| 52 | #include "heci_data_structures.h" | ||
| 53 | #include "heci_interface.h" | ||
| 54 | #include "heci.h" | ||
| 55 | |||
| 56 | |||
| 57 | const __u8 heci_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 }; | ||
| 58 | const __u8 heci_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 }; | ||
| 59 | |||
| 60 | const __u8 heci_wd_state_independence_msg[3][4] = { | ||
| 61 | {0x05, 0x02, 0x51, 0x10}, | ||
| 62 | {0x05, 0x02, 0x52, 0x10}, | ||
| 63 | {0x07, 0x02, 0x01, 0x10} | ||
| 64 | }; | ||
| 65 | |||
| 66 | static const struct guid heci_asf_guid = { | ||
| 67 | 0x75B30CD6, 0xA29E, 0x4AF7, | ||
| 68 | {0xA7, 0x12, 0xE6, 0x17, 0x43, 0x93, 0xC8, 0xA6} | ||
| 69 | }; | ||
| 70 | const struct guid heci_wd_guid = { | ||
| 71 | 0x05B79A6F, 0x4628, 0x4D7F, | ||
| 72 | {0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB} | ||
| 73 | }; | ||
| 74 | const struct guid heci_pthi_guid = { | ||
| 75 | 0x12f80028, 0xb4b7, 0x4b2d, | ||
| 76 | {0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c} | ||
| 77 | }; | ||
| 78 | |||
| 79 | |||
| 80 | /* | ||
| 81 | * heci init function prototypes | ||
| 82 | */ | ||
| 83 | static void heci_check_asf_mode(struct iamt_heci_device *dev); | ||
| 84 | static int host_start_message(struct iamt_heci_device *dev); | ||
| 85 | static int host_enum_clients_message(struct iamt_heci_device *dev); | ||
| 86 | static int allocate_me_clients_storage(struct iamt_heci_device *dev); | ||
| 87 | static void host_init_wd(struct iamt_heci_device *dev); | ||
| 88 | static void host_init_iamthif(struct iamt_heci_device *dev); | ||
| 89 | static int heci_wait_event_int_timeout(struct iamt_heci_device *dev, | ||
| 90 | long timeout); | ||
| 91 | |||
| 92 | |||
| 93 | /** | ||
| 94 | * heci_initialize_list - Sets up a queue list. | ||
| 95 | * | ||
| 96 | * @list: An instance of our list structure | ||
| 97 | * @dev: Device object for our driver | ||
| 98 | */ | ||
| 99 | void heci_initialize_list(struct io_heci_list *list, | ||
| 100 | struct iamt_heci_device *dev) | ||
| 101 | { | ||
| 102 | /* initialize our queue list */ | ||
| 103 | INIT_LIST_HEAD(&list->heci_cb.cb_list); | ||
| 104 | list->status = 0; | ||
| 105 | list->device_extension = dev; | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | * heci_flush_queues - flush our queues list belong to file_ext. | ||
| 110 | * | ||
| 111 | * @dev: Device object for our driver | ||
| 112 | * @file_ext: private data of the file object | ||
| 113 | */ | ||
| 114 | void heci_flush_queues(struct iamt_heci_device *dev, | ||
| 115 | struct heci_file_private *file_ext) | ||
| 116 | { | ||
| 117 | int i; | ||
| 118 | |||
| 119 | if (!dev || !file_ext) | ||
| 120 | return; | ||
| 121 | |||
| 122 | /* flush our queue list belong to file_ext */ | ||
| 123 | for (i = 0; i < HECI_IO_LISTS_NUMBER; i++) { | ||
| 124 | DBG("remove list entry belong to file_ext\n"); | ||
| 125 | heci_flush_list(dev->io_list_array[i], file_ext); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | |||
| 130 | /** | ||
| 131 | * heci_flush_list - remove list entry belong to file_ext. | ||
| 132 | * | ||
| 133 | * @list: An instance of our list structure | ||
| 134 | * @file_ext: private data of the file object | ||
| 135 | */ | ||
| 136 | void heci_flush_list(struct io_heci_list *list, | ||
| 137 | struct heci_file_private *file_ext) | ||
| 138 | { | ||
| 139 | struct heci_file_private *file_ext_tmp; | ||
| 140 | struct heci_cb_private *priv_cb_pos = NULL; | ||
| 141 | struct heci_cb_private *priv_cb_next = NULL; | ||
| 142 | |||
| 143 | if (!list || !file_ext) | ||
| 144 | return; | ||
| 145 | |||
| 146 | if (list->status != 0) | ||
| 147 | return; | ||
| 148 | |||
| 149 | if (list_empty(&list->heci_cb.cb_list)) | ||
| 150 | return; | ||
| 151 | |||
| 152 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 153 | &list->heci_cb.cb_list, cb_list) { | ||
| 154 | if (priv_cb_pos) { | ||
| 155 | file_ext_tmp = (struct heci_file_private *) | ||
| 156 | priv_cb_pos->file_private; | ||
| 157 | if (file_ext_tmp) { | ||
| 158 | if (heci_fe_same_id(file_ext, file_ext_tmp)) | ||
| 159 | list_del(&priv_cb_pos->cb_list); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | /** | ||
| 166 | * heci_reset_iamthif_params - initializes heci device iamthif | ||
| 167 | * | ||
| 168 | * @dev: The heci device structure | ||
| 169 | */ | ||
| 170 | static void heci_reset_iamthif_params(struct iamt_heci_device *dev) | ||
| 171 | { | ||
| 172 | /* reset iamthif parameters. */ | ||
| 173 | dev->iamthif_current_cb = NULL; | ||
| 174 | dev->iamthif_msg_buf_size = 0; | ||
| 175 | dev->iamthif_msg_buf_index = 0; | ||
| 176 | dev->iamthif_canceled = 0; | ||
| 177 | dev->iamthif_file_ext.file = NULL; | ||
| 178 | dev->iamthif_ioctl = 0; | ||
| 179 | dev->iamthif_state = HECI_IAMTHIF_IDLE; | ||
| 180 | dev->iamthif_timer = 0; | ||
| 181 | } | ||
| 182 | |||
| 183 | /** | ||
| 184 | * init_heci_device - allocates and initializes the heci device structure | ||
| 185 | * | ||
| 186 | * @pdev: The pci device structure | ||
| 187 | * | ||
| 188 | * returns The heci_device_device pointer on success, NULL on failure. | ||
| 189 | */ | ||
| 190 | struct iamt_heci_device *init_heci_device(struct pci_dev *pdev) | ||
| 191 | { | ||
| 192 | int i; | ||
| 193 | struct iamt_heci_device *dev; | ||
| 194 | |||
| 195 | dev = kzalloc(sizeof(struct iamt_heci_device), GFP_KERNEL); | ||
| 196 | if (!dev) | ||
| 197 | return NULL; | ||
| 198 | |||
| 199 | /* setup our list array */ | ||
| 200 | dev->io_list_array[0] = &dev->read_list; | ||
| 201 | dev->io_list_array[1] = &dev->write_list; | ||
| 202 | dev->io_list_array[2] = &dev->write_waiting_list; | ||
| 203 | dev->io_list_array[3] = &dev->ctrl_wr_list; | ||
| 204 | dev->io_list_array[4] = &dev->ctrl_rd_list; | ||
| 205 | dev->io_list_array[5] = &dev->pthi_cmd_list; | ||
| 206 | dev->io_list_array[6] = &dev->pthi_read_complete_list; | ||
| 207 | INIT_LIST_HEAD(&dev->file_list); | ||
| 208 | INIT_LIST_HEAD(&dev->wd_file_ext.link); | ||
| 209 | INIT_LIST_HEAD(&dev->iamthif_file_ext.link); | ||
| 210 | spin_lock_init(&dev->device_lock); | ||
| 211 | init_waitqueue_head(&dev->wait_recvd_msg); | ||
| 212 | init_waitqueue_head(&dev->wait_stop_wd); | ||
| 213 | dev->heci_state = HECI_INITIALIZING; | ||
| 214 | dev->iamthif_state = HECI_IAMTHIF_IDLE; | ||
| 215 | |||
| 216 | /* init work for schedule work */ | ||
| 217 | INIT_WORK(&dev->work, NULL); | ||
| 218 | for (i = 0; i < HECI_IO_LISTS_NUMBER; i++) | ||
| 219 | heci_initialize_list(dev->io_list_array[i], dev); | ||
| 220 | dev->pdev = pdev; | ||
| 221 | return dev; | ||
| 222 | } | ||
| 223 | |||
| 224 | |||
| 225 | |||
| 226 | |||
| 227 | static int heci_wait_event_int_timeout(struct iamt_heci_device *dev, | ||
| 228 | long timeout) | ||
| 229 | { | ||
| 230 | return wait_event_interruptible_timeout(dev->wait_recvd_msg, | ||
| 231 | (dev->recvd_msg), timeout); | ||
| 232 | } | ||
| 233 | |||
| 234 | /** | ||
| 235 | * heci_hw_init - init host and fw to start work. | ||
| 236 | * | ||
| 237 | * @dev: Device object for our driver | ||
| 238 | * | ||
| 239 | * returns 0 on success, <0 on failure. | ||
| 240 | */ | ||
| 241 | int heci_hw_init(struct iamt_heci_device *dev) | ||
| 242 | { | ||
| 243 | int err = 0; | ||
| 244 | |||
| 245 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 246 | dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); | ||
| 247 | DBG("host_hw_state = 0x%08x, mestate = 0x%08x.\n", | ||
| 248 | dev->host_hw_state, dev->me_hw_state); | ||
| 249 | |||
| 250 | if ((dev->host_hw_state & H_IS) == H_IS) { | ||
| 251 | /* acknowledge interrupt and stop interupts */ | ||
| 252 | heci_csr_clear_his(dev); | ||
| 253 | } | ||
| 254 | dev->recvd_msg = 0; | ||
| 255 | DBG("reset in start the heci device.\n"); | ||
| 256 | |||
| 257 | heci_reset(dev, 1); | ||
| 258 | |||
| 259 | DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", | ||
| 260 | dev->host_hw_state, dev->me_hw_state); | ||
| 261 | |||
| 262 | /* wait for ME to turn on ME_RDY */ | ||
| 263 | if (!dev->recvd_msg) | ||
| 264 | err = heci_wait_event_int_timeout(dev, HECI_INTEROP_TIMEOUT); | ||
| 265 | |||
| 266 | if (!err && !dev->recvd_msg) { | ||
| 267 | dev->heci_state = HECI_DISABLED; | ||
| 268 | DBG("wait_event_interruptible_timeout failed" | ||
| 269 | "on wait for ME to turn on ME_RDY.\n"); | ||
| 270 | return -ENODEV; | ||
| 271 | } else { | ||
| 272 | if (!(((dev->host_hw_state & H_RDY) == H_RDY) | ||
| 273 | && ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) { | ||
| 274 | dev->heci_state = HECI_DISABLED; | ||
| 275 | DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", | ||
| 276 | dev->host_hw_state, | ||
| 277 | dev->me_hw_state); | ||
| 278 | |||
| 279 | if (!(dev->host_hw_state & H_RDY) != H_RDY) | ||
| 280 | DBG("host turn off H_RDY.\n"); | ||
| 281 | |||
| 282 | if (!(dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) | ||
| 283 | DBG("ME turn off ME_RDY.\n"); | ||
| 284 | |||
| 285 | printk(KERN_ERR | ||
| 286 | "heci: link layer initialization failed.\n"); | ||
| 287 | return -ENODEV; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | dev->recvd_msg = 0; | ||
| 291 | DBG("host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", | ||
| 292 | dev->host_hw_state, dev->me_hw_state); | ||
| 293 | DBG("ME turn on ME_RDY and host turn on H_RDY.\n"); | ||
| 294 | printk(KERN_INFO "heci: link layer has been established.\n"); | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | /** | ||
| 299 | * heci_hw_reset - reset fw via heci csr register. | ||
| 300 | * | ||
| 301 | * @dev: Device object for our driver | ||
| 302 | * @interrupts: if interrupt should be enable after reset. | ||
| 303 | */ | ||
| 304 | static void heci_hw_reset(struct iamt_heci_device *dev, int interrupts) | ||
| 305 | { | ||
| 306 | dev->host_hw_state |= (H_RST | H_IG); | ||
| 307 | |||
| 308 | if (interrupts) | ||
| 309 | heci_csr_enable_interrupts(dev); | ||
| 310 | else | ||
| 311 | heci_csr_disable_interrupts(dev); | ||
| 312 | |||
| 313 | BUG_ON((dev->host_hw_state & H_RST) != H_RST); | ||
| 314 | BUG_ON((dev->host_hw_state & H_RDY) != 0); | ||
| 315 | } | ||
| 316 | |||
| 317 | /** | ||
| 318 | * heci_reset - reset host and fw. | ||
| 319 | * | ||
| 320 | * @dev: Device object for our driver | ||
| 321 | * @interrupts: if interrupt should be enable after reset. | ||
| 322 | */ | ||
| 323 | void heci_reset(struct iamt_heci_device *dev, int interrupts) | ||
| 324 | { | ||
| 325 | struct heci_file_private *file_pos = NULL; | ||
| 326 | struct heci_file_private *file_next = NULL; | ||
| 327 | struct heci_cb_private *priv_cb_pos = NULL; | ||
| 328 | struct heci_cb_private *priv_cb_next = NULL; | ||
| 329 | int unexpected = 0; | ||
| 330 | |||
| 331 | if (dev->heci_state == HECI_RECOVERING_FROM_RESET) { | ||
| 332 | dev->need_reset = 1; | ||
| 333 | return; | ||
| 334 | } | ||
| 335 | |||
| 336 | if (dev->heci_state != HECI_INITIALIZING && | ||
| 337 | dev->heci_state != HECI_DISABLED && | ||
| 338 | dev->heci_state != HECI_POWER_DOWN && | ||
| 339 | dev->heci_state != HECI_POWER_UP) | ||
| 340 | unexpected = 1; | ||
| 341 | |||
| 342 | if (dev->reinit_tsk != NULL) { | ||
| 343 | kthread_stop(dev->reinit_tsk); | ||
| 344 | dev->reinit_tsk = NULL; | ||
| 345 | } | ||
| 346 | |||
| 347 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 348 | |||
| 349 | DBG("before reset host_hw_state = 0x%08x.\n", | ||
| 350 | dev->host_hw_state); | ||
| 351 | |||
| 352 | heci_hw_reset(dev, interrupts); | ||
| 353 | |||
| 354 | dev->host_hw_state &= ~H_RST; | ||
| 355 | dev->host_hw_state |= H_IG; | ||
| 356 | |||
| 357 | heci_set_csr_register(dev); | ||
| 358 | |||
| 359 | DBG("currently saved host_hw_state = 0x%08x.\n", | ||
| 360 | dev->host_hw_state); | ||
| 361 | |||
| 362 | dev->need_reset = 0; | ||
| 363 | |||
| 364 | if (dev->heci_state != HECI_INITIALIZING) { | ||
| 365 | if ((dev->heci_state != HECI_DISABLED) && | ||
| 366 | (dev->heci_state != HECI_POWER_DOWN)) | ||
| 367 | dev->heci_state = HECI_RESETING; | ||
| 368 | |||
| 369 | list_for_each_entry_safe(file_pos, | ||
| 370 | file_next, &dev->file_list, link) { | ||
| 371 | file_pos->state = HECI_FILE_DISCONNECTED; | ||
| 372 | file_pos->flow_ctrl_creds = 0; | ||
| 373 | file_pos->read_cb = NULL; | ||
| 374 | file_pos->timer_count = 0; | ||
| 375 | } | ||
| 376 | /* remove entry if already in list */ | ||
| 377 | DBG("list del iamthif and wd file list.\n"); | ||
| 378 | heci_remove_client_from_file_list(dev, | ||
| 379 | dev->wd_file_ext.host_client_id); | ||
| 380 | |||
| 381 | heci_remove_client_from_file_list(dev, | ||
| 382 | dev->iamthif_file_ext.host_client_id); | ||
| 383 | |||
| 384 | heci_reset_iamthif_params(dev); | ||
| 385 | dev->wd_due_counter = 0; | ||
| 386 | dev->extra_write_index = 0; | ||
| 387 | } | ||
| 388 | |||
| 389 | dev->num_heci_me_clients = 0; | ||
| 390 | dev->rd_msg_hdr = 0; | ||
| 391 | dev->stop = 0; | ||
| 392 | dev->wd_pending = 0; | ||
| 393 | |||
| 394 | /* update the state of the registers after reset */ | ||
| 395 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 396 | dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); | ||
| 397 | |||
| 398 | DBG("after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n", | ||
| 399 | dev->host_hw_state, dev->me_hw_state); | ||
| 400 | |||
| 401 | if (unexpected) | ||
| 402 | printk(KERN_WARNING "heci: unexpected reset.\n"); | ||
| 403 | |||
| 404 | /* Wake up all readings so they can be interrupted */ | ||
| 405 | list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) { | ||
| 406 | if (&file_pos->rx_wait && | ||
| 407 | waitqueue_active(&file_pos->rx_wait)) { | ||
| 408 | printk(KERN_INFO "heci: Waking up client!\n"); | ||
| 409 | wake_up_interruptible(&file_pos->rx_wait); | ||
| 410 | } | ||
| 411 | } | ||
| 412 | /* remove all waiting requests */ | ||
| 413 | if (dev->write_list.status == 0 && | ||
| 414 | !list_empty(&dev->write_list.heci_cb.cb_list)) { | ||
| 415 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 416 | &dev->write_list.heci_cb.cb_list, cb_list) { | ||
| 417 | if (priv_cb_pos) { | ||
| 418 | list_del(&priv_cb_pos->cb_list); | ||
| 419 | heci_free_cb_private(priv_cb_pos); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | /** | ||
| 426 | * heci_initialize_clients - heci communication initialization. | ||
| 427 | * | ||
| 428 | * @dev: Device object for our driver | ||
| 429 | */ | ||
| 430 | int heci_initialize_clients(struct iamt_heci_device *dev) | ||
| 431 | { | ||
| 432 | int status; | ||
| 433 | |||
| 434 | msleep(100); /* FW needs time to be ready to talk with us */ | ||
| 435 | DBG("link is established start sending messages.\n"); | ||
| 436 | /* link is established start sending messages. */ | ||
| 437 | status = host_start_message(dev); | ||
| 438 | if (status != 0) { | ||
| 439 | spin_lock_bh(&dev->device_lock); | ||
| 440 | dev->heci_state = HECI_DISABLED; | ||
| 441 | spin_unlock_bh(&dev->device_lock); | ||
| 442 | DBG("start sending messages failed.\n"); | ||
| 443 | return status; | ||
| 444 | } | ||
| 445 | |||
| 446 | /* enumerate clients */ | ||
| 447 | status = host_enum_clients_message(dev); | ||
| 448 | if (status != 0) { | ||
| 449 | spin_lock_bh(&dev->device_lock); | ||
| 450 | dev->heci_state = HECI_DISABLED; | ||
| 451 | spin_unlock_bh(&dev->device_lock); | ||
| 452 | DBG("enum clients failed.\n"); | ||
| 453 | return status; | ||
| 454 | } | ||
| 455 | /* allocate storage for ME clients representation */ | ||
| 456 | status = allocate_me_clients_storage(dev); | ||
| 457 | if (status != 0) { | ||
| 458 | spin_lock_bh(&dev->device_lock); | ||
| 459 | dev->num_heci_me_clients = 0; | ||
| 460 | dev->heci_state = HECI_DISABLED; | ||
| 461 | spin_unlock_bh(&dev->device_lock); | ||
| 462 | DBG("allocate clients failed.\n"); | ||
| 463 | return status; | ||
| 464 | } | ||
| 465 | |||
| 466 | heci_check_asf_mode(dev); | ||
| 467 | /*heci initialization wd */ | ||
| 468 | host_init_wd(dev); | ||
| 469 | /*heci initialization iamthif client */ | ||
| 470 | host_init_iamthif(dev); | ||
| 471 | |||
| 472 | spin_lock_bh(&dev->device_lock); | ||
| 473 | if (dev->need_reset) { | ||
| 474 | dev->need_reset = 0; | ||
| 475 | dev->heci_state = HECI_DISABLED; | ||
| 476 | spin_unlock_bh(&dev->device_lock); | ||
| 477 | return -ENODEV; | ||
| 478 | } | ||
| 479 | |||
| 480 | memset(dev->heci_host_clients, 0, sizeof(dev->heci_host_clients)); | ||
| 481 | dev->open_handle_count = 0; | ||
| 482 | dev->heci_host_clients[0] |= 7; | ||
| 483 | dev->current_host_client_id = 3; | ||
| 484 | dev->heci_state = HECI_ENABLED; | ||
| 485 | spin_unlock_bh(&dev->device_lock); | ||
| 486 | DBG("initialization heci clients successful.\n"); | ||
| 487 | return 0; | ||
| 488 | } | ||
| 489 | |||
| 490 | /** | ||
| 491 | * heci_task_initialize_clients - heci reinitialization task | ||
| 492 | * | ||
| 493 | * @data: Device object for our driver | ||
| 494 | */ | ||
| 495 | int heci_task_initialize_clients(void *data) | ||
| 496 | { | ||
| 497 | int ret; | ||
| 498 | struct iamt_heci_device *dev = (struct iamt_heci_device *) data; | ||
| 499 | |||
| 500 | spin_lock_bh(&dev->device_lock); | ||
| 501 | if (dev->reinit_tsk != NULL) { | ||
| 502 | spin_unlock_bh(&dev->device_lock); | ||
| 503 | DBG("reinit task already started.\n"); | ||
| 504 | return 0; | ||
| 505 | } | ||
| 506 | dev->reinit_tsk = current; | ||
| 507 | current->flags |= PF_NOFREEZE; | ||
| 508 | spin_unlock_bh(&dev->device_lock); | ||
| 509 | |||
| 510 | ret = heci_initialize_clients(dev); | ||
| 511 | |||
| 512 | spin_lock_bh(&dev->device_lock); | ||
| 513 | dev->reinit_tsk = NULL; | ||
| 514 | spin_unlock_bh(&dev->device_lock); | ||
| 515 | |||
| 516 | return ret; | ||
| 517 | } | ||
| 518 | |||
| 519 | /** | ||
| 520 | * host_start_message - heci host send start message. | ||
| 521 | * | ||
| 522 | * @dev: Device object for our driver | ||
| 523 | * | ||
| 524 | * returns 0 on success, <0 on failure. | ||
| 525 | */ | ||
| 526 | static int host_start_message(struct iamt_heci_device *dev) | ||
| 527 | { | ||
| 528 | long timeout = 60; /* 60 second */ | ||
| 529 | |||
| 530 | struct heci_msg_hdr *heci_hdr; | ||
| 531 | struct hbm_host_version_request *host_start_req; | ||
| 532 | struct hbm_host_stop_request *host_stop_req; | ||
| 533 | int err = 0; | ||
| 534 | |||
| 535 | /* host start message */ | ||
| 536 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 537 | heci_hdr->host_addr = 0; | ||
| 538 | heci_hdr->me_addr = 0; | ||
| 539 | heci_hdr->length = sizeof(struct hbm_host_version_request); | ||
| 540 | heci_hdr->msg_complete = 1; | ||
| 541 | heci_hdr->reserved = 0; | ||
| 542 | |||
| 543 | host_start_req = | ||
| 544 | (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; | ||
| 545 | memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); | ||
| 546 | host_start_req->cmd.cmd = HOST_START_REQ_CMD; | ||
| 547 | host_start_req->host_version.major_version = HBM_MAJOR_VERSION; | ||
| 548 | host_start_req->host_version.minor_version = HBM_MINOR_VERSION; | ||
| 549 | dev->recvd_msg = 0; | ||
| 550 | if (!heci_write_message(dev, heci_hdr, | ||
| 551 | (unsigned char *) (host_start_req), | ||
| 552 | heci_hdr->length)) { | ||
| 553 | DBG("send version to fw fail.\n"); | ||
| 554 | return -ENODEV; | ||
| 555 | } | ||
| 556 | DBG("call wait_event_interruptible_timeout for response message.\n"); | ||
| 557 | /* wait for response */ | ||
| 558 | err = heci_wait_event_int_timeout(dev, timeout * HZ); | ||
| 559 | if (!err && !dev->recvd_msg) { | ||
| 560 | DBG("wait_timeout failed on host start response message.\n"); | ||
| 561 | return -ENODEV; | ||
| 562 | } | ||
| 563 | dev->recvd_msg = 0; | ||
| 564 | DBG("wait_timeout successful on host start response message.\n"); | ||
| 565 | if ((dev->version.major_version != HBM_MAJOR_VERSION) || | ||
| 566 | (dev->version.minor_version != HBM_MINOR_VERSION)) { | ||
| 567 | /* send stop message */ | ||
| 568 | heci_hdr->host_addr = 0; | ||
| 569 | heci_hdr->me_addr = 0; | ||
| 570 | heci_hdr->length = sizeof(struct hbm_host_stop_request); | ||
| 571 | heci_hdr->msg_complete = 1; | ||
| 572 | heci_hdr->reserved = 0; | ||
| 573 | |||
| 574 | host_stop_req = | ||
| 575 | (struct hbm_host_stop_request *) &dev->wr_msg_buf[1]; | ||
| 576 | |||
| 577 | memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request)); | ||
| 578 | host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD; | ||
| 579 | host_stop_req->reason = DRIVER_STOP_REQUEST; | ||
| 580 | heci_write_message(dev, heci_hdr, | ||
| 581 | (unsigned char *) (host_stop_req), | ||
| 582 | heci_hdr->length); | ||
| 583 | DBG("version mismatch.\n"); | ||
| 584 | return -ENODEV; | ||
| 585 | } | ||
| 586 | |||
| 587 | return 0; | ||
| 588 | } | ||
| 589 | |||
| 590 | /** | ||
| 591 | * host_enum_clients_message - host send enumeration client request message. | ||
| 592 | * | ||
| 593 | * @dev: Device object for our driver | ||
| 594 | * | ||
| 595 | * returns 0 on success, <0 on failure. | ||
| 596 | */ | ||
| 597 | static int host_enum_clients_message(struct iamt_heci_device *dev) | ||
| 598 | { | ||
| 599 | long timeout = 5; /*5 second */ | ||
| 600 | struct heci_msg_hdr *heci_hdr; | ||
| 601 | struct hbm_host_enum_request *host_enum_req; | ||
| 602 | int err = 0; | ||
| 603 | int i, j; | ||
| 604 | |||
| 605 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 606 | /* enumerate clients */ | ||
| 607 | heci_hdr->host_addr = 0; | ||
| 608 | heci_hdr->me_addr = 0; | ||
| 609 | heci_hdr->length = sizeof(struct hbm_host_enum_request); | ||
| 610 | heci_hdr->msg_complete = 1; | ||
| 611 | heci_hdr->reserved = 0; | ||
| 612 | |||
| 613 | host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; | ||
| 614 | memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); | ||
| 615 | host_enum_req->cmd.cmd = HOST_ENUM_REQ_CMD; | ||
| 616 | if (!heci_write_message(dev, heci_hdr, | ||
| 617 | (unsigned char *) (host_enum_req), | ||
| 618 | heci_hdr->length)) { | ||
| 619 | DBG("send enumeration request failed.\n"); | ||
| 620 | return -ENODEV; | ||
| 621 | } | ||
| 622 | /* wait for response */ | ||
| 623 | dev->recvd_msg = 0; | ||
| 624 | err = heci_wait_event_int_timeout(dev, timeout * HZ); | ||
| 625 | if (!err && !dev->recvd_msg) { | ||
| 626 | DBG("wait_event_interruptible_timeout failed " | ||
| 627 | "on enumeration clients response message.\n"); | ||
| 628 | return -ENODEV; | ||
| 629 | } | ||
| 630 | dev->recvd_msg = 0; | ||
| 631 | |||
| 632 | spin_lock_bh(&dev->device_lock); | ||
| 633 | /* count how many ME clients we have */ | ||
| 634 | for (i = 0; i < sizeof(dev->heci_me_clients); i++) { | ||
| 635 | for (j = 0; j < 8; j++) { | ||
| 636 | if ((dev->heci_me_clients[i] & (1 << j)) != 0) | ||
| 637 | dev->num_heci_me_clients++; | ||
| 638 | |||
| 639 | } | ||
| 640 | } | ||
| 641 | spin_unlock_bh(&dev->device_lock); | ||
| 642 | |||
| 643 | return 0; | ||
| 644 | } | ||
| 645 | |||
| 646 | /** | ||
| 647 | * host_client_properties - reads properties for client | ||
| 648 | * | ||
| 649 | * @dev: Device object for our driver | ||
| 650 | * @idx: client index in me client array | ||
| 651 | * @client_id: id of the client | ||
| 652 | * | ||
| 653 | * returns 0 on success, <0 on failure. | ||
| 654 | */ | ||
| 655 | static int host_client_properties(struct iamt_heci_device *dev, | ||
| 656 | struct heci_me_client *client) | ||
| 657 | { | ||
| 658 | struct heci_msg_hdr *heci_hdr; | ||
| 659 | struct hbm_props_request *host_cli_req; | ||
| 660 | int err; | ||
| 661 | |||
| 662 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 663 | heci_hdr->host_addr = 0; | ||
| 664 | heci_hdr->me_addr = 0; | ||
| 665 | heci_hdr->length = sizeof(struct hbm_props_request); | ||
| 666 | heci_hdr->msg_complete = 1; | ||
| 667 | heci_hdr->reserved = 0; | ||
| 668 | |||
| 669 | host_cli_req = (struct hbm_props_request *) &dev->wr_msg_buf[1]; | ||
| 670 | memset(host_cli_req, 0, sizeof(struct hbm_props_request)); | ||
| 671 | host_cli_req->cmd.cmd = HOST_CLIENT_PROPERTEIS_REQ_CMD; | ||
| 672 | host_cli_req->address = client->client_id; | ||
| 673 | if (!heci_write_message(dev, heci_hdr, | ||
| 674 | (unsigned char *) (host_cli_req), | ||
| 675 | heci_hdr->length)) { | ||
| 676 | DBG("send props request failed.\n"); | ||
| 677 | return -ENODEV; | ||
| 678 | } | ||
| 679 | /* wait for response */ | ||
| 680 | dev->recvd_msg = 0; | ||
| 681 | err = heci_wait_event_int_timeout(dev, 10 * HZ); | ||
| 682 | if (!err && !dev->recvd_msg) { | ||
| 683 | DBG("wait failed on props resp msg.\n"); | ||
| 684 | return -ENODEV; | ||
| 685 | } | ||
| 686 | dev->recvd_msg = 0; | ||
| 687 | return 0; | ||
| 688 | } | ||
| 689 | |||
| 690 | /** | ||
| 691 | * allocate_me_clients_storage - allocate storage for me clients | ||
| 692 | * | ||
| 693 | * @dev: Device object for our driver | ||
| 694 | * | ||
| 695 | * returns 0 on success, <0 on failure. | ||
| 696 | */ | ||
| 697 | static int allocate_me_clients_storage(struct iamt_heci_device *dev) | ||
| 698 | { | ||
| 699 | struct heci_me_client *clients; | ||
| 700 | struct heci_me_client *client; | ||
| 701 | __u8 num, i, j; | ||
| 702 | int err; | ||
| 703 | |||
| 704 | if (dev->num_heci_me_clients <= 0) | ||
| 705 | return 0; | ||
| 706 | |||
| 707 | spin_lock_bh(&dev->device_lock); | ||
| 708 | kfree(dev->me_clients); | ||
| 709 | dev->me_clients = NULL; | ||
| 710 | spin_unlock_bh(&dev->device_lock); | ||
| 711 | |||
| 712 | /* allocate storage for ME clients representation */ | ||
| 713 | clients = kcalloc(dev->num_heci_me_clients, | ||
| 714 | sizeof(struct heci_me_client), GFP_KERNEL); | ||
| 715 | if (!clients) { | ||
| 716 | DBG("memory allocation for ME clients failed.\n"); | ||
| 717 | return -ENOMEM; | ||
| 718 | } | ||
| 719 | |||
| 720 | spin_lock_bh(&dev->device_lock); | ||
| 721 | dev->me_clients = clients; | ||
| 722 | spin_unlock_bh(&dev->device_lock); | ||
| 723 | |||
| 724 | num = 0; | ||
| 725 | for (i = 0; i < sizeof(dev->heci_me_clients); i++) { | ||
| 726 | for (j = 0; j < 8; j++) { | ||
| 727 | if ((dev->heci_me_clients[i] & (1 << j)) != 0) { | ||
| 728 | client = &dev->me_clients[num]; | ||
| 729 | client->client_id = (i * 8) + j; | ||
| 730 | client->flow_ctrl_creds = 0; | ||
| 731 | err = host_client_properties(dev, client); | ||
| 732 | if (err != 0) { | ||
| 733 | spin_lock_bh(&dev->device_lock); | ||
| 734 | kfree(dev->me_clients); | ||
| 735 | dev->me_clients = NULL; | ||
| 736 | spin_unlock_bh(&dev->device_lock); | ||
| 737 | return err; | ||
| 738 | } | ||
| 739 | num++; | ||
| 740 | } | ||
| 741 | } | ||
| 742 | } | ||
| 743 | |||
| 744 | return 0; | ||
| 745 | } | ||
| 746 | |||
| 747 | /** | ||
| 748 | * heci_init_file_private - initializes private file structure. | ||
| 749 | * | ||
| 750 | * @priv: private file structure to be initialized | ||
| 751 | * @file: the file structure | ||
| 752 | */ | ||
| 753 | static void heci_init_file_private(struct heci_file_private *priv, | ||
| 754 | struct file *file) | ||
| 755 | { | ||
| 756 | memset(priv, 0, sizeof(struct heci_file_private)); | ||
| 757 | spin_lock_init(&priv->file_lock); | ||
| 758 | spin_lock_init(&priv->read_io_lock); | ||
| 759 | spin_lock_init(&priv->write_io_lock); | ||
| 760 | init_waitqueue_head(&priv->wait); | ||
| 761 | init_waitqueue_head(&priv->rx_wait); | ||
| 762 | DBG("priv->rx_wait =%p\n", &priv->rx_wait); | ||
| 763 | init_waitqueue_head(&priv->tx_wait); | ||
| 764 | INIT_LIST_HEAD(&priv->link); | ||
| 765 | priv->reading_state = HECI_IDLE; | ||
| 766 | priv->writing_state = HECI_IDLE; | ||
| 767 | } | ||
| 768 | |||
| 769 | /** | ||
| 770 | * heci_find_me_client - search for ME client guid | ||
| 771 | * sets client_id in heci_file_private if found | ||
| 772 | * @dev: Device object for our driver | ||
| 773 | * @priv: private file structure to set client_id in | ||
| 774 | * @cguid: searched guid of ME client | ||
| 775 | * @client_id: id of host client to be set in file private structure | ||
| 776 | * | ||
| 777 | * returns ME client index | ||
| 778 | */ | ||
| 779 | static __u8 heci_find_me_client(struct iamt_heci_device *dev, | ||
| 780 | struct heci_file_private *priv, | ||
| 781 | const struct guid *cguid, __u8 client_id) | ||
| 782 | { | ||
| 783 | __u8 i; | ||
| 784 | |||
| 785 | if ((dev == NULL) || (priv == NULL) || (cguid == NULL)) | ||
| 786 | return 0; | ||
| 787 | |||
| 788 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 789 | if (memcmp(cguid, | ||
| 790 | &dev->me_clients[i].props.protocol_name, | ||
| 791 | sizeof(struct guid)) == 0) { | ||
| 792 | priv->me_client_id = dev->me_clients[i].client_id; | ||
| 793 | priv->state = HECI_FILE_CONNECTING; | ||
| 794 | priv->host_client_id = client_id; | ||
| 795 | |||
| 796 | list_add_tail(&priv->link, &dev->file_list); | ||
| 797 | return i; | ||
| 798 | } | ||
| 799 | } | ||
| 800 | return 0; | ||
| 801 | } | ||
| 802 | |||
| 803 | /** | ||
| 804 | * heci_check_asf_mode - check for ASF client | ||
| 805 | * | ||
| 806 | * @dev: Device object for our driver | ||
| 807 | */ | ||
| 808 | static void heci_check_asf_mode(struct iamt_heci_device *dev) | ||
| 809 | { | ||
| 810 | __u8 i; | ||
| 811 | |||
| 812 | spin_lock_bh(&dev->device_lock); | ||
| 813 | dev->asf_mode = 0; | ||
| 814 | /* find ME ASF client - otherwise assume AMT mode */ | ||
| 815 | DBG("find ME ASF client - otherwise assume AMT mode.\n"); | ||
| 816 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 817 | if (memcmp(&heci_asf_guid, | ||
| 818 | &dev->me_clients[i].props.protocol_name, | ||
| 819 | sizeof(struct guid)) == 0) { | ||
| 820 | dev->asf_mode = 1; | ||
| 821 | spin_unlock_bh(&dev->device_lock); | ||
| 822 | DBG("found ME ASF client.\n"); | ||
| 823 | return; | ||
| 824 | } | ||
| 825 | } | ||
| 826 | spin_unlock_bh(&dev->device_lock); | ||
| 827 | DBG("assume AMT mode.\n"); | ||
| 828 | } | ||
| 829 | |||
| 830 | /** | ||
| 831 | * heci_connect_me_client - connect ME client | ||
| 832 | * @dev: Device object for our driver | ||
| 833 | * @priv: private file structure | ||
| 834 | * @timeout: connect timeout in seconds | ||
| 835 | * | ||
| 836 | * returns 1 - if connected, 0 - if not | ||
| 837 | */ | ||
| 838 | static __u8 heci_connect_me_client(struct iamt_heci_device *dev, | ||
| 839 | struct heci_file_private *priv, | ||
| 840 | long timeout) | ||
| 841 | { | ||
| 842 | int err = 0; | ||
| 843 | |||
| 844 | if ((dev == NULL) || (priv == NULL)) | ||
| 845 | return 0; | ||
| 846 | |||
| 847 | if (!heci_connect(dev, priv)) { | ||
| 848 | DBG("failed to call heci_connect for client_id=%d.\n", | ||
| 849 | priv->host_client_id); | ||
| 850 | spin_lock_bh(&dev->device_lock); | ||
| 851 | heci_remove_client_from_file_list(dev, priv->host_client_id); | ||
| 852 | priv->state = HECI_FILE_DISCONNECTED; | ||
| 853 | spin_unlock_bh(&dev->device_lock); | ||
| 854 | return 0; | ||
| 855 | } | ||
| 856 | |||
| 857 | err = wait_event_timeout(dev->wait_recvd_msg, | ||
| 858 | (HECI_FILE_CONNECTED == priv->state || | ||
| 859 | HECI_FILE_DISCONNECTED == priv->state), | ||
| 860 | timeout * HZ); | ||
| 861 | if (HECI_FILE_CONNECTED != priv->state) { | ||
| 862 | spin_lock_bh(&dev->device_lock); | ||
| 863 | heci_remove_client_from_file_list(dev, priv->host_client_id); | ||
| 864 | DBG("failed to connect client_id=%d state=%d.\n", | ||
| 865 | priv->host_client_id, priv->state); | ||
| 866 | if (err) | ||
| 867 | DBG("failed connect err=%08x\n", err); | ||
| 868 | priv->state = HECI_FILE_DISCONNECTED; | ||
| 869 | spin_unlock_bh(&dev->device_lock); | ||
| 870 | return 0; | ||
| 871 | } | ||
| 872 | DBG("successfully connected client_id=%d.\n", | ||
| 873 | priv->host_client_id); | ||
| 874 | return 1; | ||
| 875 | } | ||
| 876 | |||
| 877 | /** | ||
| 878 | * host_init_wd - heci initialization wd. | ||
| 879 | * | ||
| 880 | * @dev: Device object for our driver | ||
| 881 | */ | ||
| 882 | static void host_init_wd(struct iamt_heci_device *dev) | ||
| 883 | { | ||
| 884 | spin_lock_bh(&dev->device_lock); | ||
| 885 | |||
| 886 | heci_init_file_private(&dev->wd_file_ext, NULL); | ||
| 887 | |||
| 888 | /* look for WD client and connect to it */ | ||
| 889 | dev->wd_file_ext.state = HECI_FILE_DISCONNECTED; | ||
| 890 | dev->wd_timeout = 0; | ||
| 891 | |||
| 892 | if (dev->asf_mode) { | ||
| 893 | memcpy(dev->wd_data, heci_stop_wd_params, HECI_WD_PARAMS_SIZE); | ||
| 894 | } else { | ||
| 895 | /* AMT mode */ | ||
| 896 | dev->wd_timeout = AMT_WD_VALUE; | ||
| 897 | DBG("dev->wd_timeout=%d.\n", dev->wd_timeout); | ||
| 898 | memcpy(dev->wd_data, heci_start_wd_params, HECI_WD_PARAMS_SIZE); | ||
| 899 | memcpy(dev->wd_data + HECI_WD_PARAMS_SIZE, | ||
| 900 | &dev->wd_timeout, sizeof(__u16)); | ||
| 901 | } | ||
| 902 | |||
| 903 | /* find ME WD client */ | ||
| 904 | heci_find_me_client(dev, &dev->wd_file_ext, | ||
| 905 | &heci_wd_guid, HECI_WD_HOST_CLIENT_ID); | ||
| 906 | spin_unlock_bh(&dev->device_lock); | ||
| 907 | |||
| 908 | DBG("check wd_file_ext\n"); | ||
| 909 | if (HECI_FILE_CONNECTING == dev->wd_file_ext.state) { | ||
| 910 | if (heci_connect_me_client(dev, &dev->wd_file_ext, 15) == 1) { | ||
| 911 | DBG("dev->wd_timeout=%d.\n", dev->wd_timeout); | ||
| 912 | if (dev->wd_timeout != 0) | ||
| 913 | dev->wd_due_counter = 1; | ||
| 914 | else | ||
| 915 | dev->wd_due_counter = 0; | ||
| 916 | DBG("successfully connected to WD client.\n"); | ||
| 917 | } | ||
| 918 | } else | ||
| 919 | DBG("failed to find WD client.\n"); | ||
| 920 | |||
| 921 | |||
| 922 | spin_lock_bh(&dev->device_lock); | ||
| 923 | dev->wd_timer.function = &heci_wd_timer; | ||
| 924 | dev->wd_timer.data = (unsigned long) dev; | ||
| 925 | spin_unlock_bh(&dev->device_lock); | ||
| 926 | } | ||
| 927 | |||
| 928 | |||
| 929 | /** | ||
| 930 | * host_init_iamthif - heci initialization iamthif client. | ||
| 931 | * | ||
| 932 | * @dev: Device object for our driver | ||
| 933 | * | ||
| 934 | */ | ||
| 935 | static void host_init_iamthif(struct iamt_heci_device *dev) | ||
| 936 | { | ||
| 937 | __u8 i; | ||
| 938 | |||
| 939 | spin_lock_bh(&dev->device_lock); | ||
| 940 | |||
| 941 | heci_init_file_private(&dev->iamthif_file_ext, NULL); | ||
| 942 | dev->iamthif_file_ext.state = HECI_FILE_DISCONNECTED; | ||
| 943 | |||
| 944 | /* find ME PTHI client */ | ||
| 945 | i = heci_find_me_client(dev, &dev->iamthif_file_ext, | ||
| 946 | &heci_pthi_guid, HECI_IAMTHIF_HOST_CLIENT_ID); | ||
| 947 | if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTING) { | ||
| 948 | DBG("failed to find iamthif client.\n"); | ||
| 949 | spin_unlock_bh(&dev->device_lock); | ||
| 950 | return; | ||
| 951 | } | ||
| 952 | |||
| 953 | BUG_ON(dev->me_clients[i].props.max_msg_length != IAMTHIF_MTU); | ||
| 954 | |||
| 955 | spin_unlock_bh(&dev->device_lock); | ||
| 956 | if (heci_connect_me_client(dev, &dev->iamthif_file_ext, 15) == 1) { | ||
| 957 | DBG("connected to iamthif client.\n"); | ||
| 958 | dev->iamthif_state = HECI_IAMTHIF_IDLE; | ||
| 959 | } | ||
| 960 | } | ||
| 961 | |||
| 962 | /** | ||
| 963 | * heci_alloc_file_private - allocates a private file structure and set it up. | ||
| 964 | * @file: the file structure | ||
| 965 | * | ||
| 966 | * returns The allocated file or NULL on failure | ||
| 967 | */ | ||
| 968 | struct heci_file_private *heci_alloc_file_private(struct file *file) | ||
| 969 | { | ||
| 970 | struct heci_file_private *priv; | ||
| 971 | |||
| 972 | priv = kmalloc(sizeof(struct heci_file_private), GFP_KERNEL); | ||
| 973 | if (!priv) | ||
| 974 | return NULL; | ||
| 975 | |||
| 976 | heci_init_file_private(priv, file); | ||
| 977 | |||
| 978 | return priv; | ||
| 979 | } | ||
| 980 | |||
| 981 | |||
| 982 | |||
| 983 | /** | ||
| 984 | * heci_disconnect_host_client - send disconnect message to fw from host client. | ||
| 985 | * | ||
| 986 | * @dev: Device object for our driver | ||
| 987 | * @file_ext: private data of the file object | ||
| 988 | * | ||
| 989 | * returns 0 on success, <0 on failure. | ||
| 990 | */ | ||
| 991 | int heci_disconnect_host_client(struct iamt_heci_device *dev, | ||
| 992 | struct heci_file_private *file_ext) | ||
| 993 | { | ||
| 994 | int rets, err; | ||
| 995 | long timeout = 15; /* 15 seconds */ | ||
| 996 | struct heci_cb_private *priv_cb; | ||
| 997 | |||
| 998 | if ((!dev) || (!file_ext)) | ||
| 999 | return -ENODEV; | ||
| 1000 | |||
| 1001 | spin_lock_bh(&dev->device_lock); | ||
| 1002 | if (file_ext->state != HECI_FILE_DISCONNECTING) { | ||
| 1003 | spin_unlock_bh(&dev->device_lock); | ||
| 1004 | return 0; | ||
| 1005 | } | ||
| 1006 | spin_unlock_bh(&dev->device_lock); | ||
| 1007 | |||
| 1008 | priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL); | ||
| 1009 | if (!priv_cb) | ||
| 1010 | return -ENOMEM; | ||
| 1011 | |||
| 1012 | INIT_LIST_HEAD(&priv_cb->cb_list); | ||
| 1013 | priv_cb->file_private = file_ext; | ||
| 1014 | priv_cb->major_file_operations = HECI_CLOSE; | ||
| 1015 | spin_lock_bh(&dev->device_lock); | ||
| 1016 | if (dev->host_buffer_is_empty) { | ||
| 1017 | dev->host_buffer_is_empty = 0; | ||
| 1018 | if (heci_disconnect(dev, file_ext)) { | ||
| 1019 | mdelay(10); /* Wait for hardware disconnection ready */ | ||
| 1020 | list_add_tail(&priv_cb->cb_list, | ||
| 1021 | &dev->ctrl_rd_list.heci_cb.cb_list); | ||
| 1022 | } else { | ||
| 1023 | spin_unlock_bh(&dev->device_lock); | ||
| 1024 | rets = -ENODEV; | ||
| 1025 | DBG("failed to call heci_disconnect.\n"); | ||
| 1026 | goto free; | ||
| 1027 | } | ||
| 1028 | } else { | ||
| 1029 | DBG("add disconnect cb to control write list\n"); | ||
| 1030 | list_add_tail(&priv_cb->cb_list, | ||
| 1031 | &dev->ctrl_wr_list.heci_cb.cb_list); | ||
| 1032 | } | ||
| 1033 | spin_unlock_bh(&dev->device_lock); | ||
| 1034 | |||
| 1035 | err = wait_event_timeout(dev->wait_recvd_msg, | ||
| 1036 | (HECI_FILE_DISCONNECTED == file_ext->state), | ||
| 1037 | timeout * HZ); | ||
| 1038 | |||
| 1039 | spin_lock_bh(&dev->device_lock); | ||
| 1040 | if (HECI_FILE_DISCONNECTED == file_ext->state) { | ||
| 1041 | rets = 0; | ||
| 1042 | DBG("successfully disconnected from fw client.\n"); | ||
| 1043 | } else { | ||
| 1044 | rets = -ENODEV; | ||
| 1045 | if (HECI_FILE_DISCONNECTED != file_ext->state) | ||
| 1046 | DBG("wrong status client disconnect.\n"); | ||
| 1047 | |||
| 1048 | if (err) | ||
| 1049 | DBG("wait failed disconnect err=%08x\n", err); | ||
| 1050 | |||
| 1051 | DBG("failed to disconnect from fw client.\n"); | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | heci_flush_list(&dev->ctrl_rd_list, file_ext); | ||
| 1055 | heci_flush_list(&dev->ctrl_wr_list, file_ext); | ||
| 1056 | spin_unlock_bh(&dev->device_lock); | ||
| 1057 | free: | ||
| 1058 | heci_free_cb_private(priv_cb); | ||
| 1059 | return rets; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | /** | ||
| 1063 | * heci_remove_client_from_file_list - | ||
| 1064 | * remove file private data from device file list | ||
| 1065 | * | ||
| 1066 | * @dev: Device object for our driver | ||
| 1067 | * @host_client_id: host client id to be removed | ||
| 1068 | */ | ||
| 1069 | void heci_remove_client_from_file_list(struct iamt_heci_device *dev, | ||
| 1070 | __u8 host_client_id) | ||
| 1071 | { | ||
| 1072 | struct heci_file_private *file_pos = NULL; | ||
| 1073 | struct heci_file_private *file_next = NULL; | ||
| 1074 | list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) { | ||
| 1075 | if (host_client_id == file_pos->host_client_id) { | ||
| 1076 | DBG("remove host client = %d, ME client = %d\n", | ||
| 1077 | file_pos->host_client_id, | ||
| 1078 | file_pos->me_client_id); | ||
| 1079 | list_del_init(&file_pos->link); | ||
| 1080 | break; | ||
| 1081 | } | ||
| 1082 | } | ||
| 1083 | } | ||
diff --git a/drivers/staging/heci/heci_interface.c b/drivers/staging/heci/heci_interface.c deleted file mode 100644 index 03e1df1a88a0..000000000000 --- a/drivers/staging/heci/heci_interface.c +++ /dev/null | |||
| @@ -1,498 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | |||
| 42 | #include "heci.h" | ||
| 43 | #include "heci_interface.h" | ||
| 44 | |||
| 45 | |||
| 46 | /** | ||
| 47 | * heci_set_csr_register - write H_CSR register to the heci device, | ||
| 48 | * and ignore the H_IS bit for it is write-one-to-zero. | ||
| 49 | * | ||
| 50 | * @dev: device object for our driver | ||
| 51 | */ | ||
| 52 | void heci_set_csr_register(struct iamt_heci_device *dev) | ||
| 53 | { | ||
| 54 | if ((dev->host_hw_state & H_IS) == H_IS) | ||
| 55 | dev->host_hw_state &= ~H_IS; | ||
| 56 | write_heci_register(dev, H_CSR, dev->host_hw_state); | ||
| 57 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * heci_csr_enable_interrupts - enable heci device interrupts | ||
| 62 | * | ||
| 63 | * @dev: device object for our driver | ||
| 64 | */ | ||
| 65 | void heci_csr_enable_interrupts(struct iamt_heci_device *dev) | ||
| 66 | { | ||
| 67 | dev->host_hw_state |= H_IE; | ||
| 68 | heci_set_csr_register(dev); | ||
| 69 | } | ||
| 70 | |||
| 71 | /** | ||
| 72 | * heci_csr_disable_interrupts - disable heci device interrupts | ||
| 73 | * | ||
| 74 | * @dev: device object for our driver | ||
| 75 | */ | ||
| 76 | void heci_csr_disable_interrupts(struct iamt_heci_device *dev) | ||
| 77 | { | ||
| 78 | dev->host_hw_state &= ~H_IE; | ||
| 79 | heci_set_csr_register(dev); | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * heci_csr_clear_his - clear H_IS bit in H_CSR | ||
| 84 | * | ||
| 85 | * @dev: device object for our driver | ||
| 86 | */ | ||
| 87 | void heci_csr_clear_his(struct iamt_heci_device *dev) | ||
| 88 | { | ||
| 89 | write_heci_register(dev, H_CSR, dev->host_hw_state); | ||
| 90 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 91 | } | ||
| 92 | |||
| 93 | /** | ||
| 94 | * _host_get_filled_slots - get number of device filled buffer slots | ||
| 95 | * | ||
| 96 | * @device: the device structure | ||
| 97 | * | ||
| 98 | * returns numer of filled slots | ||
| 99 | */ | ||
| 100 | static unsigned char _host_get_filled_slots(const struct iamt_heci_device *dev) | ||
| 101 | { | ||
| 102 | char read_ptr, write_ptr; | ||
| 103 | |||
| 104 | read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8); | ||
| 105 | write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16); | ||
| 106 | |||
| 107 | return (unsigned char) (write_ptr - read_ptr); | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * host_buffer_is_empty - check if host buffer is empty. | ||
| 112 | * | ||
| 113 | * @dev: device object for our driver | ||
| 114 | * | ||
| 115 | * returns 1 if empty, 0 - otherwise. | ||
| 116 | */ | ||
| 117 | int host_buffer_is_empty(struct iamt_heci_device *dev) | ||
| 118 | { | ||
| 119 | unsigned char filled_slots; | ||
| 120 | |||
| 121 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 122 | filled_slots = _host_get_filled_slots(dev); | ||
| 123 | |||
| 124 | if (filled_slots > 0) | ||
| 125 | return 0; | ||
| 126 | |||
| 127 | return 1; | ||
| 128 | } | ||
| 129 | |||
| 130 | /** | ||
| 131 | * count_empty_write_slots - count write empty slots. | ||
| 132 | * | ||
| 133 | * @dev: device object for our driver | ||
| 134 | * | ||
| 135 | * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count | ||
| 136 | */ | ||
| 137 | __s32 count_empty_write_slots(const struct iamt_heci_device *dev) | ||
| 138 | { | ||
| 139 | unsigned char buffer_depth, filled_slots, empty_slots; | ||
| 140 | |||
| 141 | buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24); | ||
| 142 | filled_slots = _host_get_filled_slots(dev); | ||
| 143 | empty_slots = buffer_depth - filled_slots; | ||
| 144 | |||
| 145 | if (filled_slots > buffer_depth) { | ||
| 146 | /* overflow */ | ||
| 147 | return -ESLOTS_OVERFLOW; | ||
| 148 | } | ||
| 149 | |||
| 150 | return (__s32) empty_slots; | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * heci_write_message - write a message to heci device. | ||
| 155 | * | ||
| 156 | * @dev: device object for our driver | ||
| 157 | * @heci_hdr: header of message | ||
| 158 | * @write_buffer: message buffer will be write | ||
| 159 | * @write_length: message size will be write | ||
| 160 | * | ||
| 161 | * returns 1 if success, 0 - otherwise. | ||
| 162 | */ | ||
| 163 | int heci_write_message(struct iamt_heci_device *dev, | ||
| 164 | struct heci_msg_hdr *header, | ||
| 165 | unsigned char *write_buffer, | ||
| 166 | unsigned long write_length) | ||
| 167 | { | ||
| 168 | __u32 temp_msg = 0; | ||
| 169 | unsigned long bytes_written = 0; | ||
| 170 | unsigned char buffer_depth, filled_slots, empty_slots; | ||
| 171 | unsigned long dw_to_write; | ||
| 172 | |||
| 173 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 174 | DBG("host_hw_state = 0x%08x.\n", dev->host_hw_state); | ||
| 175 | DBG("heci_write_message header=%08x.\n", *((__u32 *) header)); | ||
| 176 | buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24); | ||
| 177 | filled_slots = _host_get_filled_slots(dev); | ||
| 178 | empty_slots = buffer_depth - filled_slots; | ||
| 179 | DBG("filled = %hu, empty = %hu.\n", filled_slots, empty_slots); | ||
| 180 | |||
| 181 | dw_to_write = ((write_length + 3) / 4); | ||
| 182 | |||
| 183 | if (dw_to_write > empty_slots) | ||
| 184 | return 0; | ||
| 185 | |||
| 186 | write_heci_register(dev, H_CB_WW, *((__u32 *) header)); | ||
| 187 | |||
| 188 | while (write_length >= 4) { | ||
| 189 | write_heci_register(dev, H_CB_WW, | ||
| 190 | *(__u32 *) (write_buffer + bytes_written)); | ||
| 191 | bytes_written += 4; | ||
| 192 | write_length -= 4; | ||
| 193 | } | ||
| 194 | |||
| 195 | if (write_length > 0) { | ||
| 196 | memcpy(&temp_msg, &write_buffer[bytes_written], write_length); | ||
| 197 | write_heci_register(dev, H_CB_WW, temp_msg); | ||
| 198 | } | ||
| 199 | |||
| 200 | dev->host_hw_state |= H_IG; | ||
| 201 | heci_set_csr_register(dev); | ||
| 202 | dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); | ||
| 203 | if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA) | ||
| 204 | return 0; | ||
| 205 | |||
| 206 | dev->write_hang = 0; | ||
| 207 | return 1; | ||
| 208 | } | ||
| 209 | |||
| 210 | /** | ||
| 211 | * count_full_read_slots - count read full slots. | ||
| 212 | * | ||
| 213 | * @dev: device object for our driver | ||
| 214 | * | ||
| 215 | * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count | ||
| 216 | */ | ||
| 217 | __s32 count_full_read_slots(struct iamt_heci_device *dev) | ||
| 218 | { | ||
| 219 | char read_ptr, write_ptr; | ||
| 220 | unsigned char buffer_depth, filled_slots; | ||
| 221 | |||
| 222 | dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); | ||
| 223 | buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24); | ||
| 224 | read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8); | ||
| 225 | write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16); | ||
| 226 | filled_slots = (unsigned char) (write_ptr - read_ptr); | ||
| 227 | |||
| 228 | if (filled_slots > buffer_depth) { | ||
| 229 | /* overflow */ | ||
| 230 | return -ESLOTS_OVERFLOW; | ||
| 231 | } | ||
| 232 | |||
| 233 | DBG("filled_slots =%08x \n", filled_slots); | ||
| 234 | return (__s32) filled_slots; | ||
| 235 | } | ||
| 236 | |||
| 237 | /** | ||
| 238 | * heci_read_slots - read a message from heci device. | ||
| 239 | * | ||
| 240 | * @dev: device object for our driver | ||
| 241 | * @buffer: message buffer will be write | ||
| 242 | * @buffer_length: message size will be read | ||
| 243 | */ | ||
| 244 | void heci_read_slots(struct iamt_heci_device *dev, | ||
| 245 | unsigned char *buffer, unsigned long buffer_length) | ||
| 246 | { | ||
| 247 | __u32 i = 0; | ||
| 248 | unsigned char temp_buf[sizeof(__u32)]; | ||
| 249 | |||
| 250 | while (buffer_length >= sizeof(__u32)) { | ||
| 251 | ((__u32 *) buffer)[i] = read_heci_register(dev, ME_CB_RW); | ||
| 252 | DBG("buffer[%d]= %d\n", i, ((__u32 *) buffer)[i]); | ||
| 253 | i++; | ||
| 254 | buffer_length -= sizeof(__u32); | ||
| 255 | } | ||
| 256 | |||
| 257 | if (buffer_length > 0) { | ||
| 258 | *((__u32 *) &temp_buf) = read_heci_register(dev, ME_CB_RW); | ||
| 259 | memcpy(&buffer[i * 4], temp_buf, buffer_length); | ||
| 260 | } | ||
| 261 | |||
| 262 | dev->host_hw_state |= H_IG; | ||
| 263 | heci_set_csr_register(dev); | ||
| 264 | } | ||
| 265 | |||
| 266 | /** | ||
| 267 | * flow_ctrl_creds - check flow_control credentials. | ||
| 268 | * | ||
| 269 | * @dev: device object for our driver | ||
| 270 | * @file_ext: private data of the file object | ||
| 271 | * | ||
| 272 | * returns 1 if flow_ctrl_creds >0, 0 - otherwise. | ||
| 273 | */ | ||
| 274 | int flow_ctrl_creds(struct iamt_heci_device *dev, | ||
| 275 | struct heci_file_private *file_ext) | ||
| 276 | { | ||
| 277 | __u8 i; | ||
| 278 | |||
| 279 | if (!dev->num_heci_me_clients) | ||
| 280 | return 0; | ||
| 281 | |||
| 282 | if (file_ext == NULL) | ||
| 283 | return 0; | ||
| 284 | |||
| 285 | if (file_ext->flow_ctrl_creds > 0) | ||
| 286 | return 1; | ||
| 287 | |||
| 288 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 289 | if (dev->me_clients[i].client_id == file_ext->me_client_id) { | ||
| 290 | if (dev->me_clients[i].flow_ctrl_creds > 0) { | ||
| 291 | BUG_ON(dev->me_clients[i].props.single_recv_buf | ||
| 292 | == 0); | ||
| 293 | return 1; | ||
| 294 | } | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | BUG(); | ||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | /** | ||
| 303 | * flow_ctrl_reduce - reduce flow_control. | ||
| 304 | * | ||
| 305 | * @dev: device object for our driver | ||
| 306 | * @file_ext: private data of the file object | ||
| 307 | */ | ||
| 308 | void flow_ctrl_reduce(struct iamt_heci_device *dev, | ||
| 309 | struct heci_file_private *file_ext) | ||
| 310 | { | ||
| 311 | __u8 i; | ||
| 312 | |||
| 313 | if (!dev->num_heci_me_clients) | ||
| 314 | return; | ||
| 315 | |||
| 316 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 317 | if (dev->me_clients[i].client_id == file_ext->me_client_id) { | ||
| 318 | if (dev->me_clients[i].props.single_recv_buf != 0) { | ||
| 319 | BUG_ON(dev->me_clients[i].flow_ctrl_creds <= 0); | ||
| 320 | dev->me_clients[i].flow_ctrl_creds--; | ||
| 321 | } else { | ||
| 322 | BUG_ON(file_ext->flow_ctrl_creds <= 0); | ||
| 323 | file_ext->flow_ctrl_creds--; | ||
| 324 | } | ||
| 325 | return; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | BUG(); | ||
| 329 | } | ||
| 330 | |||
| 331 | /** | ||
| 332 | * heci_send_flow_control - send flow control to fw. | ||
| 333 | * | ||
| 334 | * @dev: device object for our driver | ||
| 335 | * @file_ext: private data of the file object | ||
| 336 | * | ||
| 337 | * returns 1 if success, 0 - otherwise. | ||
| 338 | */ | ||
| 339 | int heci_send_flow_control(struct iamt_heci_device *dev, | ||
| 340 | struct heci_file_private *file_ext) | ||
| 341 | { | ||
| 342 | struct heci_msg_hdr *heci_hdr; | ||
| 343 | struct hbm_flow_control *heci_flow_control; | ||
| 344 | |||
| 345 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 346 | heci_hdr->host_addr = 0; | ||
| 347 | heci_hdr->me_addr = 0; | ||
| 348 | heci_hdr->length = sizeof(struct hbm_flow_control); | ||
| 349 | heci_hdr->msg_complete = 1; | ||
| 350 | heci_hdr->reserved = 0; | ||
| 351 | |||
| 352 | heci_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1]; | ||
| 353 | memset(heci_flow_control, 0, sizeof(heci_flow_control)); | ||
| 354 | heci_flow_control->host_addr = file_ext->host_client_id; | ||
| 355 | heci_flow_control->me_addr = file_ext->me_client_id; | ||
| 356 | heci_flow_control->cmd.cmd = HECI_FLOW_CONTROL_CMD; | ||
| 357 | memset(heci_flow_control->reserved, 0, | ||
| 358 | sizeof(heci_flow_control->reserved)); | ||
| 359 | DBG("sending flow control host client = %d, me client = %d\n", | ||
| 360 | file_ext->host_client_id, file_ext->me_client_id); | ||
| 361 | if (!heci_write_message(dev, heci_hdr, | ||
| 362 | (unsigned char *) heci_flow_control, | ||
| 363 | sizeof(struct hbm_flow_control))) | ||
| 364 | return 0; | ||
| 365 | |||
| 366 | return 1; | ||
| 367 | |||
| 368 | } | ||
| 369 | |||
| 370 | /** | ||
| 371 | * other_client_is_connecting - check if other | ||
| 372 | * client with the same client id is connected. | ||
| 373 | * | ||
| 374 | * @dev: device object for our driver | ||
| 375 | * @file_ext: private data of the file object | ||
| 376 | * | ||
| 377 | * returns 1 if other client is connected, 0 - otherwise. | ||
| 378 | */ | ||
| 379 | int other_client_is_connecting(struct iamt_heci_device *dev, | ||
| 380 | struct heci_file_private *file_ext) | ||
| 381 | { | ||
| 382 | struct heci_file_private *file_pos = NULL; | ||
| 383 | struct heci_file_private *file_next = NULL; | ||
| 384 | |||
| 385 | list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) { | ||
| 386 | if ((file_pos->state == HECI_FILE_CONNECTING) | ||
| 387 | && (file_pos != file_ext) | ||
| 388 | && file_ext->me_client_id == file_pos->me_client_id) | ||
| 389 | return 1; | ||
| 390 | |||
| 391 | } | ||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | |||
| 395 | /** | ||
| 396 | * heci_send_wd - send watch dog message to fw. | ||
| 397 | * | ||
| 398 | * @dev: device object for our driver | ||
| 399 | * | ||
| 400 | * returns 1 if success, 0 - otherwise. | ||
| 401 | */ | ||
| 402 | int heci_send_wd(struct iamt_heci_device *dev) | ||
| 403 | { | ||
| 404 | struct heci_msg_hdr *heci_hdr; | ||
| 405 | |||
| 406 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 407 | heci_hdr->host_addr = dev->wd_file_ext.host_client_id; | ||
| 408 | heci_hdr->me_addr = dev->wd_file_ext.me_client_id; | ||
| 409 | heci_hdr->msg_complete = 1; | ||
| 410 | heci_hdr->reserved = 0; | ||
| 411 | |||
| 412 | if (!memcmp(dev->wd_data, heci_start_wd_params, | ||
| 413 | HECI_WD_PARAMS_SIZE)) { | ||
| 414 | heci_hdr->length = HECI_START_WD_DATA_SIZE; | ||
| 415 | } else { | ||
| 416 | BUG_ON(memcmp(dev->wd_data, heci_stop_wd_params, | ||
| 417 | HECI_WD_PARAMS_SIZE)); | ||
| 418 | heci_hdr->length = HECI_WD_PARAMS_SIZE; | ||
| 419 | } | ||
| 420 | |||
| 421 | if (!heci_write_message(dev, heci_hdr, dev->wd_data, heci_hdr->length)) | ||
| 422 | return 0; | ||
| 423 | |||
| 424 | return 1; | ||
| 425 | } | ||
| 426 | |||
| 427 | /** | ||
| 428 | * heci_disconnect - send disconnect message to fw. | ||
| 429 | * | ||
| 430 | * @dev: device object for our driver | ||
| 431 | * @file_ext: private data of the file object | ||
| 432 | * | ||
| 433 | * returns 1 if success, 0 - otherwise. | ||
| 434 | */ | ||
| 435 | int heci_disconnect(struct iamt_heci_device *dev, | ||
| 436 | struct heci_file_private *file_ext) | ||
| 437 | { | ||
| 438 | struct heci_msg_hdr *heci_hdr; | ||
| 439 | struct hbm_client_disconnect_request *heci_cli_disconnect; | ||
| 440 | |||
| 441 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 442 | heci_hdr->host_addr = 0; | ||
| 443 | heci_hdr->me_addr = 0; | ||
| 444 | heci_hdr->length = sizeof(struct hbm_client_disconnect_request); | ||
| 445 | heci_hdr->msg_complete = 1; | ||
| 446 | heci_hdr->reserved = 0; | ||
| 447 | |||
| 448 | heci_cli_disconnect = | ||
| 449 | (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1]; | ||
| 450 | memset(heci_cli_disconnect, 0, sizeof(heci_cli_disconnect)); | ||
| 451 | heci_cli_disconnect->host_addr = file_ext->host_client_id; | ||
| 452 | heci_cli_disconnect->me_addr = file_ext->me_client_id; | ||
| 453 | heci_cli_disconnect->cmd.cmd = CLIENT_DISCONNECT_REQ_CMD; | ||
| 454 | heci_cli_disconnect->reserved[0] = 0; | ||
| 455 | |||
| 456 | if (!heci_write_message(dev, heci_hdr, | ||
| 457 | (unsigned char *) heci_cli_disconnect, | ||
| 458 | sizeof(struct hbm_client_disconnect_request))) | ||
| 459 | return 0; | ||
| 460 | |||
| 461 | return 1; | ||
| 462 | } | ||
| 463 | |||
| 464 | /** | ||
| 465 | * heci_connect - send connect message to fw. | ||
| 466 | * | ||
| 467 | * @dev: device object for our driver | ||
| 468 | * @file_ext: private data of the file object | ||
| 469 | * | ||
| 470 | * returns 1 if success, 0 - otherwise. | ||
| 471 | */ | ||
| 472 | int heci_connect(struct iamt_heci_device *dev, | ||
| 473 | struct heci_file_private *file_ext) | ||
| 474 | { | ||
| 475 | struct heci_msg_hdr *heci_hdr; | ||
| 476 | struct hbm_client_connect_request *heci_cli_connect; | ||
| 477 | |||
| 478 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 479 | heci_hdr->host_addr = 0; | ||
| 480 | heci_hdr->me_addr = 0; | ||
| 481 | heci_hdr->length = sizeof(struct hbm_client_connect_request); | ||
| 482 | heci_hdr->msg_complete = 1; | ||
| 483 | heci_hdr->reserved = 0; | ||
| 484 | |||
| 485 | heci_cli_connect = | ||
| 486 | (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; | ||
| 487 | heci_cli_connect->host_addr = file_ext->host_client_id; | ||
| 488 | heci_cli_connect->me_addr = file_ext->me_client_id; | ||
| 489 | heci_cli_connect->cmd.cmd = CLIENT_CONNECT_REQ_CMD; | ||
| 490 | heci_cli_connect->reserved = 0; | ||
| 491 | |||
| 492 | if (!heci_write_message(dev, heci_hdr, | ||
| 493 | (unsigned char *) heci_cli_connect, | ||
| 494 | sizeof(struct hbm_client_connect_request))) | ||
| 495 | return 0; | ||
| 496 | |||
| 497 | return 1; | ||
| 498 | } | ||
diff --git a/drivers/staging/heci/heci_interface.h b/drivers/staging/heci/heci_interface.h deleted file mode 100644 index 34db7e52b8ef..000000000000 --- a/drivers/staging/heci/heci_interface.h +++ /dev/null | |||
| @@ -1,170 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | |||
| 42 | #ifndef _HECI_INTERFACE_H_ | ||
| 43 | #define _HECI_INTERFACE_H_ | ||
| 44 | |||
| 45 | #include <linux/spinlock.h> | ||
| 46 | #include <linux/list.h> | ||
| 47 | #include <linux/pci.h> | ||
| 48 | #include <linux/timer.h> | ||
| 49 | #include <linux/interrupt.h> | ||
| 50 | #include <linux/workqueue.h> | ||
| 51 | #include <linux/module.h> | ||
| 52 | #include <linux/aio.h> | ||
| 53 | #include <linux/types.h> | ||
| 54 | #include "heci_data_structures.h" | ||
| 55 | |||
| 56 | |||
| 57 | #define HBM_MINOR_VERSION 0 | ||
| 58 | #define HBM_MAJOR_VERSION 1 | ||
| 59 | #define HBM_TIMEOUT 1 /* 1 second */ | ||
| 60 | |||
| 61 | |||
| 62 | #define HOST_START_REQ_CMD 0x01 | ||
| 63 | #define HOST_START_RES_CMD 0x81 | ||
| 64 | |||
| 65 | #define HOST_STOP_REQ_CMD 0x02 | ||
| 66 | #define HOST_STOP_RES_CMD 0x82 | ||
| 67 | |||
| 68 | #define ME_STOP_REQ_CMD 0x03 | ||
| 69 | |||
| 70 | #define HOST_ENUM_REQ_CMD 0x04 | ||
| 71 | #define HOST_ENUM_RES_CMD 0x84 | ||
| 72 | |||
| 73 | #define HOST_CLIENT_PROPERTEIS_REQ_CMD 0x05 | ||
| 74 | #define HOST_CLIENT_PROPERTEIS_RES_CMD 0x85 | ||
| 75 | |||
| 76 | #define CLIENT_CONNECT_REQ_CMD 0x06 | ||
| 77 | #define CLIENT_CONNECT_RES_CMD 0x86 | ||
| 78 | |||
| 79 | #define CLIENT_DISCONNECT_REQ_CMD 0x07 | ||
| 80 | #define CLIENT_DISCONNECT_RES_CMD 0x87 | ||
| 81 | |||
| 82 | #define HECI_FLOW_CONTROL_CMD 0x08 | ||
| 83 | |||
| 84 | |||
| 85 | #define AMT_WD_VALUE 120 /* seconds */ | ||
| 86 | |||
| 87 | #define HECI_WATCHDOG_DATA_SIZE 16 | ||
| 88 | #define HECI_START_WD_DATA_SIZE 20 | ||
| 89 | #define HECI_WD_PARAMS_SIZE 4 | ||
| 90 | |||
| 91 | /* IOCTL commands */ | ||
| 92 | #define IOCTL_HECI_GET_VERSION \ | ||
| 93 | _IOWR('H' , 0x0, struct heci_message_data) | ||
| 94 | #define IOCTL_HECI_CONNECT_CLIENT \ | ||
| 95 | _IOWR('H' , 0x01, struct heci_message_data) | ||
| 96 | #define IOCTL_HECI_WD \ | ||
| 97 | _IOWR('H' , 0x02, struct heci_message_data) | ||
| 98 | #define IOCTL_HECI_BYPASS_WD \ | ||
| 99 | _IOWR('H' , 0x10, struct heci_message_data) | ||
| 100 | |||
| 101 | enum heci_stop_reason_types{ | ||
| 102 | DRIVER_STOP_REQUEST = 0x00, | ||
| 103 | DEVICE_D1_ENTRY = 0x01, | ||
| 104 | DEVICE_D2_ENTRY = 0x02, | ||
| 105 | DEVICE_D3_ENTRY = 0x03, | ||
| 106 | SYSTEM_S1_ENTRY = 0x04, | ||
| 107 | SYSTEM_S2_ENTRY = 0x05, | ||
| 108 | SYSTEM_S3_ENTRY = 0x06, | ||
| 109 | SYSTEM_S4_ENTRY = 0x07, | ||
| 110 | SYSTEM_S5_ENTRY = 0x08 | ||
| 111 | }; | ||
| 112 | |||
| 113 | enum me_stop_reason_types{ | ||
| 114 | FW_UPDATE = 0x00 | ||
| 115 | }; | ||
| 116 | |||
| 117 | enum client_connect_status_types{ | ||
| 118 | CCS_SUCCESS = 0x00, | ||
| 119 | CCS_NOT_FOUND = 0x01, | ||
| 120 | CCS_ALREADY_STARTED = 0x02, | ||
| 121 | CCS_OUT_OF_RESOURCES = 0x03, | ||
| 122 | CCS_MESSAGE_SMALL = 0x04 | ||
| 123 | }; | ||
| 124 | |||
| 125 | enum client_disconnect_status_types{ | ||
| 126 | CDS_SUCCESS = 0x00 | ||
| 127 | }; | ||
| 128 | |||
| 129 | |||
| 130 | /* | ||
| 131 | * heci interface function prototypes | ||
| 132 | */ | ||
| 133 | void heci_set_csr_register(struct iamt_heci_device *dev); | ||
| 134 | void heci_csr_enable_interrupts(struct iamt_heci_device *dev); | ||
| 135 | void heci_csr_disable_interrupts(struct iamt_heci_device *dev); | ||
| 136 | void heci_csr_clear_his(struct iamt_heci_device *dev); | ||
| 137 | |||
| 138 | void heci_read_slots(struct iamt_heci_device *dev, | ||
| 139 | unsigned char *buffer, unsigned long buffer_length); | ||
| 140 | |||
| 141 | int heci_write_message(struct iamt_heci_device *dev, | ||
| 142 | struct heci_msg_hdr *header, | ||
| 143 | unsigned char *write_buffer, | ||
| 144 | unsigned long write_length); | ||
| 145 | |||
| 146 | int host_buffer_is_empty(struct iamt_heci_device *dev); | ||
| 147 | |||
| 148 | __s32 count_full_read_slots(struct iamt_heci_device *dev); | ||
| 149 | |||
| 150 | __s32 count_empty_write_slots(const struct iamt_heci_device *dev); | ||
| 151 | |||
| 152 | int flow_ctrl_creds(struct iamt_heci_device *dev, | ||
| 153 | struct heci_file_private *file_ext); | ||
| 154 | |||
| 155 | int heci_send_wd(struct iamt_heci_device *dev); | ||
| 156 | |||
| 157 | void flow_ctrl_reduce(struct iamt_heci_device *dev, | ||
| 158 | struct heci_file_private *file_ext); | ||
| 159 | |||
| 160 | int heci_send_flow_control(struct iamt_heci_device *dev, | ||
| 161 | struct heci_file_private *file_ext); | ||
| 162 | |||
| 163 | int heci_disconnect(struct iamt_heci_device *dev, | ||
| 164 | struct heci_file_private *file_ext); | ||
| 165 | int other_client_is_connecting(struct iamt_heci_device *dev, | ||
| 166 | struct heci_file_private *file_ext); | ||
| 167 | int heci_connect(struct iamt_heci_device *dev, | ||
| 168 | struct heci_file_private *file_ext); | ||
| 169 | |||
| 170 | #endif /* _HECI_INTERFACE_H_ */ | ||
diff --git a/drivers/staging/heci/heci_main.c b/drivers/staging/heci/heci_main.c deleted file mode 100644 index ddf48227e358..000000000000 --- a/drivers/staging/heci/heci_main.c +++ /dev/null | |||
| @@ -1,1576 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | |||
| 42 | #include <linux/module.h> | ||
| 43 | #include <linux/moduleparam.h> | ||
| 44 | #include <linux/kernel.h> | ||
| 45 | #include <linux/slab.h> | ||
| 46 | #include <linux/fs.h> | ||
| 47 | #include <linux/errno.h> | ||
| 48 | #include <linux/types.h> | ||
| 49 | #include <linux/fcntl.h> | ||
| 50 | #include <linux/aio.h> | ||
| 51 | #include <linux/pci.h> | ||
| 52 | #include <linux/reboot.h> | ||
| 53 | #include <linux/poll.h> | ||
| 54 | #include <linux/init.h> | ||
| 55 | #include <linux/kdev_t.h> | ||
| 56 | #include <linux/ioctl.h> | ||
| 57 | #include <linux/cdev.h> | ||
| 58 | #include <linux/device.h> | ||
| 59 | #include <linux/unistd.h> | ||
| 60 | #include <linux/kthread.h> | ||
| 61 | |||
| 62 | #include "heci.h" | ||
| 63 | #include "heci_interface.h" | ||
| 64 | #include "heci_version.h" | ||
| 65 | |||
| 66 | |||
| 67 | #define HECI_READ_TIMEOUT 45 | ||
| 68 | |||
| 69 | #define HECI_DRIVER_NAME "heci" | ||
| 70 | |||
| 71 | /* | ||
| 72 | * heci driver strings | ||
| 73 | */ | ||
| 74 | static char heci_driver_name[] = HECI_DRIVER_NAME; | ||
| 75 | static char heci_driver_string[] = "Intel(R) Management Engine Interface"; | ||
| 76 | static char heci_driver_version[] = HECI_DRIVER_VERSION; | ||
| 77 | static char heci_copyright[] = "Copyright (c) 2003 - 2008 Intel Corporation."; | ||
| 78 | |||
| 79 | |||
| 80 | #ifdef HECI_DEBUG | ||
| 81 | int heci_debug = 1; | ||
| 82 | #else | ||
| 83 | int heci_debug; | ||
| 84 | #endif | ||
| 85 | MODULE_PARM_DESC(heci_debug, "Debug enabled or not"); | ||
| 86 | module_param(heci_debug, int, 0644); | ||
| 87 | |||
| 88 | |||
| 89 | #define HECI_DEV_NAME "heci" | ||
| 90 | |||
| 91 | /* heci char device for registration */ | ||
| 92 | static struct cdev heci_cdev; | ||
| 93 | |||
| 94 | /* major number for device */ | ||
| 95 | static int heci_major; | ||
| 96 | /* The device pointer */ | ||
| 97 | static struct pci_dev *heci_device; | ||
| 98 | |||
| 99 | static struct class *heci_class; | ||
| 100 | |||
| 101 | |||
| 102 | /* heci_pci_tbl - PCI Device ID Table */ | ||
| 103 | static struct pci_device_id heci_pci_tbl[] = { | ||
| 104 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82946GZ)}, | ||
| 105 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82G35)}, | ||
| 106 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82Q965)}, | ||
| 107 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82G965)}, | ||
| 108 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82GM965)}, | ||
| 109 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_82GME965)}, | ||
| 110 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82Q35)}, | ||
| 111 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82G33)}, | ||
| 112 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82Q33)}, | ||
| 113 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_82X38)}, | ||
| 114 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_3200)}, | ||
| 115 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_6)}, | ||
| 116 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_7)}, | ||
| 117 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_8)}, | ||
| 118 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_9)}, | ||
| 119 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9_10)}, | ||
| 120 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_1)}, | ||
| 121 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_2)}, | ||
| 122 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_3)}, | ||
| 123 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH9M_4)}, | ||
| 124 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_1)}, | ||
| 125 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_2)}, | ||
| 126 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_3)}, | ||
| 127 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, HECI_DEV_ID_ICH10_4)}, | ||
| 128 | /* required last entry */ | ||
| 129 | {0, } | ||
| 130 | }; | ||
| 131 | |||
| 132 | MODULE_DEVICE_TABLE(pci, heci_pci_tbl); | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Local Function Prototypes | ||
| 136 | */ | ||
| 137 | static int __init heci_init_module(void); | ||
| 138 | static void __exit heci_exit_module(void); | ||
| 139 | static int __devinit heci_probe(struct pci_dev *pdev, | ||
| 140 | const struct pci_device_id *ent); | ||
| 141 | static void __devexit heci_remove(struct pci_dev *pdev); | ||
| 142 | static int heci_open(struct inode *inode, struct file *file); | ||
| 143 | static int heci_release(struct inode *inode, struct file *file); | ||
| 144 | static ssize_t heci_read(struct file *file, char __user *ubuf, | ||
| 145 | size_t length, loff_t *offset); | ||
| 146 | static int heci_ioctl(struct inode *inode, struct file *file, | ||
| 147 | unsigned int cmd, unsigned long data); | ||
| 148 | static ssize_t heci_write(struct file *file, const char __user *ubuf, | ||
| 149 | size_t length, loff_t *offset); | ||
| 150 | static unsigned int heci_poll(struct file *file, poll_table *wait); | ||
| 151 | static struct heci_cb_private *find_read_list_entry( | ||
| 152 | struct iamt_heci_device *dev, | ||
| 153 | struct heci_file_private *file_ext); | ||
| 154 | #ifdef CONFIG_PM | ||
| 155 | static int heci_suspend(struct pci_dev *pdev, pm_message_t state); | ||
| 156 | static int heci_resume(struct pci_dev *pdev); | ||
| 157 | static __u16 g_sus_wd_timeout; | ||
| 158 | #else | ||
| 159 | #define heci_suspend NULL | ||
| 160 | #define heci_resume NULL | ||
| 161 | #endif | ||
| 162 | /* | ||
| 163 | * PCI driver structure | ||
| 164 | */ | ||
| 165 | static struct pci_driver heci_driver = { | ||
| 166 | .name = heci_driver_name, | ||
| 167 | .id_table = heci_pci_tbl, | ||
| 168 | .probe = heci_probe, | ||
| 169 | .remove = __devexit_p(heci_remove), | ||
| 170 | .shutdown = __devexit_p(heci_remove), | ||
| 171 | .suspend = heci_suspend, | ||
| 172 | .resume = heci_resume | ||
| 173 | }; | ||
| 174 | |||
| 175 | /* | ||
| 176 | * file operations structure will be use heci char device. | ||
| 177 | */ | ||
| 178 | static const struct file_operations heci_fops = { | ||
| 179 | .owner = THIS_MODULE, | ||
| 180 | .read = heci_read, | ||
| 181 | .ioctl = heci_ioctl, | ||
| 182 | .open = heci_open, | ||
| 183 | .release = heci_release, | ||
| 184 | .write = heci_write, | ||
| 185 | .poll = heci_poll, | ||
| 186 | }; | ||
| 187 | |||
| 188 | /** | ||
| 189 | * heci_registration_cdev - set up the cdev structure for heci device. | ||
| 190 | * | ||
| 191 | * @dev: char device struct | ||
| 192 | * @hminor: minor number for registration char device | ||
| 193 | * @fops: file operations structure | ||
| 194 | * | ||
| 195 | * returns 0 on success, <0 on failure. | ||
| 196 | */ | ||
| 197 | static int heci_registration_cdev(struct cdev *dev, int hminor, | ||
| 198 | const struct file_operations *fops) | ||
| 199 | { | ||
| 200 | int ret, devno = MKDEV(heci_major, hminor); | ||
| 201 | |||
| 202 | cdev_init(dev, fops); | ||
| 203 | dev->owner = THIS_MODULE; | ||
| 204 | ret = cdev_add(dev, devno, 1); | ||
| 205 | /* Fail gracefully if need be */ | ||
| 206 | if (ret) { | ||
| 207 | printk(KERN_ERR "heci: Error %d registering heci device %d\n", | ||
| 208 | ret, hminor); | ||
| 209 | } | ||
| 210 | return ret; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* Display the version of heci driver. */ | ||
| 214 | static ssize_t version_show(struct class *dev, char *buf) | ||
| 215 | { | ||
| 216 | return sprintf(buf, "%s %s.\n", | ||
| 217 | heci_driver_string, heci_driver_version); | ||
| 218 | } | ||
| 219 | |||
| 220 | static CLASS_ATTR(version, S_IRUGO, version_show, NULL); | ||
| 221 | |||
| 222 | /** | ||
| 223 | * heci_register_cdev - registers heci char device | ||
| 224 | * | ||
| 225 | * returns 0 on success, <0 on failure. | ||
| 226 | */ | ||
| 227 | static int heci_register_cdev(void) | ||
| 228 | { | ||
| 229 | int ret; | ||
| 230 | dev_t dev; | ||
| 231 | |||
| 232 | /* registration of char devices */ | ||
| 233 | ret = alloc_chrdev_region(&dev, HECI_MINORS_BASE, HECI_MINORS_COUNT, | ||
| 234 | HECI_DRIVER_NAME); | ||
| 235 | if (ret) { | ||
| 236 | printk(KERN_ERR "heci: Error allocating char device region.\n"); | ||
| 237 | return ret; | ||
| 238 | } | ||
| 239 | |||
| 240 | heci_major = MAJOR(dev); | ||
| 241 | |||
| 242 | ret = heci_registration_cdev(&heci_cdev, HECI_MINOR_NUMBER, | ||
| 243 | &heci_fops); | ||
| 244 | if (ret) | ||
| 245 | unregister_chrdev_region(MKDEV(heci_major, HECI_MINORS_BASE), | ||
| 246 | HECI_MINORS_COUNT); | ||
| 247 | |||
| 248 | return ret; | ||
| 249 | } | ||
| 250 | |||
| 251 | /** | ||
| 252 | * heci_unregister_cdev - unregisters heci char device | ||
| 253 | */ | ||
| 254 | static void heci_unregister_cdev(void) | ||
| 255 | { | ||
| 256 | cdev_del(&heci_cdev); | ||
| 257 | unregister_chrdev_region(MKDEV(heci_major, HECI_MINORS_BASE), | ||
| 258 | HECI_MINORS_COUNT); | ||
| 259 | } | ||
| 260 | |||
| 261 | #ifndef HECI_DEVICE_CREATE | ||
| 262 | #define HECI_DEVICE_CREATE device_create | ||
| 263 | #endif | ||
| 264 | /** | ||
| 265 | * heci_sysfs_device_create - adds device entry to sysfs | ||
| 266 | * | ||
| 267 | * returns 0 on success, <0 on failure. | ||
| 268 | */ | ||
| 269 | static int heci_sysfs_device_create(void) | ||
| 270 | { | ||
| 271 | struct class *class; | ||
| 272 | void *tmphdev; | ||
| 273 | int err = 0; | ||
| 274 | |||
| 275 | class = class_create(THIS_MODULE, HECI_DRIVER_NAME); | ||
| 276 | if (IS_ERR(class)) { | ||
| 277 | err = PTR_ERR(class); | ||
| 278 | printk(KERN_ERR "heci: Error creating heci class.\n"); | ||
| 279 | goto err_out; | ||
| 280 | } | ||
| 281 | |||
| 282 | err = class_create_file(class, &class_attr_version); | ||
| 283 | if (err) { | ||
| 284 | class_destroy(class); | ||
| 285 | printk(KERN_ERR "heci: Error creating heci class file.\n"); | ||
| 286 | goto err_out; | ||
| 287 | } | ||
| 288 | |||
| 289 | tmphdev = HECI_DEVICE_CREATE(class, NULL, heci_cdev.dev, NULL, | ||
| 290 | HECI_DEV_NAME); | ||
| 291 | if (IS_ERR(tmphdev)) { | ||
| 292 | err = PTR_ERR(tmphdev); | ||
| 293 | class_remove_file(class, &class_attr_version); | ||
| 294 | class_destroy(class); | ||
| 295 | goto err_out; | ||
| 296 | } | ||
| 297 | |||
| 298 | heci_class = class; | ||
| 299 | err_out: | ||
| 300 | return err; | ||
| 301 | } | ||
| 302 | |||
| 303 | /** | ||
| 304 | * heci_sysfs_device_remove - unregisters the device entry on sysfs | ||
| 305 | */ | ||
| 306 | static void heci_sysfs_device_remove(void) | ||
| 307 | { | ||
| 308 | if ((heci_class == NULL) || (IS_ERR(heci_class))) | ||
| 309 | return; | ||
| 310 | |||
| 311 | device_destroy(heci_class, heci_cdev.dev); | ||
| 312 | class_remove_file(heci_class, &class_attr_version); | ||
| 313 | class_destroy(heci_class); | ||
| 314 | } | ||
| 315 | |||
| 316 | /** | ||
| 317 | * heci_init_module - Driver Registration Routine | ||
| 318 | * | ||
| 319 | * heci_init_module is the first routine called when the driver is | ||
| 320 | * loaded. All it does is register with the PCI subsystem. | ||
| 321 | * | ||
| 322 | * returns 0 on success, <0 on failure. | ||
| 323 | */ | ||
| 324 | static int __init heci_init_module(void) | ||
| 325 | { | ||
| 326 | int ret = 0; | ||
| 327 | |||
| 328 | printk(KERN_INFO "heci: %s - version %s\n", heci_driver_string, | ||
| 329 | heci_driver_version); | ||
| 330 | printk(KERN_INFO "heci: %s\n", heci_copyright); | ||
| 331 | |||
| 332 | /* init pci module */ | ||
| 333 | ret = pci_register_driver(&heci_driver); | ||
| 334 | if (ret < 0) { | ||
| 335 | printk(KERN_ERR "heci: Error registering driver.\n"); | ||
| 336 | goto end; | ||
| 337 | } | ||
| 338 | |||
| 339 | ret = heci_register_cdev(); | ||
| 340 | if (ret) | ||
| 341 | goto unregister_pci; | ||
| 342 | |||
| 343 | ret = heci_sysfs_device_create(); | ||
| 344 | if (ret) | ||
| 345 | goto unregister_cdev; | ||
| 346 | |||
| 347 | return ret; | ||
| 348 | |||
| 349 | unregister_cdev: | ||
| 350 | heci_unregister_cdev(); | ||
| 351 | unregister_pci: | ||
| 352 | pci_unregister_driver(&heci_driver); | ||
| 353 | end: | ||
| 354 | return ret; | ||
| 355 | } | ||
| 356 | |||
| 357 | module_init(heci_init_module); | ||
| 358 | |||
| 359 | |||
| 360 | /** | ||
| 361 | * heci_exit_module - Driver Exit Cleanup Routine | ||
| 362 | * | ||
| 363 | * heci_exit_module is called just before the driver is removed | ||
| 364 | * from memory. | ||
| 365 | */ | ||
| 366 | static void __exit heci_exit_module(void) | ||
| 367 | { | ||
| 368 | pci_unregister_driver(&heci_driver); | ||
| 369 | heci_sysfs_device_remove(); | ||
| 370 | heci_unregister_cdev(); | ||
| 371 | } | ||
| 372 | |||
| 373 | module_exit(heci_exit_module); | ||
| 374 | |||
| 375 | |||
| 376 | /** | ||
| 377 | * heci_probe - Device Initialization Routine | ||
| 378 | * | ||
| 379 | * @pdev: PCI device information struct | ||
| 380 | * @ent: entry in kcs_pci_tbl | ||
| 381 | * | ||
| 382 | * returns 0 on success, <0 on failure. | ||
| 383 | */ | ||
| 384 | static int __devinit heci_probe(struct pci_dev *pdev, | ||
| 385 | const struct pci_device_id *ent) | ||
| 386 | { | ||
| 387 | struct iamt_heci_device *dev = NULL; | ||
| 388 | int i, err = 0; | ||
| 389 | |||
| 390 | if (heci_device) { | ||
| 391 | err = -EEXIST; | ||
| 392 | goto end; | ||
| 393 | } | ||
| 394 | /* enable pci dev */ | ||
| 395 | err = pci_enable_device(pdev); | ||
| 396 | if (err) { | ||
| 397 | printk(KERN_ERR "heci: Failed to enable pci device.\n"); | ||
| 398 | goto end; | ||
| 399 | } | ||
| 400 | /* set PCI host mastering */ | ||
| 401 | pci_set_master(pdev); | ||
| 402 | /* pci request regions for heci driver */ | ||
| 403 | err = pci_request_regions(pdev, heci_driver_name); | ||
| 404 | if (err) { | ||
| 405 | printk(KERN_ERR "heci: Failed to get pci regions.\n"); | ||
| 406 | goto disable_device; | ||
| 407 | } | ||
| 408 | /* allocates and initializes the heci dev structure */ | ||
| 409 | dev = init_heci_device(pdev); | ||
| 410 | if (!dev) { | ||
| 411 | err = -ENOMEM; | ||
| 412 | goto release_regions; | ||
| 413 | } | ||
| 414 | /* mapping IO device memory */ | ||
| 415 | for (i = 0; i <= 5; i++) { | ||
| 416 | if (pci_resource_len(pdev, i) == 0) | ||
| 417 | continue; | ||
| 418 | if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { | ||
| 419 | printk(KERN_ERR "heci: heci has IO ports.\n"); | ||
| 420 | goto free_device; | ||
| 421 | } else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { | ||
| 422 | if (dev->mem_base) { | ||
| 423 | printk(KERN_ERR | ||
| 424 | "heci: Too many mem addresses.\n"); | ||
| 425 | goto free_device; | ||
| 426 | } | ||
| 427 | dev->mem_base = pci_resource_start(pdev, i); | ||
| 428 | dev->mem_length = pci_resource_len(pdev, i); | ||
| 429 | } | ||
| 430 | } | ||
| 431 | if (!dev->mem_base) { | ||
| 432 | printk(KERN_ERR "heci: No address to use.\n"); | ||
| 433 | err = -ENODEV; | ||
| 434 | goto free_device; | ||
| 435 | } | ||
| 436 | dev->mem_addr = ioremap_nocache(dev->mem_base, | ||
| 437 | dev->mem_length); | ||
| 438 | if (!dev->mem_addr) { | ||
| 439 | printk(KERN_ERR "heci: Remap IO device memory failure.\n"); | ||
| 440 | err = -ENOMEM; | ||
| 441 | goto free_device; | ||
| 442 | } | ||
| 443 | /* request and enable interrupt */ | ||
| 444 | err = request_irq(pdev->irq, heci_isr_interrupt, IRQF_SHARED, | ||
| 445 | heci_driver_name, dev); | ||
| 446 | if (err) { | ||
| 447 | printk(KERN_ERR "heci: Request_irq failure. irq = %d \n", | ||
| 448 | pdev->irq); | ||
| 449 | goto unmap_memory; | ||
| 450 | } | ||
| 451 | |||
| 452 | if (heci_hw_init(dev)) { | ||
| 453 | printk(KERN_ERR "heci: Init hw failure.\n"); | ||
| 454 | err = -ENODEV; | ||
| 455 | goto release_irq; | ||
| 456 | } | ||
| 457 | init_timer(&dev->wd_timer); | ||
| 458 | |||
| 459 | heci_initialize_clients(dev); | ||
| 460 | if (dev->heci_state != HECI_ENABLED) { | ||
| 461 | err = -ENODEV; | ||
| 462 | goto release_hw; | ||
| 463 | } | ||
| 464 | |||
| 465 | spin_lock_bh(&dev->device_lock); | ||
| 466 | heci_device = pdev; | ||
| 467 | pci_set_drvdata(pdev, dev); | ||
| 468 | spin_unlock_bh(&dev->device_lock); | ||
| 469 | |||
| 470 | if (dev->wd_timeout) | ||
| 471 | mod_timer(&dev->wd_timer, jiffies); | ||
| 472 | |||
| 473 | #ifdef CONFIG_PM | ||
| 474 | g_sus_wd_timeout = 0; | ||
| 475 | #endif | ||
| 476 | printk(KERN_INFO "heci driver initialization successful.\n"); | ||
| 477 | return 0; | ||
| 478 | |||
| 479 | release_hw: | ||
| 480 | /* disable interrupts */ | ||
| 481 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 482 | heci_csr_disable_interrupts(dev); | ||
| 483 | |||
| 484 | del_timer_sync(&dev->wd_timer); | ||
| 485 | |||
| 486 | flush_scheduled_work(); | ||
| 487 | |||
| 488 | release_irq: | ||
| 489 | free_irq(pdev->irq, dev); | ||
| 490 | unmap_memory: | ||
| 491 | if (dev->mem_addr) | ||
| 492 | iounmap(dev->mem_addr); | ||
| 493 | free_device: | ||
| 494 | kfree(dev); | ||
| 495 | release_regions: | ||
| 496 | pci_release_regions(pdev); | ||
| 497 | disable_device: | ||
| 498 | pci_disable_device(pdev); | ||
| 499 | end: | ||
| 500 | printk(KERN_ERR "heci driver initialization failed.\n"); | ||
| 501 | return err; | ||
| 502 | } | ||
| 503 | |||
| 504 | /** | ||
| 505 | * heci_remove - Device Removal Routine | ||
| 506 | * | ||
| 507 | * @pdev: PCI device information struct | ||
| 508 | * | ||
| 509 | * heci_remove is called by the PCI subsystem to alert the driver | ||
| 510 | * that it should release a PCI device. | ||
| 511 | */ | ||
| 512 | static void __devexit heci_remove(struct pci_dev *pdev) | ||
| 513 | { | ||
| 514 | struct iamt_heci_device *dev = pci_get_drvdata(pdev); | ||
| 515 | |||
| 516 | if (heci_device != pdev) | ||
| 517 | return; | ||
| 518 | |||
| 519 | if (dev == NULL) | ||
| 520 | return; | ||
| 521 | |||
| 522 | spin_lock_bh(&dev->device_lock); | ||
| 523 | if (heci_device != pdev) { | ||
| 524 | spin_unlock_bh(&dev->device_lock); | ||
| 525 | return; | ||
| 526 | } | ||
| 527 | |||
| 528 | if (dev->reinit_tsk != NULL) { | ||
| 529 | kthread_stop(dev->reinit_tsk); | ||
| 530 | dev->reinit_tsk = NULL; | ||
| 531 | } | ||
| 532 | |||
| 533 | del_timer_sync(&dev->wd_timer); | ||
| 534 | if (dev->wd_file_ext.state == HECI_FILE_CONNECTED | ||
| 535 | && dev->wd_timeout) { | ||
| 536 | dev->wd_timeout = 0; | ||
| 537 | dev->wd_due_counter = 0; | ||
| 538 | memcpy(dev->wd_data, heci_stop_wd_params, HECI_WD_PARAMS_SIZE); | ||
| 539 | dev->stop = 1; | ||
| 540 | if (dev->host_buffer_is_empty && | ||
| 541 | flow_ctrl_creds(dev, &dev->wd_file_ext)) { | ||
| 542 | dev->host_buffer_is_empty = 0; | ||
| 543 | |||
| 544 | if (!heci_send_wd(dev)) | ||
| 545 | DBG("send stop WD failed\n"); | ||
| 546 | else | ||
| 547 | flow_ctrl_reduce(dev, &dev->wd_file_ext); | ||
| 548 | |||
| 549 | dev->wd_pending = 0; | ||
| 550 | } else { | ||
| 551 | dev->wd_pending = 1; | ||
| 552 | } | ||
| 553 | dev->wd_stoped = 0; | ||
| 554 | spin_unlock_bh(&dev->device_lock); | ||
| 555 | |||
| 556 | wait_event_interruptible_timeout(dev->wait_stop_wd, | ||
| 557 | (dev->wd_stoped), 10 * HZ); | ||
| 558 | spin_lock_bh(&dev->device_lock); | ||
| 559 | if (!dev->wd_stoped) | ||
| 560 | DBG("stop wd failed to complete.\n"); | ||
| 561 | else | ||
| 562 | DBG("stop wd complete.\n"); | ||
| 563 | |||
| 564 | } | ||
| 565 | |||
| 566 | heci_device = NULL; | ||
| 567 | spin_unlock_bh(&dev->device_lock); | ||
| 568 | |||
| 569 | if (dev->iamthif_file_ext.state == HECI_FILE_CONNECTED) { | ||
| 570 | dev->iamthif_file_ext.state = HECI_FILE_DISCONNECTING; | ||
| 571 | heci_disconnect_host_client(dev, | ||
| 572 | &dev->iamthif_file_ext); | ||
| 573 | } | ||
| 574 | if (dev->wd_file_ext.state == HECI_FILE_CONNECTED) { | ||
| 575 | dev->wd_file_ext.state = HECI_FILE_DISCONNECTING; | ||
| 576 | heci_disconnect_host_client(dev, | ||
| 577 | &dev->wd_file_ext); | ||
| 578 | } | ||
| 579 | |||
| 580 | spin_lock_bh(&dev->device_lock); | ||
| 581 | |||
| 582 | /* remove entry if already in list */ | ||
| 583 | DBG("list del iamthif and wd file list.\n"); | ||
| 584 | heci_remove_client_from_file_list(dev, dev->wd_file_ext. | ||
| 585 | host_client_id); | ||
| 586 | heci_remove_client_from_file_list(dev, | ||
| 587 | dev->iamthif_file_ext.host_client_id); | ||
| 588 | |||
| 589 | dev->iamthif_current_cb = NULL; | ||
| 590 | dev->iamthif_file_ext.file = NULL; | ||
| 591 | dev->num_heci_me_clients = 0; | ||
| 592 | |||
| 593 | spin_unlock_bh(&dev->device_lock); | ||
| 594 | |||
| 595 | flush_scheduled_work(); | ||
| 596 | |||
| 597 | /* disable interrupts */ | ||
| 598 | heci_csr_disable_interrupts(dev); | ||
| 599 | |||
| 600 | free_irq(pdev->irq, dev); | ||
| 601 | pci_set_drvdata(pdev, NULL); | ||
| 602 | |||
| 603 | if (dev->mem_addr) | ||
| 604 | iounmap(dev->mem_addr); | ||
| 605 | |||
| 606 | kfree(dev); | ||
| 607 | |||
| 608 | pci_release_regions(pdev); | ||
| 609 | pci_disable_device(pdev); | ||
| 610 | } | ||
| 611 | |||
| 612 | /** | ||
| 613 | * heci_clear_list - remove all callbacks associated with file | ||
| 614 | * from heci_cb_list | ||
| 615 | * | ||
| 616 | * @file: file information struct | ||
| 617 | * @heci_cb_list: callbacks list | ||
| 618 | * | ||
| 619 | * heci_clear_list is called to clear resources associated with file | ||
| 620 | * when application calls close function or Ctrl-C was pressed | ||
| 621 | * | ||
| 622 | * returns 1 if callback removed from the list, 0 otherwise | ||
| 623 | */ | ||
| 624 | static int heci_clear_list(struct iamt_heci_device *dev, | ||
| 625 | struct file *file, struct list_head *heci_cb_list) | ||
| 626 | { | ||
| 627 | struct heci_cb_private *priv_cb_pos = NULL; | ||
| 628 | struct heci_cb_private *priv_cb_next = NULL; | ||
| 629 | struct file *file_temp; | ||
| 630 | int rets = 0; | ||
| 631 | |||
| 632 | /* list all list member */ | ||
| 633 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 634 | heci_cb_list, cb_list) { | ||
| 635 | file_temp = (struct file *)priv_cb_pos->file_object; | ||
| 636 | /* check if list member associated with a file */ | ||
| 637 | if (file_temp == file) { | ||
| 638 | /* remove member from the list */ | ||
| 639 | list_del(&priv_cb_pos->cb_list); | ||
| 640 | /* check if cb equal to current iamthif cb */ | ||
| 641 | if (dev->iamthif_current_cb == priv_cb_pos) { | ||
| 642 | dev->iamthif_current_cb = NULL; | ||
| 643 | /* send flow control to iamthif client */ | ||
| 644 | heci_send_flow_control(dev, | ||
| 645 | &dev->iamthif_file_ext); | ||
| 646 | } | ||
| 647 | /* free all allocated buffers */ | ||
| 648 | heci_free_cb_private(priv_cb_pos); | ||
| 649 | rets = 1; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | return rets; | ||
| 653 | } | ||
| 654 | |||
| 655 | /** | ||
| 656 | * heci_clear_lists - remove all callbacks associated with file | ||
| 657 | * | ||
| 658 | * @dev: device information struct | ||
| 659 | * @file: file information struct | ||
| 660 | * | ||
| 661 | * heci_clear_lists is called to clear resources associated with file | ||
| 662 | * when application calls close function or Ctrl-C was pressed | ||
| 663 | * | ||
| 664 | * returns 1 if callback removed from the list, 0 otherwise | ||
| 665 | */ | ||
| 666 | static int heci_clear_lists(struct iamt_heci_device *dev, struct file *file) | ||
| 667 | { | ||
| 668 | int rets = 0; | ||
| 669 | |||
| 670 | /* remove callbacks associated with a file */ | ||
| 671 | heci_clear_list(dev, file, &dev->pthi_cmd_list.heci_cb.cb_list); | ||
| 672 | if (heci_clear_list(dev, file, | ||
| 673 | &dev->pthi_read_complete_list.heci_cb.cb_list)) | ||
| 674 | rets = 1; | ||
| 675 | |||
| 676 | heci_clear_list(dev, file, &dev->ctrl_rd_list.heci_cb.cb_list); | ||
| 677 | |||
| 678 | if (heci_clear_list(dev, file, &dev->ctrl_wr_list.heci_cb.cb_list)) | ||
| 679 | rets = 1; | ||
| 680 | |||
| 681 | if (heci_clear_list(dev, file, | ||
| 682 | &dev->write_waiting_list.heci_cb.cb_list)) | ||
| 683 | rets = 1; | ||
| 684 | |||
| 685 | if (heci_clear_list(dev, file, &dev->write_list.heci_cb.cb_list)) | ||
| 686 | rets = 1; | ||
| 687 | |||
| 688 | /* check if iamthif_current_cb not NULL */ | ||
| 689 | if (dev->iamthif_current_cb && (!rets)) { | ||
| 690 | /* check file and iamthif current cb association */ | ||
| 691 | if (dev->iamthif_current_cb->file_object == file) { | ||
| 692 | /* remove cb */ | ||
| 693 | heci_free_cb_private(dev->iamthif_current_cb); | ||
| 694 | dev->iamthif_current_cb = NULL; | ||
| 695 | rets = 1; | ||
| 696 | } | ||
| 697 | } | ||
| 698 | return rets; | ||
| 699 | } | ||
| 700 | |||
| 701 | /** | ||
| 702 | * heci_open - the open function | ||
| 703 | * | ||
| 704 | * @inode: pointer to inode structure | ||
| 705 | * @file: pointer to file structure | ||
| 706 | * | ||
| 707 | * returns 0 on success, <0 on error | ||
| 708 | */ | ||
| 709 | static int heci_open(struct inode *inode, struct file *file) | ||
| 710 | { | ||
| 711 | struct heci_file_private *file_ext; | ||
| 712 | int if_num = iminor(inode); | ||
| 713 | struct iamt_heci_device *dev; | ||
| 714 | |||
| 715 | if (!heci_device) | ||
| 716 | return -ENODEV; | ||
| 717 | |||
| 718 | dev = pci_get_drvdata(heci_device); | ||
| 719 | if ((if_num != HECI_MINOR_NUMBER) || (!dev)) | ||
| 720 | return -ENODEV; | ||
| 721 | |||
| 722 | file_ext = heci_alloc_file_private(file); | ||
| 723 | if (file_ext == NULL) | ||
| 724 | return -ENOMEM; | ||
| 725 | |||
| 726 | spin_lock_bh(&dev->device_lock); | ||
| 727 | if (dev->heci_state != HECI_ENABLED) { | ||
| 728 | spin_unlock_bh(&dev->device_lock); | ||
| 729 | kfree(file_ext); | ||
| 730 | return -ENODEV; | ||
| 731 | } | ||
| 732 | if (dev->open_handle_count >= HECI_MAX_OPEN_HANDLE_COUNT) { | ||
| 733 | spin_unlock_bh(&dev->device_lock); | ||
| 734 | kfree(file_ext); | ||
| 735 | return -ENFILE; | ||
| 736 | }; | ||
| 737 | dev->open_handle_count++; | ||
| 738 | list_add_tail(&file_ext->link, &dev->file_list); | ||
| 739 | while ((dev->heci_host_clients[dev->current_host_client_id / 8] | ||
| 740 | & (1 << (dev->current_host_client_id % 8))) != 0) { | ||
| 741 | |||
| 742 | dev->current_host_client_id++; /* allow overflow */ | ||
| 743 | DBG("current_host_client_id = %d\n", | ||
| 744 | dev->current_host_client_id); | ||
| 745 | DBG("dev->open_handle_count = %lu\n", | ||
| 746 | dev->open_handle_count); | ||
| 747 | } | ||
| 748 | DBG("current_host_client_id = %d\n", dev->current_host_client_id); | ||
| 749 | file_ext->host_client_id = dev->current_host_client_id; | ||
| 750 | dev->heci_host_clients[file_ext->host_client_id / 8] |= | ||
| 751 | (1 << (file_ext->host_client_id % 8)); | ||
| 752 | spin_unlock_bh(&dev->device_lock); | ||
| 753 | spin_lock(&file_ext->file_lock); | ||
| 754 | spin_lock_bh(&dev->device_lock); | ||
| 755 | file_ext->state = HECI_FILE_INITIALIZING; | ||
| 756 | spin_unlock_bh(&dev->device_lock); | ||
| 757 | file_ext->sm_state = 0; | ||
| 758 | |||
| 759 | file->private_data = file_ext; | ||
| 760 | spin_unlock(&file_ext->file_lock); | ||
| 761 | |||
| 762 | return 0; | ||
| 763 | } | ||
| 764 | |||
| 765 | /** | ||
| 766 | * heci_release - the release function | ||
| 767 | * | ||
| 768 | * @inode: pointer to inode structure | ||
| 769 | * @file: pointer to file structure | ||
| 770 | * | ||
| 771 | * returns 0 on success, <0 on error | ||
| 772 | */ | ||
| 773 | static int heci_release(struct inode *inode, struct file *file) | ||
| 774 | { | ||
| 775 | int rets = 0; | ||
| 776 | int if_num = iminor(inode); | ||
| 777 | struct heci_file_private *file_ext = file->private_data; | ||
| 778 | struct heci_cb_private *priv_cb = NULL; | ||
| 779 | struct iamt_heci_device *dev; | ||
| 780 | |||
| 781 | if (!heci_device) | ||
| 782 | return -ENODEV; | ||
| 783 | |||
| 784 | dev = pci_get_drvdata(heci_device); | ||
| 785 | if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) | ||
| 786 | return -ENODEV; | ||
| 787 | |||
| 788 | if (file_ext != &dev->iamthif_file_ext) { | ||
| 789 | spin_lock(&file_ext->file_lock); | ||
| 790 | spin_lock_bh(&dev->device_lock); | ||
| 791 | if (file_ext->state == HECI_FILE_CONNECTED) { | ||
| 792 | file_ext->state = HECI_FILE_DISCONNECTING; | ||
| 793 | spin_unlock_bh(&dev->device_lock); | ||
| 794 | spin_unlock(&file_ext->file_lock); | ||
| 795 | DBG("disconnecting client host client = %d, " | ||
| 796 | "ME client = %d\n", | ||
| 797 | file_ext->host_client_id, | ||
| 798 | file_ext->me_client_id); | ||
| 799 | rets = heci_disconnect_host_client(dev, file_ext); | ||
| 800 | spin_lock(&file_ext->file_lock); | ||
| 801 | spin_lock_bh(&dev->device_lock); | ||
| 802 | } | ||
| 803 | heci_flush_queues(dev, file_ext); | ||
| 804 | DBG("remove client host client = %d, ME client = %d\n", | ||
| 805 | file_ext->host_client_id, | ||
| 806 | file_ext->me_client_id); | ||
| 807 | |||
| 808 | if (dev->open_handle_count > 0) { | ||
| 809 | dev->heci_host_clients[file_ext->host_client_id / 8] &= | ||
| 810 | ~(1 << (file_ext->host_client_id % 8)); | ||
| 811 | dev->open_handle_count--; | ||
| 812 | } | ||
| 813 | heci_remove_client_from_file_list(dev, | ||
| 814 | file_ext->host_client_id); | ||
| 815 | |||
| 816 | /* free read cb */ | ||
| 817 | if (file_ext->read_cb != NULL) { | ||
| 818 | priv_cb = find_read_list_entry(dev, file_ext); | ||
| 819 | /* Remove entry from read list */ | ||
| 820 | if (priv_cb != NULL) | ||
| 821 | list_del(&priv_cb->cb_list); | ||
| 822 | |||
| 823 | priv_cb = file_ext->read_cb; | ||
| 824 | file_ext->read_cb = NULL; | ||
| 825 | } | ||
| 826 | |||
| 827 | spin_unlock_bh(&dev->device_lock); | ||
| 828 | file->private_data = NULL; | ||
| 829 | spin_unlock(&file_ext->file_lock); | ||
| 830 | |||
| 831 | if (priv_cb != NULL) | ||
| 832 | heci_free_cb_private(priv_cb); | ||
| 833 | |||
| 834 | kfree(file_ext); | ||
| 835 | } else { | ||
| 836 | spin_lock_bh(&dev->device_lock); | ||
| 837 | |||
| 838 | if (dev->open_handle_count > 0) | ||
| 839 | dev->open_handle_count--; | ||
| 840 | |||
| 841 | if (dev->iamthif_file_object == file | ||
| 842 | && dev->iamthif_state != HECI_IAMTHIF_IDLE) { | ||
| 843 | DBG("pthi canceled iamthif state %d\n", | ||
| 844 | dev->iamthif_state); | ||
| 845 | dev->iamthif_canceled = 1; | ||
| 846 | if (dev->iamthif_state == HECI_IAMTHIF_READ_COMPLETE) { | ||
| 847 | DBG("run next pthi iamthif cb\n"); | ||
| 848 | run_next_iamthif_cmd(dev); | ||
| 849 | } | ||
| 850 | } | ||
| 851 | |||
| 852 | if (heci_clear_lists(dev, file)) | ||
| 853 | dev->iamthif_state = HECI_IAMTHIF_IDLE; | ||
| 854 | |||
| 855 | spin_unlock_bh(&dev->device_lock); | ||
| 856 | } | ||
| 857 | return rets; | ||
| 858 | } | ||
| 859 | |||
| 860 | static struct heci_cb_private *find_read_list_entry( | ||
| 861 | struct iamt_heci_device *dev, | ||
| 862 | struct heci_file_private *file_ext) | ||
| 863 | { | ||
| 864 | struct heci_cb_private *priv_cb_pos = NULL; | ||
| 865 | struct heci_cb_private *priv_cb_next = NULL; | ||
| 866 | struct heci_file_private *file_ext_list_temp; | ||
| 867 | |||
| 868 | if (dev->read_list.status == 0 | ||
| 869 | && !list_empty(&dev->read_list.heci_cb.cb_list)) { | ||
| 870 | DBG("remove read_list CB \n"); | ||
| 871 | list_for_each_entry_safe(priv_cb_pos, | ||
| 872 | priv_cb_next, | ||
| 873 | &dev->read_list.heci_cb.cb_list, cb_list) { | ||
| 874 | |||
| 875 | file_ext_list_temp = (struct heci_file_private *) | ||
| 876 | priv_cb_pos->file_private; | ||
| 877 | |||
| 878 | if ((file_ext_list_temp != NULL) && | ||
| 879 | heci_fe_same_id(file_ext, file_ext_list_temp)) | ||
| 880 | return priv_cb_pos; | ||
| 881 | |||
| 882 | } | ||
| 883 | } | ||
| 884 | return NULL; | ||
| 885 | } | ||
| 886 | |||
| 887 | /** | ||
| 888 | * heci_read - the read client message function. | ||
| 889 | * | ||
| 890 | * @file: pointer to file structure | ||
| 891 | * @ubuf: pointer to user buffer | ||
| 892 | * @length: buffer length | ||
| 893 | * @offset: data offset in buffer | ||
| 894 | * | ||
| 895 | * returns >=0 data length on success , <0 on error | ||
| 896 | */ | ||
| 897 | static ssize_t heci_read(struct file *file, char __user *ubuf, | ||
| 898 | size_t length, loff_t *offset) | ||
| 899 | { | ||
| 900 | int i; | ||
| 901 | int rets = 0, err = 0; | ||
| 902 | int if_num = iminor(file->f_dentry->d_inode); | ||
| 903 | struct heci_file_private *file_ext = file->private_data; | ||
| 904 | struct heci_cb_private *priv_cb_pos = NULL; | ||
| 905 | struct heci_cb_private *priv_cb = NULL; | ||
| 906 | struct iamt_heci_device *dev; | ||
| 907 | |||
| 908 | if (!heci_device) | ||
| 909 | return -ENODEV; | ||
| 910 | |||
| 911 | dev = pci_get_drvdata(heci_device); | ||
| 912 | if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) | ||
| 913 | return -ENODEV; | ||
| 914 | |||
| 915 | spin_lock_bh(&dev->device_lock); | ||
| 916 | if (dev->heci_state != HECI_ENABLED) { | ||
| 917 | spin_unlock_bh(&dev->device_lock); | ||
| 918 | return -ENODEV; | ||
| 919 | } | ||
| 920 | spin_unlock_bh(&dev->device_lock); | ||
| 921 | |||
| 922 | spin_lock(&file_ext->file_lock); | ||
| 923 | if ((file_ext->sm_state & HECI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) { | ||
| 924 | spin_unlock(&file_ext->file_lock); | ||
| 925 | /* Do not allow to read watchdog client */ | ||
| 926 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 927 | if (memcmp(&heci_wd_guid, | ||
| 928 | &dev->me_clients[i].props.protocol_name, | ||
| 929 | sizeof(struct guid)) == 0) { | ||
| 930 | if (file_ext->me_client_id == | ||
| 931 | dev->me_clients[i].client_id) | ||
| 932 | return -EBADF; | ||
| 933 | } | ||
| 934 | } | ||
| 935 | } else { | ||
| 936 | file_ext->sm_state &= ~HECI_WD_STATE_INDEPENDENCE_MSG_SENT; | ||
| 937 | spin_unlock(&file_ext->file_lock); | ||
| 938 | } | ||
| 939 | |||
| 940 | if (file_ext == &dev->iamthif_file_ext) { | ||
| 941 | rets = pthi_read(dev, if_num, file, ubuf, length, offset); | ||
| 942 | goto out; | ||
| 943 | } | ||
| 944 | |||
| 945 | if (file_ext->read_cb && file_ext->read_cb->information > *offset) { | ||
| 946 | priv_cb = file_ext->read_cb; | ||
| 947 | goto copy_buffer; | ||
| 948 | } else if (file_ext->read_cb && file_ext->read_cb->information > 0 && | ||
| 949 | file_ext->read_cb->information <= *offset) { | ||
| 950 | priv_cb = file_ext->read_cb; | ||
| 951 | rets = 0; | ||
| 952 | goto free; | ||
| 953 | } else if ((!file_ext->read_cb || file_ext->read_cb->information == 0) | ||
| 954 | && *offset > 0) { | ||
| 955 | /*Offset needs to be cleaned for contingous reads*/ | ||
| 956 | *offset = 0; | ||
| 957 | rets = 0; | ||
| 958 | goto out; | ||
| 959 | } | ||
| 960 | |||
| 961 | err = heci_start_read(dev, if_num, file_ext); | ||
| 962 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 963 | if (err != 0 && err != -EBUSY) { | ||
| 964 | DBG("heci start read failure with status = %d\n", err); | ||
| 965 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 966 | rets = err; | ||
| 967 | goto out; | ||
| 968 | } | ||
| 969 | if (HECI_READ_COMPLETE != file_ext->reading_state | ||
| 970 | && !waitqueue_active(&file_ext->rx_wait)) { | ||
| 971 | if (file->f_flags & O_NONBLOCK) { | ||
| 972 | rets = -EAGAIN; | ||
| 973 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 974 | goto out; | ||
| 975 | } | ||
| 976 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 977 | |||
| 978 | if (wait_event_interruptible(file_ext->rx_wait, | ||
| 979 | (HECI_READ_COMPLETE == file_ext->reading_state | ||
| 980 | || HECI_FILE_INITIALIZING == file_ext->state | ||
| 981 | || HECI_FILE_DISCONNECTED == file_ext->state | ||
| 982 | || HECI_FILE_DISCONNECTING == file_ext->state))) { | ||
| 983 | if (signal_pending(current)) { | ||
| 984 | rets = -EINTR; | ||
| 985 | goto out; | ||
| 986 | } | ||
| 987 | return -ERESTARTSYS; | ||
| 988 | } | ||
| 989 | |||
| 990 | spin_lock_bh(&dev->device_lock); | ||
| 991 | if (HECI_FILE_INITIALIZING == file_ext->state || | ||
| 992 | HECI_FILE_DISCONNECTED == file_ext->state || | ||
| 993 | HECI_FILE_DISCONNECTING == file_ext->state) { | ||
| 994 | spin_unlock_bh(&dev->device_lock); | ||
| 995 | rets = -EBUSY; | ||
| 996 | goto out; | ||
| 997 | } | ||
| 998 | spin_unlock_bh(&dev->device_lock); | ||
| 999 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | priv_cb = file_ext->read_cb; | ||
| 1003 | |||
| 1004 | if (!priv_cb) { | ||
| 1005 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 1006 | return -ENODEV; | ||
| 1007 | } | ||
| 1008 | if (file_ext->reading_state != HECI_READ_COMPLETE) { | ||
| 1009 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 1010 | return 0; | ||
| 1011 | } | ||
| 1012 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 1013 | /* now copy the data to user space */ | ||
| 1014 | copy_buffer: | ||
| 1015 | DBG("priv_cb->response_buffer size - %d\n", | ||
| 1016 | priv_cb->response_buffer.size); | ||
| 1017 | DBG("priv_cb->information - %lu\n", | ||
| 1018 | priv_cb->information); | ||
| 1019 | if (length == 0 || ubuf == NULL || | ||
| 1020 | *offset > priv_cb->information) { | ||
| 1021 | rets = -EMSGSIZE; | ||
| 1022 | goto free; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | /* length is being turncated to PAGE_SIZE, however, */ | ||
| 1026 | /* information size may be longer */ | ||
| 1027 | length = (length < (priv_cb->information - *offset) ? | ||
| 1028 | length : (priv_cb->information - *offset)); | ||
| 1029 | |||
| 1030 | if (copy_to_user(ubuf, | ||
| 1031 | priv_cb->response_buffer.data + *offset, | ||
| 1032 | length)) { | ||
| 1033 | rets = -EFAULT; | ||
| 1034 | goto free; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | rets = length; | ||
| 1038 | *offset += length; | ||
| 1039 | if ((unsigned long)*offset < priv_cb->information) | ||
| 1040 | goto out; | ||
| 1041 | |||
| 1042 | free: | ||
| 1043 | spin_lock_bh(&dev->device_lock); | ||
| 1044 | priv_cb_pos = find_read_list_entry(dev, file_ext); | ||
| 1045 | /* Remove entry from read list */ | ||
| 1046 | if (priv_cb_pos != NULL) | ||
| 1047 | list_del(&priv_cb_pos->cb_list); | ||
| 1048 | spin_unlock_bh(&dev->device_lock); | ||
| 1049 | heci_free_cb_private(priv_cb); | ||
| 1050 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 1051 | file_ext->reading_state = HECI_IDLE; | ||
| 1052 | file_ext->read_cb = NULL; | ||
| 1053 | file_ext->read_pending = 0; | ||
| 1054 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 1055 | out: DBG("end heci read rets= %d\n", rets); | ||
| 1056 | return rets; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | /** | ||
| 1060 | * heci_write - the write function. | ||
| 1061 | * | ||
| 1062 | * @file: pointer to file structure | ||
| 1063 | * @ubuf: pointer to user buffer | ||
| 1064 | * @length: buffer length | ||
| 1065 | * @offset: data offset in buffer | ||
| 1066 | * | ||
| 1067 | * returns >=0 data length on success , <0 on error | ||
| 1068 | */ | ||
| 1069 | static ssize_t heci_write(struct file *file, const char __user *ubuf, | ||
| 1070 | size_t length, loff_t *offset) | ||
| 1071 | { | ||
| 1072 | int rets = 0; | ||
| 1073 | __u8 i; | ||
| 1074 | int if_num = iminor(file->f_dentry->d_inode); | ||
| 1075 | struct heci_file_private *file_ext = file->private_data; | ||
| 1076 | struct heci_cb_private *priv_write_cb = NULL; | ||
| 1077 | struct heci_msg_hdr heci_hdr; | ||
| 1078 | struct iamt_heci_device *dev; | ||
| 1079 | unsigned long currtime = get_seconds(); | ||
| 1080 | |||
| 1081 | if (!heci_device) | ||
| 1082 | return -ENODEV; | ||
| 1083 | |||
| 1084 | dev = pci_get_drvdata(heci_device); | ||
| 1085 | |||
| 1086 | if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) | ||
| 1087 | return -ENODEV; | ||
| 1088 | |||
| 1089 | spin_lock_bh(&dev->device_lock); | ||
| 1090 | |||
| 1091 | if (dev->heci_state != HECI_ENABLED) { | ||
| 1092 | spin_unlock_bh(&dev->device_lock); | ||
| 1093 | return -ENODEV; | ||
| 1094 | } | ||
| 1095 | if (file_ext == &dev->iamthif_file_ext) { | ||
| 1096 | priv_write_cb = find_pthi_read_list_entry(dev, file); | ||
| 1097 | if ((priv_write_cb != NULL) && | ||
| 1098 | (((currtime - priv_write_cb->read_time) >= | ||
| 1099 | IAMTHIF_READ_TIMER) || | ||
| 1100 | (file_ext->reading_state == HECI_READ_COMPLETE))) { | ||
| 1101 | (*offset) = 0; | ||
| 1102 | list_del(&priv_write_cb->cb_list); | ||
| 1103 | heci_free_cb_private(priv_write_cb); | ||
| 1104 | priv_write_cb = NULL; | ||
| 1105 | } | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | /* free entry used in read */ | ||
| 1109 | if (file_ext->reading_state == HECI_READ_COMPLETE) { | ||
| 1110 | *offset = 0; | ||
| 1111 | priv_write_cb = find_read_list_entry(dev, file_ext); | ||
| 1112 | if (priv_write_cb != NULL) { | ||
| 1113 | list_del(&priv_write_cb->cb_list); | ||
| 1114 | heci_free_cb_private(priv_write_cb); | ||
| 1115 | priv_write_cb = NULL; | ||
| 1116 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 1117 | file_ext->reading_state = HECI_IDLE; | ||
| 1118 | file_ext->read_cb = NULL; | ||
| 1119 | file_ext->read_pending = 0; | ||
| 1120 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 1121 | } | ||
| 1122 | } else if (file_ext->reading_state == HECI_IDLE && | ||
| 1123 | file_ext->read_pending == 0) | ||
| 1124 | (*offset) = 0; | ||
| 1125 | |||
| 1126 | spin_unlock_bh(&dev->device_lock); | ||
| 1127 | |||
| 1128 | priv_write_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL); | ||
| 1129 | if (!priv_write_cb) | ||
| 1130 | return -ENOMEM; | ||
| 1131 | |||
| 1132 | priv_write_cb->file_object = file; | ||
| 1133 | priv_write_cb->file_private = file_ext; | ||
| 1134 | priv_write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); | ||
| 1135 | if (!priv_write_cb->request_buffer.data) { | ||
| 1136 | kfree(priv_write_cb); | ||
| 1137 | return -ENOMEM; | ||
| 1138 | } | ||
| 1139 | DBG("length =%d\n", (int) length); | ||
| 1140 | |||
| 1141 | if (copy_from_user(priv_write_cb->request_buffer.data, | ||
| 1142 | ubuf, length)) { | ||
| 1143 | rets = -EFAULT; | ||
| 1144 | goto fail; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | spin_lock(&file_ext->file_lock); | ||
| 1148 | file_ext->sm_state = 0; | ||
| 1149 | if ((length == 4) && | ||
| 1150 | ((memcmp(heci_wd_state_independence_msg[0], | ||
| 1151 | priv_write_cb->request_buffer.data, 4) == 0) || | ||
| 1152 | (memcmp(heci_wd_state_independence_msg[1], | ||
| 1153 | priv_write_cb->request_buffer.data, 4) == 0) || | ||
| 1154 | (memcmp(heci_wd_state_independence_msg[2], | ||
| 1155 | priv_write_cb->request_buffer.data, 4) == 0))) | ||
| 1156 | file_ext->sm_state |= HECI_WD_STATE_INDEPENDENCE_MSG_SENT; | ||
| 1157 | spin_unlock(&file_ext->file_lock); | ||
| 1158 | |||
| 1159 | INIT_LIST_HEAD(&priv_write_cb->cb_list); | ||
| 1160 | if (file_ext == &dev->iamthif_file_ext) { | ||
| 1161 | priv_write_cb->response_buffer.data = | ||
| 1162 | kmalloc(IAMTHIF_MTU, GFP_KERNEL); | ||
| 1163 | if (!priv_write_cb->response_buffer.data) { | ||
| 1164 | rets = -ENOMEM; | ||
| 1165 | goto fail; | ||
| 1166 | } | ||
| 1167 | spin_lock_bh(&dev->device_lock); | ||
| 1168 | if (dev->heci_state != HECI_ENABLED) { | ||
| 1169 | spin_unlock_bh(&dev->device_lock); | ||
| 1170 | rets = -ENODEV; | ||
| 1171 | goto fail; | ||
| 1172 | } | ||
| 1173 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 1174 | if (dev->me_clients[i].client_id == | ||
| 1175 | dev->iamthif_file_ext.me_client_id) | ||
| 1176 | break; | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); | ||
| 1180 | if ((i == dev->num_heci_me_clients) || | ||
| 1181 | (dev->me_clients[i].client_id != | ||
| 1182 | dev->iamthif_file_ext.me_client_id)) { | ||
| 1183 | |||
| 1184 | spin_unlock_bh(&dev->device_lock); | ||
| 1185 | rets = -ENODEV; | ||
| 1186 | goto fail; | ||
| 1187 | } else if ((length > dev->me_clients[i].props.max_msg_length) | ||
| 1188 | || (length <= 0)) { | ||
| 1189 | spin_unlock_bh(&dev->device_lock); | ||
| 1190 | rets = -EMSGSIZE; | ||
| 1191 | goto fail; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | |||
| 1195 | priv_write_cb->response_buffer.size = IAMTHIF_MTU; | ||
| 1196 | priv_write_cb->major_file_operations = HECI_IOCTL; | ||
| 1197 | priv_write_cb->information = 0; | ||
| 1198 | priv_write_cb->request_buffer.size = length; | ||
| 1199 | if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) { | ||
| 1200 | spin_unlock_bh(&dev->device_lock); | ||
| 1201 | rets = -ENODEV; | ||
| 1202 | goto fail; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | if (!list_empty(&dev->pthi_cmd_list.heci_cb.cb_list) | ||
| 1206 | || dev->iamthif_state != HECI_IAMTHIF_IDLE) { | ||
| 1207 | DBG("pthi_state = %d\n", (int) dev->iamthif_state); | ||
| 1208 | DBG("add PTHI cb to pthi cmd waiting list\n"); | ||
| 1209 | list_add_tail(&priv_write_cb->cb_list, | ||
| 1210 | &dev->pthi_cmd_list.heci_cb.cb_list); | ||
| 1211 | rets = length; | ||
| 1212 | } else { | ||
| 1213 | DBG("call pthi write\n"); | ||
| 1214 | rets = pthi_write(dev, priv_write_cb); | ||
| 1215 | |||
| 1216 | if (rets != 0) { | ||
| 1217 | DBG("pthi write failed with status = %d\n", | ||
| 1218 | rets); | ||
| 1219 | spin_unlock_bh(&dev->device_lock); | ||
| 1220 | goto fail; | ||
| 1221 | } | ||
| 1222 | rets = length; | ||
| 1223 | } | ||
| 1224 | spin_unlock_bh(&dev->device_lock); | ||
| 1225 | return rets; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | priv_write_cb->major_file_operations = HECI_WRITE; | ||
| 1229 | /* make sure information is zero before we start */ | ||
| 1230 | |||
| 1231 | priv_write_cb->information = 0; | ||
| 1232 | priv_write_cb->request_buffer.size = length; | ||
| 1233 | |||
| 1234 | spin_lock(&file_ext->write_io_lock); | ||
| 1235 | spin_lock_bh(&dev->device_lock); | ||
| 1236 | DBG("host client = %d, ME client = %d\n", | ||
| 1237 | file_ext->host_client_id, file_ext->me_client_id); | ||
| 1238 | if (file_ext->state != HECI_FILE_CONNECTED) { | ||
| 1239 | rets = -ENODEV; | ||
| 1240 | DBG("host client = %d, is not connected to ME client = %d", | ||
| 1241 | file_ext->host_client_id, | ||
| 1242 | file_ext->me_client_id); | ||
| 1243 | spin_unlock_bh(&dev->device_lock); | ||
| 1244 | goto unlock; | ||
| 1245 | } | ||
| 1246 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 1247 | if (dev->me_clients[i].client_id == | ||
| 1248 | file_ext->me_client_id) | ||
| 1249 | break; | ||
| 1250 | } | ||
| 1251 | BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); | ||
| 1252 | if (i == dev->num_heci_me_clients) { | ||
| 1253 | rets = -ENODEV; | ||
| 1254 | spin_unlock_bh(&dev->device_lock); | ||
| 1255 | goto unlock; | ||
| 1256 | } | ||
| 1257 | if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { | ||
| 1258 | rets = -EINVAL; | ||
| 1259 | spin_unlock_bh(&dev->device_lock); | ||
| 1260 | goto unlock; | ||
| 1261 | } | ||
| 1262 | priv_write_cb->file_private = file_ext; | ||
| 1263 | |||
| 1264 | if (flow_ctrl_creds(dev, file_ext) && | ||
| 1265 | dev->host_buffer_is_empty) { | ||
| 1266 | spin_unlock_bh(&dev->device_lock); | ||
| 1267 | dev->host_buffer_is_empty = 0; | ||
| 1268 | if (length > ((((dev->host_hw_state & H_CBD) >> 24) * | ||
| 1269 | sizeof(__u32)) - sizeof(struct heci_msg_hdr))) { | ||
| 1270 | |||
| 1271 | heci_hdr.length = | ||
| 1272 | (((dev->host_hw_state & H_CBD) >> 24) * | ||
| 1273 | sizeof(__u32)) - | ||
| 1274 | sizeof(struct heci_msg_hdr); | ||
| 1275 | heci_hdr.msg_complete = 0; | ||
| 1276 | } else { | ||
| 1277 | heci_hdr.length = length; | ||
| 1278 | heci_hdr.msg_complete = 1; | ||
| 1279 | } | ||
| 1280 | heci_hdr.host_addr = file_ext->host_client_id; | ||
| 1281 | heci_hdr.me_addr = file_ext->me_client_id; | ||
| 1282 | heci_hdr.reserved = 0; | ||
| 1283 | DBG("call heci_write_message header=%08x.\n", | ||
| 1284 | *((__u32 *) &heci_hdr)); | ||
| 1285 | spin_unlock(&file_ext->write_io_lock); | ||
| 1286 | /* protect heci low level write */ | ||
| 1287 | spin_lock_bh(&dev->device_lock); | ||
| 1288 | if (!heci_write_message(dev, &heci_hdr, | ||
| 1289 | (unsigned char *) (priv_write_cb->request_buffer.data), | ||
| 1290 | heci_hdr.length)) { | ||
| 1291 | |||
| 1292 | spin_unlock_bh(&dev->device_lock); | ||
| 1293 | heci_free_cb_private(priv_write_cb); | ||
| 1294 | rets = -ENODEV; | ||
| 1295 | priv_write_cb->information = 0; | ||
| 1296 | return rets; | ||
| 1297 | } | ||
| 1298 | file_ext->writing_state = HECI_WRITING; | ||
| 1299 | priv_write_cb->information = heci_hdr.length; | ||
| 1300 | if (heci_hdr.msg_complete) { | ||
| 1301 | flow_ctrl_reduce(dev, file_ext); | ||
| 1302 | list_add_tail(&priv_write_cb->cb_list, | ||
| 1303 | &dev->write_waiting_list.heci_cb.cb_list); | ||
| 1304 | } else { | ||
| 1305 | list_add_tail(&priv_write_cb->cb_list, | ||
| 1306 | &dev->write_list.heci_cb.cb_list); | ||
| 1307 | } | ||
| 1308 | spin_unlock_bh(&dev->device_lock); | ||
| 1309 | |||
| 1310 | } else { | ||
| 1311 | |||
| 1312 | spin_unlock_bh(&dev->device_lock); | ||
| 1313 | priv_write_cb->information = 0; | ||
| 1314 | file_ext->writing_state = HECI_WRITING; | ||
| 1315 | spin_unlock(&file_ext->write_io_lock); | ||
| 1316 | list_add_tail(&priv_write_cb->cb_list, | ||
| 1317 | &dev->write_list.heci_cb.cb_list); | ||
| 1318 | } | ||
| 1319 | return length; | ||
| 1320 | |||
| 1321 | unlock: | ||
| 1322 | spin_unlock(&file_ext->write_io_lock); | ||
| 1323 | fail: | ||
| 1324 | heci_free_cb_private(priv_write_cb); | ||
| 1325 | return rets; | ||
| 1326 | |||
| 1327 | } | ||
| 1328 | |||
| 1329 | /** | ||
| 1330 | * heci_ioctl - the IOCTL function | ||
| 1331 | * | ||
| 1332 | * @inode: pointer to inode structure | ||
| 1333 | * @file: pointer to file structure | ||
| 1334 | * @cmd: ioctl command | ||
| 1335 | * @data: pointer to heci message structure | ||
| 1336 | * | ||
| 1337 | * returns 0 on success , <0 on error | ||
| 1338 | */ | ||
| 1339 | static int heci_ioctl(struct inode *inode, struct file *file, | ||
| 1340 | unsigned int cmd, unsigned long data) | ||
| 1341 | { | ||
| 1342 | int rets = 0; | ||
| 1343 | int if_num = iminor(inode); | ||
| 1344 | struct heci_file_private *file_ext = file->private_data; | ||
| 1345 | /* in user space */ | ||
| 1346 | struct heci_message_data __user *u_msg; | ||
| 1347 | struct heci_message_data k_msg; /* all in kernel on the stack */ | ||
| 1348 | struct iamt_heci_device *dev; | ||
| 1349 | |||
| 1350 | if (!capable(CAP_SYS_ADMIN)) | ||
| 1351 | return -EPERM; | ||
| 1352 | |||
| 1353 | if (!heci_device) | ||
| 1354 | return -ENODEV; | ||
| 1355 | |||
| 1356 | dev = pci_get_drvdata(heci_device); | ||
| 1357 | if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) | ||
| 1358 | return -ENODEV; | ||
| 1359 | |||
| 1360 | spin_lock_bh(&dev->device_lock); | ||
| 1361 | if (dev->heci_state != HECI_ENABLED) { | ||
| 1362 | spin_unlock_bh(&dev->device_lock); | ||
| 1363 | return -ENODEV; | ||
| 1364 | } | ||
| 1365 | spin_unlock_bh(&dev->device_lock); | ||
| 1366 | |||
| 1367 | /* first copy from user all data needed */ | ||
| 1368 | u_msg = (struct heci_message_data __user *)data; | ||
| 1369 | if (copy_from_user(&k_msg, u_msg, sizeof(k_msg))) { | ||
| 1370 | DBG("first copy from user all data needed filled\n"); | ||
| 1371 | return -EFAULT; | ||
| 1372 | } | ||
| 1373 | DBG("user message size is %d\n", k_msg.size); | ||
| 1374 | |||
| 1375 | switch (cmd) { | ||
| 1376 | case IOCTL_HECI_GET_VERSION: | ||
| 1377 | DBG(": IOCTL_HECI_GET_VERSION\n"); | ||
| 1378 | rets = heci_ioctl_get_version(dev, if_num, u_msg, k_msg, | ||
| 1379 | file_ext); | ||
| 1380 | break; | ||
| 1381 | |||
| 1382 | case IOCTL_HECI_CONNECT_CLIENT: | ||
| 1383 | DBG(": IOCTL_HECI_CONNECT_CLIENT.\n"); | ||
| 1384 | rets = heci_ioctl_connect_client(dev, if_num, u_msg, k_msg, | ||
| 1385 | file); | ||
| 1386 | break; | ||
| 1387 | |||
| 1388 | case IOCTL_HECI_WD: | ||
| 1389 | DBG(": IOCTL_HECI_WD.\n"); | ||
| 1390 | rets = heci_ioctl_wd(dev, if_num, k_msg, file_ext); | ||
| 1391 | break; | ||
| 1392 | |||
| 1393 | case IOCTL_HECI_BYPASS_WD: | ||
| 1394 | DBG(": IOCTL_HECI_BYPASS_WD.\n"); | ||
| 1395 | rets = heci_ioctl_bypass_wd(dev, if_num, k_msg, file_ext); | ||
| 1396 | break; | ||
| 1397 | |||
| 1398 | default: | ||
| 1399 | rets = -EINVAL; | ||
| 1400 | break; | ||
| 1401 | } | ||
| 1402 | return rets; | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | /** | ||
| 1406 | * heci_poll - the poll function | ||
| 1407 | * | ||
| 1408 | * @file: pointer to file structure | ||
| 1409 | * @wait: pointer to poll_table structure | ||
| 1410 | * | ||
| 1411 | * returns poll mask | ||
| 1412 | */ | ||
| 1413 | static unsigned int heci_poll(struct file *file, poll_table *wait) | ||
| 1414 | { | ||
| 1415 | int if_num = iminor(file->f_dentry->d_inode); | ||
| 1416 | unsigned int mask = 0; | ||
| 1417 | struct heci_file_private *file_ext = file->private_data; | ||
| 1418 | struct iamt_heci_device *dev; | ||
| 1419 | |||
| 1420 | if (!heci_device) | ||
| 1421 | return mask; | ||
| 1422 | |||
| 1423 | dev = pci_get_drvdata(heci_device); | ||
| 1424 | |||
| 1425 | if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) | ||
| 1426 | return mask; | ||
| 1427 | |||
| 1428 | spin_lock_bh(&dev->device_lock); | ||
| 1429 | if (dev->heci_state != HECI_ENABLED) { | ||
| 1430 | spin_unlock_bh(&dev->device_lock); | ||
| 1431 | return mask; | ||
| 1432 | } | ||
| 1433 | spin_unlock_bh(&dev->device_lock); | ||
| 1434 | |||
| 1435 | if (file_ext == &dev->iamthif_file_ext) { | ||
| 1436 | poll_wait(file, &dev->iamthif_file_ext.wait, wait); | ||
| 1437 | spin_lock(&dev->iamthif_file_ext.file_lock); | ||
| 1438 | if (dev->iamthif_state == HECI_IAMTHIF_READ_COMPLETE | ||
| 1439 | && dev->iamthif_file_object == file) { | ||
| 1440 | mask |= (POLLIN | POLLRDNORM); | ||
| 1441 | spin_lock_bh(&dev->device_lock); | ||
| 1442 | DBG("run next pthi cb\n"); | ||
| 1443 | run_next_iamthif_cmd(dev); | ||
| 1444 | spin_unlock_bh(&dev->device_lock); | ||
| 1445 | } | ||
| 1446 | spin_unlock(&dev->iamthif_file_ext.file_lock); | ||
| 1447 | |||
| 1448 | } else{ | ||
| 1449 | poll_wait(file, &file_ext->tx_wait, wait); | ||
| 1450 | spin_lock(&file_ext->write_io_lock); | ||
| 1451 | if (HECI_WRITE_COMPLETE == file_ext->writing_state) | ||
| 1452 | mask |= (POLLIN | POLLRDNORM); | ||
| 1453 | |||
| 1454 | spin_unlock(&file_ext->write_io_lock); | ||
| 1455 | } | ||
| 1456 | |||
| 1457 | return mask; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | #ifdef CONFIG_PM | ||
| 1461 | static int heci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
| 1462 | { | ||
| 1463 | struct iamt_heci_device *dev = pci_get_drvdata(pdev); | ||
| 1464 | int err = 0; | ||
| 1465 | |||
| 1466 | spin_lock_bh(&dev->device_lock); | ||
| 1467 | if (dev->reinit_tsk != NULL) { | ||
| 1468 | kthread_stop(dev->reinit_tsk); | ||
| 1469 | dev->reinit_tsk = NULL; | ||
| 1470 | } | ||
| 1471 | spin_unlock_bh(&dev->device_lock); | ||
| 1472 | |||
| 1473 | /* Stop watchdog if exists */ | ||
| 1474 | del_timer_sync(&dev->wd_timer); | ||
| 1475 | if (dev->wd_file_ext.state == HECI_FILE_CONNECTED | ||
| 1476 | && dev->wd_timeout) { | ||
| 1477 | spin_lock_bh(&dev->device_lock); | ||
| 1478 | g_sus_wd_timeout = dev->wd_timeout; | ||
| 1479 | dev->wd_timeout = 0; | ||
| 1480 | dev->wd_due_counter = 0; | ||
| 1481 | memcpy(dev->wd_data, heci_stop_wd_params, | ||
| 1482 | HECI_WD_PARAMS_SIZE); | ||
| 1483 | dev->stop = 1; | ||
| 1484 | if (dev->host_buffer_is_empty && | ||
| 1485 | flow_ctrl_creds(dev, &dev->wd_file_ext)) { | ||
| 1486 | dev->host_buffer_is_empty = 0; | ||
| 1487 | if (!heci_send_wd(dev)) | ||
| 1488 | DBG("send stop WD failed\n"); | ||
| 1489 | else | ||
| 1490 | flow_ctrl_reduce(dev, &dev->wd_file_ext); | ||
| 1491 | |||
| 1492 | dev->wd_pending = 0; | ||
| 1493 | } else { | ||
| 1494 | dev->wd_pending = 1; | ||
| 1495 | } | ||
| 1496 | spin_unlock_bh(&dev->device_lock); | ||
| 1497 | dev->wd_stoped = 0; | ||
| 1498 | |||
| 1499 | err = wait_event_interruptible_timeout(dev->wait_stop_wd, | ||
| 1500 | (dev->wd_stoped), | ||
| 1501 | 10 * HZ); | ||
| 1502 | if (!dev->wd_stoped) | ||
| 1503 | DBG("stop wd failed to complete.\n"); | ||
| 1504 | else { | ||
| 1505 | DBG("stop wd complete %d.\n", err); | ||
| 1506 | err = 0; | ||
| 1507 | } | ||
| 1508 | } | ||
| 1509 | /* Set new heci state */ | ||
| 1510 | spin_lock_bh(&dev->device_lock); | ||
| 1511 | if (dev->heci_state == HECI_ENABLED || | ||
| 1512 | dev->heci_state == HECI_RECOVERING_FROM_RESET) { | ||
| 1513 | dev->heci_state = HECI_POWER_DOWN; | ||
| 1514 | heci_reset(dev, 0); | ||
| 1515 | } | ||
| 1516 | spin_unlock_bh(&dev->device_lock); | ||
| 1517 | |||
| 1518 | pci_save_state(pdev); | ||
| 1519 | |||
| 1520 | pci_disable_device(pdev); | ||
| 1521 | free_irq(pdev->irq, dev); | ||
| 1522 | |||
| 1523 | pci_set_power_state(pdev, PCI_D3hot); | ||
| 1524 | |||
| 1525 | return err; | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | static int heci_resume(struct pci_dev *pdev) | ||
| 1529 | { | ||
| 1530 | struct iamt_heci_device *dev; | ||
| 1531 | int err = 0; | ||
| 1532 | |||
| 1533 | pci_set_power_state(pdev, PCI_D0); | ||
| 1534 | pci_restore_state(pdev); | ||
| 1535 | |||
| 1536 | dev = pci_get_drvdata(pdev); | ||
| 1537 | if (!dev) | ||
| 1538 | return -ENODEV; | ||
| 1539 | |||
| 1540 | /* request and enable interrupt */ | ||
| 1541 | err = request_irq(pdev->irq, heci_isr_interrupt, IRQF_SHARED, | ||
| 1542 | heci_driver_name, dev); | ||
| 1543 | if (err) { | ||
| 1544 | printk(KERN_ERR "heci: Request_irq failure. irq = %d \n", | ||
| 1545 | pdev->irq); | ||
| 1546 | return err; | ||
| 1547 | } | ||
| 1548 | |||
| 1549 | spin_lock_bh(&dev->device_lock); | ||
| 1550 | dev->heci_state = HECI_POWER_UP; | ||
| 1551 | heci_reset(dev, 1); | ||
| 1552 | spin_unlock_bh(&dev->device_lock); | ||
| 1553 | |||
| 1554 | /* Start watchdog if stopped in suspend */ | ||
| 1555 | if (g_sus_wd_timeout != 0) { | ||
| 1556 | dev->wd_timeout = g_sus_wd_timeout; | ||
| 1557 | |||
| 1558 | memcpy(dev->wd_data, heci_start_wd_params, | ||
| 1559 | HECI_WD_PARAMS_SIZE); | ||
| 1560 | memcpy(dev->wd_data + HECI_WD_PARAMS_SIZE, | ||
| 1561 | &dev->wd_timeout, sizeof(__u16)); | ||
| 1562 | dev->wd_due_counter = 1; | ||
| 1563 | |||
| 1564 | if (dev->wd_timeout) | ||
| 1565 | mod_timer(&dev->wd_timer, jiffies); | ||
| 1566 | |||
| 1567 | g_sus_wd_timeout = 0; | ||
| 1568 | } | ||
| 1569 | return err; | ||
| 1570 | } | ||
| 1571 | #endif | ||
| 1572 | |||
| 1573 | MODULE_AUTHOR("Intel Corporation"); | ||
| 1574 | MODULE_DESCRIPTION("Intel(R) Management Engine Interface"); | ||
| 1575 | MODULE_LICENSE("Dual BSD/GPL"); | ||
| 1576 | MODULE_VERSION(HECI_DRIVER_VERSION); | ||
diff --git a/drivers/staging/heci/heci_version.h b/drivers/staging/heci/heci_version.h deleted file mode 100644 index 3007aa6e17d4..000000000000 --- a/drivers/staging/heci/heci_version.h +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | #ifndef HECI_VERSION_H | ||
| 42 | #define HECI_VERSION_H | ||
| 43 | |||
| 44 | #define MAJOR_VERSION 5 | ||
| 45 | #define MINOR_VERSION 0 | ||
| 46 | #define QUICK_FIX_NUMBER 0 | ||
| 47 | #define VER_BUILD 31 | ||
| 48 | |||
| 49 | #define HECI_DRV_VER1 __stringify(MAJOR_VERSION) "." __stringify(MINOR_VERSION) | ||
| 50 | #define HECI_DRV_VER2 __stringify(QUICK_FIX_NUMBER) "." __stringify(VER_BUILD) | ||
| 51 | |||
| 52 | #define HECI_DRIVER_VERSION HECI_DRV_VER1 "." HECI_DRV_VER2 | ||
| 53 | |||
| 54 | #endif | ||
diff --git a/drivers/staging/heci/interrupt.c b/drivers/staging/heci/interrupt.c deleted file mode 100644 index 2a3a01a62bbf..000000000000 --- a/drivers/staging/heci/interrupt.c +++ /dev/null | |||
| @@ -1,1555 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | #include <linux/kthread.h> | ||
| 42 | |||
| 43 | #include "heci.h" | ||
| 44 | #include "heci_interface.h" | ||
| 45 | |||
| 46 | /* | ||
| 47 | * interrupt function prototypes | ||
| 48 | */ | ||
| 49 | static void heci_bh_handler(struct work_struct *work); | ||
| 50 | static int heci_bh_read_handler(struct io_heci_list *complete_list, | ||
| 51 | struct iamt_heci_device *dev, | ||
| 52 | __s32 *slots); | ||
| 53 | static int heci_bh_write_handler(struct io_heci_list *complete_list, | ||
| 54 | struct iamt_heci_device *dev, | ||
| 55 | __s32 *slots); | ||
| 56 | static void heci_bh_read_bus_message(struct iamt_heci_device *dev, | ||
| 57 | struct heci_msg_hdr *heci_hdr); | ||
| 58 | static int heci_bh_read_pthi_message(struct io_heci_list *complete_list, | ||
| 59 | struct iamt_heci_device *dev, | ||
| 60 | struct heci_msg_hdr *heci_hdr); | ||
| 61 | static int heci_bh_read_client_message(struct io_heci_list *complete_list, | ||
| 62 | struct iamt_heci_device *dev, | ||
| 63 | struct heci_msg_hdr *heci_hdr); | ||
| 64 | static void heci_client_connect_response(struct iamt_heci_device *dev, | ||
| 65 | struct hbm_client_connect_response *connect_res); | ||
| 66 | static void heci_client_disconnect_response(struct iamt_heci_device *dev, | ||
| 67 | struct hbm_client_connect_response *disconnect_res); | ||
| 68 | static void heci_client_flow_control_response(struct iamt_heci_device *dev, | ||
| 69 | struct hbm_flow_control *flow_control); | ||
| 70 | static void heci_client_disconnect_request(struct iamt_heci_device *dev, | ||
| 71 | struct hbm_client_disconnect_request *disconnect_req); | ||
| 72 | |||
| 73 | |||
| 74 | /** | ||
| 75 | * heci_isr_interrupt - The ISR of the HECI device | ||
| 76 | * | ||
| 77 | * @irq: The irq number | ||
| 78 | * @dev_id: pointer to the device structure | ||
| 79 | * | ||
| 80 | * returns irqreturn_t | ||
| 81 | */ | ||
| 82 | irqreturn_t heci_isr_interrupt(int irq, void *dev_id) | ||
| 83 | { | ||
| 84 | int err; | ||
| 85 | struct iamt_heci_device *dev = (struct iamt_heci_device *) dev_id; | ||
| 86 | |||
| 87 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 88 | |||
| 89 | if ((dev->host_hw_state & H_IS) != H_IS) | ||
| 90 | return IRQ_NONE; | ||
| 91 | |||
| 92 | /* disable interrupts */ | ||
| 93 | heci_csr_disable_interrupts(dev); | ||
| 94 | |||
| 95 | /* clear H_IS bit in H_CSR */ | ||
| 96 | heci_csr_clear_his(dev); | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Our device interrupted, schedule work the heci_bh_handler | ||
| 100 | * to handle the interrupt processing. This needs to be a | ||
| 101 | * workqueue item since the handler can sleep. | ||
| 102 | */ | ||
| 103 | PREPARE_WORK(&dev->work, heci_bh_handler); | ||
| 104 | DBG("schedule work the heci_bh_handler.\n"); | ||
| 105 | err = schedule_work(&dev->work); | ||
| 106 | if (!err) | ||
| 107 | DBG("heci_bh_handler was already on the workqueue.\n"); | ||
| 108 | return IRQ_HANDLED; | ||
| 109 | } | ||
| 110 | |||
| 111 | /** | ||
| 112 | * _heci_cmpl - process completed operation. | ||
| 113 | * | ||
| 114 | * @file_ext: private data of the file object. | ||
| 115 | * @priv_cb_pos: callback block. | ||
| 116 | */ | ||
| 117 | static void _heci_cmpl(struct heci_file_private *file_ext, | ||
| 118 | struct heci_cb_private *priv_cb_pos) | ||
| 119 | { | ||
| 120 | if (priv_cb_pos->major_file_operations == HECI_WRITE) { | ||
| 121 | heci_free_cb_private(priv_cb_pos); | ||
| 122 | DBG("completing write call back.\n"); | ||
| 123 | file_ext->writing_state = HECI_WRITE_COMPLETE; | ||
| 124 | if ((&file_ext->tx_wait) && | ||
| 125 | waitqueue_active(&file_ext->tx_wait)) | ||
| 126 | wake_up_interruptible(&file_ext->tx_wait); | ||
| 127 | |||
| 128 | } else if (priv_cb_pos->major_file_operations == HECI_READ | ||
| 129 | && HECI_READING == file_ext->reading_state) { | ||
| 130 | DBG("completing read call back information= %lu\n", | ||
| 131 | priv_cb_pos->information); | ||
| 132 | file_ext->reading_state = HECI_READ_COMPLETE; | ||
| 133 | if ((&file_ext->rx_wait) && | ||
| 134 | waitqueue_active(&file_ext->rx_wait)) | ||
| 135 | wake_up_interruptible(&file_ext->rx_wait); | ||
| 136 | |||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * _heci_cmpl_iamthif - process completed iamthif operation. | ||
| 142 | * | ||
| 143 | * @dev: Device object for our driver. | ||
| 144 | * @priv_cb_pos: callback block. | ||
| 145 | */ | ||
| 146 | static void _heci_cmpl_iamthif(struct iamt_heci_device *dev, | ||
| 147 | struct heci_cb_private *priv_cb_pos) | ||
| 148 | { | ||
| 149 | if (dev->iamthif_canceled != 1) { | ||
| 150 | dev->iamthif_state = HECI_IAMTHIF_READ_COMPLETE; | ||
| 151 | dev->iamthif_stall_timer = 0; | ||
| 152 | memcpy(priv_cb_pos->response_buffer.data, | ||
| 153 | dev->iamthif_msg_buf, | ||
| 154 | dev->iamthif_msg_buf_index); | ||
| 155 | list_add_tail(&priv_cb_pos->cb_list, | ||
| 156 | &dev->pthi_read_complete_list.heci_cb.cb_list); | ||
| 157 | DBG("pthi read completed.\n"); | ||
| 158 | } else { | ||
| 159 | run_next_iamthif_cmd(dev); | ||
| 160 | } | ||
| 161 | if (&dev->iamthif_file_ext.wait) { | ||
| 162 | DBG("completing pthi call back.\n"); | ||
| 163 | wake_up_interruptible(&dev->iamthif_file_ext.wait); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | /** | ||
| 167 | * heci_bh_handler - function called after ISR to handle the interrupt | ||
| 168 | * processing. | ||
| 169 | * | ||
| 170 | * @work: pointer to the work structure | ||
| 171 | * | ||
| 172 | * NOTE: This function is called by schedule work | ||
| 173 | */ | ||
| 174 | static void heci_bh_handler(struct work_struct *work) | ||
| 175 | { | ||
| 176 | struct iamt_heci_device *dev = | ||
| 177 | container_of(work, struct iamt_heci_device, work); | ||
| 178 | struct io_heci_list complete_list; | ||
| 179 | __s32 slots; | ||
| 180 | int rets; | ||
| 181 | struct heci_cb_private *cb_pos = NULL, *cb_next = NULL; | ||
| 182 | struct heci_file_private *file_ext; | ||
| 183 | int bus_message_received = 0; | ||
| 184 | struct task_struct *tsk; | ||
| 185 | |||
| 186 | DBG("function called after ISR to handle the interrupt processing.\n"); | ||
| 187 | /* initialize our complete list */ | ||
| 188 | spin_lock_bh(&dev->device_lock); | ||
| 189 | heci_initialize_list(&complete_list, dev); | ||
| 190 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 191 | dev->me_hw_state = read_heci_register(dev, ME_CSR_HA); | ||
| 192 | |||
| 193 | /* check if ME wants a reset */ | ||
| 194 | if (((dev->me_hw_state & ME_RDY_HRA) == 0) | ||
| 195 | && (dev->heci_state != HECI_RESETING) | ||
| 196 | && (dev->heci_state != HECI_INITIALIZING)) { | ||
| 197 | DBG("FW not ready.\n"); | ||
| 198 | heci_reset(dev, 1); | ||
| 199 | spin_unlock_bh(&dev->device_lock); | ||
| 200 | return; | ||
| 201 | } | ||
| 202 | |||
| 203 | /* check if we need to start the dev */ | ||
| 204 | if ((dev->host_hw_state & H_RDY) == 0) { | ||
| 205 | if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) { | ||
| 206 | DBG("we need to start the dev.\n"); | ||
| 207 | dev->host_hw_state |= (H_IE | H_IG | H_RDY); | ||
| 208 | heci_set_csr_register(dev); | ||
| 209 | if (dev->heci_state == HECI_INITIALIZING) { | ||
| 210 | dev->recvd_msg = 1; | ||
| 211 | spin_unlock_bh(&dev->device_lock); | ||
| 212 | wake_up_interruptible(&dev->wait_recvd_msg); | ||
| 213 | return; | ||
| 214 | |||
| 215 | } else { | ||
| 216 | spin_unlock_bh(&dev->device_lock); | ||
| 217 | tsk = kthread_run(heci_task_initialize_clients, | ||
| 218 | dev, "heci_reinit"); | ||
| 219 | if (IS_ERR(tsk)) { | ||
| 220 | int rc = PTR_ERR(tsk); | ||
| 221 | printk(KERN_WARNING "heci: Unable to" | ||
| 222 | "start the heci thread: %d\n", rc); | ||
| 223 | } | ||
| 224 | return; | ||
| 225 | } | ||
| 226 | } else { | ||
| 227 | DBG("enable interrupt FW not ready.\n"); | ||
| 228 | heci_csr_enable_interrupts(dev); | ||
| 229 | spin_unlock_bh(&dev->device_lock); | ||
| 230 | return; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | /* check slots avalable for reading */ | ||
| 234 | slots = count_full_read_slots(dev); | ||
| 235 | DBG("slots =%08x extra_write_index =%08x.\n", | ||
| 236 | slots, dev->extra_write_index); | ||
| 237 | while ((slots > 0) && (!dev->extra_write_index)) { | ||
| 238 | DBG("slots =%08x extra_write_index =%08x.\n", slots, | ||
| 239 | dev->extra_write_index); | ||
| 240 | DBG("call heci_bh_read_handler.\n"); | ||
| 241 | rets = heci_bh_read_handler(&complete_list, dev, &slots); | ||
| 242 | if (rets != 0) | ||
| 243 | goto end; | ||
| 244 | } | ||
| 245 | rets = heci_bh_write_handler(&complete_list, dev, &slots); | ||
| 246 | end: | ||
| 247 | DBG("end of bottom half function.\n"); | ||
| 248 | dev->host_hw_state = read_heci_register(dev, H_CSR); | ||
| 249 | dev->host_buffer_is_empty = host_buffer_is_empty(dev); | ||
| 250 | |||
| 251 | if ((dev->host_hw_state & H_IS) == H_IS) { | ||
| 252 | /* acknowledge interrupt and disable interrupts */ | ||
| 253 | heci_csr_disable_interrupts(dev); | ||
| 254 | |||
| 255 | /* clear H_IS bit in H_CSR */ | ||
| 256 | heci_csr_clear_his(dev); | ||
| 257 | |||
| 258 | PREPARE_WORK(&dev->work, heci_bh_handler); | ||
| 259 | DBG("schedule work the heci_bh_handler.\n"); | ||
| 260 | rets = schedule_work(&dev->work); | ||
| 261 | if (!rets) | ||
| 262 | DBG("heci_bh_handler was already queued.\n"); | ||
| 263 | } else { | ||
| 264 | heci_csr_enable_interrupts(dev); | ||
| 265 | } | ||
| 266 | |||
| 267 | if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) { | ||
| 268 | DBG("received waiting bus message\n"); | ||
| 269 | bus_message_received = 1; | ||
| 270 | } | ||
| 271 | spin_unlock_bh(&dev->device_lock); | ||
| 272 | if (bus_message_received) { | ||
| 273 | DBG("wake up dev->wait_recvd_msg\n"); | ||
| 274 | wake_up_interruptible(&dev->wait_recvd_msg); | ||
| 275 | bus_message_received = 0; | ||
| 276 | } | ||
| 277 | if ((complete_list.status != 0) | ||
| 278 | || list_empty(&complete_list.heci_cb.cb_list)) | ||
| 279 | return; | ||
| 280 | |||
| 281 | |||
| 282 | list_for_each_entry_safe(cb_pos, cb_next, | ||
| 283 | &complete_list.heci_cb.cb_list, cb_list) { | ||
| 284 | file_ext = (struct heci_file_private *)cb_pos->file_private; | ||
| 285 | list_del(&cb_pos->cb_list); | ||
| 286 | if (file_ext != NULL) { | ||
| 287 | if (file_ext != &dev->iamthif_file_ext) { | ||
| 288 | DBG("completing call back.\n"); | ||
| 289 | _heci_cmpl(file_ext, cb_pos); | ||
| 290 | cb_pos = NULL; | ||
| 291 | } else if (file_ext == &dev->iamthif_file_ext) { | ||
| 292 | _heci_cmpl_iamthif(dev, cb_pos); | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | |||
| 299 | /** | ||
| 300 | * heci_bh_read_handler - bottom half read routine after ISR to | ||
| 301 | * handle the read processing. | ||
| 302 | * | ||
| 303 | * @cmpl_list: An instance of our list structure | ||
| 304 | * @dev: Device object for our driver | ||
| 305 | * @slots: slots to read. | ||
| 306 | * | ||
| 307 | * returns 0 on success, <0 on failure. | ||
| 308 | */ | ||
| 309 | static int heci_bh_read_handler(struct io_heci_list *cmpl_list, | ||
| 310 | struct iamt_heci_device *dev, | ||
| 311 | __s32 *slots) | ||
| 312 | { | ||
| 313 | struct heci_msg_hdr *heci_hdr; | ||
| 314 | int ret = 0; | ||
| 315 | struct heci_file_private *file_pos = NULL; | ||
| 316 | struct heci_file_private *file_next = NULL; | ||
| 317 | |||
| 318 | if (!dev->rd_msg_hdr) { | ||
| 319 | dev->rd_msg_hdr = read_heci_register(dev, ME_CB_RW); | ||
| 320 | DBG("slots=%08x.\n", *slots); | ||
| 321 | (*slots)--; | ||
| 322 | DBG("slots=%08x.\n", *slots); | ||
| 323 | } | ||
| 324 | heci_hdr = (struct heci_msg_hdr *) &dev->rd_msg_hdr; | ||
| 325 | DBG("heci_hdr->length =%d\n", heci_hdr->length); | ||
| 326 | |||
| 327 | if ((heci_hdr->reserved) || !(dev->rd_msg_hdr)) { | ||
| 328 | DBG("corrupted message header.\n"); | ||
| 329 | ret = -ECORRUPTED_MESSAGE_HEADER; | ||
| 330 | goto end; | ||
| 331 | } | ||
| 332 | |||
| 333 | if ((heci_hdr->host_addr) || (heci_hdr->me_addr)) { | ||
| 334 | list_for_each_entry_safe(file_pos, file_next, | ||
| 335 | &dev->file_list, link) { | ||
| 336 | DBG("list_for_each_entry_safe read host" | ||
| 337 | " client = %d, ME client = %d\n", | ||
| 338 | file_pos->host_client_id, | ||
| 339 | file_pos->me_client_id); | ||
| 340 | if ((file_pos->host_client_id == heci_hdr->host_addr) | ||
| 341 | && (file_pos->me_client_id == heci_hdr->me_addr)) | ||
| 342 | break; | ||
| 343 | } | ||
| 344 | |||
| 345 | if (&file_pos->link == &dev->file_list) { | ||
| 346 | DBG("corrupted message header\n"); | ||
| 347 | ret = -ECORRUPTED_MESSAGE_HEADER; | ||
| 348 | goto end; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | if (((*slots) * sizeof(__u32)) < heci_hdr->length) { | ||
| 352 | DBG("we can't read the message slots=%08x.\n", *slots); | ||
| 353 | /* we can't read the message */ | ||
| 354 | ret = -ERANGE; | ||
| 355 | goto end; | ||
| 356 | } | ||
| 357 | |||
| 358 | /* decide where to read the message too */ | ||
| 359 | if (!heci_hdr->host_addr) { | ||
| 360 | DBG("call heci_bh_read_bus_message.\n"); | ||
| 361 | heci_bh_read_bus_message(dev, heci_hdr); | ||
| 362 | DBG("end heci_bh_read_bus_message.\n"); | ||
| 363 | } else if ((heci_hdr->host_addr == dev->iamthif_file_ext.host_client_id) | ||
| 364 | && (HECI_FILE_CONNECTED == dev->iamthif_file_ext.state) | ||
| 365 | && (dev->iamthif_state == HECI_IAMTHIF_READING)) { | ||
| 366 | DBG("call heci_bh_read_iamthif_message.\n"); | ||
| 367 | DBG("heci_hdr->length =%d\n", heci_hdr->length); | ||
| 368 | ret = heci_bh_read_pthi_message(cmpl_list, dev, heci_hdr); | ||
| 369 | if (ret != 0) | ||
| 370 | goto end; | ||
| 371 | |||
| 372 | } else { | ||
| 373 | DBG("call heci_bh_read_client_message.\n"); | ||
| 374 | ret = heci_bh_read_client_message(cmpl_list, dev, heci_hdr); | ||
| 375 | if (ret != 0) | ||
| 376 | goto end; | ||
| 377 | |||
| 378 | } | ||
| 379 | |||
| 380 | /* reset the number of slots and header */ | ||
| 381 | *slots = count_full_read_slots(dev); | ||
| 382 | dev->rd_msg_hdr = 0; | ||
| 383 | |||
| 384 | if (*slots == -ESLOTS_OVERFLOW) { | ||
| 385 | /* overflow - reset */ | ||
| 386 | DBG("reseting due to slots overflow.\n"); | ||
| 387 | /* set the event since message has been read */ | ||
| 388 | ret = -ERANGE; | ||
| 389 | goto end; | ||
| 390 | } | ||
| 391 | end: | ||
| 392 | return ret; | ||
| 393 | } | ||
| 394 | |||
| 395 | |||
| 396 | /** | ||
| 397 | * heci_bh_read_bus_message - bottom half read routine after ISR to | ||
| 398 | * handle the read bus message cmd processing. | ||
| 399 | * | ||
| 400 | * @dev: Device object for our driver | ||
| 401 | * @heci_hdr: header of bus message | ||
| 402 | */ | ||
| 403 | static void heci_bh_read_bus_message(struct iamt_heci_device *dev, | ||
| 404 | struct heci_msg_hdr *heci_hdr) | ||
| 405 | { | ||
| 406 | struct heci_bus_message *heci_msg; | ||
| 407 | struct hbm_host_version_response *version_res; | ||
| 408 | struct hbm_client_connect_response *connect_res; | ||
| 409 | struct hbm_client_connect_response *disconnect_res; | ||
| 410 | struct hbm_flow_control *flow_control; | ||
| 411 | struct hbm_props_response *props_res; | ||
| 412 | struct hbm_host_enum_response *enum_res; | ||
| 413 | struct hbm_client_disconnect_request *disconnect_req; | ||
| 414 | struct hbm_host_stop_request *h_stop_req; | ||
| 415 | int i; | ||
| 416 | unsigned char *buffer; | ||
| 417 | |||
| 418 | /* read the message to our buffer */ | ||
| 419 | buffer = (unsigned char *) dev->rd_msg_buf; | ||
| 420 | BUG_ON(heci_hdr->length >= sizeof(dev->rd_msg_buf)); | ||
| 421 | heci_read_slots(dev, buffer, heci_hdr->length); | ||
| 422 | heci_msg = (struct heci_bus_message *) buffer; | ||
| 423 | |||
| 424 | switch (*(__u8 *) heci_msg) { | ||
| 425 | case HOST_START_RES_CMD: | ||
| 426 | version_res = (struct hbm_host_version_response *) heci_msg; | ||
| 427 | if (version_res->host_version_supported) { | ||
| 428 | dev->version.major_version = HBM_MAJOR_VERSION; | ||
| 429 | dev->version.minor_version = HBM_MINOR_VERSION; | ||
| 430 | } else { | ||
| 431 | dev->version = version_res->me_max_version; | ||
| 432 | } | ||
| 433 | dev->recvd_msg = 1; | ||
| 434 | DBG("host start response message received.\n"); | ||
| 435 | break; | ||
| 436 | |||
| 437 | case CLIENT_CONNECT_RES_CMD: | ||
| 438 | connect_res = | ||
| 439 | (struct hbm_client_connect_response *) heci_msg; | ||
| 440 | heci_client_connect_response(dev, connect_res); | ||
| 441 | DBG("client connect response message received.\n"); | ||
| 442 | wake_up(&dev->wait_recvd_msg); | ||
| 443 | break; | ||
| 444 | |||
| 445 | case CLIENT_DISCONNECT_RES_CMD: | ||
| 446 | disconnect_res = | ||
| 447 | (struct hbm_client_connect_response *) heci_msg; | ||
| 448 | heci_client_disconnect_response(dev, disconnect_res); | ||
| 449 | DBG("client disconnect response message received.\n"); | ||
| 450 | wake_up(&dev->wait_recvd_msg); | ||
| 451 | break; | ||
| 452 | |||
| 453 | case HECI_FLOW_CONTROL_CMD: | ||
| 454 | flow_control = (struct hbm_flow_control *) heci_msg; | ||
| 455 | heci_client_flow_control_response(dev, flow_control); | ||
| 456 | DBG("client flow control response message received.\n"); | ||
| 457 | break; | ||
| 458 | |||
| 459 | case HOST_CLIENT_PROPERTEIS_RES_CMD: | ||
| 460 | props_res = (struct hbm_props_response *) heci_msg; | ||
| 461 | if (props_res->status != 0) { | ||
| 462 | BUG(); | ||
| 463 | break; | ||
| 464 | } | ||
| 465 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 466 | if (dev->me_clients[i].client_id == | ||
| 467 | props_res->address) { | ||
| 468 | dev->me_clients[i].props = | ||
| 469 | props_res->client_properties; | ||
| 470 | break; | ||
| 471 | } | ||
| 472 | |||
| 473 | } | ||
| 474 | dev->recvd_msg = 1; | ||
| 475 | break; | ||
| 476 | |||
| 477 | case HOST_ENUM_RES_CMD: | ||
| 478 | enum_res = (struct hbm_host_enum_response *) heci_msg; | ||
| 479 | memcpy(dev->heci_me_clients, enum_res->valid_addresses, 32); | ||
| 480 | dev->recvd_msg = 1; | ||
| 481 | break; | ||
| 482 | |||
| 483 | case HOST_STOP_RES_CMD: | ||
| 484 | dev->heci_state = HECI_DISABLED; | ||
| 485 | DBG("reseting because of FW stop response.\n"); | ||
| 486 | heci_reset(dev, 1); | ||
| 487 | break; | ||
| 488 | |||
| 489 | case CLIENT_DISCONNECT_REQ_CMD: | ||
| 490 | /* search for client */ | ||
| 491 | disconnect_req = | ||
| 492 | (struct hbm_client_disconnect_request *) heci_msg; | ||
| 493 | heci_client_disconnect_request(dev, disconnect_req); | ||
| 494 | break; | ||
| 495 | |||
| 496 | case ME_STOP_REQ_CMD: | ||
| 497 | /* prepare stop request */ | ||
| 498 | heci_hdr = (struct heci_msg_hdr *) &dev->ext_msg_buf[0]; | ||
| 499 | heci_hdr->host_addr = 0; | ||
| 500 | heci_hdr->me_addr = 0; | ||
| 501 | heci_hdr->length = sizeof(struct hbm_host_stop_request); | ||
| 502 | heci_hdr->msg_complete = 1; | ||
| 503 | heci_hdr->reserved = 0; | ||
| 504 | h_stop_req = | ||
| 505 | (struct hbm_host_stop_request *) &dev->ext_msg_buf[1]; | ||
| 506 | memset(h_stop_req, 0, sizeof(struct hbm_host_stop_request)); | ||
| 507 | h_stop_req->cmd.cmd = HOST_STOP_REQ_CMD; | ||
| 508 | h_stop_req->reason = DRIVER_STOP_REQUEST; | ||
| 509 | h_stop_req->reserved[0] = 0; | ||
| 510 | h_stop_req->reserved[1] = 0; | ||
| 511 | dev->extra_write_index = 2; | ||
| 512 | break; | ||
| 513 | |||
| 514 | default: | ||
| 515 | BUG(); | ||
| 516 | break; | ||
| 517 | |||
| 518 | } | ||
| 519 | } | ||
| 520 | |||
| 521 | /** | ||
| 522 | * heci_bh_read_pthi_message - bottom half read routine after ISR to | ||
| 523 | * handle the read pthi message data processing. | ||
| 524 | * | ||
| 525 | * @complete_list: An instance of our list structure | ||
| 526 | * @dev: Device object for our driver | ||
| 527 | * @heci_hdr: header of pthi message | ||
| 528 | * | ||
| 529 | * returns 0 on success, <0 on failure. | ||
| 530 | */ | ||
| 531 | static int heci_bh_read_pthi_message(struct io_heci_list *complete_list, | ||
| 532 | struct iamt_heci_device *dev, | ||
| 533 | struct heci_msg_hdr *heci_hdr) | ||
| 534 | { | ||
| 535 | struct heci_file_private *file_ext; | ||
| 536 | struct heci_cb_private *priv_cb; | ||
| 537 | unsigned char *buffer; | ||
| 538 | |||
| 539 | BUG_ON(heci_hdr->me_addr != dev->iamthif_file_ext.me_client_id); | ||
| 540 | BUG_ON(dev->iamthif_state != HECI_IAMTHIF_READING); | ||
| 541 | |||
| 542 | buffer = (unsigned char *) (dev->iamthif_msg_buf + | ||
| 543 | dev->iamthif_msg_buf_index); | ||
| 544 | BUG_ON(sizeof(dev->iamthif_msg_buf) < | ||
| 545 | (dev->iamthif_msg_buf_index + heci_hdr->length)); | ||
| 546 | |||
| 547 | heci_read_slots(dev, buffer, heci_hdr->length); | ||
| 548 | |||
| 549 | dev->iamthif_msg_buf_index += heci_hdr->length; | ||
| 550 | |||
| 551 | if (!(heci_hdr->msg_complete)) | ||
| 552 | return 0; | ||
| 553 | |||
| 554 | DBG("pthi_message_buffer_index=%d\n", heci_hdr->length); | ||
| 555 | DBG("completed pthi read.\n "); | ||
| 556 | if (!dev->iamthif_current_cb) | ||
| 557 | return -ENODEV; | ||
| 558 | |||
| 559 | priv_cb = dev->iamthif_current_cb; | ||
| 560 | dev->iamthif_current_cb = NULL; | ||
| 561 | |||
| 562 | file_ext = (struct heci_file_private *)priv_cb->file_private; | ||
| 563 | if (!file_ext) | ||
| 564 | return -ENODEV; | ||
| 565 | |||
| 566 | dev->iamthif_stall_timer = 0; | ||
| 567 | priv_cb->information = dev->iamthif_msg_buf_index; | ||
| 568 | priv_cb->read_time = get_seconds(); | ||
| 569 | if ((dev->iamthif_ioctl) && (file_ext == &dev->iamthif_file_ext)) { | ||
| 570 | /* found the iamthif cb */ | ||
| 571 | DBG("complete the pthi read cb.\n "); | ||
| 572 | if (&dev->iamthif_file_ext) { | ||
| 573 | DBG("add the pthi read cb to complete.\n "); | ||
| 574 | list_add_tail(&priv_cb->cb_list, | ||
| 575 | &complete_list->heci_cb.cb_list); | ||
| 576 | } | ||
| 577 | } | ||
| 578 | return 0; | ||
| 579 | } | ||
| 580 | |||
| 581 | /** | ||
| 582 | * _heci_bh_state_ok - check if heci header matches file private data | ||
| 583 | * | ||
| 584 | * @file_ext: private data of the file object | ||
| 585 | * @heci_hdr: header of heci client message | ||
| 586 | * | ||
| 587 | * returns !=0 if matches, 0 if no match. | ||
| 588 | */ | ||
| 589 | static int _heci_bh_state_ok(struct heci_file_private *file_ext, | ||
| 590 | struct heci_msg_hdr *heci_hdr) | ||
| 591 | { | ||
| 592 | return ((file_ext->host_client_id == heci_hdr->host_addr) | ||
| 593 | && (file_ext->me_client_id == heci_hdr->me_addr) | ||
| 594 | && (file_ext->state == HECI_FILE_CONNECTED) | ||
| 595 | && (HECI_READ_COMPLETE != file_ext->reading_state)); | ||
| 596 | } | ||
| 597 | |||
| 598 | /** | ||
| 599 | * heci_bh_read_client_message - bottom half read routine after ISR to | ||
| 600 | * handle the read heci client message data processing. | ||
| 601 | * | ||
| 602 | * @complete_list: An instance of our list structure | ||
| 603 | * @dev: Device object for our driver | ||
| 604 | * @heci_hdr: header of heci client message | ||
| 605 | * | ||
| 606 | * returns 0 on success, <0 on failure. | ||
| 607 | */ | ||
| 608 | static int heci_bh_read_client_message(struct io_heci_list *complete_list, | ||
| 609 | struct iamt_heci_device *dev, | ||
| 610 | struct heci_msg_hdr *heci_hdr) | ||
| 611 | { | ||
| 612 | struct heci_file_private *file_ext; | ||
| 613 | struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL; | ||
| 614 | unsigned char *buffer = NULL; | ||
| 615 | |||
| 616 | DBG("start client msg\n"); | ||
| 617 | if (!((dev->read_list.status == 0) && | ||
| 618 | !list_empty(&dev->read_list.heci_cb.cb_list))) | ||
| 619 | goto quit; | ||
| 620 | |||
| 621 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 622 | &dev->read_list.heci_cb.cb_list, cb_list) { | ||
| 623 | file_ext = (struct heci_file_private *) | ||
| 624 | priv_cb_pos->file_private; | ||
| 625 | if ((file_ext != NULL) && | ||
| 626 | (_heci_bh_state_ok(file_ext, heci_hdr))) { | ||
| 627 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 628 | file_ext->reading_state = HECI_READING; | ||
| 629 | buffer = (unsigned char *) | ||
| 630 | (priv_cb_pos->response_buffer.data + | ||
| 631 | priv_cb_pos->information); | ||
| 632 | BUG_ON(priv_cb_pos->response_buffer.size < | ||
| 633 | heci_hdr->length + | ||
| 634 | priv_cb_pos->information); | ||
| 635 | |||
| 636 | if (priv_cb_pos->response_buffer.size < | ||
| 637 | heci_hdr->length + | ||
| 638 | priv_cb_pos->information) { | ||
| 639 | DBG("message overflow.\n"); | ||
| 640 | list_del(&priv_cb_pos->cb_list); | ||
| 641 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 642 | return -ENOMEM; | ||
| 643 | } | ||
| 644 | if (buffer) { | ||
| 645 | heci_read_slots(dev, buffer, | ||
| 646 | heci_hdr->length); | ||
| 647 | } | ||
| 648 | priv_cb_pos->information += heci_hdr->length; | ||
| 649 | if (heci_hdr->msg_complete) { | ||
| 650 | file_ext->status = 0; | ||
| 651 | list_del(&priv_cb_pos->cb_list); | ||
| 652 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 653 | DBG("completed read host client = %d," | ||
| 654 | "ME client = %d, " | ||
| 655 | "data length = %lu\n", | ||
| 656 | file_ext->host_client_id, | ||
| 657 | file_ext->me_client_id, | ||
| 658 | priv_cb_pos->information); | ||
| 659 | |||
| 660 | *(priv_cb_pos->response_buffer.data + | ||
| 661 | priv_cb_pos->information) = '\0'; | ||
| 662 | DBG("priv_cb_pos->res_buffer - %s\n", | ||
| 663 | priv_cb_pos->response_buffer.data); | ||
| 664 | list_add_tail(&priv_cb_pos->cb_list, | ||
| 665 | &complete_list->heci_cb.cb_list); | ||
| 666 | } else { | ||
| 667 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 668 | } | ||
| 669 | |||
| 670 | break; | ||
| 671 | } | ||
| 672 | |||
| 673 | } | ||
| 674 | |||
| 675 | quit: | ||
| 676 | DBG("message read\n"); | ||
| 677 | if (!buffer) { | ||
| 678 | heci_read_slots(dev, (unsigned char *) dev->rd_msg_buf, | ||
| 679 | heci_hdr->length); | ||
| 680 | DBG("discarding message, header=%08x.\n", | ||
| 681 | *(__u32 *) dev->rd_msg_buf); | ||
| 682 | } | ||
| 683 | |||
| 684 | return 0; | ||
| 685 | } | ||
| 686 | |||
| 687 | /** | ||
| 688 | * _heci_bh_iamthif_read - prepare to read iamthif data. | ||
| 689 | * | ||
| 690 | * @dev: Device object for our driver. | ||
| 691 | * @slots: free slots. | ||
| 692 | * | ||
| 693 | * returns 0, OK; otherwise, error. | ||
| 694 | */ | ||
| 695 | static int _heci_bh_iamthif_read(struct iamt_heci_device *dev, __s32 *slots) | ||
| 696 | { | ||
| 697 | |||
| 698 | if (((*slots) * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) | ||
| 699 | + sizeof(struct hbm_flow_control))) { | ||
| 700 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 701 | sizeof(struct hbm_flow_control) + 3) / 4; | ||
| 702 | if (!heci_send_flow_control(dev, &dev->iamthif_file_ext)) { | ||
| 703 | DBG("iamthif flow control failed\n"); | ||
| 704 | } else { | ||
| 705 | DBG("iamthif flow control success\n"); | ||
| 706 | dev->iamthif_state = HECI_IAMTHIF_READING; | ||
| 707 | dev->iamthif_flow_control_pending = 0; | ||
| 708 | dev->iamthif_msg_buf_index = 0; | ||
| 709 | dev->iamthif_msg_buf_size = 0; | ||
| 710 | dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER; | ||
| 711 | dev->host_buffer_is_empty = host_buffer_is_empty(dev); | ||
| 712 | } | ||
| 713 | return 0; | ||
| 714 | } else { | ||
| 715 | return -ECOMPLETE_MESSAGE; | ||
| 716 | } | ||
| 717 | } | ||
| 718 | |||
| 719 | /** | ||
| 720 | * _heci_bh_close - process close related operation. | ||
| 721 | * | ||
| 722 | * @dev: Device object for our driver. | ||
| 723 | * @slots: free slots. | ||
| 724 | * @priv_cb_pos: callback block. | ||
| 725 | * @file_ext: private data of the file object. | ||
| 726 | * @cmpl_list: complete list. | ||
| 727 | * | ||
| 728 | * returns 0, OK; otherwise, error. | ||
| 729 | */ | ||
| 730 | static int _heci_bh_close(struct iamt_heci_device *dev, __s32 *slots, | ||
| 731 | struct heci_cb_private *priv_cb_pos, | ||
| 732 | struct heci_file_private *file_ext, | ||
| 733 | struct io_heci_list *cmpl_list) | ||
| 734 | { | ||
| 735 | if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) + | ||
| 736 | sizeof(struct hbm_client_disconnect_request))) { | ||
| 737 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 738 | sizeof(struct hbm_client_disconnect_request) + 3) / 4; | ||
| 739 | |||
| 740 | if (!heci_disconnect(dev, file_ext)) { | ||
| 741 | file_ext->status = 0; | ||
| 742 | priv_cb_pos->information = 0; | ||
| 743 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 744 | &cmpl_list->heci_cb.cb_list); | ||
| 745 | return -ECOMPLETE_MESSAGE; | ||
| 746 | } else { | ||
| 747 | file_ext->state = HECI_FILE_DISCONNECTING; | ||
| 748 | file_ext->status = 0; | ||
| 749 | priv_cb_pos->information = 0; | ||
| 750 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 751 | &dev->ctrl_rd_list.heci_cb.cb_list); | ||
| 752 | file_ext->timer_count = HECI_CONNECT_TIMEOUT; | ||
| 753 | } | ||
| 754 | } else { | ||
| 755 | /* return the cancel routine */ | ||
| 756 | return -ECORRUPTED_MESSAGE_HEADER; | ||
| 757 | } | ||
| 758 | |||
| 759 | return 0; | ||
| 760 | } | ||
| 761 | |||
| 762 | /** | ||
| 763 | * _heci_hb_close - process read related operation. | ||
| 764 | * | ||
| 765 | * @dev: Device object for our driver. | ||
| 766 | * @slots: free slots. | ||
| 767 | * @priv_cb_pos: callback block. | ||
| 768 | * @file_ext: private data of the file object. | ||
| 769 | * @cmpl_list: complete list. | ||
| 770 | * | ||
| 771 | * returns 0, OK; otherwise, error. | ||
| 772 | */ | ||
| 773 | static int _heci_bh_read(struct iamt_heci_device *dev, __s32 *slots, | ||
| 774 | struct heci_cb_private *priv_cb_pos, | ||
| 775 | struct heci_file_private *file_ext, | ||
| 776 | struct io_heci_list *cmpl_list) | ||
| 777 | { | ||
| 778 | if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) + | ||
| 779 | sizeof(struct hbm_flow_control))) { | ||
| 780 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 781 | sizeof(struct hbm_flow_control) + 3) / 4; | ||
| 782 | if (!heci_send_flow_control(dev, file_ext)) { | ||
| 783 | file_ext->status = -ENODEV; | ||
| 784 | priv_cb_pos->information = 0; | ||
| 785 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 786 | &cmpl_list->heci_cb.cb_list); | ||
| 787 | return -ENODEV; | ||
| 788 | } else { | ||
| 789 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 790 | &dev->read_list.heci_cb.cb_list); | ||
| 791 | } | ||
| 792 | } else { | ||
| 793 | /* return the cancel routine */ | ||
| 794 | list_del(&priv_cb_pos->cb_list); | ||
| 795 | return -ECORRUPTED_MESSAGE_HEADER; | ||
| 796 | } | ||
| 797 | |||
| 798 | return 0; | ||
| 799 | } | ||
| 800 | |||
| 801 | |||
| 802 | /** | ||
| 803 | * _heci_bh_ioctl - process ioctl related operation. | ||
| 804 | * | ||
| 805 | * @dev: Device object for our driver. | ||
| 806 | * @slots: free slots. | ||
| 807 | * @priv_cb_pos: callback block. | ||
| 808 | * @file_ext: private data of the file object. | ||
| 809 | * @cmpl_list: complete list. | ||
| 810 | * | ||
| 811 | * returns 0, OK; otherwise, error. | ||
| 812 | */ | ||
| 813 | static int _heci_bh_ioctl(struct iamt_heci_device *dev, __s32 *slots, | ||
| 814 | struct heci_cb_private *priv_cb_pos, | ||
| 815 | struct heci_file_private *file_ext, | ||
| 816 | struct io_heci_list *cmpl_list) | ||
| 817 | { | ||
| 818 | if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) + | ||
| 819 | sizeof(struct hbm_client_connect_request))) { | ||
| 820 | file_ext->state = HECI_FILE_CONNECTING; | ||
| 821 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 822 | sizeof(struct hbm_client_connect_request) + 3) / 4; | ||
| 823 | if (!heci_connect(dev, file_ext)) { | ||
| 824 | file_ext->status = -ENODEV; | ||
| 825 | priv_cb_pos->information = 0; | ||
| 826 | list_del(&priv_cb_pos->cb_list); | ||
| 827 | return -ENODEV; | ||
| 828 | } else { | ||
| 829 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 830 | &dev->ctrl_rd_list.heci_cb.cb_list); | ||
| 831 | file_ext->timer_count = HECI_CONNECT_TIMEOUT; | ||
| 832 | } | ||
| 833 | } else { | ||
| 834 | /* return the cancel routine */ | ||
| 835 | list_del(&priv_cb_pos->cb_list); | ||
| 836 | return -ECORRUPTED_MESSAGE_HEADER; | ||
| 837 | } | ||
| 838 | |||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | |||
| 842 | /** | ||
| 843 | * _heci_bh_cmpl - process completed and no-iamthif operation. | ||
| 844 | * | ||
| 845 | * @dev: Device object for our driver. | ||
| 846 | * @slots: free slots. | ||
| 847 | * @priv_cb_pos: callback block. | ||
| 848 | * @file_ext: private data of the file object. | ||
| 849 | * @cmpl_list: complete list. | ||
| 850 | * | ||
| 851 | * returns 0, OK; otherwise, error. | ||
| 852 | */ | ||
| 853 | static int _heci_bh_cmpl(struct iamt_heci_device *dev, __s32 *slots, | ||
| 854 | struct heci_cb_private *priv_cb_pos, | ||
| 855 | struct heci_file_private *file_ext, | ||
| 856 | struct io_heci_list *cmpl_list) | ||
| 857 | { | ||
| 858 | struct heci_msg_hdr *heci_hdr; | ||
| 859 | |||
| 860 | if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) + | ||
| 861 | (priv_cb_pos->request_buffer.size - | ||
| 862 | priv_cb_pos->information))) { | ||
| 863 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 864 | heci_hdr->host_addr = file_ext->host_client_id; | ||
| 865 | heci_hdr->me_addr = file_ext->me_client_id; | ||
| 866 | heci_hdr->length = ((priv_cb_pos->request_buffer.size) - | ||
| 867 | (priv_cb_pos->information)); | ||
| 868 | heci_hdr->msg_complete = 1; | ||
| 869 | heci_hdr->reserved = 0; | ||
| 870 | DBG("priv_cb_pos->request_buffer.size =%d" | ||
| 871 | "heci_hdr->msg_complete= %d\n", | ||
| 872 | priv_cb_pos->request_buffer.size, | ||
| 873 | heci_hdr->msg_complete); | ||
| 874 | DBG("priv_cb_pos->information =%lu\n", | ||
| 875 | priv_cb_pos->information); | ||
| 876 | DBG("heci_hdr->length =%d\n", | ||
| 877 | heci_hdr->length); | ||
| 878 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 879 | heci_hdr->length + 3) / 4; | ||
| 880 | if (!heci_write_message(dev, heci_hdr, | ||
| 881 | (unsigned char *) | ||
| 882 | (priv_cb_pos->request_buffer.data + | ||
| 883 | priv_cb_pos->information), | ||
| 884 | heci_hdr->length)) { | ||
| 885 | file_ext->status = -ENODEV; | ||
| 886 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 887 | &cmpl_list->heci_cb.cb_list); | ||
| 888 | return -ENODEV; | ||
| 889 | } else { | ||
| 890 | flow_ctrl_reduce(dev, file_ext); | ||
| 891 | file_ext->status = 0; | ||
| 892 | priv_cb_pos->information += heci_hdr->length; | ||
| 893 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 894 | &dev->write_waiting_list.heci_cb.cb_list); | ||
| 895 | } | ||
| 896 | } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) { | ||
| 897 | /* buffer is still empty */ | ||
| 898 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 899 | heci_hdr->host_addr = file_ext->host_client_id; | ||
| 900 | heci_hdr->me_addr = file_ext->me_client_id; | ||
| 901 | heci_hdr->length = | ||
| 902 | (*slots * sizeof(__u32)) - sizeof(struct heci_msg_hdr); | ||
| 903 | heci_hdr->msg_complete = 0; | ||
| 904 | heci_hdr->reserved = 0; | ||
| 905 | |||
| 906 | (*slots) -= (sizeof(struct heci_msg_hdr) + | ||
| 907 | heci_hdr->length + 3) / 4; | ||
| 908 | if (!heci_write_message(dev, heci_hdr, | ||
| 909 | (unsigned char *) | ||
| 910 | (priv_cb_pos->request_buffer.data + | ||
| 911 | priv_cb_pos->information), | ||
| 912 | heci_hdr->length)) { | ||
| 913 | file_ext->status = -ENODEV; | ||
| 914 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 915 | &cmpl_list->heci_cb.cb_list); | ||
| 916 | return -ENODEV; | ||
| 917 | } else { | ||
| 918 | priv_cb_pos->information += heci_hdr->length; | ||
| 919 | DBG("priv_cb_pos->request_buffer.size =%d" | ||
| 920 | " heci_hdr->msg_complete= %d\n", | ||
| 921 | priv_cb_pos->request_buffer.size, | ||
| 922 | heci_hdr->msg_complete); | ||
| 923 | DBG("priv_cb_pos->information =%lu\n", | ||
| 924 | priv_cb_pos->information); | ||
| 925 | DBG("heci_hdr->length =%d\n", heci_hdr->length); | ||
| 926 | } | ||
| 927 | return -ECOMPLETE_MESSAGE; | ||
| 928 | } else { | ||
| 929 | return -ECORRUPTED_MESSAGE_HEADER; | ||
| 930 | } | ||
| 931 | |||
| 932 | return 0; | ||
| 933 | } | ||
| 934 | |||
| 935 | /** | ||
| 936 | * _heci_bh_cmpl_iamthif - process completed iamthif operation. | ||
| 937 | * | ||
| 938 | * @dev: Device object for our driver. | ||
| 939 | * @slots: free slots. | ||
| 940 | * @priv_cb_pos: callback block. | ||
| 941 | * @file_ext: private data of the file object. | ||
| 942 | * @cmpl_list: complete list. | ||
| 943 | * | ||
| 944 | * returns 0, OK; otherwise, error. | ||
| 945 | */ | ||
| 946 | static int _heci_bh_cmpl_iamthif(struct iamt_heci_device *dev, __s32 *slots, | ||
| 947 | struct heci_cb_private *priv_cb_pos, | ||
| 948 | struct heci_file_private *file_ext, | ||
| 949 | struct io_heci_list *cmpl_list) | ||
| 950 | { | ||
| 951 | struct heci_msg_hdr *heci_hdr; | ||
| 952 | |||
| 953 | if ((*slots * sizeof(__u32)) >= (sizeof(struct heci_msg_hdr) + | ||
| 954 | dev->iamthif_msg_buf_size - | ||
| 955 | dev->iamthif_msg_buf_index)) { | ||
| 956 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 957 | heci_hdr->host_addr = file_ext->host_client_id; | ||
| 958 | heci_hdr->me_addr = file_ext->me_client_id; | ||
| 959 | heci_hdr->length = dev->iamthif_msg_buf_size - | ||
| 960 | dev->iamthif_msg_buf_index; | ||
| 961 | heci_hdr->msg_complete = 1; | ||
| 962 | heci_hdr->reserved = 0; | ||
| 963 | |||
| 964 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 965 | heci_hdr->length + 3) / 4; | ||
| 966 | |||
| 967 | if (!heci_write_message(dev, heci_hdr, | ||
| 968 | (dev->iamthif_msg_buf + | ||
| 969 | dev->iamthif_msg_buf_index), | ||
| 970 | heci_hdr->length)) { | ||
| 971 | dev->iamthif_state = HECI_IAMTHIF_IDLE; | ||
| 972 | file_ext->status = -ENODEV; | ||
| 973 | list_del(&priv_cb_pos->cb_list); | ||
| 974 | return -ENODEV; | ||
| 975 | } else { | ||
| 976 | flow_ctrl_reduce(dev, file_ext); | ||
| 977 | dev->iamthif_msg_buf_index += heci_hdr->length; | ||
| 978 | priv_cb_pos->information = dev->iamthif_msg_buf_index; | ||
| 979 | file_ext->status = 0; | ||
| 980 | dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL; | ||
| 981 | dev->iamthif_flow_control_pending = 1; | ||
| 982 | /* save iamthif cb sent to pthi client */ | ||
| 983 | dev->iamthif_current_cb = priv_cb_pos; | ||
| 984 | list_move_tail(&priv_cb_pos->cb_list, | ||
| 985 | &dev->write_waiting_list.heci_cb.cb_list); | ||
| 986 | |||
| 987 | } | ||
| 988 | } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) { | ||
| 989 | /* buffer is still empty */ | ||
| 990 | heci_hdr = (struct heci_msg_hdr *) &dev->wr_msg_buf[0]; | ||
| 991 | heci_hdr->host_addr = file_ext->host_client_id; | ||
| 992 | heci_hdr->me_addr = file_ext->me_client_id; | ||
| 993 | heci_hdr->length = | ||
| 994 | (*slots * sizeof(__u32)) - sizeof(struct heci_msg_hdr); | ||
| 995 | heci_hdr->msg_complete = 0; | ||
| 996 | heci_hdr->reserved = 0; | ||
| 997 | |||
| 998 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 999 | heci_hdr->length + 3) / 4; | ||
| 1000 | |||
| 1001 | if (!heci_write_message(dev, heci_hdr, | ||
| 1002 | (dev->iamthif_msg_buf + | ||
| 1003 | dev->iamthif_msg_buf_index), | ||
| 1004 | heci_hdr->length)) { | ||
| 1005 | file_ext->status = -ENODEV; | ||
| 1006 | list_del(&priv_cb_pos->cb_list); | ||
| 1007 | } else { | ||
| 1008 | dev->iamthif_msg_buf_index += heci_hdr->length; | ||
| 1009 | } | ||
| 1010 | return -ECOMPLETE_MESSAGE; | ||
| 1011 | } else { | ||
| 1012 | return -ECORRUPTED_MESSAGE_HEADER; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | return 0; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | /** | ||
| 1019 | * heci_bh_write_handler - bottom half write routine after | ||
| 1020 | * ISR to handle the write processing. | ||
| 1021 | * | ||
| 1022 | * @cmpl_list: An instance of our list structure | ||
| 1023 | * @dev: Device object for our driver | ||
| 1024 | * @slots: slots to write. | ||
| 1025 | * | ||
| 1026 | * returns 0 on success, <0 on failure. | ||
| 1027 | */ | ||
| 1028 | static int heci_bh_write_handler(struct io_heci_list *cmpl_list, | ||
| 1029 | struct iamt_heci_device *dev, | ||
| 1030 | __s32 *slots) | ||
| 1031 | { | ||
| 1032 | |||
| 1033 | struct heci_file_private *file_ext; | ||
| 1034 | struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL; | ||
| 1035 | struct io_heci_list *list; | ||
| 1036 | int ret; | ||
| 1037 | |||
| 1038 | if (!host_buffer_is_empty(dev)) { | ||
| 1039 | DBG("host buffer is not empty.\n"); | ||
| 1040 | return 0; | ||
| 1041 | } | ||
| 1042 | dev->write_hang = -1; | ||
| 1043 | *slots = count_empty_write_slots(dev); | ||
| 1044 | /* complete all waiting for write CB */ | ||
| 1045 | DBG("complete all waiting for write cb.\n"); | ||
| 1046 | |||
| 1047 | list = &dev->write_waiting_list; | ||
| 1048 | if ((list->status == 0) | ||
| 1049 | && !list_empty(&list->heci_cb.cb_list)) { | ||
| 1050 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 1051 | &list->heci_cb.cb_list, cb_list) { | ||
| 1052 | file_ext = (struct heci_file_private *) | ||
| 1053 | priv_cb_pos->file_private; | ||
| 1054 | if (file_ext != NULL) { | ||
| 1055 | file_ext->status = 0; | ||
| 1056 | list_del(&priv_cb_pos->cb_list); | ||
| 1057 | if ((HECI_WRITING == file_ext->writing_state) && | ||
| 1058 | (priv_cb_pos->major_file_operations == | ||
| 1059 | HECI_WRITE) && | ||
| 1060 | (file_ext != &dev->iamthif_file_ext)) { | ||
| 1061 | DBG("HECI WRITE COMPLETE\n"); | ||
| 1062 | file_ext->writing_state = | ||
| 1063 | HECI_WRITE_COMPLETE; | ||
| 1064 | list_add_tail(&priv_cb_pos->cb_list, | ||
| 1065 | &cmpl_list->heci_cb.cb_list); | ||
| 1066 | } | ||
| 1067 | if (file_ext == &dev->iamthif_file_ext) { | ||
| 1068 | DBG("check iamthif flow control.\n"); | ||
| 1069 | if (dev->iamthif_flow_control_pending) { | ||
| 1070 | ret = _heci_bh_iamthif_read(dev, | ||
| 1071 | slots); | ||
| 1072 | if (ret != 0) | ||
| 1073 | return ret; | ||
| 1074 | } | ||
| 1075 | } | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | } | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | if ((dev->stop) && (!dev->wd_pending)) { | ||
| 1082 | dev->wd_stoped = 1; | ||
| 1083 | wake_up_interruptible(&dev->wait_stop_wd); | ||
| 1084 | return 0; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | if (dev->extra_write_index != 0) { | ||
| 1088 | DBG("extra_write_index =%d.\n", dev->extra_write_index); | ||
| 1089 | heci_write_message(dev, | ||
| 1090 | (struct heci_msg_hdr *) &dev->ext_msg_buf[0], | ||
| 1091 | (unsigned char *) &dev->ext_msg_buf[1], | ||
| 1092 | (dev->extra_write_index - 1) * sizeof(__u32)); | ||
| 1093 | *slots -= dev->extra_write_index; | ||
| 1094 | dev->extra_write_index = 0; | ||
| 1095 | } | ||
| 1096 | if (dev->heci_state == HECI_ENABLED) { | ||
| 1097 | if ((dev->wd_pending) | ||
| 1098 | && flow_ctrl_creds(dev, &dev->wd_file_ext)) { | ||
| 1099 | if (!heci_send_wd(dev)) | ||
| 1100 | DBG("wd send failed.\n"); | ||
| 1101 | else | ||
| 1102 | flow_ctrl_reduce(dev, &dev->wd_file_ext); | ||
| 1103 | |||
| 1104 | dev->wd_pending = 0; | ||
| 1105 | |||
| 1106 | if (dev->wd_timeout != 0) { | ||
| 1107 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 1108 | HECI_START_WD_DATA_SIZE + 3) / 4; | ||
| 1109 | dev->wd_due_counter = 2; | ||
| 1110 | } else { | ||
| 1111 | *slots -= (sizeof(struct heci_msg_hdr) + | ||
| 1112 | HECI_WD_PARAMS_SIZE + 3) / 4; | ||
| 1113 | dev->wd_due_counter = 0; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | } | ||
| 1117 | } | ||
| 1118 | if (dev->stop) | ||
| 1119 | return ~ENODEV; | ||
| 1120 | |||
| 1121 | /* complete control write list CB */ | ||
| 1122 | if (dev->ctrl_wr_list.status == 0) { | ||
| 1123 | /* complete control write list CB */ | ||
| 1124 | DBG("complete control write list cb.\n"); | ||
| 1125 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 1126 | &dev->ctrl_wr_list.heci_cb.cb_list, cb_list) { | ||
| 1127 | file_ext = (struct heci_file_private *) | ||
| 1128 | priv_cb_pos->file_private; | ||
| 1129 | if (file_ext == NULL) { | ||
| 1130 | list_del(&priv_cb_pos->cb_list); | ||
| 1131 | return -ENODEV; | ||
| 1132 | } | ||
| 1133 | switch (priv_cb_pos->major_file_operations) { | ||
| 1134 | case HECI_CLOSE: | ||
| 1135 | /* send disconnect message */ | ||
| 1136 | ret = _heci_bh_close(dev, slots, | ||
| 1137 | priv_cb_pos, | ||
| 1138 | file_ext, cmpl_list); | ||
| 1139 | if (ret != 0) | ||
| 1140 | return ret; | ||
| 1141 | |||
| 1142 | break; | ||
| 1143 | case HECI_READ: | ||
| 1144 | /* send flow control message */ | ||
| 1145 | ret = _heci_bh_read(dev, slots, | ||
| 1146 | priv_cb_pos, | ||
| 1147 | file_ext, cmpl_list); | ||
| 1148 | if (ret != 0) | ||
| 1149 | return ret; | ||
| 1150 | |||
| 1151 | break; | ||
| 1152 | case HECI_IOCTL: | ||
| 1153 | /* connect message */ | ||
| 1154 | if (!other_client_is_connecting(dev, file_ext)) | ||
| 1155 | continue; | ||
| 1156 | ret = _heci_bh_ioctl(dev, slots, | ||
| 1157 | priv_cb_pos, | ||
| 1158 | file_ext, cmpl_list); | ||
| 1159 | if (ret != 0) | ||
| 1160 | return ret; | ||
| 1161 | |||
| 1162 | break; | ||
| 1163 | |||
| 1164 | default: | ||
| 1165 | BUG(); | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | } | ||
| 1169 | } | ||
| 1170 | /* complete write list CB */ | ||
| 1171 | if ((dev->write_list.status == 0) | ||
| 1172 | && !list_empty(&dev->write_list.heci_cb.cb_list)) { | ||
| 1173 | DBG("complete write list cb.\n"); | ||
| 1174 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 1175 | &dev->write_list.heci_cb.cb_list, cb_list) { | ||
| 1176 | file_ext = (struct heci_file_private *) | ||
| 1177 | priv_cb_pos->file_private; | ||
| 1178 | |||
| 1179 | if (file_ext != NULL) { | ||
| 1180 | if (file_ext != &dev->iamthif_file_ext) { | ||
| 1181 | if (!flow_ctrl_creds(dev, file_ext)) { | ||
| 1182 | DBG("No flow control" | ||
| 1183 | " credentials for client" | ||
| 1184 | " %d, not sending.\n", | ||
| 1185 | file_ext->host_client_id); | ||
| 1186 | continue; | ||
| 1187 | } | ||
| 1188 | ret = _heci_bh_cmpl(dev, slots, | ||
| 1189 | priv_cb_pos, | ||
| 1190 | file_ext, | ||
| 1191 | cmpl_list); | ||
| 1192 | if (ret != 0) | ||
| 1193 | return ret; | ||
| 1194 | |||
| 1195 | } else if (file_ext == &dev->iamthif_file_ext) { | ||
| 1196 | /* IAMTHIF IOCTL */ | ||
| 1197 | DBG("complete pthi write cb.\n"); | ||
| 1198 | if (!flow_ctrl_creds(dev, file_ext)) { | ||
| 1199 | DBG("No flow control" | ||
| 1200 | " credentials for pthi" | ||
| 1201 | " client %d.\n", | ||
| 1202 | file_ext->host_client_id); | ||
| 1203 | continue; | ||
| 1204 | } | ||
| 1205 | ret = _heci_bh_cmpl_iamthif(dev, slots, | ||
| 1206 | priv_cb_pos, | ||
| 1207 | file_ext, | ||
| 1208 | cmpl_list); | ||
| 1209 | if (ret != 0) | ||
| 1210 | return ret; | ||
| 1211 | |||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | } | ||
| 1216 | } | ||
| 1217 | return 0; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | |||
| 1221 | /** | ||
| 1222 | * is_treat_specially_client - check if the message belong | ||
| 1223 | * to the file private data. | ||
| 1224 | * | ||
| 1225 | * @file_ext: private data of the file object | ||
| 1226 | * @rs: connect response bus message | ||
| 1227 | * @dev: Device object for our driver | ||
| 1228 | * | ||
| 1229 | * returns 0 on success, <0 on failure. | ||
| 1230 | */ | ||
| 1231 | static int is_treat_specially_client(struct heci_file_private *file_ext, | ||
| 1232 | struct hbm_client_connect_response *rs) | ||
| 1233 | { | ||
| 1234 | int ret = 0; | ||
| 1235 | |||
| 1236 | if ((file_ext->host_client_id == rs->host_addr) && | ||
| 1237 | (file_ext->me_client_id == rs->me_addr)) { | ||
| 1238 | if (rs->status == 0) { | ||
| 1239 | DBG("client connect status = 0x%08x.\n", rs->status); | ||
| 1240 | file_ext->state = HECI_FILE_CONNECTED; | ||
| 1241 | file_ext->status = 0; | ||
| 1242 | } else { | ||
| 1243 | DBG("client connect status = 0x%08x.\n", rs->status); | ||
| 1244 | file_ext->state = HECI_FILE_DISCONNECTED; | ||
| 1245 | file_ext->status = -ENODEV; | ||
| 1246 | } | ||
| 1247 | ret = 1; | ||
| 1248 | } | ||
| 1249 | DBG("client state = %d.\n", file_ext->state); | ||
| 1250 | return ret; | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | /** | ||
| 1254 | * heci_client_connect_response - connect response bh routine | ||
| 1255 | * | ||
| 1256 | * @dev: Device object for our driver | ||
| 1257 | * @rs: connect response bus message | ||
| 1258 | */ | ||
| 1259 | static void heci_client_connect_response(struct iamt_heci_device *dev, | ||
| 1260 | struct hbm_client_connect_response *rs) | ||
| 1261 | { | ||
| 1262 | |||
| 1263 | struct heci_file_private *file_ext; | ||
| 1264 | struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL; | ||
| 1265 | |||
| 1266 | /* if WD or iamthif client treat specially */ | ||
| 1267 | |||
| 1268 | if ((is_treat_specially_client(&(dev->wd_file_ext), rs)) || | ||
| 1269 | (is_treat_specially_client(&(dev->iamthif_file_ext), rs))) | ||
| 1270 | return; | ||
| 1271 | |||
| 1272 | if (dev->ctrl_rd_list.status == 0 | ||
| 1273 | && !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) { | ||
| 1274 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 1275 | &dev->ctrl_rd_list.heci_cb.cb_list, cb_list) { | ||
| 1276 | file_ext = (struct heci_file_private *) | ||
| 1277 | priv_cb_pos->file_private; | ||
| 1278 | if (file_ext == NULL) { | ||
| 1279 | list_del(&priv_cb_pos->cb_list); | ||
| 1280 | return; | ||
| 1281 | } | ||
| 1282 | if (HECI_IOCTL == priv_cb_pos->major_file_operations) { | ||
| 1283 | if (is_treat_specially_client(file_ext, rs)) { | ||
| 1284 | list_del(&priv_cb_pos->cb_list); | ||
| 1285 | file_ext->status = 0; | ||
| 1286 | file_ext->timer_count = 0; | ||
| 1287 | break; | ||
| 1288 | } | ||
| 1289 | } | ||
| 1290 | } | ||
| 1291 | } | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | /** | ||
| 1295 | * heci_client_disconnect_response - disconnect response bh routine | ||
| 1296 | * | ||
| 1297 | * @dev: Device object for our driver | ||
| 1298 | * @rs: disconnect response bus message | ||
| 1299 | */ | ||
| 1300 | static void heci_client_disconnect_response(struct iamt_heci_device *dev, | ||
| 1301 | struct hbm_client_connect_response *rs) | ||
| 1302 | { | ||
| 1303 | struct heci_file_private *file_ext; | ||
| 1304 | struct heci_cb_private *priv_cb_pos = NULL, *priv_cb_next = NULL; | ||
| 1305 | |||
| 1306 | if (dev->ctrl_rd_list.status == 0 | ||
| 1307 | && !list_empty(&dev->ctrl_rd_list.heci_cb.cb_list)) { | ||
| 1308 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 1309 | &dev->ctrl_rd_list.heci_cb.cb_list, cb_list) { | ||
| 1310 | file_ext = (struct heci_file_private *) | ||
| 1311 | priv_cb_pos->file_private; | ||
| 1312 | |||
| 1313 | if (file_ext == NULL) { | ||
| 1314 | list_del(&priv_cb_pos->cb_list); | ||
| 1315 | return; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | DBG("list_for_each_entry_safe in ctrl_rd_list.\n"); | ||
| 1319 | if ((file_ext->host_client_id == rs->host_addr) && | ||
| 1320 | (file_ext->me_client_id == rs->me_addr)) { | ||
| 1321 | |||
| 1322 | list_del(&priv_cb_pos->cb_list); | ||
| 1323 | if (rs->status == 0) { | ||
| 1324 | file_ext->state = | ||
| 1325 | HECI_FILE_DISCONNECTED; | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | file_ext->status = 0; | ||
| 1329 | file_ext->timer_count = 0; | ||
| 1330 | break; | ||
| 1331 | } | ||
| 1332 | } | ||
| 1333 | } | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | /** | ||
| 1337 | * same_flow_addr - tell they have same address. | ||
| 1338 | * | ||
| 1339 | * @file: private data of the file object. | ||
| 1340 | * @flow: flow control. | ||
| 1341 | * | ||
| 1342 | * returns !=0, same; 0,not. | ||
| 1343 | */ | ||
| 1344 | static int same_flow_addr(struct heci_file_private *file, | ||
| 1345 | struct hbm_flow_control *flow) | ||
| 1346 | { | ||
| 1347 | return ((file->host_client_id == flow->host_addr) | ||
| 1348 | && (file->me_client_id == flow->me_addr)); | ||
| 1349 | } | ||
| 1350 | |||
| 1351 | /** | ||
| 1352 | * add_single_flow_creds - add single buffer credentials. | ||
| 1353 | * | ||
| 1354 | * @file: private data ot the file object. | ||
| 1355 | * @flow: flow control. | ||
| 1356 | */ | ||
| 1357 | static void add_single_flow_creds(struct iamt_heci_device *dev, | ||
| 1358 | struct hbm_flow_control *flow) | ||
| 1359 | { | ||
| 1360 | struct heci_me_client *client; | ||
| 1361 | int i; | ||
| 1362 | |||
| 1363 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 1364 | client = &dev->me_clients[i]; | ||
| 1365 | if ((client != NULL) && | ||
| 1366 | (flow->me_addr == client->client_id)) { | ||
| 1367 | if (client->props.single_recv_buf != 0) { | ||
| 1368 | client->flow_ctrl_creds++; | ||
| 1369 | DBG("recv flow ctrl msg ME %d (single).\n", | ||
| 1370 | flow->me_addr); | ||
| 1371 | DBG("flow control credentials=%d.\n", | ||
| 1372 | client->flow_ctrl_creds); | ||
| 1373 | } else { | ||
| 1374 | BUG(); /* error in flow control */ | ||
| 1375 | } | ||
| 1376 | } | ||
| 1377 | } | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | /** | ||
| 1381 | * heci_client_flow_control_response - flow control response bh routine | ||
| 1382 | * | ||
| 1383 | * @dev: Device object for our driver | ||
| 1384 | * @flow_control: flow control response bus message | ||
| 1385 | */ | ||
| 1386 | static void heci_client_flow_control_response(struct iamt_heci_device *dev, | ||
| 1387 | struct hbm_flow_control *flow_control) | ||
| 1388 | { | ||
| 1389 | struct heci_file_private *file_pos = NULL; | ||
| 1390 | struct heci_file_private *file_next = NULL; | ||
| 1391 | |||
| 1392 | if (flow_control->host_addr == 0) { | ||
| 1393 | /* single receive buffer */ | ||
| 1394 | add_single_flow_creds(dev, flow_control); | ||
| 1395 | } else { | ||
| 1396 | /* normal connection */ | ||
| 1397 | list_for_each_entry_safe(file_pos, file_next, | ||
| 1398 | &dev->file_list, link) { | ||
| 1399 | DBG("list_for_each_entry_safe in file_list\n"); | ||
| 1400 | |||
| 1401 | DBG("file_ext of host client %d ME client %d.\n", | ||
| 1402 | file_pos->host_client_id, | ||
| 1403 | file_pos->me_client_id); | ||
| 1404 | DBG("flow ctrl msg for host %d ME %d.\n", | ||
| 1405 | flow_control->host_addr, | ||
| 1406 | flow_control->me_addr); | ||
| 1407 | if (same_flow_addr(file_pos, flow_control)) { | ||
| 1408 | DBG("recv ctrl msg for host %d ME %d.\n", | ||
| 1409 | flow_control->host_addr, | ||
| 1410 | flow_control->me_addr); | ||
| 1411 | file_pos->flow_ctrl_creds++; | ||
| 1412 | DBG("flow control credentials=%d.\n", | ||
| 1413 | file_pos->flow_ctrl_creds); | ||
| 1414 | break; | ||
| 1415 | } | ||
| 1416 | } | ||
| 1417 | } | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | /** | ||
| 1421 | * same_disconn_addr - tell they have same address | ||
| 1422 | * | ||
| 1423 | * @file: private data of the file object. | ||
| 1424 | * @disconn: disconnection request. | ||
| 1425 | * | ||
| 1426 | * returns !=0, same; 0,not. | ||
| 1427 | */ | ||
| 1428 | static int same_disconn_addr(struct heci_file_private *file, | ||
| 1429 | struct hbm_client_disconnect_request *disconn) | ||
| 1430 | { | ||
| 1431 | return ((file->host_client_id == disconn->host_addr) | ||
| 1432 | && (file->me_client_id == disconn->me_addr)); | ||
| 1433 | } | ||
| 1434 | |||
| 1435 | /** | ||
| 1436 | * heci_client_disconnect_request - disconnect request bh routine | ||
| 1437 | * | ||
| 1438 | * @dev: Device object for our driver. | ||
| 1439 | * @disconnect_req: disconnect request bus message. | ||
| 1440 | */ | ||
| 1441 | static void heci_client_disconnect_request(struct iamt_heci_device *dev, | ||
| 1442 | struct hbm_client_disconnect_request *disconnect_req) | ||
| 1443 | { | ||
| 1444 | struct heci_msg_hdr *heci_hdr; | ||
| 1445 | struct hbm_client_connect_response *disconnect_res; | ||
| 1446 | struct heci_file_private *file_pos = NULL; | ||
| 1447 | struct heci_file_private *file_next = NULL; | ||
| 1448 | |||
| 1449 | list_for_each_entry_safe(file_pos, file_next, &dev->file_list, link) { | ||
| 1450 | if (same_disconn_addr(file_pos, disconnect_req)) { | ||
| 1451 | DBG("disconnect request host client %d ME client %d.\n", | ||
| 1452 | disconnect_req->host_addr, | ||
| 1453 | disconnect_req->me_addr); | ||
| 1454 | file_pos->state = HECI_FILE_DISCONNECTED; | ||
| 1455 | file_pos->timer_count = 0; | ||
| 1456 | if (file_pos == &dev->wd_file_ext) { | ||
| 1457 | dev->wd_due_counter = 0; | ||
| 1458 | dev->wd_pending = 0; | ||
| 1459 | } else if (file_pos == &dev->iamthif_file_ext) | ||
| 1460 | dev->iamthif_timer = 0; | ||
| 1461 | |||
| 1462 | /* prepare disconnect response */ | ||
| 1463 | heci_hdr = | ||
| 1464 | (struct heci_msg_hdr *) &dev->ext_msg_buf[0]; | ||
| 1465 | heci_hdr->host_addr = 0; | ||
| 1466 | heci_hdr->me_addr = 0; | ||
| 1467 | heci_hdr->length = | ||
| 1468 | sizeof(struct hbm_client_connect_response); | ||
| 1469 | heci_hdr->msg_complete = 1; | ||
| 1470 | heci_hdr->reserved = 0; | ||
| 1471 | |||
| 1472 | disconnect_res = | ||
| 1473 | (struct hbm_client_connect_response *) | ||
| 1474 | &dev->ext_msg_buf[1]; | ||
| 1475 | disconnect_res->host_addr = file_pos->host_client_id; | ||
| 1476 | disconnect_res->me_addr = file_pos->me_client_id; | ||
| 1477 | *(__u8 *) (&disconnect_res->cmd) = | ||
| 1478 | CLIENT_DISCONNECT_RES_CMD; | ||
| 1479 | disconnect_res->status = 0; | ||
| 1480 | dev->extra_write_index = 2; | ||
| 1481 | break; | ||
| 1482 | } | ||
| 1483 | } | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | /** | ||
| 1487 | * heci_timer - timer function. | ||
| 1488 | * | ||
| 1489 | * @data: pointer to the device structure | ||
| 1490 | * | ||
| 1491 | * NOTE: This function is called by timer interrupt work | ||
| 1492 | */ | ||
| 1493 | void heci_wd_timer(unsigned long data) | ||
| 1494 | { | ||
| 1495 | struct iamt_heci_device *dev = (struct iamt_heci_device *) data; | ||
| 1496 | |||
| 1497 | DBG("send watchdog.\n"); | ||
| 1498 | spin_lock_bh(&dev->device_lock); | ||
| 1499 | if (dev->heci_state != HECI_ENABLED) { | ||
| 1500 | mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ)); | ||
| 1501 | spin_unlock_bh(&dev->device_lock); | ||
| 1502 | return; | ||
| 1503 | } | ||
| 1504 | if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) { | ||
| 1505 | mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ)); | ||
| 1506 | spin_unlock_bh(&dev->device_lock); | ||
| 1507 | return; | ||
| 1508 | } | ||
| 1509 | /* Watchdog */ | ||
| 1510 | if ((dev->wd_due_counter != 0) && (dev->wd_bypass == 0)) { | ||
| 1511 | if (--dev->wd_due_counter == 0) { | ||
| 1512 | if (dev->host_buffer_is_empty && | ||
| 1513 | flow_ctrl_creds(dev, &dev->wd_file_ext)) { | ||
| 1514 | dev->host_buffer_is_empty = 0; | ||
| 1515 | if (!heci_send_wd(dev)) { | ||
| 1516 | DBG("wd send failed.\n"); | ||
| 1517 | } else { | ||
| 1518 | flow_ctrl_reduce(dev, | ||
| 1519 | &dev->wd_file_ext); | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | if (dev->wd_timeout != 0) | ||
| 1523 | dev->wd_due_counter = 2; | ||
| 1524 | else | ||
| 1525 | dev->wd_due_counter = 0; | ||
| 1526 | |||
| 1527 | } else | ||
| 1528 | dev->wd_pending = 1; | ||
| 1529 | |||
| 1530 | } | ||
| 1531 | } | ||
| 1532 | if (dev->iamthif_stall_timer != 0) { | ||
| 1533 | if (--dev->iamthif_stall_timer == 0) { | ||
| 1534 | DBG("reseting because of hang to PTHI.\n"); | ||
| 1535 | heci_reset(dev, 1); | ||
| 1536 | dev->iamthif_msg_buf_size = 0; | ||
| 1537 | dev->iamthif_msg_buf_index = 0; | ||
| 1538 | dev->iamthif_canceled = 0; | ||
| 1539 | dev->iamthif_ioctl = 1; | ||
| 1540 | dev->iamthif_state = HECI_IAMTHIF_IDLE; | ||
| 1541 | dev->iamthif_timer = 0; | ||
| 1542 | spin_unlock_bh(&dev->device_lock); | ||
| 1543 | |||
| 1544 | if (dev->iamthif_current_cb) | ||
| 1545 | heci_free_cb_private(dev->iamthif_current_cb); | ||
| 1546 | |||
| 1547 | spin_lock_bh(&dev->device_lock); | ||
| 1548 | dev->iamthif_file_object = NULL; | ||
| 1549 | dev->iamthif_current_cb = NULL; | ||
| 1550 | run_next_iamthif_cmd(dev); | ||
| 1551 | } | ||
| 1552 | } | ||
| 1553 | mod_timer(&dev->wd_timer, round_jiffies(jiffies + 2 * HZ)); | ||
| 1554 | spin_unlock_bh(&dev->device_lock); | ||
| 1555 | } | ||
diff --git a/drivers/staging/heci/io_heci.c b/drivers/staging/heci/io_heci.c deleted file mode 100644 index 1a6faf88e16c..000000000000 --- a/drivers/staging/heci/io_heci.c +++ /dev/null | |||
| @@ -1,872 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Part of Intel(R) Manageability Engine Interface Linux driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2003 - 2008 Intel Corp. | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * 1. Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions, and the following disclaimer, | ||
| 12 | * without modification. | ||
| 13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
| 14 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
| 15 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
| 16 | * including a substantially similar Disclaimer requirement for further | ||
| 17 | * binary redistribution. | ||
| 18 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
| 19 | * of any contributors may be used to endorse or promote products derived | ||
| 20 | * from this software without specific prior written permission. | ||
| 21 | * | ||
| 22 | * Alternatively, this software may be distributed under the terms of the | ||
| 23 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
| 24 | * Software Foundation. | ||
| 25 | * | ||
| 26 | * NO WARRANTY | ||
| 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
| 30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| 31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| 35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
| 36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 37 | * POSSIBILITY OF SUCH DAMAGES. | ||
| 38 | * | ||
| 39 | */ | ||
| 40 | |||
| 41 | #include <linux/module.h> | ||
| 42 | #include <linux/moduleparam.h> | ||
| 43 | #include <linux/kernel.h> | ||
| 44 | #include <linux/slab.h> | ||
| 45 | #include <linux/fs.h> | ||
| 46 | #include <linux/errno.h> | ||
| 47 | #include <linux/types.h> | ||
| 48 | #include <linux/fcntl.h> | ||
| 49 | #include <linux/aio.h> | ||
| 50 | #include <linux/pci.h> | ||
| 51 | #include <linux/reboot.h> | ||
| 52 | #include <linux/poll.h> | ||
| 53 | #include <linux/init.h> | ||
| 54 | #include <linux/kdev_t.h> | ||
| 55 | #include <linux/ioctl.h> | ||
| 56 | #include <linux/cdev.h> | ||
| 57 | #include <linux/list.h> | ||
| 58 | #include <linux/unistd.h> | ||
| 59 | #include <linux/delay.h> | ||
| 60 | |||
| 61 | #include "heci_data_structures.h" | ||
| 62 | #include "heci.h" | ||
| 63 | #include "heci_interface.h" | ||
| 64 | #include "heci_version.h" | ||
| 65 | |||
| 66 | |||
| 67 | /** | ||
| 68 | * heci_ioctl_get_version - the get driver version IOCTL function | ||
| 69 | * | ||
| 70 | * @dev: Device object for our driver | ||
| 71 | * @if_num: minor number | ||
| 72 | * @*u_msg: pointer to user data struct in user space | ||
| 73 | * @k_msg: data in kernel on the stack | ||
| 74 | * @file_ext: private data of the file object | ||
| 75 | * | ||
| 76 | * returns 0 on success, <0 on failure. | ||
| 77 | */ | ||
| 78 | int heci_ioctl_get_version(struct iamt_heci_device *dev, int if_num, | ||
| 79 | struct heci_message_data __user *u_msg, | ||
| 80 | struct heci_message_data k_msg, | ||
| 81 | struct heci_file_private *file_ext) | ||
| 82 | { | ||
| 83 | int rets = 0; | ||
| 84 | struct heci_driver_version *version; | ||
| 85 | struct heci_message_data res_msg; | ||
| 86 | |||
| 87 | if ((if_num != HECI_MINOR_NUMBER) || (!dev) | ||
| 88 | || (!file_ext)) | ||
| 89 | return -ENODEV; | ||
| 90 | |||
| 91 | if (k_msg.size < (sizeof(struct heci_driver_version) - 2)) { | ||
| 92 | DBG("user buffer less than heci_driver_version.\n"); | ||
| 93 | return -EMSGSIZE; | ||
| 94 | } | ||
| 95 | |||
| 96 | res_msg.data = kmalloc(sizeof(struct heci_driver_version), GFP_KERNEL); | ||
| 97 | if (!res_msg.data) { | ||
| 98 | DBG("failed allocation response buffer size = %d.\n", | ||
| 99 | (int) sizeof(struct heci_driver_version)); | ||
| 100 | return -ENOMEM; | ||
| 101 | } | ||
| 102 | |||
| 103 | version = (struct heci_driver_version *) res_msg.data; | ||
| 104 | version->major = MAJOR_VERSION; | ||
| 105 | version->minor = MINOR_VERSION; | ||
| 106 | version->hotfix = QUICK_FIX_NUMBER; | ||
| 107 | version->build = VER_BUILD; | ||
| 108 | res_msg.size = sizeof(struct heci_driver_version); | ||
| 109 | if (k_msg.size < sizeof(struct heci_driver_version)) | ||
| 110 | res_msg.size -= 2; | ||
| 111 | |||
| 112 | rets = file_ext->status; | ||
| 113 | /* now copy the data to user space */ | ||
| 114 | if (copy_to_user((void __user *)k_msg.data, res_msg.data, res_msg.size)) { | ||
| 115 | rets = -EFAULT; | ||
| 116 | goto end; | ||
| 117 | } | ||
| 118 | if (put_user(res_msg.size, &u_msg->size)) { | ||
| 119 | rets = -EFAULT; | ||
| 120 | goto end; | ||
| 121 | } | ||
| 122 | end: | ||
| 123 | kfree(res_msg.data); | ||
| 124 | return rets; | ||
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 128 | * heci_ioctl_connect_client - the connect to fw client IOCTL function | ||
| 129 | * | ||
| 130 | * @dev: Device object for our driver | ||
| 131 | * @if_num: minor number | ||
| 132 | * @*u_msg: pointer to user data struct in user space | ||
| 133 | * @k_msg: data in kernel on the stack | ||
| 134 | * @file_ext: private data of the file object | ||
| 135 | * | ||
| 136 | * returns 0 on success, <0 on failure. | ||
| 137 | */ | ||
| 138 | int heci_ioctl_connect_client(struct iamt_heci_device *dev, int if_num, | ||
| 139 | struct heci_message_data __user *u_msg, | ||
| 140 | struct heci_message_data k_msg, | ||
| 141 | struct file *file) | ||
| 142 | { | ||
| 143 | int rets = 0; | ||
| 144 | struct heci_message_data req_msg, res_msg; | ||
| 145 | struct heci_cb_private *priv_cb = NULL; | ||
| 146 | struct heci_client *client; | ||
| 147 | struct heci_file_private *file_ext; | ||
| 148 | struct heci_file_private *file_pos = NULL; | ||
| 149 | struct heci_file_private *file_next = NULL; | ||
| 150 | long timeout = 15; /*15 second */ | ||
| 151 | __u8 i; | ||
| 152 | int err = 0; | ||
| 153 | |||
| 154 | if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file)) | ||
| 155 | return -ENODEV; | ||
| 156 | |||
| 157 | file_ext = file->private_data; | ||
| 158 | if (!file_ext) | ||
| 159 | return -ENODEV; | ||
| 160 | |||
| 161 | if (k_msg.size != sizeof(struct guid)) { | ||
| 162 | DBG("user buffer size is not equal to size of struct " | ||
| 163 | "guid(16).\n"); | ||
| 164 | return -EMSGSIZE; | ||
| 165 | } | ||
| 166 | |||
| 167 | if (!k_msg.data) | ||
| 168 | return -EIO; | ||
| 169 | |||
| 170 | req_msg.data = kmalloc(sizeof(struct guid), GFP_KERNEL); | ||
| 171 | res_msg.data = kmalloc(sizeof(struct heci_client), GFP_KERNEL); | ||
| 172 | |||
| 173 | if (!res_msg.data) { | ||
| 174 | DBG("failed allocation response buffer size = %d.\n", | ||
| 175 | (int) sizeof(struct heci_client)); | ||
| 176 | kfree(req_msg.data); | ||
| 177 | return -ENOMEM; | ||
| 178 | } | ||
| 179 | if (!req_msg.data) { | ||
| 180 | DBG("failed allocation request buffer size = %d.\n", | ||
| 181 | (int) sizeof(struct guid)); | ||
| 182 | kfree(res_msg.data); | ||
| 183 | return -ENOMEM; | ||
| 184 | } | ||
| 185 | req_msg.size = sizeof(struct guid); | ||
| 186 | res_msg.size = sizeof(struct heci_client); | ||
| 187 | |||
| 188 | /* copy the message to kernel space - | ||
| 189 | * use a pointer already copied into kernel space | ||
| 190 | */ | ||
| 191 | if (copy_from_user(req_msg.data, (void __user *)k_msg.data, k_msg.size)) { | ||
| 192 | rets = -EFAULT; | ||
| 193 | goto end; | ||
| 194 | } | ||
| 195 | /* buffered ioctl cb */ | ||
| 196 | priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL); | ||
| 197 | if (!priv_cb) { | ||
| 198 | rets = -ENOMEM; | ||
| 199 | goto end; | ||
| 200 | } | ||
| 201 | INIT_LIST_HEAD(&priv_cb->cb_list); | ||
| 202 | priv_cb->response_buffer.data = res_msg.data; | ||
| 203 | priv_cb->response_buffer.size = res_msg.size; | ||
| 204 | priv_cb->request_buffer.data = req_msg.data; | ||
| 205 | priv_cb->request_buffer.size = req_msg.size; | ||
| 206 | priv_cb->major_file_operations = HECI_IOCTL; | ||
| 207 | spin_lock_bh(&dev->device_lock); | ||
| 208 | if (dev->heci_state != HECI_ENABLED) { | ||
| 209 | rets = -ENODEV; | ||
| 210 | spin_unlock_bh(&dev->device_lock); | ||
| 211 | goto end; | ||
| 212 | } | ||
| 213 | if ((file_ext->state != HECI_FILE_INITIALIZING) && | ||
| 214 | (file_ext->state != HECI_FILE_DISCONNECTED)) { | ||
| 215 | rets = -EBUSY; | ||
| 216 | spin_unlock_bh(&dev->device_lock); | ||
| 217 | goto end; | ||
| 218 | } | ||
| 219 | |||
| 220 | /* find ME client we're trying to connect to */ | ||
| 221 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 222 | if (memcmp((struct guid *)req_msg.data, | ||
| 223 | &dev->me_clients[i].props.protocol_name, | ||
| 224 | sizeof(struct guid)) == 0) { | ||
| 225 | if (dev->me_clients[i].props.fixed_address == 0) { | ||
| 226 | file_ext->me_client_id = | ||
| 227 | dev->me_clients[i].client_id; | ||
| 228 | file_ext->state = HECI_FILE_CONNECTING; | ||
| 229 | } | ||
| 230 | break; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | /* if we're connecting to PTHI client so we will use the exist | ||
| 234 | * connection | ||
| 235 | */ | ||
| 236 | if (memcmp((struct guid *)req_msg.data, &heci_pthi_guid, | ||
| 237 | sizeof(struct guid)) == 0) { | ||
| 238 | if (dev->iamthif_file_ext.state != HECI_FILE_CONNECTED) { | ||
| 239 | rets = -ENODEV; | ||
| 240 | spin_unlock_bh(&dev->device_lock); | ||
| 241 | goto end; | ||
| 242 | } | ||
| 243 | dev->heci_host_clients[file_ext->host_client_id / 8] &= | ||
| 244 | ~(1 << (file_ext->host_client_id % 8)); | ||
| 245 | list_for_each_entry_safe(file_pos, | ||
| 246 | file_next, &dev->file_list, link) { | ||
| 247 | if (heci_fe_same_id(file_ext, file_pos)) { | ||
| 248 | DBG("remove file private data node host" | ||
| 249 | " client = %d, ME client = %d.\n", | ||
| 250 | file_pos->host_client_id, | ||
| 251 | file_pos->me_client_id); | ||
| 252 | list_del(&file_pos->link); | ||
| 253 | } | ||
| 254 | |||
| 255 | } | ||
| 256 | DBG("free file private data memory.\n"); | ||
| 257 | kfree(file_ext); | ||
| 258 | file_ext = NULL; | ||
| 259 | file->private_data = &dev->iamthif_file_ext; | ||
| 260 | client = (struct heci_client *) res_msg.data; | ||
| 261 | client->max_msg_length = | ||
| 262 | dev->me_clients[i].props.max_msg_length; | ||
| 263 | client->protocol_version = | ||
| 264 | dev->me_clients[i].props.protocol_version; | ||
| 265 | rets = dev->iamthif_file_ext.status; | ||
| 266 | spin_unlock_bh(&dev->device_lock); | ||
| 267 | |||
| 268 | /* now copy the data to user space */ | ||
| 269 | if (copy_to_user((void __user *)k_msg.data, | ||
| 270 | res_msg.data, res_msg.size)) { | ||
| 271 | rets = -EFAULT; | ||
| 272 | goto end; | ||
| 273 | } | ||
| 274 | if (put_user(res_msg.size, &u_msg->size)) { | ||
| 275 | rets = -EFAULT; | ||
| 276 | goto end; | ||
| 277 | } | ||
| 278 | goto end; | ||
| 279 | } | ||
| 280 | spin_unlock_bh(&dev->device_lock); | ||
| 281 | |||
| 282 | spin_lock(&file_ext->file_lock); | ||
| 283 | spin_lock_bh(&dev->device_lock); | ||
| 284 | if (file_ext->state != HECI_FILE_CONNECTING) { | ||
| 285 | rets = -ENODEV; | ||
| 286 | spin_unlock_bh(&dev->device_lock); | ||
| 287 | spin_unlock(&file_ext->file_lock); | ||
| 288 | goto end; | ||
| 289 | } | ||
| 290 | /* prepare the output buffer */ | ||
| 291 | client = (struct heci_client *) res_msg.data; | ||
| 292 | client->max_msg_length = dev->me_clients[i].props.max_msg_length; | ||
| 293 | client->protocol_version = dev->me_clients[i].props.protocol_version; | ||
| 294 | if (dev->host_buffer_is_empty | ||
| 295 | && !other_client_is_connecting(dev, file_ext)) { | ||
| 296 | dev->host_buffer_is_empty = 0; | ||
| 297 | if (!heci_connect(dev, file_ext)) { | ||
| 298 | rets = -ENODEV; | ||
| 299 | spin_unlock_bh(&dev->device_lock); | ||
| 300 | spin_unlock(&file_ext->file_lock); | ||
| 301 | goto end; | ||
| 302 | } else { | ||
| 303 | file_ext->timer_count = HECI_CONNECT_TIMEOUT; | ||
| 304 | priv_cb->file_private = file_ext; | ||
| 305 | list_add_tail(&priv_cb->cb_list, | ||
| 306 | &dev->ctrl_rd_list.heci_cb. | ||
| 307 | cb_list); | ||
| 308 | } | ||
| 309 | |||
| 310 | |||
| 311 | } else { | ||
| 312 | priv_cb->file_private = file_ext; | ||
| 313 | DBG("add connect cb to control write list.\n"); | ||
| 314 | list_add_tail(&priv_cb->cb_list, | ||
| 315 | &dev->ctrl_wr_list.heci_cb.cb_list); | ||
| 316 | } | ||
| 317 | spin_unlock_bh(&dev->device_lock); | ||
| 318 | spin_unlock(&file_ext->file_lock); | ||
| 319 | err = wait_event_timeout(dev->wait_recvd_msg, | ||
| 320 | (HECI_FILE_CONNECTED == file_ext->state | ||
| 321 | || HECI_FILE_DISCONNECTED == file_ext->state), | ||
| 322 | timeout * HZ); | ||
| 323 | |||
| 324 | spin_lock_bh(&dev->device_lock); | ||
| 325 | if (HECI_FILE_CONNECTED == file_ext->state) { | ||
| 326 | spin_unlock_bh(&dev->device_lock); | ||
| 327 | DBG("successfully connected to FW client.\n"); | ||
| 328 | rets = file_ext->status; | ||
| 329 | /* now copy the data to user space */ | ||
| 330 | if (copy_to_user((void __user *)k_msg.data, | ||
| 331 | res_msg.data, res_msg.size)) { | ||
| 332 | rets = -EFAULT; | ||
| 333 | goto end; | ||
| 334 | } | ||
| 335 | if (put_user(res_msg.size, &u_msg->size)) { | ||
| 336 | rets = -EFAULT; | ||
| 337 | goto end; | ||
| 338 | } | ||
| 339 | goto end; | ||
| 340 | } else { | ||
| 341 | DBG("failed to connect to FW client.file_ext->state = %d.\n", | ||
| 342 | file_ext->state); | ||
| 343 | spin_unlock_bh(&dev->device_lock); | ||
| 344 | if (!err) { | ||
| 345 | DBG("wait_event_interruptible_timeout failed on client" | ||
| 346 | " connect message fw response message.\n"); | ||
| 347 | } | ||
| 348 | rets = -EFAULT; | ||
| 349 | goto remove_list; | ||
| 350 | } | ||
| 351 | |||
| 352 | remove_list: | ||
| 353 | if (priv_cb) { | ||
| 354 | spin_lock_bh(&dev->device_lock); | ||
| 355 | heci_flush_list(&dev->ctrl_rd_list, file_ext); | ||
| 356 | heci_flush_list(&dev->ctrl_wr_list, file_ext); | ||
| 357 | spin_unlock_bh(&dev->device_lock); | ||
| 358 | } | ||
| 359 | end: | ||
| 360 | DBG("free connect cb memory."); | ||
| 361 | kfree(req_msg.data); | ||
| 362 | kfree(res_msg.data); | ||
| 363 | kfree(priv_cb); | ||
| 364 | return rets; | ||
| 365 | } | ||
| 366 | |||
| 367 | /** | ||
| 368 | * heci_ioctl_wd - the wd IOCTL function | ||
| 369 | * | ||
| 370 | * @dev: Device object for our driver | ||
| 371 | * @if_num: minor number | ||
| 372 | * @k_msg: data in kernel on the stack | ||
| 373 | * @file_ext: private data of the file object | ||
| 374 | * | ||
| 375 | * returns 0 on success, <0 on failure. | ||
| 376 | */ | ||
| 377 | int heci_ioctl_wd(struct iamt_heci_device *dev, int if_num, | ||
| 378 | struct heci_message_data k_msg, | ||
| 379 | struct heci_file_private *file_ext) | ||
| 380 | { | ||
| 381 | int rets = 0; | ||
| 382 | struct heci_message_data req_msg; /*in kernel on the stack */ | ||
| 383 | |||
| 384 | if (if_num != HECI_MINOR_NUMBER) | ||
| 385 | return -ENODEV; | ||
| 386 | |||
| 387 | spin_lock(&file_ext->file_lock); | ||
| 388 | if (k_msg.size != HECI_WATCHDOG_DATA_SIZE) { | ||
| 389 | DBG("user buffer has invalid size.\n"); | ||
| 390 | spin_unlock(&file_ext->file_lock); | ||
| 391 | return -EMSGSIZE; | ||
| 392 | } | ||
| 393 | spin_unlock(&file_ext->file_lock); | ||
| 394 | |||
| 395 | req_msg.data = kmalloc(HECI_WATCHDOG_DATA_SIZE, GFP_KERNEL); | ||
| 396 | if (!req_msg.data) { | ||
| 397 | DBG("failed allocation request buffer size = %d.\n", | ||
| 398 | HECI_WATCHDOG_DATA_SIZE); | ||
| 399 | return -ENOMEM; | ||
| 400 | } | ||
| 401 | req_msg.size = HECI_WATCHDOG_DATA_SIZE; | ||
| 402 | |||
| 403 | /* copy the message to kernel space - use a pointer already | ||
| 404 | * copied into kernel space | ||
| 405 | */ | ||
| 406 | if (copy_from_user(req_msg.data, | ||
| 407 | (void __user *)k_msg.data, req_msg.size)) { | ||
| 408 | rets = -EFAULT; | ||
| 409 | goto end; | ||
| 410 | } | ||
| 411 | spin_lock_bh(&dev->device_lock); | ||
| 412 | if (dev->heci_state != HECI_ENABLED) { | ||
| 413 | rets = -ENODEV; | ||
| 414 | spin_unlock_bh(&dev->device_lock); | ||
| 415 | goto end; | ||
| 416 | } | ||
| 417 | |||
| 418 | if (dev->wd_file_ext.state != HECI_FILE_CONNECTED) { | ||
| 419 | rets = -ENODEV; | ||
| 420 | spin_unlock_bh(&dev->device_lock); | ||
| 421 | goto end; | ||
| 422 | } | ||
| 423 | if (!dev->asf_mode) { | ||
| 424 | rets = -EIO; | ||
| 425 | spin_unlock_bh(&dev->device_lock); | ||
| 426 | goto end; | ||
| 427 | } | ||
| 428 | |||
| 429 | memcpy(&dev->wd_data[HECI_WD_PARAMS_SIZE], req_msg.data, | ||
| 430 | HECI_WATCHDOG_DATA_SIZE); | ||
| 431 | |||
| 432 | dev->wd_timeout = (req_msg.data[1] << 8) + req_msg.data[0]; | ||
| 433 | dev->wd_pending = 0; | ||
| 434 | dev->wd_due_counter = 1; /* next timer */ | ||
| 435 | if (dev->wd_timeout == 0) { | ||
| 436 | memcpy(dev->wd_data, heci_stop_wd_params, | ||
| 437 | HECI_WD_PARAMS_SIZE); | ||
| 438 | } else { | ||
| 439 | memcpy(dev->wd_data, heci_start_wd_params, | ||
| 440 | HECI_WD_PARAMS_SIZE); | ||
| 441 | mod_timer(&dev->wd_timer, jiffies); | ||
| 442 | } | ||
| 443 | spin_unlock_bh(&dev->device_lock); | ||
| 444 | end: | ||
| 445 | kfree(req_msg.data); | ||
| 446 | return rets; | ||
| 447 | } | ||
| 448 | |||
| 449 | |||
| 450 | /** | ||
| 451 | * heci_ioctl_bypass_wd - the bypass_wd IOCTL function | ||
| 452 | * | ||
| 453 | * @dev: Device object for our driver | ||
| 454 | * @if_num: minor number | ||
| 455 | * @k_msg: data in kernel on the stack | ||
| 456 | * @file_ext: private data of the file object | ||
| 457 | * | ||
| 458 | * returns 0 on success, <0 on failure. | ||
| 459 | */ | ||
| 460 | int heci_ioctl_bypass_wd(struct iamt_heci_device *dev, int if_num, | ||
| 461 | struct heci_message_data k_msg, | ||
| 462 | struct heci_file_private *file_ext) | ||
| 463 | { | ||
| 464 | __u8 flag = 0; | ||
| 465 | int rets = 0; | ||
| 466 | |||
| 467 | if (if_num != HECI_MINOR_NUMBER) | ||
| 468 | return -ENODEV; | ||
| 469 | |||
| 470 | spin_lock(&file_ext->file_lock); | ||
| 471 | if (k_msg.size < 1) { | ||
| 472 | DBG("user buffer less than HECI_WATCHDOG_DATA_SIZE.\n"); | ||
| 473 | spin_unlock(&file_ext->file_lock); | ||
| 474 | return -EMSGSIZE; | ||
| 475 | } | ||
| 476 | spin_unlock(&file_ext->file_lock); | ||
| 477 | if (copy_from_user(&flag, (void __user *)k_msg.data, 1)) { | ||
| 478 | rets = -EFAULT; | ||
| 479 | goto end; | ||
| 480 | } | ||
| 481 | |||
| 482 | spin_lock_bh(&dev->device_lock); | ||
| 483 | flag = flag ? (1) : (0); | ||
| 484 | dev->wd_bypass = flag; | ||
| 485 | spin_unlock_bh(&dev->device_lock); | ||
| 486 | end: | ||
| 487 | return rets; | ||
| 488 | } | ||
| 489 | |||
| 490 | /** | ||
| 491 | * find_pthi_read_list_entry - finds a PTHIlist entry for current file | ||
| 492 | * | ||
| 493 | * @dev: Device object for our driver | ||
| 494 | * @file: pointer to file object | ||
| 495 | * | ||
| 496 | * returns returned a list entry on success, NULL on failure. | ||
| 497 | */ | ||
| 498 | struct heci_cb_private *find_pthi_read_list_entry( | ||
| 499 | struct iamt_heci_device *dev, | ||
| 500 | struct file *file) | ||
| 501 | { | ||
| 502 | struct heci_file_private *file_ext_temp; | ||
| 503 | struct heci_cb_private *priv_cb_pos = NULL; | ||
| 504 | struct heci_cb_private *priv_cb_next = NULL; | ||
| 505 | |||
| 506 | if ((dev->pthi_read_complete_list.status == 0) && | ||
| 507 | !list_empty(&dev->pthi_read_complete_list.heci_cb.cb_list)) { | ||
| 508 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 509 | &dev->pthi_read_complete_list.heci_cb.cb_list, cb_list) { | ||
| 510 | file_ext_temp = (struct heci_file_private *) | ||
| 511 | priv_cb_pos->file_private; | ||
| 512 | if ((file_ext_temp != NULL) && | ||
| 513 | (file_ext_temp == &dev->iamthif_file_ext) && | ||
| 514 | (priv_cb_pos->file_object == file)) | ||
| 515 | return priv_cb_pos; | ||
| 516 | } | ||
| 517 | } | ||
| 518 | return NULL; | ||
| 519 | } | ||
| 520 | |||
| 521 | /** | ||
| 522 | * pthi_read - read data from pthi client | ||
| 523 | * | ||
| 524 | * @dev: Device object for our driver | ||
| 525 | * @if_num: minor number | ||
| 526 | * @file: pointer to file object | ||
| 527 | * @*ubuf: pointer to user data in user space | ||
| 528 | * @length: data length to read | ||
| 529 | * @offset: data read offset | ||
| 530 | * | ||
| 531 | * returns | ||
| 532 | * returned data length on success, | ||
| 533 | * zero if no data to read, | ||
| 534 | * negative on failure. | ||
| 535 | */ | ||
| 536 | int pthi_read(struct iamt_heci_device *dev, int if_num, struct file *file, | ||
| 537 | char __user *ubuf, size_t length, loff_t *offset) | ||
| 538 | { | ||
| 539 | int rets = 0; | ||
| 540 | struct heci_cb_private *priv_cb = NULL; | ||
| 541 | struct heci_file_private *file_ext = file->private_data; | ||
| 542 | __u8 i; | ||
| 543 | unsigned long currtime = get_seconds(); | ||
| 544 | |||
| 545 | if ((if_num != HECI_MINOR_NUMBER) || (!dev)) | ||
| 546 | return -ENODEV; | ||
| 547 | |||
| 548 | if ((file_ext == NULL) || (file_ext != &dev->iamthif_file_ext)) | ||
| 549 | return -ENODEV; | ||
| 550 | |||
| 551 | spin_lock_bh(&dev->device_lock); | ||
| 552 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 553 | if (dev->me_clients[i].client_id == | ||
| 554 | dev->iamthif_file_ext.me_client_id) | ||
| 555 | break; | ||
| 556 | } | ||
| 557 | BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); | ||
| 558 | if ((i == dev->num_heci_me_clients) | ||
| 559 | || (dev->me_clients[i].client_id != | ||
| 560 | dev->iamthif_file_ext.me_client_id)) { | ||
| 561 | DBG("PTHI client not found.\n"); | ||
| 562 | spin_unlock_bh(&dev->device_lock); | ||
| 563 | return -ENODEV; | ||
| 564 | } | ||
| 565 | priv_cb = find_pthi_read_list_entry(dev, file); | ||
| 566 | if (!priv_cb) { | ||
| 567 | spin_unlock_bh(&dev->device_lock); | ||
| 568 | return 0; /* No more data to read */ | ||
| 569 | } else { | ||
| 570 | if (priv_cb && | ||
| 571 | (currtime - priv_cb->read_time > IAMTHIF_READ_TIMER)) { | ||
| 572 | /* 15 sec for the message has expired */ | ||
| 573 | list_del(&priv_cb->cb_list); | ||
| 574 | spin_unlock_bh(&dev->device_lock); | ||
| 575 | rets = -ETIMEDOUT; | ||
| 576 | goto free; | ||
| 577 | } | ||
| 578 | /* if the whole message will fit remove it from the list */ | ||
| 579 | if ((priv_cb->information >= *offset) && | ||
| 580 | (length >= (priv_cb->information - *offset))) | ||
| 581 | list_del(&priv_cb->cb_list); | ||
| 582 | else if ((priv_cb->information > 0) && | ||
| 583 | (priv_cb->information <= *offset)) { | ||
| 584 | /* end of the message has been reached */ | ||
| 585 | list_del(&priv_cb->cb_list); | ||
| 586 | rets = 0; | ||
| 587 | spin_unlock_bh(&dev->device_lock); | ||
| 588 | goto free; | ||
| 589 | } | ||
| 590 | /* else means that not full buffer will be read and do not | ||
| 591 | * remove message from deletion list | ||
| 592 | */ | ||
| 593 | } | ||
| 594 | DBG("pthi priv_cb->response_buffer size - %d\n", | ||
| 595 | priv_cb->response_buffer.size); | ||
| 596 | DBG("pthi priv_cb->information - %lu\n", | ||
| 597 | priv_cb->information); | ||
| 598 | spin_unlock_bh(&dev->device_lock); | ||
| 599 | |||
| 600 | /* length is being turncated to PAGE_SIZE, however, | ||
| 601 | * the information may be longer */ | ||
| 602 | length = length < (priv_cb->information - *offset) ? | ||
| 603 | length : (priv_cb->information - *offset); | ||
| 604 | |||
| 605 | if (copy_to_user(ubuf, | ||
| 606 | priv_cb->response_buffer.data + *offset, | ||
| 607 | length)) | ||
| 608 | rets = -EFAULT; | ||
| 609 | else { | ||
| 610 | rets = length; | ||
| 611 | if ((*offset + length) < priv_cb->information) { | ||
| 612 | *offset += length; | ||
| 613 | goto out; | ||
| 614 | } | ||
| 615 | } | ||
| 616 | free: | ||
| 617 | DBG("free pthi cb memory.\n"); | ||
| 618 | *offset = 0; | ||
| 619 | heci_free_cb_private(priv_cb); | ||
| 620 | out: | ||
| 621 | return rets; | ||
| 622 | } | ||
| 623 | |||
| 624 | /** | ||
| 625 | * heci_start_read - the start read client message function. | ||
| 626 | * | ||
| 627 | * @dev: Device object for our driver | ||
| 628 | * @if_num: minor number | ||
| 629 | * @file_ext: private data of the file object | ||
| 630 | * | ||
| 631 | * returns 0 on success, <0 on failure. | ||
| 632 | */ | ||
| 633 | int heci_start_read(struct iamt_heci_device *dev, int if_num, | ||
| 634 | struct heci_file_private *file_ext) | ||
| 635 | { | ||
| 636 | int rets = 0; | ||
| 637 | __u8 i; | ||
| 638 | struct heci_cb_private *priv_cb = NULL; | ||
| 639 | |||
| 640 | if ((if_num != HECI_MINOR_NUMBER) || (!dev) || (!file_ext)) { | ||
| 641 | DBG("received wrong function input param.\n"); | ||
| 642 | return -ENODEV; | ||
| 643 | } | ||
| 644 | |||
| 645 | spin_lock_bh(&dev->device_lock); | ||
| 646 | if (file_ext->state != HECI_FILE_CONNECTED) { | ||
| 647 | spin_unlock_bh(&dev->device_lock); | ||
| 648 | return -ENODEV; | ||
| 649 | } | ||
| 650 | |||
| 651 | if (dev->heci_state != HECI_ENABLED) { | ||
| 652 | spin_unlock_bh(&dev->device_lock); | ||
| 653 | return -ENODEV; | ||
| 654 | } | ||
| 655 | spin_unlock_bh(&dev->device_lock); | ||
| 656 | DBG("check if read is pending.\n"); | ||
| 657 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 658 | if ((file_ext->read_pending) || (file_ext->read_cb != NULL)) { | ||
| 659 | DBG("read is pending.\n"); | ||
| 660 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 661 | return -EBUSY; | ||
| 662 | } | ||
| 663 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 664 | |||
| 665 | priv_cb = kzalloc(sizeof(struct heci_cb_private), GFP_KERNEL); | ||
| 666 | if (!priv_cb) | ||
| 667 | return -ENOMEM; | ||
| 668 | |||
| 669 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 670 | DBG("allocation call back success\n" | ||
| 671 | "host client = %d, ME client = %d\n", | ||
| 672 | file_ext->host_client_id, file_ext->me_client_id); | ||
| 673 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 674 | |||
| 675 | spin_lock_bh(&dev->device_lock); | ||
| 676 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 677 | for (i = 0; i < dev->num_heci_me_clients; i++) { | ||
| 678 | if (dev->me_clients[i].client_id == file_ext->me_client_id) | ||
| 679 | break; | ||
| 680 | |||
| 681 | } | ||
| 682 | |||
| 683 | BUG_ON(dev->me_clients[i].client_id != file_ext->me_client_id); | ||
| 684 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 685 | if (i == dev->num_heci_me_clients) { | ||
| 686 | rets = -ENODEV; | ||
| 687 | goto unlock; | ||
| 688 | } | ||
| 689 | |||
| 690 | priv_cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; | ||
| 691 | spin_unlock_bh(&dev->device_lock); | ||
| 692 | priv_cb->response_buffer.data = | ||
| 693 | kmalloc(priv_cb->response_buffer.size, GFP_KERNEL); | ||
| 694 | if (!priv_cb->response_buffer.data) { | ||
| 695 | rets = -ENOMEM; | ||
| 696 | goto fail; | ||
| 697 | } | ||
| 698 | DBG("allocation call back data success.\n"); | ||
| 699 | priv_cb->major_file_operations = HECI_READ; | ||
| 700 | /* make sure information is zero before we start */ | ||
| 701 | priv_cb->information = 0; | ||
| 702 | priv_cb->file_private = (void *) file_ext; | ||
| 703 | spin_lock_bh(&dev->device_lock); | ||
| 704 | spin_lock_bh(&file_ext->read_io_lock); | ||
| 705 | file_ext->read_cb = priv_cb; | ||
| 706 | if (dev->host_buffer_is_empty) { | ||
| 707 | dev->host_buffer_is_empty = 0; | ||
| 708 | if (!heci_send_flow_control(dev, file_ext)) { | ||
| 709 | rets = -ENODEV; | ||
| 710 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 711 | goto unlock; | ||
| 712 | } else { | ||
| 713 | list_add_tail(&priv_cb->cb_list, | ||
| 714 | &dev->read_list.heci_cb.cb_list); | ||
| 715 | } | ||
| 716 | } else { | ||
| 717 | list_add_tail(&priv_cb->cb_list, | ||
| 718 | &dev->ctrl_wr_list.heci_cb.cb_list); | ||
| 719 | } | ||
| 720 | spin_unlock_bh(&file_ext->read_io_lock); | ||
| 721 | spin_unlock_bh(&dev->device_lock); | ||
| 722 | return rets; | ||
| 723 | unlock: | ||
| 724 | spin_unlock_bh(&dev->device_lock); | ||
| 725 | fail: | ||
| 726 | heci_free_cb_private(priv_cb); | ||
| 727 | return rets; | ||
| 728 | } | ||
| 729 | |||
| 730 | /** | ||
| 731 | * pthi_write - write iamthif data to pthi client | ||
| 732 | * | ||
| 733 | * @dev: Device object for our driver | ||
| 734 | * @priv_cb: heci call back struct | ||
| 735 | * | ||
| 736 | * returns 0 on success, <0 on failure. | ||
| 737 | */ | ||
| 738 | int pthi_write(struct iamt_heci_device *dev, | ||
| 739 | struct heci_cb_private *priv_cb) | ||
| 740 | { | ||
| 741 | int rets = 0; | ||
| 742 | struct heci_msg_hdr heci_hdr; | ||
| 743 | |||
| 744 | if ((!dev) || (!priv_cb)) | ||
| 745 | return -ENODEV; | ||
| 746 | |||
| 747 | DBG("write data to pthi client.\n"); | ||
| 748 | |||
| 749 | dev->iamthif_state = HECI_IAMTHIF_WRITING; | ||
| 750 | dev->iamthif_current_cb = priv_cb; | ||
| 751 | dev->iamthif_file_object = priv_cb->file_object; | ||
| 752 | dev->iamthif_canceled = 0; | ||
| 753 | dev->iamthif_ioctl = 1; | ||
| 754 | dev->iamthif_msg_buf_size = priv_cb->request_buffer.size; | ||
| 755 | memcpy(dev->iamthif_msg_buf, priv_cb->request_buffer.data, | ||
| 756 | priv_cb->request_buffer.size); | ||
| 757 | |||
| 758 | if (flow_ctrl_creds(dev, &dev->iamthif_file_ext) && | ||
| 759 | dev->host_buffer_is_empty) { | ||
| 760 | dev->host_buffer_is_empty = 0; | ||
| 761 | if (priv_cb->request_buffer.size > | ||
| 762 | (((dev->host_hw_state & H_CBD) >> 24) * | ||
| 763 | sizeof(__u32)) - sizeof(struct heci_msg_hdr)) { | ||
| 764 | heci_hdr.length = | ||
| 765 | (((dev->host_hw_state & H_CBD) >> 24) * | ||
| 766 | sizeof(__u32)) - sizeof(struct heci_msg_hdr); | ||
| 767 | heci_hdr.msg_complete = 0; | ||
| 768 | } else { | ||
| 769 | heci_hdr.length = priv_cb->request_buffer.size; | ||
| 770 | heci_hdr.msg_complete = 1; | ||
| 771 | } | ||
| 772 | |||
| 773 | heci_hdr.host_addr = dev->iamthif_file_ext.host_client_id; | ||
| 774 | heci_hdr.me_addr = dev->iamthif_file_ext.me_client_id; | ||
| 775 | heci_hdr.reserved = 0; | ||
| 776 | dev->iamthif_msg_buf_index += heci_hdr.length; | ||
| 777 | if (!heci_write_message(dev, &heci_hdr, | ||
| 778 | (unsigned char *)(dev->iamthif_msg_buf), | ||
| 779 | heci_hdr.length)) | ||
| 780 | return -ENODEV; | ||
| 781 | |||
| 782 | if (heci_hdr.msg_complete) { | ||
| 783 | flow_ctrl_reduce(dev, &dev->iamthif_file_ext); | ||
| 784 | dev->iamthif_flow_control_pending = 1; | ||
| 785 | dev->iamthif_state = HECI_IAMTHIF_FLOW_CONTROL; | ||
| 786 | DBG("add pthi cb to write waiting list\n"); | ||
| 787 | dev->iamthif_current_cb = priv_cb; | ||
| 788 | dev->iamthif_file_object = priv_cb->file_object; | ||
| 789 | list_add_tail(&priv_cb->cb_list, | ||
| 790 | &dev->write_waiting_list.heci_cb.cb_list); | ||
| 791 | } else { | ||
| 792 | DBG("message does not complete, " | ||
| 793 | "so add pthi cb to write list.\n"); | ||
| 794 | list_add_tail(&priv_cb->cb_list, | ||
| 795 | &dev->write_list.heci_cb.cb_list); | ||
| 796 | } | ||
| 797 | } else { | ||
| 798 | if (!(dev->host_buffer_is_empty)) | ||
| 799 | DBG("host buffer is not empty"); | ||
| 800 | |||
| 801 | DBG("No flow control credentials, " | ||
| 802 | "so add iamthif cb to write list.\n"); | ||
| 803 | list_add_tail(&priv_cb->cb_list, | ||
| 804 | &dev->write_list.heci_cb.cb_list); | ||
| 805 | } | ||
| 806 | return rets; | ||
| 807 | } | ||
| 808 | |||
| 809 | /** | ||
| 810 | * iamthif_ioctl_send_msg - send cmd data to pthi client | ||
| 811 | * | ||
| 812 | * @dev: Device object for our driver | ||
| 813 | * | ||
| 814 | * returns 0 on success, <0 on failure. | ||
| 815 | */ | ||
| 816 | void run_next_iamthif_cmd(struct iamt_heci_device *dev) | ||
| 817 | { | ||
| 818 | struct heci_file_private *file_ext_tmp; | ||
| 819 | struct heci_cb_private *priv_cb_pos = NULL; | ||
| 820 | struct heci_cb_private *priv_cb_next = NULL; | ||
| 821 | int status = 0; | ||
| 822 | |||
| 823 | if (!dev) | ||
| 824 | return; | ||
| 825 | |||
| 826 | dev->iamthif_msg_buf_size = 0; | ||
| 827 | dev->iamthif_msg_buf_index = 0; | ||
| 828 | dev->iamthif_canceled = 0; | ||
| 829 | dev->iamthif_ioctl = 1; | ||
| 830 | dev->iamthif_state = HECI_IAMTHIF_IDLE; | ||
| 831 | dev->iamthif_timer = 0; | ||
| 832 | dev->iamthif_file_object = NULL; | ||
| 833 | |||
| 834 | if (dev->pthi_cmd_list.status == 0 && | ||
| 835 | !list_empty(&dev->pthi_cmd_list.heci_cb.cb_list)) { | ||
| 836 | DBG("complete pthi cmd_list cb.\n"); | ||
| 837 | |||
| 838 | list_for_each_entry_safe(priv_cb_pos, priv_cb_next, | ||
| 839 | &dev->pthi_cmd_list.heci_cb.cb_list, cb_list) { | ||
| 840 | list_del(&priv_cb_pos->cb_list); | ||
| 841 | file_ext_tmp = (struct heci_file_private *) | ||
| 842 | priv_cb_pos->file_private; | ||
| 843 | |||
| 844 | if ((file_ext_tmp != NULL) && | ||
| 845 | (file_ext_tmp == &dev->iamthif_file_ext)) { | ||
| 846 | status = pthi_write(dev, priv_cb_pos); | ||
| 847 | if (status != 0) { | ||
| 848 | DBG("pthi write failed status = %d\n", | ||
| 849 | status); | ||
| 850 | return; | ||
| 851 | } | ||
| 852 | break; | ||
| 853 | } | ||
| 854 | } | ||
| 855 | } | ||
| 856 | } | ||
| 857 | |||
| 858 | /** | ||
| 859 | * heci_free_cb_private - free heci_cb_private related memory | ||
| 860 | * | ||
| 861 | * @priv_cb: heci callback struct | ||
| 862 | */ | ||
| 863 | void heci_free_cb_private(struct heci_cb_private *priv_cb) | ||
| 864 | { | ||
| 865 | if (priv_cb == NULL) | ||
| 866 | return; | ||
| 867 | |||
| 868 | kfree(priv_cb->request_buffer.data); | ||
| 869 | kfree(priv_cb->response_buffer.data); | ||
| 870 | kfree(priv_cb); | ||
| 871 | } | ||
| 872 | |||
