diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-22 14:38:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-22 14:38:22 -0500 |
commit | e30aee9e10bb5168579e047f05c3d13d09e23356 (patch) | |
tree | 12371bdcd52d2427cad838201997479e31b6a9c9 /drivers/misc | |
parent | 8ff546b801e5cca0337c0f0a7234795d0a6309a1 (diff) | |
parent | 6cf18e6927c0b224f972e3042fb85770d63cb9f8 (diff) |
Merge tag 'char-misc-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH:
"Here is the big char/misc driver patchset for 4.11-rc1.
Lots of different driver subsystems updated here: rework for the
hyperv subsystem to handle new platforms better, mei and w1 and extcon
driver updates, as well as a number of other "minor" driver updates.
All of these have been in linux-next for a while with no reported
issues"
* tag 'char-misc-4.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (169 commits)
goldfish: Sanitize the broken interrupt handler
x86/platform/goldfish: Prevent unconditional loading
vmbus: replace modulus operation with subtraction
vmbus: constify parameters where possible
vmbus: expose hv_begin/end_read
vmbus: remove conditional locking of vmbus_write
vmbus: add direct isr callback mode
vmbus: change to per channel tasklet
vmbus: put related per-cpu variable together
vmbus: callback is in softirq not workqueue
binder: Add support for file-descriptor arrays
binder: Add support for scatter-gather
binder: Add extra size to allocator
binder: Refactor binder_transact()
binder: Support multiple /dev instances
binder: Deal with contexts in debugfs
binder: Support multiple context managers
binder: Split flat_binder_object
auxdisplay: ht16k33: remove private workqueue
auxdisplay: ht16k33: rework input device initialization
...
Diffstat (limited to 'drivers/misc')
28 files changed, 2215 insertions, 519 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 64971baf11fa..c290990d73ed 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -474,11 +474,15 @@ config SRAM | |||
474 | bool "Generic on-chip SRAM driver" | 474 | bool "Generic on-chip SRAM driver" |
475 | depends on HAS_IOMEM | 475 | depends on HAS_IOMEM |
476 | select GENERIC_ALLOCATOR | 476 | select GENERIC_ALLOCATOR |
477 | select SRAM_EXEC if ARM | ||
477 | help | 478 | help |
478 | This driver allows you to declare a memory region to be managed by | 479 | This driver allows you to declare a memory region to be managed by |
479 | the genalloc API. It is supposed to be used for small on-chip SRAM | 480 | the genalloc API. It is supposed to be used for small on-chip SRAM |
480 | areas found on many SoCs. | 481 | areas found on many SoCs. |
481 | 482 | ||
483 | config SRAM_EXEC | ||
484 | bool | ||
485 | |||
482 | config VEXPRESS_SYSCFG | 486 | config VEXPRESS_SYSCFG |
483 | bool "Versatile Express System Configuration driver" | 487 | bool "Versatile Express System Configuration driver" |
484 | depends on VEXPRESS_CONFIG | 488 | depends on VEXPRESS_CONFIG |
@@ -487,6 +491,7 @@ config VEXPRESS_SYSCFG | |||
487 | ARM Ltd. Versatile Express uses specialised platform configuration | 491 | ARM Ltd. Versatile Express uses specialised platform configuration |
488 | bus. System Configuration interface is one of the possible means | 492 | bus. System Configuration interface is one of the possible means |
489 | of generating transactions on this bus. | 493 | of generating transactions on this bus. |
494 | |||
490 | config PANEL | 495 | config PANEL |
491 | tristate "Parallel port LCD/Keypad Panel support" | 496 | tristate "Parallel port LCD/Keypad Panel support" |
492 | depends on PARPORT | 497 | depends on PARPORT |
@@ -494,14 +499,14 @@ config PANEL | |||
494 | Say Y here if you have an HD44780 or KS-0074 LCD connected to your | 499 | Say Y here if you have an HD44780 or KS-0074 LCD connected to your |
495 | parallel port. This driver also features 4 and 6-key keypads. The LCD | 500 | parallel port. This driver also features 4 and 6-key keypads. The LCD |
496 | is accessible through the /dev/lcd char device (10, 156), and the | 501 | is accessible through the /dev/lcd char device (10, 156), and the |
497 | keypad through /dev/keypad (10, 185). Both require misc device to be | 502 | keypad through /dev/keypad (10, 185). This code can either be |
498 | enabled. This code can either be compiled as a module, or linked into | 503 | compiled as a module, or linked into the kernel and started at boot. |
499 | the kernel and started at boot. If you don't understand what all this | 504 | If you don't understand what all this is about, say N. |
500 | is about, say N. | 505 | |
506 | if PANEL | ||
501 | 507 | ||
502 | config PANEL_PARPORT | 508 | config PANEL_PARPORT |
503 | int "Default parallel port number (0=LPT1)" | 509 | int "Default parallel port number (0=LPT1)" |
504 | depends on PANEL | ||
505 | range 0 255 | 510 | range 0 255 |
506 | default "0" | 511 | default "0" |
507 | ---help--- | 512 | ---help--- |
@@ -513,7 +518,6 @@ config PANEL_PARPORT | |||
513 | 518 | ||
514 | config PANEL_PROFILE | 519 | config PANEL_PROFILE |
515 | int "Default panel profile (0-5, 0=custom)" | 520 | int "Default panel profile (0-5, 0=custom)" |
516 | depends on PANEL | ||
517 | range 0 5 | 521 | range 0 5 |
518 | default "5" | 522 | default "5" |
519 | ---help--- | 523 | ---help--- |
@@ -534,7 +538,7 @@ config PANEL_PROFILE | |||
534 | for experts. | 538 | for experts. |
535 | 539 | ||
536 | config PANEL_KEYPAD | 540 | config PANEL_KEYPAD |
537 | depends on PANEL && PANEL_PROFILE="0" | 541 | depends on PANEL_PROFILE="0" |
538 | int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)" | 542 | int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)" |
539 | range 0 3 | 543 | range 0 3 |
540 | default 0 | 544 | default 0 |
@@ -551,7 +555,7 @@ config PANEL_KEYPAD | |||
551 | supports simultaneous keys pressed when the keypad supports them. | 555 | supports simultaneous keys pressed when the keypad supports them. |
552 | 556 | ||
553 | config PANEL_LCD | 557 | config PANEL_LCD |
554 | depends on PANEL && PANEL_PROFILE="0" | 558 | depends on PANEL_PROFILE="0" |
555 | int "LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)" | 559 | int "LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)" |
556 | range 0 5 | 560 | range 0 5 |
557 | default 0 | 561 | default 0 |
@@ -574,7 +578,7 @@ config PANEL_LCD | |||
574 | that those values changed from the 2.4 driver for better consistency. | 578 | that those values changed from the 2.4 driver for better consistency. |
575 | 579 | ||
576 | config PANEL_LCD_HEIGHT | 580 | config PANEL_LCD_HEIGHT |
577 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | 581 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" |
578 | int "Number of lines on the LCD (1-2)" | 582 | int "Number of lines on the LCD (1-2)" |
579 | range 1 2 | 583 | range 1 2 |
580 | default 2 | 584 | default 2 |
@@ -583,7 +587,7 @@ config PANEL_LCD_HEIGHT | |||
583 | It can either be 1 or 2. | 587 | It can either be 1 or 2. |
584 | 588 | ||
585 | config PANEL_LCD_WIDTH | 589 | config PANEL_LCD_WIDTH |
586 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | 590 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" |
587 | int "Number of characters per line on the LCD (1-40)" | 591 | int "Number of characters per line on the LCD (1-40)" |
588 | range 1 40 | 592 | range 1 40 |
589 | default 40 | 593 | default 40 |
@@ -592,7 +596,7 @@ config PANEL_LCD_WIDTH | |||
592 | Common values are 16,20,24,40. | 596 | Common values are 16,20,24,40. |
593 | 597 | ||
594 | config PANEL_LCD_BWIDTH | 598 | config PANEL_LCD_BWIDTH |
595 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | 599 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" |
596 | int "Internal LCD line width (1-40, 40 by default)" | 600 | int "Internal LCD line width (1-40, 40 by default)" |
597 | range 1 40 | 601 | range 1 40 |
598 | default 40 | 602 | default 40 |
@@ -608,7 +612,7 @@ config PANEL_LCD_BWIDTH | |||
608 | If you don't know, put '40' here. | 612 | If you don't know, put '40' here. |
609 | 613 | ||
610 | config PANEL_LCD_HWIDTH | 614 | config PANEL_LCD_HWIDTH |
611 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | 615 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" |
612 | int "Hardware LCD line width (1-64, 64 by default)" | 616 | int "Hardware LCD line width (1-64, 64 by default)" |
613 | range 1 64 | 617 | range 1 64 |
614 | default 64 | 618 | default 64 |
@@ -622,7 +626,7 @@ config PANEL_LCD_HWIDTH | |||
622 | 64 here for a 2x40. | 626 | 64 here for a 2x40. |
623 | 627 | ||
624 | config PANEL_LCD_CHARSET | 628 | config PANEL_LCD_CHARSET |
625 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | 629 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" |
626 | int "LCD character set (0=normal, 1=KS0074)" | 630 | int "LCD character set (0=normal, 1=KS0074)" |
627 | range 0 1 | 631 | range 0 1 |
628 | default 0 | 632 | default 0 |
@@ -638,7 +642,7 @@ config PANEL_LCD_CHARSET | |||
638 | If you don't know, use the normal one (0). | 642 | If you don't know, use the normal one (0). |
639 | 643 | ||
640 | config PANEL_LCD_PROTO | 644 | config PANEL_LCD_PROTO |
641 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | 645 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" |
642 | int "LCD communication mode (0=parallel 8 bits, 1=serial)" | 646 | int "LCD communication mode (0=parallel 8 bits, 1=serial)" |
643 | range 0 1 | 647 | range 0 1 |
644 | default 0 | 648 | default 0 |
@@ -651,7 +655,7 @@ config PANEL_LCD_PROTO | |||
651 | parallel LCD, and 1 for a serial LCD. | 655 | parallel LCD, and 1 for a serial LCD. |
652 | 656 | ||
653 | config PANEL_LCD_PIN_E | 657 | config PANEL_LCD_PIN_E |
654 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | 658 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" |
655 | int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) " | 659 | int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) " |
656 | range -17 17 | 660 | range -17 17 |
657 | default 14 | 661 | default 14 |
@@ -666,7 +670,7 @@ config PANEL_LCD_PIN_E | |||
666 | Default for the 'E' pin in custom profile is '14' (AUTOFEED). | 670 | Default for the 'E' pin in custom profile is '14' (AUTOFEED). |
667 | 671 | ||
668 | config PANEL_LCD_PIN_RS | 672 | config PANEL_LCD_PIN_RS |
669 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | 673 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" |
670 | int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) " | 674 | int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) " |
671 | range -17 17 | 675 | range -17 17 |
672 | default 17 | 676 | default 17 |
@@ -681,7 +685,7 @@ config PANEL_LCD_PIN_RS | |||
681 | Default for the 'RS' pin in custom profile is '17' (SELECT IN). | 685 | Default for the 'RS' pin in custom profile is '17' (SELECT IN). |
682 | 686 | ||
683 | config PANEL_LCD_PIN_RW | 687 | config PANEL_LCD_PIN_RW |
684 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" | 688 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" |
685 | int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) " | 689 | int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) " |
686 | range -17 17 | 690 | range -17 17 |
687 | default 16 | 691 | default 16 |
@@ -696,7 +700,7 @@ config PANEL_LCD_PIN_RW | |||
696 | Default for the 'RW' pin in custom profile is '16' (INIT). | 700 | Default for the 'RW' pin in custom profile is '16' (INIT). |
697 | 701 | ||
698 | config PANEL_LCD_PIN_SCL | 702 | config PANEL_LCD_PIN_SCL |
699 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" | 703 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" |
700 | int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) " | 704 | int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) " |
701 | range -17 17 | 705 | range -17 17 |
702 | default 1 | 706 | default 1 |
@@ -711,7 +715,7 @@ config PANEL_LCD_PIN_SCL | |||
711 | Default for the 'SCL' pin in custom profile is '1' (STROBE). | 715 | Default for the 'SCL' pin in custom profile is '1' (STROBE). |
712 | 716 | ||
713 | config PANEL_LCD_PIN_SDA | 717 | config PANEL_LCD_PIN_SDA |
714 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" | 718 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" |
715 | int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) " | 719 | int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) " |
716 | range -17 17 | 720 | range -17 17 |
717 | default 2 | 721 | default 2 |
@@ -726,7 +730,7 @@ config PANEL_LCD_PIN_SDA | |||
726 | Default for the 'SDA' pin in custom profile is '2' (D0). | 730 | Default for the 'SDA' pin in custom profile is '2' (D0). |
727 | 731 | ||
728 | config PANEL_LCD_PIN_BL | 732 | config PANEL_LCD_PIN_BL |
729 | depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" | 733 | depends on PANEL_PROFILE="0" && PANEL_LCD="1" |
730 | int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) " | 734 | int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) " |
731 | range -17 17 | 735 | range -17 17 |
732 | default 0 | 736 | default 0 |
@@ -741,7 +745,6 @@ config PANEL_LCD_PIN_BL | |||
741 | Default for the 'BL' pin in custom profile is '0' (uncontrolled). | 745 | Default for the 'BL' pin in custom profile is '0' (uncontrolled). |
742 | 746 | ||
743 | config PANEL_CHANGE_MESSAGE | 747 | config PANEL_CHANGE_MESSAGE |
744 | depends on PANEL | ||
745 | bool "Change LCD initialization message ?" | 748 | bool "Change LCD initialization message ?" |
746 | default "n" | 749 | default "n" |
747 | ---help--- | 750 | ---help--- |
@@ -754,7 +757,7 @@ config PANEL_CHANGE_MESSAGE | |||
754 | say 'N' and keep the default message with the version. | 757 | say 'N' and keep the default message with the version. |
755 | 758 | ||
756 | config PANEL_BOOT_MESSAGE | 759 | config PANEL_BOOT_MESSAGE |
757 | depends on PANEL && PANEL_CHANGE_MESSAGE="y" | 760 | depends on PANEL_CHANGE_MESSAGE="y" |
758 | string "New initialization message" | 761 | string "New initialization message" |
759 | default "" | 762 | default "" |
760 | ---help--- | 763 | ---help--- |
@@ -766,6 +769,8 @@ config PANEL_BOOT_MESSAGE | |||
766 | An empty message will only clear the display at driver init time. Any other | 769 | An empty message will only clear the display at driver init time. Any other |
767 | printf()-formatted message is valid with newline and escape codes. | 770 | printf()-formatted message is valid with newline and escape codes. |
768 | 771 | ||
772 | endif # PANEL | ||
773 | |||
769 | source "drivers/misc/c2port/Kconfig" | 774 | source "drivers/misc/c2port/Kconfig" |
770 | source "drivers/misc/eeprom/Kconfig" | 775 | source "drivers/misc/eeprom/Kconfig" |
771 | source "drivers/misc/cb710/Kconfig" | 776 | source "drivers/misc/cb710/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 31983366090a..7a3ea89339b4 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -47,6 +47,7 @@ obj-$(CONFIG_INTEL_MEI) += mei/ | |||
47 | obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ | 47 | obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ |
48 | obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o | 48 | obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o |
49 | obj-$(CONFIG_SRAM) += sram.o | 49 | obj-$(CONFIG_SRAM) += sram.o |
50 | obj-$(CONFIG_SRAM_EXEC) += sram-exec.o | ||
50 | obj-y += mic/ | 51 | obj-y += mic/ |
51 | obj-$(CONFIG_GENWQE) += genwqe/ | 52 | obj-$(CONFIG_GENWQE) += genwqe/ |
52 | obj-$(CONFIG_ECHO) += echo/ | 53 | obj-$(CONFIG_ECHO) += echo/ |
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index c4e41c26649e..de58762097c4 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig | |||
@@ -100,4 +100,14 @@ config EEPROM_DIGSY_MTC_CFG | |||
100 | 100 | ||
101 | If unsure, say N. | 101 | If unsure, say N. |
102 | 102 | ||
103 | config EEPROM_IDT_89HPESX | ||
104 | tristate "IDT 89HPESx PCIe-swtiches EEPROM / CSR support" | ||
105 | depends on I2C && SYSFS | ||
106 | help | ||
107 | Enable this driver to get read/write access to EEPROM / CSRs | ||
108 | over IDT PCIe-swtich i2c-slave interface. | ||
109 | |||
110 | This driver can also be built as a module. If so, the module | ||
111 | will be called idt_89hpesx. | ||
112 | |||
103 | endmenu | 113 | endmenu |
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index fc1e81d29267..90a52624ddeb 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile | |||
@@ -5,3 +5,4 @@ obj-$(CONFIG_EEPROM_MAX6875) += max6875.o | |||
5 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o | 5 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o |
6 | obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o | 6 | obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o |
7 | obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o | 7 | obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o |
8 | obj-$(CONFIG_EEPROM_IDT_89HPESX) += idt_89hpesx.o | ||
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c new file mode 100644 index 000000000000..4a22a1d99395 --- /dev/null +++ b/drivers/misc/eeprom/idt_89hpesx.c | |||
@@ -0,0 +1,1581 @@ | |||
1 | /* | ||
2 | * This file is provided under a GPLv2 license. When using or | ||
3 | * redistributing this file, you may do so under that license. | ||
4 | * | ||
5 | * GPL LICENSE SUMMARY | ||
6 | * | ||
7 | * Copyright (C) 2016 T-Platforms. All Rights Reserved. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, it can be found <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | * The full GNU General Public License is included in this distribution in | ||
22 | * the file called "COPYING". | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
28 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
35 | * | ||
36 | * IDT PCIe-switch NTB Linux driver | ||
37 | * | ||
38 | * Contact Information: | ||
39 | * Serge Semin <fancer.lancer@gmail.com>, <Sergey.Semin@t-platforms.ru> | ||
40 | */ | ||
41 | /* | ||
42 | * NOTE of the IDT 89HPESx SMBus-slave interface driver | ||
43 | * This driver primarily is developed to have an access to EEPROM device of | ||
44 | * IDT PCIe-switches. IDT provides a simple SMBus interface to perform IO- | ||
45 | * operations from/to EEPROM, which is located at private (so called Master) | ||
46 | * SMBus of switches. Using that interface this the driver creates a simple | ||
47 | * binary sysfs-file in the device directory: | ||
48 | * /sys/bus/i2c/devices/<bus>-<devaddr>/eeprom | ||
49 | * In case if read-only flag is specified in the dts-node of device desription, | ||
50 | * User-space applications won't be able to write to the EEPROM sysfs-node. | ||
51 | * Additionally IDT 89HPESx SMBus interface has an ability to write/read | ||
52 | * data of device CSRs. This driver exposes debugf-file to perform simple IO | ||
53 | * operations using that ability for just basic debug purpose. Particularly | ||
54 | * next file is created in the specific debugfs-directory: | ||
55 | * /sys/kernel/debug/idt_csr/ | ||
56 | * Format of the debugfs-node is: | ||
57 | * $ cat /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>; | ||
58 | * <CSR address>:<CSR value> | ||
59 | * So reading the content of the file gives current CSR address and it value. | ||
60 | * If User-space application wishes to change current CSR address, | ||
61 | * it can just write a proper value to the sysfs-file: | ||
62 | * $ echo "<CSR address>" > /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname> | ||
63 | * If it wants to change the CSR value as well, the format of the write | ||
64 | * operation is: | ||
65 | * $ echo "<CSR address>:<CSR value>" > \ | ||
66 | * /sys/kernel/debug/idt_csr/<bus>-<devaddr>/<devname>; | ||
67 | * CSR address and value can be any of hexadecimal, decimal or octal format. | ||
68 | */ | ||
69 | |||
70 | #include <linux/kernel.h> | ||
71 | #include <linux/init.h> | ||
72 | #include <linux/module.h> | ||
73 | #include <linux/types.h> | ||
74 | #include <linux/sizes.h> | ||
75 | #include <linux/slab.h> | ||
76 | #include <linux/mutex.h> | ||
77 | #include <linux/sysfs.h> | ||
78 | #include <linux/debugfs.h> | ||
79 | #include <linux/mod_devicetable.h> | ||
80 | #include <linux/of.h> | ||
81 | #include <linux/i2c.h> | ||
82 | #include <linux/pci_ids.h> | ||
83 | #include <linux/delay.h> | ||
84 | |||
85 | #define IDT_NAME "89hpesx" | ||
86 | #define IDT_89HPESX_DESC "IDT 89HPESx SMBus-slave interface driver" | ||
87 | #define IDT_89HPESX_VER "1.0" | ||
88 | |||
89 | MODULE_DESCRIPTION(IDT_89HPESX_DESC); | ||
90 | MODULE_VERSION(IDT_89HPESX_VER); | ||
91 | MODULE_LICENSE("GPL v2"); | ||
92 | MODULE_AUTHOR("T-platforms"); | ||
93 | |||
94 | /* | ||
95 | * csr_dbgdir - CSR read/write operations Debugfs directory | ||
96 | */ | ||
97 | static struct dentry *csr_dbgdir; | ||
98 | |||
99 | /* | ||
100 | * struct idt_89hpesx_dev - IDT 89HPESx device data structure | ||
101 | * @eesize: Size of EEPROM in bytes (calculated from "idt,eecompatible") | ||
102 | * @eero: EEPROM Read-only flag | ||
103 | * @eeaddr: EEPROM custom address | ||
104 | * | ||
105 | * @inieecmd: Initial cmd value for EEPROM read/write operations | ||
106 | * @inicsrcmd: Initial cmd value for CSR read/write operations | ||
107 | * @iniccode: Initialial command code value for IO-operations | ||
108 | * | ||
109 | * @csr: CSR address to perform read operation | ||
110 | * | ||
111 | * @smb_write: SMBus write method | ||
112 | * @smb_read: SMBus read method | ||
113 | * @smb_mtx: SMBus mutex | ||
114 | * | ||
115 | * @client: i2c client used to perform IO operations | ||
116 | * | ||
117 | * @ee_file: EEPROM read/write sysfs-file | ||
118 | * @csr_file: CSR read/write debugfs-node | ||
119 | */ | ||
120 | struct idt_smb_seq; | ||
121 | struct idt_89hpesx_dev { | ||
122 | u32 eesize; | ||
123 | bool eero; | ||
124 | u8 eeaddr; | ||
125 | |||
126 | u8 inieecmd; | ||
127 | u8 inicsrcmd; | ||
128 | u8 iniccode; | ||
129 | |||
130 | u16 csr; | ||
131 | |||
132 | int (*smb_write)(struct idt_89hpesx_dev *, const struct idt_smb_seq *); | ||
133 | int (*smb_read)(struct idt_89hpesx_dev *, struct idt_smb_seq *); | ||
134 | struct mutex smb_mtx; | ||
135 | |||
136 | struct i2c_client *client; | ||
137 | |||
138 | struct bin_attribute *ee_file; | ||
139 | struct dentry *csr_dir; | ||
140 | struct dentry *csr_file; | ||
141 | }; | ||
142 | |||
143 | /* | ||
144 | * struct idt_smb_seq - sequence of data to be read/written from/to IDT 89HPESx | ||
145 | * @ccode: SMBus command code | ||
146 | * @bytecnt: Byte count of operation | ||
147 | * @data: Data to by written | ||
148 | */ | ||
149 | struct idt_smb_seq { | ||
150 | u8 ccode; | ||
151 | u8 bytecnt; | ||
152 | u8 *data; | ||
153 | }; | ||
154 | |||
155 | /* | ||
156 | * struct idt_eeprom_seq - sequence of data to be read/written from/to EEPROM | ||
157 | * @cmd: Transaction CMD | ||
158 | * @eeaddr: EEPROM custom address | ||
159 | * @memaddr: Internal memory address of EEPROM | ||
160 | * @data: Data to be written at the memory address | ||
161 | */ | ||
162 | struct idt_eeprom_seq { | ||
163 | u8 cmd; | ||
164 | u8 eeaddr; | ||
165 | u16 memaddr; | ||
166 | u8 data; | ||
167 | } __packed; | ||
168 | |||
169 | /* | ||
170 | * struct idt_csr_seq - sequence of data to be read/written from/to CSR | ||
171 | * @cmd: Transaction CMD | ||
172 | * @csraddr: Internal IDT device CSR address | ||
173 | * @data: Data to be read/written from/to the CSR address | ||
174 | */ | ||
175 | struct idt_csr_seq { | ||
176 | u8 cmd; | ||
177 | u16 csraddr; | ||
178 | u32 data; | ||
179 | } __packed; | ||
180 | |||
181 | /* | ||
182 | * SMBus command code macros | ||
183 | * @CCODE_END: Indicates the end of transaction | ||
184 | * @CCODE_START: Indicates the start of transaction | ||
185 | * @CCODE_CSR: CSR read/write transaction | ||
186 | * @CCODE_EEPROM: EEPROM read/write transaction | ||
187 | * @CCODE_BYTE: Supplied data has BYTE length | ||
188 | * @CCODE_WORD: Supplied data has WORD length | ||
189 | * @CCODE_BLOCK: Supplied data has variable length passed in bytecnt | ||
190 | * byte right following CCODE byte | ||
191 | */ | ||
192 | #define CCODE_END ((u8)0x01) | ||
193 | #define CCODE_START ((u8)0x02) | ||
194 | #define CCODE_CSR ((u8)0x00) | ||
195 | #define CCODE_EEPROM ((u8)0x04) | ||
196 | #define CCODE_BYTE ((u8)0x00) | ||
197 | #define CCODE_WORD ((u8)0x20) | ||
198 | #define CCODE_BLOCK ((u8)0x40) | ||
199 | #define CCODE_PEC ((u8)0x80) | ||
200 | |||
201 | /* | ||
202 | * EEPROM command macros | ||
203 | * @EEPROM_OP_WRITE: EEPROM write operation | ||
204 | * @EEPROM_OP_READ: EEPROM read operation | ||
205 | * @EEPROM_USA: Use specified address of EEPROM | ||
206 | * @EEPROM_NAERR: EEPROM device is not ready to respond | ||
207 | * @EEPROM_LAERR: EEPROM arbitration loss error | ||
208 | * @EEPROM_MSS: EEPROM misplace start & stop bits error | ||
209 | * @EEPROM_WR_CNT: Bytes count to perform write operation | ||
210 | * @EEPROM_WRRD_CNT: Bytes count to write before reading | ||
211 | * @EEPROM_RD_CNT: Bytes count to perform read operation | ||
212 | * @EEPROM_DEF_SIZE: Fall back size of EEPROM | ||
213 | * @EEPROM_DEF_ADDR: Defatul EEPROM address | ||
214 | * @EEPROM_TOUT: Timeout before retry read operation if eeprom is busy | ||
215 | */ | ||
216 | #define EEPROM_OP_WRITE ((u8)0x00) | ||
217 | #define EEPROM_OP_READ ((u8)0x01) | ||
218 | #define EEPROM_USA ((u8)0x02) | ||
219 | #define EEPROM_NAERR ((u8)0x08) | ||
220 | #define EEPROM_LAERR ((u8)0x10) | ||
221 | #define EEPROM_MSS ((u8)0x20) | ||
222 | #define EEPROM_WR_CNT ((u8)5) | ||
223 | #define EEPROM_WRRD_CNT ((u8)4) | ||
224 | #define EEPROM_RD_CNT ((u8)5) | ||
225 | #define EEPROM_DEF_SIZE ((u16)4096) | ||
226 | #define EEPROM_DEF_ADDR ((u8)0x50) | ||
227 | #define EEPROM_TOUT (100) | ||
228 | |||
229 | /* | ||
230 | * CSR command macros | ||
231 | * @CSR_DWE: Enable all four bytes of the operation | ||
232 | * @CSR_OP_WRITE: CSR write operation | ||
233 | * @CSR_OP_READ: CSR read operation | ||
234 | * @CSR_RERR: Read operation error | ||
235 | * @CSR_WERR: Write operation error | ||
236 | * @CSR_WR_CNT: Bytes count to perform write operation | ||
237 | * @CSR_WRRD_CNT: Bytes count to write before reading | ||
238 | * @CSR_RD_CNT: Bytes count to perform read operation | ||
239 | * @CSR_MAX: Maximum CSR address | ||
240 | * @CSR_DEF: Default CSR address | ||
241 | * @CSR_REAL_ADDR: CSR real unshifted address | ||
242 | */ | ||
243 | #define CSR_DWE ((u8)0x0F) | ||
244 | #define CSR_OP_WRITE ((u8)0x00) | ||
245 | #define CSR_OP_READ ((u8)0x10) | ||
246 | #define CSR_RERR ((u8)0x40) | ||
247 | #define CSR_WERR ((u8)0x80) | ||
248 | #define CSR_WR_CNT ((u8)7) | ||
249 | #define CSR_WRRD_CNT ((u8)3) | ||
250 | #define CSR_RD_CNT ((u8)7) | ||
251 | #define CSR_MAX ((u32)0x3FFFF) | ||
252 | #define CSR_DEF ((u16)0x0000) | ||
253 | #define CSR_REAL_ADDR(val) ((unsigned int)val << 2) | ||
254 | |||
255 | /* | ||
256 | * IDT 89HPESx basic register | ||
257 | * @IDT_VIDDID_CSR: PCIe VID and DID of IDT 89HPESx | ||
258 | * @IDT_VID_MASK: Mask of VID | ||
259 | */ | ||
260 | #define IDT_VIDDID_CSR ((u32)0x0000) | ||
261 | #define IDT_VID_MASK ((u32)0xFFFF) | ||
262 | |||
263 | /* | ||
264 | * IDT 89HPESx can send NACK when new command is sent before previous one | ||
265 | * fininshed execution. In this case driver retries operation | ||
266 | * certain times. | ||
267 | * @RETRY_CNT: Number of retries before giving up and fail | ||
268 | * @idt_smb_safe: Generate a retry loop on corresponding SMBus method | ||
269 | */ | ||
270 | #define RETRY_CNT (128) | ||
271 | #define idt_smb_safe(ops, args...) ({ \ | ||
272 | int __retry = RETRY_CNT; \ | ||
273 | s32 __sts; \ | ||
274 | do { \ | ||
275 | __sts = i2c_smbus_ ## ops ## _data(args); \ | ||
276 | } while (__retry-- && __sts < 0); \ | ||
277 | __sts; \ | ||
278 | }) | ||
279 | |||
280 | /*=========================================================================== | ||
281 | * i2c bus level IO-operations | ||
282 | *=========================================================================== | ||
283 | */ | ||
284 | |||
285 | /* | ||
286 | * idt_smb_write_byte() - SMBus write method when I2C_SMBUS_BYTE_DATA operation | ||
287 | * is only available | ||
288 | * @pdev: Pointer to the driver data | ||
289 | * @seq: Sequence of data to be written | ||
290 | */ | ||
291 | static int idt_smb_write_byte(struct idt_89hpesx_dev *pdev, | ||
292 | const struct idt_smb_seq *seq) | ||
293 | { | ||
294 | s32 sts; | ||
295 | u8 ccode; | ||
296 | int idx; | ||
297 | |||
298 | /* Loop over the supplied data sending byte one-by-one */ | ||
299 | for (idx = 0; idx < seq->bytecnt; idx++) { | ||
300 | /* Collect the command code byte */ | ||
301 | ccode = seq->ccode | CCODE_BYTE; | ||
302 | if (idx == 0) | ||
303 | ccode |= CCODE_START; | ||
304 | if (idx == seq->bytecnt - 1) | ||
305 | ccode |= CCODE_END; | ||
306 | |||
307 | /* Send data to the device */ | ||
308 | sts = idt_smb_safe(write_byte, pdev->client, ccode, | ||
309 | seq->data[idx]); | ||
310 | if (sts != 0) | ||
311 | return (int)sts; | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * idt_smb_read_byte() - SMBus read method when I2C_SMBUS_BYTE_DATA operation | ||
319 | * is only available | ||
320 | * @pdev: Pointer to the driver data | ||
321 | * @seq: Buffer to read data to | ||
322 | */ | ||
323 | static int idt_smb_read_byte(struct idt_89hpesx_dev *pdev, | ||
324 | struct idt_smb_seq *seq) | ||
325 | { | ||
326 | s32 sts; | ||
327 | u8 ccode; | ||
328 | int idx; | ||
329 | |||
330 | /* Loop over the supplied buffer receiving byte one-by-one */ | ||
331 | for (idx = 0; idx < seq->bytecnt; idx++) { | ||
332 | /* Collect the command code byte */ | ||
333 | ccode = seq->ccode | CCODE_BYTE; | ||
334 | if (idx == 0) | ||
335 | ccode |= CCODE_START; | ||
336 | if (idx == seq->bytecnt - 1) | ||
337 | ccode |= CCODE_END; | ||
338 | |||
339 | /* Read data from the device */ | ||
340 | sts = idt_smb_safe(read_byte, pdev->client, ccode); | ||
341 | if (sts < 0) | ||
342 | return (int)sts; | ||
343 | |||
344 | seq->data[idx] = (u8)sts; | ||
345 | } | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * idt_smb_write_word() - SMBus write method when I2C_SMBUS_BYTE_DATA and | ||
352 | * I2C_FUNC_SMBUS_WORD_DATA operations are available | ||
353 | * @pdev: Pointer to the driver data | ||
354 | * @seq: Sequence of data to be written | ||
355 | */ | ||
356 | static int idt_smb_write_word(struct idt_89hpesx_dev *pdev, | ||
357 | const struct idt_smb_seq *seq) | ||
358 | { | ||
359 | s32 sts; | ||
360 | u8 ccode; | ||
361 | int idx, evencnt; | ||
362 | |||
363 | /* Calculate the even count of data to send */ | ||
364 | evencnt = seq->bytecnt - (seq->bytecnt % 2); | ||
365 | |||
366 | /* Loop over the supplied data sending two bytes at a time */ | ||
367 | for (idx = 0; idx < evencnt; idx += 2) { | ||
368 | /* Collect the command code byte */ | ||
369 | ccode = seq->ccode | CCODE_WORD; | ||
370 | if (idx == 0) | ||
371 | ccode |= CCODE_START; | ||
372 | if (idx == evencnt - 2) | ||
373 | ccode |= CCODE_END; | ||
374 | |||
375 | /* Send word data to the device */ | ||
376 | sts = idt_smb_safe(write_word, pdev->client, ccode, | ||
377 | *(u16 *)&seq->data[idx]); | ||
378 | if (sts != 0) | ||
379 | return (int)sts; | ||
380 | } | ||
381 | |||
382 | /* If there is odd number of bytes then send just one last byte */ | ||
383 | if (seq->bytecnt != evencnt) { | ||
384 | /* Collect the command code byte */ | ||
385 | ccode = seq->ccode | CCODE_BYTE | CCODE_END; | ||
386 | if (idx == 0) | ||
387 | ccode |= CCODE_START; | ||
388 | |||
389 | /* Send byte data to the device */ | ||
390 | sts = idt_smb_safe(write_byte, pdev->client, ccode, | ||
391 | seq->data[idx]); | ||
392 | if (sts != 0) | ||
393 | return (int)sts; | ||
394 | } | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * idt_smb_read_word() - SMBus read method when I2C_SMBUS_BYTE_DATA and | ||
401 | * I2C_FUNC_SMBUS_WORD_DATA operations are available | ||
402 | * @pdev: Pointer to the driver data | ||
403 | * @seq: Buffer to read data to | ||
404 | */ | ||
405 | static int idt_smb_read_word(struct idt_89hpesx_dev *pdev, | ||
406 | struct idt_smb_seq *seq) | ||
407 | { | ||
408 | s32 sts; | ||
409 | u8 ccode; | ||
410 | int idx, evencnt; | ||
411 | |||
412 | /* Calculate the even count of data to send */ | ||
413 | evencnt = seq->bytecnt - (seq->bytecnt % 2); | ||
414 | |||
415 | /* Loop over the supplied data reading two bytes at a time */ | ||
416 | for (idx = 0; idx < evencnt; idx += 2) { | ||
417 | /* Collect the command code byte */ | ||
418 | ccode = seq->ccode | CCODE_WORD; | ||
419 | if (idx == 0) | ||
420 | ccode |= CCODE_START; | ||
421 | if (idx == evencnt - 2) | ||
422 | ccode |= CCODE_END; | ||
423 | |||
424 | /* Read word data from the device */ | ||
425 | sts = idt_smb_safe(read_word, pdev->client, ccode); | ||
426 | if (sts < 0) | ||
427 | return (int)sts; | ||
428 | |||
429 | *(u16 *)&seq->data[idx] = (u16)sts; | ||
430 | } | ||
431 | |||
432 | /* If there is odd number of bytes then receive just one last byte */ | ||
433 | if (seq->bytecnt != evencnt) { | ||
434 | /* Collect the command code byte */ | ||
435 | ccode = seq->ccode | CCODE_BYTE | CCODE_END; | ||
436 | if (idx == 0) | ||
437 | ccode |= CCODE_START; | ||
438 | |||
439 | /* Read last data byte from the device */ | ||
440 | sts = idt_smb_safe(read_byte, pdev->client, ccode); | ||
441 | if (sts < 0) | ||
442 | return (int)sts; | ||
443 | |||
444 | seq->data[idx] = (u8)sts; | ||
445 | } | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | /* | ||
451 | * idt_smb_write_block() - SMBus write method when I2C_SMBUS_BLOCK_DATA | ||
452 | * operation is available | ||
453 | * @pdev: Pointer to the driver data | ||
454 | * @seq: Sequence of data to be written | ||
455 | */ | ||
456 | static int idt_smb_write_block(struct idt_89hpesx_dev *pdev, | ||
457 | const struct idt_smb_seq *seq) | ||
458 | { | ||
459 | u8 ccode; | ||
460 | |||
461 | /* Return error if too much data passed to send */ | ||
462 | if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) | ||
463 | return -EINVAL; | ||
464 | |||
465 | /* Collect the command code byte */ | ||
466 | ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; | ||
467 | |||
468 | /* Send block of data to the device */ | ||
469 | return idt_smb_safe(write_block, pdev->client, ccode, seq->bytecnt, | ||
470 | seq->data); | ||
471 | } | ||
472 | |||
473 | /* | ||
474 | * idt_smb_read_block() - SMBus read method when I2C_SMBUS_BLOCK_DATA | ||
475 | * operation is available | ||
476 | * @pdev: Pointer to the driver data | ||
477 | * @seq: Buffer to read data to | ||
478 | */ | ||
479 | static int idt_smb_read_block(struct idt_89hpesx_dev *pdev, | ||
480 | struct idt_smb_seq *seq) | ||
481 | { | ||
482 | s32 sts; | ||
483 | u8 ccode; | ||
484 | |||
485 | /* Return error if too much data passed to send */ | ||
486 | if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) | ||
487 | return -EINVAL; | ||
488 | |||
489 | /* Collect the command code byte */ | ||
490 | ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; | ||
491 | |||
492 | /* Read block of data from the device */ | ||
493 | sts = idt_smb_safe(read_block, pdev->client, ccode, seq->data); | ||
494 | if (sts != seq->bytecnt) | ||
495 | return (sts < 0 ? sts : -ENODATA); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * idt_smb_write_i2c_block() - SMBus write method when I2C_SMBUS_I2C_BLOCK_DATA | ||
502 | * operation is available | ||
503 | * @pdev: Pointer to the driver data | ||
504 | * @seq: Sequence of data to be written | ||
505 | * | ||
506 | * NOTE It's usual SMBus write block operation, except the actual data length is | ||
507 | * sent as first byte of data | ||
508 | */ | ||
509 | static int idt_smb_write_i2c_block(struct idt_89hpesx_dev *pdev, | ||
510 | const struct idt_smb_seq *seq) | ||
511 | { | ||
512 | u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1]; | ||
513 | |||
514 | /* Return error if too much data passed to send */ | ||
515 | if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) | ||
516 | return -EINVAL; | ||
517 | |||
518 | /* Collect the data to send. Length byte must be added prior the data */ | ||
519 | buf[0] = seq->bytecnt; | ||
520 | memcpy(&buf[1], seq->data, seq->bytecnt); | ||
521 | |||
522 | /* Collect the command code byte */ | ||
523 | ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; | ||
524 | |||
525 | /* Send length and block of data to the device */ | ||
526 | return idt_smb_safe(write_i2c_block, pdev->client, ccode, | ||
527 | seq->bytecnt + 1, buf); | ||
528 | } | ||
529 | |||
530 | /* | ||
531 | * idt_smb_read_i2c_block() - SMBus read method when I2C_SMBUS_I2C_BLOCK_DATA | ||
532 | * operation is available | ||
533 | * @pdev: Pointer to the driver data | ||
534 | * @seq: Buffer to read data to | ||
535 | * | ||
536 | * NOTE It's usual SMBus read block operation, except the actual data length is | ||
537 | * retrieved as first byte of data | ||
538 | */ | ||
539 | static int idt_smb_read_i2c_block(struct idt_89hpesx_dev *pdev, | ||
540 | struct idt_smb_seq *seq) | ||
541 | { | ||
542 | u8 ccode, buf[I2C_SMBUS_BLOCK_MAX + 1]; | ||
543 | s32 sts; | ||
544 | |||
545 | /* Return error if too much data passed to send */ | ||
546 | if (seq->bytecnt > I2C_SMBUS_BLOCK_MAX) | ||
547 | return -EINVAL; | ||
548 | |||
549 | /* Collect the command code byte */ | ||
550 | ccode = seq->ccode | CCODE_BLOCK | CCODE_START | CCODE_END; | ||
551 | |||
552 | /* Read length and block of data from the device */ | ||
553 | sts = idt_smb_safe(read_i2c_block, pdev->client, ccode, | ||
554 | seq->bytecnt + 1, buf); | ||
555 | if (sts != seq->bytecnt + 1) | ||
556 | return (sts < 0 ? sts : -ENODATA); | ||
557 | if (buf[0] != seq->bytecnt) | ||
558 | return -ENODATA; | ||
559 | |||
560 | /* Copy retrieved data to the output data buffer */ | ||
561 | memcpy(seq->data, &buf[1], seq->bytecnt); | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | /*=========================================================================== | ||
567 | * EEPROM IO-operations | ||
568 | *=========================================================================== | ||
569 | */ | ||
570 | |||
571 | /* | ||
572 | * idt_eeprom_read_byte() - read just one byte from EEPROM | ||
573 | * @pdev: Pointer to the driver data | ||
574 | * @memaddr: Start EEPROM memory address | ||
575 | * @data: Data to be written to EEPROM | ||
576 | */ | ||
577 | static int idt_eeprom_read_byte(struct idt_89hpesx_dev *pdev, u16 memaddr, | ||
578 | u8 *data) | ||
579 | { | ||
580 | struct device *dev = &pdev->client->dev; | ||
581 | struct idt_eeprom_seq eeseq; | ||
582 | struct idt_smb_seq smbseq; | ||
583 | int ret, retry; | ||
584 | |||
585 | /* Initialize SMBus sequence fields */ | ||
586 | smbseq.ccode = pdev->iniccode | CCODE_EEPROM; | ||
587 | smbseq.data = (u8 *)&eeseq; | ||
588 | |||
589 | /* | ||
590 | * Sometimes EEPROM may respond with NACK if it's busy with previous | ||
591 | * operation, so we need to perform a few attempts of read cycle | ||
592 | */ | ||
593 | retry = RETRY_CNT; | ||
594 | do { | ||
595 | /* Send EEPROM memory address to read data from */ | ||
596 | smbseq.bytecnt = EEPROM_WRRD_CNT; | ||
597 | eeseq.cmd = pdev->inieecmd | EEPROM_OP_READ; | ||
598 | eeseq.eeaddr = pdev->eeaddr; | ||
599 | eeseq.memaddr = cpu_to_le16(memaddr); | ||
600 | ret = pdev->smb_write(pdev, &smbseq); | ||
601 | if (ret != 0) { | ||
602 | dev_err(dev, "Failed to init eeprom addr 0x%02hhx", | ||
603 | memaddr); | ||
604 | break; | ||
605 | } | ||
606 | |||
607 | /* Perform read operation */ | ||
608 | smbseq.bytecnt = EEPROM_RD_CNT; | ||
609 | ret = pdev->smb_read(pdev, &smbseq); | ||
610 | if (ret != 0) { | ||
611 | dev_err(dev, "Failed to read eeprom data 0x%02hhx", | ||
612 | memaddr); | ||
613 | break; | ||
614 | } | ||
615 | |||
616 | /* Restart read operation if the device is busy */ | ||
617 | if (retry && (eeseq.cmd & EEPROM_NAERR)) { | ||
618 | dev_dbg(dev, "EEPROM busy, retry reading after %d ms", | ||
619 | EEPROM_TOUT); | ||
620 | msleep(EEPROM_TOUT); | ||
621 | continue; | ||
622 | } | ||
623 | |||
624 | /* Check whether IDT successfully read data from EEPROM */ | ||
625 | if (eeseq.cmd & (EEPROM_NAERR | EEPROM_LAERR | EEPROM_MSS)) { | ||
626 | dev_err(dev, | ||
627 | "Communication with eeprom failed, cmd 0x%hhx", | ||
628 | eeseq.cmd); | ||
629 | ret = -EREMOTEIO; | ||
630 | break; | ||
631 | } | ||
632 | |||
633 | /* Save retrieved data and exit the loop */ | ||
634 | *data = eeseq.data; | ||
635 | break; | ||
636 | } while (retry--); | ||
637 | |||
638 | /* Return the status of operation */ | ||
639 | return ret; | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * idt_eeprom_write() - EEPROM write operation | ||
644 | * @pdev: Pointer to the driver data | ||
645 | * @memaddr: Start EEPROM memory address | ||
646 | * @len: Length of data to be written | ||
647 | * @data: Data to be written to EEPROM | ||
648 | */ | ||
649 | static int idt_eeprom_write(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len, | ||
650 | const u8 *data) | ||
651 | { | ||
652 | struct device *dev = &pdev->client->dev; | ||
653 | struct idt_eeprom_seq eeseq; | ||
654 | struct idt_smb_seq smbseq; | ||
655 | int ret; | ||
656 | u16 idx; | ||
657 | |||
658 | /* Initialize SMBus sequence fields */ | ||
659 | smbseq.ccode = pdev->iniccode | CCODE_EEPROM; | ||
660 | smbseq.data = (u8 *)&eeseq; | ||
661 | |||
662 | /* Send data byte-by-byte, checking if it is successfully written */ | ||
663 | for (idx = 0; idx < len; idx++, memaddr++) { | ||
664 | /* Lock IDT SMBus device */ | ||
665 | mutex_lock(&pdev->smb_mtx); | ||
666 | |||
667 | /* Perform write operation */ | ||
668 | smbseq.bytecnt = EEPROM_WR_CNT; | ||
669 | eeseq.cmd = pdev->inieecmd | EEPROM_OP_WRITE; | ||
670 | eeseq.eeaddr = pdev->eeaddr; | ||
671 | eeseq.memaddr = cpu_to_le16(memaddr); | ||
672 | eeseq.data = data[idx]; | ||
673 | ret = pdev->smb_write(pdev, &smbseq); | ||
674 | if (ret != 0) { | ||
675 | dev_err(dev, | ||
676 | "Failed to write 0x%04hx:0x%02hhx to eeprom", | ||
677 | memaddr, data[idx]); | ||
678 | goto err_mutex_unlock; | ||
679 | } | ||
680 | |||
681 | /* | ||
682 | * Check whether the data is successfully written by reading | ||
683 | * from the same EEPROM memory address. | ||
684 | */ | ||
685 | eeseq.data = ~data[idx]; | ||
686 | ret = idt_eeprom_read_byte(pdev, memaddr, &eeseq.data); | ||
687 | if (ret != 0) | ||
688 | goto err_mutex_unlock; | ||
689 | |||
690 | /* Check whether the read byte is the same as written one */ | ||
691 | if (eeseq.data != data[idx]) { | ||
692 | dev_err(dev, "Values don't match 0x%02hhx != 0x%02hhx", | ||
693 | eeseq.data, data[idx]); | ||
694 | ret = -EREMOTEIO; | ||
695 | goto err_mutex_unlock; | ||
696 | } | ||
697 | |||
698 | /* Unlock IDT SMBus device */ | ||
699 | err_mutex_unlock: | ||
700 | mutex_unlock(&pdev->smb_mtx); | ||
701 | if (ret != 0) | ||
702 | return ret; | ||
703 | } | ||
704 | |||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | /* | ||
709 | * idt_eeprom_read() - EEPROM read operation | ||
710 | * @pdev: Pointer to the driver data | ||
711 | * @memaddr: Start EEPROM memory address | ||
712 | * @len: Length of data to read | ||
713 | * @buf: Buffer to read data to | ||
714 | */ | ||
715 | static int idt_eeprom_read(struct idt_89hpesx_dev *pdev, u16 memaddr, u16 len, | ||
716 | u8 *buf) | ||
717 | { | ||
718 | int ret; | ||
719 | u16 idx; | ||
720 | |||
721 | /* Read data byte-by-byte, retrying if it wasn't successful */ | ||
722 | for (idx = 0; idx < len; idx++, memaddr++) { | ||
723 | /* Lock IDT SMBus device */ | ||
724 | mutex_lock(&pdev->smb_mtx); | ||
725 | |||
726 | /* Just read the byte to the buffer */ | ||
727 | ret = idt_eeprom_read_byte(pdev, memaddr, &buf[idx]); | ||
728 | |||
729 | /* Unlock IDT SMBus device */ | ||
730 | mutex_unlock(&pdev->smb_mtx); | ||
731 | |||
732 | /* Return error if read operation failed */ | ||
733 | if (ret != 0) | ||
734 | return ret; | ||
735 | } | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | /*=========================================================================== | ||
741 | * CSR IO-operations | ||
742 | *=========================================================================== | ||
743 | */ | ||
744 | |||
745 | /* | ||
746 | * idt_csr_write() - CSR write operation | ||
747 | * @pdev: Pointer to the driver data | ||
748 | * @csraddr: CSR address (with no two LS bits) | ||
749 | * @data: Data to be written to CSR | ||
750 | */ | ||
751 | static int idt_csr_write(struct idt_89hpesx_dev *pdev, u16 csraddr, | ||
752 | const u32 data) | ||
753 | { | ||
754 | struct device *dev = &pdev->client->dev; | ||
755 | struct idt_csr_seq csrseq; | ||
756 | struct idt_smb_seq smbseq; | ||
757 | int ret; | ||
758 | |||
759 | /* Initialize SMBus sequence fields */ | ||
760 | smbseq.ccode = pdev->iniccode | CCODE_CSR; | ||
761 | smbseq.data = (u8 *)&csrseq; | ||
762 | |||
763 | /* Lock IDT SMBus device */ | ||
764 | mutex_lock(&pdev->smb_mtx); | ||
765 | |||
766 | /* Perform write operation */ | ||
767 | smbseq.bytecnt = CSR_WR_CNT; | ||
768 | csrseq.cmd = pdev->inicsrcmd | CSR_OP_WRITE; | ||
769 | csrseq.csraddr = cpu_to_le16(csraddr); | ||
770 | csrseq.data = cpu_to_le32(data); | ||
771 | ret = pdev->smb_write(pdev, &smbseq); | ||
772 | if (ret != 0) { | ||
773 | dev_err(dev, "Failed to write 0x%04x: 0x%04x to csr", | ||
774 | CSR_REAL_ADDR(csraddr), data); | ||
775 | goto err_mutex_unlock; | ||
776 | } | ||
777 | |||
778 | /* Send CSR address to read data from */ | ||
779 | smbseq.bytecnt = CSR_WRRD_CNT; | ||
780 | csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ; | ||
781 | ret = pdev->smb_write(pdev, &smbseq); | ||
782 | if (ret != 0) { | ||
783 | dev_err(dev, "Failed to init csr address 0x%04x", | ||
784 | CSR_REAL_ADDR(csraddr)); | ||
785 | goto err_mutex_unlock; | ||
786 | } | ||
787 | |||
788 | /* Perform read operation */ | ||
789 | smbseq.bytecnt = CSR_RD_CNT; | ||
790 | ret = pdev->smb_read(pdev, &smbseq); | ||
791 | if (ret != 0) { | ||
792 | dev_err(dev, "Failed to read csr 0x%04x", | ||
793 | CSR_REAL_ADDR(csraddr)); | ||
794 | goto err_mutex_unlock; | ||
795 | } | ||
796 | |||
797 | /* Check whether IDT successfully retrieved CSR data */ | ||
798 | if (csrseq.cmd & (CSR_RERR | CSR_WERR)) { | ||
799 | dev_err(dev, "IDT failed to perform CSR r/w"); | ||
800 | ret = -EREMOTEIO; | ||
801 | goto err_mutex_unlock; | ||
802 | } | ||
803 | |||
804 | /* Unlock IDT SMBus device */ | ||
805 | err_mutex_unlock: | ||
806 | mutex_unlock(&pdev->smb_mtx); | ||
807 | |||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | /* | ||
812 | * idt_csr_read() - CSR read operation | ||
813 | * @pdev: Pointer to the driver data | ||
814 | * @csraddr: CSR address (with no two LS bits) | ||
815 | * @data: Data to be written to CSR | ||
816 | */ | ||
817 | static int idt_csr_read(struct idt_89hpesx_dev *pdev, u16 csraddr, u32 *data) | ||
818 | { | ||
819 | struct device *dev = &pdev->client->dev; | ||
820 | struct idt_csr_seq csrseq; | ||
821 | struct idt_smb_seq smbseq; | ||
822 | int ret; | ||
823 | |||
824 | /* Initialize SMBus sequence fields */ | ||
825 | smbseq.ccode = pdev->iniccode | CCODE_CSR; | ||
826 | smbseq.data = (u8 *)&csrseq; | ||
827 | |||
828 | /* Lock IDT SMBus device */ | ||
829 | mutex_lock(&pdev->smb_mtx); | ||
830 | |||
831 | /* Send CSR register address before reading it */ | ||
832 | smbseq.bytecnt = CSR_WRRD_CNT; | ||
833 | csrseq.cmd = pdev->inicsrcmd | CSR_OP_READ; | ||
834 | csrseq.csraddr = cpu_to_le16(csraddr); | ||
835 | ret = pdev->smb_write(pdev, &smbseq); | ||
836 | if (ret != 0) { | ||
837 | dev_err(dev, "Failed to init csr address 0x%04x", | ||
838 | CSR_REAL_ADDR(csraddr)); | ||
839 | goto err_mutex_unlock; | ||
840 | } | ||
841 | |||
842 | /* Perform read operation */ | ||
843 | smbseq.bytecnt = CSR_RD_CNT; | ||
844 | ret = pdev->smb_read(pdev, &smbseq); | ||
845 | if (ret != 0) { | ||
846 | dev_err(dev, "Failed to read csr 0x%04hx", | ||
847 | CSR_REAL_ADDR(csraddr)); | ||
848 | goto err_mutex_unlock; | ||
849 | } | ||
850 | |||
851 | /* Check whether IDT successfully retrieved CSR data */ | ||
852 | if (csrseq.cmd & (CSR_RERR | CSR_WERR)) { | ||
853 | dev_err(dev, "IDT failed to perform CSR r/w"); | ||
854 | ret = -EREMOTEIO; | ||
855 | goto err_mutex_unlock; | ||
856 | } | ||
857 | |||
858 | /* Save data retrieved from IDT */ | ||
859 | *data = le32_to_cpu(csrseq.data); | ||
860 | |||
861 | /* Unlock IDT SMBus device */ | ||
862 | err_mutex_unlock: | ||
863 | mutex_unlock(&pdev->smb_mtx); | ||
864 | |||
865 | return ret; | ||
866 | } | ||
867 | |||
868 | /*=========================================================================== | ||
869 | * Sysfs/debugfs-nodes IO-operations | ||
870 | *=========================================================================== | ||
871 | */ | ||
872 | |||
873 | /* | ||
874 | * eeprom_write() - EEPROM sysfs-node write callback | ||
875 | * @filep: Pointer to the file system node | ||
876 | * @kobj: Pointer to the kernel object related to the sysfs-node | ||
877 | * @attr: Attributes of the file | ||
878 | * @buf: Buffer to write data to | ||
879 | * @off: Offset at which data should be written to | ||
880 | * @count: Number of bytes to write | ||
881 | */ | ||
882 | static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, | ||
883 | struct bin_attribute *attr, | ||
884 | char *buf, loff_t off, size_t count) | ||
885 | { | ||
886 | struct idt_89hpesx_dev *pdev; | ||
887 | int ret; | ||
888 | |||
889 | /* Retrieve driver data */ | ||
890 | pdev = dev_get_drvdata(kobj_to_dev(kobj)); | ||
891 | |||
892 | /* Perform EEPROM write operation */ | ||
893 | ret = idt_eeprom_write(pdev, (u16)off, (u16)count, (u8 *)buf); | ||
894 | return (ret != 0 ? ret : count); | ||
895 | } | ||
896 | |||
897 | /* | ||
898 | * eeprom_read() - EEPROM sysfs-node read callback | ||
899 | * @filep: Pointer to the file system node | ||
900 | * @kobj: Pointer to the kernel object related to the sysfs-node | ||
901 | * @attr: Attributes of the file | ||
902 | * @buf: Buffer to write data to | ||
903 | * @off: Offset at which data should be written to | ||
904 | * @count: Number of bytes to write | ||
905 | */ | ||
906 | static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, | ||
907 | struct bin_attribute *attr, | ||
908 | char *buf, loff_t off, size_t count) | ||
909 | { | ||
910 | struct idt_89hpesx_dev *pdev; | ||
911 | int ret; | ||
912 | |||
913 | /* Retrieve driver data */ | ||
914 | pdev = dev_get_drvdata(kobj_to_dev(kobj)); | ||
915 | |||
916 | /* Perform EEPROM read operation */ | ||
917 | ret = idt_eeprom_read(pdev, (u16)off, (u16)count, (u8 *)buf); | ||
918 | return (ret != 0 ? ret : count); | ||
919 | } | ||
920 | |||
921 | /* | ||
922 | * idt_dbgfs_csr_write() - CSR debugfs-node write callback | ||
923 | * @filep: Pointer to the file system file descriptor | ||
924 | * @buf: Buffer to read data from | ||
925 | * @count: Size of the buffer | ||
926 | * @offp: Offset within the file | ||
927 | * | ||
928 | * It accepts either "0x<reg addr>:0x<value>" for saving register address | ||
929 | * and writing value to specified DWORD register or "0x<reg addr>" for | ||
930 | * just saving register address in order to perform next read operation. | ||
931 | * | ||
932 | * WARNING No spaces are allowed. Incoming string must be strictly formated as: | ||
933 | * "<reg addr>:<value>". Register address must be aligned within 4 bytes | ||
934 | * (one DWORD). | ||
935 | */ | ||
936 | static ssize_t idt_dbgfs_csr_write(struct file *filep, const char __user *ubuf, | ||
937 | size_t count, loff_t *offp) | ||
938 | { | ||
939 | struct idt_89hpesx_dev *pdev = filep->private_data; | ||
940 | char *colon_ch, *csraddr_str, *csrval_str; | ||
941 | int ret, csraddr_len, csrval_len; | ||
942 | u32 csraddr, csrval; | ||
943 | char *buf; | ||
944 | |||
945 | /* Copy data from User-space */ | ||
946 | buf = kmalloc(count + 1, GFP_KERNEL); | ||
947 | if (!buf) | ||
948 | return -ENOMEM; | ||
949 | |||
950 | ret = simple_write_to_buffer(buf, count, offp, ubuf, count); | ||
951 | if (ret < 0) | ||
952 | goto free_buf; | ||
953 | buf[count] = 0; | ||
954 | |||
955 | /* Find position of colon in the buffer */ | ||
956 | colon_ch = strnchr(buf, count, ':'); | ||
957 | |||
958 | /* | ||
959 | * If there is colon passed then new CSR value should be parsed as | ||
960 | * well, so allocate buffer for CSR address substring. | ||
961 | * If no colon is found, then string must have just one number with | ||
962 | * no new CSR value | ||
963 | */ | ||
964 | if (colon_ch != NULL) { | ||
965 | csraddr_len = colon_ch - buf; | ||
966 | csraddr_str = | ||
967 | kmalloc(sizeof(char)*(csraddr_len + 1), GFP_KERNEL); | ||
968 | if (csraddr_str == NULL) { | ||
969 | ret = -ENOMEM; | ||
970 | goto free_buf; | ||
971 | } | ||
972 | /* Copy the register address to the substring buffer */ | ||
973 | strncpy(csraddr_str, buf, csraddr_len); | ||
974 | csraddr_str[csraddr_len] = '\0'; | ||
975 | /* Register value must follow the colon */ | ||
976 | csrval_str = colon_ch + 1; | ||
977 | csrval_len = strnlen(csrval_str, count - csraddr_len); | ||
978 | } else /* if (str_colon == NULL) */ { | ||
979 | csraddr_str = (char *)buf; /* Just to shut warning up */ | ||
980 | csraddr_len = strnlen(csraddr_str, count); | ||
981 | csrval_str = NULL; | ||
982 | csrval_len = 0; | ||
983 | } | ||
984 | |||
985 | /* Convert CSR address to u32 value */ | ||
986 | ret = kstrtou32(csraddr_str, 0, &csraddr); | ||
987 | if (ret != 0) | ||
988 | goto free_csraddr_str; | ||
989 | |||
990 | /* Check whether passed register address is valid */ | ||
991 | if (csraddr > CSR_MAX || !IS_ALIGNED(csraddr, SZ_4)) { | ||
992 | ret = -EINVAL; | ||
993 | goto free_csraddr_str; | ||
994 | } | ||
995 | |||
996 | /* Shift register address to the right so to have u16 address */ | ||
997 | pdev->csr = (csraddr >> 2); | ||
998 | |||
999 | /* Parse new CSR value and send it to IDT, if colon has been found */ | ||
1000 | if (colon_ch != NULL) { | ||
1001 | ret = kstrtou32(csrval_str, 0, &csrval); | ||
1002 | if (ret != 0) | ||
1003 | goto free_csraddr_str; | ||
1004 | |||
1005 | ret = idt_csr_write(pdev, pdev->csr, csrval); | ||
1006 | if (ret != 0) | ||
1007 | goto free_csraddr_str; | ||
1008 | } | ||
1009 | |||
1010 | /* Free memory only if colon has been found */ | ||
1011 | free_csraddr_str: | ||
1012 | if (colon_ch != NULL) | ||
1013 | kfree(csraddr_str); | ||
1014 | |||
1015 | /* Free buffer allocated for data retrieved from User-space */ | ||
1016 | free_buf: | ||
1017 | kfree(buf); | ||
1018 | |||
1019 | return (ret != 0 ? ret : count); | ||
1020 | } | ||
1021 | |||
1022 | /* | ||
1023 | * idt_dbgfs_csr_read() - CSR debugfs-node read callback | ||
1024 | * @filep: Pointer to the file system file descriptor | ||
1025 | * @buf: Buffer to write data to | ||
1026 | * @count: Size of the buffer | ||
1027 | * @offp: Offset within the file | ||
1028 | * | ||
1029 | * It just prints the pair "0x<reg addr>:0x<value>" to passed buffer. | ||
1030 | */ | ||
1031 | #define CSRBUF_SIZE ((size_t)32) | ||
1032 | static ssize_t idt_dbgfs_csr_read(struct file *filep, char __user *ubuf, | ||
1033 | size_t count, loff_t *offp) | ||
1034 | { | ||
1035 | struct idt_89hpesx_dev *pdev = filep->private_data; | ||
1036 | u32 csraddr, csrval; | ||
1037 | char buf[CSRBUF_SIZE]; | ||
1038 | int ret, size; | ||
1039 | |||
1040 | /* Perform CSR read operation */ | ||
1041 | ret = idt_csr_read(pdev, pdev->csr, &csrval); | ||
1042 | if (ret != 0) | ||
1043 | return ret; | ||
1044 | |||
1045 | /* Shift register address to the left so to have real address */ | ||
1046 | csraddr = ((u32)pdev->csr << 2); | ||
1047 | |||
1048 | /* Print the "0x<reg addr>:0x<value>" to buffer */ | ||
1049 | size = snprintf(buf, CSRBUF_SIZE, "0x%05x:0x%08x\n", | ||
1050 | (unsigned int)csraddr, (unsigned int)csrval); | ||
1051 | |||
1052 | /* Copy data to User-space */ | ||
1053 | return simple_read_from_buffer(ubuf, count, offp, buf, size); | ||
1054 | } | ||
1055 | |||
1056 | /* | ||
1057 | * eeprom_attribute - EEPROM sysfs-node attributes | ||
1058 | * | ||
1059 | * NOTE Size will be changed in compliance with OF node. EEPROM attribute will | ||
1060 | * be read-only as well if the corresponding flag is specified in OF node. | ||
1061 | */ | ||
1062 | static BIN_ATTR_RW(eeprom, EEPROM_DEF_SIZE); | ||
1063 | |||
1064 | /* | ||
1065 | * csr_dbgfs_ops - CSR debugfs-node read/write operations | ||
1066 | */ | ||
1067 | static const struct file_operations csr_dbgfs_ops = { | ||
1068 | .owner = THIS_MODULE, | ||
1069 | .open = simple_open, | ||
1070 | .write = idt_dbgfs_csr_write, | ||
1071 | .read = idt_dbgfs_csr_read | ||
1072 | }; | ||
1073 | |||
1074 | /*=========================================================================== | ||
1075 | * Driver init/deinit methods | ||
1076 | *=========================================================================== | ||
1077 | */ | ||
1078 | |||
1079 | /* | ||
1080 | * idt_set_defval() - disable EEPROM access by default | ||
1081 | * @pdev: Pointer to the driver data | ||
1082 | */ | ||
1083 | static void idt_set_defval(struct idt_89hpesx_dev *pdev) | ||
1084 | { | ||
1085 | /* If OF info is missing then use next values */ | ||
1086 | pdev->eesize = 0; | ||
1087 | pdev->eero = true; | ||
1088 | pdev->inieecmd = 0; | ||
1089 | pdev->eeaddr = 0; | ||
1090 | } | ||
1091 | |||
1092 | #ifdef CONFIG_OF | ||
1093 | static const struct i2c_device_id ee_ids[]; | ||
1094 | /* | ||
1095 | * idt_ee_match_id() - check whether the node belongs to compatible EEPROMs | ||
1096 | */ | ||
1097 | static const struct i2c_device_id *idt_ee_match_id(struct device_node *node) | ||
1098 | { | ||
1099 | const struct i2c_device_id *id = ee_ids; | ||
1100 | char devname[I2C_NAME_SIZE]; | ||
1101 | |||
1102 | /* Retrieve the device name without manufacturer name */ | ||
1103 | if (of_modalias_node(node, devname, sizeof(devname))) | ||
1104 | return NULL; | ||
1105 | |||
1106 | /* Search through the device name */ | ||
1107 | while (id->name[0]) { | ||
1108 | if (strcmp(devname, id->name) == 0) | ||
1109 | return id; | ||
1110 | id++; | ||
1111 | } | ||
1112 | return NULL; | ||
1113 | } | ||
1114 | |||
1115 | /* | ||
1116 | * idt_get_ofdata() - get IDT i2c-device parameters from device tree | ||
1117 | * @pdev: Pointer to the driver data | ||
1118 | */ | ||
1119 | static void idt_get_ofdata(struct idt_89hpesx_dev *pdev) | ||
1120 | { | ||
1121 | const struct device_node *node = pdev->client->dev.of_node; | ||
1122 | struct device *dev = &pdev->client->dev; | ||
1123 | |||
1124 | /* Read dts node parameters */ | ||
1125 | if (node) { | ||
1126 | const struct i2c_device_id *ee_id = NULL; | ||
1127 | struct device_node *child; | ||
1128 | const __be32 *addr_be; | ||
1129 | int len; | ||
1130 | |||
1131 | /* Walk through all child nodes looking for compatible one */ | ||
1132 | for_each_available_child_of_node(node, child) { | ||
1133 | ee_id = idt_ee_match_id(child); | ||
1134 | if (IS_ERR_OR_NULL(ee_id)) { | ||
1135 | dev_warn(dev, "Skip unsupported child node %s", | ||
1136 | child->full_name); | ||
1137 | continue; | ||
1138 | } else | ||
1139 | break; | ||
1140 | } | ||
1141 | |||
1142 | /* If there is no child EEPROM device, then set zero size */ | ||
1143 | if (!ee_id) { | ||
1144 | idt_set_defval(pdev); | ||
1145 | return; | ||
1146 | } | ||
1147 | |||
1148 | /* Retrieve EEPROM size */ | ||
1149 | pdev->eesize = (u32)ee_id->driver_data; | ||
1150 | |||
1151 | /* Get custom EEPROM address from 'reg' attribute */ | ||
1152 | addr_be = of_get_property(child, "reg", &len); | ||
1153 | if (!addr_be || (len < sizeof(*addr_be))) { | ||
1154 | dev_warn(dev, "No reg on %s, use default address %d", | ||
1155 | child->full_name, EEPROM_DEF_ADDR); | ||
1156 | pdev->inieecmd = 0; | ||
1157 | pdev->eeaddr = EEPROM_DEF_ADDR << 1; | ||
1158 | } else { | ||
1159 | pdev->inieecmd = EEPROM_USA; | ||
1160 | pdev->eeaddr = be32_to_cpup(addr_be) << 1; | ||
1161 | } | ||
1162 | |||
1163 | /* Check EEPROM 'read-only' flag */ | ||
1164 | if (of_get_property(child, "read-only", NULL)) | ||
1165 | pdev->eero = true; | ||
1166 | else /* if (!of_get_property(node, "read-only", NULL)) */ | ||
1167 | pdev->eero = false; | ||
1168 | |||
1169 | dev_dbg(dev, "EEPROM of %u bytes found by %hhu", | ||
1170 | pdev->eesize, pdev->eeaddr); | ||
1171 | } else { | ||
1172 | dev_warn(dev, "No dts node, EEPROM access disabled"); | ||
1173 | idt_set_defval(pdev); | ||
1174 | } | ||
1175 | } | ||
1176 | #else | ||
1177 | static void idt_get_ofdata(struct idt_89hpesx_dev *pdev) | ||
1178 | { | ||
1179 | struct device *dev = &pdev->client->dev; | ||
1180 | |||
1181 | dev_warn(dev, "OF table is unsupported, EEPROM access disabled"); | ||
1182 | |||
1183 | /* Nothing we can do, just set the default values */ | ||
1184 | idt_set_defval(pdev); | ||
1185 | } | ||
1186 | #endif /* CONFIG_OF */ | ||
1187 | |||
1188 | /* | ||
1189 | * idt_create_pdev() - create and init data structure of the driver | ||
1190 | * @client: i2c client of IDT PCIe-switch device | ||
1191 | */ | ||
1192 | static struct idt_89hpesx_dev *idt_create_pdev(struct i2c_client *client) | ||
1193 | { | ||
1194 | struct idt_89hpesx_dev *pdev; | ||
1195 | |||
1196 | /* Allocate memory for driver data */ | ||
1197 | pdev = devm_kmalloc(&client->dev, sizeof(struct idt_89hpesx_dev), | ||
1198 | GFP_KERNEL); | ||
1199 | if (pdev == NULL) | ||
1200 | return ERR_PTR(-ENOMEM); | ||
1201 | |||
1202 | /* Initialize basic fields of the data */ | ||
1203 | pdev->client = client; | ||
1204 | i2c_set_clientdata(client, pdev); | ||
1205 | |||
1206 | /* Read OF nodes information */ | ||
1207 | idt_get_ofdata(pdev); | ||
1208 | |||
1209 | /* Initialize basic CSR CMD field - use full DWORD-sized r/w ops */ | ||
1210 | pdev->inicsrcmd = CSR_DWE; | ||
1211 | pdev->csr = CSR_DEF; | ||
1212 | |||
1213 | /* Enable Packet Error Checking if it's supported by adapter */ | ||
1214 | if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_PEC)) { | ||
1215 | pdev->iniccode = CCODE_PEC; | ||
1216 | client->flags |= I2C_CLIENT_PEC; | ||
1217 | } else /* PEC is unsupported */ { | ||
1218 | pdev->iniccode = 0; | ||
1219 | } | ||
1220 | |||
1221 | return pdev; | ||
1222 | } | ||
1223 | |||
1224 | /* | ||
1225 | * idt_free_pdev() - free data structure of the driver | ||
1226 | * @pdev: Pointer to the driver data | ||
1227 | */ | ||
1228 | static void idt_free_pdev(struct idt_89hpesx_dev *pdev) | ||
1229 | { | ||
1230 | /* Clear driver data from device private field */ | ||
1231 | i2c_set_clientdata(pdev->client, NULL); | ||
1232 | } | ||
1233 | |||
1234 | /* | ||
1235 | * idt_set_smbus_ops() - set supported SMBus operations | ||
1236 | * @pdev: Pointer to the driver data | ||
1237 | * Return status of smbus check operations | ||
1238 | */ | ||
1239 | static int idt_set_smbus_ops(struct idt_89hpesx_dev *pdev) | ||
1240 | { | ||
1241 | struct i2c_adapter *adapter = pdev->client->adapter; | ||
1242 | struct device *dev = &pdev->client->dev; | ||
1243 | |||
1244 | /* Check i2c adapter read functionality */ | ||
1245 | if (i2c_check_functionality(adapter, | ||
1246 | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { | ||
1247 | pdev->smb_read = idt_smb_read_block; | ||
1248 | dev_dbg(dev, "SMBus block-read op chosen"); | ||
1249 | } else if (i2c_check_functionality(adapter, | ||
1250 | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | ||
1251 | pdev->smb_read = idt_smb_read_i2c_block; | ||
1252 | dev_dbg(dev, "SMBus i2c-block-read op chosen"); | ||
1253 | } else if (i2c_check_functionality(adapter, | ||
1254 | I2C_FUNC_SMBUS_READ_WORD_DATA) && | ||
1255 | i2c_check_functionality(adapter, | ||
1256 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { | ||
1257 | pdev->smb_read = idt_smb_read_word; | ||
1258 | dev_warn(dev, "Use slow word/byte SMBus read ops"); | ||
1259 | } else if (i2c_check_functionality(adapter, | ||
1260 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) { | ||
1261 | pdev->smb_read = idt_smb_read_byte; | ||
1262 | dev_warn(dev, "Use slow byte SMBus read op"); | ||
1263 | } else /* no supported smbus read operations */ { | ||
1264 | dev_err(dev, "No supported SMBus read op"); | ||
1265 | return -EPFNOSUPPORT; | ||
1266 | } | ||
1267 | |||
1268 | /* Check i2c adapter write functionality */ | ||
1269 | if (i2c_check_functionality(adapter, | ||
1270 | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)) { | ||
1271 | pdev->smb_write = idt_smb_write_block; | ||
1272 | dev_dbg(dev, "SMBus block-write op chosen"); | ||
1273 | } else if (i2c_check_functionality(adapter, | ||
1274 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { | ||
1275 | pdev->smb_write = idt_smb_write_i2c_block; | ||
1276 | dev_dbg(dev, "SMBus i2c-block-write op chosen"); | ||
1277 | } else if (i2c_check_functionality(adapter, | ||
1278 | I2C_FUNC_SMBUS_WRITE_WORD_DATA) && | ||
1279 | i2c_check_functionality(adapter, | ||
1280 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { | ||
1281 | pdev->smb_write = idt_smb_write_word; | ||
1282 | dev_warn(dev, "Use slow word/byte SMBus write op"); | ||
1283 | } else if (i2c_check_functionality(adapter, | ||
1284 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { | ||
1285 | pdev->smb_write = idt_smb_write_byte; | ||
1286 | dev_warn(dev, "Use slow byte SMBus write op"); | ||
1287 | } else /* no supported smbus write operations */ { | ||
1288 | dev_err(dev, "No supported SMBus write op"); | ||
1289 | return -EPFNOSUPPORT; | ||
1290 | } | ||
1291 | |||
1292 | /* Initialize IDT SMBus slave interface mutex */ | ||
1293 | mutex_init(&pdev->smb_mtx); | ||
1294 | |||
1295 | return 0; | ||
1296 | } | ||
1297 | |||
1298 | /* | ||
1299 | * idt_check_dev() - check whether it's really IDT 89HPESx device | ||
1300 | * @pdev: Pointer to the driver data | ||
1301 | * Return status of i2c adapter check operation | ||
1302 | */ | ||
1303 | static int idt_check_dev(struct idt_89hpesx_dev *pdev) | ||
1304 | { | ||
1305 | struct device *dev = &pdev->client->dev; | ||
1306 | u32 viddid; | ||
1307 | int ret; | ||
1308 | |||
1309 | /* Read VID and DID directly from IDT memory space */ | ||
1310 | ret = idt_csr_read(pdev, IDT_VIDDID_CSR, &viddid); | ||
1311 | if (ret != 0) { | ||
1312 | dev_err(dev, "Failed to read VID/DID"); | ||
1313 | return ret; | ||
1314 | } | ||
1315 | |||
1316 | /* Check whether it's IDT device */ | ||
1317 | if ((viddid & IDT_VID_MASK) != PCI_VENDOR_ID_IDT) { | ||
1318 | dev_err(dev, "Got unsupported VID/DID: 0x%08x", viddid); | ||
1319 | return -ENODEV; | ||
1320 | } | ||
1321 | |||
1322 | dev_info(dev, "Found IDT 89HPES device VID:0x%04x, DID:0x%04x", | ||
1323 | (viddid & IDT_VID_MASK), (viddid >> 16)); | ||
1324 | |||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | /* | ||
1329 | * idt_create_sysfs_files() - create sysfs attribute files | ||
1330 | * @pdev: Pointer to the driver data | ||
1331 | * Return status of operation | ||
1332 | */ | ||
1333 | static int idt_create_sysfs_files(struct idt_89hpesx_dev *pdev) | ||
1334 | { | ||
1335 | struct device *dev = &pdev->client->dev; | ||
1336 | int ret; | ||
1337 | |||
1338 | /* Don't do anything if EEPROM isn't accessible */ | ||
1339 | if (pdev->eesize == 0) { | ||
1340 | dev_dbg(dev, "Skip creating sysfs-files"); | ||
1341 | return 0; | ||
1342 | } | ||
1343 | |||
1344 | /* Allocate memory for attribute file */ | ||
1345 | pdev->ee_file = devm_kmalloc(dev, sizeof(*pdev->ee_file), GFP_KERNEL); | ||
1346 | if (!pdev->ee_file) | ||
1347 | return -ENOMEM; | ||
1348 | |||
1349 | /* Copy the declared EEPROM attr structure to change some of fields */ | ||
1350 | memcpy(pdev->ee_file, &bin_attr_eeprom, sizeof(*pdev->ee_file)); | ||
1351 | |||
1352 | /* In case of read-only EEPROM get rid of write ability */ | ||
1353 | if (pdev->eero) { | ||
1354 | pdev->ee_file->attr.mode &= ~0200; | ||
1355 | pdev->ee_file->write = NULL; | ||
1356 | } | ||
1357 | /* Create EEPROM sysfs file */ | ||
1358 | pdev->ee_file->size = pdev->eesize; | ||
1359 | ret = sysfs_create_bin_file(&dev->kobj, pdev->ee_file); | ||
1360 | if (ret != 0) { | ||
1361 | dev_err(dev, "Failed to create EEPROM sysfs-node"); | ||
1362 | return ret; | ||
1363 | } | ||
1364 | |||
1365 | return 0; | ||
1366 | } | ||
1367 | |||
1368 | /* | ||
1369 | * idt_remove_sysfs_files() - remove sysfs attribute files | ||
1370 | * @pdev: Pointer to the driver data | ||
1371 | */ | ||
1372 | static void idt_remove_sysfs_files(struct idt_89hpesx_dev *pdev) | ||
1373 | { | ||
1374 | struct device *dev = &pdev->client->dev; | ||
1375 | |||
1376 | /* Don't do anything if EEPROM wasn't accessible */ | ||
1377 | if (pdev->eesize == 0) | ||
1378 | return; | ||
1379 | |||
1380 | /* Remove EEPROM sysfs file */ | ||
1381 | sysfs_remove_bin_file(&dev->kobj, pdev->ee_file); | ||
1382 | } | ||
1383 | |||
1384 | /* | ||
1385 | * idt_create_dbgfs_files() - create debugfs files | ||
1386 | * @pdev: Pointer to the driver data | ||
1387 | */ | ||
1388 | #define CSRNAME_LEN ((size_t)32) | ||
1389 | static void idt_create_dbgfs_files(struct idt_89hpesx_dev *pdev) | ||
1390 | { | ||
1391 | struct i2c_client *cli = pdev->client; | ||
1392 | char fname[CSRNAME_LEN]; | ||
1393 | |||
1394 | /* Create Debugfs directory for CSR file */ | ||
1395 | snprintf(fname, CSRNAME_LEN, "%d-%04hx", cli->adapter->nr, cli->addr); | ||
1396 | pdev->csr_dir = debugfs_create_dir(fname, csr_dbgdir); | ||
1397 | |||
1398 | /* Create Debugfs file for CSR read/write operations */ | ||
1399 | pdev->csr_file = debugfs_create_file(cli->name, 0600, | ||
1400 | pdev->csr_dir, pdev, &csr_dbgfs_ops); | ||
1401 | } | ||
1402 | |||
1403 | /* | ||
1404 | * idt_remove_dbgfs_files() - remove debugfs files | ||
1405 | * @pdev: Pointer to the driver data | ||
1406 | */ | ||
1407 | static void idt_remove_dbgfs_files(struct idt_89hpesx_dev *pdev) | ||
1408 | { | ||
1409 | /* Remove CSR directory and it sysfs-node */ | ||
1410 | debugfs_remove_recursive(pdev->csr_dir); | ||
1411 | } | ||
1412 | |||
1413 | /* | ||
1414 | * idt_probe() - IDT 89HPESx driver probe() callback method | ||
1415 | */ | ||
1416 | static int idt_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
1417 | { | ||
1418 | struct idt_89hpesx_dev *pdev; | ||
1419 | int ret; | ||
1420 | |||
1421 | /* Create driver data */ | ||
1422 | pdev = idt_create_pdev(client); | ||
1423 | if (IS_ERR(pdev)) | ||
1424 | return PTR_ERR(pdev); | ||
1425 | |||
1426 | /* Set SMBus operations */ | ||
1427 | ret = idt_set_smbus_ops(pdev); | ||
1428 | if (ret != 0) | ||
1429 | goto err_free_pdev; | ||
1430 | |||
1431 | /* Check whether it is truly IDT 89HPESx device */ | ||
1432 | ret = idt_check_dev(pdev); | ||
1433 | if (ret != 0) | ||
1434 | goto err_free_pdev; | ||
1435 | |||
1436 | /* Create sysfs files */ | ||
1437 | ret = idt_create_sysfs_files(pdev); | ||
1438 | if (ret != 0) | ||
1439 | goto err_free_pdev; | ||
1440 | |||
1441 | /* Create debugfs files */ | ||
1442 | idt_create_dbgfs_files(pdev); | ||
1443 | |||
1444 | return 0; | ||
1445 | |||
1446 | err_free_pdev: | ||
1447 | idt_free_pdev(pdev); | ||
1448 | |||
1449 | return ret; | ||
1450 | } | ||
1451 | |||
1452 | /* | ||
1453 | * idt_remove() - IDT 89HPESx driver remove() callback method | ||
1454 | */ | ||
1455 | static int idt_remove(struct i2c_client *client) | ||
1456 | { | ||
1457 | struct idt_89hpesx_dev *pdev = i2c_get_clientdata(client); | ||
1458 | |||
1459 | /* Remove debugfs files first */ | ||
1460 | idt_remove_dbgfs_files(pdev); | ||
1461 | |||
1462 | /* Remove sysfs files */ | ||
1463 | idt_remove_sysfs_files(pdev); | ||
1464 | |||
1465 | /* Discard driver data structure */ | ||
1466 | idt_free_pdev(pdev); | ||
1467 | |||
1468 | return 0; | ||
1469 | } | ||
1470 | |||
1471 | /* | ||
1472 | * ee_ids - array of supported EEPROMs | ||
1473 | */ | ||
1474 | static const struct i2c_device_id ee_ids[] = { | ||
1475 | { "24c32", 4096}, | ||
1476 | { "24c64", 8192}, | ||
1477 | { "24c128", 16384}, | ||
1478 | { "24c256", 32768}, | ||
1479 | { "24c512", 65536}, | ||
1480 | {} | ||
1481 | }; | ||
1482 | MODULE_DEVICE_TABLE(i2c, ee_ids); | ||
1483 | |||
1484 | /* | ||
1485 | * idt_ids - supported IDT 89HPESx devices | ||
1486 | */ | ||
1487 | static const struct i2c_device_id idt_ids[] = { | ||
1488 | { "89hpes8nt2", 0 }, | ||
1489 | { "89hpes12nt3", 0 }, | ||
1490 | |||
1491 | { "89hpes24nt6ag2", 0 }, | ||
1492 | { "89hpes32nt8ag2", 0 }, | ||
1493 | { "89hpes32nt8bg2", 0 }, | ||
1494 | { "89hpes12nt12g2", 0 }, | ||
1495 | { "89hpes16nt16g2", 0 }, | ||
1496 | { "89hpes24nt24g2", 0 }, | ||
1497 | { "89hpes32nt24ag2", 0 }, | ||
1498 | { "89hpes32nt24bg2", 0 }, | ||
1499 | |||
1500 | { "89hpes12n3", 0 }, | ||
1501 | { "89hpes12n3a", 0 }, | ||
1502 | { "89hpes24n3", 0 }, | ||
1503 | { "89hpes24n3a", 0 }, | ||
1504 | |||
1505 | { "89hpes32h8", 0 }, | ||
1506 | { "89hpes32h8g2", 0 }, | ||
1507 | { "89hpes48h12", 0 }, | ||
1508 | { "89hpes48h12g2", 0 }, | ||
1509 | { "89hpes48h12ag2", 0 }, | ||
1510 | { "89hpes16h16", 0 }, | ||
1511 | { "89hpes22h16", 0 }, | ||
1512 | { "89hpes22h16g2", 0 }, | ||
1513 | { "89hpes34h16", 0 }, | ||
1514 | { "89hpes34h16g2", 0 }, | ||
1515 | { "89hpes64h16", 0 }, | ||
1516 | { "89hpes64h16g2", 0 }, | ||
1517 | { "89hpes64h16ag2", 0 }, | ||
1518 | |||
1519 | /* { "89hpes3t3", 0 }, // No SMBus-slave iface */ | ||
1520 | { "89hpes12t3g2", 0 }, | ||
1521 | { "89hpes24t3g2", 0 }, | ||
1522 | /* { "89hpes4t4", 0 }, // No SMBus-slave iface */ | ||
1523 | { "89hpes16t4", 0 }, | ||
1524 | { "89hpes4t4g2", 0 }, | ||
1525 | { "89hpes10t4g2", 0 }, | ||
1526 | { "89hpes16t4g2", 0 }, | ||
1527 | { "89hpes16t4ag2", 0 }, | ||
1528 | { "89hpes5t5", 0 }, | ||
1529 | { "89hpes6t5", 0 }, | ||
1530 | { "89hpes8t5", 0 }, | ||
1531 | { "89hpes8t5a", 0 }, | ||
1532 | { "89hpes24t6", 0 }, | ||
1533 | { "89hpes6t6g2", 0 }, | ||
1534 | { "89hpes24t6g2", 0 }, | ||
1535 | { "89hpes16t7", 0 }, | ||
1536 | { "89hpes32t8", 0 }, | ||
1537 | { "89hpes32t8g2", 0 }, | ||
1538 | { "89hpes48t12", 0 }, | ||
1539 | { "89hpes48t12g2", 0 }, | ||
1540 | { /* END OF LIST */ } | ||
1541 | }; | ||
1542 | MODULE_DEVICE_TABLE(i2c, idt_ids); | ||
1543 | |||
1544 | /* | ||
1545 | * idt_driver - IDT 89HPESx driver structure | ||
1546 | */ | ||
1547 | static struct i2c_driver idt_driver = { | ||
1548 | .driver = { | ||
1549 | .name = IDT_NAME, | ||
1550 | }, | ||
1551 | .probe = idt_probe, | ||
1552 | .remove = idt_remove, | ||
1553 | .id_table = idt_ids, | ||
1554 | }; | ||
1555 | |||
1556 | /* | ||
1557 | * idt_init() - IDT 89HPESx driver init() callback method | ||
1558 | */ | ||
1559 | static int __init idt_init(void) | ||
1560 | { | ||
1561 | /* Create Debugfs directory first */ | ||
1562 | if (debugfs_initialized()) | ||
1563 | csr_dbgdir = debugfs_create_dir("idt_csr", NULL); | ||
1564 | |||
1565 | /* Add new i2c-device driver */ | ||
1566 | return i2c_add_driver(&idt_driver); | ||
1567 | } | ||
1568 | module_init(idt_init); | ||
1569 | |||
1570 | /* | ||
1571 | * idt_exit() - IDT 89HPESx driver exit() callback method | ||
1572 | */ | ||
1573 | static void __exit idt_exit(void) | ||
1574 | { | ||
1575 | /* Discard debugfs directory and all files if any */ | ||
1576 | debugfs_remove_recursive(csr_dbgdir); | ||
1577 | |||
1578 | /* Unregister i2c-device driver */ | ||
1579 | i2c_del_driver(&idt_driver); | ||
1580 | } | ||
1581 | module_exit(idt_exit); | ||
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c index 6c1f49a85023..4fd21e86ad56 100644 --- a/drivers/misc/genwqe/card_base.c +++ b/drivers/misc/genwqe/card_base.c | |||
@@ -1336,7 +1336,6 @@ static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs) | |||
1336 | static struct pci_error_handlers genwqe_err_handler = { | 1336 | static struct pci_error_handlers genwqe_err_handler = { |
1337 | .error_detected = genwqe_err_error_detected, | 1337 | .error_detected = genwqe_err_error_detected, |
1338 | .mmio_enabled = genwqe_err_result_none, | 1338 | .mmio_enabled = genwqe_err_result_none, |
1339 | .link_reset = genwqe_err_result_none, | ||
1340 | .slot_reset = genwqe_err_slot_reset, | 1339 | .slot_reset = genwqe_err_slot_reset, |
1341 | .resume = genwqe_err_resume, | 1340 | .resume = genwqe_err_resume, |
1342 | }; | 1341 | }; |
diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c index cba0837aee2e..e3f4cd8876b5 100644 --- a/drivers/misc/lkdtm_bugs.c +++ b/drivers/misc/lkdtm_bugs.c | |||
@@ -81,12 +81,17 @@ void lkdtm_OVERFLOW(void) | |||
81 | (void) recursive_loop(recur_count); | 81 | (void) recursive_loop(recur_count); |
82 | } | 82 | } |
83 | 83 | ||
84 | static noinline void __lkdtm_CORRUPT_STACK(void *stack) | ||
85 | { | ||
86 | memset(stack, 'a', 64); | ||
87 | } | ||
88 | |||
84 | noinline void lkdtm_CORRUPT_STACK(void) | 89 | noinline void lkdtm_CORRUPT_STACK(void) |
85 | { | 90 | { |
86 | /* Use default char array length that triggers stack protection. */ | 91 | /* Use default char array length that triggers stack protection. */ |
87 | char data[8]; | 92 | char data[8]; |
93 | __lkdtm_CORRUPT_STACK(&data); | ||
88 | 94 | ||
89 | memset((void *)data, 'a', 64); | ||
90 | pr_info("Corrupted stack with '%16s'...\n", data); | 95 | pr_info("Corrupted stack with '%16s'...\n", data); |
91 | } | 96 | } |
92 | 97 | ||
diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 16e4cf110930..b9a4cd4a9b68 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c | |||
@@ -539,7 +539,9 @@ static void __exit lkdtm_module_exit(void) | |||
539 | /* Handle test-specific clean-up. */ | 539 | /* Handle test-specific clean-up. */ |
540 | lkdtm_usercopy_exit(); | 540 | lkdtm_usercopy_exit(); |
541 | 541 | ||
542 | unregister_jprobe(lkdtm_jprobe); | 542 | if (lkdtm_jprobe != NULL) |
543 | unregister_jprobe(lkdtm_jprobe); | ||
544 | |||
543 | pr_info("Crash point unregistered\n"); | 545 | pr_info("Crash point unregistered\n"); |
544 | } | 546 | } |
545 | 547 | ||
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index 466afb2611c6..0e7406ccb6dd 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c | |||
@@ -132,8 +132,7 @@ int mei_amthif_run_next_cmd(struct mei_device *dev) | |||
132 | 132 | ||
133 | dev_dbg(dev->dev, "complete amthif cmd_list cb.\n"); | 133 | dev_dbg(dev->dev, "complete amthif cmd_list cb.\n"); |
134 | 134 | ||
135 | cb = list_first_entry_or_null(&dev->amthif_cmd_list.list, | 135 | cb = list_first_entry_or_null(&dev->amthif_cmd_list, typeof(*cb), list); |
136 | typeof(*cb), list); | ||
137 | if (!cb) { | 136 | if (!cb) { |
138 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 137 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
139 | cl->fp = NULL; | 138 | cl->fp = NULL; |
@@ -167,7 +166,7 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
167 | 166 | ||
168 | struct mei_device *dev = cl->dev; | 167 | struct mei_device *dev = cl->dev; |
169 | 168 | ||
170 | list_add_tail(&cb->list, &dev->amthif_cmd_list.list); | 169 | list_add_tail(&cb->list, &dev->amthif_cmd_list); |
171 | 170 | ||
172 | /* | 171 | /* |
173 | * The previous request is still in processing, queue this one. | 172 | * The previous request is still in processing, queue this one. |
@@ -211,7 +210,7 @@ unsigned int mei_amthif_poll(struct file *file, poll_table *wait) | |||
211 | * Return: 0, OK; otherwise, error. | 210 | * Return: 0, OK; otherwise, error. |
212 | */ | 211 | */ |
213 | int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | 212 | int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, |
214 | struct mei_cl_cb *cmpl_list) | 213 | struct list_head *cmpl_list) |
215 | { | 214 | { |
216 | int ret; | 215 | int ret; |
217 | 216 | ||
@@ -237,7 +236,7 @@ int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
237 | */ | 236 | */ |
238 | int mei_amthif_irq_read_msg(struct mei_cl *cl, | 237 | int mei_amthif_irq_read_msg(struct mei_cl *cl, |
239 | struct mei_msg_hdr *mei_hdr, | 238 | struct mei_msg_hdr *mei_hdr, |
240 | struct mei_cl_cb *cmpl_list) | 239 | struct list_head *cmpl_list) |
241 | { | 240 | { |
242 | struct mei_device *dev; | 241 | struct mei_device *dev; |
243 | int ret; | 242 | int ret; |
@@ -312,50 +311,30 @@ void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
312 | } | 311 | } |
313 | 312 | ||
314 | /** | 313 | /** |
315 | * mei_clear_list - removes all callbacks associated with file | ||
316 | * from mei_cb_list | ||
317 | * | ||
318 | * @file: file structure | ||
319 | * @mei_cb_list: callbacks list | ||
320 | * | ||
321 | * mei_clear_list is called to clear resources associated with file | ||
322 | * when application calls close function or Ctrl-C was pressed | ||
323 | */ | ||
324 | static void mei_clear_list(const struct file *file, | ||
325 | struct list_head *mei_cb_list) | ||
326 | { | ||
327 | struct mei_cl_cb *cb, *next; | ||
328 | |||
329 | list_for_each_entry_safe(cb, next, mei_cb_list, list) | ||
330 | if (file == cb->fp) | ||
331 | mei_io_cb_free(cb); | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * mei_amthif_release - the release function | 314 | * mei_amthif_release - the release function |
336 | * | 315 | * |
337 | * @dev: device structure | 316 | * @dev: device structure |
338 | * @file: pointer to file structure | 317 | * @fp: pointer to file structure |
339 | * | 318 | * |
340 | * Return: 0 on success, <0 on error | 319 | * Return: 0 on success, <0 on error |
341 | */ | 320 | */ |
342 | int mei_amthif_release(struct mei_device *dev, struct file *file) | 321 | int mei_amthif_release(struct mei_device *dev, struct file *fp) |
343 | { | 322 | { |
344 | struct mei_cl *cl = file->private_data; | 323 | struct mei_cl *cl = fp->private_data; |
345 | 324 | ||
346 | if (dev->iamthif_open_count > 0) | 325 | if (dev->iamthif_open_count > 0) |
347 | dev->iamthif_open_count--; | 326 | dev->iamthif_open_count--; |
348 | 327 | ||
349 | if (cl->fp == file && dev->iamthif_state != MEI_IAMTHIF_IDLE) { | 328 | if (cl->fp == fp && dev->iamthif_state != MEI_IAMTHIF_IDLE) { |
350 | 329 | ||
351 | dev_dbg(dev->dev, "amthif canceled iamthif state %d\n", | 330 | dev_dbg(dev->dev, "amthif canceled iamthif state %d\n", |
352 | dev->iamthif_state); | 331 | dev->iamthif_state); |
353 | dev->iamthif_canceled = true; | 332 | dev->iamthif_canceled = true; |
354 | } | 333 | } |
355 | 334 | ||
356 | mei_clear_list(file, &dev->amthif_cmd_list.list); | 335 | /* Don't clean ctrl_rd_list here, the reads has to be completed */ |
357 | mei_clear_list(file, &cl->rd_completed); | 336 | mei_io_list_free_fp(&dev->amthif_cmd_list, fp); |
358 | mei_clear_list(file, &dev->ctrl_rd_list.list); | 337 | mei_io_list_free_fp(&cl->rd_completed, fp); |
359 | 338 | ||
360 | return 0; | 339 | return 0; |
361 | } | 340 | } |
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 2d9c5dd06e42..cb3e9e0ca049 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
@@ -499,6 +499,25 @@ out: | |||
499 | EXPORT_SYMBOL_GPL(mei_cldev_enable); | 499 | EXPORT_SYMBOL_GPL(mei_cldev_enable); |
500 | 500 | ||
501 | /** | 501 | /** |
502 | * mei_cldev_unregister_callbacks - internal wrapper for unregistering | ||
503 | * callbacks. | ||
504 | * | ||
505 | * @cldev: client device | ||
506 | */ | ||
507 | static void mei_cldev_unregister_callbacks(struct mei_cl_device *cldev) | ||
508 | { | ||
509 | if (cldev->rx_cb) { | ||
510 | cancel_work_sync(&cldev->rx_work); | ||
511 | cldev->rx_cb = NULL; | ||
512 | } | ||
513 | |||
514 | if (cldev->notif_cb) { | ||
515 | cancel_work_sync(&cldev->notif_work); | ||
516 | cldev->notif_cb = NULL; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | /** | ||
502 | * mei_cldev_disable - disable me client device | 521 | * mei_cldev_disable - disable me client device |
503 | * disconnect form the me client | 522 | * disconnect form the me client |
504 | * | 523 | * |
@@ -519,6 +538,8 @@ int mei_cldev_disable(struct mei_cl_device *cldev) | |||
519 | 538 | ||
520 | bus = cldev->bus; | 539 | bus = cldev->bus; |
521 | 540 | ||
541 | mei_cldev_unregister_callbacks(cldev); | ||
542 | |||
522 | mutex_lock(&bus->device_lock); | 543 | mutex_lock(&bus->device_lock); |
523 | 544 | ||
524 | if (!mei_cl_is_connected(cl)) { | 545 | if (!mei_cl_is_connected(cl)) { |
@@ -542,6 +563,37 @@ out: | |||
542 | EXPORT_SYMBOL_GPL(mei_cldev_disable); | 563 | EXPORT_SYMBOL_GPL(mei_cldev_disable); |
543 | 564 | ||
544 | /** | 565 | /** |
566 | * mei_cl_bus_module_get - acquire module of the underlying | ||
567 | * hw module. | ||
568 | * | ||
569 | * @cl: host client | ||
570 | * | ||
571 | * Return: true on success; false if the module was removed. | ||
572 | */ | ||
573 | bool mei_cl_bus_module_get(struct mei_cl *cl) | ||
574 | { | ||
575 | struct mei_cl_device *cldev = cl->cldev; | ||
576 | |||
577 | if (!cldev) | ||
578 | return true; | ||
579 | |||
580 | return try_module_get(cldev->bus->dev->driver->owner); | ||
581 | } | ||
582 | |||
583 | /** | ||
584 | * mei_cl_bus_module_put - release the underlying hw module. | ||
585 | * | ||
586 | * @cl: host client | ||
587 | */ | ||
588 | void mei_cl_bus_module_put(struct mei_cl *cl) | ||
589 | { | ||
590 | struct mei_cl_device *cldev = cl->cldev; | ||
591 | |||
592 | if (cldev) | ||
593 | module_put(cldev->bus->dev->driver->owner); | ||
594 | } | ||
595 | |||
596 | /** | ||
545 | * mei_cl_device_find - find matching entry in the driver id table | 597 | * mei_cl_device_find - find matching entry in the driver id table |
546 | * | 598 | * |
547 | * @cldev: me client device | 599 | * @cldev: me client device |
@@ -665,19 +717,12 @@ static int mei_cl_device_remove(struct device *dev) | |||
665 | if (!cldev || !dev->driver) | 717 | if (!cldev || !dev->driver) |
666 | return 0; | 718 | return 0; |
667 | 719 | ||
668 | if (cldev->rx_cb) { | ||
669 | cancel_work_sync(&cldev->rx_work); | ||
670 | cldev->rx_cb = NULL; | ||
671 | } | ||
672 | if (cldev->notif_cb) { | ||
673 | cancel_work_sync(&cldev->notif_work); | ||
674 | cldev->notif_cb = NULL; | ||
675 | } | ||
676 | |||
677 | cldrv = to_mei_cl_driver(dev->driver); | 720 | cldrv = to_mei_cl_driver(dev->driver); |
678 | if (cldrv->remove) | 721 | if (cldrv->remove) |
679 | ret = cldrv->remove(cldev); | 722 | ret = cldrv->remove(cldev); |
680 | 723 | ||
724 | mei_cldev_unregister_callbacks(cldev); | ||
725 | |||
681 | module_put(THIS_MODULE); | 726 | module_put(THIS_MODULE); |
682 | dev->driver = NULL; | 727 | dev->driver = NULL; |
683 | return ret; | 728 | return ret; |
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index b0395601c6ae..68fe37b5bc52 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c | |||
@@ -377,19 +377,19 @@ static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, | |||
377 | } | 377 | } |
378 | 378 | ||
379 | /** | 379 | /** |
380 | * __mei_io_list_flush - removes and frees cbs belonging to cl. | 380 | * __mei_io_list_flush_cl - removes and frees cbs belonging to cl. |
381 | * | 381 | * |
382 | * @list: an instance of our list structure | 382 | * @head: an instance of our list structure |
383 | * @cl: host client, can be NULL for flushing the whole list | 383 | * @cl: host client, can be NULL for flushing the whole list |
384 | * @free: whether to free the cbs | 384 | * @free: whether to free the cbs |
385 | */ | 385 | */ |
386 | static void __mei_io_list_flush(struct mei_cl_cb *list, | 386 | static void __mei_io_list_flush_cl(struct list_head *head, |
387 | struct mei_cl *cl, bool free) | 387 | const struct mei_cl *cl, bool free) |
388 | { | 388 | { |
389 | struct mei_cl_cb *cb, *next; | 389 | struct mei_cl_cb *cb, *next; |
390 | 390 | ||
391 | /* enable removing everything if no cl is specified */ | 391 | /* enable removing everything if no cl is specified */ |
392 | list_for_each_entry_safe(cb, next, &list->list, list) { | 392 | list_for_each_entry_safe(cb, next, head, list) { |
393 | if (!cl || mei_cl_cmp_id(cl, cb->cl)) { | 393 | if (!cl || mei_cl_cmp_id(cl, cb->cl)) { |
394 | list_del_init(&cb->list); | 394 | list_del_init(&cb->list); |
395 | if (free) | 395 | if (free) |
@@ -399,25 +399,42 @@ static void __mei_io_list_flush(struct mei_cl_cb *list, | |||
399 | } | 399 | } |
400 | 400 | ||
401 | /** | 401 | /** |
402 | * mei_io_list_flush - removes list entry belonging to cl. | 402 | * mei_io_list_flush_cl - removes list entry belonging to cl. |
403 | * | 403 | * |
404 | * @list: An instance of our list structure | 404 | * @head: An instance of our list structure |
405 | * @cl: host client | 405 | * @cl: host client |
406 | */ | 406 | */ |
407 | void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) | 407 | static inline void mei_io_list_flush_cl(struct list_head *head, |
408 | const struct mei_cl *cl) | ||
408 | { | 409 | { |
409 | __mei_io_list_flush(list, cl, false); | 410 | __mei_io_list_flush_cl(head, cl, false); |
410 | } | 411 | } |
411 | 412 | ||
412 | /** | 413 | /** |
413 | * mei_io_list_free - removes cb belonging to cl and free them | 414 | * mei_io_list_free_cl - removes cb belonging to cl and free them |
414 | * | 415 | * |
415 | * @list: An instance of our list structure | 416 | * @head: An instance of our list structure |
416 | * @cl: host client | 417 | * @cl: host client |
417 | */ | 418 | */ |
418 | static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl) | 419 | static inline void mei_io_list_free_cl(struct list_head *head, |
420 | const struct mei_cl *cl) | ||
419 | { | 421 | { |
420 | __mei_io_list_flush(list, cl, true); | 422 | __mei_io_list_flush_cl(head, cl, true); |
423 | } | ||
424 | |||
425 | /** | ||
426 | * mei_io_list_free_fp - free cb from a list that matches file pointer | ||
427 | * | ||
428 | * @head: io list | ||
429 | * @fp: file pointer (matching cb file object), may be NULL | ||
430 | */ | ||
431 | void mei_io_list_free_fp(struct list_head *head, const struct file *fp) | ||
432 | { | ||
433 | struct mei_cl_cb *cb, *next; | ||
434 | |||
435 | list_for_each_entry_safe(cb, next, head, list) | ||
436 | if (!fp || fp == cb->fp) | ||
437 | mei_io_cb_free(cb); | ||
421 | } | 438 | } |
422 | 439 | ||
423 | /** | 440 | /** |
@@ -479,7 +496,7 @@ struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length, | |||
479 | if (!cb) | 496 | if (!cb) |
480 | return NULL; | 497 | return NULL; |
481 | 498 | ||
482 | list_add_tail(&cb->list, &cl->dev->ctrl_wr_list.list); | 499 | list_add_tail(&cb->list, &cl->dev->ctrl_wr_list); |
483 | return cb; | 500 | return cb; |
484 | } | 501 | } |
485 | 502 | ||
@@ -504,27 +521,6 @@ struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, const struct file *fp) | |||
504 | } | 521 | } |
505 | 522 | ||
506 | /** | 523 | /** |
507 | * mei_cl_read_cb_flush - free client's read pending and completed cbs | ||
508 | * for a specific file | ||
509 | * | ||
510 | * @cl: host client | ||
511 | * @fp: file pointer (matching cb file object), may be NULL | ||
512 | */ | ||
513 | void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp) | ||
514 | { | ||
515 | struct mei_cl_cb *cb, *next; | ||
516 | |||
517 | list_for_each_entry_safe(cb, next, &cl->rd_completed, list) | ||
518 | if (!fp || fp == cb->fp) | ||
519 | mei_io_cb_free(cb); | ||
520 | |||
521 | |||
522 | list_for_each_entry_safe(cb, next, &cl->rd_pending, list) | ||
523 | if (!fp || fp == cb->fp) | ||
524 | mei_io_cb_free(cb); | ||
525 | } | ||
526 | |||
527 | /** | ||
528 | * mei_cl_flush_queues - flushes queue lists belonging to cl. | 524 | * mei_cl_flush_queues - flushes queue lists belonging to cl. |
529 | * | 525 | * |
530 | * @cl: host client | 526 | * @cl: host client |
@@ -542,18 +538,16 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp) | |||
542 | dev = cl->dev; | 538 | dev = cl->dev; |
543 | 539 | ||
544 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); | 540 | cl_dbg(dev, cl, "remove list entry belonging to cl\n"); |
545 | mei_io_list_free(&cl->dev->write_list, cl); | 541 | mei_io_list_free_cl(&cl->dev->write_list, cl); |
546 | mei_io_list_free(&cl->dev->write_waiting_list, cl); | 542 | mei_io_list_free_cl(&cl->dev->write_waiting_list, cl); |
547 | mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); | 543 | mei_io_list_flush_cl(&cl->dev->ctrl_wr_list, cl); |
548 | mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); | 544 | mei_io_list_flush_cl(&cl->dev->ctrl_rd_list, cl); |
549 | mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); | 545 | mei_io_list_free_fp(&cl->rd_pending, fp); |
550 | 546 | mei_io_list_free_fp(&cl->rd_completed, fp); | |
551 | mei_cl_read_cb_flush(cl, fp); | ||
552 | 547 | ||
553 | return 0; | 548 | return 0; |
554 | } | 549 | } |
555 | 550 | ||
556 | |||
557 | /** | 551 | /** |
558 | * mei_cl_init - initializes cl. | 552 | * mei_cl_init - initializes cl. |
559 | * | 553 | * |
@@ -756,7 +750,7 @@ static void mei_cl_wake_all(struct mei_cl *cl) | |||
756 | * | 750 | * |
757 | * @cl: host client | 751 | * @cl: host client |
758 | */ | 752 | */ |
759 | void mei_cl_set_disconnected(struct mei_cl *cl) | 753 | static void mei_cl_set_disconnected(struct mei_cl *cl) |
760 | { | 754 | { |
761 | struct mei_device *dev = cl->dev; | 755 | struct mei_device *dev = cl->dev; |
762 | 756 | ||
@@ -765,15 +759,18 @@ void mei_cl_set_disconnected(struct mei_cl *cl) | |||
765 | return; | 759 | return; |
766 | 760 | ||
767 | cl->state = MEI_FILE_DISCONNECTED; | 761 | cl->state = MEI_FILE_DISCONNECTED; |
768 | mei_io_list_free(&dev->write_list, cl); | 762 | mei_io_list_free_cl(&dev->write_list, cl); |
769 | mei_io_list_free(&dev->write_waiting_list, cl); | 763 | mei_io_list_free_cl(&dev->write_waiting_list, cl); |
770 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 764 | mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); |
771 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | 765 | mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); |
766 | mei_io_list_free_cl(&dev->amthif_cmd_list, cl); | ||
772 | mei_cl_wake_all(cl); | 767 | mei_cl_wake_all(cl); |
773 | cl->rx_flow_ctrl_creds = 0; | 768 | cl->rx_flow_ctrl_creds = 0; |
774 | cl->tx_flow_ctrl_creds = 0; | 769 | cl->tx_flow_ctrl_creds = 0; |
775 | cl->timer_count = 0; | 770 | cl->timer_count = 0; |
776 | 771 | ||
772 | mei_cl_bus_module_put(cl); | ||
773 | |||
777 | if (!cl->me_cl) | 774 | if (!cl->me_cl) |
778 | return; | 775 | return; |
779 | 776 | ||
@@ -829,7 +826,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
829 | return ret; | 826 | return ret; |
830 | } | 827 | } |
831 | 828 | ||
832 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 829 | list_move_tail(&cb->list, &dev->ctrl_rd_list); |
833 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 830 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
834 | mei_schedule_stall_timer(dev); | 831 | mei_schedule_stall_timer(dev); |
835 | 832 | ||
@@ -847,7 +844,7 @@ static int mei_cl_send_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
847 | * Return: 0, OK; otherwise, error. | 844 | * Return: 0, OK; otherwise, error. |
848 | */ | 845 | */ |
849 | int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, | 846 | int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, |
850 | struct mei_cl_cb *cmpl_list) | 847 | struct list_head *cmpl_list) |
851 | { | 848 | { |
852 | struct mei_device *dev = cl->dev; | 849 | struct mei_device *dev = cl->dev; |
853 | u32 msg_slots; | 850 | u32 msg_slots; |
@@ -862,7 +859,7 @@ int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
862 | 859 | ||
863 | ret = mei_cl_send_disconnect(cl, cb); | 860 | ret = mei_cl_send_disconnect(cl, cb); |
864 | if (ret) | 861 | if (ret) |
865 | list_move_tail(&cb->list, &cmpl_list->list); | 862 | list_move_tail(&cb->list, cmpl_list); |
866 | 863 | ||
867 | return ret; | 864 | return ret; |
868 | } | 865 | } |
@@ -984,7 +981,7 @@ static bool mei_cl_is_other_connecting(struct mei_cl *cl) | |||
984 | 981 | ||
985 | dev = cl->dev; | 982 | dev = cl->dev; |
986 | 983 | ||
987 | list_for_each_entry(cb, &dev->ctrl_rd_list.list, list) { | 984 | list_for_each_entry(cb, &dev->ctrl_rd_list, list) { |
988 | if (cb->fop_type == MEI_FOP_CONNECT && | 985 | if (cb->fop_type == MEI_FOP_CONNECT && |
989 | mei_cl_me_id(cl) == mei_cl_me_id(cb->cl)) | 986 | mei_cl_me_id(cl) == mei_cl_me_id(cb->cl)) |
990 | return true; | 987 | return true; |
@@ -1015,7 +1012,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
1015 | return ret; | 1012 | return ret; |
1016 | } | 1013 | } |
1017 | 1014 | ||
1018 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 1015 | list_move_tail(&cb->list, &dev->ctrl_rd_list); |
1019 | cl->timer_count = MEI_CONNECT_TIMEOUT; | 1016 | cl->timer_count = MEI_CONNECT_TIMEOUT; |
1020 | mei_schedule_stall_timer(dev); | 1017 | mei_schedule_stall_timer(dev); |
1021 | return 0; | 1018 | return 0; |
@@ -1031,7 +1028,7 @@ static int mei_cl_send_connect(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
1031 | * Return: 0, OK; otherwise, error. | 1028 | * Return: 0, OK; otherwise, error. |
1032 | */ | 1029 | */ |
1033 | int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, | 1030 | int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, |
1034 | struct mei_cl_cb *cmpl_list) | 1031 | struct list_head *cmpl_list) |
1035 | { | 1032 | { |
1036 | struct mei_device *dev = cl->dev; | 1033 | struct mei_device *dev = cl->dev; |
1037 | u32 msg_slots; | 1034 | u32 msg_slots; |
@@ -1049,7 +1046,7 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1049 | 1046 | ||
1050 | rets = mei_cl_send_connect(cl, cb); | 1047 | rets = mei_cl_send_connect(cl, cb); |
1051 | if (rets) | 1048 | if (rets) |
1052 | list_move_tail(&cb->list, &cmpl_list->list); | 1049 | list_move_tail(&cb->list, cmpl_list); |
1053 | 1050 | ||
1054 | return rets; | 1051 | return rets; |
1055 | } | 1052 | } |
@@ -1077,13 +1074,17 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, | |||
1077 | 1074 | ||
1078 | dev = cl->dev; | 1075 | dev = cl->dev; |
1079 | 1076 | ||
1077 | if (!mei_cl_bus_module_get(cl)) | ||
1078 | return -ENODEV; | ||
1079 | |||
1080 | rets = mei_cl_set_connecting(cl, me_cl); | 1080 | rets = mei_cl_set_connecting(cl, me_cl); |
1081 | if (rets) | 1081 | if (rets) |
1082 | return rets; | 1082 | goto nortpm; |
1083 | 1083 | ||
1084 | if (mei_cl_is_fixed_address(cl)) { | 1084 | if (mei_cl_is_fixed_address(cl)) { |
1085 | cl->state = MEI_FILE_CONNECTED; | 1085 | cl->state = MEI_FILE_CONNECTED; |
1086 | return 0; | 1086 | rets = 0; |
1087 | goto nortpm; | ||
1087 | } | 1088 | } |
1088 | 1089 | ||
1089 | rets = pm_runtime_get(dev->dev); | 1090 | rets = pm_runtime_get(dev->dev); |
@@ -1117,8 +1118,8 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, | |||
1117 | 1118 | ||
1118 | if (!mei_cl_is_connected(cl)) { | 1119 | if (!mei_cl_is_connected(cl)) { |
1119 | if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) { | 1120 | if (cl->state == MEI_FILE_DISCONNECT_REQUIRED) { |
1120 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 1121 | mei_io_list_flush_cl(&dev->ctrl_rd_list, cl); |
1121 | mei_io_list_flush(&dev->ctrl_wr_list, cl); | 1122 | mei_io_list_flush_cl(&dev->ctrl_wr_list, cl); |
1122 | /* ignore disconnect return valuue; | 1123 | /* ignore disconnect return valuue; |
1123 | * in case of failure reset will be invoked | 1124 | * in case of failure reset will be invoked |
1124 | */ | 1125 | */ |
@@ -1270,7 +1271,7 @@ enum mei_cb_file_ops mei_cl_notify_req2fop(u8 req) | |||
1270 | * Return: 0 on such and error otherwise. | 1271 | * Return: 0 on such and error otherwise. |
1271 | */ | 1272 | */ |
1272 | int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, | 1273 | int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, |
1273 | struct mei_cl_cb *cmpl_list) | 1274 | struct list_head *cmpl_list) |
1274 | { | 1275 | { |
1275 | struct mei_device *dev = cl->dev; | 1276 | struct mei_device *dev = cl->dev; |
1276 | u32 msg_slots; | 1277 | u32 msg_slots; |
@@ -1288,11 +1289,11 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1288 | ret = mei_hbm_cl_notify_req(dev, cl, request); | 1289 | ret = mei_hbm_cl_notify_req(dev, cl, request); |
1289 | if (ret) { | 1290 | if (ret) { |
1290 | cl->status = ret; | 1291 | cl->status = ret; |
1291 | list_move_tail(&cb->list, &cmpl_list->list); | 1292 | list_move_tail(&cb->list, cmpl_list); |
1292 | return ret; | 1293 | return ret; |
1293 | } | 1294 | } |
1294 | 1295 | ||
1295 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 1296 | list_move_tail(&cb->list, &dev->ctrl_rd_list); |
1296 | return 0; | 1297 | return 0; |
1297 | } | 1298 | } |
1298 | 1299 | ||
@@ -1325,6 +1326,9 @@ int mei_cl_notify_request(struct mei_cl *cl, | |||
1325 | return -EOPNOTSUPP; | 1326 | return -EOPNOTSUPP; |
1326 | } | 1327 | } |
1327 | 1328 | ||
1329 | if (!mei_cl_is_connected(cl)) | ||
1330 | return -ENODEV; | ||
1331 | |||
1328 | rets = pm_runtime_get(dev->dev); | 1332 | rets = pm_runtime_get(dev->dev); |
1329 | if (rets < 0 && rets != -EINPROGRESS) { | 1333 | if (rets < 0 && rets != -EINPROGRESS) { |
1330 | pm_runtime_put_noidle(dev->dev); | 1334 | pm_runtime_put_noidle(dev->dev); |
@@ -1344,7 +1348,7 @@ int mei_cl_notify_request(struct mei_cl *cl, | |||
1344 | rets = -ENODEV; | 1348 | rets = -ENODEV; |
1345 | goto out; | 1349 | goto out; |
1346 | } | 1350 | } |
1347 | list_move_tail(&cb->list, &dev->ctrl_rd_list.list); | 1351 | list_move_tail(&cb->list, &dev->ctrl_rd_list); |
1348 | } | 1352 | } |
1349 | 1353 | ||
1350 | mutex_unlock(&dev->device_lock); | 1354 | mutex_unlock(&dev->device_lock); |
@@ -1419,6 +1423,11 @@ int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev) | |||
1419 | 1423 | ||
1420 | dev = cl->dev; | 1424 | dev = cl->dev; |
1421 | 1425 | ||
1426 | if (!dev->hbm_f_ev_supported) { | ||
1427 | cl_dbg(dev, cl, "notifications not supported\n"); | ||
1428 | return -EOPNOTSUPP; | ||
1429 | } | ||
1430 | |||
1422 | if (!mei_cl_is_connected(cl)) | 1431 | if (!mei_cl_is_connected(cl)) |
1423 | return -ENODEV; | 1432 | return -ENODEV; |
1424 | 1433 | ||
@@ -1519,7 +1528,7 @@ nortpm: | |||
1519 | * Return: 0, OK; otherwise error. | 1528 | * Return: 0, OK; otherwise error. |
1520 | */ | 1529 | */ |
1521 | int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | 1530 | int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, |
1522 | struct mei_cl_cb *cmpl_list) | 1531 | struct list_head *cmpl_list) |
1523 | { | 1532 | { |
1524 | struct mei_device *dev; | 1533 | struct mei_device *dev; |
1525 | struct mei_msg_data *buf; | 1534 | struct mei_msg_data *buf; |
@@ -1591,13 +1600,13 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
1591 | } | 1600 | } |
1592 | 1601 | ||
1593 | if (mei_hdr.msg_complete) | 1602 | if (mei_hdr.msg_complete) |
1594 | list_move_tail(&cb->list, &dev->write_waiting_list.list); | 1603 | list_move_tail(&cb->list, &dev->write_waiting_list); |
1595 | 1604 | ||
1596 | return 0; | 1605 | return 0; |
1597 | 1606 | ||
1598 | err: | 1607 | err: |
1599 | cl->status = rets; | 1608 | cl->status = rets; |
1600 | list_move_tail(&cb->list, &cmpl_list->list); | 1609 | list_move_tail(&cb->list, cmpl_list); |
1601 | return rets; | 1610 | return rets; |
1602 | } | 1611 | } |
1603 | 1612 | ||
@@ -1687,9 +1696,9 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb) | |||
1687 | 1696 | ||
1688 | out: | 1697 | out: |
1689 | if (mei_hdr.msg_complete) | 1698 | if (mei_hdr.msg_complete) |
1690 | list_add_tail(&cb->list, &dev->write_waiting_list.list); | 1699 | list_add_tail(&cb->list, &dev->write_waiting_list); |
1691 | else | 1700 | else |
1692 | list_add_tail(&cb->list, &dev->write_list.list); | 1701 | list_add_tail(&cb->list, &dev->write_list); |
1693 | 1702 | ||
1694 | cb = NULL; | 1703 | cb = NULL; |
1695 | if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { | 1704 | if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) { |
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index f2545af9be7b..545ae319ba90 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h | |||
@@ -83,17 +83,7 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl) | |||
83 | * MEI IO Functions | 83 | * MEI IO Functions |
84 | */ | 84 | */ |
85 | void mei_io_cb_free(struct mei_cl_cb *priv_cb); | 85 | void mei_io_cb_free(struct mei_cl_cb *priv_cb); |
86 | 86 | void mei_io_list_free_fp(struct list_head *head, const struct file *fp); | |
87 | /** | ||
88 | * mei_io_list_init - Sets up a queue list. | ||
89 | * | ||
90 | * @list: An instance cl callback structure | ||
91 | */ | ||
92 | static inline void mei_io_list_init(struct mei_cl_cb *list) | ||
93 | { | ||
94 | INIT_LIST_HEAD(&list->list); | ||
95 | } | ||
96 | void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl); | ||
97 | 87 | ||
98 | /* | 88 | /* |
99 | * MEI Host Client Functions | 89 | * MEI Host Client Functions |
@@ -110,7 +100,6 @@ struct mei_cl *mei_cl_alloc_linked(struct mei_device *dev); | |||
110 | 100 | ||
111 | struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, | 101 | struct mei_cl_cb *mei_cl_read_cb(const struct mei_cl *cl, |
112 | const struct file *fp); | 102 | const struct file *fp); |
113 | void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp); | ||
114 | struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, | 103 | struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length, |
115 | enum mei_cb_file_ops type, | 104 | enum mei_cb_file_ops type, |
116 | const struct file *fp); | 105 | const struct file *fp); |
@@ -209,19 +198,18 @@ static inline u8 mei_cl_host_addr(const struct mei_cl *cl) | |||
209 | } | 198 | } |
210 | 199 | ||
211 | int mei_cl_disconnect(struct mei_cl *cl); | 200 | int mei_cl_disconnect(struct mei_cl *cl); |
212 | void mei_cl_set_disconnected(struct mei_cl *cl); | ||
213 | int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, | 201 | int mei_cl_irq_disconnect(struct mei_cl *cl, struct mei_cl_cb *cb, |
214 | struct mei_cl_cb *cmpl_list); | 202 | struct list_head *cmpl_list); |
215 | int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, | 203 | int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl, |
216 | const struct file *file); | 204 | const struct file *file); |
217 | int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, | 205 | int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb, |
218 | struct mei_cl_cb *cmpl_list); | 206 | struct list_head *cmpl_list); |
219 | int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp); | 207 | int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp); |
220 | int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr, | 208 | int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr, |
221 | struct mei_cl_cb *cmpl_list); | 209 | struct list_head *cmpl_list); |
222 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb); | 210 | int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb); |
223 | int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | 211 | int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, |
224 | struct mei_cl_cb *cmpl_list); | 212 | struct list_head *cmpl_list); |
225 | 213 | ||
226 | void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb); | 214 | void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb); |
227 | 215 | ||
@@ -232,7 +220,7 @@ enum mei_cb_file_ops mei_cl_notify_req2fop(u8 request); | |||
232 | int mei_cl_notify_request(struct mei_cl *cl, | 220 | int mei_cl_notify_request(struct mei_cl *cl, |
233 | const struct file *file, u8 request); | 221 | const struct file *file, u8 request); |
234 | int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, | 222 | int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb, |
235 | struct mei_cl_cb *cmpl_list); | 223 | struct list_head *cmpl_list); |
236 | int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev); | 224 | int mei_cl_notify_get(struct mei_cl *cl, bool block, bool *notify_ev); |
237 | void mei_cl_notify(struct mei_cl *cl); | 225 | void mei_cl_notify(struct mei_cl *cl); |
238 | 226 | ||
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 25b4a1ba522d..ba3a774c8d71 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c | |||
@@ -815,7 +815,7 @@ static void mei_hbm_cl_res(struct mei_device *dev, | |||
815 | struct mei_cl_cb *cb, *next; | 815 | struct mei_cl_cb *cb, *next; |
816 | 816 | ||
817 | cl = NULL; | 817 | cl = NULL; |
818 | list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list.list, list) { | 818 | list_for_each_entry_safe(cb, next, &dev->ctrl_rd_list, list) { |
819 | 819 | ||
820 | cl = cb->cl; | 820 | cl = cb->cl; |
821 | 821 | ||
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index a05375a3338a..71216affcab1 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c | |||
@@ -140,6 +140,19 @@ static inline void mei_hcsr_set(struct mei_device *dev, u32 reg) | |||
140 | } | 140 | } |
141 | 141 | ||
142 | /** | 142 | /** |
143 | * mei_hcsr_set_hig - set host interrupt (set H_IG) | ||
144 | * | ||
145 | * @dev: the device structure | ||
146 | */ | ||
147 | static inline void mei_hcsr_set_hig(struct mei_device *dev) | ||
148 | { | ||
149 | u32 hcsr; | ||
150 | |||
151 | hcsr = mei_hcsr_read(dev) | H_IG; | ||
152 | mei_hcsr_set(dev, hcsr); | ||
153 | } | ||
154 | |||
155 | /** | ||
143 | * mei_me_d0i3c_read - Reads 32bit data from the D0I3C register | 156 | * mei_me_d0i3c_read - Reads 32bit data from the D0I3C register |
144 | * | 157 | * |
145 | * @dev: the device structure | 158 | * @dev: the device structure |
@@ -381,6 +394,19 @@ static bool mei_me_hw_is_ready(struct mei_device *dev) | |||
381 | } | 394 | } |
382 | 395 | ||
383 | /** | 396 | /** |
397 | * mei_me_hw_is_resetting - check whether the me(hw) is in reset | ||
398 | * | ||
399 | * @dev: mei device | ||
400 | * Return: bool | ||
401 | */ | ||
402 | static bool mei_me_hw_is_resetting(struct mei_device *dev) | ||
403 | { | ||
404 | u32 mecsr = mei_me_mecsr_read(dev); | ||
405 | |||
406 | return (mecsr & ME_RST_HRA) == ME_RST_HRA; | ||
407 | } | ||
408 | |||
409 | /** | ||
384 | * mei_me_hw_ready_wait - wait until the me(hw) has turned ready | 410 | * mei_me_hw_ready_wait - wait until the me(hw) has turned ready |
385 | * or timeout is reached | 411 | * or timeout is reached |
386 | * | 412 | * |
@@ -505,7 +531,6 @@ static int mei_me_hbuf_write(struct mei_device *dev, | |||
505 | unsigned long rem; | 531 | unsigned long rem; |
506 | unsigned long length = header->length; | 532 | unsigned long length = header->length; |
507 | u32 *reg_buf = (u32 *)buf; | 533 | u32 *reg_buf = (u32 *)buf; |
508 | u32 hcsr; | ||
509 | u32 dw_cnt; | 534 | u32 dw_cnt; |
510 | int i; | 535 | int i; |
511 | int empty_slots; | 536 | int empty_slots; |
@@ -532,8 +557,7 @@ static int mei_me_hbuf_write(struct mei_device *dev, | |||
532 | mei_me_hcbww_write(dev, reg); | 557 | mei_me_hcbww_write(dev, reg); |
533 | } | 558 | } |
534 | 559 | ||
535 | hcsr = mei_hcsr_read(dev) | H_IG; | 560 | mei_hcsr_set_hig(dev); |
536 | mei_hcsr_set(dev, hcsr); | ||
537 | if (!mei_me_hw_is_ready(dev)) | 561 | if (!mei_me_hw_is_ready(dev)) |
538 | return -EIO; | 562 | return -EIO; |
539 | 563 | ||
@@ -580,7 +604,6 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, | |||
580 | unsigned long buffer_length) | 604 | unsigned long buffer_length) |
581 | { | 605 | { |
582 | u32 *reg_buf = (u32 *)buffer; | 606 | u32 *reg_buf = (u32 *)buffer; |
583 | u32 hcsr; | ||
584 | 607 | ||
585 | for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32)) | 608 | for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32)) |
586 | *reg_buf++ = mei_me_mecbrw_read(dev); | 609 | *reg_buf++ = mei_me_mecbrw_read(dev); |
@@ -591,8 +614,7 @@ static int mei_me_read_slots(struct mei_device *dev, unsigned char *buffer, | |||
591 | memcpy(reg_buf, ®, buffer_length); | 614 | memcpy(reg_buf, ®, buffer_length); |
592 | } | 615 | } |
593 | 616 | ||
594 | hcsr = mei_hcsr_read(dev) | H_IG; | 617 | mei_hcsr_set_hig(dev); |
595 | mei_hcsr_set(dev, hcsr); | ||
596 | return 0; | 618 | return 0; |
597 | } | 619 | } |
598 | 620 | ||
@@ -1189,7 +1211,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id) | |||
1189 | irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | 1211 | irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) |
1190 | { | 1212 | { |
1191 | struct mei_device *dev = (struct mei_device *) dev_id; | 1213 | struct mei_device *dev = (struct mei_device *) dev_id; |
1192 | struct mei_cl_cb complete_list; | 1214 | struct list_head cmpl_list; |
1193 | s32 slots; | 1215 | s32 slots; |
1194 | u32 hcsr; | 1216 | u32 hcsr; |
1195 | int rets = 0; | 1217 | int rets = 0; |
@@ -1201,7 +1223,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
1201 | hcsr = mei_hcsr_read(dev); | 1223 | hcsr = mei_hcsr_read(dev); |
1202 | me_intr_clear(dev, hcsr); | 1224 | me_intr_clear(dev, hcsr); |
1203 | 1225 | ||
1204 | mei_io_list_init(&complete_list); | 1226 | INIT_LIST_HEAD(&cmpl_list); |
1205 | 1227 | ||
1206 | /* check if ME wants a reset */ | 1228 | /* check if ME wants a reset */ |
1207 | if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { | 1229 | if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { |
@@ -1210,6 +1232,9 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
1210 | goto end; | 1232 | goto end; |
1211 | } | 1233 | } |
1212 | 1234 | ||
1235 | if (mei_me_hw_is_resetting(dev)) | ||
1236 | mei_hcsr_set_hig(dev); | ||
1237 | |||
1213 | mei_me_pg_intr(dev, me_intr_src(hcsr)); | 1238 | mei_me_pg_intr(dev, me_intr_src(hcsr)); |
1214 | 1239 | ||
1215 | /* check if we need to start the dev */ | 1240 | /* check if we need to start the dev */ |
@@ -1227,7 +1252,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
1227 | slots = mei_count_full_read_slots(dev); | 1252 | slots = mei_count_full_read_slots(dev); |
1228 | while (slots > 0) { | 1253 | while (slots > 0) { |
1229 | dev_dbg(dev->dev, "slots to read = %08x\n", slots); | 1254 | dev_dbg(dev->dev, "slots to read = %08x\n", slots); |
1230 | rets = mei_irq_read_handler(dev, &complete_list, &slots); | 1255 | rets = mei_irq_read_handler(dev, &cmpl_list, &slots); |
1231 | /* There is a race between ME write and interrupt delivery: | 1256 | /* There is a race between ME write and interrupt delivery: |
1232 | * Not all data is always available immediately after the | 1257 | * Not all data is always available immediately after the |
1233 | * interrupt, so try to read again on the next interrupt. | 1258 | * interrupt, so try to read again on the next interrupt. |
@@ -1252,11 +1277,11 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) | |||
1252 | */ | 1277 | */ |
1253 | if (dev->pg_event != MEI_PG_EVENT_WAIT && | 1278 | if (dev->pg_event != MEI_PG_EVENT_WAIT && |
1254 | dev->pg_event != MEI_PG_EVENT_RECEIVED) { | 1279 | dev->pg_event != MEI_PG_EVENT_RECEIVED) { |
1255 | rets = mei_irq_write_handler(dev, &complete_list); | 1280 | rets = mei_irq_write_handler(dev, &cmpl_list); |
1256 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); | 1281 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); |
1257 | } | 1282 | } |
1258 | 1283 | ||
1259 | mei_irq_compl_handler(dev, &complete_list); | 1284 | mei_irq_compl_handler(dev, &cmpl_list); |
1260 | 1285 | ||
1261 | end: | 1286 | end: |
1262 | dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets); | 1287 | dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets); |
@@ -1389,7 +1414,7 @@ const struct mei_cfg mei_me_pch8_sps_cfg = { | |||
1389 | * @pdev: The pci device structure | 1414 | * @pdev: The pci device structure |
1390 | * @cfg: per device generation config | 1415 | * @cfg: per device generation config |
1391 | * | 1416 | * |
1392 | * Return: The mei_device_device pointer on success, NULL on failure. | 1417 | * Return: The mei_device pointer on success, NULL on failure. |
1393 | */ | 1418 | */ |
1394 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev, | 1419 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev, |
1395 | const struct mei_cfg *cfg) | 1420 | const struct mei_cfg *cfg) |
@@ -1397,8 +1422,8 @@ struct mei_device *mei_me_dev_init(struct pci_dev *pdev, | |||
1397 | struct mei_device *dev; | 1422 | struct mei_device *dev; |
1398 | struct mei_me_hw *hw; | 1423 | struct mei_me_hw *hw; |
1399 | 1424 | ||
1400 | dev = kzalloc(sizeof(struct mei_device) + | 1425 | dev = devm_kzalloc(&pdev->dev, sizeof(struct mei_device) + |
1401 | sizeof(struct mei_me_hw), GFP_KERNEL); | 1426 | sizeof(struct mei_me_hw), GFP_KERNEL); |
1402 | if (!dev) | 1427 | if (!dev) |
1403 | return NULL; | 1428 | return NULL; |
1404 | hw = to_me_hw(dev); | 1429 | hw = to_me_hw(dev); |
diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c index e9f8c0aeec13..24e4a4c96606 100644 --- a/drivers/misc/mei/hw-txe.c +++ b/drivers/misc/mei/hw-txe.c | |||
@@ -1057,7 +1057,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) | |||
1057 | { | 1057 | { |
1058 | struct mei_device *dev = (struct mei_device *) dev_id; | 1058 | struct mei_device *dev = (struct mei_device *) dev_id; |
1059 | struct mei_txe_hw *hw = to_txe_hw(dev); | 1059 | struct mei_txe_hw *hw = to_txe_hw(dev); |
1060 | struct mei_cl_cb complete_list; | 1060 | struct list_head cmpl_list; |
1061 | s32 slots; | 1061 | s32 slots; |
1062 | int rets = 0; | 1062 | int rets = 0; |
1063 | 1063 | ||
@@ -1069,7 +1069,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) | |||
1069 | 1069 | ||
1070 | /* initialize our complete list */ | 1070 | /* initialize our complete list */ |
1071 | mutex_lock(&dev->device_lock); | 1071 | mutex_lock(&dev->device_lock); |
1072 | mei_io_list_init(&complete_list); | 1072 | INIT_LIST_HEAD(&cmpl_list); |
1073 | 1073 | ||
1074 | if (pci_dev_msi_enabled(to_pci_dev(dev->dev))) | 1074 | if (pci_dev_msi_enabled(to_pci_dev(dev->dev))) |
1075 | mei_txe_check_and_ack_intrs(dev, true); | 1075 | mei_txe_check_and_ack_intrs(dev, true); |
@@ -1126,7 +1126,7 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) | |||
1126 | slots = mei_count_full_read_slots(dev); | 1126 | slots = mei_count_full_read_slots(dev); |
1127 | if (test_and_clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause)) { | 1127 | if (test_and_clear_bit(TXE_INTR_OUT_DB_BIT, &hw->intr_cause)) { |
1128 | /* Read from TXE */ | 1128 | /* Read from TXE */ |
1129 | rets = mei_irq_read_handler(dev, &complete_list, &slots); | 1129 | rets = mei_irq_read_handler(dev, &cmpl_list, &slots); |
1130 | if (rets && dev->dev_state != MEI_DEV_RESETTING) { | 1130 | if (rets && dev->dev_state != MEI_DEV_RESETTING) { |
1131 | dev_err(dev->dev, | 1131 | dev_err(dev->dev, |
1132 | "mei_irq_read_handler ret = %d.\n", rets); | 1132 | "mei_irq_read_handler ret = %d.\n", rets); |
@@ -1144,14 +1144,14 @@ irqreturn_t mei_txe_irq_thread_handler(int irq, void *dev_id) | |||
1144 | if (hw->aliveness && dev->hbuf_is_ready) { | 1144 | if (hw->aliveness && dev->hbuf_is_ready) { |
1145 | /* get the real register value */ | 1145 | /* get the real register value */ |
1146 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); | 1146 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); |
1147 | rets = mei_irq_write_handler(dev, &complete_list); | 1147 | rets = mei_irq_write_handler(dev, &cmpl_list); |
1148 | if (rets && rets != -EMSGSIZE) | 1148 | if (rets && rets != -EMSGSIZE) |
1149 | dev_err(dev->dev, "mei_irq_write_handler ret = %d.\n", | 1149 | dev_err(dev->dev, "mei_irq_write_handler ret = %d.\n", |
1150 | rets); | 1150 | rets); |
1151 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); | 1151 | dev->hbuf_is_ready = mei_hbuf_is_ready(dev); |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | mei_irq_compl_handler(dev, &complete_list); | 1154 | mei_irq_compl_handler(dev, &cmpl_list); |
1155 | 1155 | ||
1156 | end: | 1156 | end: |
1157 | dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets); | 1157 | dev_dbg(dev->dev, "interrupt thread end ret = %d\n", rets); |
@@ -1207,8 +1207,8 @@ struct mei_device *mei_txe_dev_init(struct pci_dev *pdev) | |||
1207 | struct mei_device *dev; | 1207 | struct mei_device *dev; |
1208 | struct mei_txe_hw *hw; | 1208 | struct mei_txe_hw *hw; |
1209 | 1209 | ||
1210 | dev = kzalloc(sizeof(struct mei_device) + | 1210 | dev = devm_kzalloc(&pdev->dev, sizeof(struct mei_device) + |
1211 | sizeof(struct mei_txe_hw), GFP_KERNEL); | 1211 | sizeof(struct mei_txe_hw), GFP_KERNEL); |
1212 | if (!dev) | 1212 | if (!dev) |
1213 | return NULL; | 1213 | return NULL; |
1214 | 1214 | ||
diff --git a/drivers/misc/mei/hw-txe.h b/drivers/misc/mei/hw-txe.h index ce3ed0b88b0c..e1e8b66d7648 100644 --- a/drivers/misc/mei/hw-txe.h +++ b/drivers/misc/mei/hw-txe.h | |||
@@ -45,7 +45,7 @@ | |||
45 | * @intr_cause: translated interrupt cause | 45 | * @intr_cause: translated interrupt cause |
46 | */ | 46 | */ |
47 | struct mei_txe_hw { | 47 | struct mei_txe_hw { |
48 | void __iomem *mem_addr[NUM_OF_MEM_BARS]; | 48 | void __iomem * const *mem_addr; |
49 | u32 aliveness; | 49 | u32 aliveness; |
50 | u32 readiness; | 50 | u32 readiness; |
51 | u32 slots; | 51 | u32 slots; |
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 41e5760a6886..cfb1cdf176fa 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
@@ -349,16 +349,16 @@ EXPORT_SYMBOL_GPL(mei_stop); | |||
349 | bool mei_write_is_idle(struct mei_device *dev) | 349 | bool mei_write_is_idle(struct mei_device *dev) |
350 | { | 350 | { |
351 | bool idle = (dev->dev_state == MEI_DEV_ENABLED && | 351 | bool idle = (dev->dev_state == MEI_DEV_ENABLED && |
352 | list_empty(&dev->ctrl_wr_list.list) && | 352 | list_empty(&dev->ctrl_wr_list) && |
353 | list_empty(&dev->write_list.list) && | 353 | list_empty(&dev->write_list) && |
354 | list_empty(&dev->write_waiting_list.list)); | 354 | list_empty(&dev->write_waiting_list)); |
355 | 355 | ||
356 | dev_dbg(dev->dev, "write pg: is idle[%d] state=%s ctrl=%01d write=%01d wwait=%01d\n", | 356 | dev_dbg(dev->dev, "write pg: is idle[%d] state=%s ctrl=%01d write=%01d wwait=%01d\n", |
357 | idle, | 357 | idle, |
358 | mei_dev_state_str(dev->dev_state), | 358 | mei_dev_state_str(dev->dev_state), |
359 | list_empty(&dev->ctrl_wr_list.list), | 359 | list_empty(&dev->ctrl_wr_list), |
360 | list_empty(&dev->write_list.list), | 360 | list_empty(&dev->write_list), |
361 | list_empty(&dev->write_waiting_list.list)); | 361 | list_empty(&dev->write_waiting_list)); |
362 | 362 | ||
363 | return idle; | 363 | return idle; |
364 | } | 364 | } |
@@ -388,17 +388,17 @@ void mei_device_init(struct mei_device *dev, | |||
388 | dev->dev_state = MEI_DEV_INITIALIZING; | 388 | dev->dev_state = MEI_DEV_INITIALIZING; |
389 | dev->reset_count = 0; | 389 | dev->reset_count = 0; |
390 | 390 | ||
391 | mei_io_list_init(&dev->write_list); | 391 | INIT_LIST_HEAD(&dev->write_list); |
392 | mei_io_list_init(&dev->write_waiting_list); | 392 | INIT_LIST_HEAD(&dev->write_waiting_list); |
393 | mei_io_list_init(&dev->ctrl_wr_list); | 393 | INIT_LIST_HEAD(&dev->ctrl_wr_list); |
394 | mei_io_list_init(&dev->ctrl_rd_list); | 394 | INIT_LIST_HEAD(&dev->ctrl_rd_list); |
395 | 395 | ||
396 | INIT_DELAYED_WORK(&dev->timer_work, mei_timer); | 396 | INIT_DELAYED_WORK(&dev->timer_work, mei_timer); |
397 | INIT_WORK(&dev->reset_work, mei_reset_work); | 397 | INIT_WORK(&dev->reset_work, mei_reset_work); |
398 | INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work); | 398 | INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work); |
399 | 399 | ||
400 | INIT_LIST_HEAD(&dev->iamthif_cl.link); | 400 | INIT_LIST_HEAD(&dev->iamthif_cl.link); |
401 | mei_io_list_init(&dev->amthif_cmd_list); | 401 | INIT_LIST_HEAD(&dev->amthif_cmd_list); |
402 | 402 | ||
403 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | 403 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); |
404 | dev->open_handle_count = 0; | 404 | dev->open_handle_count = 0; |
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index b584749bcc4a..406e9e2b2fff 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c | |||
@@ -35,14 +35,14 @@ | |||
35 | * for the completed callbacks | 35 | * for the completed callbacks |
36 | * | 36 | * |
37 | * @dev: mei device | 37 | * @dev: mei device |
38 | * @compl_list: list of completed cbs | 38 | * @cmpl_list: list of completed cbs |
39 | */ | 39 | */ |
40 | void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list) | 40 | void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list) |
41 | { | 41 | { |
42 | struct mei_cl_cb *cb, *next; | 42 | struct mei_cl_cb *cb, *next; |
43 | struct mei_cl *cl; | 43 | struct mei_cl *cl; |
44 | 44 | ||
45 | list_for_each_entry_safe(cb, next, &compl_list->list, list) { | 45 | list_for_each_entry_safe(cb, next, cmpl_list, list) { |
46 | cl = cb->cl; | 46 | cl = cb->cl; |
47 | list_del_init(&cb->list); | 47 | list_del_init(&cb->list); |
48 | 48 | ||
@@ -92,13 +92,13 @@ void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
92 | * | 92 | * |
93 | * @cl: reading client | 93 | * @cl: reading client |
94 | * @mei_hdr: header of mei client message | 94 | * @mei_hdr: header of mei client message |
95 | * @complete_list: completion list | 95 | * @cmpl_list: completion list |
96 | * | 96 | * |
97 | * Return: always 0 | 97 | * Return: always 0 |
98 | */ | 98 | */ |
99 | int mei_cl_irq_read_msg(struct mei_cl *cl, | 99 | int mei_cl_irq_read_msg(struct mei_cl *cl, |
100 | struct mei_msg_hdr *mei_hdr, | 100 | struct mei_msg_hdr *mei_hdr, |
101 | struct mei_cl_cb *complete_list) | 101 | struct list_head *cmpl_list) |
102 | { | 102 | { |
103 | struct mei_device *dev = cl->dev; | 103 | struct mei_device *dev = cl->dev; |
104 | struct mei_cl_cb *cb; | 104 | struct mei_cl_cb *cb; |
@@ -144,7 +144,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, | |||
144 | 144 | ||
145 | if (mei_hdr->msg_complete) { | 145 | if (mei_hdr->msg_complete) { |
146 | cl_dbg(dev, cl, "completed read length = %zu\n", cb->buf_idx); | 146 | cl_dbg(dev, cl, "completed read length = %zu\n", cb->buf_idx); |
147 | list_move_tail(&cb->list, &complete_list->list); | 147 | list_move_tail(&cb->list, cmpl_list); |
148 | } else { | 148 | } else { |
149 | pm_runtime_mark_last_busy(dev->dev); | 149 | pm_runtime_mark_last_busy(dev->dev); |
150 | pm_request_autosuspend(dev->dev); | 150 | pm_request_autosuspend(dev->dev); |
@@ -154,7 +154,7 @@ int mei_cl_irq_read_msg(struct mei_cl *cl, | |||
154 | 154 | ||
155 | discard: | 155 | discard: |
156 | if (cb) | 156 | if (cb) |
157 | list_move_tail(&cb->list, &complete_list->list); | 157 | list_move_tail(&cb->list, cmpl_list); |
158 | mei_irq_discard_msg(dev, mei_hdr); | 158 | mei_irq_discard_msg(dev, mei_hdr); |
159 | return 0; | 159 | return 0; |
160 | } | 160 | } |
@@ -169,7 +169,7 @@ discard: | |||
169 | * Return: 0, OK; otherwise, error. | 169 | * Return: 0, OK; otherwise, error. |
170 | */ | 170 | */ |
171 | static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb, | 171 | static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb, |
172 | struct mei_cl_cb *cmpl_list) | 172 | struct list_head *cmpl_list) |
173 | { | 173 | { |
174 | struct mei_device *dev = cl->dev; | 174 | struct mei_device *dev = cl->dev; |
175 | u32 msg_slots; | 175 | u32 msg_slots; |
@@ -183,7 +183,7 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
183 | return -EMSGSIZE; | 183 | return -EMSGSIZE; |
184 | 184 | ||
185 | ret = mei_hbm_cl_disconnect_rsp(dev, cl); | 185 | ret = mei_hbm_cl_disconnect_rsp(dev, cl); |
186 | list_move_tail(&cb->list, &cmpl_list->list); | 186 | list_move_tail(&cb->list, cmpl_list); |
187 | 187 | ||
188 | return ret; | 188 | return ret; |
189 | } | 189 | } |
@@ -199,7 +199,7 @@ static int mei_cl_irq_disconnect_rsp(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
199 | * Return: 0, OK; otherwise, error. | 199 | * Return: 0, OK; otherwise, error. |
200 | */ | 200 | */ |
201 | static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, | 201 | static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, |
202 | struct mei_cl_cb *cmpl_list) | 202 | struct list_head *cmpl_list) |
203 | { | 203 | { |
204 | struct mei_device *dev = cl->dev; | 204 | struct mei_device *dev = cl->dev; |
205 | u32 msg_slots; | 205 | u32 msg_slots; |
@@ -219,7 +219,7 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
219 | if (ret) { | 219 | if (ret) { |
220 | cl->status = ret; | 220 | cl->status = ret; |
221 | cb->buf_idx = 0; | 221 | cb->buf_idx = 0; |
222 | list_move_tail(&cb->list, &cmpl_list->list); | 222 | list_move_tail(&cb->list, cmpl_list); |
223 | return ret; | 223 | return ret; |
224 | } | 224 | } |
225 | 225 | ||
@@ -249,7 +249,7 @@ static inline bool hdr_is_fixed(struct mei_msg_hdr *mei_hdr) | |||
249 | * Return: 0 on success, <0 on failure. | 249 | * Return: 0 on success, <0 on failure. |
250 | */ | 250 | */ |
251 | int mei_irq_read_handler(struct mei_device *dev, | 251 | int mei_irq_read_handler(struct mei_device *dev, |
252 | struct mei_cl_cb *cmpl_list, s32 *slots) | 252 | struct list_head *cmpl_list, s32 *slots) |
253 | { | 253 | { |
254 | struct mei_msg_hdr *mei_hdr; | 254 | struct mei_msg_hdr *mei_hdr; |
255 | struct mei_cl *cl; | 255 | struct mei_cl *cl; |
@@ -347,12 +347,11 @@ EXPORT_SYMBOL_GPL(mei_irq_read_handler); | |||
347 | * | 347 | * |
348 | * Return: 0 on success, <0 on failure. | 348 | * Return: 0 on success, <0 on failure. |
349 | */ | 349 | */ |
350 | int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | 350 | int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list) |
351 | { | 351 | { |
352 | 352 | ||
353 | struct mei_cl *cl; | 353 | struct mei_cl *cl; |
354 | struct mei_cl_cb *cb, *next; | 354 | struct mei_cl_cb *cb, *next; |
355 | struct mei_cl_cb *list; | ||
356 | s32 slots; | 355 | s32 slots; |
357 | int ret; | 356 | int ret; |
358 | 357 | ||
@@ -367,19 +366,18 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
367 | /* complete all waiting for write CB */ | 366 | /* complete all waiting for write CB */ |
368 | dev_dbg(dev->dev, "complete all waiting for write cb.\n"); | 367 | dev_dbg(dev->dev, "complete all waiting for write cb.\n"); |
369 | 368 | ||
370 | list = &dev->write_waiting_list; | 369 | list_for_each_entry_safe(cb, next, &dev->write_waiting_list, list) { |
371 | list_for_each_entry_safe(cb, next, &list->list, list) { | ||
372 | cl = cb->cl; | 370 | cl = cb->cl; |
373 | 371 | ||
374 | cl->status = 0; | 372 | cl->status = 0; |
375 | cl_dbg(dev, cl, "MEI WRITE COMPLETE\n"); | 373 | cl_dbg(dev, cl, "MEI WRITE COMPLETE\n"); |
376 | cl->writing_state = MEI_WRITE_COMPLETE; | 374 | cl->writing_state = MEI_WRITE_COMPLETE; |
377 | list_move_tail(&cb->list, &cmpl_list->list); | 375 | list_move_tail(&cb->list, cmpl_list); |
378 | } | 376 | } |
379 | 377 | ||
380 | /* complete control write list CB */ | 378 | /* complete control write list CB */ |
381 | dev_dbg(dev->dev, "complete control write list cb.\n"); | 379 | dev_dbg(dev->dev, "complete control write list cb.\n"); |
382 | list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list.list, list) { | 380 | list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list, list) { |
383 | cl = cb->cl; | 381 | cl = cb->cl; |
384 | switch (cb->fop_type) { | 382 | switch (cb->fop_type) { |
385 | case MEI_FOP_DISCONNECT: | 383 | case MEI_FOP_DISCONNECT: |
@@ -423,7 +421,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) | |||
423 | } | 421 | } |
424 | /* complete write list CB */ | 422 | /* complete write list CB */ |
425 | dev_dbg(dev->dev, "complete write list cb.\n"); | 423 | dev_dbg(dev->dev, "complete write list cb.\n"); |
426 | list_for_each_entry_safe(cb, next, &dev->write_list.list, list) { | 424 | list_for_each_entry_safe(cb, next, &dev->write_list, list) { |
427 | cl = cb->cl; | 425 | cl = cb->cl; |
428 | if (cl == &dev->iamthif_cl) | 426 | if (cl == &dev->iamthif_cl) |
429 | ret = mei_amthif_irq_write(cl, cb, cmpl_list); | 427 | ret = mei_amthif_irq_write(cl, cb, cmpl_list); |
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e1bf54481fd6..9d0b7050c79a 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -182,32 +182,36 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
182 | goto out; | 182 | goto out; |
183 | } | 183 | } |
184 | 184 | ||
185 | if (rets == -EBUSY && | ||
186 | !mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, file)) { | ||
187 | rets = -ENOMEM; | ||
188 | goto out; | ||
189 | } | ||
190 | 185 | ||
191 | do { | 186 | again: |
192 | mutex_unlock(&dev->device_lock); | 187 | mutex_unlock(&dev->device_lock); |
193 | 188 | if (wait_event_interruptible(cl->rx_wait, | |
194 | if (wait_event_interruptible(cl->rx_wait, | 189 | !list_empty(&cl->rd_completed) || |
195 | (!list_empty(&cl->rd_completed)) || | 190 | !mei_cl_is_connected(cl))) { |
196 | (!mei_cl_is_connected(cl)))) { | 191 | if (signal_pending(current)) |
192 | return -EINTR; | ||
193 | return -ERESTARTSYS; | ||
194 | } | ||
195 | mutex_lock(&dev->device_lock); | ||
197 | 196 | ||
198 | if (signal_pending(current)) | 197 | if (!mei_cl_is_connected(cl)) { |
199 | return -EINTR; | 198 | rets = -ENODEV; |
200 | return -ERESTARTSYS; | 199 | goto out; |
201 | } | 200 | } |
202 | 201 | ||
203 | mutex_lock(&dev->device_lock); | 202 | cb = mei_cl_read_cb(cl, file); |
204 | if (!mei_cl_is_connected(cl)) { | 203 | if (!cb) { |
205 | rets = -ENODEV; | 204 | /* |
206 | goto out; | 205 | * For amthif all the waiters are woken up, |
207 | } | 206 | * but only fp with matching cb->fp get the cb, |
207 | * the others have to return to wait on read. | ||
208 | */ | ||
209 | if (cl == &dev->iamthif_cl) | ||
210 | goto again; | ||
208 | 211 | ||
209 | cb = mei_cl_read_cb(cl, file); | 212 | rets = 0; |
210 | } while (!cb); | 213 | goto out; |
214 | } | ||
211 | 215 | ||
212 | copy_buffer: | 216 | copy_buffer: |
213 | /* now copy the data to user space */ | 217 | /* now copy the data to user space */ |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 8dadb98662a9..d41aac53a2ac 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -328,6 +328,8 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, | |||
328 | bool mei_cl_bus_rx_event(struct mei_cl *cl); | 328 | bool mei_cl_bus_rx_event(struct mei_cl *cl); |
329 | bool mei_cl_bus_notify_event(struct mei_cl *cl); | 329 | bool mei_cl_bus_notify_event(struct mei_cl *cl); |
330 | void mei_cl_bus_remove_devices(struct mei_device *bus); | 330 | void mei_cl_bus_remove_devices(struct mei_device *bus); |
331 | bool mei_cl_bus_module_get(struct mei_cl *cl); | ||
332 | void mei_cl_bus_module_put(struct mei_cl *cl); | ||
331 | int mei_cl_bus_init(void); | 333 | int mei_cl_bus_init(void); |
332 | void mei_cl_bus_exit(void); | 334 | void mei_cl_bus_exit(void); |
333 | 335 | ||
@@ -439,10 +441,10 @@ struct mei_device { | |||
439 | struct cdev cdev; | 441 | struct cdev cdev; |
440 | int minor; | 442 | int minor; |
441 | 443 | ||
442 | struct mei_cl_cb write_list; | 444 | struct list_head write_list; |
443 | struct mei_cl_cb write_waiting_list; | 445 | struct list_head write_waiting_list; |
444 | struct mei_cl_cb ctrl_wr_list; | 446 | struct list_head ctrl_wr_list; |
445 | struct mei_cl_cb ctrl_rd_list; | 447 | struct list_head ctrl_rd_list; |
446 | 448 | ||
447 | struct list_head file_list; | 449 | struct list_head file_list; |
448 | long open_handle_count; | 450 | long open_handle_count; |
@@ -499,7 +501,7 @@ struct mei_device { | |||
499 | bool override_fixed_address; | 501 | bool override_fixed_address; |
500 | 502 | ||
501 | /* amthif list for cmd waiting */ | 503 | /* amthif list for cmd waiting */ |
502 | struct mei_cl_cb amthif_cmd_list; | 504 | struct list_head amthif_cmd_list; |
503 | struct mei_cl iamthif_cl; | 505 | struct mei_cl iamthif_cl; |
504 | long iamthif_open_count; | 506 | long iamthif_open_count; |
505 | u32 iamthif_stall_timer; | 507 | u32 iamthif_stall_timer; |
@@ -571,10 +573,10 @@ void mei_cancel_work(struct mei_device *dev); | |||
571 | void mei_timer(struct work_struct *work); | 573 | void mei_timer(struct work_struct *work); |
572 | void mei_schedule_stall_timer(struct mei_device *dev); | 574 | void mei_schedule_stall_timer(struct mei_device *dev); |
573 | int mei_irq_read_handler(struct mei_device *dev, | 575 | int mei_irq_read_handler(struct mei_device *dev, |
574 | struct mei_cl_cb *cmpl_list, s32 *slots); | 576 | struct list_head *cmpl_list, s32 *slots); |
575 | 577 | ||
576 | int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list); | 578 | int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list); |
577 | void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list); | 579 | void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list); |
578 | 580 | ||
579 | /* | 581 | /* |
580 | * AMTHIF - AMT Host Interface Functions | 582 | * AMTHIF - AMT Host Interface Functions |
@@ -590,12 +592,12 @@ int mei_amthif_release(struct mei_device *dev, struct file *file); | |||
590 | int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb); | 592 | int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb); |
591 | int mei_amthif_run_next_cmd(struct mei_device *dev); | 593 | int mei_amthif_run_next_cmd(struct mei_device *dev); |
592 | int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, | 594 | int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, |
593 | struct mei_cl_cb *cmpl_list); | 595 | struct list_head *cmpl_list); |
594 | 596 | ||
595 | void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb); | 597 | void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb); |
596 | int mei_amthif_irq_read_msg(struct mei_cl *cl, | 598 | int mei_amthif_irq_read_msg(struct mei_cl *cl, |
597 | struct mei_msg_hdr *mei_hdr, | 599 | struct mei_msg_hdr *mei_hdr, |
598 | struct mei_cl_cb *complete_list); | 600 | struct list_head *cmpl_list); |
599 | int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); | 601 | int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); |
600 | 602 | ||
601 | /* | 603 | /* |
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index f9c6ec4b98ab..0a668fdfbbe9 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c | |||
@@ -149,18 +149,18 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
149 | return -ENODEV; | 149 | return -ENODEV; |
150 | 150 | ||
151 | /* enable pci dev */ | 151 | /* enable pci dev */ |
152 | err = pci_enable_device(pdev); | 152 | err = pcim_enable_device(pdev); |
153 | if (err) { | 153 | if (err) { |
154 | dev_err(&pdev->dev, "failed to enable pci device.\n"); | 154 | dev_err(&pdev->dev, "failed to enable pci device.\n"); |
155 | goto end; | 155 | goto end; |
156 | } | 156 | } |
157 | /* set PCI host mastering */ | 157 | /* set PCI host mastering */ |
158 | pci_set_master(pdev); | 158 | pci_set_master(pdev); |
159 | /* pci request regions for mei driver */ | 159 | /* pci request regions and mapping IO device memory for mei driver */ |
160 | err = pci_request_regions(pdev, KBUILD_MODNAME); | 160 | err = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME); |
161 | if (err) { | 161 | if (err) { |
162 | dev_err(&pdev->dev, "failed to get pci regions.\n"); | 162 | dev_err(&pdev->dev, "failed to get pci regions.\n"); |
163 | goto disable_device; | 163 | goto end; |
164 | } | 164 | } |
165 | 165 | ||
166 | if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) || | 166 | if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) || |
@@ -173,24 +173,18 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
173 | } | 173 | } |
174 | if (err) { | 174 | if (err) { |
175 | dev_err(&pdev->dev, "No usable DMA configuration, aborting\n"); | 175 | dev_err(&pdev->dev, "No usable DMA configuration, aborting\n"); |
176 | goto release_regions; | 176 | goto end; |
177 | } | 177 | } |
178 | 178 | ||
179 | |||
180 | /* allocates and initializes the mei dev structure */ | 179 | /* allocates and initializes the mei dev structure */ |
181 | dev = mei_me_dev_init(pdev, cfg); | 180 | dev = mei_me_dev_init(pdev, cfg); |
182 | if (!dev) { | 181 | if (!dev) { |
183 | err = -ENOMEM; | 182 | err = -ENOMEM; |
184 | goto release_regions; | 183 | goto end; |
185 | } | 184 | } |
186 | hw = to_me_hw(dev); | 185 | hw = to_me_hw(dev); |
187 | /* mapping IO device memory */ | 186 | hw->mem_addr = pcim_iomap_table(pdev)[0]; |
188 | hw->mem_addr = pci_iomap(pdev, 0, 0); | 187 | |
189 | if (!hw->mem_addr) { | ||
190 | dev_err(&pdev->dev, "mapping I/O device memory failure.\n"); | ||
191 | err = -ENOMEM; | ||
192 | goto free_device; | ||
193 | } | ||
194 | pci_enable_msi(pdev); | 188 | pci_enable_msi(pdev); |
195 | 189 | ||
196 | /* request and enable interrupt */ | 190 | /* request and enable interrupt */ |
@@ -203,7 +197,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
203 | if (err) { | 197 | if (err) { |
204 | dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n", | 198 | dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n", |
205 | pdev->irq); | 199 | pdev->irq); |
206 | goto disable_msi; | 200 | goto end; |
207 | } | 201 | } |
208 | 202 | ||
209 | if (mei_start(dev)) { | 203 | if (mei_start(dev)) { |
@@ -242,15 +236,6 @@ release_irq: | |||
242 | mei_cancel_work(dev); | 236 | mei_cancel_work(dev); |
243 | mei_disable_interrupts(dev); | 237 | mei_disable_interrupts(dev); |
244 | free_irq(pdev->irq, dev); | 238 | free_irq(pdev->irq, dev); |
245 | disable_msi: | ||
246 | pci_disable_msi(pdev); | ||
247 | pci_iounmap(pdev, hw->mem_addr); | ||
248 | free_device: | ||
249 | kfree(dev); | ||
250 | release_regions: | ||
251 | pci_release_regions(pdev); | ||
252 | disable_device: | ||
253 | pci_disable_device(pdev); | ||
254 | end: | 239 | end: |
255 | dev_err(&pdev->dev, "initialization failed.\n"); | 240 | dev_err(&pdev->dev, "initialization failed.\n"); |
256 | return err; | 241 | return err; |
@@ -267,7 +252,6 @@ end: | |||
267 | static void mei_me_remove(struct pci_dev *pdev) | 252 | static void mei_me_remove(struct pci_dev *pdev) |
268 | { | 253 | { |
269 | struct mei_device *dev; | 254 | struct mei_device *dev; |
270 | struct mei_me_hw *hw; | ||
271 | 255 | ||
272 | dev = pci_get_drvdata(pdev); | 256 | dev = pci_get_drvdata(pdev); |
273 | if (!dev) | 257 | if (!dev) |
@@ -276,33 +260,19 @@ static void mei_me_remove(struct pci_dev *pdev) | |||
276 | if (mei_pg_is_enabled(dev)) | 260 | if (mei_pg_is_enabled(dev)) |
277 | pm_runtime_get_noresume(&pdev->dev); | 261 | pm_runtime_get_noresume(&pdev->dev); |
278 | 262 | ||
279 | hw = to_me_hw(dev); | ||
280 | |||
281 | |||
282 | dev_dbg(&pdev->dev, "stop\n"); | 263 | dev_dbg(&pdev->dev, "stop\n"); |
283 | mei_stop(dev); | 264 | mei_stop(dev); |
284 | 265 | ||
285 | if (!pci_dev_run_wake(pdev)) | 266 | if (!pci_dev_run_wake(pdev)) |
286 | mei_me_unset_pm_domain(dev); | 267 | mei_me_unset_pm_domain(dev); |
287 | 268 | ||
288 | /* disable interrupts */ | ||
289 | mei_disable_interrupts(dev); | 269 | mei_disable_interrupts(dev); |
290 | 270 | ||
291 | free_irq(pdev->irq, dev); | 271 | free_irq(pdev->irq, dev); |
292 | pci_disable_msi(pdev); | ||
293 | |||
294 | if (hw->mem_addr) | ||
295 | pci_iounmap(pdev, hw->mem_addr); | ||
296 | 272 | ||
297 | mei_deregister(dev); | 273 | mei_deregister(dev); |
298 | |||
299 | kfree(dev); | ||
300 | |||
301 | pci_release_regions(pdev); | ||
302 | pci_disable_device(pdev); | ||
303 | |||
304 | |||
305 | } | 274 | } |
275 | |||
306 | #ifdef CONFIG_PM_SLEEP | 276 | #ifdef CONFIG_PM_SLEEP |
307 | static int mei_me_pci_suspend(struct device *device) | 277 | static int mei_me_pci_suspend(struct device *device) |
308 | { | 278 | { |
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c index 58ffd30dcc91..fe088b40daf9 100644 --- a/drivers/misc/mei/pci-txe.c +++ b/drivers/misc/mei/pci-txe.c | |||
@@ -52,17 +52,6 @@ static inline void mei_txe_set_pm_domain(struct mei_device *dev) {} | |||
52 | static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {} | 52 | static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {} |
53 | #endif /* CONFIG_PM */ | 53 | #endif /* CONFIG_PM */ |
54 | 54 | ||
55 | static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw) | ||
56 | { | ||
57 | int i; | ||
58 | |||
59 | for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) { | ||
60 | if (hw->mem_addr[i]) { | ||
61 | pci_iounmap(pdev, hw->mem_addr[i]); | ||
62 | hw->mem_addr[i] = NULL; | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | /** | 55 | /** |
67 | * mei_txe_probe - Device Initialization Routine | 56 | * mei_txe_probe - Device Initialization Routine |
68 | * | 57 | * |
@@ -75,22 +64,22 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
75 | { | 64 | { |
76 | struct mei_device *dev; | 65 | struct mei_device *dev; |
77 | struct mei_txe_hw *hw; | 66 | struct mei_txe_hw *hw; |
67 | const int mask = BIT(SEC_BAR) | BIT(BRIDGE_BAR); | ||
78 | int err; | 68 | int err; |
79 | int i; | ||
80 | 69 | ||
81 | /* enable pci dev */ | 70 | /* enable pci dev */ |
82 | err = pci_enable_device(pdev); | 71 | err = pcim_enable_device(pdev); |
83 | if (err) { | 72 | if (err) { |
84 | dev_err(&pdev->dev, "failed to enable pci device.\n"); | 73 | dev_err(&pdev->dev, "failed to enable pci device.\n"); |
85 | goto end; | 74 | goto end; |
86 | } | 75 | } |
87 | /* set PCI host mastering */ | 76 | /* set PCI host mastering */ |
88 | pci_set_master(pdev); | 77 | pci_set_master(pdev); |
89 | /* pci request regions for mei driver */ | 78 | /* pci request regions and mapping IO device memory for mei driver */ |
90 | err = pci_request_regions(pdev, KBUILD_MODNAME); | 79 | err = pcim_iomap_regions(pdev, mask, KBUILD_MODNAME); |
91 | if (err) { | 80 | if (err) { |
92 | dev_err(&pdev->dev, "failed to get pci regions.\n"); | 81 | dev_err(&pdev->dev, "failed to get pci regions.\n"); |
93 | goto disable_device; | 82 | goto end; |
94 | } | 83 | } |
95 | 84 | ||
96 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); | 85 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); |
@@ -98,7 +87,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
98 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | 87 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); |
99 | if (err) { | 88 | if (err) { |
100 | dev_err(&pdev->dev, "No suitable DMA available.\n"); | 89 | dev_err(&pdev->dev, "No suitable DMA available.\n"); |
101 | goto release_regions; | 90 | goto end; |
102 | } | 91 | } |
103 | } | 92 | } |
104 | 93 | ||
@@ -106,20 +95,10 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
106 | dev = mei_txe_dev_init(pdev); | 95 | dev = mei_txe_dev_init(pdev); |
107 | if (!dev) { | 96 | if (!dev) { |
108 | err = -ENOMEM; | 97 | err = -ENOMEM; |
109 | goto release_regions; | 98 | goto end; |
110 | } | 99 | } |
111 | hw = to_txe_hw(dev); | 100 | hw = to_txe_hw(dev); |
112 | 101 | hw->mem_addr = pcim_iomap_table(pdev); | |
113 | /* mapping IO device memory */ | ||
114 | for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) { | ||
115 | hw->mem_addr[i] = pci_iomap(pdev, i, 0); | ||
116 | if (!hw->mem_addr[i]) { | ||
117 | dev_err(&pdev->dev, "mapping I/O device memory failure.\n"); | ||
118 | err = -ENOMEM; | ||
119 | goto free_device; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | 102 | ||
124 | pci_enable_msi(pdev); | 103 | pci_enable_msi(pdev); |
125 | 104 | ||
@@ -140,7 +119,7 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
140 | if (err) { | 119 | if (err) { |
141 | dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n", | 120 | dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n", |
142 | pdev->irq); | 121 | pdev->irq); |
143 | goto free_device; | 122 | goto end; |
144 | } | 123 | } |
145 | 124 | ||
146 | if (mei_start(dev)) { | 125 | if (mei_start(dev)) { |
@@ -173,23 +152,9 @@ static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
173 | stop: | 152 | stop: |
174 | mei_stop(dev); | 153 | mei_stop(dev); |
175 | release_irq: | 154 | release_irq: |
176 | |||
177 | mei_cancel_work(dev); | 155 | mei_cancel_work(dev); |
178 | |||
179 | /* disable interrupts */ | ||
180 | mei_disable_interrupts(dev); | 156 | mei_disable_interrupts(dev); |
181 | |||
182 | free_irq(pdev->irq, dev); | 157 | free_irq(pdev->irq, dev); |
183 | pci_disable_msi(pdev); | ||
184 | |||
185 | free_device: | ||
186 | mei_txe_pci_iounmap(pdev, hw); | ||
187 | |||
188 | kfree(dev); | ||
189 | release_regions: | ||
190 | pci_release_regions(pdev); | ||
191 | disable_device: | ||
192 | pci_disable_device(pdev); | ||
193 | end: | 158 | end: |
194 | dev_err(&pdev->dev, "initialization failed.\n"); | 159 | dev_err(&pdev->dev, "initialization failed.\n"); |
195 | return err; | 160 | return err; |
@@ -206,38 +171,24 @@ end: | |||
206 | static void mei_txe_remove(struct pci_dev *pdev) | 171 | static void mei_txe_remove(struct pci_dev *pdev) |
207 | { | 172 | { |
208 | struct mei_device *dev; | 173 | struct mei_device *dev; |
209 | struct mei_txe_hw *hw; | ||
210 | 174 | ||
211 | dev = pci_get_drvdata(pdev); | 175 | dev = pci_get_drvdata(pdev); |
212 | if (!dev) { | 176 | if (!dev) { |
213 | dev_err(&pdev->dev, "mei: dev =NULL\n"); | 177 | dev_err(&pdev->dev, "mei: dev == NULL\n"); |
214 | return; | 178 | return; |
215 | } | 179 | } |
216 | 180 | ||
217 | pm_runtime_get_noresume(&pdev->dev); | 181 | pm_runtime_get_noresume(&pdev->dev); |
218 | 182 | ||
219 | hw = to_txe_hw(dev); | ||
220 | |||
221 | mei_stop(dev); | 183 | mei_stop(dev); |
222 | 184 | ||
223 | if (!pci_dev_run_wake(pdev)) | 185 | if (!pci_dev_run_wake(pdev)) |
224 | mei_txe_unset_pm_domain(dev); | 186 | mei_txe_unset_pm_domain(dev); |
225 | 187 | ||
226 | /* disable interrupts */ | ||
227 | mei_disable_interrupts(dev); | 188 | mei_disable_interrupts(dev); |
228 | free_irq(pdev->irq, dev); | 189 | free_irq(pdev->irq, dev); |
229 | pci_disable_msi(pdev); | ||
230 | |||
231 | pci_set_drvdata(pdev, NULL); | ||
232 | |||
233 | mei_txe_pci_iounmap(pdev, hw); | ||
234 | 190 | ||
235 | mei_deregister(dev); | 191 | mei_deregister(dev); |
236 | |||
237 | kfree(dev); | ||
238 | |||
239 | pci_release_regions(pdev); | ||
240 | pci_disable_device(pdev); | ||
241 | } | 192 | } |
242 | 193 | ||
243 | 194 | ||
diff --git a/drivers/misc/mic/vop/vop_vringh.c b/drivers/misc/mic/vop/vop_vringh.c index 88e45234d527..fed992e2c258 100644 --- a/drivers/misc/mic/vop/vop_vringh.c +++ b/drivers/misc/mic/vop/vop_vringh.c | |||
@@ -292,7 +292,6 @@ static int vop_virtio_add_device(struct vop_vdev *vdev, | |||
292 | if (ret) { | 292 | if (ret) { |
293 | dev_err(vop_dev(vdev), "%s %d err %d\n", | 293 | dev_err(vop_dev(vdev), "%s %d err %d\n", |
294 | __func__, __LINE__, ret); | 294 | __func__, __LINE__, ret); |
295 | kfree(vdev); | ||
296 | return ret; | 295 | return ret; |
297 | } | 296 | } |
298 | 297 | ||
diff --git a/drivers/misc/panel.c b/drivers/misc/panel.c index 6030ac5b8c63..ef2ece0f26af 100644 --- a/drivers/misc/panel.c +++ b/drivers/misc/panel.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <linux/list.h> | 56 | #include <linux/list.h> |
57 | #include <linux/notifier.h> | 57 | #include <linux/notifier.h> |
58 | #include <linux/reboot.h> | 58 | #include <linux/reboot.h> |
59 | #include <linux/workqueue.h> | ||
59 | #include <generated/utsrelease.h> | 60 | #include <generated/utsrelease.h> |
60 | 61 | ||
61 | #include <linux/io.h> | 62 | #include <linux/io.h> |
@@ -64,8 +65,6 @@ | |||
64 | #define LCD_MINOR 156 | 65 | #define LCD_MINOR 156 |
65 | #define KEYPAD_MINOR 185 | 66 | #define KEYPAD_MINOR 185 |
66 | 67 | ||
67 | #define PANEL_VERSION "0.9.5" | ||
68 | |||
69 | #define LCD_MAXBYTES 256 /* max burst write */ | 68 | #define LCD_MAXBYTES 256 /* max burst write */ |
70 | 69 | ||
71 | #define KEYPAD_BUFFER 64 | 70 | #define KEYPAD_BUFFER 64 |
@@ -77,8 +76,8 @@ | |||
77 | /* a key repeats this times INPUT_POLL_TIME */ | 76 | /* a key repeats this times INPUT_POLL_TIME */ |
78 | #define KEYPAD_REP_DELAY (2) | 77 | #define KEYPAD_REP_DELAY (2) |
79 | 78 | ||
80 | /* keep the light on this times INPUT_POLL_TIME for each flash */ | 79 | /* keep the light on this many seconds for each flash */ |
81 | #define FLASH_LIGHT_TEMPO (200) | 80 | #define FLASH_LIGHT_TEMPO (4) |
82 | 81 | ||
83 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ | 82 | /* converts an r_str() input to an active high, bits string : 000BAOSE */ |
84 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) | 83 | #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3) |
@@ -121,8 +120,6 @@ | |||
121 | #define PIN_SELECP 17 | 120 | #define PIN_SELECP 17 |
122 | #define PIN_NOT_SET 127 | 121 | #define PIN_NOT_SET 127 |
123 | 122 | ||
124 | #define LCD_FLAG_S 0x0001 | ||
125 | #define LCD_FLAG_ID 0x0002 | ||
126 | #define LCD_FLAG_B 0x0004 /* blink on */ | 123 | #define LCD_FLAG_B 0x0004 /* blink on */ |
127 | #define LCD_FLAG_C 0x0008 /* cursor on */ | 124 | #define LCD_FLAG_C 0x0008 /* cursor on */ |
128 | #define LCD_FLAG_D 0x0010 /* display on */ | 125 | #define LCD_FLAG_D 0x0010 /* display on */ |
@@ -256,7 +253,10 @@ static struct { | |||
256 | int hwidth; | 253 | int hwidth; |
257 | int charset; | 254 | int charset; |
258 | int proto; | 255 | int proto; |
259 | int light_tempo; | 256 | |
257 | struct delayed_work bl_work; | ||
258 | struct mutex bl_tempo_lock; /* Protects access to bl_tempo */ | ||
259 | bool bl_tempo; | ||
260 | 260 | ||
261 | /* TODO: use union here? */ | 261 | /* TODO: use union here? */ |
262 | struct { | 262 | struct { |
@@ -661,8 +661,6 @@ static void lcd_get_bits(unsigned int port, int *val) | |||
661 | } | 661 | } |
662 | } | 662 | } |
663 | 663 | ||
664 | static void init_scan_timer(void); | ||
665 | |||
666 | /* sets data port bits according to current signals values */ | 664 | /* sets data port bits according to current signals values */ |
667 | static int set_data_bits(void) | 665 | static int set_data_bits(void) |
668 | { | 666 | { |
@@ -794,11 +792,8 @@ static void lcd_send_serial(int byte) | |||
794 | } | 792 | } |
795 | 793 | ||
796 | /* turn the backlight on or off */ | 794 | /* turn the backlight on or off */ |
797 | static void lcd_backlight(int on) | 795 | static void __lcd_backlight(int on) |
798 | { | 796 | { |
799 | if (lcd.pins.bl == PIN_NONE) | ||
800 | return; | ||
801 | |||
802 | /* The backlight is activated by setting the AUTOFEED line to +5V */ | 797 | /* The backlight is activated by setting the AUTOFEED line to +5V */ |
803 | spin_lock_irq(&pprt_lock); | 798 | spin_lock_irq(&pprt_lock); |
804 | if (on) | 799 | if (on) |
@@ -809,6 +804,44 @@ static void lcd_backlight(int on) | |||
809 | spin_unlock_irq(&pprt_lock); | 804 | spin_unlock_irq(&pprt_lock); |
810 | } | 805 | } |
811 | 806 | ||
807 | static void lcd_backlight(int on) | ||
808 | { | ||
809 | if (lcd.pins.bl == PIN_NONE) | ||
810 | return; | ||
811 | |||
812 | mutex_lock(&lcd.bl_tempo_lock); | ||
813 | if (!lcd.bl_tempo) | ||
814 | __lcd_backlight(on); | ||
815 | mutex_unlock(&lcd.bl_tempo_lock); | ||
816 | } | ||
817 | |||
818 | static void lcd_bl_off(struct work_struct *work) | ||
819 | { | ||
820 | mutex_lock(&lcd.bl_tempo_lock); | ||
821 | if (lcd.bl_tempo) { | ||
822 | lcd.bl_tempo = false; | ||
823 | if (!(lcd.flags & LCD_FLAG_L)) | ||
824 | __lcd_backlight(0); | ||
825 | } | ||
826 | mutex_unlock(&lcd.bl_tempo_lock); | ||
827 | } | ||
828 | |||
829 | /* turn the backlight on for a little while */ | ||
830 | static void lcd_poke(void) | ||
831 | { | ||
832 | if (lcd.pins.bl == PIN_NONE) | ||
833 | return; | ||
834 | |||
835 | cancel_delayed_work_sync(&lcd.bl_work); | ||
836 | |||
837 | mutex_lock(&lcd.bl_tempo_lock); | ||
838 | if (!lcd.bl_tempo && !(lcd.flags & LCD_FLAG_L)) | ||
839 | __lcd_backlight(1); | ||
840 | lcd.bl_tempo = true; | ||
841 | schedule_delayed_work(&lcd.bl_work, FLASH_LIGHT_TEMPO * HZ); | ||
842 | mutex_unlock(&lcd.bl_tempo_lock); | ||
843 | } | ||
844 | |||
812 | /* send a command to the LCD panel in serial mode */ | 845 | /* send a command to the LCD panel in serial mode */ |
813 | static void lcd_write_cmd_s(int cmd) | 846 | static void lcd_write_cmd_s(int cmd) |
814 | { | 847 | { |
@@ -907,6 +940,13 @@ static void lcd_gotoxy(void) | |||
907 | (lcd.hwidth - 1) : lcd.bwidth - 1)); | 940 | (lcd.hwidth - 1) : lcd.bwidth - 1)); |
908 | } | 941 | } |
909 | 942 | ||
943 | static void lcd_home(void) | ||
944 | { | ||
945 | lcd.addr.x = 0; | ||
946 | lcd.addr.y = 0; | ||
947 | lcd_gotoxy(); | ||
948 | } | ||
949 | |||
910 | static void lcd_print(char c) | 950 | static void lcd_print(char c) |
911 | { | 951 | { |
912 | if (lcd.addr.x < lcd.bwidth) { | 952 | if (lcd.addr.x < lcd.bwidth) { |
@@ -925,9 +965,7 @@ static void lcd_clear_fast_s(void) | |||
925 | { | 965 | { |
926 | int pos; | 966 | int pos; |
927 | 967 | ||
928 | lcd.addr.x = 0; | 968 | lcd_home(); |
929 | lcd.addr.y = 0; | ||
930 | lcd_gotoxy(); | ||
931 | 969 | ||
932 | spin_lock_irq(&pprt_lock); | 970 | spin_lock_irq(&pprt_lock); |
933 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 971 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { |
@@ -939,9 +977,7 @@ static void lcd_clear_fast_s(void) | |||
939 | } | 977 | } |
940 | spin_unlock_irq(&pprt_lock); | 978 | spin_unlock_irq(&pprt_lock); |
941 | 979 | ||
942 | lcd.addr.x = 0; | 980 | lcd_home(); |
943 | lcd.addr.y = 0; | ||
944 | lcd_gotoxy(); | ||
945 | } | 981 | } |
946 | 982 | ||
947 | /* fills the display with spaces and resets X/Y */ | 983 | /* fills the display with spaces and resets X/Y */ |
@@ -949,9 +985,7 @@ static void lcd_clear_fast_p8(void) | |||
949 | { | 985 | { |
950 | int pos; | 986 | int pos; |
951 | 987 | ||
952 | lcd.addr.x = 0; | 988 | lcd_home(); |
953 | lcd.addr.y = 0; | ||
954 | lcd_gotoxy(); | ||
955 | 989 | ||
956 | spin_lock_irq(&pprt_lock); | 990 | spin_lock_irq(&pprt_lock); |
957 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 991 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { |
@@ -977,9 +1011,7 @@ static void lcd_clear_fast_p8(void) | |||
977 | } | 1011 | } |
978 | spin_unlock_irq(&pprt_lock); | 1012 | spin_unlock_irq(&pprt_lock); |
979 | 1013 | ||
980 | lcd.addr.x = 0; | 1014 | lcd_home(); |
981 | lcd.addr.y = 0; | ||
982 | lcd_gotoxy(); | ||
983 | } | 1015 | } |
984 | 1016 | ||
985 | /* fills the display with spaces and resets X/Y */ | 1017 | /* fills the display with spaces and resets X/Y */ |
@@ -987,9 +1019,7 @@ static void lcd_clear_fast_tilcd(void) | |||
987 | { | 1019 | { |
988 | int pos; | 1020 | int pos; |
989 | 1021 | ||
990 | lcd.addr.x = 0; | 1022 | lcd_home(); |
991 | lcd.addr.y = 0; | ||
992 | lcd_gotoxy(); | ||
993 | 1023 | ||
994 | spin_lock_irq(&pprt_lock); | 1024 | spin_lock_irq(&pprt_lock); |
995 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { | 1025 | for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { |
@@ -1000,9 +1030,7 @@ static void lcd_clear_fast_tilcd(void) | |||
1000 | 1030 | ||
1001 | spin_unlock_irq(&pprt_lock); | 1031 | spin_unlock_irq(&pprt_lock); |
1002 | 1032 | ||
1003 | lcd.addr.x = 0; | 1033 | lcd_home(); |
1004 | lcd.addr.y = 0; | ||
1005 | lcd_gotoxy(); | ||
1006 | } | 1034 | } |
1007 | 1035 | ||
1008 | /* clears the display and resets X/Y */ | 1036 | /* clears the display and resets X/Y */ |
@@ -1108,13 +1136,8 @@ static inline int handle_lcd_special_code(void) | |||
1108 | processed = 1; | 1136 | processed = 1; |
1109 | break; | 1137 | break; |
1110 | case '*': | 1138 | case '*': |
1111 | /* flash back light using the keypad timer */ | 1139 | /* flash back light */ |
1112 | if (scan_timer.function) { | 1140 | lcd_poke(); |
1113 | if (lcd.light_tempo == 0 && | ||
1114 | ((lcd.flags & LCD_FLAG_L) == 0)) | ||
1115 | lcd_backlight(1); | ||
1116 | lcd.light_tempo = FLASH_LIGHT_TEMPO; | ||
1117 | } | ||
1118 | processed = 1; | 1141 | processed = 1; |
1119 | break; | 1142 | break; |
1120 | case 'f': /* Small Font */ | 1143 | case 'f': /* Small Font */ |
@@ -1278,21 +1301,14 @@ static inline int handle_lcd_special_code(void) | |||
1278 | lcd_write_cmd(LCD_CMD_FUNCTION_SET | 1301 | lcd_write_cmd(LCD_CMD_FUNCTION_SET |
1279 | | LCD_CMD_DATA_LEN_8BITS | 1302 | | LCD_CMD_DATA_LEN_8BITS |
1280 | | ((lcd.flags & LCD_FLAG_F) | 1303 | | ((lcd.flags & LCD_FLAG_F) |
1281 | ? LCD_CMD_TWO_LINES : 0) | ||
1282 | | ((lcd.flags & LCD_FLAG_N) | ||
1283 | ? LCD_CMD_FONT_5X10_DOTS | 1304 | ? LCD_CMD_FONT_5X10_DOTS |
1305 | : 0) | ||
1306 | | ((lcd.flags & LCD_FLAG_N) | ||
1307 | ? LCD_CMD_TWO_LINES | ||
1284 | : 0)); | 1308 | : 0)); |
1285 | /* check whether L flag was changed */ | 1309 | /* check whether L flag was changed */ |
1286 | else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) { | 1310 | else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) |
1287 | if (lcd.flags & (LCD_FLAG_L)) | 1311 | lcd_backlight(!!(lcd.flags & LCD_FLAG_L)); |
1288 | lcd_backlight(1); | ||
1289 | else if (lcd.light_tempo == 0) | ||
1290 | /* | ||
1291 | * switch off the light only when the tempo | ||
1292 | * lighting is gone | ||
1293 | */ | ||
1294 | lcd_backlight(0); | ||
1295 | } | ||
1296 | } | 1312 | } |
1297 | 1313 | ||
1298 | return processed; | 1314 | return processed; |
@@ -1376,9 +1392,7 @@ static void lcd_write_char(char c) | |||
1376 | processed = 1; | 1392 | processed = 1; |
1377 | } else if (!strcmp(lcd.esc_seq.buf, "[H")) { | 1393 | } else if (!strcmp(lcd.esc_seq.buf, "[H")) { |
1378 | /* cursor to home */ | 1394 | /* cursor to home */ |
1379 | lcd.addr.x = 0; | 1395 | lcd_home(); |
1380 | lcd.addr.y = 0; | ||
1381 | lcd_gotoxy(); | ||
1382 | processed = 1; | 1396 | processed = 1; |
1383 | } | 1397 | } |
1384 | /* codes starting with ^[[L */ | 1398 | /* codes starting with ^[[L */ |
@@ -1625,8 +1639,10 @@ static void lcd_init(void) | |||
1625 | else | 1639 | else |
1626 | lcd_char_conv = NULL; | 1640 | lcd_char_conv = NULL; |
1627 | 1641 | ||
1628 | if (lcd.pins.bl != PIN_NONE) | 1642 | if (lcd.pins.bl != PIN_NONE) { |
1629 | init_scan_timer(); | 1643 | mutex_init(&lcd.bl_tempo_lock); |
1644 | INIT_DELAYED_WORK(&lcd.bl_work, lcd_bl_off); | ||
1645 | } | ||
1630 | 1646 | ||
1631 | pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], | 1647 | pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], |
1632 | lcd_bits[LCD_PORT_C][LCD_BIT_E]); | 1648 | lcd_bits[LCD_PORT_C][LCD_BIT_E]); |
@@ -1655,14 +1671,11 @@ static void lcd_init(void) | |||
1655 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); | 1671 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); |
1656 | #endif | 1672 | #endif |
1657 | #else | 1673 | #else |
1658 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\nPanel-" | 1674 | panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE); |
1659 | PANEL_VERSION); | ||
1660 | #endif | 1675 | #endif |
1661 | lcd.addr.x = 0; | ||
1662 | lcd.addr.y = 0; | ||
1663 | /* clear the display on the next device opening */ | 1676 | /* clear the display on the next device opening */ |
1664 | lcd.must_clear = true; | 1677 | lcd.must_clear = true; |
1665 | lcd_gotoxy(); | 1678 | lcd_home(); |
1666 | } | 1679 | } |
1667 | 1680 | ||
1668 | /* | 1681 | /* |
@@ -1997,19 +2010,8 @@ static void panel_scan_timer(void) | |||
1997 | panel_process_inputs(); | 2010 | panel_process_inputs(); |
1998 | } | 2011 | } |
1999 | 2012 | ||
2000 | if (lcd.enabled && lcd.initialized) { | 2013 | if (keypressed && lcd.enabled && lcd.initialized) |
2001 | if (keypressed) { | 2014 | lcd_poke(); |
2002 | if (lcd.light_tempo == 0 && | ||
2003 | ((lcd.flags & LCD_FLAG_L) == 0)) | ||
2004 | lcd_backlight(1); | ||
2005 | lcd.light_tempo = FLASH_LIGHT_TEMPO; | ||
2006 | } else if (lcd.light_tempo > 0) { | ||
2007 | lcd.light_tempo--; | ||
2008 | if (lcd.light_tempo == 0 && | ||
2009 | ((lcd.flags & LCD_FLAG_L) == 0)) | ||
2010 | lcd_backlight(0); | ||
2011 | } | ||
2012 | } | ||
2013 | 2015 | ||
2014 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); | 2016 | mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME); |
2015 | } | 2017 | } |
@@ -2270,25 +2272,26 @@ static void panel_detach(struct parport *port) | |||
2270 | if (scan_timer.function) | 2272 | if (scan_timer.function) |
2271 | del_timer_sync(&scan_timer); | 2273 | del_timer_sync(&scan_timer); |
2272 | 2274 | ||
2273 | if (pprt) { | 2275 | if (keypad.enabled) { |
2274 | if (keypad.enabled) { | 2276 | misc_deregister(&keypad_dev); |
2275 | misc_deregister(&keypad_dev); | 2277 | keypad_initialized = 0; |
2276 | keypad_initialized = 0; | 2278 | } |
2277 | } | ||
2278 | 2279 | ||
2279 | if (lcd.enabled) { | 2280 | if (lcd.enabled) { |
2280 | panel_lcd_print("\x0cLCD driver " PANEL_VERSION | 2281 | panel_lcd_print("\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-"); |
2281 | "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-"); | 2282 | misc_deregister(&lcd_dev); |
2282 | misc_deregister(&lcd_dev); | 2283 | if (lcd.pins.bl != PIN_NONE) { |
2283 | lcd.initialized = false; | 2284 | cancel_delayed_work_sync(&lcd.bl_work); |
2285 | __lcd_backlight(0); | ||
2284 | } | 2286 | } |
2285 | 2287 | lcd.initialized = false; | |
2286 | /* TODO: free all input signals */ | ||
2287 | parport_release(pprt); | ||
2288 | parport_unregister_device(pprt); | ||
2289 | pprt = NULL; | ||
2290 | unregister_reboot_notifier(&panel_notifier); | ||
2291 | } | 2288 | } |
2289 | |||
2290 | /* TODO: free all input signals */ | ||
2291 | parport_release(pprt); | ||
2292 | parport_unregister_device(pprt); | ||
2293 | pprt = NULL; | ||
2294 | unregister_reboot_notifier(&panel_notifier); | ||
2292 | } | 2295 | } |
2293 | 2296 | ||
2294 | static struct parport_driver panel_driver = { | 2297 | static struct parport_driver panel_driver = { |
@@ -2400,7 +2403,7 @@ static int __init panel_init_module(void) | |||
2400 | 2403 | ||
2401 | if (!lcd.enabled && !keypad.enabled) { | 2404 | if (!lcd.enabled && !keypad.enabled) { |
2402 | /* no device enabled, let's exit */ | 2405 | /* no device enabled, let's exit */ |
2403 | pr_err("driver version " PANEL_VERSION " disabled.\n"); | 2406 | pr_err("panel driver disabled.\n"); |
2404 | return -ENODEV; | 2407 | return -ENODEV; |
2405 | } | 2408 | } |
2406 | 2409 | ||
@@ -2411,12 +2414,10 @@ static int __init panel_init_module(void) | |||
2411 | } | 2414 | } |
2412 | 2415 | ||
2413 | if (pprt) | 2416 | if (pprt) |
2414 | pr_info("driver version " PANEL_VERSION | 2417 | pr_info("panel driver registered on parport%d (io=0x%lx).\n", |
2415 | " registered on parport%d (io=0x%lx).\n", parport, | 2418 | parport, pprt->port->base); |
2416 | pprt->port->base); | ||
2417 | else | 2419 | else |
2418 | pr_info("driver version " PANEL_VERSION | 2420 | pr_info("panel driver not yet registered\n"); |
2419 | " not yet registered\n"); | ||
2420 | return 0; | 2421 | return 0; |
2421 | } | 2422 | } |
2422 | 2423 | ||
diff --git a/drivers/misc/sram-exec.c b/drivers/misc/sram-exec.c new file mode 100644 index 000000000000..ac522417c462 --- /dev/null +++ b/drivers/misc/sram-exec.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * SRAM protect-exec region helper functions | ||
3 | * | ||
4 | * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * Dave Gerlach | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
12 | * kind, whether express or implied; without even the implied warranty | ||
13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/device.h> | ||
18 | #include <linux/genalloc.h> | ||
19 | #include <linux/sram.h> | ||
20 | |||
21 | #include <asm/cacheflush.h> | ||
22 | |||
23 | #include "sram.h" | ||
24 | |||
25 | static DEFINE_MUTEX(exec_pool_list_mutex); | ||
26 | static LIST_HEAD(exec_pool_list); | ||
27 | |||
28 | int sram_check_protect_exec(struct sram_dev *sram, struct sram_reserve *block, | ||
29 | struct sram_partition *part) | ||
30 | { | ||
31 | unsigned long base = (unsigned long)part->base; | ||
32 | unsigned long end = base + block->size; | ||
33 | |||
34 | if (!PAGE_ALIGNED(base) || !PAGE_ALIGNED(end)) { | ||
35 | dev_err(sram->dev, | ||
36 | "SRAM pool marked with 'protect-exec' is not page aligned and will not be created.\n"); | ||
37 | return -ENOMEM; | ||
38 | } | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | int sram_add_protect_exec(struct sram_partition *part) | ||
44 | { | ||
45 | mutex_lock(&exec_pool_list_mutex); | ||
46 | list_add_tail(&part->list, &exec_pool_list); | ||
47 | mutex_unlock(&exec_pool_list_mutex); | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * sram_exec_copy - copy data to a protected executable region of sram | ||
54 | * | ||
55 | * @pool: struct gen_pool retrieved that is part of this sram | ||
56 | * @dst: Destination address for the copy, that must be inside pool | ||
57 | * @src: Source address for the data to copy | ||
58 | * @size: Size of copy to perform, which starting from dst, must reside in pool | ||
59 | * | ||
60 | * This helper function allows sram driver to act as central control location | ||
61 | * of 'protect-exec' pools which are normal sram pools but are always set | ||
62 | * read-only and executable except when copying data to them, at which point | ||
63 | * they are set to read-write non-executable, to make sure no memory is | ||
64 | * writeable and executable at the same time. This region must be page-aligned | ||
65 | * and is checked during probe, otherwise page attribute manipulation would | ||
66 | * not be possible. | ||
67 | */ | ||
68 | int sram_exec_copy(struct gen_pool *pool, void *dst, void *src, | ||
69 | size_t size) | ||
70 | { | ||
71 | struct sram_partition *part = NULL, *p; | ||
72 | unsigned long base; | ||
73 | int pages; | ||
74 | |||
75 | mutex_lock(&exec_pool_list_mutex); | ||
76 | list_for_each_entry(p, &exec_pool_list, list) { | ||
77 | if (p->pool == pool) | ||
78 | part = p; | ||
79 | } | ||
80 | mutex_unlock(&exec_pool_list_mutex); | ||
81 | |||
82 | if (!part) | ||
83 | return -EINVAL; | ||
84 | |||
85 | if (!addr_in_gen_pool(pool, (unsigned long)dst, size)) | ||
86 | return -EINVAL; | ||
87 | |||
88 | base = (unsigned long)part->base; | ||
89 | pages = PAGE_ALIGN(size) / PAGE_SIZE; | ||
90 | |||
91 | mutex_lock(&part->lock); | ||
92 | |||
93 | set_memory_nx((unsigned long)base, pages); | ||
94 | set_memory_rw((unsigned long)base, pages); | ||
95 | |||
96 | memcpy(dst, src, size); | ||
97 | |||
98 | set_memory_ro((unsigned long)base, pages); | ||
99 | set_memory_x((unsigned long)base, pages); | ||
100 | |||
101 | mutex_unlock(&part->lock); | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(sram_exec_copy); | ||
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index b33ab8ce47ab..d1185b78cf9a 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c | |||
@@ -31,35 +31,9 @@ | |||
31 | #include <linux/mfd/syscon.h> | 31 | #include <linux/mfd/syscon.h> |
32 | #include <soc/at91/atmel-secumod.h> | 32 | #include <soc/at91/atmel-secumod.h> |
33 | 33 | ||
34 | #define SRAM_GRANULARITY 32 | 34 | #include "sram.h" |
35 | |||
36 | struct sram_partition { | ||
37 | void __iomem *base; | ||
38 | |||
39 | struct gen_pool *pool; | ||
40 | struct bin_attribute battr; | ||
41 | struct mutex lock; | ||
42 | }; | ||
43 | |||
44 | struct sram_dev { | ||
45 | struct device *dev; | ||
46 | void __iomem *virt_base; | ||
47 | |||
48 | struct gen_pool *pool; | ||
49 | struct clk *clk; | ||
50 | 35 | ||
51 | struct sram_partition *partition; | 36 | #define SRAM_GRANULARITY 32 |
52 | u32 partitions; | ||
53 | }; | ||
54 | |||
55 | struct sram_reserve { | ||
56 | struct list_head list; | ||
57 | u32 start; | ||
58 | u32 size; | ||
59 | bool export; | ||
60 | bool pool; | ||
61 | const char *label; | ||
62 | }; | ||
63 | 37 | ||
64 | static ssize_t sram_read(struct file *filp, struct kobject *kobj, | 38 | static ssize_t sram_read(struct file *filp, struct kobject *kobj, |
65 | struct bin_attribute *attr, | 39 | struct bin_attribute *attr, |
@@ -148,6 +122,18 @@ static int sram_add_partition(struct sram_dev *sram, struct sram_reserve *block, | |||
148 | if (ret) | 122 | if (ret) |
149 | return ret; | 123 | return ret; |
150 | } | 124 | } |
125 | if (block->protect_exec) { | ||
126 | ret = sram_check_protect_exec(sram, block, part); | ||
127 | if (ret) | ||
128 | return ret; | ||
129 | |||
130 | ret = sram_add_pool(sram, block, start, part); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | |||
134 | sram_add_protect_exec(part); | ||
135 | } | ||
136 | |||
151 | sram->partitions++; | 137 | sram->partitions++; |
152 | 138 | ||
153 | return 0; | 139 | return 0; |
@@ -233,7 +219,11 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) | |||
233 | if (of_find_property(child, "pool", NULL)) | 219 | if (of_find_property(child, "pool", NULL)) |
234 | block->pool = true; | 220 | block->pool = true; |
235 | 221 | ||
236 | if ((block->export || block->pool) && block->size) { | 222 | if (of_find_property(child, "protect-exec", NULL)) |
223 | block->protect_exec = true; | ||
224 | |||
225 | if ((block->export || block->pool || block->protect_exec) && | ||
226 | block->size) { | ||
237 | exports++; | 227 | exports++; |
238 | 228 | ||
239 | label = NULL; | 229 | label = NULL; |
@@ -249,8 +239,10 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) | |||
249 | 239 | ||
250 | block->label = devm_kstrdup(sram->dev, | 240 | block->label = devm_kstrdup(sram->dev, |
251 | label, GFP_KERNEL); | 241 | label, GFP_KERNEL); |
252 | if (!block->label) | 242 | if (!block->label) { |
243 | ret = -ENOMEM; | ||
253 | goto err_chunks; | 244 | goto err_chunks; |
245 | } | ||
254 | 246 | ||
255 | dev_dbg(sram->dev, "found %sblock '%s' 0x%x-0x%x\n", | 247 | dev_dbg(sram->dev, "found %sblock '%s' 0x%x-0x%x\n", |
256 | block->export ? "exported " : "", block->label, | 248 | block->export ? "exported " : "", block->label, |
@@ -293,7 +285,8 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) | |||
293 | goto err_chunks; | 285 | goto err_chunks; |
294 | } | 286 | } |
295 | 287 | ||
296 | if ((block->export || block->pool) && block->size) { | 288 | if ((block->export || block->pool || block->protect_exec) && |
289 | block->size) { | ||
297 | ret = sram_add_partition(sram, block, | 290 | ret = sram_add_partition(sram, block, |
298 | res->start + block->start); | 291 | res->start + block->start); |
299 | if (ret) { | 292 | if (ret) { |
diff --git a/drivers/misc/sram.h b/drivers/misc/sram.h new file mode 100644 index 000000000000..c181ce4c8fca --- /dev/null +++ b/drivers/misc/sram.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Defines for the SRAM driver | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #ifndef __SRAM_H | ||
9 | #define __SRAM_H | ||
10 | |||
11 | struct sram_partition { | ||
12 | void __iomem *base; | ||
13 | |||
14 | struct gen_pool *pool; | ||
15 | struct bin_attribute battr; | ||
16 | struct mutex lock; | ||
17 | struct list_head list; | ||
18 | }; | ||
19 | |||
20 | struct sram_dev { | ||
21 | struct device *dev; | ||
22 | void __iomem *virt_base; | ||
23 | |||
24 | struct gen_pool *pool; | ||
25 | struct clk *clk; | ||
26 | |||
27 | struct sram_partition *partition; | ||
28 | u32 partitions; | ||
29 | }; | ||
30 | |||
31 | struct sram_reserve { | ||
32 | struct list_head list; | ||
33 | u32 start; | ||
34 | u32 size; | ||
35 | bool export; | ||
36 | bool pool; | ||
37 | bool protect_exec; | ||
38 | const char *label; | ||
39 | }; | ||
40 | |||
41 | #ifdef CONFIG_SRAM_EXEC | ||
42 | int sram_check_protect_exec(struct sram_dev *sram, struct sram_reserve *block, | ||
43 | struct sram_partition *part); | ||
44 | int sram_add_protect_exec(struct sram_partition *part); | ||
45 | #else | ||
46 | static inline int sram_check_protect_exec(struct sram_dev *sram, | ||
47 | struct sram_reserve *block, | ||
48 | struct sram_partition *part) | ||
49 | { | ||
50 | return -ENODEV; | ||
51 | } | ||
52 | |||
53 | static inline int sram_add_protect_exec(struct sram_partition *part) | ||
54 | { | ||
55 | return -ENODEV; | ||
56 | } | ||
57 | #endif /* CONFIG_SRAM_EXEC */ | ||
58 | #endif /* __SRAM_H */ | ||
diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 189b32519748..9d659542a335 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c | |||
@@ -54,10 +54,7 @@ struct vmci_guest_device { | |||
54 | struct device *dev; /* PCI device we are attached to */ | 54 | struct device *dev; /* PCI device we are attached to */ |
55 | void __iomem *iobase; | 55 | void __iomem *iobase; |
56 | 56 | ||
57 | unsigned int irq; | ||
58 | unsigned int intr_type; | ||
59 | bool exclusive_vectors; | 57 | bool exclusive_vectors; |
60 | struct msix_entry msix_entries[VMCI_MAX_INTRS]; | ||
61 | 58 | ||
62 | struct tasklet_struct datagram_tasklet; | 59 | struct tasklet_struct datagram_tasklet; |
63 | struct tasklet_struct bm_tasklet; | 60 | struct tasklet_struct bm_tasklet; |
@@ -369,30 +366,6 @@ static void vmci_process_bitmap(unsigned long data) | |||
369 | } | 366 | } |
370 | 367 | ||
371 | /* | 368 | /* |
372 | * Enable MSI-X. Try exclusive vectors first, then shared vectors. | ||
373 | */ | ||
374 | static int vmci_enable_msix(struct pci_dev *pdev, | ||
375 | struct vmci_guest_device *vmci_dev) | ||
376 | { | ||
377 | int i; | ||
378 | int result; | ||
379 | |||
380 | for (i = 0; i < VMCI_MAX_INTRS; ++i) { | ||
381 | vmci_dev->msix_entries[i].entry = i; | ||
382 | vmci_dev->msix_entries[i].vector = i; | ||
383 | } | ||
384 | |||
385 | result = pci_enable_msix_exact(pdev, | ||
386 | vmci_dev->msix_entries, VMCI_MAX_INTRS); | ||
387 | if (result == 0) | ||
388 | vmci_dev->exclusive_vectors = true; | ||
389 | else if (result == -ENOSPC) | ||
390 | result = pci_enable_msix_exact(pdev, vmci_dev->msix_entries, 1); | ||
391 | |||
392 | return result; | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Interrupt handler for legacy or MSI interrupt, or for first MSI-X | 369 | * Interrupt handler for legacy or MSI interrupt, or for first MSI-X |
397 | * interrupt (vector VMCI_INTR_DATAGRAM). | 370 | * interrupt (vector VMCI_INTR_DATAGRAM). |
398 | */ | 371 | */ |
@@ -406,7 +379,7 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev) | |||
406 | * Otherwise we must read the ICR to determine what to do. | 379 | * Otherwise we must read the ICR to determine what to do. |
407 | */ | 380 | */ |
408 | 381 | ||
409 | if (dev->intr_type == VMCI_INTR_TYPE_MSIX && dev->exclusive_vectors) { | 382 | if (dev->exclusive_vectors) { |
410 | tasklet_schedule(&dev->datagram_tasklet); | 383 | tasklet_schedule(&dev->datagram_tasklet); |
411 | } else { | 384 | } else { |
412 | unsigned int icr; | 385 | unsigned int icr; |
@@ -491,7 +464,6 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, | |||
491 | } | 464 | } |
492 | 465 | ||
493 | vmci_dev->dev = &pdev->dev; | 466 | vmci_dev->dev = &pdev->dev; |
494 | vmci_dev->intr_type = VMCI_INTR_TYPE_INTX; | ||
495 | vmci_dev->exclusive_vectors = false; | 467 | vmci_dev->exclusive_vectors = false; |
496 | vmci_dev->iobase = iobase; | 468 | vmci_dev->iobase = iobase; |
497 | 469 | ||
@@ -592,26 +564,26 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, | |||
592 | * Enable interrupts. Try MSI-X first, then MSI, and then fallback on | 564 | * Enable interrupts. Try MSI-X first, then MSI, and then fallback on |
593 | * legacy interrupts. | 565 | * legacy interrupts. |
594 | */ | 566 | */ |
595 | if (!vmci_disable_msix && !vmci_enable_msix(pdev, vmci_dev)) { | 567 | error = pci_alloc_irq_vectors(pdev, VMCI_MAX_INTRS, VMCI_MAX_INTRS, |
596 | vmci_dev->intr_type = VMCI_INTR_TYPE_MSIX; | 568 | PCI_IRQ_MSIX); |
597 | vmci_dev->irq = vmci_dev->msix_entries[0].vector; | 569 | if (error) { |
598 | } else if (!vmci_disable_msi && !pci_enable_msi(pdev)) { | 570 | error = pci_alloc_irq_vectors(pdev, 1, 1, |
599 | vmci_dev->intr_type = VMCI_INTR_TYPE_MSI; | 571 | PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY); |
600 | vmci_dev->irq = pdev->irq; | 572 | if (error) |
573 | goto err_remove_bitmap; | ||
601 | } else { | 574 | } else { |
602 | vmci_dev->intr_type = VMCI_INTR_TYPE_INTX; | 575 | vmci_dev->exclusive_vectors = true; |
603 | vmci_dev->irq = pdev->irq; | ||
604 | } | 576 | } |
605 | 577 | ||
606 | /* | 578 | /* |
607 | * Request IRQ for legacy or MSI interrupts, or for first | 579 | * Request IRQ for legacy or MSI interrupts, or for first |
608 | * MSI-X vector. | 580 | * MSI-X vector. |
609 | */ | 581 | */ |
610 | error = request_irq(vmci_dev->irq, vmci_interrupt, IRQF_SHARED, | 582 | error = request_irq(pci_irq_vector(pdev, 0), vmci_interrupt, |
611 | KBUILD_MODNAME, vmci_dev); | 583 | IRQF_SHARED, KBUILD_MODNAME, vmci_dev); |
612 | if (error) { | 584 | if (error) { |
613 | dev_err(&pdev->dev, "Irq %u in use: %d\n", | 585 | dev_err(&pdev->dev, "Irq %u in use: %d\n", |
614 | vmci_dev->irq, error); | 586 | pci_irq_vector(pdev, 0), error); |
615 | goto err_disable_msi; | 587 | goto err_disable_msi; |
616 | } | 588 | } |
617 | 589 | ||
@@ -622,13 +594,13 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, | |||
622 | * between the vectors. | 594 | * between the vectors. |
623 | */ | 595 | */ |
624 | if (vmci_dev->exclusive_vectors) { | 596 | if (vmci_dev->exclusive_vectors) { |
625 | error = request_irq(vmci_dev->msix_entries[1].vector, | 597 | error = request_irq(pci_irq_vector(pdev, 1), |
626 | vmci_interrupt_bm, 0, KBUILD_MODNAME, | 598 | vmci_interrupt_bm, 0, KBUILD_MODNAME, |
627 | vmci_dev); | 599 | vmci_dev); |
628 | if (error) { | 600 | if (error) { |
629 | dev_err(&pdev->dev, | 601 | dev_err(&pdev->dev, |
630 | "Failed to allocate irq %u: %d\n", | 602 | "Failed to allocate irq %u: %d\n", |
631 | vmci_dev->msix_entries[1].vector, error); | 603 | pci_irq_vector(pdev, 1), error); |
632 | goto err_free_irq; | 604 | goto err_free_irq; |
633 | } | 605 | } |
634 | } | 606 | } |
@@ -651,15 +623,12 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, | |||
651 | return 0; | 623 | return 0; |
652 | 624 | ||
653 | err_free_irq: | 625 | err_free_irq: |
654 | free_irq(vmci_dev->irq, vmci_dev); | 626 | free_irq(pci_irq_vector(pdev, 0), vmci_dev); |
655 | tasklet_kill(&vmci_dev->datagram_tasklet); | 627 | tasklet_kill(&vmci_dev->datagram_tasklet); |
656 | tasklet_kill(&vmci_dev->bm_tasklet); | 628 | tasklet_kill(&vmci_dev->bm_tasklet); |
657 | 629 | ||
658 | err_disable_msi: | 630 | err_disable_msi: |
659 | if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSIX) | 631 | pci_free_irq_vectors(pdev); |
660 | pci_disable_msix(pdev); | ||
661 | else if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSI) | ||
662 | pci_disable_msi(pdev); | ||
663 | 632 | ||
664 | vmci_err = vmci_event_unsubscribe(ctx_update_sub_id); | 633 | vmci_err = vmci_event_unsubscribe(ctx_update_sub_id); |
665 | if (vmci_err < VMCI_SUCCESS) | 634 | if (vmci_err < VMCI_SUCCESS) |
@@ -719,14 +688,10 @@ static void vmci_guest_remove_device(struct pci_dev *pdev) | |||
719 | * MSI-X, we might have multiple vectors, each with their own | 688 | * MSI-X, we might have multiple vectors, each with their own |
720 | * IRQ, which we must free too. | 689 | * IRQ, which we must free too. |
721 | */ | 690 | */ |
722 | free_irq(vmci_dev->irq, vmci_dev); | 691 | if (vmci_dev->exclusive_vectors) |
723 | if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSIX) { | 692 | free_irq(pci_irq_vector(pdev, 1), vmci_dev); |
724 | if (vmci_dev->exclusive_vectors) | 693 | free_irq(pci_irq_vector(pdev, 0), vmci_dev); |
725 | free_irq(vmci_dev->msix_entries[1].vector, vmci_dev); | 694 | pci_free_irq_vectors(pdev); |
726 | pci_disable_msix(pdev); | ||
727 | } else if (vmci_dev->intr_type == VMCI_INTR_TYPE_MSI) { | ||
728 | pci_disable_msi(pdev); | ||
729 | } | ||
730 | 695 | ||
731 | tasklet_kill(&vmci_dev->datagram_tasklet); | 696 | tasklet_kill(&vmci_dev->datagram_tasklet); |
732 | tasklet_kill(&vmci_dev->bm_tasklet); | 697 | tasklet_kill(&vmci_dev->bm_tasklet); |