diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-21 16:57:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-21 16:57:13 -0500 |
commit | 7ed214ac2095f561a94335ca672b6c42a1ea40ff (patch) | |
tree | da41901bff1d0d8d61170bf362384fdc61deb3ab /drivers/misc/mei/main.c | |
parent | 21eaab6d19ed43e82ed39c8deb7f192134fb4a0e (diff) | |
parent | 29e5507ae4ab34397f538f06b7070c81a4e4a2bf (diff) |
Merge tag 'char-misc-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver patches from Greg Kroah-Hartman:
"Here's the big char/misc driver patches for 3.9-rc1.
Nothing major here, just lots of different driver updates (mei,
hyperv, ipack, extcon, vmci, etc.).
All of these have been in the linux-next tree for a while."
* tag 'char-misc-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (209 commits)
w1: w1_therm: Add force-pullup option for "broken" sensors
w1: ds2482: Added 1-Wire pull-up support to the driver
vme: add missing put_device() after device_register() fails
extcon: max8997: Use workqueue to check cable state after completing boot of platform
extcon: max8997: Set default UART/USB path on probe
extcon: max8997: Consolidate duplicate code for checking ADC/CHG cable type
extcon: max8997: Set default of ADC debounce time during initialization
extcon: max8997: Remove duplicate code related to set H/W line path
extcon: max8997: Move defined constant to header file
extcon: max77693: Make max77693_extcon_cable static
extcon: max8997: Remove unreachable code
extcon: max8997: Make max8997_extcon_cable static
extcon: max77693: Remove unnecessary goto statement to improve readability
extcon: max77693: Convert to devm_input_allocate_device()
extcon: gpio: Rename filename of extcon-gpio.c according to kernel naming style
CREDITS: update email and address of Harald Hoyer
extcon: arizona: Use MICDET for final microphone identification
extcon: arizona: Always take the first HPDET reading as the final one
extcon: arizona: Clear _trig_sts bits after jack detection
extcon: arizona: Don't HPDET magic when headphones are enabled
...
Diffstat (limited to 'drivers/misc/mei/main.c')
-rw-r--r-- | drivers/misc/mei/main.c | 536 |
1 files changed, 135 insertions, 401 deletions
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 43fb52ff98ad..903f809b21f7 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -37,79 +37,11 @@ | |||
37 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
38 | #include <linux/miscdevice.h> | 38 | #include <linux/miscdevice.h> |
39 | 39 | ||
40 | #include "mei_dev.h" | ||
41 | #include <linux/mei.h> | 40 | #include <linux/mei.h> |
42 | #include "interface.h" | ||
43 | |||
44 | /* AMT device is a singleton on the platform */ | ||
45 | static struct pci_dev *mei_pdev; | ||
46 | |||
47 | /* mei_pci_tbl - PCI Device ID Table */ | ||
48 | static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = { | ||
49 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)}, | ||
50 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)}, | ||
51 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)}, | ||
52 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)}, | ||
53 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)}, | ||
54 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)}, | ||
55 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)}, | ||
56 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)}, | ||
57 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)}, | ||
58 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)}, | ||
59 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)}, | ||
60 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)}, | ||
61 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)}, | ||
62 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)}, | ||
63 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)}, | ||
64 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)}, | ||
65 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)}, | ||
66 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)}, | ||
67 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)}, | ||
68 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)}, | ||
69 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)}, | ||
70 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)}, | ||
71 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)}, | ||
72 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)}, | ||
73 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)}, | ||
74 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)}, | ||
75 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)}, | ||
76 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)}, | ||
77 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)}, | ||
78 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)}, | ||
79 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)}, | ||
80 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)}, | ||
81 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)}, | ||
82 | |||
83 | /* required last entry */ | ||
84 | {0, } | ||
85 | }; | ||
86 | |||
87 | MODULE_DEVICE_TABLE(pci, mei_pci_tbl); | ||
88 | 41 | ||
89 | static DEFINE_MUTEX(mei_mutex); | 42 | #include "mei_dev.h" |
90 | 43 | #include "hw-me.h" | |
91 | 44 | #include "client.h" | |
92 | /** | ||
93 | * find_read_list_entry - find read list entry | ||
94 | * | ||
95 | * @dev: device structure | ||
96 | * @file: pointer to file structure | ||
97 | * | ||
98 | * returns cb on success, NULL on error | ||
99 | */ | ||
100 | static struct mei_cl_cb *find_read_list_entry( | ||
101 | struct mei_device *dev, | ||
102 | struct mei_cl *cl) | ||
103 | { | ||
104 | struct mei_cl_cb *pos = NULL; | ||
105 | struct mei_cl_cb *next = NULL; | ||
106 | |||
107 | dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); | ||
108 | list_for_each_entry_safe(pos, next, &dev->read_list.list, list) | ||
109 | if (mei_cl_cmp_id(cl, pos->cl)) | ||
110 | return pos; | ||
111 | return NULL; | ||
112 | } | ||
113 | 45 | ||
114 | /** | 46 | /** |
115 | * mei_open - the open function | 47 | * mei_open - the open function |
@@ -121,16 +53,20 @@ static struct mei_cl_cb *find_read_list_entry( | |||
121 | */ | 53 | */ |
122 | static int mei_open(struct inode *inode, struct file *file) | 54 | static int mei_open(struct inode *inode, struct file *file) |
123 | { | 55 | { |
56 | struct miscdevice *misc = file->private_data; | ||
57 | struct pci_dev *pdev; | ||
124 | struct mei_cl *cl; | 58 | struct mei_cl *cl; |
125 | struct mei_device *dev; | 59 | struct mei_device *dev; |
126 | unsigned long cl_id; | 60 | |
127 | int err; | 61 | int err; |
128 | 62 | ||
129 | err = -ENODEV; | 63 | err = -ENODEV; |
130 | if (!mei_pdev) | 64 | if (!misc->parent) |
131 | goto out; | 65 | goto out; |
132 | 66 | ||
133 | dev = pci_get_drvdata(mei_pdev); | 67 | pdev = container_of(misc->parent, struct pci_dev, dev); |
68 | |||
69 | dev = pci_get_drvdata(pdev); | ||
134 | if (!dev) | 70 | if (!dev) |
135 | goto out; | 71 | goto out; |
136 | 72 | ||
@@ -153,24 +89,9 @@ static int mei_open(struct inode *inode, struct file *file) | |||
153 | goto out_unlock; | 89 | goto out_unlock; |
154 | } | 90 | } |
155 | 91 | ||
156 | cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX); | 92 | err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY); |
157 | if (cl_id >= MEI_CLIENTS_MAX) { | 93 | if (err) |
158 | dev_err(&dev->pdev->dev, "client_id exceded %d", | ||
159 | MEI_CLIENTS_MAX) ; | ||
160 | goto out_unlock; | 94 | goto out_unlock; |
161 | } | ||
162 | |||
163 | cl->host_client_id = cl_id; | ||
164 | |||
165 | dev_dbg(&dev->pdev->dev, "client_id = %d\n", cl->host_client_id); | ||
166 | |||
167 | dev->open_handle_count++; | ||
168 | |||
169 | list_add_tail(&cl->link, &dev->file_list); | ||
170 | |||
171 | set_bit(cl->host_client_id, dev->host_clients_map); | ||
172 | cl->state = MEI_FILE_INITIALIZING; | ||
173 | cl->sm_state = 0; | ||
174 | 95 | ||
175 | file->private_data = cl; | 96 | file->private_data = cl; |
176 | mutex_unlock(&dev->device_lock); | 97 | mutex_unlock(&dev->device_lock); |
@@ -216,7 +137,7 @@ static int mei_release(struct inode *inode, struct file *file) | |||
216 | "ME client = %d\n", | 137 | "ME client = %d\n", |
217 | cl->host_client_id, | 138 | cl->host_client_id, |
218 | cl->me_client_id); | 139 | cl->me_client_id); |
219 | rets = mei_disconnect_host_client(dev, cl); | 140 | rets = mei_cl_disconnect(cl); |
220 | } | 141 | } |
221 | mei_cl_flush_queues(cl); | 142 | mei_cl_flush_queues(cl); |
222 | dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", | 143 | dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", |
@@ -227,12 +148,13 @@ static int mei_release(struct inode *inode, struct file *file) | |||
227 | clear_bit(cl->host_client_id, dev->host_clients_map); | 148 | clear_bit(cl->host_client_id, dev->host_clients_map); |
228 | dev->open_handle_count--; | 149 | dev->open_handle_count--; |
229 | } | 150 | } |
230 | mei_me_cl_unlink(dev, cl); | 151 | mei_cl_unlink(cl); |
152 | |||
231 | 153 | ||
232 | /* free read cb */ | 154 | /* free read cb */ |
233 | cb = NULL; | 155 | cb = NULL; |
234 | if (cl->read_cb) { | 156 | if (cl->read_cb) { |
235 | cb = find_read_list_entry(dev, cl); | 157 | cb = mei_cl_find_read_cb(cl); |
236 | /* Remove entry from read list */ | 158 | /* Remove entry from read list */ |
237 | if (cb) | 159 | if (cb) |
238 | list_del(&cb->list); | 160 | list_del(&cb->list); |
@@ -322,7 +244,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
322 | goto out; | 244 | goto out; |
323 | } | 245 | } |
324 | 246 | ||
325 | err = mei_start_read(dev, cl); | 247 | err = mei_cl_read_start(cl); |
326 | if (err && err != -EBUSY) { | 248 | if (err && err != -EBUSY) { |
327 | dev_dbg(&dev->pdev->dev, | 249 | dev_dbg(&dev->pdev->dev, |
328 | "mei start read failure with status = %d\n", err); | 250 | "mei start read failure with status = %d\n", err); |
@@ -393,14 +315,13 @@ copy_buffer: | |||
393 | goto out; | 315 | goto out; |
394 | 316 | ||
395 | free: | 317 | free: |
396 | cb_pos = find_read_list_entry(dev, cl); | 318 | cb_pos = mei_cl_find_read_cb(cl); |
397 | /* Remove entry from read list */ | 319 | /* Remove entry from read list */ |
398 | if (cb_pos) | 320 | if (cb_pos) |
399 | list_del(&cb_pos->list); | 321 | list_del(&cb_pos->list); |
400 | mei_io_cb_free(cb); | 322 | mei_io_cb_free(cb); |
401 | cl->reading_state = MEI_IDLE; | 323 | cl->reading_state = MEI_IDLE; |
402 | cl->read_cb = NULL; | 324 | cl->read_cb = NULL; |
403 | cl->read_pending = 0; | ||
404 | out: | 325 | out: |
405 | dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets); | 326 | dev_dbg(&dev->pdev->dev, "end mei read rets= %d\n", rets); |
406 | mutex_unlock(&dev->device_lock); | 327 | mutex_unlock(&dev->device_lock); |
@@ -475,16 +396,15 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
475 | /* free entry used in read */ | 396 | /* free entry used in read */ |
476 | if (cl->reading_state == MEI_READ_COMPLETE) { | 397 | if (cl->reading_state == MEI_READ_COMPLETE) { |
477 | *offset = 0; | 398 | *offset = 0; |
478 | write_cb = find_read_list_entry(dev, cl); | 399 | write_cb = mei_cl_find_read_cb(cl); |
479 | if (write_cb) { | 400 | if (write_cb) { |
480 | list_del(&write_cb->list); | 401 | list_del(&write_cb->list); |
481 | mei_io_cb_free(write_cb); | 402 | mei_io_cb_free(write_cb); |
482 | write_cb = NULL; | 403 | write_cb = NULL; |
483 | cl->reading_state = MEI_IDLE; | 404 | cl->reading_state = MEI_IDLE; |
484 | cl->read_cb = NULL; | 405 | cl->read_cb = NULL; |
485 | cl->read_pending = 0; | ||
486 | } | 406 | } |
487 | } else if (cl->reading_state == MEI_IDLE && !cl->read_pending) | 407 | } else if (cl->reading_state == MEI_IDLE) |
488 | *offset = 0; | 408 | *offset = 0; |
489 | 409 | ||
490 | 410 | ||
@@ -519,7 +439,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
519 | 439 | ||
520 | if (rets) { | 440 | if (rets) { |
521 | dev_err(&dev->pdev->dev, | 441 | dev_err(&dev->pdev->dev, |
522 | "amthi write failed with status = %d\n", rets); | 442 | "amthif write failed with status = %d\n", rets); |
523 | goto err; | 443 | goto err; |
524 | } | 444 | } |
525 | mutex_unlock(&dev->device_lock); | 445 | mutex_unlock(&dev->device_lock); |
@@ -530,20 +450,20 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
530 | 450 | ||
531 | dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", | 451 | dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", |
532 | cl->host_client_id, cl->me_client_id); | 452 | cl->host_client_id, cl->me_client_id); |
533 | rets = mei_flow_ctrl_creds(dev, cl); | 453 | rets = mei_cl_flow_ctrl_creds(cl); |
534 | if (rets < 0) | 454 | if (rets < 0) |
535 | goto err; | 455 | goto err; |
536 | 456 | ||
537 | if (rets == 0 || dev->mei_host_buffer_is_empty == false) { | 457 | if (rets == 0 || !dev->hbuf_is_ready) { |
538 | write_cb->buf_idx = 0; | 458 | write_cb->buf_idx = 0; |
539 | mei_hdr.msg_complete = 0; | 459 | mei_hdr.msg_complete = 0; |
540 | cl->writing_state = MEI_WRITING; | 460 | cl->writing_state = MEI_WRITING; |
541 | goto out; | 461 | goto out; |
542 | } | 462 | } |
543 | 463 | ||
544 | dev->mei_host_buffer_is_empty = false; | 464 | dev->hbuf_is_ready = false; |
545 | if (length > mei_hbuf_max_data(dev)) { | 465 | if (length > mei_hbuf_max_len(dev)) { |
546 | mei_hdr.length = mei_hbuf_max_data(dev); | 466 | mei_hdr.length = mei_hbuf_max_len(dev); |
547 | mei_hdr.msg_complete = 0; | 467 | mei_hdr.msg_complete = 0; |
548 | } else { | 468 | } else { |
549 | mei_hdr.length = length; | 469 | mei_hdr.length = length; |
@@ -552,10 +472,10 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
552 | mei_hdr.host_addr = cl->host_client_id; | 472 | mei_hdr.host_addr = cl->host_client_id; |
553 | mei_hdr.me_addr = cl->me_client_id; | 473 | mei_hdr.me_addr = cl->me_client_id; |
554 | mei_hdr.reserved = 0; | 474 | mei_hdr.reserved = 0; |
555 | dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", | 475 | |
556 | *((u32 *) &mei_hdr)); | 476 | dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n", |
557 | if (mei_write_message(dev, &mei_hdr, | 477 | MEI_HDR_PRM(&mei_hdr)); |
558 | write_cb->request_buffer.data, mei_hdr.length)) { | 478 | if (mei_write_message(dev, &mei_hdr, write_cb->request_buffer.data)) { |
559 | rets = -ENODEV; | 479 | rets = -ENODEV; |
560 | goto err; | 480 | goto err; |
561 | } | 481 | } |
@@ -564,7 +484,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
564 | 484 | ||
565 | out: | 485 | out: |
566 | if (mei_hdr.msg_complete) { | 486 | if (mei_hdr.msg_complete) { |
567 | if (mei_flow_ctrl_reduce(dev, cl)) { | 487 | if (mei_cl_flow_ctrl_reduce(cl)) { |
568 | rets = -ENODEV; | 488 | rets = -ENODEV; |
569 | goto err; | 489 | goto err; |
570 | } | 490 | } |
@@ -582,6 +502,103 @@ err: | |||
582 | return rets; | 502 | return rets; |
583 | } | 503 | } |
584 | 504 | ||
505 | /** | ||
506 | * mei_ioctl_connect_client - the connect to fw client IOCTL function | ||
507 | * | ||
508 | * @dev: the device structure | ||
509 | * @data: IOCTL connect data, input and output parameters | ||
510 | * @file: private data of the file object | ||
511 | * | ||
512 | * Locking: called under "dev->device_lock" lock | ||
513 | * | ||
514 | * returns 0 on success, <0 on failure. | ||
515 | */ | ||
516 | static int mei_ioctl_connect_client(struct file *file, | ||
517 | struct mei_connect_client_data *data) | ||
518 | { | ||
519 | struct mei_device *dev; | ||
520 | struct mei_client *client; | ||
521 | struct mei_cl *cl; | ||
522 | int i; | ||
523 | int rets; | ||
524 | |||
525 | cl = file->private_data; | ||
526 | if (WARN_ON(!cl || !cl->dev)) | ||
527 | return -ENODEV; | ||
528 | |||
529 | dev = cl->dev; | ||
530 | |||
531 | if (dev->dev_state != MEI_DEV_ENABLED) { | ||
532 | rets = -ENODEV; | ||
533 | goto end; | ||
534 | } | ||
535 | |||
536 | if (cl->state != MEI_FILE_INITIALIZING && | ||
537 | cl->state != MEI_FILE_DISCONNECTED) { | ||
538 | rets = -EBUSY; | ||
539 | goto end; | ||
540 | } | ||
541 | |||
542 | /* find ME client we're trying to connect to */ | ||
543 | i = mei_me_cl_by_uuid(dev, &data->in_client_uuid); | ||
544 | if (i >= 0 && !dev->me_clients[i].props.fixed_address) { | ||
545 | cl->me_client_id = dev->me_clients[i].client_id; | ||
546 | cl->state = MEI_FILE_CONNECTING; | ||
547 | } | ||
548 | |||
549 | dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", | ||
550 | cl->me_client_id); | ||
551 | dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n", | ||
552 | dev->me_clients[i].props.protocol_version); | ||
553 | dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n", | ||
554 | dev->me_clients[i].props.max_msg_length); | ||
555 | |||
556 | /* if we're connecting to amthif client then we will use the | ||
557 | * existing connection | ||
558 | */ | ||
559 | if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) { | ||
560 | dev_dbg(&dev->pdev->dev, "FW Client is amthi\n"); | ||
561 | if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { | ||
562 | rets = -ENODEV; | ||
563 | goto end; | ||
564 | } | ||
565 | clear_bit(cl->host_client_id, dev->host_clients_map); | ||
566 | mei_cl_unlink(cl); | ||
567 | |||
568 | kfree(cl); | ||
569 | cl = NULL; | ||
570 | file->private_data = &dev->iamthif_cl; | ||
571 | |||
572 | client = &data->out_client_properties; | ||
573 | client->max_msg_length = | ||
574 | dev->me_clients[i].props.max_msg_length; | ||
575 | client->protocol_version = | ||
576 | dev->me_clients[i].props.protocol_version; | ||
577 | rets = dev->iamthif_cl.status; | ||
578 | |||
579 | goto end; | ||
580 | } | ||
581 | |||
582 | if (cl->state != MEI_FILE_CONNECTING) { | ||
583 | rets = -ENODEV; | ||
584 | goto end; | ||
585 | } | ||
586 | |||
587 | |||
588 | /* prepare the output buffer */ | ||
589 | client = &data->out_client_properties; | ||
590 | client->max_msg_length = dev->me_clients[i].props.max_msg_length; | ||
591 | client->protocol_version = dev->me_clients[i].props.protocol_version; | ||
592 | dev_dbg(&dev->pdev->dev, "Can connect?\n"); | ||
593 | |||
594 | |||
595 | rets = mei_cl_connect(cl, file); | ||
596 | |||
597 | end: | ||
598 | dev_dbg(&dev->pdev->dev, "free connect cb memory."); | ||
599 | return rets; | ||
600 | } | ||
601 | |||
585 | 602 | ||
586 | /** | 603 | /** |
587 | * mei_ioctl - the IOCTL function | 604 | * mei_ioctl - the IOCTL function |
@@ -630,6 +647,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) | |||
630 | rets = -EFAULT; | 647 | rets = -EFAULT; |
631 | goto out; | 648 | goto out; |
632 | } | 649 | } |
650 | |||
633 | rets = mei_ioctl_connect_client(file, connect_data); | 651 | rets = mei_ioctl_connect_client(file, connect_data); |
634 | 652 | ||
635 | /* if all is ok, copying the data back to user. */ | 653 | /* if all is ok, copying the data back to user. */ |
@@ -726,7 +744,6 @@ static const struct file_operations mei_fops = { | |||
726 | .llseek = no_llseek | 744 | .llseek = no_llseek |
727 | }; | 745 | }; |
728 | 746 | ||
729 | |||
730 | /* | 747 | /* |
731 | * Misc Device Struct | 748 | * Misc Device Struct |
732 | */ | 749 | */ |
@@ -736,300 +753,17 @@ static struct miscdevice mei_misc_device = { | |||
736 | .minor = MISC_DYNAMIC_MINOR, | 753 | .minor = MISC_DYNAMIC_MINOR, |
737 | }; | 754 | }; |
738 | 755 | ||
739 | /** | 756 | int mei_register(struct device *dev) |
740 | * mei_quirk_probe - probe for devices that doesn't valid ME interface | ||
741 | * @pdev: PCI device structure | ||
742 | * @ent: entry into pci_device_table | ||
743 | * | ||
744 | * returns true if ME Interface is valid, false otherwise | ||
745 | */ | ||
746 | static bool mei_quirk_probe(struct pci_dev *pdev, | ||
747 | const struct pci_device_id *ent) | ||
748 | { | 757 | { |
749 | u32 reg; | 758 | mei_misc_device.parent = dev; |
750 | if (ent->device == MEI_DEV_ID_PBG_1) { | 759 | return misc_register(&mei_misc_device); |
751 | pci_read_config_dword(pdev, 0x48, ®); | ||
752 | /* make sure that bit 9 is up and bit 10 is down */ | ||
753 | if ((reg & 0x600) == 0x200) { | ||
754 | dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n"); | ||
755 | return false; | ||
756 | } | ||
757 | } | ||
758 | return true; | ||
759 | } | ||
760 | /** | ||
761 | * mei_probe - Device Initialization Routine | ||
762 | * | ||
763 | * @pdev: PCI device structure | ||
764 | * @ent: entry in kcs_pci_tbl | ||
765 | * | ||
766 | * returns 0 on success, <0 on failure. | ||
767 | */ | ||
768 | static int mei_probe(struct pci_dev *pdev, | ||
769 | const struct pci_device_id *ent) | ||
770 | { | ||
771 | struct mei_device *dev; | ||
772 | int err; | ||
773 | |||
774 | mutex_lock(&mei_mutex); | ||
775 | |||
776 | if (!mei_quirk_probe(pdev, ent)) { | ||
777 | err = -ENODEV; | ||
778 | goto end; | ||
779 | } | ||
780 | |||
781 | if (mei_pdev) { | ||
782 | err = -EEXIST; | ||
783 | goto end; | ||
784 | } | ||
785 | /* enable pci dev */ | ||
786 | err = pci_enable_device(pdev); | ||
787 | if (err) { | ||
788 | dev_err(&pdev->dev, "failed to enable pci device.\n"); | ||
789 | goto end; | ||
790 | } | ||
791 | /* set PCI host mastering */ | ||
792 | pci_set_master(pdev); | ||
793 | /* pci request regions for mei driver */ | ||
794 | err = pci_request_regions(pdev, KBUILD_MODNAME); | ||
795 | if (err) { | ||
796 | dev_err(&pdev->dev, "failed to get pci regions.\n"); | ||
797 | goto disable_device; | ||
798 | } | ||
799 | /* allocates and initializes the mei dev structure */ | ||
800 | dev = mei_device_init(pdev); | ||
801 | if (!dev) { | ||
802 | err = -ENOMEM; | ||
803 | goto release_regions; | ||
804 | } | ||
805 | /* mapping IO device memory */ | ||
806 | dev->mem_addr = pci_iomap(pdev, 0, 0); | ||
807 | if (!dev->mem_addr) { | ||
808 | dev_err(&pdev->dev, "mapping I/O device memory failure.\n"); | ||
809 | err = -ENOMEM; | ||
810 | goto free_device; | ||
811 | } | ||
812 | pci_enable_msi(pdev); | ||
813 | |||
814 | /* request and enable interrupt */ | ||
815 | if (pci_dev_msi_enabled(pdev)) | ||
816 | err = request_threaded_irq(pdev->irq, | ||
817 | NULL, | ||
818 | mei_interrupt_thread_handler, | ||
819 | IRQF_ONESHOT, KBUILD_MODNAME, dev); | ||
820 | else | ||
821 | err = request_threaded_irq(pdev->irq, | ||
822 | mei_interrupt_quick_handler, | ||
823 | mei_interrupt_thread_handler, | ||
824 | IRQF_SHARED, KBUILD_MODNAME, dev); | ||
825 | |||
826 | if (err) { | ||
827 | dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n", | ||
828 | pdev->irq); | ||
829 | goto disable_msi; | ||
830 | } | ||
831 | INIT_DELAYED_WORK(&dev->timer_work, mei_timer); | ||
832 | INIT_WORK(&dev->init_work, mei_host_client_init); | ||
833 | |||
834 | if (mei_hw_init(dev)) { | ||
835 | dev_err(&pdev->dev, "init hw failure.\n"); | ||
836 | err = -ENODEV; | ||
837 | goto release_irq; | ||
838 | } | ||
839 | |||
840 | err = misc_register(&mei_misc_device); | ||
841 | if (err) | ||
842 | goto release_irq; | ||
843 | |||
844 | mei_pdev = pdev; | ||
845 | pci_set_drvdata(pdev, dev); | ||
846 | |||
847 | |||
848 | schedule_delayed_work(&dev->timer_work, HZ); | ||
849 | |||
850 | mutex_unlock(&mei_mutex); | ||
851 | |||
852 | pr_debug("initialization successful.\n"); | ||
853 | |||
854 | return 0; | ||
855 | |||
856 | release_irq: | ||
857 | /* disable interrupts */ | ||
858 | dev->host_hw_state = mei_hcsr_read(dev); | ||
859 | mei_disable_interrupts(dev); | ||
860 | flush_scheduled_work(); | ||
861 | free_irq(pdev->irq, dev); | ||
862 | disable_msi: | ||
863 | pci_disable_msi(pdev); | ||
864 | pci_iounmap(pdev, dev->mem_addr); | ||
865 | free_device: | ||
866 | kfree(dev); | ||
867 | release_regions: | ||
868 | pci_release_regions(pdev); | ||
869 | disable_device: | ||
870 | pci_disable_device(pdev); | ||
871 | end: | ||
872 | mutex_unlock(&mei_mutex); | ||
873 | dev_err(&pdev->dev, "initialization failed.\n"); | ||
874 | return err; | ||
875 | } | 760 | } |
876 | 761 | ||
877 | /** | 762 | void mei_deregister(void) |
878 | * mei_remove - Device Removal Routine | ||
879 | * | ||
880 | * @pdev: PCI device structure | ||
881 | * | ||
882 | * mei_remove is called by the PCI subsystem to alert the driver | ||
883 | * that it should release a PCI device. | ||
884 | */ | ||
885 | static void mei_remove(struct pci_dev *pdev) | ||
886 | { | 763 | { |
887 | struct mei_device *dev; | ||
888 | |||
889 | if (mei_pdev != pdev) | ||
890 | return; | ||
891 | |||
892 | dev = pci_get_drvdata(pdev); | ||
893 | if (!dev) | ||
894 | return; | ||
895 | |||
896 | mutex_lock(&dev->device_lock); | ||
897 | |||
898 | cancel_delayed_work(&dev->timer_work); | ||
899 | |||
900 | mei_wd_stop(dev); | ||
901 | |||
902 | mei_pdev = NULL; | ||
903 | |||
904 | if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) { | ||
905 | dev->iamthif_cl.state = MEI_FILE_DISCONNECTING; | ||
906 | mei_disconnect_host_client(dev, &dev->iamthif_cl); | ||
907 | } | ||
908 | if (dev->wd_cl.state == MEI_FILE_CONNECTED) { | ||
909 | dev->wd_cl.state = MEI_FILE_DISCONNECTING; | ||
910 | mei_disconnect_host_client(dev, &dev->wd_cl); | ||
911 | } | ||
912 | |||
913 | /* Unregistering watchdog device */ | ||
914 | mei_watchdog_unregister(dev); | ||
915 | |||
916 | /* remove entry if already in list */ | ||
917 | dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); | ||
918 | mei_me_cl_unlink(dev, &dev->wd_cl); | ||
919 | mei_me_cl_unlink(dev, &dev->iamthif_cl); | ||
920 | |||
921 | dev->iamthif_current_cb = NULL; | ||
922 | dev->me_clients_num = 0; | ||
923 | |||
924 | mutex_unlock(&dev->device_lock); | ||
925 | |||
926 | flush_scheduled_work(); | ||
927 | |||
928 | /* disable interrupts */ | ||
929 | mei_disable_interrupts(dev); | ||
930 | |||
931 | free_irq(pdev->irq, dev); | ||
932 | pci_disable_msi(pdev); | ||
933 | pci_set_drvdata(pdev, NULL); | ||
934 | |||
935 | if (dev->mem_addr) | ||
936 | pci_iounmap(pdev, dev->mem_addr); | ||
937 | |||
938 | kfree(dev); | ||
939 | |||
940 | pci_release_regions(pdev); | ||
941 | pci_disable_device(pdev); | ||
942 | |||
943 | misc_deregister(&mei_misc_device); | 764 | misc_deregister(&mei_misc_device); |
944 | } | 765 | mei_misc_device.parent = NULL; |
945 | #ifdef CONFIG_PM | ||
946 | static int mei_pci_suspend(struct device *device) | ||
947 | { | ||
948 | struct pci_dev *pdev = to_pci_dev(device); | ||
949 | struct mei_device *dev = pci_get_drvdata(pdev); | ||
950 | int err; | ||
951 | |||
952 | if (!dev) | ||
953 | return -ENODEV; | ||
954 | mutex_lock(&dev->device_lock); | ||
955 | |||
956 | cancel_delayed_work(&dev->timer_work); | ||
957 | |||
958 | /* Stop watchdog if exists */ | ||
959 | err = mei_wd_stop(dev); | ||
960 | /* Set new mei state */ | ||
961 | if (dev->dev_state == MEI_DEV_ENABLED || | ||
962 | dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) { | ||
963 | dev->dev_state = MEI_DEV_POWER_DOWN; | ||
964 | mei_reset(dev, 0); | ||
965 | } | ||
966 | mutex_unlock(&dev->device_lock); | ||
967 | |||
968 | free_irq(pdev->irq, dev); | ||
969 | pci_disable_msi(pdev); | ||
970 | |||
971 | return err; | ||
972 | } | 766 | } |
973 | 767 | ||
974 | static int mei_pci_resume(struct device *device) | ||
975 | { | ||
976 | struct pci_dev *pdev = to_pci_dev(device); | ||
977 | struct mei_device *dev; | ||
978 | int err; | ||
979 | |||
980 | dev = pci_get_drvdata(pdev); | ||
981 | if (!dev) | ||
982 | return -ENODEV; | ||
983 | |||
984 | pci_enable_msi(pdev); | ||
985 | |||
986 | /* request and enable interrupt */ | ||
987 | if (pci_dev_msi_enabled(pdev)) | ||
988 | err = request_threaded_irq(pdev->irq, | ||
989 | NULL, | ||
990 | mei_interrupt_thread_handler, | ||
991 | IRQF_ONESHOT, KBUILD_MODNAME, dev); | ||
992 | else | ||
993 | err = request_threaded_irq(pdev->irq, | ||
994 | mei_interrupt_quick_handler, | ||
995 | mei_interrupt_thread_handler, | ||
996 | IRQF_SHARED, KBUILD_MODNAME, dev); | ||
997 | |||
998 | if (err) { | ||
999 | dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n", | ||
1000 | pdev->irq); | ||
1001 | return err; | ||
1002 | } | ||
1003 | |||
1004 | mutex_lock(&dev->device_lock); | ||
1005 | dev->dev_state = MEI_DEV_POWER_UP; | ||
1006 | mei_reset(dev, 1); | ||
1007 | mutex_unlock(&dev->device_lock); | ||
1008 | |||
1009 | /* Start timer if stopped in suspend */ | ||
1010 | schedule_delayed_work(&dev->timer_work, HZ); | ||
1011 | |||
1012 | return err; | ||
1013 | } | ||
1014 | static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume); | ||
1015 | #define MEI_PM_OPS (&mei_pm_ops) | ||
1016 | #else | ||
1017 | #define MEI_PM_OPS NULL | ||
1018 | #endif /* CONFIG_PM */ | ||
1019 | /* | ||
1020 | * PCI driver structure | ||
1021 | */ | ||
1022 | static struct pci_driver mei_driver = { | ||
1023 | .name = KBUILD_MODNAME, | ||
1024 | .id_table = mei_pci_tbl, | ||
1025 | .probe = mei_probe, | ||
1026 | .remove = mei_remove, | ||
1027 | .shutdown = mei_remove, | ||
1028 | .driver.pm = MEI_PM_OPS, | ||
1029 | }; | ||
1030 | |||
1031 | module_pci_driver(mei_driver); | ||
1032 | |||
1033 | MODULE_AUTHOR("Intel Corporation"); | ||
1034 | MODULE_DESCRIPTION("Intel(R) Management Engine Interface"); | ||
1035 | MODULE_LICENSE("GPL v2"); | 768 | MODULE_LICENSE("GPL v2"); |
769 | |||