aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/heci/Kconfig7
-rw-r--r--drivers/staging/heci/Makefile9
-rw-r--r--drivers/staging/heci/TODO6
-rw-r--r--drivers/staging/heci/heci.h175
-rw-r--r--drivers/staging/heci/heci_data_structures.h529
-rw-r--r--drivers/staging/heci/heci_init.c1083
-rw-r--r--drivers/staging/heci/heci_interface.c498
-rw-r--r--drivers/staging/heci/heci_interface.h170
-rw-r--r--drivers/staging/heci/heci_main.c1576
-rw-r--r--drivers/staging/heci/heci_version.h54
-rw-r--r--drivers/staging/heci/interrupt.c1555
-rw-r--r--drivers/staging/heci/io_heci.c872
14 files changed, 0 insertions, 6537 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 66188a5bf44..e86a6716156 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -103,8 +103,6 @@ source "drivers/staging/phison/Kconfig"
103 103
104source "drivers/staging/p9auth/Kconfig" 104source "drivers/staging/p9auth/Kconfig"
105 105
106source "drivers/staging/heci/Kconfig"
107
108source "drivers/staging/line6/Kconfig" 106source "drivers/staging/line6/Kconfig"
109 107
110source "drivers/gpu/drm/radeon/Kconfig" 108source "drivers/gpu/drm/radeon/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 3c64d5fad65..fa5361664ba 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -34,7 +34,6 @@ obj-$(CONFIG_STLC45XX) += stlc45xx/
34obj-$(CONFIG_B3DFG) += b3dfg/ 34obj-$(CONFIG_B3DFG) += b3dfg/
35obj-$(CONFIG_IDE_PHISON) += phison/ 35obj-$(CONFIG_IDE_PHISON) += phison/
36obj-$(CONFIG_PLAN9AUTH) += p9auth/ 36obj-$(CONFIG_PLAN9AUTH) += p9auth/
37obj-$(CONFIG_HECI) += heci/
38obj-$(CONFIG_LINE6_USB) += line6/ 37obj-$(CONFIG_LINE6_USB) += line6/
39obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/ 38obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
40obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/ 39obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/
diff --git a/drivers/staging/heci/Kconfig b/drivers/staging/heci/Kconfig
deleted file mode 100644
index c7206f8bcd9..00000000000
--- a/drivers/staging/heci/Kconfig
+++ /dev/null
@@ -1,7 +0,0 @@
1config 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 0524856fa3a..00000000000
--- a/drivers/staging/heci/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
1obj-$(CONFIG_HECI) += heci.o
2
3heci-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 f86715d631c..00000000000
--- a/drivers/staging/heci/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
1TODO:
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 48f120dc3b2..00000000000
--- 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
55extern const struct guid heci_pthi_guid;
56extern const struct guid heci_wd_guid;
57extern const __u8 heci_start_wd_params[];
58extern const __u8 heci_stop_wd_params[];
59extern 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 */
97struct iamt_heci_device *init_heci_device(struct pci_dev *pdev);
98void heci_reset(struct iamt_heci_device *dev, int interrupts);
99int heci_hw_init(struct iamt_heci_device *dev);
100int heci_task_initialize_clients(void *data);
101int heci_initialize_clients(struct iamt_heci_device *dev);
102struct heci_file_private *heci_alloc_file_private(struct file *file);
103int heci_disconnect_host_client(struct iamt_heci_device *dev,
104 struct heci_file_private *file_ext);
105void heci_initialize_list(struct io_heci_list *list,
106 struct iamt_heci_device *dev);
107void heci_flush_list(struct io_heci_list *list,
108 struct heci_file_private *file_ext);
109void heci_flush_queues(struct iamt_heci_device *dev,
110 struct heci_file_private *file_ext);
111
112void heci_remove_client_from_file_list(struct iamt_heci_device *dev,
113 __u8 host_client_id);
114
115/*
116 * interrupt function prototype
117 */
118irqreturn_t heci_isr_interrupt(int irq, void *dev_id);
119
120void heci_wd_timer(unsigned long data);
121
122/*
123 * input output function prototype
124 */
125int 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
130int 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
135int 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
139int 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
143int heci_start_read(struct iamt_heci_device *dev, int if_num,
144 struct heci_file_private *file_ext);
145
146int pthi_write(struct iamt_heci_device *dev,
147 struct heci_cb_private *priv_cb);
148
149int pthi_read(struct iamt_heci_device *dev, int if_num, struct file *file,
150 char __user *ubuf, size_t length, loff_t *offset);
151
152struct heci_cb_private *find_pthi_read_list_entry(
153 struct iamt_heci_device *dev,
154 struct file *file);
155
156void run_next_iamthif_cmd(struct iamt_heci_device *dev);
157
158void 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 */
168static 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 ff30386d097..00000000000
--- 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 */
136extern 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
160struct guid {
161 __u32 data1;
162 __u16 data2;
163 __u16 data3;
164 __u8 data4[8];
165};
166
167/* File state */
168enum 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 */
177enum 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
187enum 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
195enum 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 */
205enum 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 */
214struct 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
224struct 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 */
236struct 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
259struct io_heci_list {
260 struct heci_cb_private heci_cb;
261 int status;
262 struct iamt_heci_device *device_extension;
263};
264
265struct heci_driver_version {
266 __u8 major;
267 __u8 minor;
268 __u8 hotfix;
269 __u16 build;
270} __attribute__((packed));
271
272
273struct heci_client {
274 __u32 max_msg_length;
275 __u8 protocol_version;
276} __attribute__((packed));
277
278/*
279 * HECI BUS Interface Section
280 */
281struct 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
290struct hbm_cmd {
291 __u8 cmd:7;
292 __u8 is_response:1;
293} __attribute__((packed));
294
295
296struct heci_bus_message {
297 struct hbm_cmd cmd;
298 __u8 command_specific_data[];
299} __attribute__((packed));
300
301struct hbm_version {
302 __u8 minor_version;
303 __u8 major_version;
304} __attribute__((packed));
305
306struct hbm_host_version_request {
307 struct hbm_cmd cmd;
308 __u8 reserved;
309 struct hbm_version host_version;
310} __attribute__((packed));
311
312struct 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
318struct hbm_host_stop_request {
319 struct hbm_cmd cmd;
320 __u8 reason;
321 __u8 reserved[2];
322} __attribute__((packed));
323
324struct hbm_host_stop_response {
325 struct hbm_cmd cmd;
326 __u8 reserved[3];
327} __attribute__((packed));
328
329struct hbm_me_stop_request {
330 struct hbm_cmd cmd;
331 __u8 reason;
332 __u8 reserved[2];
333} __attribute__((packed));
334
335struct hbm_host_enum_request {
336 struct hbm_cmd cmd;
337 __u8 reserved[3];
338} __attribute__((packed));
339
340struct hbm_host_enum_response {
341 struct hbm_cmd cmd;
342 __u8 reserved[3];
343 __u8 valid_addresses[32];
344} __attribute__((packed));
345
346struct 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
355struct hbm_props_request {
356 struct hbm_cmd cmd;
357 __u8 address;
358 __u8 reserved[2];
359} __attribute__((packed));
360
361
362struct 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
370struct hbm_client_connect_request {
371 struct hbm_cmd cmd;
372 __u8 me_addr;
373 __u8 host_addr;
374 __u8 reserved;
375} __attribute__((packed));
376
377struct hbm_client_connect_response {
378 struct hbm_cmd cmd;
379 __u8 me_addr;
380 __u8 host_addr;
381 __u8 status;
382} __attribute__((packed));
383
384struct 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
391struct 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
398struct 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 */
405struct 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 */
510static 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 */
523static 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 31fd891c099..00000000000
--- 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
57const __u8 heci_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
58const __u8 heci_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
59
60const __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
66static const struct guid heci_asf_guid = {
67 0x75B30CD6, 0xA29E, 0x4AF7,
68 {0xA7, 0x12, 0xE6, 0x17, 0x43, 0x93, 0xC8, 0xA6}
69};
70const struct guid heci_wd_guid = {
71 0x05B79A6F, 0x4628, 0x4D7F,
72 {0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB}
73};
74const 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 */
83static void heci_check_asf_mode(struct iamt_heci_device *dev);
84static int host_start_message(struct iamt_heci_device *dev);
85static int host_enum_clients_message(struct iamt_heci_device *dev);
86static int allocate_me_clients_storage(struct iamt_heci_device *dev);
87static void host_init_wd(struct iamt_heci_device *dev);
88static void host_init_iamthif(struct iamt_heci_device *dev);
89static 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 */
99void 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 */
114void 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 */
136void 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 */
170static 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 */
190struct 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
227static 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 */
241int 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 */
304static 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 */
323void 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 */
430int 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 */
495int 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 */
526static 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 */
597static 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 */
655static 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 */
697static 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 */
753static 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 */
779static __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 */
808static 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 */
838static __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 */
882static 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 */
935static 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 */
968struct 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 */
991int 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);
1057free:
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 */
1069void 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 03e1df1a88a..00000000000
--- 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 */
52void 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 */
65void 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 */
76void 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 */
87void 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 */
100static 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 */
117int 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 */
163int 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 */
244void 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 */
274int 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 */
308void 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 */
339int 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 */
379int 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 */
402int 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 */
435int 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 */
472int 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 34db7e52b8e..00000000000
--- 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
101enum 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
113enum me_stop_reason_types{
114 FW_UPDATE = 0x00
115};
116
117enum 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
125enum client_disconnect_status_types{
126 CDS_SUCCESS = 0x00
127};
128
129
130/*
131 * heci interface function prototypes
132 */
133void heci_set_csr_register(struct iamt_heci_device *dev);
134void heci_csr_enable_interrupts(struct iamt_heci_device *dev);
135void heci_csr_disable_interrupts(struct iamt_heci_device *dev);
136void heci_csr_clear_his(struct iamt_heci_device *dev);
137
138void heci_read_slots(struct iamt_heci_device *dev,
139 unsigned char *buffer, unsigned long buffer_length);
140
141int 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
146int 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
152int flow_ctrl_creds(struct iamt_heci_device *dev,
153 struct heci_file_private *file_ext);
154
155int heci_send_wd(struct iamt_heci_device *dev);
156
157void flow_ctrl_reduce(struct iamt_heci_device *dev,
158 struct heci_file_private *file_ext);
159
160int heci_send_flow_control(struct iamt_heci_device *dev,
161 struct heci_file_private *file_ext);
162
163int heci_disconnect(struct iamt_heci_device *dev,
164 struct heci_file_private *file_ext);
165int other_client_is_connecting(struct iamt_heci_device *dev,
166 struct heci_file_private *file_ext);
167int 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 ddf48227e35..00000000000
--- 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 */
74static char heci_driver_name[] = HECI_DRIVER_NAME;
75static char heci_driver_string[] = "Intel(R) Management Engine Interface";
76static char heci_driver_version[] = HECI_DRIVER_VERSION;
77static char heci_copyright[] = "Copyright (c) 2003 - 2008 Intel Corporation.";
78
79
80#ifdef HECI_DEBUG
81int heci_debug = 1;
82#else
83int heci_debug;
84#endif
85MODULE_PARM_DESC(heci_debug, "Debug enabled or not");
86module_param(heci_debug, int, 0644);
87
88
89#define HECI_DEV_NAME "heci"
90
91/* heci char device for registration */
92static struct cdev heci_cdev;
93
94/* major number for device */
95static int heci_major;
96/* The device pointer */
97static struct pci_dev *heci_device;
98
99static struct class *heci_class;
100
101
102/* heci_pci_tbl - PCI Device ID Table */
103static 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
132MODULE_DEVICE_TABLE(pci, heci_pci_tbl);
133
134/*
135 * Local Function Prototypes
136 */
137static int __init heci_init_module(void);
138static void __exit heci_exit_module(void);
139static int __devinit heci_probe(struct pci_dev *pdev,
140 const struct pci_device_id *ent);
141static void __devexit heci_remove(struct pci_dev *pdev);
142static int heci_open(struct inode *inode, struct file *file);
143static int heci_release(struct inode *inode, struct file *file);
144static ssize_t heci_read(struct file *file, char __user *ubuf,
145 size_t length, loff_t *offset);
146static int heci_ioctl(struct inode *inode, struct file *file,
147 unsigned int cmd, unsigned long data);
148static ssize_t heci_write(struct file *file, const char __user *ubuf,
149 size_t length, loff_t *offset);
150static unsigned int heci_poll(struct file *file, poll_table *wait);
151static 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
155static int heci_suspend(struct pci_dev *pdev, pm_message_t state);
156static int heci_resume(struct pci_dev *pdev);
157static __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 */
165static 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 */
178static 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 */
197static 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. */
214static 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
220static 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 */
227static 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 */
254static 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 */
269static 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;
299err_out:
300 return err;
301}
302
303/**
304 * heci_sysfs_device_remove - unregisters the device entry on sysfs
305 */
306static 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 */
324static 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
349unregister_cdev:
350 heci_unregister_cdev();
351unregister_pci:
352 pci_unregister_driver(&heci_driver);
353end:
354 return ret;
355}
356
357module_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 */
366static void __exit heci_exit_module(void)
367{
368 pci_unregister_driver(&heci_driver);
369 heci_sysfs_device_remove();
370 heci_unregister_cdev();
371}
372
373module_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 */
384static 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
479release_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
488release_irq:
489 free_irq(pdev->irq, dev);
490unmap_memory:
491 if (dev->mem_addr)
492 iounmap(dev->mem_addr);
493free_device:
494 kfree(dev);
495release_regions:
496 pci_release_regions(pdev);
497disable_device:
498 pci_disable_device(pdev);
499end:
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 */
512static 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 */
624static 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 */
666static 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 */
709static 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 */
773static 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
860static 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 */
897static 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 */
1014copy_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
1042free:
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);
1055out: 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 */
1069static 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
1321unlock:
1322 spin_unlock(&file_ext->write_io_lock);
1323fail:
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 */
1339static 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 */
1413static 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
1461static 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
1528static 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
1573MODULE_AUTHOR("Intel Corporation");
1574MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
1575MODULE_LICENSE("Dual BSD/GPL");
1576MODULE_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 3007aa6e17d..00000000000
--- 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 2a3a01a62bb..00000000000
--- 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 */
49static void heci_bh_handler(struct work_struct *work);
50static int heci_bh_read_handler(struct io_heci_list *complete_list,
51 struct iamt_heci_device *dev,
52 __s32 *slots);
53static int heci_bh_write_handler(struct io_heci_list *complete_list,
54 struct iamt_heci_device *dev,
55 __s32 *slots);
56static void heci_bh_read_bus_message(struct iamt_heci_device *dev,
57 struct heci_msg_hdr *heci_hdr);
58static 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);
61static 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);
64static void heci_client_connect_response(struct iamt_heci_device *dev,
65 struct hbm_client_connect_response *connect_res);
66static void heci_client_disconnect_response(struct iamt_heci_device *dev,
67 struct hbm_client_connect_response *disconnect_res);
68static void heci_client_flow_control_response(struct iamt_heci_device *dev,
69 struct hbm_flow_control *flow_control);
70static 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 */
82irqreturn_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 */
117static 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 */
146static 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 */
174static 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);
246end:
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 */
309static 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 }
391end:
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 */
403static 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 */
531static 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 */
589static 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 */
608static 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
675quit:
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 */
695static 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 */
730static 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 */
773static 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 */
813static 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 */
853static 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 */
946static 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 */
1028static 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 */
1231static 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 */
1259static 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 */
1300static 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 */
1344static 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 */
1357static 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 */
1386static 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 */
1428static 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 */
1441static 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 */
1493void 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 1a6faf88e16..00000000000
--- 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 */
78int 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 }
122end:
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 */
138int 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
352remove_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 }
359end:
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 */
377int 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);
444end:
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 */
460int 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);
486end:
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 */
498struct 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 */
536int 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 }
616free:
617 DBG("free pthi cb memory.\n");
618 *offset = 0;
619 heci_free_cb_private(priv_cb);
620out:
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 */
633int 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;
723unlock:
724 spin_unlock_bh(&dev->device_lock);
725fail:
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 */
738int 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 */
816void 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 */
863void 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