~ubuntu-branches/ubuntu/quantal/linux-lowlatency/quantal-proposed

« back to all changes in this revision

Viewing changes to drivers/staging/mei/interface.c

  • Committer: Package Import Robot
  • Author(s): Andy Whitcroft, Andy Whitcroft
  • Date: 2012-06-21 09:16:38 UTC
  • Revision ID: package-import@ubuntu.com-20120621091638-gubhv4nox8xez1ct
Tags: 3.5.0-1.1
[ Andy Whitcroft]

* Rebuild lowlatency against Ubuntu-3.5.0-1.1
* All new configuration system to allow configuration deltas to be
  exposed via debian.lowlatency/config-delta

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *
3
 
 * Intel Management Engine Interface (Intel MEI) Linux driver
4
 
 * Copyright (c) 2003-2011, Intel Corporation.
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify it
7
 
 * under the terms and conditions of the GNU General Public License,
8
 
 * version 2, as published by the Free Software Foundation.
9
 
 *
10
 
 * This program is distributed in the hope it will be useful, but WITHOUT
11
 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
 
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13
 
 * more details.
14
 
 *
15
 
 */
16
 
 
17
 
#include <linux/pci.h>
18
 
#include "mei_dev.h"
19
 
#include "mei.h"
20
 
#include "interface.h"
21
 
 
22
 
 
23
 
 
24
 
/**
25
 
 * mei_set_csr_register - writes H_CSR register to the mei device,
26
 
 * and ignores the H_IS bit for it is write-one-to-zero.
27
 
 *
28
 
 * @dev: the device structure
29
 
 */
30
 
void 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
 
 */
43
 
void 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
 
 */
54
 
void 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
 
 */
67
 
static 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
 
 */
84
 
int 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
 
 */
104
 
int mei_count_empty_write_slots(struct mei_device *dev)
105
 
{
106
 
        unsigned char buffer_depth, filled_slots, empty_slots;
107
 
 
108
 
        dev->host_hw_state = mei_hcsr_read(dev);
109
 
        buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
110
 
        filled_slots = _host_get_filled_slots(dev);
111
 
        empty_slots = buffer_depth - filled_slots;
112
 
 
113
 
        /* check for overflow */
114
 
        if (filled_slots > buffer_depth)
115
 
                return -EOVERFLOW;
116
 
 
117
 
        return empty_slots;
118
 
}
119
 
 
120
 
/**
121
 
 * mei_write_message - writes a message to mei device.
122
 
 *
123
 
 * @dev: the device structure
124
 
 * @header: header of message
125
 
 * @write_buffer: message buffer will be written
126
 
 * @write_length: message size will be written
127
 
 *
128
 
 * returns 1 if success, 0 - otherwise.
129
 
 */
130
 
int mei_write_message(struct mei_device *dev,
131
 
                             struct mei_msg_hdr *header,
132
 
                             unsigned char *write_buffer,
133
 
                             unsigned long write_length)
134
 
{
135
 
        u32 temp_msg = 0;
136
 
        unsigned long bytes_written = 0;
137
 
        unsigned char buffer_depth, filled_slots, empty_slots;
138
 
        unsigned long dw_to_write;
139
 
 
140
 
        dev->host_hw_state = mei_hcsr_read(dev);
141
 
 
142
 
        dev_dbg(&dev->pdev->dev,
143
 
                        "host_hw_state = 0x%08x.\n",
144
 
                        dev->host_hw_state);
145
 
 
146
 
        dev_dbg(&dev->pdev->dev,
147
 
                        "mei_write_message header=%08x.\n",
148
 
                        *((u32 *) header));
149
 
 
150
 
        buffer_depth = (unsigned char) ((dev->host_hw_state & H_CBD) >> 24);
151
 
        filled_slots = _host_get_filled_slots(dev);
152
 
        empty_slots = buffer_depth - filled_slots;
153
 
        dev_dbg(&dev->pdev->dev,
154
 
                        "filled = %hu, empty = %hu.\n",
155
 
                        filled_slots, empty_slots);
156
 
 
157
 
        dw_to_write = ((write_length + 3) / 4);
158
 
 
159
 
        if (dw_to_write > empty_slots)
160
 
                return 0;
161
 
 
162
 
        mei_reg_write(dev, H_CB_WW, *((u32 *) header));
163
 
 
164
 
        while (write_length >= 4) {
165
 
                mei_reg_write(dev, H_CB_WW,
166
 
                                *(u32 *) (write_buffer + bytes_written));
167
 
                bytes_written += 4;
168
 
                write_length -= 4;
169
 
        }
170
 
 
171
 
        if (write_length > 0) {
172
 
                memcpy(&temp_msg, &write_buffer[bytes_written], write_length);
173
 
                mei_reg_write(dev, H_CB_WW, temp_msg);
174
 
        }
175
 
 
176
 
        dev->host_hw_state |= H_IG;
177
 
        mei_hcsr_set(dev);
178
 
        dev->me_hw_state = mei_mecsr_read(dev);
179
 
        if ((dev->me_hw_state & ME_RDY_HRA) != ME_RDY_HRA)
180
 
                return 0;
181
 
 
182
 
        return 1;
183
 
}
184
 
 
185
 
/**
186
 
 * mei_count_full_read_slots - counts read full slots.
187
 
 *
188
 
 * @dev: the device structure
189
 
 *
190
 
 * returns -1(ESLOTS_OVERFLOW) if overflow, otherwise filled slots count
191
 
 */
192
 
int 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
 
 */
218
 
void mei_read_slots(struct mei_device *dev,
219
 
                     unsigned char *buffer, unsigned long buffer_length)
220
 
{
221
 
        u32 i = 0;
222
 
        unsigned char temp_buf[sizeof(u32)];
223
 
 
224
 
        while (buffer_length >= sizeof(u32)) {
225
 
                ((u32 *) buffer)[i] = mei_mecbrw_read(dev);
226
 
 
227
 
                dev_dbg(&dev->pdev->dev,
228
 
                                "buffer[%d]= %d\n",
229
 
                                i, ((u32 *) buffer)[i]);
230
 
 
231
 
                i++;
232
 
                buffer_length -= sizeof(u32);
233
 
        }
234
 
 
235
 
        if (buffer_length > 0) {
236
 
                *((u32 *) &temp_buf) = mei_mecbrw_read(dev);
237
 
                memcpy(&buffer[i * 4], temp_buf, buffer_length);
238
 
        }
239
 
 
240
 
        dev->host_hw_state |= H_IG;
241
 
        mei_hcsr_set(dev);
242
 
}
243
 
 
244
 
/**
245
 
 * mei_flow_ctrl_creds - checks flow_control credentials.
246
 
 *
247
 
 * @dev: the device structure
248
 
 * @cl: private data of the file object
249
 
 *
250
 
 * returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
251
 
 *      -ENOENT if mei_cl is not present
252
 
 *      -EINVAL if single_recv_buf == 0
253
 
 */
254
 
int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl)
255
 
{
256
 
        int i;
257
 
 
258
 
        if (!dev->me_clients_num)
259
 
                return 0;
260
 
 
261
 
        if (cl->mei_flow_ctrl_creds > 0)
262
 
                return 1;
263
 
 
264
 
        for (i = 0; i < dev->me_clients_num; i++) {
265
 
                struct mei_me_client  *me_cl = &dev->me_clients[i];
266
 
                if (me_cl->client_id == cl->me_client_id) {
267
 
                        if (me_cl->mei_flow_ctrl_creds) {
268
 
                                if (WARN_ON(me_cl->props.single_recv_buf == 0))
269
 
                                        return -EINVAL;
270
 
                                return 1;
271
 
                        } else {
272
 
                                return 0;
273
 
                        }
274
 
                }
275
 
        }
276
 
        return -ENOENT;
277
 
}
278
 
 
279
 
/**
280
 
 * mei_flow_ctrl_reduce - reduces flow_control.
281
 
 *
282
 
 * @dev: the device structure
283
 
 * @cl: private data of the file object
284
 
 * @returns
285
 
 *      0 on success
286
 
 *      -ENOENT when me client is not found
287
 
 *      -EINVAL wehn ctrl credits are <= 0
288
 
 */
289
 
int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl)
290
 
{
291
 
        int i;
292
 
 
293
 
        if (!dev->me_clients_num)
294
 
                return -ENOENT;
295
 
 
296
 
        for (i = 0; i < dev->me_clients_num; i++) {
297
 
                struct mei_me_client  *me_cl = &dev->me_clients[i];
298
 
                if (me_cl->client_id == cl->me_client_id) {
299
 
                        if (me_cl->props.single_recv_buf != 0) {
300
 
                                if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
301
 
                                        return -EINVAL;
302
 
                                dev->me_clients[i].mei_flow_ctrl_creds--;
303
 
                        } else {
304
 
                                if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
305
 
                                        return -EINVAL;
306
 
                                cl->mei_flow_ctrl_creds--;
307
 
                        }
308
 
                        return 0;
309
 
                }
310
 
        }
311
 
        return -ENOENT;
312
 
}
313
 
 
314
 
/**
315
 
 * mei_send_flow_control - sends flow control to fw.
316
 
 *
317
 
 * @dev: the device structure
318
 
 * @cl: private data of the file object
319
 
 *
320
 
 * returns 1 if success, 0 - otherwise.
321
 
 */
322
 
int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl)
323
 
{
324
 
        struct mei_msg_hdr *mei_hdr;
325
 
        struct hbm_flow_control *mei_flow_control;
326
 
 
327
 
        mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
328
 
        mei_hdr->host_addr = 0;
329
 
        mei_hdr->me_addr = 0;
330
 
        mei_hdr->length = sizeof(struct hbm_flow_control);
331
 
        mei_hdr->msg_complete = 1;
332
 
        mei_hdr->reserved = 0;
333
 
 
334
 
        mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1];
335
 
        memset(mei_flow_control, 0, sizeof(*mei_flow_control));
336
 
        mei_flow_control->host_addr = cl->host_client_id;
337
 
        mei_flow_control->me_addr = cl->me_client_id;
338
 
        mei_flow_control->cmd.cmd = MEI_FLOW_CONTROL_CMD;
339
 
        memset(mei_flow_control->reserved, 0,
340
 
                        sizeof(mei_flow_control->reserved));
341
 
        dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n",
342
 
            cl->host_client_id, cl->me_client_id);
343
 
        if (!mei_write_message(dev, mei_hdr,
344
 
                                (unsigned char *) mei_flow_control,
345
 
                                sizeof(struct hbm_flow_control)))
346
 
                return 0;
347
 
 
348
 
        return 1;
349
 
 
350
 
}
351
 
 
352
 
/**
353
 
 * mei_other_client_is_connecting - checks if other
354
 
 *    client with the same client id is connected.
355
 
 *
356
 
 * @dev: the device structure
357
 
 * @cl: private data of the file object
358
 
 *
359
 
 * returns 1 if other client is connected, 0 - otherwise.
360
 
 */
361
 
int mei_other_client_is_connecting(struct mei_device *dev,
362
 
                                struct mei_cl *cl)
363
 
{
364
 
        struct mei_cl *cl_pos = NULL;
365
 
        struct mei_cl *cl_next = NULL;
366
 
 
367
 
        list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
368
 
                if ((cl_pos->state == MEI_FILE_CONNECTING) &&
369
 
                        (cl_pos != cl) &&
370
 
                        cl->me_client_id == cl_pos->me_client_id)
371
 
                        return 1;
372
 
 
373
 
        }
374
 
        return 0;
375
 
}
376
 
 
377
 
/**
378
 
 * mei_disconnect - sends disconnect message to fw.
379
 
 *
380
 
 * @dev: the device structure
381
 
 * @cl: private data of the file object
382
 
 *
383
 
 * returns 1 if success, 0 - otherwise.
384
 
 */
385
 
int mei_disconnect(struct mei_device *dev, struct mei_cl *cl)
386
 
{
387
 
        struct mei_msg_hdr *mei_hdr;
388
 
        struct hbm_client_disconnect_request *mei_cli_disconnect;
389
 
 
390
 
        mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
391
 
        mei_hdr->host_addr = 0;
392
 
        mei_hdr->me_addr = 0;
393
 
        mei_hdr->length = sizeof(struct hbm_client_disconnect_request);
394
 
        mei_hdr->msg_complete = 1;
395
 
        mei_hdr->reserved = 0;
396
 
 
397
 
        mei_cli_disconnect =
398
 
            (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1];
399
 
        memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect));
400
 
        mei_cli_disconnect->host_addr = cl->host_client_id;
401
 
        mei_cli_disconnect->me_addr = cl->me_client_id;
402
 
        mei_cli_disconnect->cmd.cmd = CLIENT_DISCONNECT_REQ_CMD;
403
 
        mei_cli_disconnect->reserved[0] = 0;
404
 
 
405
 
        if (!mei_write_message(dev, mei_hdr,
406
 
                                (unsigned char *) mei_cli_disconnect,
407
 
                                sizeof(struct hbm_client_disconnect_request)))
408
 
                return 0;
409
 
 
410
 
        return 1;
411
 
}
412
 
 
413
 
/**
414
 
 * mei_connect - sends connect message to fw.
415
 
 *
416
 
 * @dev: the device structure
417
 
 * @cl: private data of the file object
418
 
 *
419
 
 * returns 1 if success, 0 - otherwise.
420
 
 */
421
 
int mei_connect(struct mei_device *dev, struct mei_cl *cl)
422
 
{
423
 
        struct mei_msg_hdr *mei_hdr;
424
 
        struct hbm_client_connect_request *mei_cli_connect;
425
 
 
426
 
        mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0];
427
 
        mei_hdr->host_addr = 0;
428
 
        mei_hdr->me_addr = 0;
429
 
        mei_hdr->length = sizeof(struct hbm_client_connect_request);
430
 
        mei_hdr->msg_complete = 1;
431
 
        mei_hdr->reserved = 0;
432
 
 
433
 
        mei_cli_connect =
434
 
            (struct hbm_client_connect_request *) &dev->wr_msg_buf[1];
435
 
        mei_cli_connect->host_addr = cl->host_client_id;
436
 
        mei_cli_connect->me_addr = cl->me_client_id;
437
 
        mei_cli_connect->cmd.cmd = CLIENT_CONNECT_REQ_CMD;
438
 
        mei_cli_connect->reserved = 0;
439
 
 
440
 
        if (!mei_write_message(dev, mei_hdr,
441
 
                                (unsigned char *) mei_cli_connect,
442
 
                                sizeof(struct hbm_client_connect_request)))
443
 
                return 0;
444
 
 
445
 
        return 1;
446
 
}