aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/mei
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/mei')
-rw-r--r--drivers/staging/mei/Kconfig28
-rw-r--r--drivers/staging/mei/Makefile11
-rw-r--r--drivers/staging/mei/TODO17
-rw-r--r--drivers/staging/mei/hw.h333
-rw-r--r--drivers/staging/mei/init.c765
-rw-r--r--drivers/staging/mei/interface.c446
-rw-r--r--drivers/staging/mei/interface.h62
-rw-r--r--drivers/staging/mei/interrupt.c1623
-rw-r--r--drivers/staging/mei/iorw.c604
-rw-r--r--drivers/staging/mei/main.c1342
-rw-r--r--drivers/staging/mei/mei.h105
-rw-r--r--drivers/staging/mei/mei.txt189
-rw-r--r--drivers/staging/mei/mei_dev.h425
-rw-r--r--drivers/staging/mei/mei_version.h31
-rw-r--r--drivers/staging/mei/wd.c188
15 files changed, 6169 insertions, 0 deletions
diff --git a/drivers/staging/mei/Kconfig b/drivers/staging/mei/Kconfig
new file mode 100644
index 00000000000..3f3f170890e
--- /dev/null
+++ b/drivers/staging/mei/Kconfig
@@ -0,0 +1,28 @@
1config INTEL_MEI
2 tristate "Intel Management Engine Interface (Intel MEI)"
3 depends on X86 && PCI && EXPERIMENTAL
4 help
5 The Intel Management Engine (Intel ME) provides Manageability,
6 Security and Media services for system containing Intel chipsets.
7 if selected /dev/mei misc device will be created.
8
9 Supported Chipsets are:
10 7 Series Chipset Family
11 6 Series Chipset Family
12 5 Series Chipset Family
13 4 Series Chipset Family
14 Mobile 4 Series Chipset Family
15 ICH9
16 82946GZ/GL
17 82G35 Express
18 82Q963/Q965
19 82P965/G965
20 Mobile PM965/GM965
21 Mobile GME965/GLE960
22 82Q35 Express
23 82G33/G31/P35/P31 Express
24 82Q33 Express
25 82X38/X48 Express
26
27 For more information see
28 <http://software.intel.com/en-us/manageability/>
diff --git a/drivers/staging/mei/Makefile b/drivers/staging/mei/Makefile
new file mode 100644
index 00000000000..57168db6c7e
--- /dev/null
+++ b/drivers/staging/mei/Makefile
@@ -0,0 +1,11 @@
1#
2# Makefile - Intel Management Engine Interface (Intel MEI) Linux driver
3# Copyright (c) 2010-2011, Intel Corporation.
4#
5obj-$(CONFIG_INTEL_MEI) += mei.o
6mei-objs := init.o
7mei-objs += interrupt.o
8mei-objs += interface.o
9mei-objs += iorw.o
10mei-objs += main.o
11mei-objs += wd.o
diff --git a/drivers/staging/mei/TODO b/drivers/staging/mei/TODO
new file mode 100644
index 00000000000..3b6a667a580
--- /dev/null
+++ b/drivers/staging/mei/TODO
@@ -0,0 +1,17 @@
1TODO:
2 - Create in-kernel Client API. Examples of in-kernel clients are watchdog and AMTHI.
3 - ME Watchdog Driver to expose standard Linux watchdog interface
4 - Rewrite AMTHI to use in-kernel client interface
5 - Cleanup init and probe functions
6 - Review BUG/BUG_ON usage
7 - Cleanup and reorganize header files
8 - Rewrite client data structure
9 - Make state machine more readable
10 - Add mei.txt with driver explanation and it's driver
11 - Fix Kconfig
12 - Cleanup and split the timer function
13Upon Unstaging:
14 - move mei.h to include/linux/mei.h
15 - Documentation/ioctl/ioctl-number.txt
16 - drop mei_version.h
17 - Updated MAINTAINERS
diff --git a/drivers/staging/mei/hw.h b/drivers/staging/mei/hw.h
new file mode 100644
index 00000000000..9b9008cb693
--- /dev/null
+++ b/drivers/staging/mei/hw.h
@@ -0,0 +1,333 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17#ifndef _MEI_HW_TYPES_H_
18#define _MEI_HW_TYPES_H_
19
20#include <linux/uuid.h>
21
22/*
23 * Timeouts
24 */
25#define MEI_INTEROP_TIMEOUT (HZ * 7)
26#define MEI_CONNECT_TIMEOUT 3 /* at least 2 seconds */
27
28#define CONNECT_TIMEOUT 15 /* HPS definition */
29#define INIT_CLIENTS_TIMEOUT 15 /* HPS definition */
30
31#define IAMTHIF_STALL_TIMER 12 /* seconds */
32#define IAMTHIF_READ_TIMER 10000 /* ms */
33
34/*
35 * Internal Clients Number
36 */
37#define MEI_WD_HOST_CLIENT_ID 1
38#define MEI_IAMTHIF_HOST_CLIENT_ID 2
39
40/*
41 * MEI device IDs
42 */
43#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */
44#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */
45#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */
46#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */
47
48#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */
49#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */
50
51#define MEI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */
52#define MEI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */
53#define MEI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */
54#define MEI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */
55#define MEI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */
56
57#define MEI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */
58#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */
59#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */
60#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */
61#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */
62
63#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */
64#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */
65#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */
66#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */
67
68#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */
69#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */
70#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */
71#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */
72
73#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */
74#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */
75
76#define MEI_DEV_ID_CPT_1 0x1C3A /* Cougerpoint */
77#define MEI_DEV_ID_PBG_1 0x1D3A /* PBG */
78
79#define MEI_DEV_ID_PPT_1 0x1E3A /* Pantherpoint PPT */
80#define MEI_DEV_ID_PPT_2 0x1CBA /* Pantherpoint PPT */
81#define MEI_DEV_ID_PPT_3 0x1DBA /* Pantherpoint PPT */
82
83
84/*
85 * MEI HW Section
86 */
87
88/* MEI registers */
89/* H_CB_WW - Host Circular Buffer (CB) Write Window register */
90#define H_CB_WW 0
91/* H_CSR - Host Control Status register */
92#define H_CSR 4
93/* ME_CB_RW - ME Circular Buffer Read Window register (read only) */
94#define ME_CB_RW 8
95/* ME_CSR_HA - ME Control Status Host Access register (read only) */
96#define ME_CSR_HA 0xC
97
98
99/* register bits of H_CSR (Host Control Status register) */
100/* Host Circular Buffer Depth - maximum number of 32-bit entries in CB */
101#define H_CBD 0xFF000000
102/* Host Circular Buffer Write Pointer */
103#define H_CBWP 0x00FF0000
104/* Host Circular Buffer Read Pointer */
105#define H_CBRP 0x0000FF00
106/* Host Reset */
107#define H_RST 0x00000010
108/* Host Ready */
109#define H_RDY 0x00000008
110/* Host Interrupt Generate */
111#define H_IG 0x00000004
112/* Host Interrupt Status */
113#define H_IS 0x00000002
114/* Host Interrupt Enable */
115#define H_IE 0x00000001
116
117
118/* register bits of ME_CSR_HA (ME Control Status Host Access register) */
119/* ME CB (Circular Buffer) Depth HRA (Host Read Access) - host read only
120access to ME_CBD */
121#define ME_CBD_HRA 0xFF000000
122/* ME CB Write Pointer HRA - host read only access to ME_CBWP */
123#define ME_CBWP_HRA 0x00FF0000
124/* ME CB Read Pointer HRA - host read only access to ME_CBRP */
125#define ME_CBRP_HRA 0x0000FF00
126/* ME Reset HRA - host read only access to ME_RST */
127#define ME_RST_HRA 0x00000010
128/* ME Ready HRA - host read only access to ME_RDY */
129#define ME_RDY_HRA 0x00000008
130/* ME Interrupt Generate HRA - host read only access to ME_IG */
131#define ME_IG_HRA 0x00000004
132/* ME Interrupt Status HRA - host read only access to ME_IS */
133#define ME_IS_HRA 0x00000002
134/* ME Interrupt Enable HRA - host read only access to ME_IE */
135#define ME_IE_HRA 0x00000001
136
137/*
138 * MEI Version
139 */
140#define HBM_MINOR_VERSION 0
141#define HBM_MAJOR_VERSION 1
142#define HBM_TIMEOUT 1 /* 1 second */
143
144/*
145 * MEI Bus Message Command IDs
146 */
147#define HOST_START_REQ_CMD 0x01
148#define HOST_START_RES_CMD 0x81
149
150#define HOST_STOP_REQ_CMD 0x02
151#define HOST_STOP_RES_CMD 0x82
152
153#define ME_STOP_REQ_CMD 0x03
154
155#define HOST_ENUM_REQ_CMD 0x04
156#define HOST_ENUM_RES_CMD 0x84
157
158#define HOST_CLIENT_PROPERTIES_REQ_CMD 0x05
159#define HOST_CLIENT_PROPERTIES_RES_CMD 0x85
160
161#define CLIENT_CONNECT_REQ_CMD 0x06
162#define CLIENT_CONNECT_RES_CMD 0x86
163
164#define CLIENT_DISCONNECT_REQ_CMD 0x07
165#define CLIENT_DISCONNECT_RES_CMD 0x87
166
167#define MEI_FLOW_CONTROL_CMD 0x08
168
169/*
170 * MEI Stop Reason
171 * used by hbm_host_stop_request.reason
172 */
173enum mei_stop_reason_types {
174 DRIVER_STOP_REQUEST = 0x00,
175 DEVICE_D1_ENTRY = 0x01,
176 DEVICE_D2_ENTRY = 0x02,
177 DEVICE_D3_ENTRY = 0x03,
178 SYSTEM_S1_ENTRY = 0x04,
179 SYSTEM_S2_ENTRY = 0x05,
180 SYSTEM_S3_ENTRY = 0x06,
181 SYSTEM_S4_ENTRY = 0x07,
182 SYSTEM_S5_ENTRY = 0x08
183};
184
185/*
186 * Client Connect Status
187 * used by hbm_client_connect_response.status
188 */
189enum client_connect_status_types {
190 CCS_SUCCESS = 0x00,
191 CCS_NOT_FOUND = 0x01,
192 CCS_ALREADY_STARTED = 0x02,
193 CCS_OUT_OF_RESOURCES = 0x03,
194 CCS_MESSAGE_SMALL = 0x04
195};
196
197/*
198 * Client Disconnect Status
199 */
200enum client_disconnect_status_types {
201 CDS_SUCCESS = 0x00
202};
203
204/*
205 * MEI BUS Interface Section
206 */
207struct mei_msg_hdr {
208 u32 me_addr:8;
209 u32 host_addr:8;
210 u32 length:9;
211 u32 reserved:6;
212 u32 msg_complete:1;
213} __packed;
214
215
216struct hbm_cmd {
217 u8 cmd:7;
218 u8 is_response:1;
219} __packed;
220
221
222struct mei_bus_message {
223 struct hbm_cmd cmd;
224 u8 command_specific_data[];
225} __packed;
226
227struct hbm_version {
228 u8 minor_version;
229 u8 major_version;
230} __packed;
231
232struct hbm_host_version_request {
233 struct hbm_cmd cmd;
234 u8 reserved;
235 struct hbm_version host_version;
236} __packed;
237
238struct hbm_host_version_response {
239 struct hbm_cmd cmd;
240 int host_version_supported;
241 struct hbm_version me_max_version;
242} __packed;
243
244struct hbm_host_stop_request {
245 struct hbm_cmd cmd;
246 u8 reason;
247 u8 reserved[2];
248} __packed;
249
250struct hbm_host_stop_response {
251 struct hbm_cmd cmd;
252 u8 reserved[3];
253} __packed;
254
255struct hbm_me_stop_request {
256 struct hbm_cmd cmd;
257 u8 reason;
258 u8 reserved[2];
259} __packed;
260
261struct hbm_host_enum_request {
262 struct hbm_cmd cmd;
263 u8 reserved[3];
264} __packed;
265
266struct hbm_host_enum_response {
267 struct hbm_cmd cmd;
268 u8 reserved[3];
269 u8 valid_addresses[32];
270} __packed;
271
272struct mei_client_properties {
273 uuid_le protocol_name;
274 u8 protocol_version;
275 u8 max_number_of_connections;
276 u8 fixed_address;
277 u8 single_recv_buf;
278 u32 max_msg_length;
279} __packed;
280
281struct hbm_props_request {
282 struct hbm_cmd cmd;
283 u8 address;
284 u8 reserved[2];
285} __packed;
286
287
288struct hbm_props_response {
289 struct hbm_cmd cmd;
290 u8 address;
291 u8 status;
292 u8 reserved[1];
293 struct mei_client_properties client_properties;
294} __packed;
295
296struct hbm_client_connect_request {
297 struct hbm_cmd cmd;
298 u8 me_addr;
299 u8 host_addr;
300 u8 reserved;
301} __packed;
302
303struct hbm_client_connect_response {
304 struct hbm_cmd cmd;
305 u8 me_addr;
306 u8 host_addr;
307 u8 status;
308} __packed;
309
310struct hbm_client_disconnect_request {
311 struct hbm_cmd cmd;
312 u8 me_addr;
313 u8 host_addr;
314 u8 reserved[1];
315} __packed;
316
317#define MEI_FC_MESSAGE_RESERVED_LENGTH 5
318
319struct hbm_flow_control {
320 struct hbm_cmd cmd;
321 u8 me_addr;
322 u8 host_addr;
323 u8 reserved[MEI_FC_MESSAGE_RESERVED_LENGTH];
324} __packed;
325
326struct mei_me_client {
327 struct mei_client_properties props;
328 u8 client_id;
329 u8 mei_flow_ctrl_creds;
330} __packed;
331
332
333#endif
diff --git a/drivers/staging/mei/init.c b/drivers/staging/mei/init.c
new file mode 100644
index 00000000000..0fa8216fd0e
--- /dev/null
+++ b/drivers/staging/mei/init.c
@@ -0,0 +1,765 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17#include <linux/pci.h>
18#include <linux/sched.h>
19#include <linux/wait.h>
20#include <linux/delay.h>
21
22#include "mei_dev.h"
23#include "hw.h"
24#include "interface.h"
25#include "mei.h"
26
27const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
28 0xa8, 0x46, 0xe0, 0xff, 0x65,
29 0x81, 0x4c);
30
31/**
32 * mei_io_list_init - Sets up a queue list.
33 *
34 * @list: An instance io list structure
35 * @dev: the device structure
36 */
37void mei_io_list_init(struct mei_io_list *list)
38{
39 /* initialize our queue list */
40 INIT_LIST_HEAD(&list->mei_cb.cb_list);
41 list->status = 0;
42}
43
44/**
45 * mei_io_list_flush - removes list entry belonging to cl.
46 *
47 * @list: An instance of our list structure
48 * @cl: private data of the file object
49 */
50void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl)
51{
52 struct mei_cl_cb *cb_pos = NULL;
53 struct mei_cl_cb *cb_next = NULL;
54
55 if (list->status != 0)
56 return;
57
58 if (list_empty(&list->mei_cb.cb_list))
59 return;
60
61 list_for_each_entry_safe(cb_pos, cb_next,
62 &list->mei_cb.cb_list, cb_list) {
63 if (cb_pos) {
64 struct mei_cl *cl_tmp;
65 cl_tmp = (struct mei_cl *)cb_pos->file_private;
66 if (mei_cl_cmp_id(cl, cl_tmp))
67 list_del(&cb_pos->cb_list);
68 }
69 }
70}
71/**
72 * mei_cl_flush_queues - flushes queue lists belonging to cl.
73 *
74 * @dev: the device structure
75 * @cl: private data of the file object
76 */
77int mei_cl_flush_queues(struct mei_cl *cl)
78{
79 if (!cl || !cl->dev)
80 return -EINVAL;
81
82 dev_dbg(&cl->dev->pdev->dev, "remove list entry belonging to cl\n");
83 mei_io_list_flush(&cl->dev->read_list, cl);
84 mei_io_list_flush(&cl->dev->write_list, cl);
85 mei_io_list_flush(&cl->dev->write_waiting_list, cl);
86 mei_io_list_flush(&cl->dev->ctrl_wr_list, cl);
87 mei_io_list_flush(&cl->dev->ctrl_rd_list, cl);
88 mei_io_list_flush(&cl->dev->amthi_cmd_list, cl);
89 mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl);
90 return 0;
91}
92
93
94
95/**
96 * mei_reset_iamthif_params - initializes mei device iamthif
97 *
98 * @dev: the device structure
99 */
100static void mei_reset_iamthif_params(struct mei_device *dev)
101{
102 /* reset iamthif parameters. */
103 dev->iamthif_current_cb = NULL;
104 dev->iamthif_msg_buf_size = 0;
105 dev->iamthif_msg_buf_index = 0;
106 dev->iamthif_canceled = false;
107 dev->iamthif_ioctl = false;
108 dev->iamthif_state = MEI_IAMTHIF_IDLE;
109 dev->iamthif_timer = 0;
110}
111
112/**
113 * init_mei_device - allocates and initializes the mei device structure
114 *
115 * @pdev: The pci device structure
116 *
117 * returns The mei_device_device pointer on success, NULL on failure.
118 */
119struct mei_device *mei_device_init(struct pci_dev *pdev)
120{
121 struct mei_device *dev;
122
123 dev = kzalloc(sizeof(struct mei_device), GFP_KERNEL);
124 if (!dev)
125 return NULL;
126
127 /* setup our list array */
128 INIT_LIST_HEAD(&dev->file_list);
129 INIT_LIST_HEAD(&dev->wd_cl.link);
130 INIT_LIST_HEAD(&dev->iamthif_cl.link);
131 mutex_init(&dev->device_lock);
132 init_waitqueue_head(&dev->wait_recvd_msg);
133 init_waitqueue_head(&dev->wait_stop_wd);
134 dev->mei_state = MEI_INITIALIZING;
135 dev->iamthif_state = MEI_IAMTHIF_IDLE;
136
137
138 mei_io_list_init(&dev->read_list);
139 mei_io_list_init(&dev->write_list);
140 mei_io_list_init(&dev->write_waiting_list);
141 mei_io_list_init(&dev->ctrl_wr_list);
142 mei_io_list_init(&dev->ctrl_rd_list);
143 mei_io_list_init(&dev->amthi_cmd_list);
144 mei_io_list_init(&dev->amthi_read_complete_list);
145 dev->pdev = pdev;
146 return dev;
147}
148
149/**
150 * mei_hw_init - initializes host and fw to start work.
151 *
152 * @dev: the device structure
153 *
154 * returns 0 on success, <0 on failure.
155 */
156int mei_hw_init(struct mei_device *dev)
157{
158 int err = 0;
159 int ret;
160
161 mutex_lock(&dev->device_lock);
162
163 dev->host_hw_state = mei_hcsr_read(dev);
164 dev->me_hw_state = mei_mecsr_read(dev);
165 dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, mestate = 0x%08x.\n",
166 dev->host_hw_state, dev->me_hw_state);
167
168 /* acknowledge interrupt and stop interupts */
169 if ((dev->host_hw_state & H_IS) == H_IS)
170 mei_reg_write(dev, H_CSR, dev->host_hw_state);
171
172 dev->recvd_msg = false;
173 dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
174
175 mei_reset(dev, 1);
176
177 dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
178 dev->host_hw_state, dev->me_hw_state);
179
180 /* wait for ME to turn on ME_RDY */
181 if (!dev->recvd_msg) {
182 mutex_unlock(&dev->device_lock);
183 err = wait_event_interruptible_timeout(dev->wait_recvd_msg,
184 dev->recvd_msg, MEI_INTEROP_TIMEOUT);
185 mutex_lock(&dev->device_lock);
186 }
187
188 if (err <= 0 && !dev->recvd_msg) {
189 dev->mei_state = MEI_DISABLED;
190 dev_dbg(&dev->pdev->dev,
191 "wait_event_interruptible_timeout failed"
192 "on wait for ME to turn on ME_RDY.\n");
193 ret = -ENODEV;
194 goto out;
195 }
196
197 if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
198 ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
199 dev->mei_state = MEI_DISABLED;
200 dev_dbg(&dev->pdev->dev,
201 "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
202 dev->host_hw_state, dev->me_hw_state);
203
204 if (!(dev->host_hw_state & H_RDY))
205 dev_dbg(&dev->pdev->dev, "host turn off H_RDY.\n");
206
207 if (!(dev->me_hw_state & ME_RDY_HRA))
208 dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
209
210 printk(KERN_ERR "mei: link layer initialization failed.\n");
211 ret = -ENODEV;
212 goto out;
213 }
214
215 if (dev->version.major_version != HBM_MAJOR_VERSION ||
216 dev->version.minor_version != HBM_MINOR_VERSION) {
217 dev_dbg(&dev->pdev->dev, "MEI start failed.\n");
218 ret = -ENODEV;
219 goto out;
220 }
221
222 dev->recvd_msg = false;
223 dev_dbg(&dev->pdev->dev, "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
224 dev->host_hw_state, dev->me_hw_state);
225 dev_dbg(&dev->pdev->dev, "ME turn on ME_RDY and host turn on H_RDY.\n");
226 dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
227 dev_dbg(&dev->pdev->dev, "MEI start success.\n");
228 ret = 0;
229
230out:
231 mutex_unlock(&dev->device_lock);
232 return ret;
233}
234
235/**
236 * mei_hw_reset - resets fw via mei csr register.
237 *
238 * @dev: the device structure
239 * @interrupts_enabled: if interrupt should be enabled after reset.
240 */
241static void mei_hw_reset(struct mei_device *dev, int interrupts_enabled)
242{
243 dev->host_hw_state |= (H_RST | H_IG);
244
245 if (interrupts_enabled)
246 mei_enable_interrupts(dev);
247 else
248 mei_disable_interrupts(dev);
249}
250
251/**
252 * mei_reset - resets host and fw.
253 *
254 * @dev: the device structure
255 * @interrupts_enabled: if interrupt should be enabled after reset.
256 */
257void mei_reset(struct mei_device *dev, int interrupts_enabled)
258{
259 struct mei_cl *cl_pos = NULL;
260 struct mei_cl *cl_next = NULL;
261 struct mei_cl_cb *cb_pos = NULL;
262 struct mei_cl_cb *cb_next = NULL;
263 bool unexpected;
264
265 if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
266 dev->need_reset = true;
267 return;
268 }
269
270 unexpected = (dev->mei_state != MEI_INITIALIZING &&
271 dev->mei_state != MEI_DISABLED &&
272 dev->mei_state != MEI_POWER_DOWN &&
273 dev->mei_state != MEI_POWER_UP);
274
275 dev->host_hw_state = mei_hcsr_read(dev);
276
277 dev_dbg(&dev->pdev->dev, "before reset host_hw_state = 0x%08x.\n",
278 dev->host_hw_state);
279
280 mei_hw_reset(dev, interrupts_enabled);
281
282 dev->host_hw_state &= ~H_RST;
283 dev->host_hw_state |= H_IG;
284
285 mei_hcsr_set(dev);
286
287 dev_dbg(&dev->pdev->dev, "currently saved host_hw_state = 0x%08x.\n",
288 dev->host_hw_state);
289
290 dev->need_reset = false;
291
292 if (dev->mei_state != MEI_INITIALIZING) {
293 if (dev->mei_state != MEI_DISABLED &&
294 dev->mei_state != MEI_POWER_DOWN)
295 dev->mei_state = MEI_RESETING;
296
297 list_for_each_entry_safe(cl_pos,
298 cl_next, &dev->file_list, link) {
299 cl_pos->state = MEI_FILE_DISCONNECTED;
300 cl_pos->mei_flow_ctrl_creds = 0;
301 cl_pos->read_cb = NULL;
302 cl_pos->timer_count = 0;
303 }
304 /* remove entry if already in list */
305 dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n");
306 mei_remove_client_from_file_list(dev,
307 dev->wd_cl.host_client_id);
308
309 mei_remove_client_from_file_list(dev,
310 dev->iamthif_cl.host_client_id);
311
312 mei_reset_iamthif_params(dev);
313 dev->wd_due_counter = 0;
314 dev->extra_write_index = 0;
315 }
316
317 dev->me_clients_num = 0;
318 dev->rd_msg_hdr = 0;
319 dev->stop = false;
320 dev->wd_pending = false;
321
322 /* update the state of the registers after reset */
323 dev->host_hw_state = mei_hcsr_read(dev);
324 dev->me_hw_state = mei_mecsr_read(dev);
325
326 dev_dbg(&dev->pdev->dev, "after reset host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
327 dev->host_hw_state, dev->me_hw_state);
328
329 if (unexpected)
330 dev_warn(&dev->pdev->dev, "unexpected reset.\n");
331
332 /* Wake up all readings so they can be interrupted */
333 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
334 if (waitqueue_active(&cl_pos->rx_wait)) {
335 dev_dbg(&dev->pdev->dev, "Waking up client!\n");
336 wake_up_interruptible(&cl_pos->rx_wait);
337 }
338 }
339 /* remove all waiting requests */
340 if (dev->write_list.status == 0 &&
341 !list_empty(&dev->write_list.mei_cb.cb_list)) {
342 list_for_each_entry_safe(cb_pos, cb_next,
343 &dev->write_list.mei_cb.cb_list, cb_list) {
344 if (cb_pos) {
345 list_del(&cb_pos->cb_list);
346 mei_free_cb_private(cb_pos);
347 cb_pos = NULL;
348 }
349 }
350 }
351}
352
353
354
355/**
356 * host_start_message - mei host sends start message.
357 *
358 * @dev: the device structure
359 *
360 * returns none.
361 */
362void mei_host_start_message(struct mei_device *dev)
363{
364 struct mei_msg_hdr *mei_hdr;
365 struct hbm_host_version_request *host_start_req;
366
367 /* host start message */
368 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
369 mei_hdr->host_addr = 0;
370 mei_hdr->me_addr = 0;
371 mei_hdr->length = sizeof(struct hbm_host_version_request);
372 mei_hdr->msg_complete = 1;
373 mei_hdr->reserved = 0;
374
375 host_start_req =
376 (struct hbm_host_version_request *) &dev->wr_msg_buf[1];
377 memset(host_start_req, 0, sizeof(struct hbm_host_version_request));
378 host_start_req->cmd.cmd = HOST_START_REQ_CMD;
379 host_start_req->host_version.major_version = HBM_MAJOR_VERSION;
380 host_start_req->host_version.minor_version = HBM_MINOR_VERSION;
381 dev->recvd_msg = false;
382 if (!mei_write_message(dev, mei_hdr,
383 (unsigned char *) (host_start_req),
384 mei_hdr->length)) {
385 dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
386 dev->mei_state = MEI_RESETING;
387 mei_reset(dev, 1);
388 }
389 dev->init_clients_state = MEI_START_MESSAGE;
390 dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
391 return ;
392}
393
394/**
395 * host_enum_clients_message - host sends enumeration client request message.
396 *
397 * @dev: the device structure
398 *
399 * returns none.
400 */
401void mei_host_enum_clients_message(struct mei_device *dev)
402{
403 struct mei_msg_hdr *mei_hdr;
404 struct hbm_host_enum_request *host_enum_req;
405 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
406 /* enumerate clients */
407 mei_hdr->host_addr = 0;
408 mei_hdr->me_addr = 0;
409 mei_hdr->length = sizeof(struct hbm_host_enum_request);
410 mei_hdr->msg_complete = 1;
411 mei_hdr->reserved = 0;
412
413 host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1];
414 memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request));
415 host_enum_req->cmd.cmd = HOST_ENUM_REQ_CMD;
416 if (!mei_write_message(dev, mei_hdr,
417 (unsigned char *) (host_enum_req),
418 mei_hdr->length)) {
419 dev->mei_state = MEI_RESETING;
420 dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
421 mei_reset(dev, 1);
422 }
423 dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
424 dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
425 return ;
426}
427
428
429/**
430 * allocate_me_clients_storage - allocates storage for me clients
431 *
432 * @dev: the device structure
433 *
434 * returns none.
435 */
436void mei_allocate_me_clients_storage(struct mei_device *dev)
437{
438 struct mei_me_client *clients;
439 int b;
440
441 /* count how many ME clients we have */
442 for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX)
443 dev->me_clients_num++;
444
445 if (dev->me_clients_num <= 0)
446 return ;
447
448
449 if (dev->me_clients != NULL) {
450 kfree(dev->me_clients);
451 dev->me_clients = NULL;
452 }
453 dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n",
454 dev->me_clients_num * sizeof(struct mei_me_client));
455 /* allocate storage for ME clients representation */
456 clients = kcalloc(dev->me_clients_num,
457 sizeof(struct mei_me_client), GFP_KERNEL);
458 if (!clients) {
459 dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
460 dev->mei_state = MEI_RESETING;
461 mei_reset(dev, 1);
462 return ;
463 }
464 dev->me_clients = clients;
465 return ;
466}
467/**
468 * host_client_properties - reads properties for client
469 *
470 * @dev: the device structure
471 *
472 * returns none.
473 */
474void mei_host_client_properties(struct mei_device *dev)
475{
476 struct mei_msg_hdr *mei_header;
477 struct hbm_props_request *host_cli_req;
478 int b;
479 u8 client_num = dev->me_client_presentation_num;
480
481 b = dev->me_client_index;
482 b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b);
483 if (b < MEI_CLIENTS_MAX) {
484 dev->me_clients[client_num].client_id = b;
485 dev->me_clients[client_num].mei_flow_ctrl_creds = 0;
486 mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0];
487 mei_header->host_addr = 0;
488 mei_header->me_addr = 0;
489 mei_header->length = sizeof(struct hbm_props_request);
490 mei_header->msg_complete = 1;
491 mei_header->reserved = 0;
492
493 host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1];
494
495 memset(host_cli_req, 0, sizeof(struct hbm_props_request));
496
497 host_cli_req->cmd.cmd = HOST_CLIENT_PROPERTIES_REQ_CMD;
498 host_cli_req->address = b;
499
500 if (!mei_write_message(dev, mei_header,
501 (unsigned char *)host_cli_req,
502 mei_header->length)) {
503 dev->mei_state = MEI_RESETING;
504 dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
505 mei_reset(dev, 1);
506 return;
507 }
508
509 dev->init_clients_timer = INIT_CLIENTS_TIMEOUT;
510 dev->me_client_index = b;
511 return;
512 }
513
514
515 /*
516 * Clear Map for indicating now ME clients
517 * with associated host client
518 */
519 bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
520 dev->open_handle_count = 0;
521 bitmap_set(dev->host_clients_map, 0, 3);
522 dev->mei_state = MEI_ENABLED;
523
524 mei_wd_host_init(dev);
525 return;
526}
527
528/**
529 * mei_init_file_private - initializes private file structure.
530 *
531 * @priv: private file structure to be initialized
532 * @file: the file structure
533 */
534void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
535{
536 memset(priv, 0, sizeof(struct mei_cl));
537 init_waitqueue_head(&priv->wait);
538 init_waitqueue_head(&priv->rx_wait);
539 init_waitqueue_head(&priv->tx_wait);
540 INIT_LIST_HEAD(&priv->link);
541 priv->reading_state = MEI_IDLE;
542 priv->writing_state = MEI_IDLE;
543 priv->dev = dev;
544}
545
546int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
547{
548 int i, res = -1;
549
550 for (i = 0; i < dev->me_clients_num; ++i)
551 if (uuid_le_cmp(cuuid,
552 dev->me_clients[i].props.protocol_name) == 0) {
553 res = i;
554 break;
555 }
556
557 return res;
558}
559
560
561/**
562 * mei_find_me_client_update_filext - searches for ME client guid
563 * sets client_id in mei_file_private if found
564 * @dev: the device structure
565 * @priv: private file structure to set client_id in
566 * @cguid: searched guid of ME client
567 * @client_id: id of host client to be set in file private structure
568 *
569 * returns ME client index
570 */
571u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
572 const uuid_le *cguid, u8 client_id)
573{
574 int i;
575
576 if (!dev || !priv || !cguid)
577 return 0;
578
579 /* check for valid client id */
580 i = mei_find_me_client_index(dev, *cguid);
581 if (i >= 0) {
582 priv->me_client_id = dev->me_clients[i].client_id;
583 priv->state = MEI_FILE_CONNECTING;
584 priv->host_client_id = client_id;
585
586 list_add_tail(&priv->link, &dev->file_list);
587 return (u8)i;
588 }
589
590 return 0;
591}
592
593/**
594 * host_init_iamthif - mei initialization iamthif client.
595 *
596 * @dev: the device structure
597 *
598 */
599void mei_host_init_iamthif(struct mei_device *dev)
600{
601 u8 i;
602 unsigned char *msg_buf;
603
604 mei_cl_init(&dev->iamthif_cl, dev);
605 dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
606
607 /* find ME amthi client */
608 i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
609 &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
610 if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
611 dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
612 return;
613 }
614
615 /* Do not render the system unusable when iamthif_mtu is not equal to
616 the value received from ME.
617 Assign iamthif_mtu to the value received from ME in order to solve the
618 hardware macro incompatibility. */
619
620 dev_dbg(&dev->pdev->dev, "[DEFAULT] IAMTHIF = %d\n", dev->iamthif_mtu);
621 dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length;
622 dev_dbg(&dev->pdev->dev,
623 "IAMTHIF = %d\n",
624 dev->me_clients[i].props.max_msg_length);
625
626 kfree(dev->iamthif_msg_buf);
627 dev->iamthif_msg_buf = NULL;
628
629 /* allocate storage for ME message buffer */
630 msg_buf = kcalloc(dev->iamthif_mtu,
631 sizeof(unsigned char), GFP_KERNEL);
632 if (!msg_buf) {
633 dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n");
634 return;
635 }
636
637 dev->iamthif_msg_buf = msg_buf;
638
639 if (!mei_connect(dev, &dev->iamthif_cl)) {
640 dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n");
641 dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
642 dev->iamthif_cl.host_client_id = 0;
643 } else {
644 dev->iamthif_cl.timer_count = CONNECT_TIMEOUT;
645 }
646}
647
648/**
649 * mei_alloc_file_private - allocates a private file structure and sets it up.
650 * @file: the file structure
651 *
652 * returns The allocated file or NULL on failure
653 */
654struct mei_cl *mei_cl_allocate(struct mei_device *dev)
655{
656 struct mei_cl *cl;
657
658 cl = kmalloc(sizeof(struct mei_cl), GFP_KERNEL);
659 if (!cl)
660 return NULL;
661
662 mei_cl_init(cl, dev);
663
664 return cl;
665}
666
667
668
669/**
670 * mei_disconnect_host_client - sends disconnect message to fw from host client.
671 *
672 * @dev: the device structure
673 * @cl: private data of the file object
674 *
675 * Locking: called under "dev->device_lock" lock
676 *
677 * returns 0 on success, <0 on failure.
678 */
679int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl)
680{
681 int rets, err;
682 long timeout = 15; /* 15 seconds */
683 struct mei_cl_cb *cb;
684
685 if (!dev || !cl)
686 return -ENODEV;
687
688 if (cl->state != MEI_FILE_DISCONNECTING)
689 return 0;
690
691 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
692 if (!cb)
693 return -ENOMEM;
694
695 INIT_LIST_HEAD(&cb->cb_list);
696 cb->file_private = cl;
697 cb->major_file_operations = MEI_CLOSE;
698 if (dev->mei_host_buffer_is_empty) {
699 dev->mei_host_buffer_is_empty = false;
700 if (mei_disconnect(dev, cl)) {
701 mdelay(10); /* Wait for hardware disconnection ready */
702 list_add_tail(&cb->cb_list,
703 &dev->ctrl_rd_list.mei_cb.cb_list);
704 } else {
705 rets = -ENODEV;
706 dev_dbg(&dev->pdev->dev, "failed to call mei_disconnect.\n");
707 goto free;
708 }
709 } else {
710 dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n");
711 list_add_tail(&cb->cb_list,
712 &dev->ctrl_wr_list.mei_cb.cb_list);
713 }
714 mutex_unlock(&dev->device_lock);
715
716 err = wait_event_timeout(dev->wait_recvd_msg,
717 (MEI_FILE_DISCONNECTED == cl->state),
718 timeout * HZ);
719
720 mutex_lock(&dev->device_lock);
721 if (MEI_FILE_DISCONNECTED == cl->state) {
722 rets = 0;
723 dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n");
724 } else {
725 rets = -ENODEV;
726 if (MEI_FILE_DISCONNECTED != cl->state)
727 dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n");
728
729 if (err)
730 dev_dbg(&dev->pdev->dev,
731 "wait failed disconnect err=%08x\n",
732 err);
733
734 dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n");
735 }
736
737 mei_io_list_flush(&dev->ctrl_rd_list, cl);
738 mei_io_list_flush(&dev->ctrl_wr_list, cl);
739free:
740 mei_free_cb_private(cb);
741 return rets;
742}
743
744/**
745 * mei_remove_client_from_file_list -
746 * removes file private data from device file list
747 *
748 * @dev: the device structure
749 * @host_client_id: host client id to be removed
750 */
751void mei_remove_client_from_file_list(struct mei_device *dev,
752 u8 host_client_id)
753{
754 struct mei_cl *cl_pos = NULL;
755 struct mei_cl *cl_next = NULL;
756 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
757 if (host_client_id == cl_pos->host_client_id) {
758 dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n",
759 cl_pos->host_client_id,
760 cl_pos->me_client_id);
761 list_del_init(&cl_pos->link);
762 break;
763 }
764 }
765}
diff --git a/drivers/staging/mei/interface.c b/drivers/staging/mei/interface.c
new file mode 100644
index 00000000000..cfec92dfc1c
--- /dev/null
+++ b/drivers/staging/mei/interface.c
@@ -0,0 +1,446 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17#include <linux/pci.h>
18#include "mei_dev.h"
19#include "mei.h"
20#include "interface.h"
21
22
23
24/**
25 * mei_set_csr_register - writes H_CSR register to the mei device,
26 * and ignores the H_IS bit for it is write-one-to-zero.
27 *
28 * @dev: the device structure
29 */
30void mei_hcsr_set(struct mei_device *dev)
31{
32 if ((dev->host_hw_state & H_IS) == H_IS)
33 dev->host_hw_state &= ~H_IS;
34 mei_reg_write(dev, H_CSR, dev->host_hw_state);
35 dev->host_hw_state = mei_hcsr_read(dev);
36}
37
38/**
39 * mei_csr_enable_interrupts - enables mei device interrupts
40 *
41 * @dev: the device structure
42 */
43void mei_enable_interrupts(struct mei_device *dev)
44{
45 dev->host_hw_state |= H_IE;
46 mei_hcsr_set(dev);
47}
48
49/**
50 * mei_csr_disable_interrupts - disables mei device interrupts
51 *
52 * @dev: the device structure
53 */
54void mei_disable_interrupts(struct mei_device *dev)
55{
56 dev->host_hw_state &= ~H_IE;
57 mei_hcsr_set(dev);
58}
59
60/**
61 * _host_get_filled_slots - gets number of device filled buffer slots
62 *
63 * @device: the device structure
64 *
65 * returns number of filled slots
66 */
67static unsigned char _host_get_filled_slots(const struct mei_device *dev)
68{
69 char read_ptr, write_ptr;
70
71 read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
72 write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);
73
74 return (unsigned char) (write_ptr - read_ptr);
75}
76
77/**
78 * mei_host_buffer_is_empty - checks if host buffer is empty.
79 *
80 * @dev: the device structure
81 *
82 * returns 1 if empty, 0 - otherwise.
83 */
84int mei_host_buffer_is_empty(struct mei_device *dev)
85{
86 unsigned char filled_slots;
87
88 dev->host_hw_state = mei_hcsr_read(dev);
89 filled_slots = _host_get_filled_slots(dev);
90
91 if (filled_slots == 0)
92 return 1;
93
94 return 0;
95}
96
97/**
98 * mei_count_empty_write_slots - counts write empty slots.
99 *
100 * @dev: the device structure
101 *
102 * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise empty slots count
103 */
104int mei_count_empty_write_slots(struct mei_device *dev)
105{
106 unsigned char buffer_depth, filled_slots, empty_slots;
107
108 dev->host_hw_state = mei_hcsr_read(dev);
109 buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
110 filled_slots = _host_get_filled_slots(dev);
111 empty_slots = buffer_depth - filled_slots;
112
113 /* check for overflow */
114 if (filled_slots > buffer_depth)
115 return -EOVERFLOW;
116
117 return empty_slots;
118}
119
120/**
121 * mei_write_message - writes a message to mei device.
122 *
123 * @dev: the device structure
124 * @header: header of message
125 * @write_buffer: message buffer will be written
126 * @write_length: message size will be written
127 *
128 * returns 1 if success, 0 - otherwise.
129 */
130int mei_write_message(struct mei_device *dev,
131 struct mei_msg_hdr *header,
132 unsigned char *write_buffer,
133 unsigned long write_length)
134{
135 u32 temp_msg = 0;
136 unsigned long bytes_written = 0;
137 unsigned char buffer_depth, filled_slots, empty_slots;
138 unsigned long dw_to_write;
139
140 dev->host_hw_state = mei_hcsr_read(dev);
141
142 dev_dbg(&dev->pdev->dev,
143 "host_hw_state = 0x%08x.\n",
144 dev->host_hw_state);
145
146 dev_dbg(&dev->pdev->dev,
147 "mei_write_message header=%08x.\n",
148 *((u32 *) header));
149
150 buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
151 filled_slots = _host_get_filled_slots(dev);
152 empty_slots = buffer_depth - filled_slots;
153 dev_dbg(&dev->pdev->dev,
154 "filled = %hu, empty = %hu.\n",
155 filled_slots, empty_slots);
156
157 dw_to_write = ((write_length + 3) / 4);
158
159 if (dw_to_write > empty_slots)
160 return 0;
161
162 mei_reg_write(dev, H_CB_WW, *((u32 *) header));
163
164 while (write_length >= 4) {
165 mei_reg_write(dev, H_CB_WW,
166 *(u32 *) (write_buffer + bytes_written));
167 bytes_written += 4;
168 write_length -= 4;
169 }
170
171 if (write_length > 0) {
172 memcpy(&temp_msg, &write_buffer[bytes_written], write_length);
173 mei_reg_write(dev, H_CB_WW, temp_msg);
174 }
175
176 dev->host_hw_state |= H_IG;
177 mei_hcsr_set(dev);
178 dev->me_hw_state = mei_mecsr_read(dev);
179 if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
180 return 0;
181
182 return 1;
183}
184
185/**
186 * mei_count_full_read_slots - counts read full slots.
187 *
188 * @dev: the device structure
189 *
190 * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
191 */
192int mei_count_full_read_slots(struct mei_device *dev)
193{
194 char read_ptr, write_ptr;
195 unsigned char buffer_depth, filled_slots;
196
197 dev->me_hw_state = mei_mecsr_read(dev);
198 buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24);
199 read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8);
200 write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16);
201 filled_slots = (unsigned char) (write_ptr - read_ptr);
202
203 /* check for overflow */
204 if (filled_slots > buffer_depth)
205 return -EOVERFLOW;
206
207 dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
208 return (int)filled_slots;
209}
210
211/**
212 * mei_read_slots - reads a message from mei device.
213 *
214 * @dev: the device structure
215 * @buffer: message buffer will be written
216 * @buffer_length: message size will be read
217 */
218void mei_read_slots(struct mei_device *dev,
219 unsigned char *buffer, unsigned long buffer_length)
220{
221 u32 i = 0;
222 unsigned char temp_buf[sizeof(u32)];
223
224 while (buffer_length >= sizeof(u32)) {
225 ((u32 *) buffer)[i] = mei_mecbrw_read(dev);
226
227 dev_dbg(&dev->pdev->dev,
228 "buffer[%d]= %d\n",
229 i, ((u32 *) buffer)[i]);
230
231 i++;
232 buffer_length -= sizeof(u32);
233 }
234
235 if (buffer_length > 0) {
236 *((u32 *) &temp_buf) = mei_mecbrw_read(dev);
237 memcpy(&buffer[i * 4], temp_buf, buffer_length);
238 }
239
240 dev->host_hw_state |= H_IG;
241 mei_hcsr_set(dev);
242}
243
244/**
245 * mei_flow_ctrl_creds - checks flow_control credentials.
246 *
247 * @dev: the device structure
248 * @cl: private data of the file object
249 *
250 * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
251 * -ENOENT if mei_cl is not present
252 * -EINVAL if single_recv_buf == 0
253 */
254int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
255{
256 int i;
257
258 if (!dev->me_clients_num)
259 return 0;
260
261 if (cl->mei_flow_ctrl_creds > 0)
262 return 1;
263
264 for (i = 0; i < dev->me_clients_num; i++) {
265 struct mei_me_client *me_cl = &dev->me_clients[i];
266 if (me_cl->client_id == cl->me_client_id) {
267 if (me_cl->mei_flow_ctrl_creds) {
268 if (WARN_ON(me_cl->props.single_recv_buf == 0))
269 return -EINVAL;
270 return 1;
271 } else {
272 return 0;
273 }
274 }
275 }
276 return -ENOENT;
277}
278
279/**
280 * mei_flow_ctrl_reduce - reduces flow_control.
281 *
282 * @dev: the device structure
283 * @cl: private data of the file object
284 * @returns
285 * 0 on success
286 * -ENOENT when me client is not found
287 * -EINVAL wehn ctrl credits are <= 0
288 */
289int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
290{
291 int i;
292
293 if (!dev->me_clients_num)
294 return -ENOENT;
295
296 for (i = 0; i < dev->me_clients_num; i++) {
297 struct mei_me_client *me_cl = &dev->me_clients[i];
298 if (me_cl->client_id == cl->me_client_id) {
299 if (me_cl->props.single_recv_buf != 0) {
300 if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
301 return -EINVAL;
302 dev->me_clients[i].mei_flow_ctrl_creds--;
303 } else {
304 if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
305 return -EINVAL;
306 cl->mei_flow_ctrl_creds--;
307 }
308 return 0;
309 }
310 }
311 return -ENOENT;
312}
313
314/**
315 * mei_send_flow_control - sends flow control to fw.
316 *
317 * @dev: the device structure
318 * @cl: private data of the file object
319 *
320 * returns 1 if success, 0 - otherwise.
321 */
322int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
323{
324 struct mei_msg_hdr *mei_hdr;
325 struct hbm_flow_control *mei_flow_control;
326
327 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
328 mei_hdr->host_addr = 0;
329 mei_hdr->me_addr = 0;
330 mei_hdr->length = sizeof(struct hbm_flow_control);
331 mei_hdr->msg_complete = 1;
332 mei_hdr->reserved = 0;
333
334 mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
335 memset(mei_flow_control, 0, sizeof(mei_flow_control));
336 mei_flow_control->host_addr = cl->host_client_id;
337 mei_flow_control->me_addr = cl->me_client_id;
338 mei_flow_control->cmd.cmd = MEI_FLOW_CONTROL_CMD;
339 memset(mei_flow_control->reserved, 0,
340 sizeof(mei_flow_control->reserved));
341 dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
342 cl->host_client_id, cl->me_client_id);
343 if (!mei_write_message(dev, mei_hdr,
344 (unsigned char *) mei_flow_control,
345 sizeof(struct hbm_flow_control)))
346 return 0;
347
348 return 1;
349
350}
351
352/**
353 * mei_other_client_is_connecting - checks if other
354 * client with the same client id is connected.
355 *
356 * @dev: the device structure
357 * @cl: private data of the file object
358 *
359 * returns 1 if other client is connected, 0 - otherwise.
360 */
361int mei_other_client_is_connecting(struct mei_device *dev,
362 struct mei_cl *cl)
363{
364 struct mei_cl *cl_pos = NULL;
365 struct mei_cl *cl_next = NULL;
366
367 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
368 if ((cl_pos->state == MEI_FILE_CONNECTING) &&
369 (cl_pos != cl) &&
370 cl->me_client_id == cl_pos->me_client_id)
371 return 1;
372
373 }
374 return 0;
375}
376
377/**
378 * mei_disconnect - sends disconnect message to fw.
379 *
380 * @dev: the device structure
381 * @cl: private data of the file object
382 *
383 * returns 1 if success, 0 - otherwise.
384 */
385int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
386{
387 struct mei_msg_hdr *mei_hdr;
388 struct hbm_client_disconnect_request *mei_cli_disconnect;
389
390 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
391 mei_hdr->host_addr = 0;
392 mei_hdr->me_addr = 0;
393 mei_hdr->length = sizeof(struct hbm_client_disconnect_request);
394 mei_hdr->msg_complete = 1;
395 mei_hdr->reserved = 0;
396
397 mei_cli_disconnect =
398 (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
399 memset(mei_cli_disconnect, 0, sizeof(mei_cli_disconnect));
400 mei_cli_disconnect->host_addr = cl->host_client_id;
401 mei_cli_disconnect->me_addr = cl->me_client_id;
402 mei_cli_disconnect->cmd.cmd = CLIENT_DISCONNECT_REQ_CMD;
403 mei_cli_disconnect->reserved[0] = 0;
404
405 if (!mei_write_message(dev, mei_hdr,
406 (unsigned char *) mei_cli_disconnect,
407 sizeof(struct hbm_client_disconnect_request)))
408 return 0;
409
410 return 1;
411}
412
413/**
414 * mei_connect - sends connect message to fw.
415 *
416 * @dev: the device structure
417 * @cl: private data of the file object
418 *
419 * returns 1 if success, 0 - otherwise.
420 */
421int mei_connect(struct mei_device *dev, struct mei_cl *cl)
422{
423 struct mei_msg_hdr *mei_hdr;
424 struct hbm_client_connect_request *mei_cli_connect;
425
426 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
427 mei_hdr->host_addr = 0;
428 mei_hdr->me_addr = 0;
429 mei_hdr->length = sizeof(struct hbm_client_connect_request);
430 mei_hdr->msg_complete = 1;
431 mei_hdr->reserved = 0;
432
433 mei_cli_connect =
434 (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
435 mei_cli_connect->host_addr = cl->host_client_id;
436 mei_cli_connect->me_addr = cl->me_client_id;
437 mei_cli_connect->cmd.cmd = CLIENT_CONNECT_REQ_CMD;
438 mei_cli_connect->reserved = 0;
439
440 if (!mei_write_message(dev, mei_hdr,
441 (unsigned char *) mei_cli_connect,
442 sizeof(struct hbm_client_connect_request)))
443 return 0;
444
445 return 1;
446}
diff --git a/drivers/staging/mei/interface.h b/drivers/staging/mei/interface.h
new file mode 100644
index 00000000000..d0bf5cf4f3e
--- /dev/null
+++ b/drivers/staging/mei/interface.h
@@ -0,0 +1,62 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17
18
19#ifndef _MEI_INTERFACE_H_
20#define _MEI_INTERFACE_H_
21
22#include "mei.h"
23#include "mei_dev.h"
24
25
26#define AMT_WD_VALUE 120 /* seconds */
27
28#define MEI_WATCHDOG_DATA_SIZE 16
29#define MEI_START_WD_DATA_SIZE 20
30#define MEI_WD_PARAMS_SIZE 4
31
32
33void mei_read_slots(struct mei_device *dev,
34 unsigned char *buffer, unsigned long buffer_length);
35
36int mei_write_message(struct mei_device *dev,
37 struct mei_msg_hdr *header,
38 unsigned char *write_buffer,
39 unsigned long write_length);
40
41int mei_host_buffer_is_empty(struct mei_device *dev);
42
43int mei_count_full_read_slots(struct mei_device *dev);
44
45int mei_count_empty_write_slots(struct mei_device *dev);
46
47int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
48
49int mei_wd_send(struct mei_device *dev);
50int mei_wd_stop(struct mei_device *dev, bool preserve);
51void mei_wd_host_init(struct mei_device *dev);
52void mei_wd_start_setup(struct mei_device *dev);
53
54int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl);
55
56int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl);
57
58int mei_disconnect(struct mei_device *dev, struct mei_cl *cl);
59int mei_other_client_is_connecting(struct mei_device *dev, struct mei_cl *cl);
60int mei_connect(struct mei_device *dev, struct mei_cl *cl);
61
62#endif /* _MEI_INTERFACE_H_ */
diff --git a/drivers/staging/mei/interrupt.c b/drivers/staging/mei/interrupt.c
new file mode 100644
index 00000000000..9cb186bf187
--- /dev/null
+++ b/drivers/staging/mei/interrupt.c
@@ -0,0 +1,1623 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17
18#include <linux/pci.h>
19#include <linux/kthread.h>
20#include <linux/interrupt.h>
21#include <linux/fs.h>
22#include <linux/jiffies.h>
23
24#include "mei_dev.h"
25#include "mei.h"
26#include "hw.h"
27#include "interface.h"
28
29
30/**
31 * mei_interrupt_quick_handler - The ISR of the MEI device
32 *
33 * @irq: The irq number
34 * @dev_id: pointer to the device structure
35 *
36 * returns irqreturn_t
37 */
38irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id)
39{
40 struct mei_device *dev = (struct mei_device *) dev_id;
41 u32 csr_reg = mei_hcsr_read(dev);
42
43 if ((csr_reg & H_IS) != H_IS)
44 return IRQ_NONE;
45
46 /* clear H_IS bit in H_CSR */
47 mei_reg_write(dev, H_CSR, csr_reg);
48
49 return IRQ_WAKE_THREAD;
50}
51
52/**
53 * _mei_cmpl - processes completed operation.
54 *
55 * @cl: private data of the file object.
56 * @cb_pos: callback block.
57 */
58static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
59{
60 if (cb_pos->major_file_operations == MEI_WRITE) {
61 mei_free_cb_private(cb_pos);
62 cb_pos = NULL;
63 cl->writing_state = MEI_WRITE_COMPLETE;
64 if (waitqueue_active(&cl->tx_wait))
65 wake_up_interruptible(&cl->tx_wait);
66
67 } else if (cb_pos->major_file_operations == MEI_READ &&
68 MEI_READING == cl->reading_state) {
69 cl->reading_state = MEI_READ_COMPLETE;
70 if (waitqueue_active(&cl->rx_wait))
71 wake_up_interruptible(&cl->rx_wait);
72
73 }
74}
75
76/**
77 * _mei_cmpl_iamthif - processes completed iamthif operation.
78 *
79 * @dev: the device structure.
80 * @cb_pos: callback block.
81 */
82static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos)
83{
84 if (dev->iamthif_canceled != 1) {
85 dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
86 dev->iamthif_stall_timer = 0;
87 memcpy(cb_pos->response_buffer.data,
88 dev->iamthif_msg_buf,
89 dev->iamthif_msg_buf_index);
90 list_add_tail(&cb_pos->cb_list,
91 &dev->amthi_read_complete_list.mei_cb.cb_list);
92 dev_dbg(&dev->pdev->dev, "amthi read completed.\n");
93 dev->iamthif_timer = jiffies;
94 dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
95 dev->iamthif_timer);
96 } else {
97 mei_run_next_iamthif_cmd(dev);
98 }
99
100 dev_dbg(&dev->pdev->dev, "completing amthi call back.\n");
101 wake_up_interruptible(&dev->iamthif_cl.wait);
102}
103
104
105/**
106 * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to
107 * handle the read amthi message data processing.
108 *
109 * @complete_list: An instance of our list structure
110 * @dev: the device structure
111 * @mei_hdr: header of amthi message
112 *
113 * returns 0 on success, <0 on failure.
114 */
115static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list,
116 struct mei_device *dev,
117 struct mei_msg_hdr *mei_hdr)
118{
119 struct mei_cl *cl;
120 struct mei_cl_cb *cb;
121 unsigned char *buffer;
122
123 BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
124 BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
125
126 buffer = (unsigned char *) (dev->iamthif_msg_buf +
127 dev->iamthif_msg_buf_index);
128 BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
129
130 mei_read_slots(dev, buffer, mei_hdr->length);
131
132 dev->iamthif_msg_buf_index += mei_hdr->length;
133
134 if (!mei_hdr->msg_complete)
135 return 0;
136
137 dev_dbg(&dev->pdev->dev,
138 "amthi_message_buffer_index =%d\n",
139 mei_hdr->length);
140
141 dev_dbg(&dev->pdev->dev, "completed amthi read.\n ");
142 if (!dev->iamthif_current_cb)
143 return -ENODEV;
144
145 cb = dev->iamthif_current_cb;
146 dev->iamthif_current_cb = NULL;
147
148 cl = (struct mei_cl *)cb->file_private;
149 if (!cl)
150 return -ENODEV;
151
152 dev->iamthif_stall_timer = 0;
153 cb->information = dev->iamthif_msg_buf_index;
154 cb->read_time = jiffies;
155 if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) {
156 /* found the iamthif cb */
157 dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n ");
158 dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n ");
159 list_add_tail(&cb->cb_list,
160 &complete_list->mei_cb.cb_list);
161 }
162 return 0;
163}
164
165/**
166 * _mei_irq_thread_state_ok - checks if mei header matches file private data
167 *
168 * @cl: private data of the file object
169 * @mei_hdr: header of mei client message
170 *
171 * returns !=0 if matches, 0 if no match.
172 */
173static int _mei_irq_thread_state_ok(struct mei_cl *cl,
174 struct mei_msg_hdr *mei_hdr)
175{
176 return (cl->host_client_id == mei_hdr->host_addr &&
177 cl->me_client_id == mei_hdr->me_addr &&
178 cl->state == MEI_FILE_CONNECTED &&
179 MEI_READ_COMPLETE != cl->reading_state);
180}
181
182/**
183 * mei_irq_thread_read_client_message - bottom half read routine after ISR to
184 * handle the read mei client message data processing.
185 *
186 * @complete_list: An instance of our list structure
187 * @dev: the device structure
188 * @mei_hdr: header of mei client message
189 *
190 * returns 0 on success, <0 on failure.
191 */
192static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
193 struct mei_device *dev,
194 struct mei_msg_hdr *mei_hdr)
195{
196 struct mei_cl *cl;
197 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
198 unsigned char *buffer = NULL;
199
200 dev_dbg(&dev->pdev->dev, "start client msg\n");
201 if (!(dev->read_list.status == 0 &&
202 !list_empty(&dev->read_list.mei_cb.cb_list)))
203 goto quit;
204
205 list_for_each_entry_safe(cb_pos, cb_next,
206 &dev->read_list.mei_cb.cb_list, cb_list) {
207 cl = (struct mei_cl *)cb_pos->file_private;
208 if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
209 cl->reading_state = MEI_READING;
210 buffer = (unsigned char *)
211 (cb_pos->response_buffer.data +
212 cb_pos->information);
213 BUG_ON(cb_pos->response_buffer.size <
214 mei_hdr->length +
215 cb_pos->information);
216
217 if (cb_pos->response_buffer.size <
218 mei_hdr->length + cb_pos->information) {
219 dev_dbg(&dev->pdev->dev, "message overflow.\n");
220 list_del(&cb_pos->cb_list);
221 return -ENOMEM;
222 }
223 if (buffer)
224 mei_read_slots(dev, buffer, mei_hdr->length);
225
226 cb_pos->information += mei_hdr->length;
227 if (mei_hdr->msg_complete) {
228 cl->status = 0;
229 list_del(&cb_pos->cb_list);
230 dev_dbg(&dev->pdev->dev,
231 "completed read host client = %d,"
232 "ME client = %d, "
233 "data length = %lu\n",
234 cl->host_client_id,
235 cl->me_client_id,
236 cb_pos->information);
237
238 *(cb_pos->response_buffer.data +
239 cb_pos->information) = '\0';
240 dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n",
241 cb_pos->response_buffer.data);
242 list_add_tail(&cb_pos->cb_list,
243 &complete_list->mei_cb.cb_list);
244 }
245
246 break;
247 }
248
249 }
250
251quit:
252 dev_dbg(&dev->pdev->dev, "message read\n");
253 if (!buffer) {
254 mei_read_slots(dev, (unsigned char *) dev->rd_msg_buf,
255 mei_hdr->length);
256 dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
257 *(u32 *) dev->rd_msg_buf);
258 }
259
260 return 0;
261}
262
263/**
264 * _mei_irq_thread_iamthif_read - prepares to read iamthif data.
265 *
266 * @dev: the device structure.
267 * @slots: free slots.
268 *
269 * returns 0, OK; otherwise, error.
270 */
271static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots)
272{
273
274 if (((*slots) * sizeof(u32)) >= (sizeof(struct mei_msg_hdr)
275 + sizeof(struct hbm_flow_control))) {
276 *slots -= (sizeof(struct mei_msg_hdr) +
277 sizeof(struct hbm_flow_control) + 3) / 4;
278 if (!mei_send_flow_control(dev, &dev->iamthif_cl)) {
279 dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
280 } else {
281 dev_dbg(&dev->pdev->dev, "iamthif flow control success\n");
282 dev->iamthif_state = MEI_IAMTHIF_READING;
283 dev->iamthif_flow_control_pending = false;
284 dev->iamthif_msg_buf_index = 0;
285 dev->iamthif_msg_buf_size = 0;
286 dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER;
287 dev->mei_host_buffer_is_empty =
288 mei_host_buffer_is_empty(dev);
289 }
290 return 0;
291 } else {
292 return -EMSGSIZE;
293 }
294}
295
296/**
297 * _mei_irq_thread_close - processes close related operation.
298 *
299 * @dev: the device structure.
300 * @slots: free slots.
301 * @cb_pos: callback block.
302 * @cl: private data of the file object.
303 * @cmpl_list: complete list.
304 *
305 * returns 0, OK; otherwise, error.
306 */
307static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
308 struct mei_cl_cb *cb_pos,
309 struct mei_cl *cl,
310 struct mei_io_list *cmpl_list)
311{
312 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
313 sizeof(struct hbm_client_disconnect_request))) {
314 *slots -= (sizeof(struct mei_msg_hdr) +
315 sizeof(struct hbm_client_disconnect_request) + 3) / 4;
316
317 if (!mei_disconnect(dev, cl)) {
318 cl->status = 0;
319 cb_pos->information = 0;
320 list_move_tail(&cb_pos->cb_list,
321 &cmpl_list->mei_cb.cb_list);
322 return -EMSGSIZE;
323 } else {
324 cl->state = MEI_FILE_DISCONNECTING;
325 cl->status = 0;
326 cb_pos->information = 0;
327 list_move_tail(&cb_pos->cb_list,
328 &dev->ctrl_rd_list.mei_cb.cb_list);
329 cl->timer_count = MEI_CONNECT_TIMEOUT;
330 }
331 } else {
332 /* return the cancel routine */
333 return -EBADMSG;
334 }
335
336 return 0;
337}
338
339/**
340 * is_treat_specially_client - checks if the message belongs
341 * to the file private data.
342 *
343 * @cl: private data of the file object
344 * @rs: connect response bus message
345 *
346 */
347static bool is_treat_specially_client(struct mei_cl *cl,
348 struct hbm_client_connect_response *rs)
349{
350
351 if (cl->host_client_id == rs->host_addr &&
352 cl->me_client_id == rs->me_addr) {
353 if (!rs->status) {
354 cl->state = MEI_FILE_CONNECTED;
355 cl->status = 0;
356
357 } else {
358 cl->state = MEI_FILE_DISCONNECTED;
359 cl->status = -ENODEV;
360 }
361 cl->timer_count = 0;
362
363 return true;
364 }
365 return false;
366}
367
368/**
369 * mei_client_connect_response - connects to response irq routine
370 *
371 * @dev: the device structure
372 * @rs: connect response bus message
373 */
374static void mei_client_connect_response(struct mei_device *dev,
375 struct hbm_client_connect_response *rs)
376{
377
378 struct mei_cl *cl;
379 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
380
381 dev_dbg(&dev->pdev->dev,
382 "connect_response:\n"
383 "ME Client = %d\n"
384 "Host Client = %d\n"
385 "Status = %d\n",
386 rs->me_addr,
387 rs->host_addr,
388 rs->status);
389
390 /* if WD or iamthif client treat specially */
391
392 if (is_treat_specially_client(&(dev->wd_cl), rs)) {
393 dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n",
394 dev->wd_timeout);
395
396 dev->wd_due_counter = (dev->wd_timeout) ? 1 : 0;
397
398 dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n");
399 mei_host_init_iamthif(dev);
400 return;
401 }
402
403 if (is_treat_specially_client(&(dev->iamthif_cl), rs)) {
404 dev->iamthif_state = MEI_IAMTHIF_IDLE;
405 return;
406 }
407 if (!dev->ctrl_rd_list.status &&
408 !list_empty(&dev->ctrl_rd_list.mei_cb.cb_list)) {
409 list_for_each_entry_safe(cb_pos, cb_next,
410 &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
411 cl = (struct mei_cl *)cb_pos->file_private;
412 if (!cl) {
413 list_del(&cb_pos->cb_list);
414 return;
415 }
416 if (MEI_IOCTL == cb_pos->major_file_operations) {
417 if (is_treat_specially_client(cl, rs)) {
418 list_del(&cb_pos->cb_list);
419 cl->status = 0;
420 cl->timer_count = 0;
421 break;
422 }
423 }
424 }
425 }
426}
427
428/**
429 * mei_client_disconnect_response - disconnects from response irq routine
430 *
431 * @dev: the device structure
432 * @rs: disconnect response bus message
433 */
434static void mei_client_disconnect_response(struct mei_device *dev,
435 struct hbm_client_connect_response *rs)
436{
437 struct mei_cl *cl;
438 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
439
440 dev_dbg(&dev->pdev->dev,
441 "disconnect_response:\n"
442 "ME Client = %d\n"
443 "Host Client = %d\n"
444 "Status = %d\n",
445 rs->me_addr,
446 rs->host_addr,
447 rs->status);
448
449 if (!dev->ctrl_rd_list.status &&
450 !list_empty(&dev->ctrl_rd_list.mei_cb.cb_list)) {
451 list_for_each_entry_safe(cb_pos, cb_next,
452 &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) {
453 cl = (struct mei_cl *)cb_pos->file_private;
454
455 if (!cl) {
456 list_del(&cb_pos->cb_list);
457 return;
458 }
459
460 dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in ctrl_rd_list.\n");
461 if (cl->host_client_id == rs->host_addr &&
462 cl->me_client_id == rs->me_addr) {
463
464 list_del(&cb_pos->cb_list);
465 if (!rs->status)
466 cl->state = MEI_FILE_DISCONNECTED;
467
468 cl->status = 0;
469 cl->timer_count = 0;
470 break;
471 }
472 }
473 }
474}
475
476/**
477 * same_flow_addr - tells if they have the same address.
478 *
479 * @file: private data of the file object.
480 * @flow: flow control.
481 *
482 * returns !=0, same; 0,not.
483 */
484static int same_flow_addr(struct mei_cl *cl, struct hbm_flow_control *flow)
485{
486 return (cl->host_client_id == flow->host_addr &&
487 cl->me_client_id == flow->me_addr);
488}
489
490/**
491 * add_single_flow_creds - adds single buffer credentials.
492 *
493 * @file: private data ot the file object.
494 * @flow: flow control.
495 */
496static void add_single_flow_creds(struct mei_device *dev,
497 struct hbm_flow_control *flow)
498{
499 struct mei_me_client *client;
500 int i;
501
502 for (i = 0; i < dev->me_clients_num; i++) {
503 client = &dev->me_clients[i];
504 if (client && flow->me_addr == client->client_id) {
505 if (client->props.single_recv_buf) {
506 client->mei_flow_ctrl_creds++;
507 dev_dbg(&dev->pdev->dev, "recv flow ctrl msg ME %d (single).\n",
508 flow->me_addr);
509 dev_dbg(&dev->pdev->dev, "flow control credentials =%d.\n",
510 client->mei_flow_ctrl_creds);
511 } else {
512 BUG(); /* error in flow control */
513 }
514 }
515 }
516}
517
518/**
519 * mei_client_flow_control_response - flow control response irq routine
520 *
521 * @dev: the device structure
522 * @flow_control: flow control response bus message
523 */
524static void mei_client_flow_control_response(struct mei_device *dev,
525 struct hbm_flow_control *flow_control)
526{
527 struct mei_cl *cl_pos = NULL;
528 struct mei_cl *cl_next = NULL;
529
530 if (!flow_control->host_addr) {
531 /* single receive buffer */
532 add_single_flow_creds(dev, flow_control);
533 } else {
534 /* normal connection */
535 list_for_each_entry_safe(cl_pos, cl_next,
536 &dev->file_list, link) {
537 dev_dbg(&dev->pdev->dev, "list_for_each_entry_safe in file_list\n");
538
539 dev_dbg(&dev->pdev->dev, "cl of host client %d ME client %d.\n",
540 cl_pos->host_client_id,
541 cl_pos->me_client_id);
542 dev_dbg(&dev->pdev->dev, "flow ctrl msg for host %d ME %d.\n",
543 flow_control->host_addr,
544 flow_control->me_addr);
545 if (same_flow_addr(cl_pos, flow_control)) {
546 dev_dbg(&dev->pdev->dev, "recv ctrl msg for host %d ME %d.\n",
547 flow_control->host_addr,
548 flow_control->me_addr);
549 cl_pos->mei_flow_ctrl_creds++;
550 dev_dbg(&dev->pdev->dev, "flow control credentials = %d.\n",
551 cl_pos->mei_flow_ctrl_creds);
552 break;
553 }
554 }
555 }
556}
557
558/**
559 * same_disconn_addr - tells if they have the same address
560 *
561 * @file: private data of the file object.
562 * @disconn: disconnection request.
563 *
564 * returns !=0, same; 0,not.
565 */
566static int same_disconn_addr(struct mei_cl *cl,
567 struct hbm_client_disconnect_request *disconn)
568{
569 return (cl->host_client_id == disconn->host_addr &&
570 cl->me_client_id == disconn->me_addr);
571}
572
573/**
574 * mei_client_disconnect_request - disconnects from request irq routine
575 *
576 * @dev: the device structure.
577 * @disconnect_req: disconnect request bus message.
578 */
579static void mei_client_disconnect_request(struct mei_device *dev,
580 struct hbm_client_disconnect_request *disconnect_req)
581{
582 struct mei_msg_hdr *mei_hdr;
583 struct hbm_client_connect_response *disconnect_res;
584 struct mei_cl *cl_pos = NULL;
585 struct mei_cl *cl_next = NULL;
586
587 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
588 if (same_disconn_addr(cl_pos, disconnect_req)) {
589 dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n",
590 disconnect_req->host_addr,
591 disconnect_req->me_addr);
592 cl_pos->state = MEI_FILE_DISCONNECTED;
593 cl_pos->timer_count = 0;
594 if (cl_pos == &dev->wd_cl) {
595 dev->wd_due_counter = 0;
596 dev->wd_pending = false;
597 } else if (cl_pos == &dev->iamthif_cl)
598 dev->iamthif_timer = 0;
599
600 /* prepare disconnect response */
601 mei_hdr =
602 (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
603 mei_hdr->host_addr = 0;
604 mei_hdr->me_addr = 0;
605 mei_hdr->length =
606 sizeof(struct hbm_client_connect_response);
607 mei_hdr->msg_complete = 1;
608 mei_hdr->reserved = 0;
609
610 disconnect_res =
611 (struct hbm_client_connect_response *)
612 &dev->ext_msg_buf[1];
613 disconnect_res->host_addr = cl_pos->host_client_id;
614 disconnect_res->me_addr = cl_pos->me_client_id;
615 *(u8 *) (&disconnect_res->cmd) =
616 CLIENT_DISCONNECT_RES_CMD;
617 disconnect_res->status = 0;
618 dev->extra_write_index = 2;
619 break;
620 }
621 }
622}
623
624
625/**
626 * mei_irq_thread_read_bus_message - bottom half read routine after ISR to
627 * handle the read bus message cmd processing.
628 *
629 * @dev: the device structure
630 * @mei_hdr: header of bus message
631 */
632static void mei_irq_thread_read_bus_message(struct mei_device *dev,
633 struct mei_msg_hdr *mei_hdr)
634{
635 struct mei_bus_message *mei_msg;
636 struct hbm_host_version_response *version_res;
637 struct hbm_client_connect_response *connect_res;
638 struct hbm_client_connect_response *disconnect_res;
639 struct hbm_flow_control *flow_control;
640 struct hbm_props_response *props_res;
641 struct hbm_host_enum_response *enum_res;
642 struct hbm_client_disconnect_request *disconnect_req;
643 struct hbm_host_stop_request *host_stop_req;
644
645 unsigned char *buffer;
646
647 /* read the message to our buffer */
648 buffer = (unsigned char *) dev->rd_msg_buf;
649 BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
650 mei_read_slots(dev, buffer, mei_hdr->length);
651 mei_msg = (struct mei_bus_message *) buffer;
652
653 switch (*(u8 *) mei_msg) {
654 case HOST_START_RES_CMD:
655 version_res = (struct hbm_host_version_response *) mei_msg;
656 if (version_res->host_version_supported) {
657 dev->version.major_version = HBM_MAJOR_VERSION;
658 dev->version.minor_version = HBM_MINOR_VERSION;
659 if (dev->mei_state == MEI_INIT_CLIENTS &&
660 dev->init_clients_state == MEI_START_MESSAGE) {
661 dev->init_clients_timer = 0;
662 mei_host_enum_clients_message(dev);
663 } else {
664 dev->recvd_msg = false;
665 dev_dbg(&dev->pdev->dev, "IMEI reset due to received host start response bus message.\n");
666 mei_reset(dev, 1);
667 return;
668 }
669 } else {
670 dev->version = version_res->me_max_version;
671 /* send stop message */
672 mei_hdr->host_addr = 0;
673 mei_hdr->me_addr = 0;
674 mei_hdr->length = sizeof(struct hbm_host_stop_request);
675 mei_hdr->msg_complete = 1;
676 mei_hdr->reserved = 0;
677
678 host_stop_req = (struct hbm_host_stop_request *)
679 &dev->wr_msg_buf[1];
680
681 memset(host_stop_req,
682 0,
683 sizeof(struct hbm_host_stop_request));
684 host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
685 host_stop_req->reason = DRIVER_STOP_REQUEST;
686 mei_write_message(dev, mei_hdr,
687 (unsigned char *) (host_stop_req),
688 mei_hdr->length);
689 dev_dbg(&dev->pdev->dev, "version mismatch.\n");
690 return;
691 }
692
693 dev->recvd_msg = true;
694 dev_dbg(&dev->pdev->dev, "host start response message received.\n");
695 break;
696
697 case CLIENT_CONNECT_RES_CMD:
698 connect_res =
699 (struct hbm_client_connect_response *) mei_msg;
700 mei_client_connect_response(dev, connect_res);
701 dev_dbg(&dev->pdev->dev, "client connect response message received.\n");
702 wake_up(&dev->wait_recvd_msg);
703 break;
704
705 case CLIENT_DISCONNECT_RES_CMD:
706 disconnect_res =
707 (struct hbm_client_connect_response *) mei_msg;
708 mei_client_disconnect_response(dev, disconnect_res);
709 dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n");
710 wake_up(&dev->wait_recvd_msg);
711 break;
712
713 case MEI_FLOW_CONTROL_CMD:
714 flow_control = (struct hbm_flow_control *) mei_msg;
715 mei_client_flow_control_response(dev, flow_control);
716 dev_dbg(&dev->pdev->dev, "client flow control response message received.\n");
717 break;
718
719 case HOST_CLIENT_PROPERTIES_RES_CMD:
720 props_res = (struct hbm_props_response *)mei_msg;
721 if (props_res->status || !dev->me_clients) {
722 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
723 mei_reset(dev, 1);
724 return;
725 }
726 if (dev->me_clients[dev->me_client_presentation_num]
727 .client_id == props_res->address) {
728
729 dev->me_clients[dev->me_client_presentation_num].props
730 = props_res->client_properties;
731
732 if (dev->mei_state == MEI_INIT_CLIENTS &&
733 dev->init_clients_state ==
734 MEI_CLIENT_PROPERTIES_MESSAGE) {
735 dev->me_client_index++;
736 dev->me_client_presentation_num++;
737 mei_host_client_properties(dev);
738 } else {
739 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message");
740 mei_reset(dev, 1);
741 return;
742 }
743 } else {
744 dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n");
745 mei_reset(dev, 1);
746 return;
747 }
748 break;
749
750 case HOST_ENUM_RES_CMD:
751 enum_res = (struct hbm_host_enum_response *) mei_msg;
752 memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
753 if (dev->mei_state == MEI_INIT_CLIENTS &&
754 dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
755 dev->init_clients_timer = 0;
756 dev->me_client_presentation_num = 0;
757 dev->me_client_index = 0;
758 mei_allocate_me_clients_storage(dev);
759 dev->init_clients_state =
760 MEI_CLIENT_PROPERTIES_MESSAGE;
761 mei_host_client_properties(dev);
762 } else {
763 dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
764 mei_reset(dev, 1);
765 return;
766 }
767 break;
768
769 case HOST_STOP_RES_CMD:
770 dev->mei_state = MEI_DISABLED;
771 dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
772 mei_reset(dev, 1);
773 break;
774
775 case CLIENT_DISCONNECT_REQ_CMD:
776 /* search for client */
777 disconnect_req =
778 (struct hbm_client_disconnect_request *) mei_msg;
779 mei_client_disconnect_request(dev, disconnect_req);
780 break;
781
782 case ME_STOP_REQ_CMD:
783 /* prepare stop request */
784 mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0];
785 mei_hdr->host_addr = 0;
786 mei_hdr->me_addr = 0;
787 mei_hdr->length = sizeof(struct hbm_host_stop_request);
788 mei_hdr->msg_complete = 1;
789 mei_hdr->reserved = 0;
790 host_stop_req =
791 (struct hbm_host_stop_request *) &dev->ext_msg_buf[1];
792 memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request));
793 host_stop_req->cmd.cmd = HOST_STOP_REQ_CMD;
794 host_stop_req->reason = DRIVER_STOP_REQUEST;
795 host_stop_req->reserved[0] = 0;
796 host_stop_req->reserved[1] = 0;
797 dev->extra_write_index = 2;
798 break;
799
800 default:
801 BUG();
802 break;
803
804 }
805}
806
807
808/**
809 * _mei_hb_read - processes read related operation.
810 *
811 * @dev: the device structure.
812 * @slots: free slots.
813 * @cb_pos: callback block.
814 * @cl: private data of the file object.
815 * @cmpl_list: complete list.
816 *
817 * returns 0, OK; otherwise, error.
818 */
819static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots,
820 struct mei_cl_cb *cb_pos,
821 struct mei_cl *cl,
822 struct mei_io_list *cmpl_list)
823{
824 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
825 sizeof(struct hbm_flow_control))) {
826 *slots -= (sizeof(struct mei_msg_hdr) +
827 sizeof(struct hbm_flow_control) + 3) / 4;
828 if (!mei_send_flow_control(dev, cl)) {
829 cl->status = -ENODEV;
830 cb_pos->information = 0;
831 list_move_tail(&cb_pos->cb_list,
832 &cmpl_list->mei_cb.cb_list);
833 return -ENODEV;
834 } else {
835 list_move_tail(&cb_pos->cb_list,
836 &dev->read_list.mei_cb.cb_list);
837 }
838 } else {
839 /* return the cancel routine */
840 list_del(&cb_pos->cb_list);
841 return -EBADMSG;
842 }
843
844 return 0;
845}
846
847
848/**
849 * _mei_irq_thread_ioctl - processes ioctl related operation.
850 *
851 * @dev: the device structure.
852 * @slots: free slots.
853 * @cb_pos: callback block.
854 * @cl: private data of the file object.
855 * @cmpl_list: complete list.
856 *
857 * returns 0, OK; otherwise, error.
858 */
859static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
860 struct mei_cl_cb *cb_pos,
861 struct mei_cl *cl,
862 struct mei_io_list *cmpl_list)
863{
864 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
865 sizeof(struct hbm_client_connect_request))) {
866 cl->state = MEI_FILE_CONNECTING;
867 *slots -= (sizeof(struct mei_msg_hdr) +
868 sizeof(struct hbm_client_connect_request) + 3) / 4;
869 if (!mei_connect(dev, cl)) {
870 cl->status = -ENODEV;
871 cb_pos->information = 0;
872 list_del(&cb_pos->cb_list);
873 return -ENODEV;
874 } else {
875 list_move_tail(&cb_pos->cb_list,
876 &dev->ctrl_rd_list.mei_cb.cb_list);
877 cl->timer_count = MEI_CONNECT_TIMEOUT;
878 }
879 } else {
880 /* return the cancel routine */
881 list_del(&cb_pos->cb_list);
882 return -EBADMSG;
883 }
884
885 return 0;
886}
887
888/**
889 * _mei_irq_thread_cmpl - processes completed and no-iamthif operation.
890 *
891 * @dev: the device structure.
892 * @slots: free slots.
893 * @cb_pos: callback block.
894 * @cl: private data of the file object.
895 * @cmpl_list: complete list.
896 *
897 * returns 0, OK; otherwise, error.
898 */
899static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots,
900 struct mei_cl_cb *cb_pos,
901 struct mei_cl *cl,
902 struct mei_io_list *cmpl_list)
903{
904 struct mei_msg_hdr *mei_hdr;
905
906 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
907 (cb_pos->request_buffer.size -
908 cb_pos->information))) {
909 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
910 mei_hdr->host_addr = cl->host_client_id;
911 mei_hdr->me_addr = cl->me_client_id;
912 mei_hdr->length = cb_pos->request_buffer.size -
913 cb_pos->information;
914 mei_hdr->msg_complete = 1;
915 mei_hdr->reserved = 0;
916 dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d"
917 "mei_hdr->msg_complete = %d\n",
918 cb_pos->request_buffer.size,
919 mei_hdr->msg_complete);
920 dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n",
921 cb_pos->information);
922 dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
923 mei_hdr->length);
924 *slots -= (sizeof(struct mei_msg_hdr) +
925 mei_hdr->length + 3) / 4;
926 if (!mei_write_message(dev, mei_hdr,
927 (unsigned char *)
928 (cb_pos->request_buffer.data +
929 cb_pos->information),
930 mei_hdr->length)) {
931 cl->status = -ENODEV;
932 list_move_tail(&cb_pos->cb_list,
933 &cmpl_list->mei_cb.cb_list);
934 return -ENODEV;
935 } else {
936 if (mei_flow_ctrl_reduce(dev, cl))
937 return -ENODEV;
938 cl->status = 0;
939 cb_pos->information += mei_hdr->length;
940 list_move_tail(&cb_pos->cb_list,
941 &dev->write_waiting_list.mei_cb.cb_list);
942 }
943 } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
944 /* buffer is still empty */
945 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
946 mei_hdr->host_addr = cl->host_client_id;
947 mei_hdr->me_addr = cl->me_client_id;
948 mei_hdr->length =
949 (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
950 mei_hdr->msg_complete = 0;
951 mei_hdr->reserved = 0;
952
953 (*slots) -= (sizeof(struct mei_msg_hdr) +
954 mei_hdr->length + 3) / 4;
955 if (!mei_write_message(dev, mei_hdr,
956 (unsigned char *)
957 (cb_pos->request_buffer.data +
958 cb_pos->information),
959 mei_hdr->length)) {
960 cl->status = -ENODEV;
961 list_move_tail(&cb_pos->cb_list,
962 &cmpl_list->mei_cb.cb_list);
963 return -ENODEV;
964 } else {
965 cb_pos->information += mei_hdr->length;
966 dev_dbg(&dev->pdev->dev,
967 "cb_pos->request_buffer.size =%d"
968 " mei_hdr->msg_complete = %d\n",
969 cb_pos->request_buffer.size,
970 mei_hdr->msg_complete);
971 dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n",
972 cb_pos->information);
973 dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
974 mei_hdr->length);
975 }
976 return -EMSGSIZE;
977 } else {
978 return -EBADMSG;
979 }
980
981 return 0;
982}
983
984/**
985 * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation.
986 *
987 * @dev: the device structure.
988 * @slots: free slots.
989 * @cb_pos: callback block.
990 * @cl: private data of the file object.
991 * @cmpl_list: complete list.
992 *
993 * returns 0, OK; otherwise, error.
994 */
995static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots,
996 struct mei_cl_cb *cb_pos,
997 struct mei_cl *cl,
998 struct mei_io_list *cmpl_list)
999{
1000 struct mei_msg_hdr *mei_hdr;
1001
1002 if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) +
1003 dev->iamthif_msg_buf_size -
1004 dev->iamthif_msg_buf_index)) {
1005 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
1006 mei_hdr->host_addr = cl->host_client_id;
1007 mei_hdr->me_addr = cl->me_client_id;
1008 mei_hdr->length = dev->iamthif_msg_buf_size -
1009 dev->iamthif_msg_buf_index;
1010 mei_hdr->msg_complete = 1;
1011 mei_hdr->reserved = 0;
1012
1013 *slots -= (sizeof(struct mei_msg_hdr) +
1014 mei_hdr->length + 3) / 4;
1015
1016 if (!mei_write_message(dev, mei_hdr,
1017 (dev->iamthif_msg_buf +
1018 dev->iamthif_msg_buf_index),
1019 mei_hdr->length)) {
1020 dev->iamthif_state = MEI_IAMTHIF_IDLE;
1021 cl->status = -ENODEV;
1022 list_del(&cb_pos->cb_list);
1023 return -ENODEV;
1024 } else {
1025 if (mei_flow_ctrl_reduce(dev, cl))
1026 return -ENODEV;
1027 dev->iamthif_msg_buf_index += mei_hdr->length;
1028 cb_pos->information = dev->iamthif_msg_buf_index;
1029 cl->status = 0;
1030 dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
1031 dev->iamthif_flow_control_pending = true;
1032 /* save iamthif cb sent to amthi client */
1033 dev->iamthif_current_cb = cb_pos;
1034 list_move_tail(&cb_pos->cb_list,
1035 &dev->write_waiting_list.mei_cb.cb_list);
1036
1037 }
1038 } else if (*slots == ((dev->host_hw_state & H_CBD) >> 24)) {
1039 /* buffer is still empty */
1040 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
1041 mei_hdr->host_addr = cl->host_client_id;
1042 mei_hdr->me_addr = cl->me_client_id;
1043 mei_hdr->length =
1044 (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr);
1045 mei_hdr->msg_complete = 0;
1046 mei_hdr->reserved = 0;
1047
1048 *slots -= (sizeof(struct mei_msg_hdr) +
1049 mei_hdr->length + 3) / 4;
1050
1051 if (!mei_write_message(dev, mei_hdr,
1052 (dev->iamthif_msg_buf +
1053 dev->iamthif_msg_buf_index),
1054 mei_hdr->length)) {
1055 cl->status = -ENODEV;
1056 list_del(&cb_pos->cb_list);
1057 } else {
1058 dev->iamthif_msg_buf_index += mei_hdr->length;
1059 }
1060 return -EMSGSIZE;
1061 } else {
1062 return -EBADMSG;
1063 }
1064
1065 return 0;
1066}
1067
1068/**
1069 * mei_irq_thread_read_handler - bottom half read routine after ISR to
1070 * handle the read processing.
1071 *
1072 * @cmpl_list: An instance of our list structure
1073 * @dev: the device structure
1074 * @slots: slots to read.
1075 *
1076 * returns 0 on success, <0 on failure.
1077 */
1078static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list,
1079 struct mei_device *dev,
1080 s32 *slots)
1081{
1082 struct mei_msg_hdr *mei_hdr;
1083 struct mei_cl *cl_pos = NULL;
1084 struct mei_cl *cl_next = NULL;
1085 int ret = 0;
1086
1087 if (!dev->rd_msg_hdr) {
1088 dev->rd_msg_hdr = mei_mecbrw_read(dev);
1089 dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
1090 (*slots)--;
1091 dev_dbg(&dev->pdev->dev, "slots =%08x.\n", *slots);
1092 }
1093 mei_hdr = (struct mei_msg_hdr *) &dev->rd_msg_hdr;
1094 dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length);
1095
1096 if (mei_hdr->reserved || !dev->rd_msg_hdr) {
1097 dev_dbg(&dev->pdev->dev, "corrupted message header.\n");
1098 ret = -EBADMSG;
1099 goto end;
1100 }
1101
1102 if (mei_hdr->host_addr || mei_hdr->me_addr) {
1103 list_for_each_entry_safe(cl_pos, cl_next,
1104 &dev->file_list, link) {
1105 dev_dbg(&dev->pdev->dev,
1106 "list_for_each_entry_safe read host"
1107 " client = %d, ME client = %d\n",
1108 cl_pos->host_client_id,
1109 cl_pos->me_client_id);
1110 if (cl_pos->host_client_id == mei_hdr->host_addr &&
1111 cl_pos->me_client_id == mei_hdr->me_addr)
1112 break;
1113 }
1114
1115 if (&cl_pos->link == &dev->file_list) {
1116 dev_dbg(&dev->pdev->dev, "corrupted message header\n");
1117 ret = -EBADMSG;
1118 goto end;
1119 }
1120 }
1121 if (((*slots) * sizeof(u32)) < mei_hdr->length) {
1122 dev_dbg(&dev->pdev->dev,
1123 "we can't read the message slots =%08x.\n",
1124 *slots);
1125 /* we can't read the message */
1126 ret = -ERANGE;
1127 goto end;
1128 }
1129
1130 /* decide where to read the message too */
1131 if (!mei_hdr->host_addr) {
1132 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_bus_message.\n");
1133 mei_irq_thread_read_bus_message(dev, mei_hdr);
1134 dev_dbg(&dev->pdev->dev, "end mei_irq_thread_read_bus_message.\n");
1135 } else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
1136 (MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
1137 (dev->iamthif_state == MEI_IAMTHIF_READING)) {
1138 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
1139 dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n",
1140 mei_hdr->length);
1141 ret = mei_irq_thread_read_amthi_message(cmpl_list,
1142 dev, mei_hdr);
1143 if (ret)
1144 goto end;
1145
1146 } else {
1147 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
1148 ret = mei_irq_thread_read_client_message(cmpl_list,
1149 dev, mei_hdr);
1150 if (ret)
1151 goto end;
1152
1153 }
1154
1155 /* reset the number of slots and header */
1156 *slots = mei_count_full_read_slots(dev);
1157 dev->rd_msg_hdr = 0;
1158
1159 if (*slots == -EOVERFLOW) {
1160 /* overflow - reset */
1161 dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
1162 /* set the event since message has been read */
1163 ret = -ERANGE;
1164 goto end;
1165 }
1166end:
1167 return ret;
1168}
1169
1170
1171/**
1172 * mei_irq_thread_write_handler - bottom half write routine after
1173 * ISR to handle the write processing.
1174 *
1175 * @cmpl_list: An instance of our list structure
1176 * @dev: the device structure
1177 * @slots: slots to write.
1178 *
1179 * returns 0 on success, <0 on failure.
1180 */
1181static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
1182 struct mei_device *dev,
1183 s32 *slots)
1184{
1185
1186 struct mei_cl *cl;
1187 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
1188 struct mei_io_list *list;
1189 int ret;
1190
1191 if (!mei_host_buffer_is_empty(dev)) {
1192 dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n");
1193 return 0;
1194 }
1195 *slots = mei_count_empty_write_slots(dev);
1196 /* complete all waiting for write CB */
1197 dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n");
1198
1199 list = &dev->write_waiting_list;
1200 if (!list->status && !list_empty(&list->mei_cb.cb_list)) {
1201 list_for_each_entry_safe(cb_pos, cb_next,
1202 &list->mei_cb.cb_list, cb_list) {
1203 cl = (struct mei_cl *)cb_pos->file_private;
1204 if (cl) {
1205 cl->status = 0;
1206 list_del(&cb_pos->cb_list);
1207 if (MEI_WRITING == cl->writing_state &&
1208 (cb_pos->major_file_operations ==
1209 MEI_WRITE) &&
1210 (cl != &dev->iamthif_cl)) {
1211 dev_dbg(&dev->pdev->dev,
1212 "MEI WRITE COMPLETE\n");
1213 cl->writing_state =
1214 MEI_WRITE_COMPLETE;
1215 list_add_tail(&cb_pos->cb_list,
1216 &cmpl_list->mei_cb.cb_list);
1217 }
1218 if (cl == &dev->iamthif_cl) {
1219 dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n");
1220 if (dev->iamthif_flow_control_pending) {
1221 ret =
1222 _mei_irq_thread_iamthif_read(
1223 dev, slots);
1224 if (ret)
1225 return ret;
1226 }
1227 }
1228 }
1229
1230 }
1231 }
1232
1233 if (dev->stop && !dev->wd_pending) {
1234 dev->wd_stopped = true;
1235 wake_up_interruptible(&dev->wait_stop_wd);
1236 return 0;
1237 }
1238
1239 if (dev->extra_write_index) {
1240 dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n",
1241 dev->extra_write_index);
1242 mei_write_message(dev,
1243 (struct mei_msg_hdr *) &dev->ext_msg_buf[0],
1244 (unsigned char *) &dev->ext_msg_buf[1],
1245 (dev->extra_write_index - 1) * sizeof(u32));
1246 *slots -= dev->extra_write_index;
1247 dev->extra_write_index = 0;
1248 }
1249 if (dev->mei_state == MEI_ENABLED) {
1250 if (dev->wd_pending &&
1251 mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
1252 if (mei_wd_send(dev))
1253 dev_dbg(&dev->pdev->dev, "wd send failed.\n");
1254 else
1255 if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
1256 return -ENODEV;
1257
1258 dev->wd_pending = false;
1259
1260 if (dev->wd_timeout) {
1261 *slots -= (sizeof(struct mei_msg_hdr) +
1262 MEI_START_WD_DATA_SIZE + 3) / 4;
1263 dev->wd_due_counter = 2;
1264 } else {
1265 *slots -= (sizeof(struct mei_msg_hdr) +
1266 MEI_WD_PARAMS_SIZE + 3) / 4;
1267 dev->wd_due_counter = 0;
1268 }
1269
1270 }
1271 }
1272 if (dev->stop)
1273 return ~ENODEV;
1274
1275 /* complete control write list CB */
1276 if (!dev->ctrl_wr_list.status) {
1277 /* complete control write list CB */
1278 dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
1279 list_for_each_entry_safe(cb_pos, cb_next,
1280 &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) {
1281 cl = (struct mei_cl *)
1282 cb_pos->file_private;
1283 if (!cl) {
1284 list_del(&cb_pos->cb_list);
1285 return -ENODEV;
1286 }
1287 switch (cb_pos->major_file_operations) {
1288 case MEI_CLOSE:
1289 /* send disconnect message */
1290 ret = _mei_irq_thread_close(dev, slots,
1291 cb_pos, cl, cmpl_list);
1292 if (ret)
1293 return ret;
1294
1295 break;
1296 case MEI_READ:
1297 /* send flow control message */
1298 ret = _mei_irq_thread_read(dev, slots,
1299 cb_pos, cl, cmpl_list);
1300 if (ret)
1301 return ret;
1302
1303 break;
1304 case MEI_IOCTL:
1305 /* connect message */
1306 if (!mei_other_client_is_connecting(dev,
1307 cl))
1308 continue;
1309 ret = _mei_irq_thread_ioctl(dev, slots,
1310 cb_pos, cl, cmpl_list);
1311 if (ret)
1312 return ret;
1313
1314 break;
1315
1316 default:
1317 BUG();
1318 }
1319
1320 }
1321 }
1322 /* complete write list CB */
1323 if (!dev->write_list.status &&
1324 !list_empty(&dev->write_list.mei_cb.cb_list)) {
1325 dev_dbg(&dev->pdev->dev, "complete write list cb.\n");
1326 list_for_each_entry_safe(cb_pos, cb_next,
1327 &dev->write_list.mei_cb.cb_list, cb_list) {
1328 cl = (struct mei_cl *)cb_pos->file_private;
1329
1330 if (cl) {
1331 if (cl != &dev->iamthif_cl) {
1332 if (!mei_flow_ctrl_creds(dev,
1333 cl)) {
1334 dev_dbg(&dev->pdev->dev,
1335 "No flow control"
1336 " credentials for client"
1337 " %d, not sending.\n",
1338 cl->host_client_id);
1339 continue;
1340 }
1341 ret = _mei_irq_thread_cmpl(dev, slots,
1342 cb_pos,
1343 cl, cmpl_list);
1344 if (ret)
1345 return ret;
1346
1347 } else if (cl == &dev->iamthif_cl) {
1348 /* IAMTHIF IOCTL */
1349 dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n");
1350 if (!mei_flow_ctrl_creds(dev,
1351 cl)) {
1352 dev_dbg(&dev->pdev->dev,
1353 "No flow control"
1354 " credentials for amthi"
1355 " client %d.\n",
1356 cl->host_client_id);
1357 continue;
1358 }
1359 ret = _mei_irq_thread_cmpl_iamthif(dev,
1360 slots,
1361 cb_pos,
1362 cl,
1363 cmpl_list);
1364 if (ret)
1365 return ret;
1366
1367 }
1368 }
1369
1370 }
1371 }
1372 return 0;
1373}
1374
1375
1376
1377/**
1378 * mei_timer - timer function.
1379 *
1380 * @work: pointer to the work_struct structure
1381 *
1382 * NOTE: This function is called by timer interrupt work
1383 */
1384void mei_wd_timer(struct work_struct *work)
1385{
1386 unsigned long timeout;
1387 struct mei_cl *cl_pos = NULL;
1388 struct mei_cl *cl_next = NULL;
1389 struct list_head *amthi_complete_list = NULL;
1390 struct mei_cl_cb *cb_pos = NULL;
1391 struct mei_cl_cb *cb_next = NULL;
1392
1393 struct mei_device *dev = container_of(work,
1394 struct mei_device, wd_work.work);
1395
1396
1397 mutex_lock(&dev->device_lock);
1398 if (dev->mei_state != MEI_ENABLED) {
1399 if (dev->mei_state == MEI_INIT_CLIENTS) {
1400 if (dev->init_clients_timer) {
1401 if (--dev->init_clients_timer == 0) {
1402 dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
1403 dev->init_clients_state);
1404 mei_reset(dev, 1);
1405 }
1406 }
1407 }
1408 goto out;
1409 }
1410 /*** connect/disconnect timeouts ***/
1411 list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
1412 if (cl_pos->timer_count) {
1413 if (--cl_pos->timer_count == 0) {
1414 dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
1415 mei_reset(dev, 1);
1416 goto out;
1417 }
1418 }
1419 }
1420
1421 if (dev->wd_cl.state != MEI_FILE_CONNECTED)
1422 goto out;
1423
1424 /* Watchdog */
1425 if (dev->wd_due_counter && !dev->wd_bypass) {
1426 if (--dev->wd_due_counter == 0) {
1427 if (dev->mei_host_buffer_is_empty &&
1428 mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
1429 dev->mei_host_buffer_is_empty = false;
1430 dev_dbg(&dev->pdev->dev, "send watchdog.\n");
1431
1432 if (mei_wd_send(dev))
1433 dev_dbg(&dev->pdev->dev, "wd send failed.\n");
1434 else
1435 if (mei_flow_ctrl_reduce(dev, &dev->wd_cl))
1436 goto out;
1437
1438 if (dev->wd_timeout)
1439 dev->wd_due_counter = 2;
1440 else
1441 dev->wd_due_counter = 0;
1442
1443 } else
1444 dev->wd_pending = true;
1445
1446 }
1447 }
1448 if (dev->iamthif_stall_timer) {
1449 if (--dev->iamthif_stall_timer == 0) {
1450 dev_dbg(&dev->pdev->dev, "reseting because of hang to amthi.\n");
1451 mei_reset(dev, 1);
1452 dev->iamthif_msg_buf_size = 0;
1453 dev->iamthif_msg_buf_index = 0;
1454 dev->iamthif_canceled = false;
1455 dev->iamthif_ioctl = true;
1456 dev->iamthif_state = MEI_IAMTHIF_IDLE;
1457 dev->iamthif_timer = 0;
1458
1459 if (dev->iamthif_current_cb)
1460 mei_free_cb_private(dev->iamthif_current_cb);
1461
1462 dev->iamthif_file_object = NULL;
1463 dev->iamthif_current_cb = NULL;
1464 mei_run_next_iamthif_cmd(dev);
1465 }
1466 }
1467
1468 if (dev->iamthif_timer) {
1469
1470 timeout = dev->iamthif_timer +
1471 msecs_to_jiffies(IAMTHIF_READ_TIMER);
1472
1473 dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n",
1474 dev->iamthif_timer);
1475 dev_dbg(&dev->pdev->dev, "timeout = %ld\n", timeout);
1476 dev_dbg(&dev->pdev->dev, "jiffies = %ld\n", jiffies);
1477 if (time_after(jiffies, timeout)) {
1478 /*
1479 * User didn't read the AMTHI data on time (15sec)
1480 * freeing AMTHI for other requests
1481 */
1482
1483 dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n");
1484
1485 amthi_complete_list = &dev->amthi_read_complete_list.
1486 mei_cb.cb_list;
1487
1488 if (!list_empty(amthi_complete_list)) {
1489
1490 list_for_each_entry_safe(cb_pos, cb_next,
1491 amthi_complete_list,
1492 cb_list) {
1493
1494 cl_pos = cb_pos->file_object->private_data;
1495
1496 /* Finding the AMTHI entry. */
1497 if (cl_pos == &dev->iamthif_cl)
1498 list_del(&cb_pos->cb_list);
1499 }
1500 }
1501 if (dev->iamthif_current_cb)
1502 mei_free_cb_private(dev->iamthif_current_cb);
1503
1504 dev->iamthif_file_object->private_data = NULL;
1505 dev->iamthif_file_object = NULL;
1506 dev->iamthif_current_cb = NULL;
1507 dev->iamthif_timer = 0;
1508 mei_run_next_iamthif_cmd(dev);
1509
1510 }
1511 }
1512out:
1513 schedule_delayed_work(&dev->wd_work, 2 * HZ);
1514 mutex_unlock(&dev->device_lock);
1515}
1516
1517/**
1518 * mei_interrupt_thread_handler - function called after ISR to handle the interrupt
1519 * processing.
1520 *
1521 * @irq: The irq number
1522 * @dev_id: pointer to the device structure
1523 *
1524 * returns irqreturn_t
1525 *
1526 */
1527irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
1528{
1529 struct mei_device *dev = (struct mei_device *) dev_id;
1530 struct mei_io_list complete_list;
1531 struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
1532 struct mei_cl *cl;
1533 s32 slots;
1534 int rets;
1535 bool bus_message_received;
1536
1537
1538 dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
1539 /* initialize our complete list */
1540 mutex_lock(&dev->device_lock);
1541 mei_io_list_init(&complete_list);
1542 dev->host_hw_state = mei_hcsr_read(dev);
1543 dev->me_hw_state = mei_mecsr_read(dev);
1544
1545 /* check if ME wants a reset */
1546 if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
1547 dev->mei_state != MEI_RESETING &&
1548 dev->mei_state != MEI_INITIALIZING) {
1549 dev_dbg(&dev->pdev->dev, "FW not ready.\n");
1550 mei_reset(dev, 1);
1551 mutex_unlock(&dev->device_lock);
1552 return IRQ_HANDLED;
1553 }
1554
1555 /* check if we need to start the dev */
1556 if ((dev->host_hw_state & H_RDY) == 0) {
1557 if ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA) {
1558 dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
1559 dev->host_hw_state |= (H_IE | H_IG | H_RDY);
1560 mei_hcsr_set(dev);
1561 dev->mei_state = MEI_INIT_CLIENTS;
1562 dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
1563 /* link is established
1564 * start sending messages.
1565 */
1566 mei_host_start_message(dev);
1567 mutex_unlock(&dev->device_lock);
1568 return IRQ_HANDLED;
1569 } else {
1570 dev_dbg(&dev->pdev->dev, "FW not ready.\n");
1571 mutex_unlock(&dev->device_lock);
1572 return IRQ_HANDLED;
1573 }
1574 }
1575 /* check slots avalable for reading */
1576 slots = mei_count_full_read_slots(dev);
1577 dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n",
1578 slots, dev->extra_write_index);
1579 while (slots > 0 && !dev->extra_write_index) {
1580 dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n",
1581 slots, dev->extra_write_index);
1582 dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n");
1583 rets = mei_irq_thread_read_handler(&complete_list, dev, &slots);
1584 if (rets)
1585 goto end;
1586 }
1587 rets = mei_irq_thread_write_handler(&complete_list, dev, &slots);
1588end:
1589 dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
1590 dev->host_hw_state = mei_hcsr_read(dev);
1591 dev->mei_host_buffer_is_empty = mei_host_buffer_is_empty(dev);
1592
1593 bus_message_received = false;
1594 if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
1595 dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
1596 bus_message_received = true;
1597 }
1598 mutex_unlock(&dev->device_lock);
1599 if (bus_message_received) {
1600 dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
1601 wake_up_interruptible(&dev->wait_recvd_msg);
1602 bus_message_received = false;
1603 }
1604 if (complete_list.status || list_empty(&complete_list.mei_cb.cb_list))
1605 return IRQ_HANDLED;
1606
1607
1608 list_for_each_entry_safe(cb_pos, cb_next,
1609 &complete_list.mei_cb.cb_list, cb_list) {
1610 cl = (struct mei_cl *)cb_pos->file_private;
1611 list_del(&cb_pos->cb_list);
1612 if (cl) {
1613 if (cl != &dev->iamthif_cl) {
1614 dev_dbg(&dev->pdev->dev, "completing call back.\n");
1615 _mei_cmpl(cl, cb_pos);
1616 cb_pos = NULL;
1617 } else if (cl == &dev->iamthif_cl) {
1618 _mei_cmpl_iamthif(dev, cb_pos);
1619 }
1620 }
1621 }
1622 return IRQ_HANDLED;
1623}
diff --git a/drivers/staging/mei/iorw.c b/drivers/staging/mei/iorw.c
new file mode 100644
index 00000000000..8a61d126651
--- /dev/null
+++ b/drivers/staging/mei/iorw.c
@@ -0,0 +1,604 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17
18#include <linux/kernel.h>
19#include <linux/fs.h>
20#include <linux/errno.h>
21#include <linux/types.h>
22#include <linux/fcntl.h>
23#include <linux/aio.h>
24#include <linux/pci.h>
25#include <linux/init.h>
26#include <linux/ioctl.h>
27#include <linux/cdev.h>
28#include <linux/list.h>
29#include <linux/delay.h>
30#include <linux/sched.h>
31#include <linux/uuid.h>
32#include <linux/jiffies.h>
33#include <linux/uaccess.h>
34
35
36#include "mei_dev.h"
37#include "hw.h"
38#include "mei.h"
39#include "interface.h"
40#include "mei_version.h"
41
42
43
44/**
45 * mei_ioctl_connect_client - the connect to fw client IOCTL function
46 *
47 * @dev: the device structure
48 * @data: IOCTL connect data, input and output parameters
49 * @file: private data of the file object
50 *
51 * Locking: called under "dev->device_lock" lock
52 *
53 * returns 0 on success, <0 on failure.
54 */
55int mei_ioctl_connect_client(struct file *file,
56 struct mei_connect_client_data *data)
57{
58 struct mei_device *dev;
59 struct mei_cl_cb *cb;
60 struct mei_client *client;
61 struct mei_cl *cl;
62 struct mei_cl *cl_pos = NULL;
63 struct mei_cl *cl_next = NULL;
64 long timeout = CONNECT_TIMEOUT;
65 int i;
66 int err;
67 int rets;
68
69 cl = file->private_data;
70 if (WARN_ON(!cl || !cl->dev))
71 return -ENODEV;
72
73 dev = cl->dev;
74
75 dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n");
76
77
78 /* buffered ioctl cb */
79 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
80 if (!cb) {
81 rets = -ENOMEM;
82 goto end;
83 }
84 INIT_LIST_HEAD(&cb->cb_list);
85
86 cb->major_file_operations = MEI_IOCTL;
87
88 if (dev->mei_state != MEI_ENABLED) {
89 rets = -ENODEV;
90 goto end;
91 }
92 if (cl->state != MEI_FILE_INITIALIZING &&
93 cl->state != MEI_FILE_DISCONNECTED) {
94 rets = -EBUSY;
95 goto end;
96 }
97
98 /* find ME client we're trying to connect to */
99 i = mei_find_me_client_index(dev, data->in_client_uuid);
100 if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
101 cl->me_client_id = dev->me_clients[i].client_id;
102 cl->state = MEI_FILE_CONNECTING;
103 }
104
105 dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
106 cl->me_client_id);
107 dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
108 dev->me_clients[i].props.protocol_version);
109 dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
110 dev->me_clients[i].props.max_msg_length);
111
112 /* if we're connecting to amthi client so we will use the exist
113 * connection
114 */
115 if (uuid_le_cmp(data->in_client_uuid, mei_amthi_guid) == 0) {
116 dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
117 if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
118 rets = -ENODEV;
119 goto end;
120 }
121 clear_bit(cl->host_client_id, dev->host_clients_map);
122 list_for_each_entry_safe(cl_pos, cl_next,
123 &dev->file_list, link) {
124 if (mei_cl_cmp_id(cl, cl_pos)) {
125 dev_dbg(&dev->pdev->dev,
126 "remove file private data node host"
127 " client = %d, ME client = %d.\n",
128 cl_pos->host_client_id,
129 cl_pos->me_client_id);
130 list_del(&cl_pos->link);
131 }
132
133 }
134 dev_dbg(&dev->pdev->dev, "free file private data memory.\n");
135 kfree(cl);
136
137 cl = NULL;
138 file->private_data = &dev->iamthif_cl;
139
140 client = &data->out_client_properties;
141 client->max_msg_length =
142 dev->me_clients[i].props.max_msg_length;
143 client->protocol_version =
144 dev->me_clients[i].props.protocol_version;
145 rets = dev->iamthif_cl.status;
146
147 goto end;
148 }
149
150 if (cl->state != MEI_FILE_CONNECTING) {
151 rets = -ENODEV;
152 goto end;
153 }
154
155
156 /* prepare the output buffer */
157 client = &data->out_client_properties;
158 client->max_msg_length = dev->me_clients[i].props.max_msg_length;
159 client->protocol_version = dev->me_clients[i].props.protocol_version;
160 dev_dbg(&dev->pdev->dev, "Can connect?\n");
161 if (dev->mei_host_buffer_is_empty
162 && !mei_other_client_is_connecting(dev, cl)) {
163 dev_dbg(&dev->pdev->dev, "Sending Connect Message\n");
164 dev->mei_host_buffer_is_empty = false;
165 if (!mei_connect(dev, cl)) {
166 dev_dbg(&dev->pdev->dev, "Sending connect message - failed\n");
167 rets = -ENODEV;
168 goto end;
169 } else {
170 dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n");
171 cl->timer_count = MEI_CONNECT_TIMEOUT;
172 cb->file_private = cl;
173 list_add_tail(&cb->cb_list,
174 &dev->ctrl_rd_list.mei_cb.
175 cb_list);
176 }
177
178
179 } else {
180 dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n");
181 cb->file_private = cl;
182 dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n");
183 list_add_tail(&cb->cb_list,
184 &dev->ctrl_wr_list.mei_cb.cb_list);
185 }
186 mutex_unlock(&dev->device_lock);
187 err = wait_event_timeout(dev->wait_recvd_msg,
188 (MEI_FILE_CONNECTED == cl->state ||
189 MEI_FILE_DISCONNECTED == cl->state),
190 timeout * HZ);
191
192 mutex_lock(&dev->device_lock);
193 if (MEI_FILE_CONNECTED == cl->state) {
194 dev_dbg(&dev->pdev->dev, "successfully connected to FW client.\n");
195 rets = cl->status;
196 goto end;
197 } else {
198 dev_dbg(&dev->pdev->dev, "failed to connect to FW client.cl->state = %d.\n",
199 cl->state);
200 if (!err) {
201 dev_dbg(&dev->pdev->dev,
202 "wait_event_interruptible_timeout failed on client"
203 " connect message fw response message.\n");
204 }
205 rets = -EFAULT;
206
207 mei_io_list_flush(&dev->ctrl_rd_list, cl);
208 mei_io_list_flush(&dev->ctrl_wr_list, cl);
209 goto end;
210 }
211 rets = 0;
212end:
213 dev_dbg(&dev->pdev->dev, "free connect cb memory.");
214 kfree(cb);
215 return rets;
216}
217
218/**
219 * find_amthi_read_list_entry - finds a amthilist entry for current file
220 *
221 * @dev: the device structure
222 * @file: pointer to file object
223 *
224 * returns returned a list entry on success, NULL on failure.
225 */
226struct mei_cl_cb *find_amthi_read_list_entry(
227 struct mei_device *dev,
228 struct file *file)
229{
230 struct mei_cl *cl_temp;
231 struct mei_cl_cb *cb_pos = NULL;
232 struct mei_cl_cb *cb_next = NULL;
233
234 if (!dev->amthi_read_complete_list.status &&
235 !list_empty(&dev->amthi_read_complete_list.mei_cb.cb_list)) {
236 list_for_each_entry_safe(cb_pos, cb_next,
237 &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) {
238 cl_temp = (struct mei_cl *)cb_pos->file_private;
239 if (cl_temp && cl_temp == &dev->iamthif_cl &&
240 cb_pos->file_object == file)
241 return cb_pos;
242 }
243 }
244 return NULL;
245}
246
247/**
248 * amthi_read - read data from AMTHI client
249 *
250 * @dev: the device structure
251 * @if_num: minor number
252 * @file: pointer to file object
253 * @*ubuf: pointer to user data in user space
254 * @length: data length to read
255 * @offset: data read offset
256 *
257 * Locking: called under "dev->device_lock" lock
258 *
259 * returns
260 * returned data length on success,
261 * zero if no data to read,
262 * negative on failure.
263 */
264int amthi_read(struct mei_device *dev, struct file *file,
265 char __user *ubuf, size_t length, loff_t *offset)
266{
267 int rets;
268 int wait_ret;
269 struct mei_cl_cb *cb = NULL;
270 struct mei_cl *cl = file->private_data;
271 unsigned long timeout;
272 int i;
273
274 /* Only Posible if we are in timeout */
275 if (!cl || cl != &dev->iamthif_cl) {
276 dev_dbg(&dev->pdev->dev, "bad file ext.\n");
277 return -ETIMEDOUT;
278 }
279
280 for (i = 0; i < dev->me_clients_num; i++) {
281 if (dev->me_clients[i].client_id ==
282 dev->iamthif_cl.me_client_id)
283 break;
284 }
285
286 if (i == dev->me_clients_num) {
287 dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
288 return -ENODEV;
289 }
290 if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id))
291 return -ENODEV;
292
293 dev_dbg(&dev->pdev->dev, "checking amthi data\n");
294 cb = find_amthi_read_list_entry(dev, file);
295
296 /* Check for if we can block or not*/
297 if (cb == NULL && file->f_flags & O_NONBLOCK)
298 return -EAGAIN;
299
300
301 dev_dbg(&dev->pdev->dev, "waiting for amthi data\n");
302 while (cb == NULL) {
303 /* unlock the Mutex */
304 mutex_unlock(&dev->device_lock);
305
306 wait_ret = wait_event_interruptible(dev->iamthif_cl.wait,
307 (cb = find_amthi_read_list_entry(dev, file)));
308
309 if (wait_ret)
310 return -ERESTARTSYS;
311
312 dev_dbg(&dev->pdev->dev, "woke up from sleep\n");
313
314 /* Locking again the Mutex */
315 mutex_lock(&dev->device_lock);
316 }
317
318
319 dev_dbg(&dev->pdev->dev, "Got amthi data\n");
320 dev->iamthif_timer = 0;
321
322 if (cb) {
323 timeout = cb->read_time +
324 msecs_to_jiffies(IAMTHIF_READ_TIMER);
325 dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
326 timeout);
327
328 if (time_after(jiffies, timeout)) {
329 dev_dbg(&dev->pdev->dev, "amthi Time out\n");
330 /* 15 sec for the message has expired */
331 list_del(&cb->cb_list);
332 rets = -ETIMEDOUT;
333 goto free;
334 }
335 }
336 /* if the whole message will fit remove it from the list */
337 if (cb->information >= *offset &&
338 length >= (cb->information - *offset))
339 list_del(&cb->cb_list);
340 else if (cb->information > 0 && cb->information <= *offset) {
341 /* end of the message has been reached */
342 list_del(&cb->cb_list);
343 rets = 0;
344 goto free;
345 }
346 /* else means that not full buffer will be read and do not
347 * remove message from deletion list
348 */
349
350 dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n",
351 cb->response_buffer.size);
352 dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n",
353 cb->information);
354
355 /* length is being turncated to PAGE_SIZE, however,
356 * the information may be longer */
357 length = min_t(size_t, length, (cb->information - *offset));
358
359 if (copy_to_user(ubuf,
360 cb->response_buffer.data + *offset,
361 length))
362 rets = -EFAULT;
363 else {
364 rets = length;
365 if ((*offset + length) < cb->information) {
366 *offset += length;
367 goto out;
368 }
369 }
370free:
371 dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n");
372 *offset = 0;
373 mei_free_cb_private(cb);
374out:
375 return rets;
376}
377
378/**
379 * mei_start_read - the start read client message function.
380 *
381 * @dev: the device structure
382 * @if_num: minor number
383 * @cl: private data of the file object
384 *
385 * returns 0 on success, <0 on failure.
386 */
387int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
388{
389 struct mei_cl_cb *cb;
390 int rets = 0;
391 int i;
392
393 if (cl->state != MEI_FILE_CONNECTED)
394 return -ENODEV;
395
396 if (dev->mei_state != MEI_ENABLED)
397 return -ENODEV;
398
399 dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
400 if (cl->read_pending || cl->read_cb) {
401 dev_dbg(&dev->pdev->dev, "read is pending.\n");
402 return -EBUSY;
403 }
404
405 cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
406 if (!cb)
407 return -ENOMEM;
408
409 dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
410 cl->host_client_id, cl->me_client_id);
411
412 for (i = 0; i < dev->me_clients_num; i++) {
413 if (dev->me_clients[i].client_id == cl->me_client_id)
414 break;
415
416 }
417
418 if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
419 rets = -ENODEV;
420 goto unlock;
421 }
422
423 if (i == dev->me_clients_num) {
424 rets = -ENODEV;
425 goto unlock;
426 }
427
428 cb->response_buffer.size = dev->me_clients[i].props.max_msg_length;
429 cb->response_buffer.data =
430 kmalloc(cb->response_buffer.size, GFP_KERNEL);
431 if (!cb->response_buffer.data) {
432 rets = -ENOMEM;
433 goto unlock;
434 }
435 dev_dbg(&dev->pdev->dev, "allocation call back data success.\n");
436 cb->major_file_operations = MEI_READ;
437 /* make sure information is zero before we start */
438 cb->information = 0;
439 cb->file_private = (void *) cl;
440 cl->read_cb = cb;
441 if (dev->mei_host_buffer_is_empty) {
442 dev->mei_host_buffer_is_empty = false;
443 if (!mei_send_flow_control(dev, cl)) {
444 rets = -ENODEV;
445 goto unlock;
446 } else {
447 list_add_tail(&cb->cb_list,
448 &dev->read_list.mei_cb.cb_list);
449 }
450 } else {
451 list_add_tail(&cb->cb_list,
452 &dev->ctrl_wr_list.mei_cb.cb_list);
453 }
454 return rets;
455unlock:
456 mei_free_cb_private(cb);
457 return rets;
458}
459
460/**
461 * amthi_write - write iamthif data to amthi client
462 *
463 * @dev: the device structure
464 * @cb: mei call back struct
465 *
466 * returns 0 on success, <0 on failure.
467 */
468int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb)
469{
470 struct mei_msg_hdr mei_hdr;
471 int ret;
472
473 if (!dev || !cb)
474 return -ENODEV;
475
476 dev_dbg(&dev->pdev->dev, "write data to amthi client.\n");
477
478 dev->iamthif_state = MEI_IAMTHIF_WRITING;
479 dev->iamthif_current_cb = cb;
480 dev->iamthif_file_object = cb->file_object;
481 dev->iamthif_canceled = false;
482 dev->iamthif_ioctl = true;
483 dev->iamthif_msg_buf_size = cb->request_buffer.size;
484 memcpy(dev->iamthif_msg_buf, cb->request_buffer.data,
485 cb->request_buffer.size);
486
487 ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl);
488 if (ret < 0)
489 return ret;
490
491 if (ret && dev->mei_host_buffer_is_empty) {
492 ret = 0;
493 dev->mei_host_buffer_is_empty = false;
494 if (cb->request_buffer.size >
495 (((dev->host_hw_state & H_CBD) >> 24) * sizeof(u32))
496 -sizeof(struct mei_msg_hdr)) {
497 mei_hdr.length =
498 (((dev->host_hw_state & H_CBD) >> 24) *
499 sizeof(u32)) - sizeof(struct mei_msg_hdr);
500 mei_hdr.msg_complete = 0;
501 } else {
502 mei_hdr.length = cb->request_buffer.size;
503 mei_hdr.msg_complete = 1;
504 }
505
506 mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
507 mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
508 mei_hdr.reserved = 0;
509 dev->iamthif_msg_buf_index += mei_hdr.length;
510 if (!mei_write_message(dev, &mei_hdr,
511 (unsigned char *)(dev->iamthif_msg_buf),
512 mei_hdr.length))
513 return -ENODEV;
514
515 if (mei_hdr.msg_complete) {
516 if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl))
517 return -ENODEV;
518 dev->iamthif_flow_control_pending = true;
519 dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL;
520 dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n");
521 dev->iamthif_current_cb = cb;
522 dev->iamthif_file_object = cb->file_object;
523 list_add_tail(&cb->cb_list,
524 &dev->write_waiting_list.mei_cb.cb_list);
525 } else {
526 dev_dbg(&dev->pdev->dev, "message does not complete, "
527 "so add amthi cb to write list.\n");
528 list_add_tail(&cb->cb_list,
529 &dev->write_list.mei_cb.cb_list);
530 }
531 } else {
532 if (!(dev->mei_host_buffer_is_empty))
533 dev_dbg(&dev->pdev->dev, "host buffer is not empty");
534
535 dev_dbg(&dev->pdev->dev, "No flow control credentials, "
536 "so add iamthif cb to write list.\n");
537 list_add_tail(&cb->cb_list,
538 &dev->write_list.mei_cb.cb_list);
539 }
540 return 0;
541}
542
543/**
544 * iamthif_ioctl_send_msg - send cmd data to amthi client
545 *
546 * @dev: the device structure
547 *
548 * returns 0 on success, <0 on failure.
549 */
550void mei_run_next_iamthif_cmd(struct mei_device *dev)
551{
552 struct mei_cl *cl_tmp;
553 struct mei_cl_cb *cb_pos = NULL;
554 struct mei_cl_cb *cb_next = NULL;
555 int status;
556
557 if (!dev)
558 return;
559
560 dev->iamthif_msg_buf_size = 0;
561 dev->iamthif_msg_buf_index = 0;
562 dev->iamthif_canceled = false;
563 dev->iamthif_ioctl = true;
564 dev->iamthif_state = MEI_IAMTHIF_IDLE;
565 dev->iamthif_timer = 0;
566 dev->iamthif_file_object = NULL;
567
568 if (dev->amthi_cmd_list.status == 0 &&
569 !list_empty(&dev->amthi_cmd_list.mei_cb.cb_list)) {
570 dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n");
571
572 list_for_each_entry_safe(cb_pos, cb_next,
573 &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) {
574 list_del(&cb_pos->cb_list);
575 cl_tmp = (struct mei_cl *)cb_pos->file_private;
576
577 if (cl_tmp && cl_tmp == &dev->iamthif_cl) {
578 status = amthi_write(dev, cb_pos);
579 if (status) {
580 dev_dbg(&dev->pdev->dev,
581 "amthi write failed status = %d\n",
582 status);
583 return;
584 }
585 break;
586 }
587 }
588 }
589}
590
591/**
592 * mei_free_cb_private - free mei_cb_private related memory
593 *
594 * @cb: mei callback struct
595 */
596void mei_free_cb_private(struct mei_cl_cb *cb)
597{
598 if (cb == NULL)
599 return;
600
601 kfree(cb->request_buffer.data);
602 kfree(cb->response_buffer.data);
603 kfree(cb);
604}
diff --git a/drivers/staging/mei/main.c b/drivers/staging/mei/main.c
new file mode 100644
index 00000000000..de8825fcd8c
--- /dev/null
+++ b/drivers/staging/mei/main.c
@@ -0,0 +1,1342 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/kernel.h>
20#include <linux/device.h>
21#include <linux/fs.h>
22#include <linux/errno.h>
23#include <linux/types.h>
24#include <linux/fcntl.h>
25#include <linux/aio.h>
26#include <linux/pci.h>
27#include <linux/poll.h>
28#include <linux/init.h>
29#include <linux/ioctl.h>
30#include <linux/cdev.h>
31#include <linux/sched.h>
32#include <linux/uuid.h>
33#include <linux/compat.h>
34#include <linux/jiffies.h>
35#include <linux/interrupt.h>
36
37#include "mei_dev.h"
38#include "mei.h"
39#include "interface.h"
40#include "mei_version.h"
41
42
43#define MEI_READ_TIMEOUT 45
44#define MEI_DRIVER_NAME "mei"
45#define MEI_DEV_NAME "mei"
46
47/*
48 * mei driver strings
49 */
50static char mei_driver_name[] = MEI_DRIVER_NAME;
51static const char mei_driver_string[] = "Intel(R) Management Engine Interface";
52static const char mei_driver_version[] = MEI_DRIVER_VERSION;
53
54/* mei char device for registration */
55static struct cdev mei_cdev;
56
57/* major number for device */
58static int mei_major;
59/* The device pointer */
60/* Currently this driver works as long as there is only a single AMT device. */
61static struct pci_dev *mei_device;
62
63static struct class *mei_class;
64
65
66/* mei_pci_tbl - PCI Device ID Table */
67static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
68 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
69 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
70 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
71 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
72 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
73 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
74 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
75 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
76 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
77 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
78 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
79 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
80 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
81 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
82 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
83 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
84 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
85 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
86 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
87 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
88 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
89 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
90 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
91 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
92 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
93 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
94 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
95 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
96 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
97 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
98 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
99
100 /* required last entry */
101 {0, }
102};
103
104MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
105
106static DEFINE_MUTEX(mei_mutex);
107
108/**
109 * mei_probe - Device Initialization Routine
110 *
111 * @pdev: PCI device structure
112 * @ent: entry in kcs_pci_tbl
113 *
114 * returns 0 on success, <0 on failure.
115 */
116static int __devinit mei_probe(struct pci_dev *pdev,
117 const struct pci_device_id *ent)
118{
119 struct mei_device *dev;
120 int err;
121
122 mutex_lock(&mei_mutex);
123 if (mei_device) {
124 err = -EEXIST;
125 goto end;
126 }
127 /* enable pci dev */
128 err = pci_enable_device(pdev);
129 if (err) {
130 printk(KERN_ERR "mei: Failed to enable pci device.\n");
131 goto end;
132 }
133 /* set PCI host mastering */
134 pci_set_master(pdev);
135 /* pci request regions for mei driver */
136 err = pci_request_regions(pdev, mei_driver_name);
137 if (err) {
138 printk(KERN_ERR "mei: Failed to get pci regions.\n");
139 goto disable_device;
140 }
141 /* allocates and initializes the mei dev structure */
142 dev = mei_device_init(pdev);
143 if (!dev) {
144 err = -ENOMEM;
145 goto release_regions;
146 }
147 /* mapping IO device memory */
148 dev->mem_addr = pci_iomap(pdev, 0, 0);
149 if (!dev->mem_addr) {
150 printk(KERN_ERR "mei: mapping I/O device memory failure.\n");
151 err = -ENOMEM;
152 goto free_device;
153 }
154 /* request and enable interrupt */
155 err = request_threaded_irq(pdev->irq,
156 mei_interrupt_quick_handler,
157 mei_interrupt_thread_handler,
158 IRQF_SHARED, mei_driver_name, dev);
159 if (err) {
160 printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n",
161 pdev->irq);
162 goto unmap_memory;
163 }
164 INIT_DELAYED_WORK(&dev->wd_work, mei_wd_timer);
165 if (mei_hw_init(dev)) {
166 printk(KERN_ERR "mei: Init hw failure.\n");
167 err = -ENODEV;
168 goto release_irq;
169 }
170 mei_device = pdev;
171 pci_set_drvdata(pdev, dev);
172 schedule_delayed_work(&dev->wd_work, HZ);
173
174 mutex_unlock(&mei_mutex);
175
176 pr_debug("mei: Driver initialization successful.\n");
177
178 return 0;
179
180release_irq:
181 /* disable interrupts */
182 dev->host_hw_state = mei_hcsr_read(dev);
183 mei_disable_interrupts(dev);
184 flush_scheduled_work();
185 free_irq(pdev->irq, dev);
186unmap_memory:
187 pci_iounmap(pdev, dev->mem_addr);
188free_device:
189 kfree(dev);
190release_regions:
191 pci_release_regions(pdev);
192disable_device:
193 pci_disable_device(pdev);
194end:
195 mutex_unlock(&mei_mutex);
196 printk(KERN_ERR "mei: Driver initialization failed.\n");
197 return err;
198}
199
200/**
201 * mei_remove - Device Removal Routine
202 *
203 * @pdev: PCI device structure
204 *
205 * mei_remove is called by the PCI subsystem to alert the driver
206 * that it should release a PCI device.
207 */
208static void __devexit mei_remove(struct pci_dev *pdev)
209{
210 struct mei_device *dev;
211
212 if (mei_device != pdev)
213 return;
214
215 dev = pci_get_drvdata(pdev);
216 if (!dev)
217 return;
218
219 mutex_lock(&dev->device_lock);
220
221 mei_wd_stop(dev, false);
222
223 mei_device = NULL;
224
225 if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
226 dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
227 mei_disconnect_host_client(dev, &dev->iamthif_cl);
228 }
229 if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
230 dev->wd_cl.state = MEI_FILE_DISCONNECTING;
231 mei_disconnect_host_client(dev, &dev->wd_cl);
232 }
233
234 /* remove entry if already in list */
235 dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
236 mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id);
237 mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id);
238
239 dev->iamthif_current_cb = NULL;
240 dev->me_clients_num = 0;
241
242 mutex_unlock(&dev->device_lock);
243
244 flush_scheduled_work();
245
246 /* disable interrupts */
247 mei_disable_interrupts(dev);
248
249 free_irq(pdev->irq, dev);
250 pci_set_drvdata(pdev, NULL);
251
252 if (dev->mem_addr)
253 pci_iounmap(pdev, dev->mem_addr);
254
255 kfree(dev);
256
257 pci_release_regions(pdev);
258 pci_disable_device(pdev);
259}
260
261/**
262 * mei_clear_list - removes all callbacks associated with file
263 * from mei_cb_list
264 *
265 * @dev: device structure.
266 * @file: file structure
267 * @mei_cb_list: callbacks list
268 *
269 * mei_clear_list is called to clear resources associated with file
270 * when application calls close function or Ctrl-C was pressed
271 *
272 * returns true if callback removed from the list, false otherwise
273 */
274static bool mei_clear_list(struct mei_device *dev,
275 struct file *file, struct list_head *mei_cb_list)
276{
277 struct mei_cl_cb *cb_pos = NULL;
278 struct mei_cl_cb *cb_next = NULL;
279 struct file *file_temp;
280 bool removed = false;
281
282 /* list all list member */
283 list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) {
284 file_temp = (struct file *)cb_pos->file_object;
285 /* check if list member associated with a file */
286 if (file_temp == file) {
287 /* remove member from the list */
288 list_del(&cb_pos->cb_list);
289 /* check if cb equal to current iamthif cb */
290 if (dev->iamthif_current_cb == cb_pos) {
291 dev->iamthif_current_cb = NULL;
292 /* send flow control to iamthif client */
293 mei_send_flow_control(dev, &dev->iamthif_cl);
294 }
295 /* free all allocated buffers */
296 mei_free_cb_private(cb_pos);
297 cb_pos = NULL;
298 removed = true;
299 }
300 }
301 return removed;
302}
303
304/**
305 * mei_clear_lists - removes all callbacks associated with file
306 *
307 * @dev: device structure
308 * @file: file structure
309 *
310 * mei_clear_lists is called to clear resources associated with file
311 * when application calls close function or Ctrl-C was pressed
312 *
313 * returns true if callback removed from the list, false otherwise
314 */
315static bool mei_clear_lists(struct mei_device *dev, struct file *file)
316{
317 bool removed = false;
318
319 /* remove callbacks associated with a file */
320 mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list);
321 if (mei_clear_list(dev, file,
322 &dev->amthi_read_complete_list.mei_cb.cb_list))
323 removed = true;
324
325 mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list);
326
327 if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list))
328 removed = true;
329
330 if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list))
331 removed = true;
332
333 if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list))
334 removed = true;
335
336 /* check if iamthif_current_cb not NULL */
337 if (dev->iamthif_current_cb && !removed) {
338 /* check file and iamthif current cb association */
339 if (dev->iamthif_current_cb->file_object == file) {
340 /* remove cb */
341 mei_free_cb_private(dev->iamthif_current_cb);
342 dev->iamthif_current_cb = NULL;
343 removed = true;
344 }
345 }
346 return removed;
347}
348/**
349 * find_read_list_entry - find read list entry
350 *
351 * @dev: device structure
352 * @file: pointer to file structure
353 *
354 * returns cb on success, NULL on error
355 */
356static struct mei_cl_cb *find_read_list_entry(
357 struct mei_device *dev,
358 struct mei_cl *cl)
359{
360 struct mei_cl_cb *cb_pos = NULL;
361 struct mei_cl_cb *cb_next = NULL;
362
363 if (!dev->read_list.status &&
364 !list_empty(&dev->read_list.mei_cb.cb_list)) {
365
366 dev_dbg(&dev->pdev->dev, "remove read_list CB\n");
367 list_for_each_entry_safe(cb_pos, cb_next,
368 &dev->read_list.mei_cb.cb_list, cb_list) {
369 struct mei_cl *cl_temp;
370 cl_temp = (struct mei_cl *)cb_pos->file_private;
371
372 if (mei_cl_cmp_id(cl, cl_temp))
373 return cb_pos;
374 }
375 }
376 return NULL;
377}
378
379/**
380 * mei_open - the open function
381 *
382 * @inode: pointer to inode structure
383 * @file: pointer to file structure
384 *
385 * returns 0 on success, <0 on error
386 */
387static int mei_open(struct inode *inode, struct file *file)
388{
389 struct mei_cl *cl;
390 int if_num = iminor(inode), err;
391 struct mei_device *dev;
392
393 err = -ENODEV;
394 if (!mei_device)
395 goto out;
396
397 dev = pci_get_drvdata(mei_device);
398 if (if_num != MEI_MINOR_NUMBER || !dev)
399 goto out;
400
401 mutex_lock(&dev->device_lock);
402 err = -ENOMEM;
403 cl = mei_cl_allocate(dev);
404 if (!cl)
405 goto out;
406
407 err = -ENODEV;
408 if (dev->mei_state != MEI_ENABLED) {
409 dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n",
410 dev->mei_state);
411 goto out_unlock;
412 }
413 err = -EMFILE;
414 if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT)
415 goto out_unlock;
416
417 cl->host_client_id = find_first_zero_bit(dev->host_clients_map,
418 MEI_CLIENTS_MAX);
419 if (cl->host_client_id > MEI_CLIENTS_MAX)
420 goto out_unlock;
421
422 dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id);
423
424 dev->open_handle_count++;
425 list_add_tail(&cl->link, &dev->file_list);
426
427 set_bit(cl->host_client_id, dev->host_clients_map);
428 cl->state = MEI_FILE_INITIALIZING;
429 cl->sm_state = 0;
430
431 file->private_data = cl;
432 mutex_unlock(&dev->device_lock);
433
434 return 0;
435
436out_unlock:
437 mutex_unlock(&dev->device_lock);
438 kfree(cl);
439out:
440 return err;
441}
442
443/**
444 * mei_release - the release function
445 *
446 * @inode: pointer to inode structure
447 * @file: pointer to file structure
448 *
449 * returns 0 on success, <0 on error
450 */
451static int mei_release(struct inode *inode, struct file *file)
452{
453 struct mei_cl *cl = file->private_data;
454 struct mei_cl_cb *cb;
455 struct mei_device *dev;
456 int rets = 0;
457
458 if (WARN_ON(!cl || !cl->dev))
459 return -ENODEV;
460
461 dev = cl->dev;
462
463 mutex_lock(&dev->device_lock);
464 if (cl != &dev->iamthif_cl) {
465 if (cl->state == MEI_FILE_CONNECTED) {
466 cl->state = MEI_FILE_DISCONNECTING;
467 dev_dbg(&dev->pdev->dev,
468 "disconnecting client host client = %d, "
469 "ME client = %d\n",
470 cl->host_client_id,
471 cl->me_client_id);
472 rets = mei_disconnect_host_client(dev, cl);
473 }
474 mei_cl_flush_queues(cl);
475 dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n",
476 cl->host_client_id,
477 cl->me_client_id);
478
479 if (dev->open_handle_count > 0) {
480 clear_bit(cl->host_client_id,
481 dev->host_clients_map);
482 dev->open_handle_count--;
483 }
484 mei_remove_client_from_file_list(dev, cl->host_client_id);
485
486 /* free read cb */
487 cb = NULL;
488 if (cl->read_cb) {
489 cb = find_read_list_entry(dev, cl);
490 /* Remove entry from read list */
491 if (cb)
492 list_del(&cb->cb_list);
493
494 cb = cl->read_cb;
495 cl->read_cb = NULL;
496 }
497
498 file->private_data = NULL;
499
500 if (cb) {
501 mei_free_cb_private(cb);
502 cb = NULL;
503 }
504
505 kfree(cl);
506 } else {
507 if (dev->open_handle_count > 0)
508 dev->open_handle_count--;
509
510 if (dev->iamthif_file_object == file &&
511 dev->iamthif_state != MEI_IAMTHIF_IDLE) {
512
513 dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n",
514 dev->iamthif_state);
515 dev->iamthif_canceled = true;
516 if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
517 dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n");
518 mei_run_next_iamthif_cmd(dev);
519 }
520 }
521
522 if (mei_clear_lists(dev, file))
523 dev->iamthif_state = MEI_IAMTHIF_IDLE;
524
525 }
526 mutex_unlock(&dev->device_lock);
527 return rets;
528}
529
530
531/**
532 * mei_read - the read function.
533 *
534 * @file: pointer to file structure
535 * @ubuf: pointer to user buffer
536 * @length: buffer length
537 * @offset: data offset in buffer
538 *
539 * returns >=0 data length on success , <0 on error
540 */
541static ssize_t mei_read(struct file *file, char __user *ubuf,
542 size_t length, loff_t *offset)
543{
544 struct mei_cl *cl = file->private_data;
545 struct mei_cl_cb *cb_pos = NULL;
546 struct mei_cl_cb *cb = NULL;
547 struct mei_device *dev;
548 int i;
549 int rets;
550 int err;
551
552
553 if (WARN_ON(!cl || !cl->dev))
554 return -ENODEV;
555
556 dev = cl->dev;
557
558 mutex_lock(&dev->device_lock);
559 if (dev->mei_state != MEI_ENABLED) {
560 rets = -ENODEV;
561 goto out;
562 }
563
564 if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
565 /* Do not allow to read watchdog client */
566 i = mei_find_me_client_index(dev, mei_wd_guid);
567 if (i >= 0) {
568 struct mei_me_client *me_client = &dev->me_clients[i];
569
570 if (cl->me_client_id == me_client->client_id) {
571 rets = -EBADF;
572 goto out;
573 }
574 }
575 } else {
576 cl->sm_state &= ~MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
577 }
578
579 if (cl == &dev->iamthif_cl) {
580 rets = amthi_read(dev, file, ubuf, length, offset);
581 goto out;
582 }
583
584 if (cl->read_cb && cl->read_cb->information > *offset) {
585 cb = cl->read_cb;
586 goto copy_buffer;
587 } else if (cl->read_cb && cl->read_cb->information > 0 &&
588 cl->read_cb->information <= *offset) {
589 cb = cl->read_cb;
590 rets = 0;
591 goto free;
592 } else if ((!cl->read_cb || !cl->read_cb->information) &&
593 *offset > 0) {
594 /*Offset needs to be cleaned for contingous reads*/
595 *offset = 0;
596 rets = 0;
597 goto out;
598 }
599
600 err = mei_start_read(dev, cl);
601 if (err && err != -EBUSY) {
602 dev_dbg(&dev->pdev->dev,
603 "mei start read failure with status = %d\n", err);
604 rets = err;
605 goto out;
606 }
607
608 if (MEI_READ_COMPLETE != cl->reading_state &&
609 !waitqueue_active(&cl->rx_wait)) {
610 if (file->f_flags & O_NONBLOCK) {
611 rets = -EAGAIN;
612 goto out;
613 }
614
615 mutex_unlock(&dev->device_lock);
616
617 if (wait_event_interruptible(cl->rx_wait,
618 (MEI_READ_COMPLETE == cl->reading_state ||
619 MEI_FILE_INITIALIZING == cl->state ||
620 MEI_FILE_DISCONNECTED == cl->state ||
621 MEI_FILE_DISCONNECTING == cl->state))) {
622 if (signal_pending(current))
623 return -EINTR;
624 return -ERESTARTSYS;
625 }
626
627 mutex_lock(&dev->device_lock);
628 if (MEI_FILE_INITIALIZING == cl->state ||
629 MEI_FILE_DISCONNECTED == cl->state ||
630 MEI_FILE_DISCONNECTING == cl->state) {
631 rets = -EBUSY;
632 goto out;
633 }
634 }
635
636 cb = cl->read_cb;
637
638 if (!cb) {
639 rets = -ENODEV;
640 goto out;
641 }
642 if (cl->reading_state != MEI_READ_COMPLETE) {
643 rets = 0;
644 goto out;
645 }
646 /* now copy the data to user space */
647copy_buffer:
648 dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n",
649 cb->response_buffer.size);
650 dev_dbg(&dev->pdev->dev, "cb->information - %lu\n",
651 cb->information);
652 if (length == 0 || ubuf == NULL || *offset > cb->information) {
653 rets = -EMSGSIZE;
654 goto free;
655 }
656
657 /* length is being turncated to PAGE_SIZE, however, */
658 /* information size may be longer */
659 length = min_t(size_t, length, (cb->information - *offset));
660
661 if (copy_to_user(ubuf,
662 cb->response_buffer.data + *offset,
663 length)) {
664 rets = -EFAULT;
665 goto free;
666 }
667
668 rets = length;
669 *offset += length;
670 if ((unsigned long)*offset < cb->information)
671 goto out;
672
673free:
674 cb_pos = find_read_list_entry(dev, cl);
675 /* Remove entry from read list */
676 if (cb_pos)
677 list_del(&cb_pos->cb_list);
678 mei_free_cb_private(cb);
679 cl->reading_state = MEI_IDLE;
680 cl->read_cb = NULL;
681 cl->read_pending = 0;
682out:
683 dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets);
684 mutex_unlock(&dev->device_lock);
685 return rets;
686}
687
688/**
689 * mei_write - the write function.
690 *
691 * @file: pointer to file structure
692 * @ubuf: pointer to user buffer
693 * @length: buffer length
694 * @offset: data offset in buffer
695 *
696 * returns >=0 data length on success , <0 on error
697 */
698static ssize_t mei_write(struct file *file, const char __user *ubuf,
699 size_t length, loff_t *offset)
700{
701 struct mei_cl *cl = file->private_data;
702 struct mei_cl_cb *write_cb = NULL;
703 struct mei_msg_hdr mei_hdr;
704 struct mei_device *dev;
705 unsigned long timeout = 0;
706 int rets;
707 int i;
708
709 if (WARN_ON(!cl || !cl->dev))
710 return -ENODEV;
711
712 dev = cl->dev;
713
714 mutex_lock(&dev->device_lock);
715
716 if (dev->mei_state != MEI_ENABLED) {
717 mutex_unlock(&dev->device_lock);
718 return -ENODEV;
719 }
720
721 if (cl == &dev->iamthif_cl) {
722 write_cb = find_amthi_read_list_entry(dev, file);
723
724 if (write_cb) {
725 timeout = write_cb->read_time +
726 msecs_to_jiffies(IAMTHIF_READ_TIMER);
727
728 if (time_after(jiffies, timeout) ||
729 cl->reading_state == MEI_READ_COMPLETE) {
730 *offset = 0;
731 list_del(&write_cb->cb_list);
732 mei_free_cb_private(write_cb);
733 write_cb = NULL;
734 }
735 }
736 }
737
738 /* free entry used in read */
739 if (cl->reading_state == MEI_READ_COMPLETE) {
740 *offset = 0;
741 write_cb = find_read_list_entry(dev, cl);
742 if (write_cb) {
743 list_del(&write_cb->cb_list);
744 mei_free_cb_private(write_cb);
745 write_cb = NULL;
746 cl->reading_state = MEI_IDLE;
747 cl->read_cb = NULL;
748 cl->read_pending = 0;
749 }
750 } else if (cl->reading_state == MEI_IDLE &&
751 !cl->read_pending)
752 *offset = 0;
753
754
755 write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL);
756 if (!write_cb) {
757 mutex_unlock(&dev->device_lock);
758 return -ENOMEM;
759 }
760
761 write_cb->file_object = file;
762 write_cb->file_private = cl;
763 write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL);
764 rets = -ENOMEM;
765 if (!write_cb->request_buffer.data)
766 goto unlock_dev;
767
768 dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length);
769
770 rets = -EFAULT;
771 if (copy_from_user(write_cb->request_buffer.data, ubuf, length))
772 goto unlock_dev;
773
774 cl->sm_state = 0;
775 if (length == 4 &&
776 ((memcmp(mei_wd_state_independence_msg[0],
777 write_cb->request_buffer.data, 4) == 0) ||
778 (memcmp(mei_wd_state_independence_msg[1],
779 write_cb->request_buffer.data, 4) == 0) ||
780 (memcmp(mei_wd_state_independence_msg[2],
781 write_cb->request_buffer.data, 4) == 0)))
782 cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT;
783
784 INIT_LIST_HEAD(&write_cb->cb_list);
785 if (cl == &dev->iamthif_cl) {
786 write_cb->response_buffer.data =
787 kmalloc(dev->iamthif_mtu, GFP_KERNEL);
788 if (!write_cb->response_buffer.data) {
789 rets = -ENOMEM;
790 goto unlock_dev;
791 }
792 if (dev->mei_state != MEI_ENABLED) {
793 rets = -ENODEV;
794 goto unlock_dev;
795 }
796 for (i = 0; i < dev->me_clients_num; i++) {
797 if (dev->me_clients[i].client_id ==
798 dev->iamthif_cl.me_client_id)
799 break;
800 }
801
802 if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
803 rets = -ENODEV;
804 goto unlock_dev;
805 }
806 if (i == dev->me_clients_num ||
807 (dev->me_clients[i].client_id !=
808 dev->iamthif_cl.me_client_id)) {
809 rets = -ENODEV;
810 goto unlock_dev;
811 } else if (length > dev->me_clients[i].props.max_msg_length ||
812 length <= 0) {
813 rets = -EMSGSIZE;
814 goto unlock_dev;
815 }
816
817 write_cb->response_buffer.size = dev->iamthif_mtu;
818 write_cb->major_file_operations = MEI_IOCTL;
819 write_cb->information = 0;
820 write_cb->request_buffer.size = length;
821 if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
822 rets = -ENODEV;
823 goto unlock_dev;
824 }
825
826 if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) ||
827 dev->iamthif_state != MEI_IAMTHIF_IDLE) {
828 dev_dbg(&dev->pdev->dev, "amthi_state = %d\n",
829 (int) dev->iamthif_state);
830 dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n");
831 list_add_tail(&write_cb->cb_list,
832 &dev->amthi_cmd_list.mei_cb.cb_list);
833 rets = length;
834 } else {
835 dev_dbg(&dev->pdev->dev, "call amthi write\n");
836 rets = amthi_write(dev, write_cb);
837
838 if (rets) {
839 dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n",
840 rets);
841 goto unlock_dev;
842 }
843 rets = length;
844 }
845 mutex_unlock(&dev->device_lock);
846 return rets;
847 }
848
849 write_cb->major_file_operations = MEI_WRITE;
850 /* make sure information is zero before we start */
851
852 write_cb->information = 0;
853 write_cb->request_buffer.size = length;
854
855 dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
856 cl->host_client_id, cl->me_client_id);
857 if (cl->state != MEI_FILE_CONNECTED) {
858 rets = -ENODEV;
859 dev_dbg(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d",
860 cl->host_client_id,
861 cl->me_client_id);
862 goto unlock_dev;
863 }
864 for (i = 0; i < dev->me_clients_num; i++) {
865 if (dev->me_clients[i].client_id ==
866 cl->me_client_id)
867 break;
868 }
869 if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
870 rets = -ENODEV;
871 goto unlock_dev;
872 }
873 if (i == dev->me_clients_num) {
874 rets = -ENODEV;
875 goto unlock_dev;
876 }
877 if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
878 rets = -EINVAL;
879 goto unlock_dev;
880 }
881 write_cb->file_private = cl;
882
883 rets = mei_flow_ctrl_creds(dev, cl);
884 if (rets < 0)
885 goto unlock_dev;
886
887 if (rets && dev->mei_host_buffer_is_empty) {
888 rets = 0;
889 dev->mei_host_buffer_is_empty = false;
890 if (length > ((((dev->host_hw_state & H_CBD) >> 24) *
891 sizeof(u32)) - sizeof(struct mei_msg_hdr))) {
892
893 mei_hdr.length =
894 (((dev->host_hw_state & H_CBD) >> 24) *
895 sizeof(u32)) -
896 sizeof(struct mei_msg_hdr);
897 mei_hdr.msg_complete = 0;
898 } else {
899 mei_hdr.length = length;
900 mei_hdr.msg_complete = 1;
901 }
902 mei_hdr.host_addr = cl->host_client_id;
903 mei_hdr.me_addr = cl->me_client_id;
904 mei_hdr.reserved = 0;
905 dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n",
906 *((u32 *) &mei_hdr));
907 if (!mei_write_message(dev, &mei_hdr,
908 (unsigned char *) (write_cb->request_buffer.data),
909 mei_hdr.length)) {
910 rets = -ENODEV;
911 goto unlock_dev;
912 }
913 cl->writing_state = MEI_WRITING;
914 write_cb->information = mei_hdr.length;
915 if (mei_hdr.msg_complete) {
916 if (mei_flow_ctrl_reduce(dev, cl)) {
917 rets = -ENODEV;
918 goto unlock_dev;
919 }
920 list_add_tail(&write_cb->cb_list,
921 &dev->write_waiting_list.mei_cb.cb_list);
922 } else {
923 list_add_tail(&write_cb->cb_list,
924 &dev->write_list.mei_cb.cb_list);
925 }
926
927 } else {
928
929 write_cb->information = 0;
930 cl->writing_state = MEI_WRITING;
931 list_add_tail(&write_cb->cb_list,
932 &dev->write_list.mei_cb.cb_list);
933 }
934 mutex_unlock(&dev->device_lock);
935 return length;
936
937unlock_dev:
938 mutex_unlock(&dev->device_lock);
939 mei_free_cb_private(write_cb);
940 return rets;
941}
942
943
944/**
945 * mei_ioctl - the IOCTL function
946 *
947 * @file: pointer to file structure
948 * @cmd: ioctl command
949 * @data: pointer to mei message structure
950 *
951 * returns 0 on success , <0 on error
952 */
953static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
954{
955 struct mei_device *dev;
956 struct mei_cl *cl = file->private_data;
957 struct mei_connect_client_data *connect_data = NULL;
958 int rets;
959
960 if (cmd != IOCTL_MEI_CONNECT_CLIENT)
961 return -EINVAL;
962
963 if (WARN_ON(!cl || !cl->dev))
964 return -ENODEV;
965
966 dev = cl->dev;
967
968 dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
969
970 mutex_lock(&dev->device_lock);
971 if (dev->mei_state != MEI_ENABLED) {
972 rets = -ENODEV;
973 goto out;
974 }
975
976 dev_dbg(&dev->pdev->dev, ": IOCTL_MEI_CONNECT_CLIENT.\n");
977
978 connect_data = kzalloc(sizeof(struct mei_connect_client_data),
979 GFP_KERNEL);
980 if (!connect_data) {
981 rets = -ENOMEM;
982 goto out;
983 }
984 dev_dbg(&dev->pdev->dev, "copy connect data from user\n");
985 if (copy_from_user(connect_data, (char __user *)data,
986 sizeof(struct mei_connect_client_data))) {
987 dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n");
988 rets = -EFAULT;
989 goto out;
990 }
991 rets = mei_ioctl_connect_client(file, connect_data);
992
993 /* if all is ok, copying the data back to user. */
994 if (rets)
995 goto out;
996
997 dev_dbg(&dev->pdev->dev, "copy connect data to user\n");
998 if (copy_to_user((char __user *)data, connect_data,
999 sizeof(struct mei_connect_client_data))) {
1000 dev_dbg(&dev->pdev->dev, "failed to copy data to userland\n");
1001 rets = -EFAULT;
1002 goto out;
1003 }
1004
1005out:
1006 kfree(connect_data);
1007 mutex_unlock(&dev->device_lock);
1008 return rets;
1009}
1010
1011/**
1012 * mei_compat_ioctl - the compat IOCTL function
1013 *
1014 * @file: pointer to file structure
1015 * @cmd: ioctl command
1016 * @data: pointer to mei message structure
1017 *
1018 * returns 0 on success , <0 on error
1019 */
1020#ifdef CONFIG_COMPAT
1021static long mei_compat_ioctl(struct file *file,
1022 unsigned int cmd, unsigned long data)
1023{
1024 return mei_ioctl(file, cmd, (unsigned long)compat_ptr(data));
1025}
1026#endif
1027
1028
1029/**
1030 * mei_poll - the poll function
1031 *
1032 * @file: pointer to file structure
1033 * @wait: pointer to poll_table structure
1034 *
1035 * returns poll mask
1036 */
1037static unsigned int mei_poll(struct file *file, poll_table *wait)
1038{
1039 struct mei_cl *cl = file->private_data;
1040 struct mei_device *dev;
1041 unsigned int mask = 0;
1042
1043 if (WARN_ON(!cl || !cl->dev))
1044 return mask;
1045
1046 dev = cl->dev;
1047
1048 mutex_lock(&dev->device_lock);
1049
1050 if (dev->mei_state != MEI_ENABLED)
1051 goto out;
1052
1053
1054 if (cl == &dev->iamthif_cl) {
1055 mutex_unlock(&dev->device_lock);
1056 poll_wait(file, &dev->iamthif_cl.wait, wait);
1057 mutex_lock(&dev->device_lock);
1058 if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
1059 dev->iamthif_file_object == file) {
1060 mask |= (POLLIN | POLLRDNORM);
1061 dev_dbg(&dev->pdev->dev, "run next amthi cb\n");
1062 mei_run_next_iamthif_cmd(dev);
1063 }
1064 goto out;
1065 }
1066
1067 mutex_unlock(&dev->device_lock);
1068 poll_wait(file, &cl->tx_wait, wait);
1069 mutex_lock(&dev->device_lock);
1070 if (MEI_WRITE_COMPLETE == cl->writing_state)
1071 mask |= (POLLIN | POLLRDNORM);
1072
1073out:
1074 mutex_unlock(&dev->device_lock);
1075 return mask;
1076}
1077
1078#ifdef CONFIG_PM
1079static int mei_pci_suspend(struct device *device)
1080{
1081 struct pci_dev *pdev = to_pci_dev(device);
1082 struct mei_device *dev = pci_get_drvdata(pdev);
1083 int err;
1084
1085 if (!dev)
1086 return -ENODEV;
1087 mutex_lock(&dev->device_lock);
1088 /* Stop watchdog if exists */
1089 err = mei_wd_stop(dev, true);
1090 /* Set new mei state */
1091 if (dev->mei_state == MEI_ENABLED ||
1092 dev->mei_state == MEI_RECOVERING_FROM_RESET) {
1093 dev->mei_state = MEI_POWER_DOWN;
1094 mei_reset(dev, 0);
1095 }
1096 mutex_unlock(&dev->device_lock);
1097
1098 free_irq(pdev->irq, dev);
1099
1100
1101 return err;
1102}
1103
1104static int mei_pci_resume(struct device *device)
1105{
1106 struct pci_dev *pdev = to_pci_dev(device);
1107 struct mei_device *dev;
1108 int err;
1109
1110 dev = pci_get_drvdata(pdev);
1111 if (!dev)
1112 return -ENODEV;
1113
1114 /* request and enable interrupt */
1115 err = request_threaded_irq(pdev->irq,
1116 mei_interrupt_quick_handler,
1117 mei_interrupt_thread_handler,
1118 IRQF_SHARED, mei_driver_name, dev);
1119 if (err) {
1120 printk(KERN_ERR "mei: Request_irq failure. irq = %d\n",
1121 pdev->irq);
1122 return err;
1123 }
1124
1125 mutex_lock(&dev->device_lock);
1126 dev->mei_state = MEI_POWER_UP;
1127 mei_reset(dev, 1);
1128 mutex_unlock(&dev->device_lock);
1129
1130 /* Start watchdog if stopped in suspend */
1131 if (dev->wd_timeout) {
1132 mei_wd_start_setup(dev);
1133 dev->wd_due_counter = 1;
1134 schedule_delayed_work(&dev->wd_work, HZ);
1135 }
1136 return err;
1137}
1138static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
1139#define MEI_PM_OPS (&mei_pm_ops)
1140#else
1141#define MEI_PM_OPS NULL
1142#endif /* CONFIG_PM */
1143/*
1144 * PCI driver structure
1145 */
1146static struct pci_driver mei_driver = {
1147 .name = mei_driver_name,
1148 .id_table = mei_pci_tbl,
1149 .probe = mei_probe,
1150 .remove = __devexit_p(mei_remove),
1151 .shutdown = __devexit_p(mei_remove),
1152 .driver.pm = MEI_PM_OPS,
1153};
1154
1155/*
1156 * file operations structure will be used for mei char device.
1157 */
1158static const struct file_operations mei_fops = {
1159 .owner = THIS_MODULE,
1160 .read = mei_read,
1161 .unlocked_ioctl = mei_ioctl,
1162#ifdef CONFIG_COMPAT
1163 .compat_ioctl = mei_compat_ioctl,
1164#endif
1165 .open = mei_open,
1166 .release = mei_release,
1167 .write = mei_write,
1168 .poll = mei_poll,
1169};
1170
1171/**
1172 * mei_registration_cdev - sets up the cdev structure for mei device.
1173 *
1174 * @dev: char device struct
1175 * @hminor: minor number for registration char device
1176 * @fops: file operations structure
1177 *
1178 * returns 0 on success, <0 on failure.
1179 */
1180static int mei_registration_cdev(struct cdev *dev, int hminor,
1181 const struct file_operations *fops)
1182{
1183 int ret, devno = MKDEV(mei_major, hminor);
1184
1185 cdev_init(dev, fops);
1186 dev->owner = THIS_MODULE;
1187 ret = cdev_add(dev, devno, 1);
1188 /* Fail gracefully if need be */
1189 if (ret)
1190 printk(KERN_ERR "mei: Error %d registering mei device %d\n",
1191 ret, hminor);
1192 return ret;
1193}
1194
1195/**
1196 * mei_register_cdev - registers mei char device
1197 *
1198 * returns 0 on success, <0 on failure.
1199 */
1200static int mei_register_cdev(void)
1201{
1202 int ret;
1203 dev_t dev;
1204
1205 /* registration of char devices */
1206 ret = alloc_chrdev_region(&dev, MEI_MINORS_BASE, MEI_MINORS_COUNT,
1207 MEI_DRIVER_NAME);
1208 if (ret) {
1209 printk(KERN_ERR "mei: Error allocating char device region.\n");
1210 return ret;
1211 }
1212
1213 mei_major = MAJOR(dev);
1214
1215 ret = mei_registration_cdev(&mei_cdev, MEI_MINOR_NUMBER,
1216 &mei_fops);
1217 if (ret)
1218 unregister_chrdev_region(MKDEV(mei_major, MEI_MINORS_BASE),
1219 MEI_MINORS_COUNT);
1220
1221 return ret;
1222}
1223
1224/**
1225 * mei_unregister_cdev - unregisters mei char device
1226 */
1227static void mei_unregister_cdev(void)
1228{
1229 cdev_del(&mei_cdev);
1230 unregister_chrdev_region(MKDEV(mei_major, MEI_MINORS_BASE),
1231 MEI_MINORS_COUNT);
1232}
1233
1234/**
1235 * mei_sysfs_device_create - adds device entry to sysfs
1236 *
1237 * returns 0 on success, <0 on failure.
1238 */
1239static int mei_sysfs_device_create(void)
1240{
1241 struct class *class;
1242 void *tmphdev;
1243 int err;
1244
1245 class = class_create(THIS_MODULE, MEI_DRIVER_NAME);
1246 if (IS_ERR(class)) {
1247 err = PTR_ERR(class);
1248 printk(KERN_ERR "mei: Error creating mei class.\n");
1249 goto err_out;
1250 }
1251
1252 tmphdev = device_create(class, NULL, mei_cdev.dev, NULL,
1253 MEI_DEV_NAME);
1254 if (IS_ERR(tmphdev)) {
1255 err = PTR_ERR(tmphdev);
1256 goto err_destroy;
1257 }
1258
1259 mei_class = class;
1260 return 0;
1261
1262err_destroy:
1263 class_destroy(class);
1264err_out:
1265 return err;
1266}
1267
1268/**
1269 * mei_sysfs_device_remove - unregisters the device entry on sysfs
1270 */
1271static void mei_sysfs_device_remove(void)
1272{
1273 if (IS_ERR_OR_NULL(mei_class))
1274 return;
1275
1276 device_destroy(mei_class, mei_cdev.dev);
1277 class_destroy(mei_class);
1278}
1279
1280/**
1281 * mei_init_module - Driver Registration Routine
1282 *
1283 * mei_init_module is the first routine called when the driver is
1284 * loaded. All it does is to register with the PCI subsystem.
1285 *
1286 * returns 0 on success, <0 on failure.
1287 */
1288static int __init mei_init_module(void)
1289{
1290 int ret;
1291
1292 pr_debug("mei: %s - version %s\n",
1293 mei_driver_string, mei_driver_version);
1294 /* init pci module */
1295 ret = pci_register_driver(&mei_driver);
1296 if (ret < 0) {
1297 printk(KERN_ERR "mei: Error registering driver.\n");
1298 goto end;
1299 }
1300
1301 ret = mei_register_cdev();
1302 if (ret)
1303 goto unregister_pci;
1304
1305 ret = mei_sysfs_device_create();
1306 if (ret)
1307 goto unregister_cdev;
1308
1309 return ret;
1310
1311unregister_cdev:
1312 mei_unregister_cdev();
1313unregister_pci:
1314 pci_unregister_driver(&mei_driver);
1315end:
1316 return ret;
1317}
1318
1319module_init(mei_init_module);
1320
1321/**
1322 * mei_exit_module - Driver Exit Cleanup Routine
1323 *
1324 * mei_exit_module is called just before the driver is removed
1325 * from memory.
1326 */
1327static void __exit mei_exit_module(void)
1328{
1329 mei_sysfs_device_remove();
1330 mei_unregister_cdev();
1331 pci_unregister_driver(&mei_driver);
1332
1333 pr_debug("mei: Driver unloaded successfully.\n");
1334}
1335
1336module_exit(mei_exit_module);
1337
1338
1339MODULE_AUTHOR("Intel Corporation");
1340MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
1341MODULE_LICENSE("GPL v2");
1342MODULE_VERSION(MEI_DRIVER_VERSION);
diff --git a/drivers/staging/mei/mei.h b/drivers/staging/mei/mei.h
new file mode 100644
index 00000000000..6da7c4f33f9
--- /dev/null
+++ b/drivers/staging/mei/mei.h
@@ -0,0 +1,105 @@
1/*
2
3 Intel Management Engine Interface (Intel MEI) Linux driver
4 Intel MEI Interface Header
5
6 This file is provided under a dual BSD/GPLv2 license. When using or
7 redistributing this file, you may do so under either license.
8
9 GPL LICENSE SUMMARY
10
11 Copyright(c) 2003-2011 Intel Corporation. All rights reserved.
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of version 2 of the GNU General Public License as
15 published by the Free Software Foundation.
16
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
21
22 Contact Information:
23 Intel Corporation.
24 linux-mei@linux.intel.com
25 http://www.intel.com
26
27
28 BSD LICENSE
29
30 Copyright(c) 2003-2011 Intel Corporation. All rights reserved.
31 All rights reserved.
32
33 Redistribution and use in source and binary forms, with or without
34 modification, are permitted provided that the following conditions
35 are met:
36
37 * Redistributions of source code must retain the above copyright
38 notice, this list of conditions and the following disclaimer.
39 * Redistributions in binary form must reproduce the above copyright
40 notice, this list of conditions and the following disclaimer in
41 the documentation and/or other materials provided with the
42 distribution.
43 * Neither the name of Intel Corporation nor the names of its
44 contributors may be used to endorse or promote products derived
45 from this software without specific prior written permission.
46
47 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
48 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
49 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
50 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
51 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
57 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58
59*/
60
61
62#ifndef _LINUX_MEI_H
63#define _LINUX_MEI_H
64
65#include <linux/uuid.h>
66
67/*
68 * This IOCTL is used to associate the current file descriptor with a
69 * FW Client (given by UUID). This opens a communication channel
70 * between a host client and a FW client. From this point every read and write
71 * will communicate with the associated FW client.
72 * Only in close() (file_operation release()) the communication between
73 * the clients is disconnected
74 *
75 * The IOCTL argument is a struct with a union the contains
76 * the input parameter and the output parameter for this IOCTL.
77 *
78 * The input parameter is UUID of the FW Client.
79 * The output parameter is the properties of the FW client
80 * (FW protocol version and max message size).
81 *
82 */
83#define IOCTL_MEI_CONNECT_CLIENT \
84 _IOWR('H' , 0x01, struct mei_connect_client_data)
85
86/*
87 * Intel MEI client information struct
88 */
89struct mei_client {
90 __u32 max_msg_length;
91 __u8 protocol_version;
92 __u8 reserved[3];
93};
94
95/*
96 * IOCTL Connect Client Data structure
97 */
98struct mei_connect_client_data {
99 union {
100 uuid_le in_client_uuid;
101 struct mei_client out_client_properties;
102 };
103};
104
105#endif /* _LINUX_MEI_H */
diff --git a/drivers/staging/mei/mei.txt b/drivers/staging/mei/mei.txt
new file mode 100644
index 00000000000..17302ad2531
--- /dev/null
+++ b/drivers/staging/mei/mei.txt
@@ -0,0 +1,189 @@
1Intel MEI
2=======================
3
4Introduction
5=======================
6
7The Intel Management Engine (Intel ME) is an isolated and
8protected computing resource (Coprocessor) residing inside
9Intel chipsets. The Intel ME provides support for computer/IT
10management features.
11The Feature set depends on the Intel chipset SKU.
12
13The Intel Management Engine Interface (Intel MEI, previously known
14as HECI) is the interface between the Host and Intel ME.
15This interface is exposed to the host as a PCI device.
16The Intel MEI Driver is in charge of the communication channel
17between a host application and the ME feature.
18
19Each Intel ME feature (Intel ME Client) is addressed by
20GUID/UUID and each feature defines its own protocol.
21The protocol is message-based with a header and payload up to
22512 bytes.
23
24[place holder to URL to protocol definitions]
25
26Prominent usage of the Interface is to communicate with
27Intel Active Management Technology (Intel AMT)
28implemented in firmware running on the Intel ME.
29
30Intel AMT provides the ability to manage a host remotely out-of-band (OOB)
31even when the host processor has crashed or is in a sleep state.
32
33Some examples of Intel AMT usage are:
34 - Monitoring hardware state and platform components
35 - Remote power off/on (useful for green computing or overnight IT maintenance)
36 - OS updates
37 - Storage of useful platform information such as software assets
38 - built-in hardware KVM
39 - selective network isolation of Ethernet and IP protocol flows based on
40 policies set by a remote management console
41 - IDE device redirection from remote management console
42
43Intel AMT (OOB) communication is based on SOAP (deprecated
44starting with Release 6.0) over HTTP/HTTPS or WS-Management protocol
45over HTTP and HTTPS that are received from a remote
46management console application.
47
48For more information about Intel AMT:
49http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/aboutintelamt.htm
50
51
52MEI Driver
53=======================
54
55The driver exposes a character device called /dev/mei.
56
57An application maintains communication with an ME feature while
58/dev/mei is open. The binding to a specific features is performed
59by calling MEI_CONNECT_CLIENT_IOCTL, which passes the desired UUID.
60The number of instances of an ME feature that can be opened
61at the same time depends on the ME feature, but most of the
62features allow only a single instance.
63
64
65The Intel AMT Host Interface (AMTHI) feature requires multiple
66simultaneous user applications, therefore the MEI driver handles
67this internally by maintaining request queues for the applications.
68
69The driver is oblivious to data that are passed between
70
71Because some of the ME features can change the system
72configuration, the driver by default allows only privileged
73user to access it.
74
75A Code snippet for application communicating with AMTHI client:
76 struct mei_connect_client_data data;
77 fd = open(MEI_DEVICE);
78
79 data.d.in_client_uuid = AMTHI_UUID;
80
81 ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &data);
82
83 printf(“Ver=%d, MaxLen=%ld\n”,
84 data.d.in_client_uuid.protocol_version,
85 data.d.in_client_uuid.max_msg_length);
86
87 [...]
88
89 write(fd, amthi_req_data, amthi_req_data_len);
90
91 [...]
92
93 read(fd, &amthi_res_data, amthi_res_data_len);
94
95 [...]
96 close(fd);
97
98ME Applications:
99==============
100
1011) Intel Local Management Service (Intel LMS)
102 Applications running locally on the platform communicate with
103 Intel AMT Release 2.0 and later releases in the same way
104 that network applications do via SOAP over HTTP (deprecated
105 starting with Release 6.0) or with WS-Management over SOAP over
106 HTTP. which means that some Intel AMT feature can be access
107 from a local application using same Network interface as for
108 remote application.
109
110 When a local application sends a message addressed to the local
111 Intel AMT host name, the Local Manageability Service (LMS),
112 which listens for traffic directed to the host name, intercepts
113 the message and routes it to the Intel Management Engine Interface.
114 For more information:
115 http://software.intel.com/sites/manageability/AMT_Implementation_and_
116 Reference_Guide/WordDocuments/localaccess1.htm
117
118 The LMS opens a connection using the MEI driver to the LMS
119 FW feature using a defined UUID and then communicates with the
120 feature using a protocol
121 called Intel(R) AMT Port Forwarding Protocol (APF protocol).
122 The protocol is used to maintain multiple sessions with
123 Intel AMT from a single application.
124 See the protocol specification in
125 the Intel(R) AMT Implementation and Reference Guide
126 http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/HTMLDocuments/MPSDocuments/Intel%20AMT%20Port%20Forwarding%20Protocol%20Reference%20Manual.pdf
127
128 2) Intel AMT Remote configuration using a Local Agent:
129 A Local Agent enables IT personnel to configure Intel AMT out-of-the-box
130 without requiring installing additional data to enable setup.
131 The remote configuration process may involve an ISV-developed remote
132 configuration agent that runs on the host.
133 For more information:
134 http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/remoteconfigurationwithalocalagent.htm
135
136 How the Local Agent Works (including Command structs):
137 http://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/WordDocuments/howthelocalagentsampleworks.htm
138
139Intel AMT OS Health Watchdog:
140=============================
141The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog.
142Whenever the OS hangs or crashes, Intel AMT will send an event
143to whoever subscribed to this event. This mechanism means that
144IT knows when a platform crashes even when there is a hard failure
145on the host.
146The AMT Watchdog is composed of two parts:
147 1) FW Feature - that receives the heartbeats
148 and sends an event when the heartbeats stop.
149 2) MEI driver – connects to the watchdog (WD) feature,
150 configures the watchdog and sends the heartbeats.
151
152The MEI driver configures the Watchdog to expire by default
153every 120sec unless set by the user using module parameters.
154The Driver then sends heartbeats every 2sec.
155
156If WD feature does not exist (i.e. the connection failed),
157the MEI driver will disable the sending of heartbeats.
158
159Module Parameters
160=================
161watchdog_timeout - the user can use this module parameter
162to change the watchdog timeout setting.
163
164This value sets the Intel AMT watchdog timeout interval in seconds;
165the default value is 120sec.
166in order to disable the watchdog activites set the value to 0.
167Normal values should be between 120 and 65535
168
169Supported Chipsets:
170==================
1717 Series Chipset Family
1726 Series Chipset Family
1735 Series Chipset Family
1744 Series Chipset Family
175Mobile 4 Series Chipset Family
176ICH9
17782946GZ/GL
17882G35 Express
17982Q963/Q965
18082P965/G965
181Mobile PM965/GM965
182Mobile GME965/GLE960
18382Q35 Express
18482G33/G31/P35/P31 Express
18582Q33 Express
18682X38/X48 Express
187
188---
189linux-mei@linux.intel.com
diff --git a/drivers/staging/mei/mei_dev.h b/drivers/staging/mei/mei_dev.h
new file mode 100644
index 00000000000..d7bc10c612b
--- /dev/null
+++ b/drivers/staging/mei/mei_dev.h
@@ -0,0 +1,425 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17#ifndef _MEI_DEV_H_
18#define _MEI_DEV_H_
19
20#include <linux/types.h>
21#include "mei.h"
22#include "hw.h"
23
24/*
25 * MEI Char Driver Minors
26 */
27#define MEI_MINORS_BASE 1
28#define MEI_MINORS_COUNT 1
29#define MEI_MINOR_NUMBER 1
30
31/*
32 * watch dog definition
33 */
34#define MEI_WATCHDOG_DATA_SIZE 16
35#define MEI_START_WD_DATA_SIZE 20
36#define MEI_WD_PARAMS_SIZE 4
37#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
38
39/*
40 * AMTHI Client UUID
41 */
42extern const uuid_le mei_amthi_guid;
43
44/*
45 * Watchdog Client UUID
46 */
47extern const uuid_le mei_wd_guid;
48
49/*
50 * Watchdog independence state message
51 */
52extern const u8 mei_wd_state_independence_msg[3][4];
53
54/*
55 * Number of File descriptors/handles
56 * that can be opened to the driver.
57 *
58 * Limit to 253: 255 Total Clients
59 * minus internal client for AMTHI
60 * minus internal client for Watchdog
61 */
62#define MEI_MAX_OPEN_HANDLE_COUNT 253
63
64/*
65 * Number of Maximum MEI Clients
66 */
67#define MEI_CLIENTS_MAX 255
68
69/* File state */
70enum file_state {
71 MEI_FILE_INITIALIZING = 0,
72 MEI_FILE_CONNECTING,
73 MEI_FILE_CONNECTED,
74 MEI_FILE_DISCONNECTING,
75 MEI_FILE_DISCONNECTED
76};
77
78/* MEI device states */
79enum mei_states {
80 MEI_INITIALIZING = 0,
81 MEI_INIT_CLIENTS,
82 MEI_ENABLED,
83 MEI_RESETING,
84 MEI_DISABLED,
85 MEI_RECOVERING_FROM_RESET,
86 MEI_POWER_DOWN,
87 MEI_POWER_UP
88};
89
90/* init clients states*/
91enum mei_init_clients_states {
92 MEI_START_MESSAGE = 0,
93 MEI_ENUM_CLIENTS_MESSAGE,
94 MEI_CLIENT_PROPERTIES_MESSAGE
95};
96
97enum iamthif_states {
98 MEI_IAMTHIF_IDLE,
99 MEI_IAMTHIF_WRITING,
100 MEI_IAMTHIF_FLOW_CONTROL,
101 MEI_IAMTHIF_READING,
102 MEI_IAMTHIF_READ_COMPLETE
103};
104
105enum mei_file_transaction_states {
106 MEI_IDLE,
107 MEI_WRITING,
108 MEI_WRITE_COMPLETE,
109 MEI_FLOW_CONTROL,
110 MEI_READING,
111 MEI_READ_COMPLETE
112};
113
114/* MEI CB */
115enum mei_cb_major_types {
116 MEI_READ = 0,
117 MEI_WRITE,
118 MEI_IOCTL,
119 MEI_OPEN,
120 MEI_CLOSE
121};
122
123/*
124 * Intel MEI message data struct
125 */
126struct mei_message_data {
127 u32 size;
128 char *data;
129} __packed;
130
131
132struct mei_cl_cb {
133 struct list_head cb_list;
134 enum mei_cb_major_types major_file_operations;
135 void *file_private;
136 struct mei_message_data request_buffer;
137 struct mei_message_data response_buffer;
138 unsigned long information;
139 unsigned long read_time;
140 struct file *file_object;
141};
142
143/* MEI client instance carried as file->pirvate_data*/
144struct mei_cl {
145 struct list_head link;
146 struct mei_device *dev;
147 enum file_state state;
148 wait_queue_head_t tx_wait;
149 wait_queue_head_t rx_wait;
150 wait_queue_head_t wait;
151 int read_pending;
152 int status;
153 /* ID of client connected */
154 u8 host_client_id;
155 u8 me_client_id;
156 u8 mei_flow_ctrl_creds;
157 u8 timer_count;
158 enum mei_file_transaction_states reading_state;
159 enum mei_file_transaction_states writing_state;
160 int sm_state;
161 struct mei_cl_cb *read_cb;
162};
163
164struct mei_io_list {
165 struct mei_cl_cb mei_cb;
166 int status;
167};
168
169/* MEI private device struct */
170struct mei_device {
171 struct pci_dev *pdev; /* pointer to pci device struct */
172 /*
173 * lists of queues
174 */
175 /* array of pointers to aio lists */
176 struct mei_io_list read_list; /* driver read queue */
177 struct mei_io_list write_list; /* driver write queue */
178 struct mei_io_list write_waiting_list; /* write waiting queue */
179 struct mei_io_list ctrl_wr_list; /* managed write IOCTL list */
180 struct mei_io_list ctrl_rd_list; /* managed read IOCTL list */
181 struct mei_io_list amthi_cmd_list; /* amthi list for cmd waiting */
182
183 /* driver managed amthi list for reading completed amthi cmd data */
184 struct mei_io_list amthi_read_complete_list;
185 /*
186 * list of files
187 */
188 struct list_head file_list;
189 long open_handle_count;
190 /*
191 * memory of device
192 */
193 unsigned int mem_base;
194 unsigned int mem_length;
195 void __iomem *mem_addr;
196 /*
197 * lock for the device
198 */
199 struct mutex device_lock; /* device lock */
200 struct delayed_work wd_work; /* watch dog deleye work */
201 bool recvd_msg;
202 /*
203 * hw states of host and fw(ME)
204 */
205 u32 host_hw_state;
206 u32 me_hw_state;
207 /*
208 * waiting queue for receive message from FW
209 */
210 wait_queue_head_t wait_recvd_msg;
211 wait_queue_head_t wait_stop_wd;
212
213 /*
214 * mei device states
215 */
216 enum mei_states mei_state;
217 enum mei_init_clients_states init_clients_state;
218 u16 init_clients_timer;
219 bool stop;
220 bool need_reset;
221
222 u32 extra_write_index;
223 u32 rd_msg_buf[128]; /* used for control messages */
224 u32 wr_msg_buf[128]; /* used for control messages */
225 u32 ext_msg_buf[8]; /* for control responses */
226 u32 rd_msg_hdr;
227
228 struct hbm_version version;
229
230 struct mei_me_client *me_clients; /* Note: memory has to be allocated */
231 DECLARE_BITMAP(me_clients_map, MEI_CLIENTS_MAX);
232 DECLARE_BITMAP(host_clients_map, MEI_CLIENTS_MAX);
233 u8 me_clients_num;
234 u8 me_client_presentation_num;
235 u8 me_client_index;
236 bool mei_host_buffer_is_empty;
237
238 struct mei_cl wd_cl;
239 bool wd_pending;
240 bool wd_stopped;
241 bool wd_bypass; /* if false, don't refresh watchdog ME client */
242 u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
243 u16 wd_due_counter;
244 unsigned char wd_data[MEI_START_WD_DATA_SIZE];
245
246
247
248 struct file *iamthif_file_object;
249 struct mei_cl iamthif_cl;
250 struct mei_cl_cb *iamthif_current_cb;
251 int iamthif_mtu;
252 unsigned long iamthif_timer;
253 u32 iamthif_stall_timer;
254 unsigned char *iamthif_msg_buf; /* Note: memory has to be allocated */
255 u32 iamthif_msg_buf_size;
256 u32 iamthif_msg_buf_index;
257 enum iamthif_states iamthif_state;
258 bool iamthif_flow_control_pending;
259 bool iamthif_ioctl;
260 bool iamthif_canceled;
261};
262
263
264/*
265 * mei init function prototypes
266 */
267struct mei_device *mei_device_init(struct pci_dev *pdev);
268void mei_reset(struct mei_device *dev, int interrupts);
269int mei_hw_init(struct mei_device *dev);
270int mei_task_initialize_clients(void *data);
271int mei_initialize_clients(struct mei_device *dev);
272int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl);
273void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id);
274void mei_host_init_iamthif(struct mei_device *dev);
275void mei_allocate_me_clients_storage(struct mei_device *dev);
276
277
278u8 mei_find_me_client_update_filext(struct mei_device *dev,
279 struct mei_cl *priv,
280 const uuid_le *cguid, u8 client_id);
281
282/*
283 * MEI IO List Functions
284 */
285void mei_io_list_init(struct mei_io_list *list);
286void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl);
287
288/*
289 * MEI ME Client Functions
290 */
291
292struct mei_cl *mei_cl_allocate(struct mei_device *dev);
293void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
294int mei_cl_flush_queues(struct mei_cl *cl);
295/**
296 * mei_cl_cmp_id - tells if file private data have same id
297 *
298 * @fe1: private data of 1. file object
299 * @fe2: private data of 2. file object
300 *
301 * returns true - if ids are the same and not NULL
302 */
303static inline bool mei_cl_cmp_id(const struct mei_cl *cl1,
304 const struct mei_cl *cl2)
305{
306 return cl1 && cl2 &&
307 (cl1->host_client_id == cl2->host_client_id) &&
308 (cl1->me_client_id == cl2->me_client_id);
309}
310
311
312
313/*
314 * MEI Host Client Functions
315 */
316void mei_host_start_message(struct mei_device *dev);
317void mei_host_enum_clients_message(struct mei_device *dev);
318void mei_host_client_properties(struct mei_device *dev);
319
320/*
321 * MEI interrupt functions prototype
322 */
323irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id);
324irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id);
325void mei_wd_timer(struct work_struct *work);
326
327/*
328 * MEI input output function prototype
329 */
330int mei_ioctl_connect_client(struct file *file,
331 struct mei_connect_client_data *data);
332
333int mei_start_read(struct mei_device *dev, struct mei_cl *cl);
334
335int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb);
336
337int amthi_read(struct mei_device *dev, struct file *file,
338 char __user *ubuf, size_t length, loff_t *offset);
339
340struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev,
341 struct file *file);
342
343void mei_run_next_iamthif_cmd(struct mei_device *dev);
344
345void mei_free_cb_private(struct mei_cl_cb *priv_cb);
346
347int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
348
349/*
350 * Register Access Function
351 */
352
353/**
354 * mei_reg_read - Reads 32bit data from the mei device
355 *
356 * @dev: the device structure
357 * @offset: offset from which to read the data
358 *
359 * returns the byte read.
360 */
361static inline u32 mei_reg_read(struct mei_device *dev, unsigned long offset)
362{
363 return ioread32(dev->mem_addr + offset);
364}
365
366/**
367 * mei_reg_write - Writes 32bit data to the mei device
368 *
369 * @dev: the device structure
370 * @offset: offset from which to write the data
371 * @value: the byte to write
372 */
373static inline void mei_reg_write(struct mei_device *dev,
374 unsigned long offset, u32 value)
375{
376 iowrite32(value, dev->mem_addr + offset);
377}
378
379/**
380 * mei_hcsr_read - Reads 32bit data from the host CSR
381 *
382 * @dev: the device structure
383 *
384 * returns the byte read.
385 */
386static inline u32 mei_hcsr_read(struct mei_device *dev)
387{
388 return mei_reg_read(dev, H_CSR);
389}
390
391/**
392 * mei_mecsr_read - Reads 32bit data from the ME CSR
393 *
394 * @dev: the device structure
395 *
396 * returns ME_CSR_HA register value (u32)
397 */
398static inline u32 mei_mecsr_read(struct mei_device *dev)
399{
400 return mei_reg_read(dev, ME_CSR_HA);
401}
402
403/**
404 * get_me_cb_rw - Reads 32bit data from the mei ME_CB_RW register
405 *
406 * @dev: the device structure
407 *
408 * returns ME_CB_RW register value (u32)
409 */
410static inline u32 mei_mecbrw_read(struct mei_device *dev)
411{
412 return mei_reg_read(dev, ME_CB_RW);
413}
414
415
416/*
417 * mei interface function prototypes
418 */
419void mei_hcsr_set(struct mei_device *dev);
420void mei_csr_clear_his(struct mei_device *dev);
421
422void mei_enable_interrupts(struct mei_device *dev);
423void mei_disable_interrupts(struct mei_device *dev);
424
425#endif
diff --git a/drivers/staging/mei/mei_version.h b/drivers/staging/mei/mei_version.h
new file mode 100644
index 00000000000..075bad8f0bf
--- /dev/null
+++ b/drivers/staging/mei/mei_version.h
@@ -0,0 +1,31 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16
17
18#ifndef MEI_VERSION_H
19#define MEI_VERSION_H
20
21#define MAJOR_VERSION 7
22#define MINOR_VERSION 1
23#define QUICK_FIX_NUMBER 20
24#define VER_BUILD 1
25
26#define MEI_DRV_VER1 __stringify(MAJOR_VERSION) "." __stringify(MINOR_VERSION)
27#define MEI_DRV_VER2 __stringify(QUICK_FIX_NUMBER) "." __stringify(VER_BUILD)
28
29#define MEI_DRIVER_VERSION MEI_DRV_VER1 "." MEI_DRV_VER2
30
31#endif
diff --git a/drivers/staging/mei/wd.c b/drivers/staging/mei/wd.c
new file mode 100644
index 00000000000..42f04efc90e
--- /dev/null
+++ b/drivers/staging/mei/wd.c
@@ -0,0 +1,188 @@
1/*
2 *
3 * Intel Management Engine Interface (Intel MEI) Linux driver
4 * Copyright (c) 2003-2011, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 */
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/device.h>
20#include <linux/pci.h>
21#include <linux/sched.h>
22
23#include "mei_dev.h"
24#include "hw.h"
25#include "interface.h"
26#include "mei.h"
27
28/*
29 * MEI Watchdog Module Parameters
30 */
31static u16 watchdog_timeout = AMT_WD_VALUE;
32module_param(watchdog_timeout, ushort, 0);
33MODULE_PARM_DESC(watchdog_timeout,
34 "Intel(R) AMT Watchdog timeout value in seconds. (default="
35 __MODULE_STRING(AMT_WD_VALUE)
36 ", disable=0)");
37
38static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
39static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
40
41const u8 mei_wd_state_independence_msg[3][4] = {
42 {0x05, 0x02, 0x51, 0x10},
43 {0x05, 0x02, 0x52, 0x10},
44 {0x07, 0x02, 0x01, 0x10}
45};
46
47/* UUIDs for AMT F/W clients */
48const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
49 0x9D, 0xA9, 0x15, 0x14, 0xCB,
50 0x32, 0xAB);
51
52
53void mei_wd_start_setup(struct mei_device *dev)
54{
55 dev_dbg(&dev->pdev->dev, "dev->wd_timeout=%d.\n", dev->wd_timeout);
56 memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
57 memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE,
58 &dev->wd_timeout, sizeof(u16));
59}
60
61/**
62 * host_init_wd - mei initialization wd.
63 *
64 * @dev: the device structure
65 */
66void mei_wd_host_init(struct mei_device *dev)
67{
68 mei_cl_init(&dev->wd_cl, dev);
69
70 /* look for WD client and connect to it */
71 dev->wd_cl.state = MEI_FILE_DISCONNECTED;
72 dev->wd_timeout = watchdog_timeout;
73
74 if (dev->wd_timeout > 0) {
75 mei_wd_start_setup(dev);
76 /* find ME WD client */
77 mei_find_me_client_update_filext(dev, &dev->wd_cl,
78 &mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
79
80 dev_dbg(&dev->pdev->dev, "check wd_cl\n");
81 if (MEI_FILE_CONNECTING == dev->wd_cl.state) {
82 if (!mei_connect(dev, &dev->wd_cl)) {
83 dev_dbg(&dev->pdev->dev, "Failed to connect to WD client\n");
84 dev->wd_cl.state = MEI_FILE_DISCONNECTED;
85 dev->wd_cl.host_client_id = 0;
86 mei_host_init_iamthif(dev) ;
87 } else {
88 dev->wd_cl.timer_count = CONNECT_TIMEOUT;
89 }
90 } else {
91 dev_dbg(&dev->pdev->dev, "Failed to find WD client\n");
92 mei_host_init_iamthif(dev) ;
93 }
94 } else {
95 dev->wd_bypass = true;
96 dev_dbg(&dev->pdev->dev, "WD requested to be disabled\n");
97 mei_host_init_iamthif(dev) ;
98 }
99}
100
101/**
102 * mei_wd_send - sends watch dog message to fw.
103 *
104 * @dev: the device structure
105 *
106 * returns 0 if success,
107 * -EIO when message send fails
108 * -EINVAL when invalid message is to be sent
109 */
110int mei_wd_send(struct mei_device *dev)
111{
112 struct mei_msg_hdr *mei_hdr;
113
114 mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
115 mei_hdr->host_addr = dev->wd_cl.host_client_id;
116 mei_hdr->me_addr = dev->wd_cl.me_client_id;
117 mei_hdr->msg_complete = 1;
118 mei_hdr->reserved = 0;
119
120 if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
121 mei_hdr->length = MEI_START_WD_DATA_SIZE;
122 else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
123 mei_hdr->length = MEI_WD_PARAMS_SIZE;
124 else
125 return -EINVAL;
126
127 if (mei_write_message(dev, mei_hdr, dev->wd_data, mei_hdr->length))
128 return 0;
129 return -EIO;
130}
131
132int mei_wd_stop(struct mei_device *dev, bool preserve)
133{
134 int ret;
135 u16 wd_timeout = dev->wd_timeout;
136
137 cancel_delayed_work(&dev->wd_work);
138 if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
139 return 0;
140
141 dev->wd_timeout = 0;
142 dev->wd_due_counter = 0;
143 memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
144 dev->stop = true;
145
146 ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
147 if (ret < 0)
148 goto out;
149
150 if (ret && dev->mei_host_buffer_is_empty) {
151 ret = 0;
152 dev->mei_host_buffer_is_empty = false;
153
154 if (!mei_wd_send(dev)) {
155 ret = mei_flow_ctrl_reduce(dev, &dev->wd_cl);
156 if (ret)
157 goto out;
158 } else {
159 dev_dbg(&dev->pdev->dev, "send stop WD failed\n");
160 }
161
162 dev->wd_pending = false;
163 } else {
164 dev->wd_pending = true;
165 }
166 dev->wd_stopped = false;
167 mutex_unlock(&dev->device_lock);
168
169 ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
170 dev->wd_stopped, 10 * HZ);
171 mutex_lock(&dev->device_lock);
172 if (dev->wd_stopped) {
173 dev_dbg(&dev->pdev->dev, "stop wd complete ret=%d.\n", ret);
174 ret = 0;
175 } else {
176 if (!ret)
177 ret = -ETIMEDOUT;
178 dev_warn(&dev->pdev->dev,
179 "stop wd failed to complete ret=%d.\n", ret);
180 }
181
182 if (preserve)
183 dev->wd_timeout = wd_timeout;
184
185out:
186 return ret;
187}
188