Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
interface.c
Go to the documentation of this file.
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 <linux/mei.h>
20 #include "interface.h"
21 
22 
23 
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 
44 {
45  dev->host_hw_state |= H_IE;
46  mei_hcsr_set(dev);
47 }
48 
55 {
56  dev->host_hw_state &= ~H_IE;
57  mei_hcsr_set(dev);
58 }
59 
67 static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
68 {
69  char read_ptr, write_ptr;
70 
71  dev->host_hw_state = mei_hcsr_read(dev);
72 
73  read_ptr = (char) ((dev->host_hw_state & H_CBRP) >> 8);
74  write_ptr = (char) ((dev->host_hw_state & H_CBWP) >> 16);
75 
76  return (unsigned char) (write_ptr - read_ptr);
77 }
78 
86 bool mei_hbuf_is_empty(struct mei_device *dev)
87 {
88  return mei_hbuf_filled_slots(dev) == 0;
89 }
90 
99 {
100  unsigned char filled_slots, empty_slots;
101 
102  filled_slots = mei_hbuf_filled_slots(dev);
103  empty_slots = dev->hbuf_depth - filled_slots;
104 
105  /* check for overflow */
106  if (filled_slots > dev->hbuf_depth)
107  return -EOVERFLOW;
108 
109  return empty_slots;
110 }
111 
123  unsigned char *buf, unsigned long length)
124 {
125  unsigned long rem, dw_cnt;
126  u32 *reg_buf = (u32 *)buf;
127  int i;
128  int empty_slots;
129 
130 
131  dev_dbg(&dev->pdev->dev,
132  "mei_write_message header=%08x.\n",
133  *((u32 *) header));
134 
135  empty_slots = mei_hbuf_empty_slots(dev);
136  dev_dbg(&dev->pdev->dev, "empty slots = %hu.\n", empty_slots);
137 
138  dw_cnt = mei_data2slots(length);
139  if (empty_slots < 0 || dw_cnt > empty_slots)
140  return -EIO;
141 
142  mei_reg_write(dev, H_CB_WW, *((u32 *) header));
143 
144  for (i = 0; i < length / 4; i++)
145  mei_reg_write(dev, H_CB_WW, reg_buf[i]);
146 
147  rem = length & 0x3;
148  if (rem > 0) {
149  u32 reg = 0;
150  memcpy(&reg, &buf[length - rem], rem);
151  mei_reg_write(dev, H_CB_WW, reg);
152  }
153 
154  dev->host_hw_state = mei_hcsr_read(dev);
155  dev->host_hw_state |= H_IG;
156  mei_hcsr_set(dev);
157  dev->me_hw_state = mei_mecsr_read(dev);
158  if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
159  return -EIO;
160 
161  return 0;
162 }
163 
172 {
173  char read_ptr, write_ptr;
174  unsigned char buffer_depth, filled_slots;
175 
176  dev->me_hw_state = mei_mecsr_read(dev);
177  buffer_depth = (unsigned char)((dev->me_hw_state & ME_CBD_HRA) >> 24);
178  read_ptr = (char) ((dev->me_hw_state & ME_CBRP_HRA) >> 8);
179  write_ptr = (char) ((dev->me_hw_state & ME_CBWP_HRA) >> 16);
180  filled_slots = (unsigned char) (write_ptr - read_ptr);
181 
182  /* check for overflow */
183  if (filled_slots > buffer_depth)
184  return -EOVERFLOW;
185 
186  dev_dbg(&dev->pdev->dev, "filled_slots =%08x\n", filled_slots);
187  return (int)filled_slots;
188 }
189 
197 void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
198  unsigned long buffer_length)
199 {
200  u32 *reg_buf = (u32 *)buffer;
201 
202  for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
203  *reg_buf++ = mei_mecbrw_read(dev);
204 
205  if (buffer_length > 0) {
206  u32 reg = mei_mecbrw_read(dev);
207  memcpy(reg_buf, &reg, buffer_length);
208  }
209 
210  dev->host_hw_state |= H_IG;
211  mei_hcsr_set(dev);
212 }
213 
224 int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
225 {
226  int i;
227 
228  if (!dev->me_clients_num)
229  return 0;
230 
231  if (cl->mei_flow_ctrl_creds > 0)
232  return 1;
233 
234  for (i = 0; i < dev->me_clients_num; i++) {
235  struct mei_me_client *me_cl = &dev->me_clients[i];
236  if (me_cl->client_id == cl->me_client_id) {
237  if (me_cl->mei_flow_ctrl_creds) {
238  if (WARN_ON(me_cl->props.single_recv_buf == 0))
239  return -EINVAL;
240  return 1;
241  } else {
242  return 0;
243  }
244  }
245  }
246  return -ENOENT;
247 }
248 
259 int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
260 {
261  int i;
262 
263  if (!dev->me_clients_num)
264  return -ENOENT;
265 
266  for (i = 0; i < dev->me_clients_num; i++) {
267  struct mei_me_client *me_cl = &dev->me_clients[i];
268  if (me_cl->client_id == cl->me_client_id) {
269  if (me_cl->props.single_recv_buf != 0) {
270  if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
271  return -EINVAL;
272  dev->me_clients[i].mei_flow_ctrl_creds--;
273  } else {
274  if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
275  return -EINVAL;
276  cl->mei_flow_ctrl_creds--;
277  }
278  return 0;
279  }
280  }
281  return -ENOENT;
282 }
283 
292 int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
293 {
294  struct mei_msg_hdr *mei_hdr;
295  struct hbm_flow_control *mei_flow_control;
296 
297  mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
298  mei_hdr->host_addr = 0;
299  mei_hdr->me_addr = 0;
300  mei_hdr->length = sizeof(struct hbm_flow_control);
301  mei_hdr->msg_complete = 1;
302  mei_hdr->reserved = 0;
303 
304  mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
305  memset(mei_flow_control, 0, sizeof(*mei_flow_control));
306  mei_flow_control->host_addr = cl->host_client_id;
307  mei_flow_control->me_addr = cl->me_client_id;
308  mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD;
309  memset(mei_flow_control->reserved, 0,
310  sizeof(mei_flow_control->reserved));
311  dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
312  cl->host_client_id, cl->me_client_id);
313 
314  return mei_write_message(dev, mei_hdr,
315  (unsigned char *) mei_flow_control,
316  sizeof(struct hbm_flow_control));
317 }
318 
329  struct mei_cl *cl)
330 {
331  struct mei_cl *cl_pos = NULL;
332  struct mei_cl *cl_next = NULL;
333 
334  list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
335  if ((cl_pos->state == MEI_FILE_CONNECTING) &&
336  (cl_pos != cl) &&
337  cl->me_client_id == cl_pos->me_client_id)
338  return 1;
339 
340  }
341  return 0;
342 }
343 
352 int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
353 {
354  struct mei_msg_hdr *mei_hdr;
355  struct hbm_client_disconnect_request *mei_cli_disconnect;
356 
357  mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
358  mei_hdr->host_addr = 0;
359  mei_hdr->me_addr = 0;
360  mei_hdr->length = sizeof(struct hbm_client_disconnect_request);
361  mei_hdr->msg_complete = 1;
362  mei_hdr->reserved = 0;
363 
364  mei_cli_disconnect =
365  (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
366  memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect));
367  mei_cli_disconnect->host_addr = cl->host_client_id;
368  mei_cli_disconnect->me_addr = cl->me_client_id;
369  mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD;
370  mei_cli_disconnect->reserved[0] = 0;
371 
372  return mei_write_message(dev, mei_hdr,
373  (unsigned char *) mei_cli_disconnect,
374  sizeof(struct hbm_client_disconnect_request));
375 }
376 
385 int mei_connect(struct mei_device *dev, struct mei_cl *cl)
386 {
387  struct mei_msg_hdr *mei_hdr;
388  struct hbm_client_connect_request *mei_cli_connect;
389 
390  mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
391  mei_hdr->host_addr = 0;
392  mei_hdr->me_addr = 0;
393  mei_hdr->length = sizeof(struct hbm_client_connect_request);
394  mei_hdr->msg_complete = 1;
395  mei_hdr->reserved = 0;
396 
397  mei_cli_connect =
398  (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
399  mei_cli_connect->host_addr = cl->host_client_id;
400  mei_cli_connect->me_addr = cl->me_client_id;
401  mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD;
402  mei_cli_connect->reserved = 0;
403 
404  return mei_write_message(dev, mei_hdr,
405  (unsigned char *) mei_cli_connect,
406  sizeof(struct hbm_client_connect_request));
407 }