diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-03 11:06:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-03 11:06:56 -0400 |
commit | 4046136afbd1038d776bad9c59e1e4cca78186fb (patch) | |
tree | 1888ca7bd978c0bba891ac9ee51224fd06d1162e /drivers/misc | |
parent | b55a0ff8df92646696c858a8fea4dbf38509f202 (diff) | |
parent | a100d88df1e924e5c9678fabf054d1bae7ab74fb (diff) |
Merge tag 'char-misc-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc into next
Pull char/misc driver patches from Greg KH:
"Here is the big char / misc driver update for 3.16-rc1.
Lots of different driver updates for a variety of different drivers
and minor driver subsystems.
All have been in linux-next with no reported issues"
* tag 'char-misc-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (79 commits)
hv: use correct order when freeing monitor_pages
spmi: of: fixup generic SPMI devicetree binding example
applicom: dereferencing NULL on error path
misc: genwqe: fix uninitialized return value in genwqe_free_sync_sgl()
miscdevice.h: Simple syntax fix to make pointers consistent.
MAINTAINERS: Add miscdevice.h to file list for char/misc drivers.
mcb: Add support for shared PCI IRQs
drivers: Remove duplicate conditionally included subdirs
misc: atmel_pwm: only build for supported platforms
mei: me: move probe quirk to cfg structure
mei: add per device configuration
mei: me: read H_CSR after asserting reset
mei: me: drop harmful wait optimization
mei: me: fix hw ready reset flow
mei: fix memory leak of mei_clients array
uio: fix vma io range check in mmap
drivers: uio_dmem_genirq: Fix memory leak in uio_dmem_genirq_probe()
w1: do not unlock unheld list_mutex in __w1_remove_master_device()
w1: optional bundling of netlink kernel replies
connector: allow multiple messages to be sent in one packet
...
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 5 | ||||
-rw-r--r-- | drivers/misc/arm-charlcd.c | 7 | ||||
-rw-r--r-- | drivers/misc/ds1682.c | 5 | ||||
-rw-r--r-- | drivers/misc/genwqe/card_debugfs.c | 4 | ||||
-rw-r--r-- | drivers/misc/genwqe/card_utils.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/amthif.c | 2 | ||||
-rw-r--r-- | drivers/misc/mei/bus.c | 4 | ||||
-rw-r--r-- | drivers/misc/mei/client.c | 90 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.c | 97 | ||||
-rw-r--r-- | drivers/misc/mei/hbm.h | 2 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me-regs.h | 9 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.c | 322 | ||||
-rw-r--r-- | drivers/misc/mei/hw-me.h | 15 | ||||
-rw-r--r-- | drivers/misc/mei/hw-txe-regs.h | 2 | ||||
-rw-r--r-- | drivers/misc/mei/hw-txe.c | 111 | ||||
-rw-r--r-- | drivers/misc/mei/hw-txe.h | 21 | ||||
-rw-r--r-- | drivers/misc/mei/hw.h | 25 | ||||
-rw-r--r-- | drivers/misc/mei/init.c | 60 | ||||
-rw-r--r-- | drivers/misc/mei/main.c | 1 | ||||
-rw-r--r-- | drivers/misc/mei/mei_dev.h | 101 | ||||
-rw-r--r-- | drivers/misc/mei/pci-me.c | 256 | ||||
-rw-r--r-- | drivers/misc/mei/pci-txe.c | 155 | ||||
-rw-r--r-- | drivers/misc/mei/wd.c | 2 |
23 files changed, 1132 insertions, 166 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d9663ef90ce8..a43d0c467274 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -54,6 +54,7 @@ config AD525X_DPOT_SPI | |||
54 | config ATMEL_PWM | 54 | config ATMEL_PWM |
55 | tristate "Atmel AT32/AT91 PWM support" | 55 | tristate "Atmel AT32/AT91 PWM support" |
56 | depends on HAVE_CLK | 56 | depends on HAVE_CLK |
57 | depends on AVR32 || AT91SAM9263 || AT91SAM9RL || AT91SAM9G45 | ||
57 | help | 58 | help |
58 | This option enables device driver support for the PWM channels | 59 | This option enables device driver support for the PWM channels |
59 | on certain Atmel processors. Pulse Width Modulation is used for | 60 | on certain Atmel processors. Pulse Width Modulation is used for |
@@ -200,7 +201,7 @@ config ICS932S401 | |||
200 | 201 | ||
201 | config ATMEL_SSC | 202 | config ATMEL_SSC |
202 | tristate "Device driver for Atmel SSC peripheral" | 203 | tristate "Device driver for Atmel SSC peripheral" |
203 | depends on HAS_IOMEM | 204 | depends on HAS_IOMEM && (AVR32 || ARCH_AT91 || COMPILE_TEST) |
204 | ---help--- | 205 | ---help--- |
205 | This option enables device driver support for Atmel Synchronized | 206 | This option enables device driver support for Atmel Synchronized |
206 | Serial Communication peripheral (SSC). | 207 | Serial Communication peripheral (SSC). |
@@ -468,7 +469,7 @@ config BMP085_SPI | |||
468 | config PCH_PHUB | 469 | config PCH_PHUB |
469 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" | 470 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" |
470 | select GENERIC_NET_UTILS | 471 | select GENERIC_NET_UTILS |
471 | depends on PCI | 472 | depends on PCI && (X86_32 || COMPILE_TEST) |
472 | help | 473 | help |
473 | This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of | 474 | This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of |
474 | Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded | 475 | Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded |
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c index b7ebf8021d99..c72e96b523ed 100644 --- a/drivers/misc/arm-charlcd.c +++ b/drivers/misc/arm-charlcd.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/platform_device.h> | 13 | #include <linux/platform_device.h> |
14 | #include <linux/of.h> | ||
14 | #include <linux/completion.h> | 15 | #include <linux/completion.h> |
15 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
16 | #include <linux/io.h> | 17 | #include <linux/io.h> |
@@ -366,11 +367,17 @@ static const struct dev_pm_ops charlcd_pm_ops = { | |||
366 | .resume = charlcd_resume, | 367 | .resume = charlcd_resume, |
367 | }; | 368 | }; |
368 | 369 | ||
370 | static const struct of_device_id charlcd_match[] = { | ||
371 | { .compatible = "arm,versatile-lcd", }, | ||
372 | {} | ||
373 | }; | ||
374 | |||
369 | static struct platform_driver charlcd_driver = { | 375 | static struct platform_driver charlcd_driver = { |
370 | .driver = { | 376 | .driver = { |
371 | .name = DRIVERNAME, | 377 | .name = DRIVERNAME, |
372 | .owner = THIS_MODULE, | 378 | .owner = THIS_MODULE, |
373 | .pm = &charlcd_pm_ops, | 379 | .pm = &charlcd_pm_ops, |
380 | .of_match_table = of_match_ptr(charlcd_match), | ||
374 | }, | 381 | }, |
375 | .remove = __exit_p(charlcd_remove), | 382 | .remove = __exit_p(charlcd_remove), |
376 | }; | 383 | }; |
diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c index 6a672f9ef522..b909fb30232a 100644 --- a/drivers/misc/ds1682.c +++ b/drivers/misc/ds1682.c | |||
@@ -85,7 +85,6 @@ static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr, | |||
85 | { | 85 | { |
86 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | 86 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); |
87 | struct i2c_client *client = to_i2c_client(dev); | 87 | struct i2c_client *client = to_i2c_client(dev); |
88 | char *endp; | ||
89 | u64 val; | 88 | u64 val; |
90 | __le32 val_le; | 89 | __le32 val_le; |
91 | int rc; | 90 | int rc; |
@@ -93,8 +92,8 @@ static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr, | |||
93 | dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name); | 92 | dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name); |
94 | 93 | ||
95 | /* Decode input */ | 94 | /* Decode input */ |
96 | val = simple_strtoull(buf, &endp, 0); | 95 | rc = kstrtoull(buf, 0, &val); |
97 | if (buf == endp) { | 96 | if (rc < 0) { |
98 | dev_dbg(dev, "input string not a number\n"); | 97 | dev_dbg(dev, "input string not a number\n"); |
99 | return -EINVAL; | 98 | return -EINVAL; |
100 | } | 99 | } |
diff --git a/drivers/misc/genwqe/card_debugfs.c b/drivers/misc/genwqe/card_debugfs.c index 50d2096ea1c7..0a33ade64109 100644 --- a/drivers/misc/genwqe/card_debugfs.c +++ b/drivers/misc/genwqe/card_debugfs.c | |||
@@ -348,7 +348,7 @@ int genwqe_init_debugfs(struct genwqe_dev *cd) | |||
348 | char name[64]; | 348 | char name[64]; |
349 | unsigned int i; | 349 | unsigned int i; |
350 | 350 | ||
351 | sprintf(card_name, "%s%u_card", GENWQE_DEVNAME, cd->card_idx); | 351 | sprintf(card_name, "%s%d_card", GENWQE_DEVNAME, cd->card_idx); |
352 | 352 | ||
353 | root = debugfs_create_dir(card_name, cd->debugfs_genwqe); | 353 | root = debugfs_create_dir(card_name, cd->debugfs_genwqe); |
354 | if (!root) { | 354 | if (!root) { |
@@ -454,7 +454,7 @@ int genwqe_init_debugfs(struct genwqe_dev *cd) | |||
454 | } | 454 | } |
455 | 455 | ||
456 | for (i = 0; i < GENWQE_MAX_VFS; i++) { | 456 | for (i = 0; i < GENWQE_MAX_VFS; i++) { |
457 | sprintf(name, "vf%d_jobtimeout_msec", i); | 457 | sprintf(name, "vf%u_jobtimeout_msec", i); |
458 | 458 | ||
459 | file = debugfs_create_u32(name, 0666, root, | 459 | file = debugfs_create_u32(name, 0666, root, |
460 | &cd->vf_jobtimeout_msec[i]); | 460 | &cd->vf_jobtimeout_msec[i]); |
diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index c00adfaa6279..62cc6bb3f62e 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c | |||
@@ -454,7 +454,7 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, | |||
454 | */ | 454 | */ |
455 | int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl) | 455 | int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl) |
456 | { | 456 | { |
457 | int rc; | 457 | int rc = 0; |
458 | struct pci_dev *pci_dev = cd->pci_dev; | 458 | struct pci_dev *pci_dev = cd->pci_dev; |
459 | 459 | ||
460 | if (sgl->fpage) { | 460 | if (sgl->fpage) { |
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index b8deb3455480..0d6234db00fa 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c | |||
@@ -111,8 +111,6 @@ int mei_amthif_host_init(struct mei_device *dev) | |||
111 | return ret; | 111 | return ret; |
112 | } | 112 | } |
113 | 113 | ||
114 | cl->state = MEI_FILE_CONNECTING; | ||
115 | |||
116 | ret = mei_cl_connect(cl, NULL); | 114 | ret = mei_cl_connect(cl, NULL); |
117 | 115 | ||
118 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 116 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index ddc5ac92a200..0e993ef28b94 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
@@ -247,7 +247,7 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, | |||
247 | return id; | 247 | return id; |
248 | 248 | ||
249 | if (length > dev->me_clients[id].props.max_msg_length) | 249 | if (length > dev->me_clients[id].props.max_msg_length) |
250 | return -EINVAL; | 250 | return -EFBIG; |
251 | 251 | ||
252 | cb = mei_io_cb_init(cl, NULL); | 252 | cb = mei_io_cb_init(cl, NULL); |
253 | if (!cb) | 253 | if (!cb) |
@@ -427,8 +427,6 @@ int mei_cl_enable_device(struct mei_cl_device *device) | |||
427 | 427 | ||
428 | mutex_lock(&dev->device_lock); | 428 | mutex_lock(&dev->device_lock); |
429 | 429 | ||
430 | cl->state = MEI_FILE_CONNECTING; | ||
431 | |||
432 | err = mei_cl_connect(cl, NULL); | 430 | err = mei_cl_connect(cl, NULL); |
433 | if (err < 0) { | 431 | if (err < 0) { |
434 | mutex_unlock(&dev->device_lock); | 432 | mutex_unlock(&dev->device_lock); |
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 8c078b808cd3..59d20c599b16 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/wait.h> | 19 | #include <linux/wait.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/pm_runtime.h> | ||
21 | 22 | ||
22 | #include <linux/mei.h> | 23 | #include <linux/mei.h> |
23 | 24 | ||
@@ -415,6 +416,10 @@ void mei_host_client_init(struct work_struct *work) | |||
415 | dev->reset_count = 0; | 416 | dev->reset_count = 0; |
416 | 417 | ||
417 | mutex_unlock(&dev->device_lock); | 418 | mutex_unlock(&dev->device_lock); |
419 | |||
420 | pm_runtime_mark_last_busy(&dev->pdev->dev); | ||
421 | dev_dbg(&dev->pdev->dev, "rpm: autosuspend\n"); | ||
422 | pm_runtime_autosuspend(&dev->pdev->dev); | ||
418 | } | 423 | } |
419 | 424 | ||
420 | /** | 425 | /** |
@@ -425,6 +430,12 @@ void mei_host_client_init(struct work_struct *work) | |||
425 | */ | 430 | */ |
426 | bool mei_hbuf_acquire(struct mei_device *dev) | 431 | bool mei_hbuf_acquire(struct mei_device *dev) |
427 | { | 432 | { |
433 | if (mei_pg_state(dev) == MEI_PG_ON || | ||
434 | dev->pg_event == MEI_PG_EVENT_WAIT) { | ||
435 | dev_dbg(&dev->pdev->dev, "device is in pg\n"); | ||
436 | return false; | ||
437 | } | ||
438 | |||
428 | if (!dev->hbuf_is_ready) { | 439 | if (!dev->hbuf_is_ready) { |
429 | dev_dbg(&dev->pdev->dev, "hbuf is not ready\n"); | 440 | dev_dbg(&dev->pdev->dev, "hbuf is not ready\n"); |
430 | return false; | 441 | return false; |
@@ -460,9 +471,18 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
460 | if (cl->state != MEI_FILE_DISCONNECTING) | 471 | if (cl->state != MEI_FILE_DISCONNECTING) |
461 | return 0; | 472 | return 0; |
462 | 473 | ||
474 | rets = pm_runtime_get(&dev->pdev->dev); | ||
475 | if (rets < 0 && rets != -EINPROGRESS) { | ||
476 | pm_runtime_put_noidle(&dev->pdev->dev); | ||
477 | cl_err(dev, cl, "rpm: get failed %d\n", rets); | ||
478 | return rets; | ||
479 | } | ||
480 | |||
463 | cb = mei_io_cb_init(cl, NULL); | 481 | cb = mei_io_cb_init(cl, NULL); |
464 | if (!cb) | 482 | if (!cb) { |
465 | return -ENOMEM; | 483 | rets = -ENOMEM; |
484 | goto free; | ||
485 | } | ||
466 | 486 | ||
467 | cb->fop_type = MEI_FOP_CLOSE; | 487 | cb->fop_type = MEI_FOP_CLOSE; |
468 | if (mei_hbuf_acquire(dev)) { | 488 | if (mei_hbuf_acquire(dev)) { |
@@ -494,8 +514,7 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
494 | cl_err(dev, cl, "wrong status client disconnect.\n"); | 514 | cl_err(dev, cl, "wrong status client disconnect.\n"); |
495 | 515 | ||
496 | if (err) | 516 | if (err) |
497 | cl_dbg(dev, cl, "wait failed disconnect err=%08x\n", | 517 | cl_dbg(dev, cl, "wait failed disconnect err=%d\n", err); |
498 | err); | ||
499 | 518 | ||
500 | cl_err(dev, cl, "failed to disconnect from FW client.\n"); | 519 | cl_err(dev, cl, "failed to disconnect from FW client.\n"); |
501 | } | 520 | } |
@@ -503,6 +522,10 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
503 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 522 | mei_io_list_flush(&dev->ctrl_rd_list, cl); |
504 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | 523 | mei_io_list_flush(&dev->ctrl_wr_list, cl); |
505 | free: | 524 | free: |
525 | cl_dbg(dev, cl, "rpm: autosuspend\n"); | ||
526 | pm_runtime_mark_last_busy(&dev->pdev->dev); | ||
527 | pm_runtime_put_autosuspend(&dev->pdev->dev); | ||
528 | |||
506 | mei_io_cb_free(cb); | 529 | mei_io_cb_free(cb); |
507 | return rets; | 530 | return rets; |
508 | } | 531 | } |
@@ -557,6 +580,13 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) | |||
557 | 580 | ||
558 | dev = cl->dev; | 581 | dev = cl->dev; |
559 | 582 | ||
583 | rets = pm_runtime_get(&dev->pdev->dev); | ||
584 | if (rets < 0 && rets != -EINPROGRESS) { | ||
585 | pm_runtime_put_noidle(&dev->pdev->dev); | ||
586 | cl_err(dev, cl, "rpm: get failed %d\n", rets); | ||
587 | return rets; | ||
588 | } | ||
589 | |||
560 | cb = mei_io_cb_init(cl, file); | 590 | cb = mei_io_cb_init(cl, file); |
561 | if (!cb) { | 591 | if (!cb) { |
562 | rets = -ENOMEM; | 592 | rets = -ENOMEM; |
@@ -567,6 +597,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) | |||
567 | 597 | ||
568 | /* run hbuf acquire last so we don't have to undo */ | 598 | /* run hbuf acquire last so we don't have to undo */ |
569 | if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) { | 599 | if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) { |
600 | cl->state = MEI_FILE_CONNECTING; | ||
570 | if (mei_hbm_cl_connect_req(dev, cl)) { | 601 | if (mei_hbm_cl_connect_req(dev, cl)) { |
571 | rets = -ENODEV; | 602 | rets = -ENODEV; |
572 | goto out; | 603 | goto out; |
@@ -596,6 +627,10 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file) | |||
596 | rets = cl->status; | 627 | rets = cl->status; |
597 | 628 | ||
598 | out: | 629 | out: |
630 | cl_dbg(dev, cl, "rpm: autosuspend\n"); | ||
631 | pm_runtime_mark_last_busy(&dev->pdev->dev); | ||
632 | pm_runtime_put_autosuspend(&dev->pdev->dev); | ||
633 | |||
599 | mei_io_cb_free(cb); | 634 | mei_io_cb_free(cb); |
600 | return rets; | 635 | return rets; |
601 | } | 636 | } |
@@ -713,23 +748,31 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) | |||
713 | return -ENOTTY; | 748 | return -ENOTTY; |
714 | } | 749 | } |
715 | 750 | ||
751 | rets = pm_runtime_get(&dev->pdev->dev); | ||
752 | if (rets < 0 && rets != -EINPROGRESS) { | ||
753 | pm_runtime_put_noidle(&dev->pdev->dev); | ||
754 | cl_err(dev, cl, "rpm: get failed %d\n", rets); | ||
755 | return rets; | ||
756 | } | ||
757 | |||
716 | cb = mei_io_cb_init(cl, NULL); | 758 | cb = mei_io_cb_init(cl, NULL); |
717 | if (!cb) | 759 | if (!cb) { |
718 | return -ENOMEM; | 760 | rets = -ENOMEM; |
761 | goto out; | ||
762 | } | ||
719 | 763 | ||
720 | /* always allocate at least client max message */ | 764 | /* always allocate at least client max message */ |
721 | length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length); | 765 | length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length); |
722 | rets = mei_io_cb_alloc_resp_buf(cb, length); | 766 | rets = mei_io_cb_alloc_resp_buf(cb, length); |
723 | if (rets) | 767 | if (rets) |
724 | goto err; | 768 | goto out; |
725 | 769 | ||
726 | cb->fop_type = MEI_FOP_READ; | 770 | cb->fop_type = MEI_FOP_READ; |
727 | if (mei_hbuf_acquire(dev)) { | 771 | if (mei_hbuf_acquire(dev)) { |
728 | if (mei_hbm_cl_flow_control_req(dev, cl)) { | 772 | rets = mei_hbm_cl_flow_control_req(dev, cl); |
729 | cl_err(dev, cl, "flow control send failed\n"); | 773 | if (rets < 0) |
730 | rets = -ENODEV; | 774 | goto out; |
731 | goto err; | 775 | |
732 | } | ||
733 | list_add_tail(&cb->list, &dev->read_list.list); | 776 | list_add_tail(&cb->list, &dev->read_list.list); |
734 | } else { | 777 | } else { |
735 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | 778 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
@@ -737,9 +780,14 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) | |||
737 | 780 | ||
738 | cl->read_cb = cb; | 781 | cl->read_cb = cb; |
739 | 782 | ||
740 | return rets; | 783 | out: |
741 | err: | 784 | cl_dbg(dev, cl, "rpm: autosuspend\n"); |
742 | mei_io_cb_free(cb); | 785 | pm_runtime_mark_last_busy(&dev->pdev->dev); |
786 | pm_runtime_put_autosuspend(&dev->pdev->dev); | ||
787 | |||
788 | if (rets) | ||
789 | mei_io_cb_free(cb); | ||
790 | |||
743 | return rets; | 791 | return rets; |
744 | } | 792 | } |
745 | 793 | ||
@@ -776,7 +824,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
776 | return rets; | 824 | return rets; |
777 | 825 | ||
778 | if (rets == 0) { | 826 | if (rets == 0) { |
779 | cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); | 827 | cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); |
780 | return 0; | 828 | return 0; |
781 | } | 829 | } |
782 | 830 | ||
@@ -856,6 +904,12 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
856 | 904 | ||
857 | cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size); | 905 | cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size); |
858 | 906 | ||
907 | rets = pm_runtime_get(&dev->pdev->dev); | ||
908 | if (rets < 0 && rets != -EINPROGRESS) { | ||
909 | pm_runtime_put_noidle(&dev->pdev->dev); | ||
910 | cl_err(dev, cl, "rpm: get failed %d\n", rets); | ||
911 | return rets; | ||
912 | } | ||
859 | 913 | ||
860 | cb->fop_type = MEI_FOP_WRITE; | 914 | cb->fop_type = MEI_FOP_WRITE; |
861 | cb->buf_idx = 0; | 915 | cb->buf_idx = 0; |
@@ -926,6 +980,10 @@ out: | |||
926 | 980 | ||
927 | rets = buf->size; | 981 | rets = buf->size; |
928 | err: | 982 | err: |
983 | cl_dbg(dev, cl, "rpm: autosuspend\n"); | ||
984 | pm_runtime_mark_last_busy(&dev->pdev->dev); | ||
985 | pm_runtime_put_autosuspend(&dev->pdev->dev); | ||
986 | |||
929 | return rets; | 987 | return rets; |
930 | } | 988 | } |
931 | 989 | ||
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 4960288e543a..804106209d76 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c | |||
@@ -14,10 +14,12 @@ | |||
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/export.h> | ||
17 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
18 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
19 | #include <linux/wait.h> | 20 | #include <linux/wait.h> |
20 | #include <linux/mei.h> | 21 | #include <linux/mei.h> |
22 | #include <linux/pm_runtime.h> | ||
21 | 23 | ||
22 | #include "mei_dev.h" | 24 | #include "mei_dev.h" |
23 | #include "hbm.h" | 25 | #include "hbm.h" |
@@ -58,6 +60,34 @@ static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status) | |||
58 | } | 60 | } |
59 | 61 | ||
60 | /** | 62 | /** |
63 | * mei_hbm_idle - set hbm to idle state | ||
64 | * | ||
65 | * @dev: the device structure | ||
66 | */ | ||
67 | void mei_hbm_idle(struct mei_device *dev) | ||
68 | { | ||
69 | dev->init_clients_timer = 0; | ||
70 | dev->hbm_state = MEI_HBM_IDLE; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * mei_hbm_reset - reset hbm counters and book keeping data structurs | ||
75 | * | ||
76 | * @dev: the device structure | ||
77 | */ | ||
78 | void mei_hbm_reset(struct mei_device *dev) | ||
79 | { | ||
80 | dev->me_clients_num = 0; | ||
81 | dev->me_client_presentation_num = 0; | ||
82 | dev->me_client_index = 0; | ||
83 | |||
84 | kfree(dev->me_clients); | ||
85 | dev->me_clients = NULL; | ||
86 | |||
87 | mei_hbm_idle(dev); | ||
88 | } | ||
89 | |||
90 | /** | ||
61 | * mei_hbm_me_cl_allocate - allocates storage for me clients | 91 | * mei_hbm_me_cl_allocate - allocates storage for me clients |
62 | * | 92 | * |
63 | * @dev: the device structure | 93 | * @dev: the device structure |
@@ -69,9 +99,7 @@ static int mei_hbm_me_cl_allocate(struct mei_device *dev) | |||
69 | struct mei_me_client *clients; | 99 | struct mei_me_client *clients; |
70 | int b; | 100 | int b; |
71 | 101 | ||
72 | dev->me_clients_num = 0; | 102 | mei_hbm_reset(dev); |
73 | dev->me_client_presentation_num = 0; | ||
74 | dev->me_client_index = 0; | ||
75 | 103 | ||
76 | /* count how many ME clients we have */ | 104 | /* count how many ME clients we have */ |
77 | for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX) | 105 | for_each_set_bit(b, dev->me_clients_map, MEI_CLIENTS_MAX) |
@@ -80,9 +108,6 @@ static int mei_hbm_me_cl_allocate(struct mei_device *dev) | |||
80 | if (dev->me_clients_num == 0) | 108 | if (dev->me_clients_num == 0) |
81 | return 0; | 109 | return 0; |
82 | 110 | ||
83 | kfree(dev->me_clients); | ||
84 | dev->me_clients = NULL; | ||
85 | |||
86 | dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%ld.\n", | 111 | dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%ld.\n", |
87 | dev->me_clients_num * sizeof(struct mei_me_client)); | 112 | dev->me_clients_num * sizeof(struct mei_me_client)); |
88 | /* allocate storage for ME clients representation */ | 113 | /* allocate storage for ME clients representation */ |
@@ -133,17 +158,6 @@ bool mei_hbm_cl_addr_equal(struct mei_cl *cl, void *buf) | |||
133 | } | 158 | } |
134 | 159 | ||
135 | 160 | ||
136 | /** | ||
137 | * mei_hbm_idle - set hbm to idle state | ||
138 | * | ||
139 | * @dev: the device structure | ||
140 | */ | ||
141 | void mei_hbm_idle(struct mei_device *dev) | ||
142 | { | ||
143 | dev->init_clients_timer = 0; | ||
144 | dev->hbm_state = MEI_HBM_IDLE; | ||
145 | } | ||
146 | |||
147 | int mei_hbm_start_wait(struct mei_device *dev) | 161 | int mei_hbm_start_wait(struct mei_device *dev) |
148 | { | 162 | { |
149 | int ret; | 163 | int ret; |
@@ -289,6 +303,34 @@ static int mei_hbm_prop_req(struct mei_device *dev) | |||
289 | return 0; | 303 | return 0; |
290 | } | 304 | } |
291 | 305 | ||
306 | /* | ||
307 | * mei_hbm_pg - sends pg command | ||
308 | * | ||
309 | * @dev: the device structure | ||
310 | * @pg_cmd: the pg command code | ||
311 | * | ||
312 | * This function returns -EIO on write failure | ||
313 | */ | ||
314 | int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd) | ||
315 | { | ||
316 | struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr; | ||
317 | struct hbm_power_gate *req; | ||
318 | const size_t len = sizeof(struct hbm_power_gate); | ||
319 | int ret; | ||
320 | |||
321 | mei_hbm_hdr(mei_hdr, len); | ||
322 | |||
323 | req = (struct hbm_power_gate *)dev->wr_msg.data; | ||
324 | memset(req, 0, len); | ||
325 | req->hbm_cmd = pg_cmd; | ||
326 | |||
327 | ret = mei_write_message(dev, mei_hdr, dev->wr_msg.data); | ||
328 | if (ret) | ||
329 | dev_err(&dev->pdev->dev, "power gate command write failed.\n"); | ||
330 | return ret; | ||
331 | } | ||
332 | EXPORT_SYMBOL_GPL(mei_hbm_pg); | ||
333 | |||
292 | /** | 334 | /** |
293 | * mei_hbm_stop_req - send stop request message | 335 | * mei_hbm_stop_req - send stop request message |
294 | * | 336 | * |
@@ -701,6 +743,27 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
701 | mei_hbm_cl_flow_control_res(dev, flow_control); | 743 | mei_hbm_cl_flow_control_res(dev, flow_control); |
702 | break; | 744 | break; |
703 | 745 | ||
746 | case MEI_PG_ISOLATION_ENTRY_RES_CMD: | ||
747 | dev_dbg(&dev->pdev->dev, "power gate isolation entry response received\n"); | ||
748 | dev->pg_event = MEI_PG_EVENT_RECEIVED; | ||
749 | if (waitqueue_active(&dev->wait_pg)) | ||
750 | wake_up(&dev->wait_pg); | ||
751 | break; | ||
752 | |||
753 | case MEI_PG_ISOLATION_EXIT_REQ_CMD: | ||
754 | dev_dbg(&dev->pdev->dev, "power gate isolation exit request received\n"); | ||
755 | dev->pg_event = MEI_PG_EVENT_RECEIVED; | ||
756 | if (waitqueue_active(&dev->wait_pg)) | ||
757 | wake_up(&dev->wait_pg); | ||
758 | else | ||
759 | /* | ||
760 | * If the driver is not waiting on this then | ||
761 | * this is HW initiated exit from PG. | ||
762 | * Start runtime pm resume sequence to exit from PG. | ||
763 | */ | ||
764 | pm_request_resume(&dev->pdev->dev); | ||
765 | break; | ||
766 | |||
704 | case HOST_CLIENT_PROPERTIES_RES_CMD: | 767 | case HOST_CLIENT_PROPERTIES_RES_CMD: |
705 | dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n"); | 768 | dev_dbg(&dev->pdev->dev, "hbm: properties response: message received.\n"); |
706 | 769 | ||
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h index 20e8782711c0..683eb2835cec 100644 --- a/drivers/misc/mei/hbm.h +++ b/drivers/misc/mei/hbm.h | |||
@@ -50,6 +50,7 @@ static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length) | |||
50 | } | 50 | } |
51 | 51 | ||
52 | void mei_hbm_idle(struct mei_device *dev); | 52 | void mei_hbm_idle(struct mei_device *dev); |
53 | void mei_hbm_reset(struct mei_device *dev); | ||
53 | int mei_hbm_start_req(struct mei_device *dev); | 54 | int mei_hbm_start_req(struct mei_device *dev); |
54 | int mei_hbm_start_wait(struct mei_device *dev); | 55 | int mei_hbm_start_wait(struct mei_device *dev); |
55 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); | 56 | int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl); |
@@ -57,6 +58,7 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl); | |||
57 | int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl); | 58 | int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl); |
58 | int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); | 59 | int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl); |
59 | bool mei_hbm_version_is_supported(struct mei_device *dev); | 60 | bool mei_hbm_version_is_supported(struct mei_device *dev); |
61 | int mei_hbm_pg(struct mei_device *dev, u8 pg_cmd); | ||
60 | 62 | ||
61 | #endif /* _MEI_HBM_H_ */ | 63 | #endif /* _MEI_HBM_H_ */ |
62 | 64 | ||
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index cabc04383685..a7856c0ac576 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h | |||
@@ -133,6 +133,8 @@ | |||
133 | #define ME_CB_RW 8 | 133 | #define ME_CB_RW 8 |
134 | /* ME_CSR_HA - ME Control Status Host Access register (read only) */ | 134 | /* ME_CSR_HA - ME Control Status Host Access register (read only) */ |
135 | #define ME_CSR_HA 0xC | 135 | #define ME_CSR_HA 0xC |
136 | /* H_HGC_CSR - PGI register */ | ||
137 | #define H_HPG_CSR 0x10 | ||
136 | 138 | ||
137 | 139 | ||
138 | /* register bits of H_CSR (Host Control Status register) */ | 140 | /* register bits of H_CSR (Host Control Status register) */ |
@@ -162,6 +164,8 @@ access to ME_CBD */ | |||
162 | #define ME_CBWP_HRA 0x00FF0000 | 164 | #define ME_CBWP_HRA 0x00FF0000 |
163 | /* ME CB Read Pointer HRA - host read only access to ME_CBRP */ | 165 | /* ME CB Read Pointer HRA - host read only access to ME_CBRP */ |
164 | #define ME_CBRP_HRA 0x0000FF00 | 166 | #define ME_CBRP_HRA 0x0000FF00 |
167 | /* ME Power Gate Isolation Capability HRA - host ready only access */ | ||
168 | #define ME_PGIC_HRA 0x00000040 | ||
165 | /* ME Reset HRA - host read only access to ME_RST */ | 169 | /* ME Reset HRA - host read only access to ME_RST */ |
166 | #define ME_RST_HRA 0x00000010 | 170 | #define ME_RST_HRA 0x00000010 |
167 | /* ME Ready HRA - host read only access to ME_RDY */ | 171 | /* ME Ready HRA - host read only access to ME_RDY */ |
@@ -173,4 +177,9 @@ access to ME_CBD */ | |||
173 | /* ME Interrupt Enable HRA - host read only access to ME_IE */ | 177 | /* ME Interrupt Enable HRA - host read only access to ME_IE */ |
174 | #define ME_IE_HRA 0x00000001 | 178 | #define ME_IE_HRA 0x00000001 |
175 | 179 | ||
180 | |||
181 | /* register bits - H_HPG_CSR */ | ||
182 | #define H_HPG_CSR_PGIHEXR 0x00000001 | ||
183 | #define H_HPG_CSR_PGI 0x00000002 | ||
184 | |||
176 | #endif /* _MEI_HW_MEI_REGS_H_ */ | 185 | #endif /* _MEI_HW_MEI_REGS_H_ */ |
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 8dbdaaef1af5..6a2d272cea43 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c | |||
@@ -109,10 +109,27 @@ static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr) | |||
109 | */ | 109 | */ |
110 | static void mei_me_hw_config(struct mei_device *dev) | 110 | static void mei_me_hw_config(struct mei_device *dev) |
111 | { | 111 | { |
112 | struct mei_me_hw *hw = to_me_hw(dev); | ||
112 | u32 hcsr = mei_hcsr_read(to_me_hw(dev)); | 113 | u32 hcsr = mei_hcsr_read(to_me_hw(dev)); |
113 | /* Doesn't change in runtime */ | 114 | /* Doesn't change in runtime */ |
114 | dev->hbuf_depth = (hcsr & H_CBD) >> 24; | 115 | dev->hbuf_depth = (hcsr & H_CBD) >> 24; |
116 | |||
117 | hw->pg_state = MEI_PG_OFF; | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * mei_me_pg_state - translate internal pg state | ||
122 | * to the mei power gating state | ||
123 | * | ||
124 | * @hw - me hardware | ||
125 | * returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise | ||
126 | */ | ||
127 | static inline enum mei_pg_state mei_me_pg_state(struct mei_device *dev) | ||
128 | { | ||
129 | struct mei_me_hw *hw = to_me_hw(dev); | ||
130 | return hw->pg_state; | ||
115 | } | 131 | } |
132 | |||
116 | /** | 133 | /** |
117 | * mei_clear_interrupts - clear and stop interrupts | 134 | * mei_clear_interrupts - clear and stop interrupts |
118 | * | 135 | * |
@@ -164,6 +181,9 @@ static void mei_me_hw_reset_release(struct mei_device *dev) | |||
164 | hcsr |= H_IG; | 181 | hcsr |= H_IG; |
165 | hcsr &= ~H_RST; | 182 | hcsr &= ~H_RST; |
166 | mei_hcsr_set(hw, hcsr); | 183 | mei_hcsr_set(hw, hcsr); |
184 | |||
185 | /* complete this write before we set host ready on another CPU */ | ||
186 | mmiowb(); | ||
167 | } | 187 | } |
168 | /** | 188 | /** |
169 | * mei_me_hw_reset - resets fw via mei csr register. | 189 | * mei_me_hw_reset - resets fw via mei csr register. |
@@ -183,8 +203,21 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) | |||
183 | else | 203 | else |
184 | hcsr &= ~H_IE; | 204 | hcsr &= ~H_IE; |
185 | 205 | ||
206 | dev->recvd_hw_ready = false; | ||
186 | mei_me_reg_write(hw, H_CSR, hcsr); | 207 | mei_me_reg_write(hw, H_CSR, hcsr); |
187 | 208 | ||
209 | /* | ||
210 | * Host reads the H_CSR once to ensure that the | ||
211 | * posted write to H_CSR completes. | ||
212 | */ | ||
213 | hcsr = mei_hcsr_read(hw); | ||
214 | |||
215 | if ((hcsr & H_RST) == 0) | ||
216 | dev_warn(&dev->pdev->dev, "H_RST is not set = 0x%08X", hcsr); | ||
217 | |||
218 | if ((hcsr & H_RDY) == H_RDY) | ||
219 | dev_warn(&dev->pdev->dev, "H_RDY is not cleared 0x%08X", hcsr); | ||
220 | |||
188 | if (intr_enable == false) | 221 | if (intr_enable == false) |
189 | mei_me_hw_reset_release(dev); | 222 | mei_me_hw_reset_release(dev); |
190 | 223 | ||
@@ -201,6 +234,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) | |||
201 | static void mei_me_host_set_ready(struct mei_device *dev) | 234 | static void mei_me_host_set_ready(struct mei_device *dev) |
202 | { | 235 | { |
203 | struct mei_me_hw *hw = to_me_hw(dev); | 236 | struct mei_me_hw *hw = to_me_hw(dev); |
237 | hw->host_hw_state = mei_hcsr_read(hw); | ||
204 | hw->host_hw_state |= H_IE | H_IG | H_RDY; | 238 | hw->host_hw_state |= H_IE | H_IG | H_RDY; |
205 | mei_hcsr_set(hw, hw->host_hw_state); | 239 | mei_hcsr_set(hw, hw->host_hw_state); |
206 | } | 240 | } |
@@ -233,10 +267,7 @@ static bool mei_me_hw_is_ready(struct mei_device *dev) | |||
233 | static int mei_me_hw_ready_wait(struct mei_device *dev) | 267 | static int mei_me_hw_ready_wait(struct mei_device *dev) |
234 | { | 268 | { |
235 | int err; | 269 | int err; |
236 | if (mei_me_hw_is_ready(dev)) | ||
237 | return 0; | ||
238 | 270 | ||
239 | dev->recvd_hw_ready = false; | ||
240 | mutex_unlock(&dev->device_lock); | 271 | mutex_unlock(&dev->device_lock); |
241 | err = wait_event_interruptible_timeout(dev->wait_hw_ready, | 272 | err = wait_event_interruptible_timeout(dev->wait_hw_ready, |
242 | dev->recvd_hw_ready, | 273 | dev->recvd_hw_ready, |
@@ -431,6 +462,144 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, | |||
431 | } | 462 | } |
432 | 463 | ||
433 | /** | 464 | /** |
465 | * mei_me_pg_enter - write pg enter register to mei device. | ||
466 | * | ||
467 | * @dev: the device structure | ||
468 | */ | ||
469 | static void mei_me_pg_enter(struct mei_device *dev) | ||
470 | { | ||
471 | struct mei_me_hw *hw = to_me_hw(dev); | ||
472 | u32 reg = mei_me_reg_read(hw, H_HPG_CSR); | ||
473 | reg |= H_HPG_CSR_PGI; | ||
474 | mei_me_reg_write(hw, H_HPG_CSR, reg); | ||
475 | } | ||
476 | |||
477 | /** | ||
478 | * mei_me_pg_enter - write pg enter register to mei device. | ||
479 | * | ||
480 | * @dev: the device structure | ||
481 | */ | ||
482 | static void mei_me_pg_exit(struct mei_device *dev) | ||
483 | { | ||
484 | struct mei_me_hw *hw = to_me_hw(dev); | ||
485 | u32 reg = mei_me_reg_read(hw, H_HPG_CSR); | ||
486 | |||
487 | WARN(!(reg & H_HPG_CSR_PGI), "PGI is not set\n"); | ||
488 | |||
489 | reg |= H_HPG_CSR_PGIHEXR; | ||
490 | mei_me_reg_write(hw, H_HPG_CSR, reg); | ||
491 | } | ||
492 | |||
493 | /** | ||
494 | * mei_me_pg_set_sync - perform pg entry procedure | ||
495 | * | ||
496 | * @dev: the device structure | ||
497 | * | ||
498 | * returns 0 on success an error code otherwise | ||
499 | */ | ||
500 | int mei_me_pg_set_sync(struct mei_device *dev) | ||
501 | { | ||
502 | struct mei_me_hw *hw = to_me_hw(dev); | ||
503 | unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); | ||
504 | int ret; | ||
505 | |||
506 | dev->pg_event = MEI_PG_EVENT_WAIT; | ||
507 | |||
508 | ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_ENTRY_REQ_CMD); | ||
509 | if (ret) | ||
510 | return ret; | ||
511 | |||
512 | mutex_unlock(&dev->device_lock); | ||
513 | wait_event_timeout(dev->wait_pg, | ||
514 | dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout); | ||
515 | mutex_lock(&dev->device_lock); | ||
516 | |||
517 | if (dev->pg_event == MEI_PG_EVENT_RECEIVED) { | ||
518 | mei_me_pg_enter(dev); | ||
519 | ret = 0; | ||
520 | } else { | ||
521 | ret = -ETIME; | ||
522 | } | ||
523 | |||
524 | dev->pg_event = MEI_PG_EVENT_IDLE; | ||
525 | hw->pg_state = MEI_PG_ON; | ||
526 | |||
527 | return ret; | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * mei_me_pg_unset_sync - perform pg exit procedure | ||
532 | * | ||
533 | * @dev: the device structure | ||
534 | * | ||
535 | * returns 0 on success an error code otherwise | ||
536 | */ | ||
537 | int mei_me_pg_unset_sync(struct mei_device *dev) | ||
538 | { | ||
539 | struct mei_me_hw *hw = to_me_hw(dev); | ||
540 | unsigned long timeout = mei_secs_to_jiffies(MEI_PGI_TIMEOUT); | ||
541 | int ret; | ||
542 | |||
543 | if (dev->pg_event == MEI_PG_EVENT_RECEIVED) | ||
544 | goto reply; | ||
545 | |||
546 | dev->pg_event = MEI_PG_EVENT_WAIT; | ||
547 | |||
548 | mei_me_pg_exit(dev); | ||
549 | |||
550 | mutex_unlock(&dev->device_lock); | ||
551 | wait_event_timeout(dev->wait_pg, | ||
552 | dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout); | ||
553 | mutex_lock(&dev->device_lock); | ||
554 | |||
555 | reply: | ||
556 | if (dev->pg_event == MEI_PG_EVENT_RECEIVED) | ||
557 | ret = mei_hbm_pg(dev, MEI_PG_ISOLATION_EXIT_RES_CMD); | ||
558 | else | ||
559 | ret = -ETIME; | ||
560 | |||
561 | dev->pg_event = MEI_PG_EVENT_IDLE; | ||
562 | hw->pg_state = MEI_PG_OFF; | ||
563 | |||
564 | return ret; | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * mei_me_pg_is_enabled - detect if PG is supported by HW | ||
569 | * | ||
570 | * @dev: the device structure | ||
571 | * | ||
572 | * returns: true is pg supported, false otherwise | ||
573 | */ | ||
574 | static bool mei_me_pg_is_enabled(struct mei_device *dev) | ||
575 | { | ||
576 | struct mei_me_hw *hw = to_me_hw(dev); | ||
577 | u32 reg = mei_me_reg_read(hw, ME_CSR_HA); | ||
578 | |||
579 | if ((reg & ME_PGIC_HRA) == 0) | ||
580 | goto notsupported; | ||
581 | |||
582 | if (dev->version.major_version < HBM_MAJOR_VERSION_PGI) | ||
583 | goto notsupported; | ||
584 | |||
585 | if (dev->version.major_version == HBM_MAJOR_VERSION_PGI && | ||
586 | dev->version.minor_version < HBM_MINOR_VERSION_PGI) | ||
587 | goto notsupported; | ||
588 | |||
589 | return true; | ||
590 | |||
591 | notsupported: | ||
592 | dev_dbg(&dev->pdev->dev, "pg: not supported: HGP = %d hbm version %d.%d ?= %d.%d\n", | ||
593 | !!(reg & ME_PGIC_HRA), | ||
594 | dev->version.major_version, | ||
595 | dev->version.minor_version, | ||
596 | HBM_MAJOR_VERSION_PGI, | ||
597 | HBM_MINOR_VERSION_PGI); | ||
598 | |||
599 | return false; | ||
600 | } | ||
601 | |||
602 | /** | ||
434 | * mei_me_irq_quick_handler - The ISR of the MEI device | 603 | * mei_me_irq_quick_handler - The ISR of the MEI device |
435 | * | 604 | * |
436 | * @irq: The irq number | 605 | * @irq: The irq number |
@@ -491,14 +660,13 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
491 | /* check if we need to start the dev */ | 660 | /* check if we need to start the dev */ |
492 | if (!mei_host_is_ready(dev)) { | 661 | if (!mei_host_is_ready(dev)) { |
493 | if (mei_hw_is_ready(dev)) { | 662 | if (mei_hw_is_ready(dev)) { |
663 | mei_me_hw_reset_release(dev); | ||
494 | dev_dbg(&dev->pdev->dev, "we need to start the dev.\n"); | 664 | dev_dbg(&dev->pdev->dev, "we need to start the dev.\n"); |
495 | 665 | ||
496 | dev->recvd_hw_ready = true; | 666 | dev->recvd_hw_ready = true; |
497 | wake_up_interruptible(&dev->wait_hw_ready); | 667 | wake_up_interruptible(&dev->wait_hw_ready); |
498 | } else { | 668 | } else { |
499 | 669 | dev_dbg(&dev->pdev->dev, "Spurious Interrupt\n"); | |
500 | dev_dbg(&dev->pdev->dev, "Reset Completed.\n"); | ||
501 | mei_me_hw_reset_release(dev); | ||
502 | } | 670 | } |
503 | goto end; | 671 | goto end; |
504 | } | 672 | } |
@@ -524,9 +692,15 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
524 | 692 | ||
525 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); | 693 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); |
526 | 694 | ||
527 | rets = mei_irq_write_handler(dev, &complete_list); | 695 | /* |
528 | 696 | * During PG handshake only allowed write is the replay to the | |
529 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); | 697 | * PG exit message, so block calling write function |
698 | * if the pg state is not idle | ||
699 | */ | ||
700 | if (dev->pg_event == MEI_PG_EVENT_IDLE) { | ||
701 | rets = mei_irq_write_handler(dev, &complete_list); | ||
702 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); | ||
703 | } | ||
530 | 704 | ||
531 | mei_irq_compl_handler(dev, &complete_list); | 705 | mei_irq_compl_handler(dev, &complete_list); |
532 | 706 | ||
@@ -535,8 +709,65 @@ end: | |||
535 | mutex_unlock(&dev->device_lock); | 709 | mutex_unlock(&dev->device_lock); |
536 | return IRQ_HANDLED; | 710 | return IRQ_HANDLED; |
537 | } | 711 | } |
712 | |||
713 | /** | ||
714 | * mei_me_fw_status - retrieve fw status from the pci config space | ||
715 | * | ||
716 | * @dev: the device structure | ||
717 | * @fw_status: fw status registers storage | ||
718 | * | ||
719 | * returns 0 on success an error code otherwise | ||
720 | */ | ||
721 | static int mei_me_fw_status(struct mei_device *dev, | ||
722 | struct mei_fw_status *fw_status) | ||
723 | { | ||
724 | const u32 pci_cfg_reg[] = {PCI_CFG_HFS_1, PCI_CFG_HFS_2}; | ||
725 | int i; | ||
726 | |||
727 | if (!fw_status) | ||
728 | return -EINVAL; | ||
729 | |||
730 | switch (dev->pdev->device) { | ||
731 | case MEI_DEV_ID_IBXPK_1: | ||
732 | case MEI_DEV_ID_IBXPK_2: | ||
733 | case MEI_DEV_ID_CPT_1: | ||
734 | case MEI_DEV_ID_PBG_1: | ||
735 | case MEI_DEV_ID_PPT_1: | ||
736 | case MEI_DEV_ID_PPT_2: | ||
737 | case MEI_DEV_ID_PPT_3: | ||
738 | case MEI_DEV_ID_LPT_H: | ||
739 | case MEI_DEV_ID_LPT_W: | ||
740 | case MEI_DEV_ID_LPT_LP: | ||
741 | case MEI_DEV_ID_LPT_HR: | ||
742 | case MEI_DEV_ID_WPT_LP: | ||
743 | fw_status->count = 2; | ||
744 | break; | ||
745 | case MEI_DEV_ID_ICH10_1: | ||
746 | case MEI_DEV_ID_ICH10_2: | ||
747 | case MEI_DEV_ID_ICH10_3: | ||
748 | case MEI_DEV_ID_ICH10_4: | ||
749 | fw_status->count = 1; | ||
750 | break; | ||
751 | default: | ||
752 | fw_status->count = 0; | ||
753 | break; | ||
754 | } | ||
755 | |||
756 | for (i = 0; i < fw_status->count && i < MEI_FW_STATUS_MAX; i++) { | ||
757 | int ret; | ||
758 | ret = pci_read_config_dword(dev->pdev, | ||
759 | pci_cfg_reg[i], &fw_status->status[i]); | ||
760 | if (ret) | ||
761 | return ret; | ||
762 | } | ||
763 | return 0; | ||
764 | } | ||
765 | |||
538 | static const struct mei_hw_ops mei_me_hw_ops = { | 766 | static const struct mei_hw_ops mei_me_hw_ops = { |
539 | 767 | ||
768 | .pg_state = mei_me_pg_state, | ||
769 | |||
770 | .fw_status = mei_me_fw_status, | ||
540 | .host_is_ready = mei_me_host_is_ready, | 771 | .host_is_ready = mei_me_host_is_ready, |
541 | 772 | ||
542 | .hw_is_ready = mei_me_hw_is_ready, | 773 | .hw_is_ready = mei_me_hw_is_ready, |
@@ -544,6 +775,8 @@ static const struct mei_hw_ops mei_me_hw_ops = { | |||
544 | .hw_config = mei_me_hw_config, | 775 | .hw_config = mei_me_hw_config, |
545 | .hw_start = mei_me_hw_start, | 776 | .hw_start = mei_me_hw_start, |
546 | 777 | ||
778 | .pg_is_enabled = mei_me_pg_is_enabled, | ||
779 | |||
547 | .intr_clear = mei_me_intr_clear, | 780 | .intr_clear = mei_me_intr_clear, |
548 | .intr_enable = mei_me_intr_enable, | 781 | .intr_enable = mei_me_intr_enable, |
549 | .intr_disable = mei_me_intr_disable, | 782 | .intr_disable = mei_me_intr_disable, |
@@ -559,14 +792,81 @@ static const struct mei_hw_ops mei_me_hw_ops = { | |||
559 | .read = mei_me_read_slots | 792 | .read = mei_me_read_slots |
560 | }; | 793 | }; |
561 | 794 | ||
795 | static bool mei_me_fw_type_nm(struct pci_dev *pdev) | ||
796 | { | ||
797 | u32 reg; | ||
798 | pci_read_config_dword(pdev, PCI_CFG_HFS_2, ®); | ||
799 | /* make sure that bit 9 (NM) is up and bit 10 (DM) is down */ | ||
800 | return (reg & 0x600) == 0x200; | ||
801 | } | ||
802 | |||
803 | #define MEI_CFG_FW_NM \ | ||
804 | .quirk_probe = mei_me_fw_type_nm | ||
805 | |||
806 | static bool mei_me_fw_type_sps(struct pci_dev *pdev) | ||
807 | { | ||
808 | u32 reg; | ||
809 | /* Read ME FW Status check for SPS Firmware */ | ||
810 | pci_read_config_dword(pdev, PCI_CFG_HFS_1, ®); | ||
811 | /* if bits [19:16] = 15, running SPS Firmware */ | ||
812 | return (reg & 0xf0000) == 0xf0000; | ||
813 | } | ||
814 | |||
815 | #define MEI_CFG_FW_SPS \ | ||
816 | .quirk_probe = mei_me_fw_type_sps | ||
817 | |||
818 | |||
819 | #define MEI_CFG_LEGACY_HFS \ | ||
820 | .fw_status.count = 0 | ||
821 | |||
822 | #define MEI_CFG_ICH_HFS \ | ||
823 | .fw_status.count = 1, \ | ||
824 | .fw_status.status[0] = PCI_CFG_HFS_1 | ||
825 | |||
826 | #define MEI_CFG_PCH_HFS \ | ||
827 | .fw_status.count = 2, \ | ||
828 | .fw_status.status[0] = PCI_CFG_HFS_1, \ | ||
829 | .fw_status.status[1] = PCI_CFG_HFS_2 | ||
830 | |||
831 | |||
832 | /* ICH Legacy devices */ | ||
833 | const struct mei_cfg mei_me_legacy_cfg = { | ||
834 | MEI_CFG_LEGACY_HFS, | ||
835 | }; | ||
836 | |||
837 | /* ICH devices */ | ||
838 | const struct mei_cfg mei_me_ich_cfg = { | ||
839 | MEI_CFG_ICH_HFS, | ||
840 | }; | ||
841 | |||
842 | /* PCH devices */ | ||
843 | const struct mei_cfg mei_me_pch_cfg = { | ||
844 | MEI_CFG_PCH_HFS, | ||
845 | }; | ||
846 | |||
847 | |||
848 | /* PCH Cougar Point and Patsburg with quirk for Node Manager exclusion */ | ||
849 | const struct mei_cfg mei_me_pch_cpt_pbg_cfg = { | ||
850 | MEI_CFG_PCH_HFS, | ||
851 | MEI_CFG_FW_NM, | ||
852 | }; | ||
853 | |||
854 | /* PCH Lynx Point with quirk for SPS Firmware exclusion */ | ||
855 | const struct mei_cfg mei_me_lpt_cfg = { | ||
856 | MEI_CFG_PCH_HFS, | ||
857 | MEI_CFG_FW_SPS, | ||
858 | }; | ||
859 | |||
562 | /** | 860 | /** |
563 | * mei_me_dev_init - allocates and initializes the mei device structure | 861 | * mei_me_dev_init - allocates and initializes the mei device structure |
564 | * | 862 | * |
565 | * @pdev: The pci device structure | 863 | * @pdev: The pci device structure |
864 | * @cfg: per device generation config | ||
566 | * | 865 | * |
567 | * returns The mei_device_device pointer on success, NULL on failure. | 866 | * returns The mei_device_device pointer on success, NULL on failure. |
568 | */ | 867 | */ |
569 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev) | 868 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev, |
869 | const struct mei_cfg *cfg) | ||
570 | { | 870 | { |
571 | struct mei_device *dev; | 871 | struct mei_device *dev; |
572 | 872 | ||
@@ -575,7 +875,7 @@ struct mei_device *mei_me_dev_init(struct pci_dev *pdev) | |||
575 | if (!dev) | 875 | if (!dev) |
576 | return NULL; | 876 | return NULL; |
577 | 877 | ||
578 | mei_device_init(dev); | 878 | mei_device_init(dev, cfg); |
579 | 879 | ||
580 | dev->ops = &mei_me_hw_ops; | 880 | dev->ops = &mei_me_hw_ops; |
581 | 881 | ||
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h index 893d5119fa9b..12b0f4bbe1f1 100644 --- a/drivers/misc/mei/hw-me.h +++ b/drivers/misc/mei/hw-me.h | |||
@@ -24,6 +24,8 @@ | |||
24 | #include "mei_dev.h" | 24 | #include "mei_dev.h" |
25 | #include "client.h" | 25 | #include "client.h" |
26 | 26 | ||
27 | #define MEI_ME_RPM_TIMEOUT 500 /* ms */ | ||
28 | |||
27 | struct mei_me_hw { | 29 | struct mei_me_hw { |
28 | void __iomem *mem_addr; | 30 | void __iomem *mem_addr; |
29 | /* | 31 | /* |
@@ -31,11 +33,22 @@ struct mei_me_hw { | |||
31 | */ | 33 | */ |
32 | u32 host_hw_state; | 34 | u32 host_hw_state; |
33 | u32 me_hw_state; | 35 | u32 me_hw_state; |
36 | enum mei_pg_state pg_state; | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | #define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw) | 39 | #define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw) |
37 | 40 | ||
38 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev); | 41 | extern const struct mei_cfg mei_me_legacy_cfg; |
42 | extern const struct mei_cfg mei_me_ich_cfg; | ||
43 | extern const struct mei_cfg mei_me_pch_cfg; | ||
44 | extern const struct mei_cfg mei_me_pch_cpt_pbg_cfg; | ||
45 | extern const struct mei_cfg mei_me_lpt_cfg; | ||
46 | |||
47 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev, | ||
48 | const struct mei_cfg *cfg); | ||
49 | |||
50 | int mei_me_pg_set_sync(struct mei_device *dev); | ||
51 | int mei_me_pg_unset_sync(struct mei_device *dev); | ||
39 | 52 | ||
40 | irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id); | 53 | irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id); |
41 | irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id); | 54 | irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id); |
diff --git a/drivers/misc/mei/hw-txe-regs.h b/drivers/misc/mei/hw-txe-regs.h index 7283c24c1af1..f19229c4e655 100644 --- a/drivers/misc/mei/hw-txe-regs.h +++ b/drivers/misc/mei/hw-txe-regs.h | |||
@@ -89,7 +89,7 @@ enum { | |||
89 | # define PCI_CFG_TXE_FW_STS0_ERR_CODE_MSK 0x0000F000 | 89 | # define PCI_CFG_TXE_FW_STS0_ERR_CODE_MSK 0x0000F000 |
90 | # define PCI_CFG_TXE_FW_STS0_OP_MODE_MSK 0x000F0000 | 90 | # define PCI_CFG_TXE_FW_STS0_OP_MODE_MSK 0x000F0000 |
91 | # define PCI_CFG_TXE_FW_STS0_RST_CNT_MSK 0x00F00000 | 91 | # define PCI_CFG_TXE_FW_STS0_RST_CNT_MSK 0x00F00000 |
92 | 92 | #define PCI_CFG_TXE_FW_STS1 0x48 | |
93 | 93 | ||
94 | #define IPC_BASE_ADDR 0x80400 /* SeC IPC Base Address */ | 94 | #define IPC_BASE_ADDR 0x80400 /* SeC IPC Base Address */ |
95 | 95 | ||
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index f60182a52f96..93273783dec5 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c | |||
@@ -158,7 +158,7 @@ static bool mei_txe_aliveness_set(struct mei_device *dev, u32 req) | |||
158 | dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n", | 158 | dev_dbg(&dev->pdev->dev, "Aliveness current=%d request=%d\n", |
159 | hw->aliveness, req); | 159 | hw->aliveness, req); |
160 | if (do_req) { | 160 | if (do_req) { |
161 | hw->recvd_aliveness = false; | 161 | dev->pg_event = MEI_PG_EVENT_WAIT; |
162 | mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req); | 162 | mei_txe_br_reg_write(hw, SICR_HOST_ALIVENESS_REQ_REG, req); |
163 | } | 163 | } |
164 | return do_req; | 164 | return do_req; |
@@ -213,6 +213,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected) | |||
213 | do { | 213 | do { |
214 | hw->aliveness = mei_txe_aliveness_get(dev); | 214 | hw->aliveness = mei_txe_aliveness_get(dev); |
215 | if (hw->aliveness == expected) { | 215 | if (hw->aliveness == expected) { |
216 | dev->pg_event = MEI_PG_EVENT_IDLE; | ||
216 | dev_dbg(&dev->pdev->dev, | 217 | dev_dbg(&dev->pdev->dev, |
217 | "aliveness settled after %d msecs\n", t); | 218 | "aliveness settled after %d msecs\n", t); |
218 | return t; | 219 | return t; |
@@ -223,6 +224,7 @@ static int mei_txe_aliveness_poll(struct mei_device *dev, u32 expected) | |||
223 | t += MSEC_PER_SEC / 5; | 224 | t += MSEC_PER_SEC / 5; |
224 | } while (t < SEC_ALIVENESS_WAIT_TIMEOUT); | 225 | } while (t < SEC_ALIVENESS_WAIT_TIMEOUT); |
225 | 226 | ||
227 | dev->pg_event = MEI_PG_EVENT_IDLE; | ||
226 | dev_err(&dev->pdev->dev, "aliveness timed out\n"); | 228 | dev_err(&dev->pdev->dev, "aliveness timed out\n"); |
227 | return -ETIME; | 229 | return -ETIME; |
228 | } | 230 | } |
@@ -249,19 +251,22 @@ static int mei_txe_aliveness_wait(struct mei_device *dev, u32 expected) | |||
249 | return 0; | 251 | return 0; |
250 | 252 | ||
251 | mutex_unlock(&dev->device_lock); | 253 | mutex_unlock(&dev->device_lock); |
252 | err = wait_event_timeout(hw->wait_aliveness, | 254 | err = wait_event_timeout(hw->wait_aliveness_resp, |
253 | hw->recvd_aliveness, timeout); | 255 | dev->pg_event == MEI_PG_EVENT_RECEIVED, timeout); |
254 | mutex_lock(&dev->device_lock); | 256 | mutex_lock(&dev->device_lock); |
255 | 257 | ||
256 | hw->aliveness = mei_txe_aliveness_get(dev); | 258 | hw->aliveness = mei_txe_aliveness_get(dev); |
257 | ret = hw->aliveness == expected ? 0 : -ETIME; | 259 | ret = hw->aliveness == expected ? 0 : -ETIME; |
258 | 260 | ||
259 | if (ret) | 261 | if (ret) |
260 | dev_err(&dev->pdev->dev, "aliveness timed out"); | 262 | dev_warn(&dev->pdev->dev, "aliveness timed out = %ld aliveness = %d event = %d\n", |
263 | err, hw->aliveness, dev->pg_event); | ||
261 | else | 264 | else |
262 | dev_dbg(&dev->pdev->dev, "aliveness settled after %d msecs\n", | 265 | dev_dbg(&dev->pdev->dev, "aliveness settled after = %d msec aliveness = %d event = %d\n", |
263 | jiffies_to_msecs(timeout - err)); | 266 | jiffies_to_msecs(timeout - err), |
264 | hw->recvd_aliveness = false; | 267 | hw->aliveness, dev->pg_event); |
268 | |||
269 | dev->pg_event = MEI_PG_EVENT_IDLE; | ||
265 | return ret; | 270 | return ret; |
266 | } | 271 | } |
267 | 272 | ||
@@ -280,6 +285,32 @@ int mei_txe_aliveness_set_sync(struct mei_device *dev, u32 req) | |||
280 | } | 285 | } |
281 | 286 | ||
282 | /** | 287 | /** |
288 | * mei_txe_pg_is_enabled - detect if PG is supported by HW | ||
289 | * | ||
290 | * @dev: the device structure | ||
291 | * | ||
292 | * returns: true is pg supported, false otherwise | ||
293 | */ | ||
294 | static bool mei_txe_pg_is_enabled(struct mei_device *dev) | ||
295 | { | ||
296 | return true; | ||
297 | } | ||
298 | |||
299 | /** | ||
300 | * mei_txe_pg_state - translate aliveness register value | ||
301 | * to the mei power gating state | ||
302 | * | ||
303 | * @dev: the device structure | ||
304 | * | ||
305 | * returns: MEI_PG_OFF if aliveness is on and MEI_PG_ON otherwise | ||
306 | */ | ||
307 | static inline enum mei_pg_state mei_txe_pg_state(struct mei_device *dev) | ||
308 | { | ||
309 | struct mei_txe_hw *hw = to_txe_hw(dev); | ||
310 | return hw->aliveness ? MEI_PG_OFF : MEI_PG_ON; | ||
311 | } | ||
312 | |||
313 | /** | ||
283 | * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt | 314 | * mei_txe_input_ready_interrupt_enable - sets the Input Ready Interrupt |
284 | * | 315 | * |
285 | * @dev: the device structure | 316 | * @dev: the device structure |
@@ -589,7 +620,10 @@ static int mei_txe_write(struct mei_device *dev, | |||
589 | mei_txe_input_ready_interrupt_enable(dev); | 620 | mei_txe_input_ready_interrupt_enable(dev); |
590 | 621 | ||
591 | if (!mei_txe_is_input_ready(dev)) { | 622 | if (!mei_txe_is_input_ready(dev)) { |
592 | dev_err(&dev->pdev->dev, "Input is not ready"); | 623 | struct mei_fw_status fw_status; |
624 | mei_fw_status(dev, &fw_status); | ||
625 | dev_err(&dev->pdev->dev, "Input is not ready " FW_STS_FMT "\n", | ||
626 | FW_STS_PRM(fw_status)); | ||
593 | return -EAGAIN; | 627 | return -EAGAIN; |
594 | } | 628 | } |
595 | 629 | ||
@@ -960,9 +994,9 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) | |||
960 | /* Clear the interrupt cause */ | 994 | /* Clear the interrupt cause */ |
961 | dev_dbg(&dev->pdev->dev, | 995 | dev_dbg(&dev->pdev->dev, |
962 | "Aliveness Interrupt: Status: %d\n", hw->aliveness); | 996 | "Aliveness Interrupt: Status: %d\n", hw->aliveness); |
963 | hw->recvd_aliveness = true; | 997 | dev->pg_event = MEI_PG_EVENT_RECEIVED; |
964 | if (waitqueue_active(&hw->wait_aliveness)) | 998 | if (waitqueue_active(&hw->wait_aliveness_resp)) |
965 | wake_up(&hw->wait_aliveness); | 999 | wake_up(&hw->wait_aliveness_resp); |
966 | } | 1000 | } |
967 | 1001 | ||
968 | 1002 | ||
@@ -1008,15 +1042,51 @@ end: | |||
1008 | return IRQ_HANDLED; | 1042 | return IRQ_HANDLED; |
1009 | } | 1043 | } |
1010 | 1044 | ||
1045 | |||
1046 | /** | ||
1047 | * mei_txe_fw_status - retrieve fw status from the pci config space | ||
1048 | * | ||
1049 | * @dev: the device structure | ||
1050 | * @fw_status: fw status registers storage | ||
1051 | * | ||
1052 | * returns: 0 on success an error code otherwise | ||
1053 | */ | ||
1054 | static int mei_txe_fw_status(struct mei_device *dev, | ||
1055 | struct mei_fw_status *fw_status) | ||
1056 | { | ||
1057 | const u32 pci_cfg_reg[] = {PCI_CFG_TXE_FW_STS0, PCI_CFG_TXE_FW_STS1}; | ||
1058 | int i; | ||
1059 | |||
1060 | if (!fw_status) | ||
1061 | return -EINVAL; | ||
1062 | |||
1063 | fw_status->count = 2; | ||
1064 | |||
1065 | for (i = 0; i < fw_status->count && i < MEI_FW_STATUS_MAX; i++) { | ||
1066 | int ret; | ||
1067 | ret = pci_read_config_dword(dev->pdev, | ||
1068 | pci_cfg_reg[i], &fw_status->status[i]); | ||
1069 | if (ret) | ||
1070 | return ret; | ||
1071 | } | ||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1011 | static const struct mei_hw_ops mei_txe_hw_ops = { | 1076 | static const struct mei_hw_ops mei_txe_hw_ops = { |
1012 | 1077 | ||
1078 | .fw_status = mei_txe_fw_status, | ||
1013 | .host_is_ready = mei_txe_host_is_ready, | 1079 | .host_is_ready = mei_txe_host_is_ready, |
1014 | 1080 | ||
1081 | .pg_state = mei_txe_pg_state, | ||
1082 | |||
1015 | .hw_is_ready = mei_txe_hw_is_ready, | 1083 | .hw_is_ready = mei_txe_hw_is_ready, |
1016 | .hw_reset = mei_txe_hw_reset, | 1084 | .hw_reset = mei_txe_hw_reset, |
1017 | .hw_config = mei_txe_hw_config, | 1085 | .hw_config = mei_txe_hw_config, |
1018 | .hw_start = mei_txe_hw_start, | 1086 | .hw_start = mei_txe_hw_start, |
1019 | 1087 | ||
1088 | .pg_is_enabled = mei_txe_pg_is_enabled, | ||
1089 | |||
1020 | .intr_clear = mei_txe_intr_clear, | 1090 | .intr_clear = mei_txe_intr_clear, |
1021 | .intr_enable = mei_txe_intr_enable, | 1091 | .intr_enable = mei_txe_intr_enable, |
1022 | .intr_disable = mei_txe_intr_disable, | 1092 | .intr_disable = mei_txe_intr_disable, |
@@ -1034,14 +1104,27 @@ static const struct mei_hw_ops mei_txe_hw_ops = { | |||
1034 | 1104 | ||
1035 | }; | 1105 | }; |
1036 | 1106 | ||
1107 | #define MEI_CFG_TXE_FW_STS \ | ||
1108 | .fw_status.count = 2, \ | ||
1109 | .fw_status.status[0] = PCI_CFG_TXE_FW_STS0, \ | ||
1110 | .fw_status.status[1] = PCI_CFG_TXE_FW_STS1 | ||
1111 | |||
1112 | const struct mei_cfg mei_txe_cfg = { | ||
1113 | MEI_CFG_TXE_FW_STS, | ||
1114 | }; | ||
1115 | |||
1116 | |||
1037 | /** | 1117 | /** |
1038 | * mei_txe_dev_init - allocates and initializes txe hardware specific structure | 1118 | * mei_txe_dev_init - allocates and initializes txe hardware specific structure |
1039 | * | 1119 | * |
1040 | * @pdev - pci device | 1120 | * @pdev - pci device |
1121 | * @cfg - per device generation config | ||
1122 | * | ||
1041 | * returns struct mei_device * on success or NULL; | 1123 | * returns struct mei_device * on success or NULL; |
1042 | * | 1124 | * |
1043 | */ | 1125 | */ |
1044 | struct mei_device *mei_txe_dev_init(struct pci_dev *pdev) | 1126 | struct mei_device *mei_txe_dev_init(struct pci_dev *pdev, |
1127 | const struct mei_cfg *cfg) | ||
1045 | { | 1128 | { |
1046 | struct mei_device *dev; | 1129 | struct mei_device *dev; |
1047 | struct mei_txe_hw *hw; | 1130 | struct mei_txe_hw *hw; |
@@ -1051,11 +1134,11 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev) | |||
1051 | if (!dev) | 1134 | if (!dev) |
1052 | return NULL; | 1135 | return NULL; |
1053 | 1136 | ||
1054 | mei_device_init(dev); | 1137 | mei_device_init(dev, cfg); |
1055 | 1138 | ||
1056 | hw = to_txe_hw(dev); | 1139 | hw = to_txe_hw(dev); |
1057 | 1140 | ||
1058 | init_waitqueue_head(&hw->wait_aliveness); | 1141 | init_waitqueue_head(&hw->wait_aliveness_resp); |
1059 | 1142 | ||
1060 | dev->ops = &mei_txe_hw_ops; | 1143 | dev->ops = &mei_txe_hw_ops; |
1061 | 1144 | ||
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h index 0812d98633a4..e244af79167f 100644 --- a/drivers/misc/mei/hw-txe.h +++ b/drivers/misc/mei/hw-txe.h | |||
@@ -22,6 +22,8 @@ | |||
22 | #include "hw.h" | 22 | #include "hw.h" |
23 | #include "hw-txe-regs.h" | 23 | #include "hw-txe-regs.h" |
24 | 24 | ||
25 | #define MEI_TXI_RPM_TIMEOUT 500 /* ms */ | ||
26 | |||
25 | /* Flatten Hierarchy interrupt cause */ | 27 | /* Flatten Hierarchy interrupt cause */ |
26 | #define TXE_INTR_READINESS_BIT 0 /* HISR_INT_0_STS */ | 28 | #define TXE_INTR_READINESS_BIT 0 /* HISR_INT_0_STS */ |
27 | #define TXE_INTR_READINESS HISR_INT_0_STS | 29 | #define TXE_INTR_READINESS HISR_INT_0_STS |
@@ -35,12 +37,11 @@ | |||
35 | /** | 37 | /** |
36 | * struct mei_txe_hw - txe hardware specifics | 38 | * struct mei_txe_hw - txe hardware specifics |
37 | * | 39 | * |
38 | * @mem_addr: SeC and BRIDGE bars | 40 | * @mem_addr: SeC and BRIDGE bars |
39 | * @aliveness: aliveness (power gating) state of the hardware | 41 | * @aliveness: aliveness (power gating) state of the hardware |
40 | * @readiness: readiness state of the hardware | 42 | * @readiness: readiness state of the hardware |
41 | * @wait_aliveness: aliveness wait queue | 43 | * @wait_aliveness_resp: aliveness wait queue |
42 | * @recvd_aliveness: aliveness interrupt was recived | 44 | * @intr_cause: translated interrupt cause |
43 | * @intr_cause: translated interrupt cause | ||
44 | */ | 45 | */ |
45 | struct mei_txe_hw { | 46 | struct mei_txe_hw { |
46 | void __iomem *mem_addr[NUM_OF_MEM_BARS]; | 47 | void __iomem *mem_addr[NUM_OF_MEM_BARS]; |
@@ -48,8 +49,7 @@ struct mei_txe_hw { | |||
48 | u32 readiness; | 49 | u32 readiness; |
49 | u32 slots; | 50 | u32 slots; |
50 | 51 | ||
51 | wait_queue_head_t wait_aliveness; | 52 | wait_queue_head_t wait_aliveness_resp; |
52 | bool recvd_aliveness; | ||
53 | 53 | ||
54 | unsigned long intr_cause; | 54 | unsigned long intr_cause; |
55 | }; | 55 | }; |
@@ -61,7 +61,10 @@ static inline struct mei_device *hw_txe_to_mei(struct mei_txe_hw *hw) | |||
61 | return container_of((void *)hw, struct mei_device, hw); | 61 | return container_of((void *)hw, struct mei_device, hw); |
62 | } | 62 | } |
63 | 63 | ||
64 | struct mei_device *mei_txe_dev_init(struct pci_dev *pdev); | 64 | extern const struct mei_cfg mei_txe_cfg; |
65 | |||
66 | struct mei_device *mei_txe_dev_init(struct pci_dev *pdev, | ||
67 | const struct mei_cfg *cfg); | ||
65 | 68 | ||
66 | irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id); | 69 | irqreturn_t mei_txe_irq_quick_handler(int irq, void *dev_id); |
67 | irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id); | 70 | irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id); |
diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 6b476ab49b2e..dd448e58cc87 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h | |||
@@ -31,14 +31,21 @@ | |||
31 | #define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ | 31 | #define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ |
32 | #define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ | 32 | #define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ |
33 | 33 | ||
34 | #define MEI_PGI_TIMEOUT 1 /* PG Isolation time response 1 sec */ | ||
34 | #define MEI_HBM_TIMEOUT 1 /* 1 second */ | 35 | #define MEI_HBM_TIMEOUT 1 /* 1 second */ |
35 | 36 | ||
36 | /* | 37 | /* |
37 | * MEI Version | 38 | * MEI Version |
38 | */ | 39 | */ |
39 | #define HBM_MINOR_VERSION 0 | 40 | #define HBM_MINOR_VERSION 1 |
40 | #define HBM_MAJOR_VERSION 1 | 41 | #define HBM_MAJOR_VERSION 1 |
41 | 42 | ||
43 | /* | ||
44 | * MEI version with PGI support | ||
45 | */ | ||
46 | #define HBM_MINOR_VERSION_PGI 1 | ||
47 | #define HBM_MAJOR_VERSION_PGI 1 | ||
48 | |||
42 | /* Host bus message command opcode */ | 49 | /* Host bus message command opcode */ |
43 | #define MEI_HBM_CMD_OP_MSK 0x7f | 50 | #define MEI_HBM_CMD_OP_MSK 0x7f |
44 | /* Host bus message command RESPONSE */ | 51 | /* Host bus message command RESPONSE */ |
@@ -69,6 +76,11 @@ | |||
69 | 76 | ||
70 | #define MEI_FLOW_CONTROL_CMD 0x08 | 77 | #define MEI_FLOW_CONTROL_CMD 0x08 |
71 | 78 | ||
79 | #define MEI_PG_ISOLATION_ENTRY_REQ_CMD 0x0a | ||
80 | #define MEI_PG_ISOLATION_ENTRY_RES_CMD 0x8a | ||
81 | #define MEI_PG_ISOLATION_EXIT_REQ_CMD 0x0b | ||
82 | #define MEI_PG_ISOLATION_EXIT_RES_CMD 0x8b | ||
83 | |||
72 | /* | 84 | /* |
73 | * MEI Stop Reason | 85 | * MEI Stop Reason |
74 | * used by hbm_host_stop_request.reason | 86 | * used by hbm_host_stop_request.reason |
@@ -208,6 +220,17 @@ struct hbm_props_response { | |||
208 | } __packed; | 220 | } __packed; |
209 | 221 | ||
210 | /** | 222 | /** |
223 | * struct hbm_power_gate - power gate request/response | ||
224 | * | ||
225 | * @hbm_cmd - bus message command header | ||
226 | * @reserved[3] | ||
227 | */ | ||
228 | struct hbm_power_gate { | ||
229 | u8 hbm_cmd; | ||
230 | u8 reserved[3]; | ||
231 | } __packed; | ||
232 | |||
233 | /** | ||
211 | * struct hbm_client_connect_request - connect/disconnect request | 234 | * struct hbm_client_connect_request - connect/disconnect request |
212 | * | 235 | * |
213 | * @hbm_cmd - bus message command header | 236 | * @hbm_cmd - bus message command header |
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 4460975c0eef..006929222481 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
@@ -74,9 +74,13 @@ int mei_reset(struct mei_device *dev) | |||
74 | if (state != MEI_DEV_INITIALIZING && | 74 | if (state != MEI_DEV_INITIALIZING && |
75 | state != MEI_DEV_DISABLED && | 75 | state != MEI_DEV_DISABLED && |
76 | state != MEI_DEV_POWER_DOWN && | 76 | state != MEI_DEV_POWER_DOWN && |
77 | state != MEI_DEV_POWER_UP) | 77 | state != MEI_DEV_POWER_UP) { |
78 | dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", | 78 | struct mei_fw_status fw_status; |
79 | mei_dev_state_str(state)); | 79 | mei_fw_status(dev, &fw_status); |
80 | dev_warn(&dev->pdev->dev, | ||
81 | "unexpected reset: dev_state = %s " FW_STS_FMT "\n", | ||
82 | mei_dev_state_str(state), FW_STS_PRM(fw_status)); | ||
83 | } | ||
80 | 84 | ||
81 | /* we're already in reset, cancel the init timer | 85 | /* we're already in reset, cancel the init timer |
82 | * if the reset was called due the hbm protocol error | 86 | * if the reset was called due the hbm protocol error |
@@ -118,8 +122,8 @@ int mei_reset(struct mei_device *dev) | |||
118 | mei_amthif_reset_params(dev); | 122 | mei_amthif_reset_params(dev); |
119 | } | 123 | } |
120 | 124 | ||
125 | mei_hbm_reset(dev); | ||
121 | 126 | ||
122 | dev->me_clients_num = 0; | ||
123 | dev->rd_msg_hdr = 0; | 127 | dev->rd_msg_hdr = 0; |
124 | dev->wd_pending = false; | 128 | dev->wd_pending = false; |
125 | 129 | ||
@@ -303,15 +307,58 @@ void mei_stop(struct mei_device *dev) | |||
303 | } | 307 | } |
304 | EXPORT_SYMBOL_GPL(mei_stop); | 308 | EXPORT_SYMBOL_GPL(mei_stop); |
305 | 309 | ||
310 | /** | ||
311 | * mei_write_is_idle - check if the write queues are idle | ||
312 | * | ||
313 | * @dev: the device structure | ||
314 | * | ||
315 | * returns true of there is no pending write | ||
316 | */ | ||
317 | bool mei_write_is_idle(struct mei_device *dev) | ||
318 | { | ||
319 | bool idle = (dev->dev_state == MEI_DEV_ENABLED && | ||
320 | list_empty(&dev->ctrl_wr_list.list) && | ||
321 | list_empty(&dev->write_list.list)); | ||
306 | 322 | ||
323 | dev_dbg(&dev->pdev->dev, "write pg: is idle[%d] state=%s ctrl=%d write=%d\n", | ||
324 | idle, | ||
325 | mei_dev_state_str(dev->dev_state), | ||
326 | list_empty(&dev->ctrl_wr_list.list), | ||
327 | list_empty(&dev->write_list.list)); | ||
307 | 328 | ||
308 | void mei_device_init(struct mei_device *dev) | 329 | return idle; |
330 | } | ||
331 | EXPORT_SYMBOL_GPL(mei_write_is_idle); | ||
332 | |||
333 | int mei_fw_status(struct mei_device *dev, struct mei_fw_status *fw_status) | ||
334 | { | ||
335 | int i; | ||
336 | const struct mei_fw_status *fw_src = &dev->cfg->fw_status; | ||
337 | |||
338 | if (!fw_status) | ||
339 | return -EINVAL; | ||
340 | |||
341 | fw_status->count = fw_src->count; | ||
342 | for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) { | ||
343 | int ret; | ||
344 | ret = pci_read_config_dword(dev->pdev, | ||
345 | fw_src->status[i], &fw_status->status[i]); | ||
346 | if (ret) | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | EXPORT_SYMBOL_GPL(mei_fw_status); | ||
353 | |||
354 | void mei_device_init(struct mei_device *dev, const struct mei_cfg *cfg) | ||
309 | { | 355 | { |
310 | /* setup our list array */ | 356 | /* setup our list array */ |
311 | INIT_LIST_HEAD(&dev->file_list); | 357 | INIT_LIST_HEAD(&dev->file_list); |
312 | INIT_LIST_HEAD(&dev->device_list); | 358 | INIT_LIST_HEAD(&dev->device_list); |
313 | mutex_init(&dev->device_lock); | 359 | mutex_init(&dev->device_lock); |
314 | init_waitqueue_head(&dev->wait_hw_ready); | 360 | init_waitqueue_head(&dev->wait_hw_ready); |
361 | init_waitqueue_head(&dev->wait_pg); | ||
315 | init_waitqueue_head(&dev->wait_recvd_msg); | 362 | init_waitqueue_head(&dev->wait_recvd_msg); |
316 | init_waitqueue_head(&dev->wait_stop_wd); | 363 | init_waitqueue_head(&dev->wait_stop_wd); |
317 | dev->dev_state = MEI_DEV_INITIALIZING; | 364 | dev->dev_state = MEI_DEV_INITIALIZING; |
@@ -340,6 +387,9 @@ void mei_device_init(struct mei_device *dev) | |||
340 | * 0: Reserved for MEI Bus Message communications | 387 | * 0: Reserved for MEI Bus Message communications |
341 | */ | 388 | */ |
342 | bitmap_set(dev->host_clients_map, 0, 1); | 389 | bitmap_set(dev->host_clients_map, 0, 1); |
390 | |||
391 | dev->pg_event = MEI_PG_EVENT_IDLE; | ||
392 | dev->cfg = cfg; | ||
343 | } | 393 | } |
344 | EXPORT_SYMBOL_GPL(mei_device_init); | 394 | EXPORT_SYMBOL_GPL(mei_device_init); |
345 | 395 | ||
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 147413145c97..66f0a1a06451 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -467,7 +467,6 @@ static int mei_ioctl_connect_client(struct file *file, | |||
467 | } | 467 | } |
468 | 468 | ||
469 | cl->me_client_id = dev->me_clients[i].client_id; | 469 | cl->me_client_id = dev->me_clients[i].client_id; |
470 | cl->state = MEI_FILE_CONNECTING; | ||
471 | 470 | ||
472 | dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", | 471 | dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n", |
473 | cl->me_client_id); | 472 | cl->me_client_id); |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 94a516716d22..5c7e990e2f22 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -153,6 +153,20 @@ struct mei_msg_data { | |||
153 | unsigned char *data; | 153 | unsigned char *data; |
154 | }; | 154 | }; |
155 | 155 | ||
156 | /* Maximum number of processed FW status registers */ | ||
157 | #define MEI_FW_STATUS_MAX 2 | ||
158 | |||
159 | /* | ||
160 | * struct mei_fw_status - storage of FW status data | ||
161 | * | ||
162 | * @count - number of actually available elements in array | ||
163 | * @status - FW status registers | ||
164 | */ | ||
165 | struct mei_fw_status { | ||
166 | int count; | ||
167 | u32 status[MEI_FW_STATUS_MAX]; | ||
168 | }; | ||
169 | |||
156 | /** | 170 | /** |
157 | * struct mei_me_client - representation of me (fw) client | 171 | * struct mei_me_client - representation of me (fw) client |
158 | * | 172 | * |
@@ -213,6 +227,7 @@ struct mei_cl { | |||
213 | 227 | ||
214 | /** struct mei_hw_ops | 228 | /** struct mei_hw_ops |
215 | * | 229 | * |
230 | * @fw_status - read FW status from PCI config space | ||
216 | * @host_is_ready - query for host readiness | 231 | * @host_is_ready - query for host readiness |
217 | 232 | ||
218 | * @hw_is_ready - query if hw is ready | 233 | * @hw_is_ready - query if hw is ready |
@@ -220,6 +235,9 @@ struct mei_cl { | |||
220 | * @hw_start - start hw after reset | 235 | * @hw_start - start hw after reset |
221 | * @hw_config - configure hw | 236 | * @hw_config - configure hw |
222 | 237 | ||
238 | * @pg_state - power gating state of the device | ||
239 | * @pg_is_enabled - is power gating enabled | ||
240 | |||
223 | * @intr_clear - clear pending interrupts | 241 | * @intr_clear - clear pending interrupts |
224 | * @intr_enable - enable interrupts | 242 | * @intr_enable - enable interrupts |
225 | * @intr_disable - disable interrupts | 243 | * @intr_disable - disable interrupts |
@@ -237,6 +255,8 @@ struct mei_cl { | |||
237 | */ | 255 | */ |
238 | struct mei_hw_ops { | 256 | struct mei_hw_ops { |
239 | 257 | ||
258 | int (*fw_status)(struct mei_device *dev, | ||
259 | struct mei_fw_status *fw_status); | ||
240 | bool (*host_is_ready)(struct mei_device *dev); | 260 | bool (*host_is_ready)(struct mei_device *dev); |
241 | 261 | ||
242 | bool (*hw_is_ready)(struct mei_device *dev); | 262 | bool (*hw_is_ready)(struct mei_device *dev); |
@@ -244,6 +264,9 @@ struct mei_hw_ops { | |||
244 | int (*hw_start)(struct mei_device *dev); | 264 | int (*hw_start)(struct mei_device *dev); |
245 | void (*hw_config)(struct mei_device *dev); | 265 | void (*hw_config)(struct mei_device *dev); |
246 | 266 | ||
267 | enum mei_pg_state (*pg_state)(struct mei_device *dev); | ||
268 | bool (*pg_is_enabled)(struct mei_device *dev); | ||
269 | |||
247 | void (*intr_clear)(struct mei_device *dev); | 270 | void (*intr_clear)(struct mei_device *dev); |
248 | void (*intr_enable)(struct mei_device *dev); | 271 | void (*intr_enable)(struct mei_device *dev); |
249 | void (*intr_disable)(struct mei_device *dev); | 272 | void (*intr_disable)(struct mei_device *dev); |
@@ -331,16 +354,61 @@ struct mei_cl_device { | |||
331 | void *priv_data; | 354 | void *priv_data; |
332 | }; | 355 | }; |
333 | 356 | ||
357 | |||
358 | /** | ||
359 | * enum mei_pg_event - power gating transition events | ||
360 | * | ||
361 | * @MEI_PG_EVENT_IDLE: the driver is not in power gating transition | ||
362 | * @MEI_PG_EVENT_WAIT: the driver is waiting for a pg event to complete | ||
363 | * @MEI_PG_EVENT_RECEIVED: the driver received pg event | ||
364 | */ | ||
365 | enum mei_pg_event { | ||
366 | MEI_PG_EVENT_IDLE, | ||
367 | MEI_PG_EVENT_WAIT, | ||
368 | MEI_PG_EVENT_RECEIVED, | ||
369 | }; | ||
370 | |||
371 | /** | ||
372 | * enum mei_pg_state - device internal power gating state | ||
373 | * | ||
374 | * @MEI_PG_OFF: device is not power gated - it is active | ||
375 | * @MEI_PG_ON: device is power gated - it is in lower power state | ||
376 | */ | ||
377 | enum mei_pg_state { | ||
378 | MEI_PG_OFF = 0, | ||
379 | MEI_PG_ON = 1, | ||
380 | }; | ||
381 | |||
382 | /* | ||
383 | * mei_cfg | ||
384 | * | ||
385 | * @fw_status - FW status | ||
386 | * @quirk_probe - device exclusion quirk | ||
387 | */ | ||
388 | struct mei_cfg { | ||
389 | const struct mei_fw_status fw_status; | ||
390 | bool (*quirk_probe)(struct pci_dev *pdev); | ||
391 | }; | ||
392 | |||
393 | |||
394 | #define MEI_PCI_DEVICE(dev, cfg) \ | ||
395 | .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ | ||
396 | .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ | ||
397 | .driver_data = (kernel_ulong_t)&(cfg) | ||
398 | |||
399 | |||
334 | /** | 400 | /** |
335 | * struct mei_device - MEI private device struct | 401 | * struct mei_device - MEI private device struct |
336 | 402 | ||
337 | * @reset_count - limits the number of consecutive resets | 403 | * @reset_count - limits the number of consecutive resets |
338 | * @hbm_state - state of host bus message protocol | 404 | * @hbm_state - state of host bus message protocol |
405 | * @pg_event - power gating event | ||
339 | * @mem_addr - mem mapped base register address | 406 | * @mem_addr - mem mapped base register address |
340 | 407 | ||
341 | * @hbuf_depth - depth of hardware host/write buffer is slots | 408 | * @hbuf_depth - depth of hardware host/write buffer is slots |
342 | * @hbuf_is_ready - query if the host host/write buffer is ready | 409 | * @hbuf_is_ready - query if the host host/write buffer is ready |
343 | * @wr_msg - the buffer for hbm control messages | 410 | * @wr_msg - the buffer for hbm control messages |
411 | * @cfg - per device generation config and ops | ||
344 | */ | 412 | */ |
345 | struct mei_device { | 413 | struct mei_device { |
346 | struct pci_dev *pdev; /* pointer to pci device struct */ | 414 | struct pci_dev *pdev; /* pointer to pci device struct */ |
@@ -371,6 +439,7 @@ struct mei_device { | |||
371 | * waiting queue for receive message from FW | 439 | * waiting queue for receive message from FW |
372 | */ | 440 | */ |
373 | wait_queue_head_t wait_hw_ready; | 441 | wait_queue_head_t wait_hw_ready; |
442 | wait_queue_head_t wait_pg; | ||
374 | wait_queue_head_t wait_recvd_msg; | 443 | wait_queue_head_t wait_recvd_msg; |
375 | wait_queue_head_t wait_stop_wd; | 444 | wait_queue_head_t wait_stop_wd; |
376 | 445 | ||
@@ -382,6 +451,14 @@ struct mei_device { | |||
382 | enum mei_hbm_state hbm_state; | 451 | enum mei_hbm_state hbm_state; |
383 | u16 init_clients_timer; | 452 | u16 init_clients_timer; |
384 | 453 | ||
454 | /* | ||
455 | * Power Gating support | ||
456 | */ | ||
457 | enum mei_pg_event pg_event; | ||
458 | #ifdef CONFIG_PM_RUNTIME | ||
459 | struct dev_pm_domain pg_domain; | ||
460 | #endif /* CONFIG_PM_RUNTIME */ | ||
461 | |||
385 | unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ | 462 | unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ |
386 | u32 rd_msg_hdr; | 463 | u32 rd_msg_hdr; |
387 | 464 | ||
@@ -442,6 +519,7 @@ struct mei_device { | |||
442 | 519 | ||
443 | 520 | ||
444 | const struct mei_hw_ops *ops; | 521 | const struct mei_hw_ops *ops; |
522 | const struct mei_cfg *cfg; | ||
445 | char hw[0] __aligned(sizeof(void *)); | 523 | char hw[0] __aligned(sizeof(void *)); |
446 | }; | 524 | }; |
447 | 525 | ||
@@ -474,7 +552,7 @@ static inline u32 mei_slots2data(int slots) | |||
474 | /* | 552 | /* |
475 | * mei init function prototypes | 553 | * mei init function prototypes |
476 | */ | 554 | */ |
477 | void mei_device_init(struct mei_device *dev); | 555 | void mei_device_init(struct mei_device *dev, const struct mei_cfg *cfg); |
478 | int mei_reset(struct mei_device *dev); | 556 | int mei_reset(struct mei_device *dev); |
479 | int mei_start(struct mei_device *dev); | 557 | int mei_start(struct mei_device *dev); |
480 | int mei_restart(struct mei_device *dev); | 558 | int mei_restart(struct mei_device *dev); |
@@ -553,10 +631,22 @@ void mei_watchdog_unregister(struct mei_device *dev); | |||
553 | * Register Access Function | 631 | * Register Access Function |
554 | */ | 632 | */ |
555 | 633 | ||
634 | |||
556 | static inline void mei_hw_config(struct mei_device *dev) | 635 | static inline void mei_hw_config(struct mei_device *dev) |
557 | { | 636 | { |
558 | dev->ops->hw_config(dev); | 637 | dev->ops->hw_config(dev); |
559 | } | 638 | } |
639 | |||
640 | static inline enum mei_pg_state mei_pg_state(struct mei_device *dev) | ||
641 | { | ||
642 | return dev->ops->pg_state(dev); | ||
643 | } | ||
644 | |||
645 | static inline bool mei_pg_is_enabled(struct mei_device *dev) | ||
646 | { | ||
647 | return dev->ops->pg_is_enabled(dev); | ||
648 | } | ||
649 | |||
560 | static inline int mei_hw_reset(struct mei_device *dev, bool enable) | 650 | static inline int mei_hw_reset(struct mei_device *dev, bool enable) |
561 | { | 651 | { |
562 | return dev->ops->hw_reset(dev, enable); | 652 | return dev->ops->hw_reset(dev, enable); |
@@ -629,8 +719,17 @@ static inline int mei_count_full_read_slots(struct mei_device *dev) | |||
629 | return dev->ops->rdbuf_full_slots(dev); | 719 | return dev->ops->rdbuf_full_slots(dev); |
630 | } | 720 | } |
631 | 721 | ||
722 | int mei_fw_status(struct mei_device *dev, struct mei_fw_status *fw_status); | ||
723 | |||
724 | #define FW_STS_FMT "%08X %08X" | ||
725 | #define FW_STS_PRM(fw_status) \ | ||
726 | (fw_status).count > 0 ? (fw_status).status[0] : 0xDEADBEEF, \ | ||
727 | (fw_status).count > 1 ? (fw_status).status[1] : 0xDEADBEEF | ||
728 | |||
632 | bool mei_hbuf_acquire(struct mei_device *dev); | 729 | bool mei_hbuf_acquire(struct mei_device *dev); |
633 | 730 | ||
731 | bool mei_write_is_idle(struct mei_device *dev); | ||
732 | |||
634 | #if IS_ENABLED(CONFIG_DEBUG_FS) | 733 | #if IS_ENABLED(CONFIG_DEBUG_FS) |
635 | int mei_dbgfs_register(struct mei_device *dev, const char *name); | 734 | int mei_dbgfs_register(struct mei_device *dev, const char *name); |
636 | void mei_dbgfs_deregister(struct mei_device *dev); | 735 | void mei_dbgfs_deregister(struct mei_device *dev); |
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 95889e2e31ff..1b46c64a649f 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
34 | #include <linux/miscdevice.h> | 34 | #include <linux/miscdevice.h> |
35 | 35 | ||
36 | #include <linux/pm_runtime.h> | ||
37 | |||
36 | #include <linux/mei.h> | 38 | #include <linux/mei.h> |
37 | 39 | ||
38 | #include "mei_dev.h" | 40 | #include "mei_dev.h" |
@@ -42,42 +44,44 @@ | |||
42 | 44 | ||
43 | /* mei_pci_tbl - PCI Device ID Table */ | 45 | /* mei_pci_tbl - PCI Device ID Table */ |
44 | static const struct pci_device_id mei_me_pci_tbl[] = { | 46 | static const struct pci_device_id mei_me_pci_tbl[] = { |
45 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)}, | 47 | {MEI_PCI_DEVICE(MEI_DEV_ID_82946GZ, mei_me_legacy_cfg)}, |
46 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)}, | 48 | {MEI_PCI_DEVICE(MEI_DEV_ID_82G35, mei_me_legacy_cfg)}, |
47 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)}, | 49 | {MEI_PCI_DEVICE(MEI_DEV_ID_82Q965, mei_me_legacy_cfg)}, |
48 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)}, | 50 | {MEI_PCI_DEVICE(MEI_DEV_ID_82G965, mei_me_legacy_cfg)}, |
49 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)}, | 51 | {MEI_PCI_DEVICE(MEI_DEV_ID_82GM965, mei_me_legacy_cfg)}, |
50 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)}, | 52 | {MEI_PCI_DEVICE(MEI_DEV_ID_82GME965, mei_me_legacy_cfg)}, |
51 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)}, | 53 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82Q35, mei_me_legacy_cfg)}, |
52 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)}, | 54 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82G33, mei_me_legacy_cfg)}, |
53 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)}, | 55 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82Q33, mei_me_legacy_cfg)}, |
54 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)}, | 56 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82X38, mei_me_legacy_cfg)}, |
55 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)}, | 57 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_3200, mei_me_legacy_cfg)}, |
56 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)}, | 58 | |
57 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)}, | 59 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_6, mei_me_legacy_cfg)}, |
58 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)}, | 60 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_7, mei_me_legacy_cfg)}, |
59 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)}, | 61 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_8, mei_me_legacy_cfg)}, |
60 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)}, | 62 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_9, mei_me_legacy_cfg)}, |
61 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)}, | 63 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_10, mei_me_legacy_cfg)}, |
62 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)}, | 64 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_1, mei_me_legacy_cfg)}, |
63 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)}, | 65 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_2, mei_me_legacy_cfg)}, |
64 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)}, | 66 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_3, mei_me_legacy_cfg)}, |
65 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)}, | 67 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_4, mei_me_legacy_cfg)}, |
66 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)}, | 68 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_1, mei_me_ich_cfg)}, |
67 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)}, | 69 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_2, mei_me_ich_cfg)}, |
68 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)}, | 70 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_3, mei_me_ich_cfg)}, |
69 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)}, | 71 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_4, mei_me_ich_cfg)}, |
70 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)}, | 72 | |
71 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)}, | 73 | {MEI_PCI_DEVICE(MEI_DEV_ID_IBXPK_1, mei_me_pch_cfg)}, |
72 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)}, | 74 | {MEI_PCI_DEVICE(MEI_DEV_ID_IBXPK_2, mei_me_pch_cfg)}, |
73 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)}, | 75 | {MEI_PCI_DEVICE(MEI_DEV_ID_CPT_1, mei_me_pch_cpt_pbg_cfg)}, |
74 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)}, | 76 | {MEI_PCI_DEVICE(MEI_DEV_ID_PBG_1, mei_me_pch_cpt_pbg_cfg)}, |
75 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)}, | 77 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_1, mei_me_pch_cfg)}, |
76 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_H)}, | 78 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_2, mei_me_pch_cfg)}, |
77 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_W)}, | 79 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_3, mei_me_pch_cfg)}, |
78 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)}, | 80 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_H, mei_me_lpt_cfg)}, |
79 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_HR)}, | 81 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_W, mei_me_lpt_cfg)}, |
80 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_WPT_LP)}, | 82 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_LP, mei_me_pch_cfg)}, |
83 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_HR, mei_me_lpt_cfg)}, | ||
84 | {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, mei_me_pch_cfg)}, | ||
81 | 85 | ||
82 | /* required last entry */ | 86 | /* required last entry */ |
83 | {0, } | 87 | {0, } |
@@ -85,44 +89,33 @@ static const struct pci_device_id mei_me_pci_tbl[] = { | |||
85 | 89 | ||
86 | MODULE_DEVICE_TABLE(pci, mei_me_pci_tbl); | 90 | MODULE_DEVICE_TABLE(pci, mei_me_pci_tbl); |
87 | 91 | ||
92 | #ifdef CONFIG_PM_RUNTIME | ||
93 | static inline void mei_me_set_pm_domain(struct mei_device *dev); | ||
94 | static inline void mei_me_unset_pm_domain(struct mei_device *dev); | ||
95 | #else | ||
96 | static inline void mei_me_set_pm_domain(struct mei_device *dev) {} | ||
97 | static inline void mei_me_unset_pm_domain(struct mei_device *dev) {} | ||
98 | #endif /* CONFIG_PM_RUNTIME */ | ||
99 | |||
88 | /** | 100 | /** |
89 | * mei_quirk_probe - probe for devices that doesn't valid ME interface | 101 | * mei_quirk_probe - probe for devices that doesn't valid ME interface |
90 | * | 102 | * |
91 | * @pdev: PCI device structure | 103 | * @pdev: PCI device structure |
92 | * @ent: entry into pci_device_table | 104 | * @cfg: per generation config |
93 | * | 105 | * |
94 | * returns true if ME Interface is valid, false otherwise | 106 | * returns true if ME Interface is valid, false otherwise |
95 | */ | 107 | */ |
96 | static bool mei_me_quirk_probe(struct pci_dev *pdev, | 108 | static bool mei_me_quirk_probe(struct pci_dev *pdev, |
97 | const struct pci_device_id *ent) | 109 | const struct mei_cfg *cfg) |
98 | { | 110 | { |
99 | u32 reg; | 111 | if (cfg->quirk_probe && cfg->quirk_probe(pdev)) { |
100 | /* Cougar Point || Patsburg */ | 112 | dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n"); |
101 | if (ent->device == MEI_DEV_ID_CPT_1 || | 113 | return false; |
102 | ent->device == MEI_DEV_ID_PBG_1) { | ||
103 | pci_read_config_dword(pdev, PCI_CFG_HFS_2, ®); | ||
104 | /* make sure that bit 9 (NM) is up and bit 10 (DM) is down */ | ||
105 | if ((reg & 0x600) == 0x200) | ||
106 | goto no_mei; | ||
107 | } | ||
108 | |||
109 | /* Lynx Point */ | ||
110 | if (ent->device == MEI_DEV_ID_LPT_H || | ||
111 | ent->device == MEI_DEV_ID_LPT_W || | ||
112 | ent->device == MEI_DEV_ID_LPT_HR) { | ||
113 | /* Read ME FW Status check for SPS Firmware */ | ||
114 | pci_read_config_dword(pdev, PCI_CFG_HFS_1, ®); | ||
115 | /* if bits [19:16] = 15, running SPS Firmware */ | ||
116 | if ((reg & 0xf0000) == 0xf0000) | ||
117 | goto no_mei; | ||
118 | } | 114 | } |
119 | 115 | ||
120 | return true; | 116 | return true; |
121 | |||
122 | no_mei: | ||
123 | dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n"); | ||
124 | return false; | ||
125 | } | 117 | } |
118 | |||
126 | /** | 119 | /** |
127 | * mei_probe - Device Initialization Routine | 120 | * mei_probe - Device Initialization Routine |
128 | * | 121 | * |
@@ -133,15 +126,14 @@ no_mei: | |||
133 | */ | 126 | */ |
134 | static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 127 | static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
135 | { | 128 | { |
129 | const struct mei_cfg *cfg = (struct mei_cfg *)(ent->driver_data); | ||
136 | struct mei_device *dev; | 130 | struct mei_device *dev; |
137 | struct mei_me_hw *hw; | 131 | struct mei_me_hw *hw; |
138 | int err; | 132 | int err; |
139 | 133 | ||
140 | 134 | ||
141 | if (!mei_me_quirk_probe(pdev, ent)) { | 135 | if (!mei_me_quirk_probe(pdev, cfg)) |
142 | err = -ENODEV; | 136 | return -ENODEV; |
143 | goto end; | ||
144 | } | ||
145 | 137 | ||
146 | /* enable pci dev */ | 138 | /* enable pci dev */ |
147 | err = pci_enable_device(pdev); | 139 | err = pci_enable_device(pdev); |
@@ -173,7 +165,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
173 | 165 | ||
174 | 166 | ||
175 | /* allocates and initializes the mei dev structure */ | 167 | /* allocates and initializes the mei dev structure */ |
176 | dev = mei_me_dev_init(pdev); | 168 | dev = mei_me_dev_init(pdev, cfg); |
177 | if (!dev) { | 169 | if (!dev) { |
178 | err = -ENOMEM; | 170 | err = -ENOMEM; |
179 | goto release_regions; | 171 | goto release_regions; |
@@ -212,6 +204,9 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
212 | goto release_irq; | 204 | goto release_irq; |
213 | } | 205 | } |
214 | 206 | ||
207 | pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT); | ||
208 | pm_runtime_use_autosuspend(&pdev->dev); | ||
209 | |||
215 | err = mei_register(dev); | 210 | err = mei_register(dev); |
216 | if (err) | 211 | if (err) |
217 | goto release_irq; | 212 | goto release_irq; |
@@ -220,6 +215,17 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
220 | 215 | ||
221 | schedule_delayed_work(&dev->timer_work, HZ); | 216 | schedule_delayed_work(&dev->timer_work, HZ); |
222 | 217 | ||
218 | /* | ||
219 | * For not wake-able HW runtime pm framework | ||
220 | * can't be used on pci device level. | ||
221 | * Use domain runtime pm callbacks instead. | ||
222 | */ | ||
223 | if (!pci_dev_run_wake(pdev)) | ||
224 | mei_me_set_pm_domain(dev); | ||
225 | |||
226 | if (mei_pg_is_enabled(dev)) | ||
227 | pm_runtime_put_noidle(&pdev->dev); | ||
228 | |||
223 | dev_dbg(&pdev->dev, "initialization successful.\n"); | 229 | dev_dbg(&pdev->dev, "initialization successful.\n"); |
224 | 230 | ||
225 | return 0; | 231 | return 0; |
@@ -259,12 +265,18 @@ static void mei_me_remove(struct pci_dev *pdev) | |||
259 | if (!dev) | 265 | if (!dev) |
260 | return; | 266 | return; |
261 | 267 | ||
268 | if (mei_pg_is_enabled(dev)) | ||
269 | pm_runtime_get_noresume(&pdev->dev); | ||
270 | |||
262 | hw = to_me_hw(dev); | 271 | hw = to_me_hw(dev); |
263 | 272 | ||
264 | 273 | ||
265 | dev_dbg(&pdev->dev, "stop\n"); | 274 | dev_dbg(&pdev->dev, "stop\n"); |
266 | mei_stop(dev); | 275 | mei_stop(dev); |
267 | 276 | ||
277 | if (!pci_dev_run_wake(pdev)) | ||
278 | mei_me_unset_pm_domain(dev); | ||
279 | |||
268 | /* disable interrupts */ | 280 | /* disable interrupts */ |
269 | mei_disable_interrupts(dev); | 281 | mei_disable_interrupts(dev); |
270 | 282 | ||
@@ -343,12 +355,120 @@ static int mei_me_pci_resume(struct device *device) | |||
343 | 355 | ||
344 | return 0; | 356 | return 0; |
345 | } | 357 | } |
358 | #endif /* CONFIG_PM_SLEEP */ | ||
359 | |||
360 | #ifdef CONFIG_PM_RUNTIME | ||
361 | static int mei_me_pm_runtime_idle(struct device *device) | ||
362 | { | ||
363 | struct pci_dev *pdev = to_pci_dev(device); | ||
364 | struct mei_device *dev; | ||
365 | |||
366 | dev_dbg(&pdev->dev, "rpm: me: runtime_idle\n"); | ||
367 | |||
368 | dev = pci_get_drvdata(pdev); | ||
369 | if (!dev) | ||
370 | return -ENODEV; | ||
371 | if (mei_write_is_idle(dev)) | ||
372 | pm_schedule_suspend(device, MEI_ME_RPM_TIMEOUT * 2); | ||
373 | |||
374 | return -EBUSY; | ||
375 | } | ||
376 | |||
377 | static int mei_me_pm_runtime_suspend(struct device *device) | ||
378 | { | ||
379 | struct pci_dev *pdev = to_pci_dev(device); | ||
380 | struct mei_device *dev; | ||
381 | int ret; | ||
382 | |||
383 | dev_dbg(&pdev->dev, "rpm: me: runtime suspend\n"); | ||
384 | |||
385 | dev = pci_get_drvdata(pdev); | ||
386 | if (!dev) | ||
387 | return -ENODEV; | ||
388 | |||
389 | mutex_lock(&dev->device_lock); | ||
390 | |||
391 | if (mei_write_is_idle(dev)) | ||
392 | ret = mei_me_pg_set_sync(dev); | ||
393 | else | ||
394 | ret = -EAGAIN; | ||
395 | |||
396 | mutex_unlock(&dev->device_lock); | ||
397 | |||
398 | dev_dbg(&pdev->dev, "rpm: me: runtime suspend ret=%d\n", ret); | ||
399 | |||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | static int mei_me_pm_runtime_resume(struct device *device) | ||
404 | { | ||
405 | struct pci_dev *pdev = to_pci_dev(device); | ||
406 | struct mei_device *dev; | ||
407 | int ret; | ||
408 | |||
409 | dev_dbg(&pdev->dev, "rpm: me: runtime resume\n"); | ||
410 | |||
411 | dev = pci_get_drvdata(pdev); | ||
412 | if (!dev) | ||
413 | return -ENODEV; | ||
414 | |||
415 | mutex_lock(&dev->device_lock); | ||
416 | |||
417 | ret = mei_me_pg_unset_sync(dev); | ||
418 | |||
419 | mutex_unlock(&dev->device_lock); | ||
420 | |||
421 | dev_dbg(&pdev->dev, "rpm: me: runtime resume ret = %d\n", ret); | ||
422 | |||
423 | return ret; | ||
424 | } | ||
425 | |||
426 | /** | ||
427 | * mei_me_set_pm_domain - fill and set pm domian stucture for device | ||
428 | * | ||
429 | * @dev: mei_device | ||
430 | */ | ||
431 | static inline void mei_me_set_pm_domain(struct mei_device *dev) | ||
432 | { | ||
433 | struct pci_dev *pdev = dev->pdev; | ||
434 | |||
435 | if (pdev->dev.bus && pdev->dev.bus->pm) { | ||
436 | dev->pg_domain.ops = *pdev->dev.bus->pm; | ||
437 | |||
438 | dev->pg_domain.ops.runtime_suspend = mei_me_pm_runtime_suspend; | ||
439 | dev->pg_domain.ops.runtime_resume = mei_me_pm_runtime_resume; | ||
440 | dev->pg_domain.ops.runtime_idle = mei_me_pm_runtime_idle; | ||
441 | |||
442 | pdev->dev.pm_domain = &dev->pg_domain; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * mei_me_unset_pm_domain - clean pm domian stucture for device | ||
448 | * | ||
449 | * @dev: mei_device | ||
450 | */ | ||
451 | static inline void mei_me_unset_pm_domain(struct mei_device *dev) | ||
452 | { | ||
453 | /* stop using pm callbacks if any */ | ||
454 | dev->pdev->dev.pm_domain = NULL; | ||
455 | } | ||
456 | #endif /* CONFIG_PM_RUNTIME */ | ||
457 | |||
458 | #ifdef CONFIG_PM | ||
459 | static const struct dev_pm_ops mei_me_pm_ops = { | ||
460 | SET_SYSTEM_SLEEP_PM_OPS(mei_me_pci_suspend, | ||
461 | mei_me_pci_resume) | ||
462 | SET_RUNTIME_PM_OPS( | ||
463 | mei_me_pm_runtime_suspend, | ||
464 | mei_me_pm_runtime_resume, | ||
465 | mei_me_pm_runtime_idle) | ||
466 | }; | ||
346 | 467 | ||
347 | static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume); | ||
348 | #define MEI_ME_PM_OPS (&mei_me_pm_ops) | 468 | #define MEI_ME_PM_OPS (&mei_me_pm_ops) |
349 | #else | 469 | #else |
350 | #define MEI_ME_PM_OPS NULL | 470 | #define MEI_ME_PM_OPS NULL |
351 | #endif /* CONFIG_PM_SLEEP */ | 471 | #endif /* CONFIG_PM */ |
352 | /* | 472 | /* |
353 | * PCI driver structure | 473 | * PCI driver structure |
354 | */ | 474 | */ |
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index ad3adb009a1e..2343c6236df9 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/jiffies.h> | 27 | #include <linux/jiffies.h> |
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/workqueue.h> | 29 | #include <linux/workqueue.h> |
30 | #include <linux/pm_runtime.h> | ||
30 | 31 | ||
31 | #include <linux/mei.h> | 32 | #include <linux/mei.h> |
32 | 33 | ||
@@ -35,11 +36,18 @@ | |||
35 | #include "hw-txe.h" | 36 | #include "hw-txe.h" |
36 | 37 | ||
37 | static const struct pci_device_id mei_txe_pci_tbl[] = { | 38 | static const struct pci_device_id mei_txe_pci_tbl[] = { |
38 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */ | 39 | {MEI_PCI_DEVICE(0x0F18, mei_txe_cfg)}, /* Baytrail */ |
39 | {0, } | 40 | {0, } |
40 | }; | 41 | }; |
41 | MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl); | 42 | MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl); |
42 | 43 | ||
44 | #ifdef CONFIG_PM_RUNTIME | ||
45 | static inline void mei_txe_set_pm_domain(struct mei_device *dev); | ||
46 | static inline void mei_txe_unset_pm_domain(struct mei_device *dev); | ||
47 | #else | ||
48 | static inline void mei_txe_set_pm_domain(struct mei_device *dev) {} | ||
49 | static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {} | ||
50 | #endif /* CONFIG_PM_RUNTIME */ | ||
43 | 51 | ||
44 | static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) | 52 | static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) |
45 | { | 53 | { |
@@ -61,6 +69,7 @@ static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) | |||
61 | */ | 69 | */ |
62 | static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 70 | static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
63 | { | 71 | { |
72 | const struct mei_cfg *cfg = (struct mei_cfg *)(ent->driver_data); | ||
64 | struct mei_device *dev; | 73 | struct mei_device *dev; |
65 | struct mei_txe_hw *hw; | 74 | struct mei_txe_hw *hw; |
66 | int err; | 75 | int err; |
@@ -91,7 +100,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
91 | } | 100 | } |
92 | 101 | ||
93 | /* allocates and initializes the mei dev structure */ | 102 | /* allocates and initializes the mei dev structure */ |
94 | dev = mei_txe_dev_init(pdev); | 103 | dev = mei_txe_dev_init(pdev, cfg); |
95 | if (!dev) { | 104 | if (!dev) { |
96 | err = -ENOMEM; | 105 | err = -ENOMEM; |
97 | goto release_regions; | 106 | goto release_regions; |
@@ -137,12 +146,25 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
137 | goto release_irq; | 146 | goto release_irq; |
138 | } | 147 | } |
139 | 148 | ||
149 | pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT); | ||
150 | pm_runtime_use_autosuspend(&pdev->dev); | ||
151 | |||
140 | err = mei_register(dev); | 152 | err = mei_register(dev); |
141 | if (err) | 153 | if (err) |
142 | goto release_irq; | 154 | goto release_irq; |
143 | 155 | ||
144 | pci_set_drvdata(pdev, dev); | 156 | pci_set_drvdata(pdev, dev); |
145 | 157 | ||
158 | /* | ||
159 | * For not wake-able HW runtime pm framework | ||
160 | * can't be used on pci device level. | ||
161 | * Use domain runtime pm callbacks instead. | ||
162 | */ | ||
163 | if (!pci_dev_run_wake(pdev)) | ||
164 | mei_txe_set_pm_domain(dev); | ||
165 | |||
166 | pm_runtime_put_noidle(&pdev->dev); | ||
167 | |||
146 | return 0; | 168 | return 0; |
147 | 169 | ||
148 | release_irq: | 170 | release_irq: |
@@ -187,10 +209,15 @@ static void mei_txe_remove(struct pci_dev *pdev) | |||
187 | return; | 209 | return; |
188 | } | 210 | } |
189 | 211 | ||
212 | pm_runtime_get_noresume(&pdev->dev); | ||
213 | |||
190 | hw = to_txe_hw(dev); | 214 | hw = to_txe_hw(dev); |
191 | 215 | ||
192 | mei_stop(dev); | 216 | mei_stop(dev); |
193 | 217 | ||
218 | if (!pci_dev_run_wake(pdev)) | ||
219 | mei_txe_unset_pm_domain(dev); | ||
220 | |||
194 | /* disable interrupts */ | 221 | /* disable interrupts */ |
195 | mei_disable_interrupts(dev); | 222 | mei_disable_interrupts(dev); |
196 | free_irq(pdev->irq, dev); | 223 | free_irq(pdev->irq, dev); |
@@ -265,15 +292,131 @@ static int mei_txe_pci_resume(struct device *device) | |||
265 | 292 | ||
266 | return err; | 293 | return err; |
267 | } | 294 | } |
295 | #endif /* CONFIG_PM_SLEEP */ | ||
296 | |||
297 | #ifdef CONFIG_PM_RUNTIME | ||
298 | static int mei_txe_pm_runtime_idle(struct device *device) | ||
299 | { | ||
300 | struct pci_dev *pdev = to_pci_dev(device); | ||
301 | struct mei_device *dev; | ||
302 | |||
303 | dev_dbg(&pdev->dev, "rpm: txe: runtime_idle\n"); | ||
304 | |||
305 | dev = pci_get_drvdata(pdev); | ||
306 | if (!dev) | ||
307 | return -ENODEV; | ||
308 | if (mei_write_is_idle(dev)) | ||
309 | pm_schedule_suspend(device, MEI_TXI_RPM_TIMEOUT * 2); | ||
310 | |||
311 | return -EBUSY; | ||
312 | } | ||
313 | static int mei_txe_pm_runtime_suspend(struct device *device) | ||
314 | { | ||
315 | struct pci_dev *pdev = to_pci_dev(device); | ||
316 | struct mei_device *dev; | ||
317 | int ret; | ||
318 | |||
319 | dev_dbg(&pdev->dev, "rpm: txe: runtime suspend\n"); | ||
320 | |||
321 | dev = pci_get_drvdata(pdev); | ||
322 | if (!dev) | ||
323 | return -ENODEV; | ||
324 | |||
325 | mutex_lock(&dev->device_lock); | ||
326 | |||
327 | if (mei_write_is_idle(dev)) | ||
328 | ret = mei_txe_aliveness_set_sync(dev, 0); | ||
329 | else | ||
330 | ret = -EAGAIN; | ||
331 | |||
332 | /* | ||
333 | * If everything is okay we're about to enter PCI low | ||
334 | * power state (D3) therefor we need to disable the | ||
335 | * interrupts towards host. | ||
336 | * However if device is not wakeable we do not enter | ||
337 | * D-low state and we need to keep the interrupt kicking | ||
338 | */ | ||
339 | if (!ret && pci_dev_run_wake(pdev)) | ||
340 | mei_disable_interrupts(dev); | ||
341 | |||
342 | dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret); | ||
343 | |||
344 | mutex_unlock(&dev->device_lock); | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | static int mei_txe_pm_runtime_resume(struct device *device) | ||
349 | { | ||
350 | struct pci_dev *pdev = to_pci_dev(device); | ||
351 | struct mei_device *dev; | ||
352 | int ret; | ||
353 | |||
354 | dev_dbg(&pdev->dev, "rpm: txe: runtime resume\n"); | ||
355 | |||
356 | dev = pci_get_drvdata(pdev); | ||
357 | if (!dev) | ||
358 | return -ENODEV; | ||
359 | |||
360 | mutex_lock(&dev->device_lock); | ||
361 | |||
362 | mei_enable_interrupts(dev); | ||
363 | |||
364 | ret = mei_txe_aliveness_set_sync(dev, 1); | ||
365 | |||
366 | mutex_unlock(&dev->device_lock); | ||
367 | |||
368 | dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret); | ||
369 | |||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | /** | ||
374 | * mei_txe_set_pm_domain - fill and set pm domian stucture for device | ||
375 | * | ||
376 | * @dev: mei_device | ||
377 | */ | ||
378 | static inline void mei_txe_set_pm_domain(struct mei_device *dev) | ||
379 | { | ||
380 | struct pci_dev *pdev = dev->pdev; | ||
381 | |||
382 | if (pdev->dev.bus && pdev->dev.bus->pm) { | ||
383 | dev->pg_domain.ops = *pdev->dev.bus->pm; | ||
384 | |||
385 | dev->pg_domain.ops.runtime_suspend = mei_txe_pm_runtime_suspend; | ||
386 | dev->pg_domain.ops.runtime_resume = mei_txe_pm_runtime_resume; | ||
387 | dev->pg_domain.ops.runtime_idle = mei_txe_pm_runtime_idle; | ||
388 | |||
389 | pdev->dev.pm_domain = &dev->pg_domain; | ||
390 | } | ||
391 | } | ||
268 | 392 | ||
269 | static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops, | 393 | /** |
270 | mei_txe_pci_suspend, | 394 | * mei_txe_unset_pm_domain - clean pm domian stucture for device |
271 | mei_txe_pci_resume); | 395 | * |
396 | * @dev: mei_device | ||
397 | */ | ||
398 | static inline void mei_txe_unset_pm_domain(struct mei_device *dev) | ||
399 | { | ||
400 | /* stop using pm callbacks if any */ | ||
401 | dev->pdev->dev.pm_domain = NULL; | ||
402 | } | ||
403 | #endif /* CONFIG_PM_RUNTIME */ | ||
404 | |||
405 | #ifdef CONFIG_PM | ||
406 | static const struct dev_pm_ops mei_txe_pm_ops = { | ||
407 | SET_SYSTEM_SLEEP_PM_OPS(mei_txe_pci_suspend, | ||
408 | mei_txe_pci_resume) | ||
409 | SET_RUNTIME_PM_OPS( | ||
410 | mei_txe_pm_runtime_suspend, | ||
411 | mei_txe_pm_runtime_resume, | ||
412 | mei_txe_pm_runtime_idle) | ||
413 | }; | ||
272 | 414 | ||
273 | #define MEI_TXE_PM_OPS (&mei_txe_pm_ops) | 415 | #define MEI_TXE_PM_OPS (&mei_txe_pm_ops) |
274 | #else | 416 | #else |
275 | #define MEI_TXE_PM_OPS NULL | 417 | #define MEI_TXE_PM_OPS NULL |
276 | #endif /* CONFIG_PM_SLEEP */ | 418 | #endif /* CONFIG_PM */ |
419 | |||
277 | /* | 420 | /* |
278 | * PCI driver structure | 421 | * PCI driver structure |
279 | */ | 422 | */ |
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index ebf1cbc198fd..a84a664dfccb 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c | |||
@@ -84,8 +84,6 @@ int mei_wd_host_init(struct mei_device *dev) | |||
84 | return ret; | 84 | return ret; |
85 | } | 85 | } |
86 | 86 | ||
87 | cl->state = MEI_FILE_CONNECTING; | ||
88 | |||
89 | ret = mei_cl_connect(cl, NULL); | 87 | ret = mei_cl_connect(cl, NULL); |
90 | 88 | ||
91 | if (ret) { | 89 | if (ret) { |