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