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