diff options
73 files changed, 3454 insertions, 607 deletions
diff --git a/Documentation/ABI/testing/configfs-acpi b/Documentation/ABI/testing/configfs-acpi new file mode 100644 index 000000000000..4ab4e99aa863 --- /dev/null +++ b/Documentation/ABI/testing/configfs-acpi | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | What: /config/acpi | ||
| 2 | Date: July 2016 | ||
| 3 | KernelVersion: 4.8 | ||
| 4 | Contact: linux-acpi@vger.kernel.org | ||
| 5 | Description: | ||
| 6 | This represents the ACPI subsystem entry point directory. It | ||
| 7 | contains sub-groups corresponding to ACPI configurable options. | ||
| 8 | |||
| 9 | What: /config/acpi/table | ||
| 10 | Date: July 2016 | ||
| 11 | KernelVersion: 4.8 | ||
| 12 | Description: | ||
| 13 | |||
| 14 | This group contains the configuration for user defined ACPI | ||
| 15 | tables. The attributes of a user define table are: | ||
| 16 | |||
| 17 | aml - a binary attribute that the user can use to | ||
| 18 | fill in the ACPI aml definitions. Once the aml | ||
| 19 | data is written to this file and the file is | ||
| 20 | closed the table will be loaded and ACPI devices | ||
| 21 | will be enumerated. To check if the operation is | ||
| 22 | successful the user must check the error code | ||
| 23 | for close(). If the operation is successful, | ||
| 24 | subsequent writes to this attribute will fail. | ||
| 25 | |||
| 26 | The rest of the attributes are read-only and are valid only | ||
| 27 | after the table has been loaded by filling the aml entry: | ||
| 28 | |||
| 29 | signature - ASCII table signature | ||
| 30 | length - length of table in bytes, including the header | ||
| 31 | revision - ACPI Specification minor version number | ||
| 32 | oem_id - ASCII OEM identification | ||
| 33 | oem_table_id - ASCII OEM table identification | ||
| 34 | oem_revision - OEM revision number | ||
| 35 | asl_compiler_id - ASCII ASL compiler vendor ID | ||
| 36 | asl_compiler_revision - ASL compiler version | ||
diff --git a/Documentation/acpi/aml-debugger.txt b/Documentation/acpi/aml-debugger.txt new file mode 100644 index 000000000000..5f62aa4a493b --- /dev/null +++ b/Documentation/acpi/aml-debugger.txt | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | The AML Debugger | ||
| 2 | |||
| 3 | Copyright (C) 2016, Intel Corporation | ||
| 4 | Author: Lv Zheng <lv.zheng@intel.com> | ||
| 5 | |||
| 6 | |||
| 7 | This document describes the usage of the AML debugger embedded in the Linux | ||
| 8 | kernel. | ||
| 9 | |||
| 10 | 1. Build the debugger | ||
| 11 | |||
| 12 | The following kernel configuration items are required to enable the AML | ||
| 13 | debugger interface from the Linux kernel: | ||
| 14 | |||
| 15 | CONFIG_ACPI_DEBUGGER=y | ||
| 16 | CONFIG_ACPI_DEBUGGER_USER=m | ||
| 17 | |||
| 18 | The userspace utlities can be built from the kernel source tree using | ||
| 19 | the following commands: | ||
| 20 | |||
| 21 | $ cd tools | ||
| 22 | $ make acpi | ||
| 23 | |||
| 24 | The resultant userspace tool binary is then located at: | ||
| 25 | |||
| 26 | tools/acpi/power/acpi/acpidbg/acpidbg | ||
| 27 | |||
| 28 | It can be installed to system directories by running "make install" (as a | ||
| 29 | sufficiently privileged user). | ||
| 30 | |||
| 31 | 2. Start the userspace debugger interface | ||
| 32 | |||
| 33 | After booting the kernel with the debugger built-in, the debugger can be | ||
| 34 | started by using the following commands: | ||
| 35 | |||
| 36 | # mount -t debugfs none /sys/kernel/debug | ||
| 37 | # modprobe acpi_dbg | ||
| 38 | # tools/acpi/power/acpi/acpidbg/acpidbg | ||
| 39 | |||
| 40 | That spawns the interactive AML debugger environment where you can execute | ||
| 41 | debugger commands. | ||
| 42 | |||
| 43 | The commands are documented in the "ACPICA Overview and Programmer Reference" | ||
| 44 | that can be downloaded from | ||
| 45 | |||
| 46 | https://acpica.org/documentation | ||
| 47 | |||
| 48 | The detailed debugger commands reference is located in Chapter 12 "ACPICA | ||
| 49 | Debugger Reference". The "help" command can be used for a quick reference. | ||
| 50 | |||
| 51 | 3. Stop the userspace debugger interface | ||
| 52 | |||
| 53 | The interactive debugger interface can be closed by pressing Ctrl+C or using | ||
| 54 | the "quit" or "exit" commands. When finished, unload the module with: | ||
| 55 | |||
| 56 | # rmmod acpi_dbg | ||
| 57 | |||
| 58 | The module unloading may fail if there is an acpidbg instance running. | ||
| 59 | |||
| 60 | 4. Run the debugger in a script | ||
| 61 | |||
| 62 | It may be useful to run the AML debugger in a test script. "acpidbg" supports | ||
| 63 | this in a special "batch" mode. For example, the following command outputs | ||
| 64 | the entire ACPI namespace: | ||
| 65 | |||
| 66 | # acpidbg -b "namespace" | ||
diff --git a/Documentation/acpi/linuxized-acpica.txt b/Documentation/acpi/linuxized-acpica.txt new file mode 100644 index 000000000000..defe2eec5331 --- /dev/null +++ b/Documentation/acpi/linuxized-acpica.txt | |||
| @@ -0,0 +1,262 @@ | |||
| 1 | Linuxized ACPICA - Introduction to ACPICA Release Automation | ||
| 2 | |||
| 3 | Copyright (C) 2013-2016, Intel Corporation | ||
| 4 | Author: Lv Zheng <lv.zheng@intel.com> | ||
| 5 | |||
| 6 | |||
| 7 | Abstract: | ||
| 8 | |||
| 9 | This document describes the ACPICA project and the relationship between | ||
| 10 | ACPICA and Linux. It also describes how ACPICA code in drivers/acpi/acpica, | ||
| 11 | include/acpi and tools/power/acpi is automatically updated to follow the | ||
| 12 | upstream. | ||
| 13 | |||
| 14 | |||
| 15 | 1. ACPICA Project | ||
| 16 | |||
| 17 | The ACPI Component Architecture (ACPICA) project provides an operating | ||
| 18 | system (OS)-independent reference implementation of the Advanced | ||
| 19 | Configuration and Power Interface Specification (ACPI). It has been | ||
| 20 | adapted by various host OSes. By directly integrating ACPICA, Linux can | ||
| 21 | also benefit from the application experiences of ACPICA from other host | ||
| 22 | OSes. | ||
| 23 | |||
| 24 | The homepage of ACPICA project is: www.acpica.org, it is maintained and | ||
| 25 | supported by Intel Corporation. | ||
| 26 | |||
| 27 | The following figure depicts the Linux ACPI subystem where the ACPICA | ||
| 28 | adaptation is included: | ||
| 29 | |||
| 30 | +---------------------------------------------------------+ | ||
| 31 | | | | ||
| 32 | | +---------------------------------------------------+ | | ||
| 33 | | | +------------------+ | | | ||
| 34 | | | | Table Management | | | | ||
| 35 | | | +------------------+ | | | ||
| 36 | | | +----------------------+ | | | ||
| 37 | | | | Namespace Management | | | | ||
| 38 | | | +----------------------+ | | | ||
| 39 | | | +------------------+ ACPICA Components | | | ||
| 40 | | | | Event Management | | | | ||
| 41 | | | +------------------+ | | | ||
| 42 | | | +---------------------+ | | | ||
| 43 | | | | Resource Management | | | | ||
| 44 | | | +---------------------+ | | | ||
| 45 | | | +---------------------+ | | | ||
| 46 | | | | Hardware Management | | | | ||
| 47 | | | +---------------------+ | | | ||
| 48 | | +---------------------------------------------------+ | | | ||
| 49 | | | | +------------------+ | | | | ||
| 50 | | | | | OS Service Layer | | | | | ||
| 51 | | | | +------------------+ | | | | ||
| 52 | | | +-------------------------------------------------|-+ | | ||
| 53 | | | +--------------------+ | | | ||
| 54 | | | | Device Enumeration | | | | ||
| 55 | | | +--------------------+ | | | ||
| 56 | | | +------------------+ | | | ||
| 57 | | | | Power Management | | | | ||
| 58 | | | +------------------+ Linux/ACPI Components | | | ||
| 59 | | | +--------------------+ | | | ||
| 60 | | | | Thermal Management | | | | ||
| 61 | | | +--------------------+ | | | ||
| 62 | | | +--------------------------+ | | | ||
| 63 | | | | Drivers for ACPI Devices | | | | ||
| 64 | | | +--------------------------+ | | | ||
| 65 | | | +--------+ | | | ||
| 66 | | | | ...... | | | | ||
| 67 | | | +--------+ | | | ||
| 68 | | +---------------------------------------------------+ | | ||
| 69 | | | | ||
| 70 | +---------------------------------------------------------+ | ||
| 71 | |||
| 72 | Figure 1. Linux ACPI Software Components | ||
| 73 | |||
| 74 | NOTE: | ||
| 75 | A. OS Service Layer - Provided by Linux to offer OS dependent | ||
| 76 | implementation of the predefined ACPICA interfaces (acpi_os_*). | ||
| 77 | include/acpi/acpiosxf.h | ||
| 78 | drivers/acpi/osl.c | ||
| 79 | include/acpi/platform | ||
| 80 | include/asm/acenv.h | ||
| 81 | B. ACPICA Functionality - Released from ACPICA code base to offer | ||
| 82 | OS independent implementation of the ACPICA interfaces (acpi_*). | ||
| 83 | drivers/acpi/acpica | ||
| 84 | include/acpi/ac*.h | ||
| 85 | tools/power/acpi | ||
| 86 | C. Linux/ACPI Functionality - Providing Linux specific ACPI | ||
| 87 | functionality to the other Linux kernel subsystems and user space | ||
| 88 | programs. | ||
| 89 | drivers/acpi | ||
| 90 | include/linux/acpi.h | ||
| 91 | include/linux/acpi*.h | ||
| 92 | include/acpi | ||
| 93 | tools/power/acpi | ||
| 94 | D. Architecture Specific ACPICA/ACPI Functionalities - Provided by the | ||
| 95 | ACPI subsystem to offer architecture specific implementation of the | ||
| 96 | ACPI interfaces. They are Linux specific components and are out of | ||
| 97 | the scope of this document. | ||
| 98 | include/asm/acpi.h | ||
| 99 | include/asm/acpi*.h | ||
| 100 | arch/*/acpi | ||
| 101 | |||
| 102 | 2. ACPICA Release | ||
| 103 | |||
| 104 | The ACPICA project maintains its code base at the following repository URL: | ||
| 105 | https://github.com/acpica/acpica.git. As a rule, a release is made every | ||
| 106 | month. | ||
| 107 | |||
| 108 | As the coding style adopted by the ACPICA project is not acceptable by | ||
| 109 | Linux, there is a release process to convert the ACPICA git commits into | ||
| 110 | Linux patches. The patches generated by this process are referred to as | ||
| 111 | "linuxized ACPICA patches". The release process is carried out on a local | ||
| 112 | copy the ACPICA git repository. Each commit in the monthly release is | ||
| 113 | converted into a linuxized ACPICA patch. Together, they form the montly | ||
| 114 | ACPICA release patchset for the Linux ACPI community. This process is | ||
| 115 | illustrated in the following figure: | ||
| 116 | |||
| 117 | +-----------------------------+ | ||
| 118 | | acpica / master (-) commits | | ||
| 119 | +-----------------------------+ | ||
| 120 | /|\ | | ||
| 121 | | \|/ | ||
| 122 | | /---------------------\ +----------------------+ | ||
| 123 | | < Linuxize repo Utility >-->| old linuxized acpica |--+ | ||
| 124 | | \---------------------/ +----------------------+ | | ||
| 125 | | | | ||
| 126 | /---------\ | | ||
| 127 | < git reset > \ | ||
| 128 | \---------/ \ | ||
| 129 | /|\ /+-+ | ||
| 130 | | / | | ||
| 131 | +-----------------------------+ | | | ||
| 132 | | acpica / master (+) commits | | | | ||
| 133 | +-----------------------------+ | | | ||
| 134 | | | | | ||
| 135 | \|/ | | | ||
| 136 | /-----------------------\ +----------------------+ | | | ||
| 137 | < Linuxize repo Utilities >-->| new linuxized acpica |--+ | | ||
| 138 | \-----------------------/ +----------------------+ | | ||
| 139 | \|/ | ||
| 140 | +--------------------------+ /----------------------\ | ||
| 141 | | Linuxized ACPICA Patches |<----------------< Linuxize patch Utility > | ||
| 142 | +--------------------------+ \----------------------/ | ||
| 143 | | | ||
| 144 | \|/ | ||
| 145 | /---------------------------\ | ||
| 146 | < Linux ACPI Community Review > | ||
| 147 | \---------------------------/ | ||
| 148 | | | ||
| 149 | \|/ | ||
| 150 | +-----------------------+ /------------------\ +----------------+ | ||
| 151 | | linux-pm / linux-next |-->< Linux Merge Window >-->| linux / master | | ||
| 152 | +-----------------------+ \------------------/ +----------------+ | ||
| 153 | |||
| 154 | Figure 2. ACPICA -> Linux Upstream Process | ||
| 155 | |||
| 156 | NOTE: | ||
| 157 | A. Linuxize Utilities - Provided by the ACPICA repository, including a | ||
| 158 | utility located in source/tools/acpisrc folder and a number of | ||
| 159 | scripts located in generate/linux folder. | ||
| 160 | B. acpica / master - "master" branch of the git repository at | ||
| 161 | <https://github.com/acpica/acpica.git>. | ||
| 162 | C. linux-pm / linux-next - "linux-next" branch of the git repository at | ||
| 163 | <http://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git>. | ||
| 164 | D. linux / master - "master" branch of the git repository at | ||
| 165 | <http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git>. | ||
| 166 | |||
| 167 | Before the linuxized ACPICA patches are sent to the Linux ACPI community | ||
| 168 | for review, there is a quality ensurance build test process to reduce | ||
| 169 | porting issues. Currently this build process only takes care of the | ||
| 170 | following kernel configuration options: | ||
| 171 | CONFIG_ACPI/CONFIG_ACPI_DEBUG/CONFIG_ACPI_DEBUGGER | ||
| 172 | |||
| 173 | 3. ACPICA Divergences | ||
| 174 | |||
| 175 | Ideally, all of the ACPICA commits should be converted into Linux patches | ||
| 176 | automatically without manual modifications, the "linux / master" tree should | ||
| 177 | contain the ACPICA code that exactly corresponds to the ACPICA code | ||
| 178 | contained in "new linuxized acpica" tree and it should be possible to run | ||
| 179 | the release process fully automatically. | ||
| 180 | |||
| 181 | As a matter of fact, however, there are source code differences between | ||
| 182 | the ACPICA code in Linux and the upstream ACPICA code, referred to as | ||
| 183 | "ACPICA Divergences". | ||
| 184 | |||
| 185 | The various sources of ACPICA divergences include: | ||
| 186 | 1. Legacy divergences - Before the current ACPICA release process was | ||
| 187 | established, there already had been divergences between Linux and | ||
| 188 | ACPICA. Over the past several years those divergences have been greatly | ||
| 189 | reduced, but there still are several ones and it takes time to figure | ||
| 190 | out the underlying reasons for their existence. | ||
| 191 | 2. Manual modifications - Any manual modification (eg. coding style fixes) | ||
| 192 | made directly in the Linux sources obviously hurts the ACPICA release | ||
| 193 | automation. Thus it is recommended to fix such issues in the ACPICA | ||
| 194 | upstream source code and generate the linuxized fix using the ACPICA | ||
| 195 | release utilities (please refer to Section 4 below for the details). | ||
| 196 | 3. Linux specific features - Sometimes it's impossible to use the | ||
| 197 | current ACPICA APIs to implement features required by the Linux kernel, | ||
| 198 | so Linux developers occasionaly have to change ACPICA code directly. | ||
| 199 | Those changes may not be acceptable by ACPICA upstream and in such cases | ||
| 200 | they are left as committed ACPICA divergences unless the ACPICA side can | ||
| 201 | implement new mechanisms as replacements for them. | ||
| 202 | 4. ACPICA release fixups - ACPICA only tests commits using a set of the | ||
| 203 | user space simulation utilies, thus the linuxized ACPICA patches may | ||
| 204 | break the Linux kernel, leaving us build/boot failures. In order to | ||
| 205 | avoid breaking Linux bisection, fixes are applied directly to the | ||
| 206 | linuxized ACPICA patches during the release process. When the release | ||
| 207 | fixups are backported to the upstream ACPICA sources, they must follow | ||
| 208 | the upstream ACPICA rules and so further modifications may appear. | ||
| 209 | That may result in the appearance of new divergences. | ||
| 210 | 5. Fast tracking of ACPICA commits - Some ACPICA commits are regression | ||
| 211 | fixes or stable-candidate material, so they are applied in advance with | ||
| 212 | respect to the ACPICA release process. If such commits are reverted or | ||
| 213 | rebased on the ACPICA side in order to offer better solutions, new ACPICA | ||
| 214 | divergences are generated. | ||
| 215 | |||
| 216 | 4. ACPICA Development | ||
| 217 | |||
| 218 | This paragraph guides Linux developers to use the ACPICA upstream release | ||
| 219 | utilities to obtain Linux patches corresponding to upstream ACPICA commits | ||
| 220 | before they become available from the ACPICA release process. | ||
| 221 | |||
| 222 | 1. Cherry-pick an ACPICA commit | ||
| 223 | |||
| 224 | First you need to git clone the ACPICA repository and the ACPICA change | ||
| 225 | you want to cherry pick must be committed into the local repository. | ||
| 226 | |||
| 227 | Then the gen-patch.sh command can help to cherry-pick an ACPICA commit | ||
| 228 | from the ACPICA local repository: | ||
| 229 | |||
| 230 | $ git clone https://github.com/acpica/acpica | ||
| 231 | $ cd acpica | ||
| 232 | $ generate/linux/gen-patch.sh -u [commit ID] | ||
| 233 | |||
| 234 | Here the commit ID is the ACPICA local repository commit ID you want to | ||
| 235 | cherry pick. It can be omitted if the commit is "HEAD". | ||
| 236 | |||
| 237 | 2. Cherry-pick recent ACPICA commits | ||
| 238 | |||
| 239 | Sometimes you need to rebase your code on top of the most recent ACPICA | ||
| 240 | changes that haven't been applied to Linux yet. | ||
| 241 | |||
| 242 | You can generate the ACPICA release series yourself and rebase your code on | ||
| 243 | top of the generated ACPICA release patches: | ||
| 244 | |||
| 245 | $ git clone https://github.com/acpica/acpica | ||
| 246 | $ cd acpica | ||
| 247 | $ generate/linux/make-patches.sh -u [commit ID] | ||
| 248 | |||
| 249 | The commit ID should be the last ACPICA commit accepted by Linux. Usually, | ||
| 250 | it is the commit modifying ACPI_CA_VERSION. It can be found by executing | ||
| 251 | "git blame source/include/acpixf.h" and referencing the line that contains | ||
| 252 | "ACPI_CA_VERSION". | ||
| 253 | |||
| 254 | 3. Inspect the current divergences | ||
| 255 | |||
| 256 | If you have local copies of both Linux and upstream ACPICA, you can generate | ||
| 257 | a diff file indicating the state of the current divergences: | ||
| 258 | |||
| 259 | # git clone https://github.com/acpica/acpica | ||
| 260 | # git clone http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git | ||
| 261 | # cd acpica | ||
| 262 | # generate/linux/divergences.sh -s ../linux | ||
diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-overlays.txt new file mode 100644 index 000000000000..5ae13f161ea2 --- /dev/null +++ b/Documentation/acpi/ssdt-overlays.txt | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | |||
| 2 | In order to support ACPI open-ended hardware configurations (e.g. development | ||
| 3 | boards) we need a way to augment the ACPI configuration provided by the firmware | ||
| 4 | image. A common example is connecting sensors on I2C / SPI buses on development | ||
| 5 | boards. | ||
| 6 | |||
| 7 | Although this can be accomplished by creating a kernel platform driver or | ||
| 8 | recompiling the firmware image with updated ACPI tables, neither is practical: | ||
| 9 | the former proliferates board specific kernel code while the latter requires | ||
| 10 | access to firmware tools which are often not publicly available. | ||
| 11 | |||
| 12 | Because ACPI supports external references in AML code a more practical | ||
| 13 | way to augment firmware ACPI configuration is by dynamically loading | ||
| 14 | user defined SSDT tables that contain the board specific information. | ||
| 15 | |||
| 16 | For example, to enumerate a Bosch BMA222E accelerometer on the I2C bus of the | ||
| 17 | Minnowboard MAX development board exposed via the LSE connector [1], the | ||
| 18 | following ASL code can be used: | ||
| 19 | |||
| 20 | DefinitionBlock ("minnowmax.aml", "SSDT", 1, "Vendor", "Accel", 0x00000003) | ||
| 21 | { | ||
| 22 | External (\_SB.I2C6, DeviceObj) | ||
| 23 | |||
| 24 | Scope (\_SB.I2C6) | ||
| 25 | { | ||
| 26 | Device (STAC) | ||
| 27 | { | ||
| 28 | Name (_ADR, Zero) | ||
| 29 | Name (_HID, "BMA222E") | ||
| 30 | |||
| 31 | Method (_CRS, 0, Serialized) | ||
| 32 | { | ||
| 33 | Name (RBUF, ResourceTemplate () | ||
| 34 | { | ||
| 35 | I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80, | ||
| 36 | AddressingMode7Bit, "\\_SB.I2C6", 0x00, | ||
| 37 | ResourceConsumer, ,) | ||
| 38 | GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000, | ||
| 39 | "\\_SB.GPO2", 0x00, ResourceConsumer, , ) | ||
| 40 | { // Pin list | ||
| 41 | 0 | ||
| 42 | } | ||
| 43 | }) | ||
| 44 | Return (RBUF) | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | which can then be compiled to AML binary format: | ||
| 51 | |||
| 52 | $ iasl minnowmax.asl | ||
| 53 | |||
| 54 | Intel ACPI Component Architecture | ||
| 55 | ASL Optimizing Compiler version 20140214-64 [Mar 29 2014] | ||
| 56 | Copyright (c) 2000 - 2014 Intel Corporation | ||
| 57 | |||
| 58 | ASL Input: minnomax.asl - 30 lines, 614 bytes, 7 keywords | ||
| 59 | AML Output: minnowmax.aml - 165 bytes, 6 named objects, 1 executable opcodes | ||
| 60 | |||
| 61 | [1] http://wiki.minnowboard.org/MinnowBoard_MAX#Low_Speed_Expansion_Connector_.28Top.29 | ||
| 62 | |||
| 63 | The resulting AML code can then be loaded by the kernel using one of the methods | ||
| 64 | below. | ||
| 65 | |||
| 66 | == Loading ACPI SSDTs from initrd == | ||
| 67 | |||
| 68 | This option allows loading of user defined SSDTs from initrd and it is useful | ||
| 69 | when the system does not support EFI or when there is not enough EFI storage. | ||
| 70 | |||
| 71 | It works in a similar way with initrd based ACPI tables override/upgrade: SSDT | ||
| 72 | aml code must be placed in the first, uncompressed, initrd under the | ||
| 73 | "kernel/firmware/acpi" path. Multiple files can be used and this will translate | ||
| 74 | in loading multiple tables. Only SSDT and OEM tables are allowed. See | ||
| 75 | initrd_table_override.txt for more details. | ||
| 76 | |||
| 77 | Here is an example: | ||
| 78 | |||
| 79 | # Add the raw ACPI tables to an uncompressed cpio archive. | ||
| 80 | # They must be put into a /kernel/firmware/acpi directory inside the | ||
| 81 | # cpio archive. | ||
| 82 | # The uncompressed cpio archive must be the first. | ||
| 83 | # Other, typically compressed cpio archives, must be | ||
| 84 | # concatenated on top of the uncompressed one. | ||
| 85 | mkdir -p kernel/firmware/acpi | ||
| 86 | cp ssdt.aml kernel/firmware/acpi | ||
| 87 | |||
| 88 | # Create the uncompressed cpio archive and concatenate the original initrd | ||
| 89 | # on top: | ||
| 90 | find kernel | cpio -H newc --create > /boot/instrumented_initrd | ||
| 91 | cat /boot/initrd >>/boot/instrumented_initrd | ||
| 92 | |||
| 93 | == Loading ACPI SSDTs from EFI variables == | ||
| 94 | |||
| 95 | This is the preferred method, when EFI is supported on the platform, because it | ||
| 96 | allows a persistent, OS independent way of storing the user defined SSDTs. There | ||
| 97 | is also work underway to implement EFI support for loading user defined SSDTs | ||
| 98 | and using this method will make it easier to convert to the EFI loading | ||
| 99 | mechanism when that will arrive. | ||
| 100 | |||
| 101 | In order to load SSDTs from an EFI variable the efivar_ssdt kernel command line | ||
| 102 | parameter can be used. The argument for the option is the variable name to | ||
| 103 | use. If there are multiple variables with the same name but with different | ||
| 104 | vendor GUIDs, all of them will be loaded. | ||
| 105 | |||
| 106 | In order to store the AML code in an EFI variable the efivarfs filesystem can be | ||
| 107 | used. It is enabled and mounted by default in /sys/firmware/efi/efivars in all | ||
| 108 | recent distribution. | ||
| 109 | |||
| 110 | Creating a new file in /sys/firmware/efi/efivars will automatically create a new | ||
| 111 | EFI variable. Updating a file in /sys/firmware/efi/efivars will update the EFI | ||
| 112 | variable. Please note that the file name needs to be specially formatted as | ||
| 113 | "Name-GUID" and that the first 4 bytes in the file (little-endian format) | ||
| 114 | represent the attributes of the EFI variable (see EFI_VARIABLE_MASK in | ||
| 115 | include/linux/efi.h). Writing to the file must also be done with one write | ||
| 116 | operation. | ||
| 117 | |||
| 118 | For example, you can use the following bash script to create/update an EFI | ||
| 119 | variable with the content from a given file: | ||
| 120 | |||
| 121 | #!/bin/sh -e | ||
| 122 | |||
| 123 | while ! [ -z "$1" ]; do | ||
| 124 | case "$1" in | ||
| 125 | "-f") filename="$2"; shift;; | ||
| 126 | "-g") guid="$2"; shift;; | ||
| 127 | *) name="$1";; | ||
| 128 | esac | ||
| 129 | shift | ||
| 130 | done | ||
| 131 | |||
| 132 | usage() | ||
| 133 | { | ||
| 134 | echo "Syntax: ${0##*/} -f filename [ -g guid ] name" | ||
| 135 | exit 1 | ||
| 136 | } | ||
| 137 | |||
| 138 | [ -n "$name" -a -f "$filename" ] || usage | ||
| 139 | |||
| 140 | EFIVARFS="/sys/firmware/efi/efivars" | ||
| 141 | |||
| 142 | [ -d "$EFIVARFS" ] || exit 2 | ||
| 143 | |||
| 144 | if stat -tf $EFIVARFS | grep -q -v de5e81e4; then | ||
| 145 | mount -t efivarfs none $EFIVARFS | ||
| 146 | fi | ||
| 147 | |||
| 148 | # try to pick up an existing GUID | ||
| 149 | [ -n "$guid" ] || guid=$(find "$EFIVARFS" -name "$name-*" | head -n1 | cut -f2- -d-) | ||
| 150 | |||
| 151 | # use a randomly generated GUID | ||
| 152 | [ -n "$guid" ] || guid="$(cat /proc/sys/kernel/random/uuid)" | ||
| 153 | |||
| 154 | # efivarfs expects all of the data in one write | ||
| 155 | tmp=$(mktemp) | ||
| 156 | /bin/echo -ne "\007\000\000\000" | cat - $filename > $tmp | ||
| 157 | dd if=$tmp of="$EFIVARFS/$name-$guid" bs=$(stat -c %s $tmp) | ||
| 158 | rm $tmp | ||
| 159 | |||
| 160 | == Loading ACPI SSDTs from configfs == | ||
| 161 | |||
| 162 | This option allows loading of user defined SSDTs from userspace via the configfs | ||
| 163 | interface. The CONFIG_ACPI_CONFIGFS option must be select and configfs must be | ||
| 164 | mounted. In the following examples, we assume that configfs has been mounted in | ||
| 165 | /config. | ||
| 166 | |||
| 167 | New tables can be loading by creating new directories in /config/acpi/table/ and | ||
| 168 | writing the SSDT aml code in the aml attribute: | ||
| 169 | |||
| 170 | cd /config/acpi/table | ||
| 171 | mkdir my_ssdt | ||
| 172 | cat ~/ssdt.aml > my_ssdt/aml | ||
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 118538b548f6..769db8399ac8 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -582,6 +582,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 582 | 582 | ||
| 583 | bootmem_debug [KNL] Enable bootmem allocator debug messages. | 583 | bootmem_debug [KNL] Enable bootmem allocator debug messages. |
| 584 | 584 | ||
| 585 | bert_disable [ACPI] | ||
| 586 | Disable BERT OS support on buggy BIOSes. | ||
| 587 | |||
| 585 | bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) | 588 | bttv.card= [HW,V4L] bttv (bt848 + bt878 based grabber cards) |
| 586 | bttv.radio= Most important insmod options are available as | 589 | bttv.radio= Most important insmod options are available as |
| 587 | kernel args too. | 590 | kernel args too. |
| @@ -1193,6 +1196,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 1193 | Address Range Mirroring feature even if your box | 1196 | Address Range Mirroring feature even if your box |
| 1194 | doesn't support it. | 1197 | doesn't support it. |
| 1195 | 1198 | ||
| 1199 | efivar_ssdt= [EFI; X86] Name of an EFI variable that contains an SSDT | ||
| 1200 | that is to be dynamically loaded by Linux. If there are | ||
| 1201 | multiple variables with the same name but with different | ||
| 1202 | vendor GUIDs, all of them will be loaded. See | ||
| 1203 | Documentation/acpi/ssdt-overlays.txt for details. | ||
| 1204 | |||
| 1205 | |||
| 1196 | eisa_irq_edge= [PARISC,HW] | 1206 | eisa_irq_edge= [PARISC,HW] |
| 1197 | See header of drivers/parisc/eisa.c. | 1207 | See header of drivers/parisc/eisa.c. |
| 1198 | 1208 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 4e1e4e94a83a..3eaa4a06bcc1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -288,6 +288,7 @@ F: include/linux/acpi.h | |||
| 288 | F: include/acpi/ | 288 | F: include/acpi/ |
| 289 | F: Documentation/acpi/ | 289 | F: Documentation/acpi/ |
| 290 | F: Documentation/ABI/testing/sysfs-bus-acpi | 290 | F: Documentation/ABI/testing/sysfs-bus-acpi |
| 291 | F: Documentation/ABI/testing/configfs-acpi | ||
| 291 | F: drivers/pci/*acpi* | 292 | F: drivers/pci/*acpi* |
| 292 | F: drivers/pci/*/*acpi* | 293 | F: drivers/pci/*/*acpi* |
| 293 | F: drivers/pci/*/*/*acpi* | 294 | F: drivers/pci/*/*/*acpi* |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 5a0a691d4220..20d5a60530b1 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
| @@ -4,6 +4,7 @@ config ARM64 | |||
| 4 | select ACPI_GENERIC_GSI if ACPI | 4 | select ACPI_GENERIC_GSI if ACPI |
| 5 | select ACPI_REDUCED_HARDWARE_ONLY if ACPI | 5 | select ACPI_REDUCED_HARDWARE_ONLY if ACPI |
| 6 | select ARCH_HAS_DEVMEM_IS_ALLOWED | 6 | select ARCH_HAS_DEVMEM_IS_ALLOWED |
| 7 | select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI | ||
| 7 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 8 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
| 8 | select ARCH_HAS_ELF_RANDOMIZE | 9 | select ARCH_HAS_ELF_RANDOMIZE |
| 9 | select ARCH_HAS_GCOV_PROFILE_ALL | 10 | select ARCH_HAS_GCOV_PROFILE_ALL |
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index aee323b13802..5420cb0fcb3e 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h | |||
| @@ -113,4 +113,14 @@ static inline const char *acpi_get_enable_method(int cpu) | |||
| 113 | pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr); | 113 | pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr); |
| 114 | #endif | 114 | #endif |
| 115 | 115 | ||
| 116 | #ifdef CONFIG_ACPI_NUMA | ||
| 117 | int arm64_acpi_numa_init(void); | ||
| 118 | int acpi_numa_get_nid(unsigned int cpu, u64 hwid); | ||
| 119 | #else | ||
| 120 | static inline int arm64_acpi_numa_init(void) { return -ENOSYS; } | ||
| 121 | static inline int acpi_numa_get_nid(unsigned int cpu, u64 hwid) { return NUMA_NO_NODE; } | ||
| 122 | #endif /* CONFIG_ACPI_NUMA */ | ||
| 123 | |||
| 124 | #define ACPI_TABLE_UPGRADE_MAX_PHYS MEMBLOCK_ALLOC_ACCESSIBLE | ||
| 125 | |||
| 116 | #endif /*_ASM_ACPI_H*/ | 126 | #endif /*_ASM_ACPI_H*/ |
diff --git a/arch/arm64/include/asm/numa.h b/arch/arm64/include/asm/numa.h index e9b4f2942335..600887e491fd 100644 --- a/arch/arm64/include/asm/numa.h +++ b/arch/arm64/include/asm/numa.h | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | 5 | ||
| 6 | #ifdef CONFIG_NUMA | 6 | #ifdef CONFIG_NUMA |
| 7 | 7 | ||
| 8 | #define NR_NODE_MEMBLKS (MAX_NUMNODES * 2) | ||
| 9 | |||
| 8 | /* currently, arm64 implements flat NUMA topology */ | 10 | /* currently, arm64 implements flat NUMA topology */ |
| 9 | #define parent_node(node) (node) | 11 | #define parent_node(node) (node) |
| 10 | 12 | ||
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 2173149d8954..a5125c6d1f87 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile | |||
| @@ -42,6 +42,7 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o | |||
| 42 | arm64-obj-$(CONFIG_PCI) += pci.o | 42 | arm64-obj-$(CONFIG_PCI) += pci.o |
| 43 | arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o | 43 | arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o |
| 44 | arm64-obj-$(CONFIG_ACPI) += acpi.o | 44 | arm64-obj-$(CONFIG_ACPI) += acpi.o |
| 45 | arm64-obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o | ||
| 45 | arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL) += acpi_parking_protocol.o | 46 | arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL) += acpi_parking_protocol.o |
| 46 | arm64-obj-$(CONFIG_PARAVIRT) += paravirt.o | 47 | arm64-obj-$(CONFIG_PARAVIRT) += paravirt.o |
| 47 | arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o | 48 | arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o |
diff --git a/arch/arm64/kernel/acpi_numa.c b/arch/arm64/kernel/acpi_numa.c new file mode 100644 index 000000000000..f85149cc7c71 --- /dev/null +++ b/arch/arm64/kernel/acpi_numa.c | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | /* | ||
| 2 | * ACPI 5.1 based NUMA setup for ARM64 | ||
| 3 | * Lots of code was borrowed from arch/x86/mm/srat.c | ||
| 4 | * | ||
| 5 | * Copyright 2004 Andi Kleen, SuSE Labs. | ||
| 6 | * Copyright (C) 2013-2016, Linaro Ltd. | ||
| 7 | * Author: Hanjun Guo <hanjun.guo@linaro.org> | ||
| 8 | * | ||
| 9 | * Reads the ACPI SRAT table to figure out what memory belongs to which CPUs. | ||
| 10 | * | ||
| 11 | * Called from acpi_numa_init while reading the SRAT and SLIT tables. | ||
| 12 | * Assumes all memory regions belonging to a single proximity domain | ||
| 13 | * are in one chunk. Holes between them will be included in the node. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #define pr_fmt(fmt) "ACPI: NUMA: " fmt | ||
| 17 | |||
| 18 | #include <linux/acpi.h> | ||
| 19 | #include <linux/bitmap.h> | ||
| 20 | #include <linux/bootmem.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/mm.h> | ||
| 23 | #include <linux/memblock.h> | ||
| 24 | #include <linux/mmzone.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/topology.h> | ||
| 27 | |||
| 28 | #include <acpi/processor.h> | ||
| 29 | #include <asm/numa.h> | ||
| 30 | |||
| 31 | static int cpus_in_srat; | ||
| 32 | |||
| 33 | struct __node_cpu_hwid { | ||
| 34 | u32 node_id; /* logical node containing this CPU */ | ||
| 35 | u64 cpu_hwid; /* MPIDR for this CPU */ | ||
| 36 | }; | ||
| 37 | |||
| 38 | static struct __node_cpu_hwid early_node_cpu_hwid[NR_CPUS] = { | ||
| 39 | [0 ... NR_CPUS - 1] = {NUMA_NO_NODE, PHYS_CPUID_INVALID} }; | ||
| 40 | |||
| 41 | int acpi_numa_get_nid(unsigned int cpu, u64 hwid) | ||
| 42 | { | ||
| 43 | int i; | ||
| 44 | |||
| 45 | for (i = 0; i < cpus_in_srat; i++) { | ||
| 46 | if (hwid == early_node_cpu_hwid[i].cpu_hwid) | ||
| 47 | return early_node_cpu_hwid[i].node_id; | ||
| 48 | } | ||
| 49 | |||
| 50 | return NUMA_NO_NODE; | ||
| 51 | } | ||
| 52 | |||
| 53 | /* Callback for Proximity Domain -> ACPI processor UID mapping */ | ||
| 54 | void __init acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa) | ||
| 55 | { | ||
| 56 | int pxm, node; | ||
| 57 | phys_cpuid_t mpidr; | ||
| 58 | |||
| 59 | if (srat_disabled()) | ||
| 60 | return; | ||
| 61 | |||
| 62 | if (pa->header.length < sizeof(struct acpi_srat_gicc_affinity)) { | ||
| 63 | pr_err("SRAT: Invalid SRAT header length: %d\n", | ||
| 64 | pa->header.length); | ||
| 65 | bad_srat(); | ||
| 66 | return; | ||
| 67 | } | ||
| 68 | |||
| 69 | if (!(pa->flags & ACPI_SRAT_GICC_ENABLED)) | ||
| 70 | return; | ||
| 71 | |||
| 72 | if (cpus_in_srat >= NR_CPUS) { | ||
| 73 | pr_warn_once("SRAT: cpu_to_node_map[%d] is too small, may not be able to use all cpus\n", | ||
| 74 | NR_CPUS); | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | |||
| 78 | pxm = pa->proximity_domain; | ||
| 79 | node = acpi_map_pxm_to_node(pxm); | ||
| 80 | |||
| 81 | if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) { | ||
| 82 | pr_err("SRAT: Too many proximity domains %d\n", pxm); | ||
| 83 | bad_srat(); | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 87 | mpidr = acpi_map_madt_entry(pa->acpi_processor_uid); | ||
| 88 | if (mpidr == PHYS_CPUID_INVALID) { | ||
| 89 | pr_err("SRAT: PXM %d with ACPI ID %d has no valid MPIDR in MADT\n", | ||
| 90 | pxm, pa->acpi_processor_uid); | ||
| 91 | bad_srat(); | ||
| 92 | return; | ||
| 93 | } | ||
| 94 | |||
| 95 | early_node_cpu_hwid[cpus_in_srat].node_id = node; | ||
| 96 | early_node_cpu_hwid[cpus_in_srat].cpu_hwid = mpidr; | ||
| 97 | node_set(node, numa_nodes_parsed); | ||
| 98 | cpus_in_srat++; | ||
| 99 | pr_info("SRAT: PXM %d -> MPIDR 0x%Lx -> Node %d\n", | ||
| 100 | pxm, mpidr, node); | ||
| 101 | } | ||
| 102 | |||
| 103 | int __init arm64_acpi_numa_init(void) | ||
| 104 | { | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | ret = acpi_numa_init(); | ||
| 108 | if (ret) | ||
| 109 | return ret; | ||
| 110 | |||
| 111 | return srat_disabled() ? -EINVAL : 0; | ||
| 112 | } | ||
diff --git a/arch/arm64/kernel/cpuidle.c b/arch/arm64/kernel/cpuidle.c index e11857fce05f..75a0f8acef66 100644 --- a/arch/arm64/kernel/cpuidle.c +++ b/arch/arm64/kernel/cpuidle.c | |||
| @@ -9,13 +9,16 @@ | |||
| 9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #include <linux/acpi.h> | ||
| 13 | #include <linux/cpuidle.h> | ||
| 14 | #include <linux/cpu_pm.h> | ||
| 12 | #include <linux/of.h> | 15 | #include <linux/of.h> |
| 13 | #include <linux/of_device.h> | 16 | #include <linux/of_device.h> |
| 14 | 17 | ||
| 15 | #include <asm/cpuidle.h> | 18 | #include <asm/cpuidle.h> |
| 16 | #include <asm/cpu_ops.h> | 19 | #include <asm/cpu_ops.h> |
| 17 | 20 | ||
| 18 | int __init arm_cpuidle_init(unsigned int cpu) | 21 | int arm_cpuidle_init(unsigned int cpu) |
| 19 | { | 22 | { |
| 20 | int ret = -EOPNOTSUPP; | 23 | int ret = -EOPNOTSUPP; |
| 21 | 24 | ||
| @@ -39,3 +42,18 @@ int arm_cpuidle_suspend(int index) | |||
| 39 | 42 | ||
| 40 | return cpu_ops[cpu]->cpu_suspend(index); | 43 | return cpu_ops[cpu]->cpu_suspend(index); |
| 41 | } | 44 | } |
| 45 | |||
| 46 | #ifdef CONFIG_ACPI | ||
| 47 | |||
| 48 | #include <acpi/processor.h> | ||
| 49 | |||
| 50 | int acpi_processor_ffh_lpi_probe(unsigned int cpu) | ||
| 51 | { | ||
| 52 | return arm_cpuidle_init(cpu); | ||
| 53 | } | ||
| 54 | |||
| 55 | int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi) | ||
| 56 | { | ||
| 57 | return CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, lpi->index); | ||
| 58 | } | ||
| 59 | #endif | ||
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 3279defabaa2..92f0e1e767cf 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c | |||
| @@ -260,11 +260,13 @@ void __init setup_arch(char **cmdline_p) | |||
| 260 | efi_init(); | 260 | efi_init(); |
| 261 | arm64_memblock_init(); | 261 | arm64_memblock_init(); |
| 262 | 262 | ||
| 263 | paging_init(); | ||
| 264 | |||
| 265 | acpi_table_upgrade(); | ||
| 266 | |||
| 263 | /* Parse the ACPI tables for possible boot-time configuration */ | 267 | /* Parse the ACPI tables for possible boot-time configuration */ |
| 264 | acpi_boot_table_init(); | 268 | acpi_boot_table_init(); |
| 265 | 269 | ||
| 266 | paging_init(); | ||
| 267 | |||
| 268 | if (acpi_disabled) | 270 | if (acpi_disabled) |
| 269 | unflatten_device_tree(); | 271 | unflatten_device_tree(); |
| 270 | 272 | ||
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 62ff3c0622e2..a68e0ccd9f4b 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c | |||
| @@ -560,6 +560,8 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) | |||
| 560 | */ | 560 | */ |
| 561 | acpi_set_mailbox_entry(cpu_count, processor); | 561 | acpi_set_mailbox_entry(cpu_count, processor); |
| 562 | 562 | ||
| 563 | early_map_cpu_to_node(cpu_count, acpi_numa_get_nid(cpu_count, hwid)); | ||
| 564 | |||
| 563 | cpu_count++; | 565 | cpu_count++; |
| 564 | } | 566 | } |
| 565 | 567 | ||
diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c index 98dc1047f2a2..c7fe3ec70774 100644 --- a/arch/arm64/mm/numa.c +++ b/arch/arm64/mm/numa.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/acpi.h> | ||
| 20 | #include <linux/bootmem.h> | 21 | #include <linux/bootmem.h> |
| 21 | #include <linux/memblock.h> | 22 | #include <linux/memblock.h> |
| 22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| @@ -29,7 +30,7 @@ static int cpu_to_node_map[NR_CPUS] = { [0 ... NR_CPUS-1] = NUMA_NO_NODE }; | |||
| 29 | 30 | ||
| 30 | static int numa_distance_cnt; | 31 | static int numa_distance_cnt; |
| 31 | static u8 *numa_distance; | 32 | static u8 *numa_distance; |
| 32 | static int numa_off; | 33 | static bool numa_off; |
| 33 | 34 | ||
| 34 | static __init int numa_parse_early_param(char *opt) | 35 | static __init int numa_parse_early_param(char *opt) |
| 35 | { | 36 | { |
| @@ -37,7 +38,7 @@ static __init int numa_parse_early_param(char *opt) | |||
| 37 | return -EINVAL; | 38 | return -EINVAL; |
| 38 | if (!strncmp(opt, "off", 3)) { | 39 | if (!strncmp(opt, "off", 3)) { |
| 39 | pr_info("%s\n", "NUMA turned off"); | 40 | pr_info("%s\n", "NUMA turned off"); |
| 40 | numa_off = 1; | 41 | numa_off = true; |
| 41 | } | 42 | } |
| 42 | return 0; | 43 | return 0; |
| 43 | } | 44 | } |
| @@ -131,25 +132,25 @@ void __init early_map_cpu_to_node(unsigned int cpu, int nid) | |||
| 131 | * numa_add_memblk - Set node id to memblk | 132 | * numa_add_memblk - Set node id to memblk |
| 132 | * @nid: NUMA node ID of the new memblk | 133 | * @nid: NUMA node ID of the new memblk |
| 133 | * @start: Start address of the new memblk | 134 | * @start: Start address of the new memblk |
| 134 | * @size: Size of the new memblk | 135 | * @end: End address of the new memblk |
| 135 | * | 136 | * |
| 136 | * RETURNS: | 137 | * RETURNS: |
| 137 | * 0 on success, -errno on failure. | 138 | * 0 on success, -errno on failure. |
| 138 | */ | 139 | */ |
| 139 | int __init numa_add_memblk(int nid, u64 start, u64 size) | 140 | int __init numa_add_memblk(int nid, u64 start, u64 end) |
| 140 | { | 141 | { |
| 141 | int ret; | 142 | int ret; |
| 142 | 143 | ||
| 143 | ret = memblock_set_node(start, size, &memblock.memory, nid); | 144 | ret = memblock_set_node(start, (end - start), &memblock.memory, nid); |
| 144 | if (ret < 0) { | 145 | if (ret < 0) { |
| 145 | pr_err("NUMA: memblock [0x%llx - 0x%llx] failed to add on node %d\n", | 146 | pr_err("NUMA: memblock [0x%llx - 0x%llx] failed to add on node %d\n", |
| 146 | start, (start + size - 1), nid); | 147 | start, (end - 1), nid); |
| 147 | return ret; | 148 | return ret; |
| 148 | } | 149 | } |
| 149 | 150 | ||
| 150 | node_set(nid, numa_nodes_parsed); | 151 | node_set(nid, numa_nodes_parsed); |
| 151 | pr_info("NUMA: Adding memblock [0x%llx - 0x%llx] on node %d\n", | 152 | pr_info("NUMA: Adding memblock [0x%llx - 0x%llx] on node %d\n", |
| 152 | start, (start + size - 1), nid); | 153 | start, (end - 1), nid); |
| 153 | return ret; | 154 | return ret; |
| 154 | } | 155 | } |
| 155 | 156 | ||
| @@ -362,12 +363,15 @@ static int __init dummy_numa_init(void) | |||
| 362 | int ret; | 363 | int ret; |
| 363 | struct memblock_region *mblk; | 364 | struct memblock_region *mblk; |
| 364 | 365 | ||
| 365 | pr_info("%s\n", "No NUMA configuration found"); | 366 | if (numa_off) |
| 367 | pr_info("NUMA disabled\n"); /* Forced off on command line. */ | ||
| 368 | else | ||
| 369 | pr_info("No NUMA configuration found\n"); | ||
| 366 | pr_info("NUMA: Faking a node at [mem %#018Lx-%#018Lx]\n", | 370 | pr_info("NUMA: Faking a node at [mem %#018Lx-%#018Lx]\n", |
| 367 | 0LLU, PFN_PHYS(max_pfn) - 1); | 371 | 0LLU, PFN_PHYS(max_pfn) - 1); |
| 368 | 372 | ||
| 369 | for_each_memblock(memory, mblk) { | 373 | for_each_memblock(memory, mblk) { |
| 370 | ret = numa_add_memblk(0, mblk->base, mblk->size); | 374 | ret = numa_add_memblk(0, mblk->base, mblk->base + mblk->size); |
| 371 | if (!ret) | 375 | if (!ret) |
| 372 | continue; | 376 | continue; |
| 373 | 377 | ||
| @@ -375,7 +379,7 @@ static int __init dummy_numa_init(void) | |||
| 375 | return ret; | 379 | return ret; |
| 376 | } | 380 | } |
| 377 | 381 | ||
| 378 | numa_off = 1; | 382 | numa_off = true; |
| 379 | return 0; | 383 | return 0; |
| 380 | } | 384 | } |
| 381 | 385 | ||
| @@ -388,7 +392,9 @@ static int __init dummy_numa_init(void) | |||
| 388 | void __init arm64_numa_init(void) | 392 | void __init arm64_numa_init(void) |
| 389 | { | 393 | { |
| 390 | if (!numa_off) { | 394 | if (!numa_off) { |
| 391 | if (!numa_init(of_numa_init)) | 395 | if (!acpi_disabled && !numa_init(arm64_acpi_numa_init)) |
| 396 | return; | ||
| 397 | if (acpi_disabled && !numa_init(of_numa_init)) | ||
| 392 | return; | 398 | return; |
| 393 | } | 399 | } |
| 394 | 400 | ||
diff --git a/arch/ia64/include/asm/acpi.h b/arch/ia64/include/asm/acpi.h index aa0fdf125aba..a3d0211970e9 100644 --- a/arch/ia64/include/asm/acpi.h +++ b/arch/ia64/include/asm/acpi.h | |||
| @@ -140,6 +140,9 @@ static inline void per_cpu_scan_finalize(int min_cpus, int reserve_cpus) | |||
| 140 | } | 140 | } |
| 141 | } | 141 | } |
| 142 | } | 142 | } |
| 143 | |||
| 144 | extern void acpi_numa_fixup(void); | ||
| 145 | |||
| 143 | #endif /* CONFIG_ACPI_NUMA */ | 146 | #endif /* CONFIG_ACPI_NUMA */ |
| 144 | 147 | ||
| 145 | #endif /*__KERNEL__*/ | 148 | #endif /*__KERNEL__*/ |
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index b1698bc042c8..92b7bc956795 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c | |||
| @@ -524,7 +524,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) | |||
| 524 | return 0; | 524 | return 0; |
| 525 | } | 525 | } |
| 526 | 526 | ||
| 527 | void __init acpi_numa_arch_fixup(void) | 527 | void __init acpi_numa_fixup(void) |
| 528 | { | 528 | { |
| 529 | int i, j, node_from, node_to; | 529 | int i, j, node_from, node_to; |
| 530 | 530 | ||
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 2029a38a72ae..afddb3e80a29 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c | |||
| @@ -552,6 +552,7 @@ setup_arch (char **cmdline_p) | |||
| 552 | early_acpi_boot_init(); | 552 | early_acpi_boot_init(); |
| 553 | # ifdef CONFIG_ACPI_NUMA | 553 | # ifdef CONFIG_ACPI_NUMA |
| 554 | acpi_numa_init(); | 554 | acpi_numa_init(); |
| 555 | acpi_numa_fixup(); | ||
| 555 | # ifdef CONFIG_ACPI_HOTPLUG_CPU | 556 | # ifdef CONFIG_ACPI_HOTPLUG_CPU |
| 556 | prefill_possible_map(); | 557 | prefill_possible_map(); |
| 557 | # endif | 558 | # endif |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5977fea2c8b1..2fa55851d2a9 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -22,6 +22,7 @@ config X86 | |||
| 22 | select ANON_INODES | 22 | select ANON_INODES |
| 23 | select ARCH_CLOCKSOURCE_DATA | 23 | select ARCH_CLOCKSOURCE_DATA |
| 24 | select ARCH_DISCARD_MEMBLOCK | 24 | select ARCH_DISCARD_MEMBLOCK |
| 25 | select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI | ||
| 25 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 26 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
| 26 | select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS | 27 | select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS |
| 27 | select ARCH_HAS_DEVMEM_IS_ALLOWED | 28 | select ARCH_HAS_DEVMEM_IS_ALLOWED |
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 94c18ebfd68c..5391b0ae7cc3 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h | |||
| @@ -145,7 +145,6 @@ static inline void disable_acpi(void) { } | |||
| 145 | #define ARCH_HAS_POWER_INIT 1 | 145 | #define ARCH_HAS_POWER_INIT 1 |
| 146 | 146 | ||
| 147 | #ifdef CONFIG_ACPI_NUMA | 147 | #ifdef CONFIG_ACPI_NUMA |
| 148 | extern int acpi_numa; | ||
| 149 | extern int x86_acpi_numa_init(void); | 148 | extern int x86_acpi_numa_init(void); |
| 150 | #endif /* CONFIG_ACPI_NUMA */ | 149 | #endif /* CONFIG_ACPI_NUMA */ |
| 151 | 150 | ||
| @@ -170,4 +169,6 @@ static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr) | |||
| 170 | } | 169 | } |
| 171 | #endif | 170 | #endif |
| 172 | 171 | ||
| 172 | #define ACPI_TABLE_UPGRADE_MAX_PHYS (max_low_pfn_mapped << PAGE_SHIFT) | ||
| 173 | |||
| 173 | #endif /* _ASM_X86_ACPI_H */ | 174 | #endif /* _ASM_X86_ACPI_H */ |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index a2616584b6e9..6cb2b02fcc87 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
| @@ -400,10 +400,6 @@ static void __init reserve_initrd(void) | |||
| 400 | memblock_free(ramdisk_image, ramdisk_end - ramdisk_image); | 400 | memblock_free(ramdisk_image, ramdisk_end - ramdisk_image); |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | static void __init early_initrd_acpi_init(void) | ||
| 404 | { | ||
| 405 | early_acpi_table_init((void *)initrd_start, initrd_end - initrd_start); | ||
| 406 | } | ||
| 407 | #else | 403 | #else |
| 408 | static void __init early_reserve_initrd(void) | 404 | static void __init early_reserve_initrd(void) |
| 409 | { | 405 | { |
| @@ -411,9 +407,6 @@ static void __init early_reserve_initrd(void) | |||
| 411 | static void __init reserve_initrd(void) | 407 | static void __init reserve_initrd(void) |
| 412 | { | 408 | { |
| 413 | } | 409 | } |
| 414 | static void __init early_initrd_acpi_init(void) | ||
| 415 | { | ||
| 416 | } | ||
| 417 | #endif /* CONFIG_BLK_DEV_INITRD */ | 410 | #endif /* CONFIG_BLK_DEV_INITRD */ |
| 418 | 411 | ||
| 419 | static void __init parse_setup_data(void) | 412 | static void __init parse_setup_data(void) |
| @@ -1149,7 +1142,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 1149 | 1142 | ||
| 1150 | reserve_initrd(); | 1143 | reserve_initrd(); |
| 1151 | 1144 | ||
| 1152 | early_initrd_acpi_init(); | 1145 | acpi_table_upgrade(); |
| 1153 | 1146 | ||
| 1154 | vsmp_init(); | 1147 | vsmp_init(); |
| 1155 | 1148 | ||
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 9c086c57105c..968ac028c34e 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | /* Common code for 32 and 64-bit NUMA */ | 1 | /* Common code for 32 and 64-bit NUMA */ |
| 2 | #include <linux/acpi.h> | ||
| 2 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
| 3 | #include <linux/mm.h> | 4 | #include <linux/mm.h> |
| 4 | #include <linux/string.h> | 5 | #include <linux/string.h> |
| @@ -15,7 +16,6 @@ | |||
| 15 | #include <asm/e820.h> | 16 | #include <asm/e820.h> |
| 16 | #include <asm/proto.h> | 17 | #include <asm/proto.h> |
| 17 | #include <asm/dma.h> | 18 | #include <asm/dma.h> |
| 18 | #include <asm/acpi.h> | ||
| 19 | #include <asm/amd_nb.h> | 19 | #include <asm/amd_nb.h> |
| 20 | 20 | ||
| 21 | #include "numa_internal.h" | 21 | #include "numa_internal.h" |
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index b5f821881465..b1ecff460a46 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c | |||
| @@ -15,8 +15,6 @@ | |||
| 15 | #include <linux/bitmap.h> | 15 | #include <linux/bitmap.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/topology.h> | 17 | #include <linux/topology.h> |
| 18 | #include <linux/bootmem.h> | ||
| 19 | #include <linux/memblock.h> | ||
| 20 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
| 21 | #include <asm/proto.h> | 19 | #include <asm/proto.h> |
| 22 | #include <asm/numa.h> | 20 | #include <asm/numa.h> |
| @@ -24,51 +22,6 @@ | |||
| 24 | #include <asm/apic.h> | 22 | #include <asm/apic.h> |
| 25 | #include <asm/uv/uv.h> | 23 | #include <asm/uv/uv.h> |
| 26 | 24 | ||
| 27 | int acpi_numa __initdata; | ||
| 28 | |||
| 29 | static __init int setup_node(int pxm) | ||
| 30 | { | ||
| 31 | return acpi_map_pxm_to_node(pxm); | ||
| 32 | } | ||
| 33 | |||
| 34 | static __init void bad_srat(void) | ||
| 35 | { | ||
| 36 | printk(KERN_ERR "SRAT: SRAT not used.\n"); | ||
| 37 | acpi_numa = -1; | ||
| 38 | } | ||
| 39 | |||
| 40 | static __init inline int srat_disabled(void) | ||
| 41 | { | ||
| 42 | return acpi_numa < 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | /* | ||
| 46 | * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for | ||
| 47 | * I/O localities since SRAT does not list them. I/O localities are | ||
| 48 | * not supported at this point. | ||
| 49 | */ | ||
| 50 | void __init acpi_numa_slit_init(struct acpi_table_slit *slit) | ||
| 51 | { | ||
| 52 | int i, j; | ||
| 53 | |||
| 54 | for (i = 0; i < slit->locality_count; i++) { | ||
| 55 | const int from_node = pxm_to_node(i); | ||
| 56 | |||
| 57 | if (from_node == NUMA_NO_NODE) | ||
| 58 | continue; | ||
| 59 | |||
| 60 | for (j = 0; j < slit->locality_count; j++) { | ||
| 61 | const int to_node = pxm_to_node(j); | ||
| 62 | |||
| 63 | if (to_node == NUMA_NO_NODE) | ||
| 64 | continue; | ||
| 65 | |||
| 66 | numa_set_distance(from_node, to_node, | ||
| 67 | slit->entry[slit->locality_count * i + j]); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | /* Callback for Proximity Domain -> x2APIC mapping */ | 25 | /* Callback for Proximity Domain -> x2APIC mapping */ |
| 73 | void __init | 26 | void __init |
| 74 | acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) | 27 | acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) |
| @@ -91,7 +44,7 @@ acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) | |||
| 91 | pxm, apic_id); | 44 | pxm, apic_id); |
| 92 | return; | 45 | return; |
| 93 | } | 46 | } |
| 94 | node = setup_node(pxm); | 47 | node = acpi_map_pxm_to_node(pxm); |
| 95 | if (node < 0) { | 48 | if (node < 0) { |
| 96 | printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); | 49 | printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); |
| 97 | bad_srat(); | 50 | bad_srat(); |
| @@ -104,7 +57,6 @@ acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) | |||
| 104 | } | 57 | } |
| 105 | set_apicid_to_node(apic_id, node); | 58 | set_apicid_to_node(apic_id, node); |
| 106 | node_set(node, numa_nodes_parsed); | 59 | node_set(node, numa_nodes_parsed); |
| 107 | acpi_numa = 1; | ||
| 108 | printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", | 60 | printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", |
| 109 | pxm, apic_id, node); | 61 | pxm, apic_id, node); |
| 110 | } | 62 | } |
| @@ -127,7 +79,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) | |||
| 127 | pxm = pa->proximity_domain_lo; | 79 | pxm = pa->proximity_domain_lo; |
| 128 | if (acpi_srat_revision >= 2) | 80 | if (acpi_srat_revision >= 2) |
| 129 | pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; | 81 | pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; |
| 130 | node = setup_node(pxm); | 82 | node = acpi_map_pxm_to_node(pxm); |
| 131 | if (node < 0) { | 83 | if (node < 0) { |
| 132 | printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); | 84 | printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); |
| 133 | bad_srat(); | 85 | bad_srat(); |
| @@ -146,74 +98,10 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) | |||
| 146 | 98 | ||
| 147 | set_apicid_to_node(apic_id, node); | 99 | set_apicid_to_node(apic_id, node); |
| 148 | node_set(node, numa_nodes_parsed); | 100 | node_set(node, numa_nodes_parsed); |
| 149 | acpi_numa = 1; | ||
| 150 | printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", | 101 | printk(KERN_INFO "SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", |
| 151 | pxm, apic_id, node); | 102 | pxm, apic_id, node); |
| 152 | } | 103 | } |
| 153 | 104 | ||
| 154 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
| 155 | static inline int save_add_info(void) {return 1;} | ||
| 156 | #else | ||
| 157 | static inline int save_add_info(void) {return 0;} | ||
| 158 | #endif | ||
| 159 | |||
| 160 | /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ | ||
| 161 | int __init | ||
| 162 | acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) | ||
| 163 | { | ||
| 164 | u64 start, end; | ||
| 165 | u32 hotpluggable; | ||
| 166 | int node, pxm; | ||
| 167 | |||
| 168 | if (srat_disabled()) | ||
| 169 | goto out_err; | ||
| 170 | if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) | ||
| 171 | goto out_err_bad_srat; | ||
| 172 | if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) | ||
| 173 | goto out_err; | ||
| 174 | hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE; | ||
| 175 | if (hotpluggable && !save_add_info()) | ||
| 176 | goto out_err; | ||
| 177 | |||
| 178 | start = ma->base_address; | ||
| 179 | end = start + ma->length; | ||
| 180 | pxm = ma->proximity_domain; | ||
| 181 | if (acpi_srat_revision <= 1) | ||
| 182 | pxm &= 0xff; | ||
| 183 | |||
| 184 | node = setup_node(pxm); | ||
| 185 | if (node < 0) { | ||
| 186 | printk(KERN_ERR "SRAT: Too many proximity domains.\n"); | ||
| 187 | goto out_err_bad_srat; | ||
| 188 | } | ||
| 189 | |||
| 190 | if (numa_add_memblk(node, start, end) < 0) | ||
| 191 | goto out_err_bad_srat; | ||
| 192 | |||
| 193 | node_set(node, numa_nodes_parsed); | ||
| 194 | |||
| 195 | pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n", | ||
| 196 | node, pxm, | ||
| 197 | (unsigned long long) start, (unsigned long long) end - 1, | ||
| 198 | hotpluggable ? " hotplug" : "", | ||
| 199 | ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : ""); | ||
| 200 | |||
| 201 | /* Mark hotplug range in memblock. */ | ||
| 202 | if (hotpluggable && memblock_mark_hotplug(start, ma->length)) | ||
| 203 | pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n", | ||
| 204 | (unsigned long long)start, (unsigned long long)end - 1); | ||
| 205 | |||
| 206 | max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1)); | ||
| 207 | |||
| 208 | return 0; | ||
| 209 | out_err_bad_srat: | ||
| 210 | bad_srat(); | ||
| 211 | out_err: | ||
| 212 | return -1; | ||
| 213 | } | ||
| 214 | |||
| 215 | void __init acpi_numa_arch_fixup(void) {} | ||
| 216 | |||
| 217 | int __init x86_acpi_numa_init(void) | 105 | int __init x86_acpi_numa_init(void) |
| 218 | { | 106 | { |
| 219 | int ret; | 107 | int ret; |
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index b7e2e776397d..acad70a0bb0d 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
| @@ -213,6 +213,10 @@ config ACPI_CPU_FREQ_PSS | |||
| 213 | bool | 213 | bool |
| 214 | select THERMAL | 214 | select THERMAL |
| 215 | 215 | ||
| 216 | config ACPI_PROCESSOR_CSTATE | ||
| 217 | def_bool y | ||
| 218 | depends on IA64 || X86 | ||
| 219 | |||
| 216 | config ACPI_PROCESSOR_IDLE | 220 | config ACPI_PROCESSOR_IDLE |
| 217 | bool | 221 | bool |
| 218 | select CPU_IDLE | 222 | select CPU_IDLE |
| @@ -234,7 +238,7 @@ config ACPI_CPPC_LIB | |||
| 234 | config ACPI_PROCESSOR | 238 | config ACPI_PROCESSOR |
| 235 | tristate "Processor" | 239 | tristate "Processor" |
| 236 | depends on X86 || IA64 || ARM64 | 240 | depends on X86 || IA64 || ARM64 |
| 237 | select ACPI_PROCESSOR_IDLE if X86 || IA64 | 241 | select ACPI_PROCESSOR_IDLE |
| 238 | select ACPI_CPU_FREQ_PSS if X86 || IA64 | 242 | select ACPI_CPU_FREQ_PSS if X86 || IA64 |
| 239 | default y | 243 | default y |
| 240 | help | 244 | help |
| @@ -291,8 +295,8 @@ config ACPI_THERMAL | |||
| 291 | config ACPI_NUMA | 295 | config ACPI_NUMA |
| 292 | bool "NUMA support" | 296 | bool "NUMA support" |
| 293 | depends on NUMA | 297 | depends on NUMA |
| 294 | depends on (X86 || IA64) | 298 | depends on (X86 || IA64 || ARM64) |
| 295 | default y if IA64_GENERIC || IA64_SGI_SN2 | 299 | default y if IA64_GENERIC || IA64_SGI_SN2 || ARM64 |
| 296 | 300 | ||
| 297 | config ACPI_CUSTOM_DSDT_FILE | 301 | config ACPI_CUSTOM_DSDT_FILE |
| 298 | string "Custom DSDT Table file to include" | 302 | string "Custom DSDT Table file to include" |
| @@ -311,9 +315,12 @@ config ACPI_CUSTOM_DSDT | |||
| 311 | bool | 315 | bool |
| 312 | default ACPI_CUSTOM_DSDT_FILE != "" | 316 | default ACPI_CUSTOM_DSDT_FILE != "" |
| 313 | 317 | ||
| 318 | config ARCH_HAS_ACPI_TABLE_UPGRADE | ||
| 319 | def_bool n | ||
| 320 | |||
| 314 | config ACPI_TABLE_UPGRADE | 321 | config ACPI_TABLE_UPGRADE |
| 315 | bool "Allow upgrading ACPI tables via initrd" | 322 | bool "Allow upgrading ACPI tables via initrd" |
| 316 | depends on BLK_DEV_INITRD && X86 | 323 | depends on BLK_DEV_INITRD && ARCH_HAS_ACPI_TABLE_UPGRADE |
| 317 | default y | 324 | default y |
| 318 | help | 325 | help |
| 319 | This option provides functionality to upgrade arbitrary ACPI tables | 326 | This option provides functionality to upgrade arbitrary ACPI tables |
| @@ -475,6 +482,7 @@ config ACPI_NFIT_DEBUG | |||
| 475 | issue. | 482 | issue. |
| 476 | 483 | ||
| 477 | source "drivers/acpi/apei/Kconfig" | 484 | source "drivers/acpi/apei/Kconfig" |
| 485 | source "drivers/acpi/dptf/Kconfig" | ||
| 478 | 486 | ||
| 479 | config ACPI_EXTLOG | 487 | config ACPI_EXTLOG |
| 480 | tristate "Extended Error Log support" | 488 | tristate "Extended Error Log support" |
| @@ -519,6 +527,20 @@ config XPOWER_PMIC_OPREGION | |||
| 519 | help | 527 | help |
| 520 | This config adds ACPI operation region support for XPower AXP288 PMIC. | 528 | This config adds ACPI operation region support for XPower AXP288 PMIC. |
| 521 | 529 | ||
| 530 | config BXT_WC_PMIC_OPREGION | ||
| 531 | bool "ACPI operation region support for BXT WhiskeyCove PMIC" | ||
| 532 | depends on INTEL_SOC_PMIC | ||
| 533 | help | ||
| 534 | This config adds ACPI operation region support for BXT WhiskeyCove PMIC. | ||
| 535 | |||
| 522 | endif | 536 | endif |
| 523 | 537 | ||
| 538 | config ACPI_CONFIGFS | ||
| 539 | tristate "ACPI configfs support" | ||
| 540 | select CONFIGFS_FS | ||
| 541 | help | ||
| 542 | Select this option to enable support for ACPI configuration from | ||
| 543 | userspace. The configurable ACPI groups will be visible under | ||
| 544 | /config/acpi, assuming configfs is mounted under /config. | ||
| 545 | |||
| 524 | endif # ACPI | 546 | endif # ACPI |
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 251ce85a66fb..88f54f03e3d2 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
| @@ -44,7 +44,6 @@ acpi-y += acpi_lpss.o acpi_apd.o | |||
| 44 | acpi-y += acpi_platform.o | 44 | acpi-y += acpi_platform.o |
| 45 | acpi-y += acpi_pnp.o | 45 | acpi-y += acpi_pnp.o |
| 46 | acpi-$(CONFIG_ARM_AMBA) += acpi_amba.o | 46 | acpi-$(CONFIG_ARM_AMBA) += acpi_amba.o |
| 47 | acpi-y += int340x_thermal.o | ||
| 48 | acpi-y += power.o | 47 | acpi-y += power.o |
| 49 | acpi-y += event.o | 48 | acpi-y += event.o |
| 50 | acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o | 49 | acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o |
| @@ -99,5 +98,9 @@ obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o | |||
| 99 | obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.o | 98 | obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.o |
| 100 | obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o | 99 | obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o |
| 101 | obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o | 100 | obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o |
| 101 | obj-$(CONFIG_BXT_WC_PMIC_OPREGION) += pmic/intel_pmic_bxtwc.o | ||
| 102 | |||
| 103 | obj-$(CONFIG_ACPI_CONFIGFS) += acpi_configfs.o | ||
| 102 | 104 | ||
| 103 | video-objs += acpi_video.o video_detect.o | 105 | video-objs += acpi_video.o video_detect.o |
| 106 | obj-y += dptf/ | ||
diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c new file mode 100644 index 000000000000..146a77fb762d --- /dev/null +++ b/drivers/acpi/acpi_configfs.c | |||
| @@ -0,0 +1,267 @@ | |||
| 1 | /* | ||
| 2 | * ACPI configfs support | ||
| 3 | * | ||
| 4 | * Copyright (c) 2016 Intel Corporation | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published by | ||
| 8 | * the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #define pr_fmt(fmt) "ACPI configfs: " fmt | ||
| 12 | |||
| 13 | #include <linux/init.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/configfs.h> | ||
| 16 | #include <linux/acpi.h> | ||
| 17 | |||
| 18 | static struct config_group *acpi_table_group; | ||
| 19 | |||
| 20 | struct acpi_table { | ||
| 21 | struct config_item cfg; | ||
| 22 | struct acpi_table_header *header; | ||
| 23 | }; | ||
| 24 | |||
| 25 | static ssize_t acpi_table_aml_write(struct config_item *cfg, | ||
| 26 | const void *data, size_t size) | ||
| 27 | { | ||
| 28 | const struct acpi_table_header *header = data; | ||
| 29 | struct acpi_table *table; | ||
| 30 | int ret; | ||
| 31 | |||
| 32 | table = container_of(cfg, struct acpi_table, cfg); | ||
| 33 | |||
| 34 | if (table->header) { | ||
| 35 | pr_err("table already loaded\n"); | ||
| 36 | return -EBUSY; | ||
| 37 | } | ||
| 38 | |||
| 39 | if (header->length != size) { | ||
| 40 | pr_err("invalid table length\n"); | ||
| 41 | return -EINVAL; | ||
| 42 | } | ||
| 43 | |||
| 44 | if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) { | ||
| 45 | pr_err("invalid table signature\n"); | ||
| 46 | return -EINVAL; | ||
| 47 | } | ||
| 48 | |||
| 49 | table = container_of(cfg, struct acpi_table, cfg); | ||
| 50 | |||
| 51 | table->header = kmemdup(header, header->length, GFP_KERNEL); | ||
| 52 | if (!table->header) | ||
| 53 | return -ENOMEM; | ||
| 54 | |||
| 55 | ret = acpi_load_table(table->header); | ||
| 56 | if (ret) { | ||
| 57 | kfree(table->header); | ||
| 58 | table->header = NULL; | ||
| 59 | } | ||
| 60 | |||
| 61 | return ret; | ||
| 62 | } | ||
| 63 | |||
| 64 | static inline struct acpi_table_header *get_header(struct config_item *cfg) | ||
| 65 | { | ||
| 66 | struct acpi_table *table = container_of(cfg, struct acpi_table, cfg); | ||
| 67 | |||
| 68 | if (!table->header) | ||
| 69 | pr_err("table not loaded\n"); | ||
| 70 | |||
| 71 | return table->header; | ||
| 72 | } | ||
| 73 | |||
| 74 | static ssize_t acpi_table_aml_read(struct config_item *cfg, | ||
| 75 | void *data, size_t size) | ||
| 76 | { | ||
| 77 | struct acpi_table_header *h = get_header(cfg); | ||
| 78 | |||
| 79 | if (!h) | ||
| 80 | return -EINVAL; | ||
| 81 | |||
| 82 | if (data) | ||
| 83 | memcpy(data, h, h->length); | ||
| 84 | |||
| 85 | return h->length; | ||
| 86 | } | ||
| 87 | |||
| 88 | #define MAX_ACPI_TABLE_SIZE (128 * 1024) | ||
| 89 | |||
| 90 | CONFIGFS_BIN_ATTR(acpi_table_, aml, NULL, MAX_ACPI_TABLE_SIZE); | ||
| 91 | |||
| 92 | struct configfs_bin_attribute *acpi_table_bin_attrs[] = { | ||
| 93 | &acpi_table_attr_aml, | ||
| 94 | NULL, | ||
| 95 | }; | ||
| 96 | |||
| 97 | ssize_t acpi_table_signature_show(struct config_item *cfg, char *str) | ||
| 98 | { | ||
| 99 | struct acpi_table_header *h = get_header(cfg); | ||
| 100 | |||
| 101 | if (!h) | ||
| 102 | return -EINVAL; | ||
| 103 | |||
| 104 | return sprintf(str, "%.*s\n", ACPI_NAME_SIZE, h->signature); | ||
| 105 | } | ||
| 106 | |||
| 107 | ssize_t acpi_table_length_show(struct config_item *cfg, char *str) | ||
| 108 | { | ||
| 109 | struct acpi_table_header *h = get_header(cfg); | ||
| 110 | |||
| 111 | if (!h) | ||
| 112 | return -EINVAL; | ||
| 113 | |||
| 114 | return sprintf(str, "%d\n", h->length); | ||
| 115 | } | ||
| 116 | |||
| 117 | ssize_t acpi_table_revision_show(struct config_item *cfg, char *str) | ||
| 118 | { | ||
| 119 | struct acpi_table_header *h = get_header(cfg); | ||
| 120 | |||
| 121 | if (!h) | ||
| 122 | return -EINVAL; | ||
| 123 | |||
| 124 | return sprintf(str, "%d\n", h->revision); | ||
| 125 | } | ||
| 126 | |||
| 127 | ssize_t acpi_table_oem_id_show(struct config_item *cfg, char *str) | ||
| 128 | { | ||
| 129 | struct acpi_table_header *h = get_header(cfg); | ||
| 130 | |||
| 131 | if (!h) | ||
| 132 | return -EINVAL; | ||
| 133 | |||
| 134 | return sprintf(str, "%.*s\n", ACPI_OEM_ID_SIZE, h->oem_id); | ||
| 135 | } | ||
| 136 | |||
| 137 | ssize_t acpi_table_oem_table_id_show(struct config_item *cfg, char *str) | ||
| 138 | { | ||
| 139 | struct acpi_table_header *h = get_header(cfg); | ||
| 140 | |||
| 141 | if (!h) | ||
| 142 | return -EINVAL; | ||
| 143 | |||
| 144 | return sprintf(str, "%.*s\n", ACPI_OEM_TABLE_ID_SIZE, h->oem_table_id); | ||
| 145 | } | ||
| 146 | |||
| 147 | ssize_t acpi_table_oem_revision_show(struct config_item *cfg, char *str) | ||
| 148 | { | ||
| 149 | struct acpi_table_header *h = get_header(cfg); | ||
| 150 | |||
| 151 | if (!h) | ||
| 152 | return -EINVAL; | ||
| 153 | |||
| 154 | return sprintf(str, "%d\n", h->oem_revision); | ||
| 155 | } | ||
| 156 | |||
| 157 | ssize_t acpi_table_asl_compiler_id_show(struct config_item *cfg, char *str) | ||
| 158 | { | ||
| 159 | struct acpi_table_header *h = get_header(cfg); | ||
| 160 | |||
| 161 | if (!h) | ||
| 162 | return -EINVAL; | ||
| 163 | |||
| 164 | return sprintf(str, "%.*s\n", ACPI_NAME_SIZE, h->asl_compiler_id); | ||
| 165 | } | ||
| 166 | |||
| 167 | ssize_t acpi_table_asl_compiler_revision_show(struct config_item *cfg, | ||
| 168 | char *str) | ||
| 169 | { | ||
| 170 | struct acpi_table_header *h = get_header(cfg); | ||
| 171 | |||
| 172 | if (!h) | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | return sprintf(str, "%d\n", h->asl_compiler_revision); | ||
| 176 | } | ||
| 177 | |||
| 178 | CONFIGFS_ATTR_RO(acpi_table_, signature); | ||
| 179 | CONFIGFS_ATTR_RO(acpi_table_, length); | ||
| 180 | CONFIGFS_ATTR_RO(acpi_table_, revision); | ||
| 181 | CONFIGFS_ATTR_RO(acpi_table_, oem_id); | ||
| 182 | CONFIGFS_ATTR_RO(acpi_table_, oem_table_id); | ||
| 183 | CONFIGFS_ATTR_RO(acpi_table_, oem_revision); | ||
| 184 | CONFIGFS_ATTR_RO(acpi_table_, asl_compiler_id); | ||
| 185 | CONFIGFS_ATTR_RO(acpi_table_, asl_compiler_revision); | ||
| 186 | |||
| 187 | struct configfs_attribute *acpi_table_attrs[] = { | ||
| 188 | &acpi_table_attr_signature, | ||
| 189 | &acpi_table_attr_length, | ||
| 190 | &acpi_table_attr_revision, | ||
| 191 | &acpi_table_attr_oem_id, | ||
| 192 | &acpi_table_attr_oem_table_id, | ||
| 193 | &acpi_table_attr_oem_revision, | ||
| 194 | &acpi_table_attr_asl_compiler_id, | ||
| 195 | &acpi_table_attr_asl_compiler_revision, | ||
| 196 | NULL, | ||
| 197 | }; | ||
| 198 | |||
| 199 | static struct config_item_type acpi_table_type = { | ||
| 200 | .ct_owner = THIS_MODULE, | ||
| 201 | .ct_bin_attrs = acpi_table_bin_attrs, | ||
| 202 | .ct_attrs = acpi_table_attrs, | ||
| 203 | }; | ||
| 204 | |||
| 205 | static struct config_item *acpi_table_make_item(struct config_group *group, | ||
| 206 | const char *name) | ||
| 207 | { | ||
| 208 | struct acpi_table *table; | ||
| 209 | |||
| 210 | table = kzalloc(sizeof(*table), GFP_KERNEL); | ||
| 211 | if (!table) | ||
| 212 | return ERR_PTR(-ENOMEM); | ||
| 213 | |||
| 214 | config_item_init_type_name(&table->cfg, name, &acpi_table_type); | ||
| 215 | return &table->cfg; | ||
| 216 | } | ||
| 217 | |||
| 218 | struct configfs_group_operations acpi_table_group_ops = { | ||
| 219 | .make_item = acpi_table_make_item, | ||
| 220 | }; | ||
| 221 | |||
| 222 | static struct config_item_type acpi_tables_type = { | ||
| 223 | .ct_owner = THIS_MODULE, | ||
| 224 | .ct_group_ops = &acpi_table_group_ops, | ||
| 225 | }; | ||
| 226 | |||
| 227 | static struct config_item_type acpi_root_group_type = { | ||
| 228 | .ct_owner = THIS_MODULE, | ||
| 229 | }; | ||
| 230 | |||
| 231 | static struct configfs_subsystem acpi_configfs = { | ||
| 232 | .su_group = { | ||
| 233 | .cg_item = { | ||
| 234 | .ci_namebuf = "acpi", | ||
| 235 | .ci_type = &acpi_root_group_type, | ||
| 236 | }, | ||
| 237 | }, | ||
| 238 | .su_mutex = __MUTEX_INITIALIZER(acpi_configfs.su_mutex), | ||
| 239 | }; | ||
| 240 | |||
| 241 | static int __init acpi_configfs_init(void) | ||
| 242 | { | ||
| 243 | int ret; | ||
| 244 | struct config_group *root = &acpi_configfs.su_group; | ||
| 245 | |||
| 246 | config_group_init(root); | ||
| 247 | |||
| 248 | ret = configfs_register_subsystem(&acpi_configfs); | ||
| 249 | if (ret) | ||
| 250 | return ret; | ||
| 251 | |||
| 252 | acpi_table_group = configfs_register_default_group(root, "table", | ||
| 253 | &acpi_tables_type); | ||
| 254 | return PTR_ERR_OR_ZERO(acpi_table_group); | ||
| 255 | } | ||
| 256 | module_init(acpi_configfs_init); | ||
| 257 | |||
| 258 | static void __exit acpi_configfs_exit(void) | ||
| 259 | { | ||
| 260 | configfs_unregister_default_group(acpi_table_group); | ||
| 261 | configfs_unregister_subsystem(&acpi_configfs); | ||
| 262 | } | ||
| 263 | module_exit(acpi_configfs_exit); | ||
| 264 | |||
| 265 | MODULE_AUTHOR("Octavian Purdila <octavian.purdila@intel.com>"); | ||
| 266 | MODULE_DESCRIPTION("ACPI configfs support"); | ||
| 267 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/acpi/acpi_lpat.c b/drivers/acpi/acpi_lpat.c index feb61c1630eb..c1c4877ca96c 100644 --- a/drivers/acpi/acpi_lpat.c +++ b/drivers/acpi/acpi_lpat.c | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/module.h> | 16 | #include <linux/export.h> |
| 17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
| 18 | #include <acpi/acpi_lpat.h> | 18 | #include <acpi/acpi_lpat.h> |
| 19 | 19 | ||
| @@ -157,5 +157,3 @@ void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table | |||
| 157 | } | 157 | } |
| 158 | } | 158 | } |
| 159 | EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table); | 159 | EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table); |
| 160 | |||
| 161 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index c1d138e128cb..c5557d070954 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c | |||
| @@ -1246,6 +1246,9 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video) | |||
| 1246 | union acpi_object *dod = NULL; | 1246 | union acpi_object *dod = NULL; |
| 1247 | union acpi_object *obj; | 1247 | union acpi_object *obj; |
| 1248 | 1248 | ||
| 1249 | if (!video->cap._DOD) | ||
| 1250 | return AE_NOT_EXIST; | ||
| 1251 | |||
| 1249 | status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer); | 1252 | status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer); |
| 1250 | if (!ACPI_SUCCESS(status)) { | 1253 | if (!ACPI_SUCCESS(status)) { |
| 1251 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD")); | 1254 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD")); |
diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile index 5d575a955940..e50573de25f1 100644 --- a/drivers/acpi/apei/Makefile +++ b/drivers/acpi/apei/Makefile | |||
| @@ -3,4 +3,4 @@ obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o | |||
| 3 | obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o | 3 | obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o |
| 4 | obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o | 4 | obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o |
| 5 | 5 | ||
| 6 | apei-y := apei-base.o hest.o erst.o | 6 | apei-y := apei-base.o hest.o erst.o bert.o |
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 16129c78b489..6e9f14c0a71b 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * apei-internal.h - ACPI Platform Error Interface internal | 2 | * apei-internal.h - ACPI Platform Error Interface internal |
| 3 | * definations. | 3 | * definitions. |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #ifndef APEI_INTERNAL_H | 6 | #ifndef APEI_INTERNAL_H |
diff --git a/drivers/acpi/apei/bert.c b/drivers/acpi/apei/bert.c new file mode 100644 index 000000000000..a05b5c0cf181 --- /dev/null +++ b/drivers/acpi/apei/bert.c | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | /* | ||
| 2 | * APEI Boot Error Record Table (BERT) support | ||
| 3 | * | ||
| 4 | * Copyright 2011 Intel Corp. | ||
| 5 | * Author: Huang Ying <ying.huang@intel.com> | ||
| 6 | * | ||
| 7 | * Under normal circumstances, when a hardware error occurs, the error | ||
| 8 | * handler receives control and processes the error. This gives OSPM a | ||
| 9 | * chance to process the error condition, report it, and optionally attempt | ||
| 10 | * recovery. In some cases, the system is unable to process an error. | ||
| 11 | * For example, system firmware or a management controller may choose to | ||
| 12 | * reset the system or the system might experience an uncontrolled crash | ||
| 13 | * or reset.The boot error source is used to report unhandled errors that | ||
| 14 | * occurred in a previous boot. This mechanism is described in the BERT | ||
| 15 | * table. | ||
| 16 | * | ||
| 17 | * For more information about BERT, please refer to ACPI Specification | ||
| 18 | * version 4.0, section 17.3.1 | ||
| 19 | * | ||
| 20 | * This file is licensed under GPLv2. | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/acpi.h> | ||
| 28 | #include <linux/io.h> | ||
| 29 | |||
| 30 | #include "apei-internal.h" | ||
| 31 | |||
| 32 | #undef pr_fmt | ||
| 33 | #define pr_fmt(fmt) "BERT: " fmt | ||
| 34 | |||
| 35 | static int bert_disable; | ||
| 36 | |||
| 37 | static void __init bert_print_all(struct acpi_bert_region *region, | ||
| 38 | unsigned int region_len) | ||
| 39 | { | ||
| 40 | struct acpi_hest_generic_status *estatus = | ||
| 41 | (struct acpi_hest_generic_status *)region; | ||
| 42 | int remain = region_len; | ||
| 43 | u32 estatus_len; | ||
| 44 | |||
| 45 | if (!estatus->block_status) | ||
| 46 | return; | ||
| 47 | |||
| 48 | while (remain > sizeof(struct acpi_bert_region)) { | ||
| 49 | if (cper_estatus_check(estatus)) { | ||
| 50 | pr_err(FW_BUG "Invalid error record.\n"); | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | |||
| 54 | estatus_len = cper_estatus_len(estatus); | ||
| 55 | if (remain < estatus_len) { | ||
| 56 | pr_err(FW_BUG "Truncated status block (length: %u).\n", | ||
| 57 | estatus_len); | ||
| 58 | return; | ||
| 59 | } | ||
| 60 | |||
| 61 | pr_info_once("Error records from previous boot:\n"); | ||
| 62 | |||
| 63 | cper_estatus_print(KERN_INFO HW_ERR, estatus); | ||
| 64 | |||
| 65 | /* | ||
| 66 | * Because the boot error source is "one-time polled" type, | ||
| 67 | * clear Block Status of current Generic Error Status Block, | ||
| 68 | * once it's printed. | ||
| 69 | */ | ||
| 70 | estatus->block_status = 0; | ||
| 71 | |||
| 72 | estatus = (void *)estatus + estatus_len; | ||
| 73 | /* No more error records. */ | ||
| 74 | if (!estatus->block_status) | ||
| 75 | return; | ||
| 76 | |||
| 77 | remain -= estatus_len; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | static int __init setup_bert_disable(char *str) | ||
| 82 | { | ||
| 83 | bert_disable = 1; | ||
| 84 | |||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | __setup("bert_disable", setup_bert_disable); | ||
| 88 | |||
| 89 | static int __init bert_check_table(struct acpi_table_bert *bert_tab) | ||
| 90 | { | ||
| 91 | if (bert_tab->header.length < sizeof(struct acpi_table_bert) || | ||
| 92 | bert_tab->region_length < sizeof(struct acpi_bert_region)) | ||
| 93 | return -EINVAL; | ||
| 94 | |||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int __init bert_init(void) | ||
| 99 | { | ||
| 100 | struct acpi_bert_region *boot_error_region; | ||
| 101 | struct acpi_table_bert *bert_tab; | ||
| 102 | unsigned int region_len; | ||
| 103 | acpi_status status; | ||
| 104 | int rc = 0; | ||
| 105 | |||
| 106 | if (acpi_disabled) | ||
| 107 | return 0; | ||
| 108 | |||
| 109 | if (bert_disable) { | ||
| 110 | pr_info("Boot Error Record Table support is disabled.\n"); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | status = acpi_get_table(ACPI_SIG_BERT, 0, (struct acpi_table_header **)&bert_tab); | ||
| 115 | if (status == AE_NOT_FOUND) | ||
| 116 | return 0; | ||
| 117 | |||
| 118 | if (ACPI_FAILURE(status)) { | ||
| 119 | pr_err("get table failed, %s.\n", acpi_format_exception(status)); | ||
| 120 | return -EINVAL; | ||
| 121 | } | ||
| 122 | |||
| 123 | rc = bert_check_table(bert_tab); | ||
| 124 | if (rc) { | ||
| 125 | pr_err(FW_BUG "table invalid.\n"); | ||
| 126 | return rc; | ||
| 127 | } | ||
| 128 | |||
| 129 | region_len = bert_tab->region_length; | ||
| 130 | if (!request_mem_region(bert_tab->address, region_len, "APEI BERT")) { | ||
| 131 | pr_err("Can't request iomem region <%016llx-%016llx>.\n", | ||
| 132 | (unsigned long long)bert_tab->address, | ||
| 133 | (unsigned long long)bert_tab->address + region_len - 1); | ||
| 134 | return -EIO; | ||
| 135 | } | ||
| 136 | |||
| 137 | boot_error_region = ioremap_cache(bert_tab->address, region_len); | ||
| 138 | if (boot_error_region) { | ||
| 139 | bert_print_all(boot_error_region, region_len); | ||
| 140 | iounmap(boot_error_region); | ||
| 141 | } else { | ||
| 142 | rc = -ENOMEM; | ||
| 143 | } | ||
| 144 | |||
| 145 | release_mem_region(bert_tab->address, region_len); | ||
| 146 | |||
| 147 | return rc; | ||
| 148 | } | ||
| 149 | |||
| 150 | late_initcall(bert_init); | ||
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 559c1173de1c..eebb7e39c49c 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c | |||
| @@ -33,7 +33,8 @@ | |||
| 33 | 33 | ||
| 34 | #include "apei-internal.h" | 34 | #include "apei-internal.h" |
| 35 | 35 | ||
| 36 | #define EINJ_PFX "EINJ: " | 36 | #undef pr_fmt |
| 37 | #define pr_fmt(fmt) "EINJ: " fmt | ||
| 37 | 38 | ||
| 38 | #define SPIN_UNIT 100 /* 100ns */ | 39 | #define SPIN_UNIT 100 /* 100ns */ |
| 39 | /* Firmware should respond within 1 milliseconds */ | 40 | /* Firmware should respond within 1 milliseconds */ |
| @@ -179,8 +180,7 @@ static int einj_get_available_error_type(u32 *type) | |||
| 179 | static int einj_timedout(u64 *t) | 180 | static int einj_timedout(u64 *t) |
| 180 | { | 181 | { |
| 181 | if ((s64)*t < SPIN_UNIT) { | 182 | if ((s64)*t < SPIN_UNIT) { |
| 182 | pr_warning(FW_WARN EINJ_PFX | 183 | pr_warning(FW_WARN "Firmware does not respond in time\n"); |
| 183 | "Firmware does not respond in time\n"); | ||
| 184 | return 1; | 184 | return 1; |
| 185 | } | 185 | } |
| 186 | *t -= SPIN_UNIT; | 186 | *t -= SPIN_UNIT; |
| @@ -307,8 +307,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, | |||
| 307 | r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), | 307 | r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), |
| 308 | "APEI EINJ Trigger Table"); | 308 | "APEI EINJ Trigger Table"); |
| 309 | if (!r) { | 309 | if (!r) { |
| 310 | pr_err(EINJ_PFX | 310 | pr_err("Can not request [mem %#010llx-%#010llx] for Trigger table\n", |
| 311 | "Can not request [mem %#010llx-%#010llx] for Trigger table\n", | ||
| 312 | (unsigned long long)trigger_paddr, | 311 | (unsigned long long)trigger_paddr, |
| 313 | (unsigned long long)trigger_paddr + | 312 | (unsigned long long)trigger_paddr + |
| 314 | sizeof(*trigger_tab) - 1); | 313 | sizeof(*trigger_tab) - 1); |
| @@ -316,13 +315,12 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, | |||
| 316 | } | 315 | } |
| 317 | trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab)); | 316 | trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab)); |
| 318 | if (!trigger_tab) { | 317 | if (!trigger_tab) { |
| 319 | pr_err(EINJ_PFX "Failed to map trigger table!\n"); | 318 | pr_err("Failed to map trigger table!\n"); |
| 320 | goto out_rel_header; | 319 | goto out_rel_header; |
| 321 | } | 320 | } |
| 322 | rc = einj_check_trigger_header(trigger_tab); | 321 | rc = einj_check_trigger_header(trigger_tab); |
| 323 | if (rc) { | 322 | if (rc) { |
| 324 | pr_warning(FW_BUG EINJ_PFX | 323 | pr_warning(FW_BUG "Invalid trigger error action table.\n"); |
| 325 | "The trigger error action table is invalid\n"); | ||
| 326 | goto out_rel_header; | 324 | goto out_rel_header; |
| 327 | } | 325 | } |
| 328 | 326 | ||
| @@ -336,8 +334,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, | |||
| 336 | table_size - sizeof(*trigger_tab), | 334 | table_size - sizeof(*trigger_tab), |
| 337 | "APEI EINJ Trigger Table"); | 335 | "APEI EINJ Trigger Table"); |
| 338 | if (!r) { | 336 | if (!r) { |
| 339 | pr_err(EINJ_PFX | 337 | pr_err("Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n", |
| 340 | "Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n", | ||
| 341 | (unsigned long long)trigger_paddr + sizeof(*trigger_tab), | 338 | (unsigned long long)trigger_paddr + sizeof(*trigger_tab), |
| 342 | (unsigned long long)trigger_paddr + table_size - 1); | 339 | (unsigned long long)trigger_paddr + table_size - 1); |
| 343 | goto out_rel_header; | 340 | goto out_rel_header; |
| @@ -345,7 +342,7 @@ static int __einj_error_trigger(u64 trigger_paddr, u32 type, | |||
| 345 | iounmap(trigger_tab); | 342 | iounmap(trigger_tab); |
| 346 | trigger_tab = ioremap_cache(trigger_paddr, table_size); | 343 | trigger_tab = ioremap_cache(trigger_paddr, table_size); |
| 347 | if (!trigger_tab) { | 344 | if (!trigger_tab) { |
| 348 | pr_err(EINJ_PFX "Failed to map trigger table!\n"); | 345 | pr_err("Failed to map trigger table!\n"); |
| 349 | goto out_rel_entry; | 346 | goto out_rel_entry; |
| 350 | } | 347 | } |
| 351 | trigger_entry = (struct acpi_whea_header *) | 348 | trigger_entry = (struct acpi_whea_header *) |
| @@ -695,34 +692,42 @@ static int __init einj_init(void) | |||
| 695 | struct dentry *fentry; | 692 | struct dentry *fentry; |
| 696 | struct apei_exec_context ctx; | 693 | struct apei_exec_context ctx; |
| 697 | 694 | ||
| 698 | if (acpi_disabled) | 695 | if (acpi_disabled) { |
| 696 | pr_warn("ACPI disabled.\n"); | ||
| 699 | return -ENODEV; | 697 | return -ENODEV; |
| 698 | } | ||
| 700 | 699 | ||
| 701 | status = acpi_get_table(ACPI_SIG_EINJ, 0, | 700 | status = acpi_get_table(ACPI_SIG_EINJ, 0, |
| 702 | (struct acpi_table_header **)&einj_tab); | 701 | (struct acpi_table_header **)&einj_tab); |
| 703 | if (status == AE_NOT_FOUND) | 702 | if (status == AE_NOT_FOUND) { |
| 703 | pr_warn("EINJ table not found.\n"); | ||
| 704 | return -ENODEV; | 704 | return -ENODEV; |
| 705 | } | ||
| 705 | else if (ACPI_FAILURE(status)) { | 706 | else if (ACPI_FAILURE(status)) { |
| 706 | const char *msg = acpi_format_exception(status); | 707 | pr_err("Failed to get EINJ table: %s\n", |
| 707 | pr_err(EINJ_PFX "Failed to get table, %s\n", msg); | 708 | acpi_format_exception(status)); |
| 708 | return -EINVAL; | 709 | return -EINVAL; |
| 709 | } | 710 | } |
| 710 | 711 | ||
| 711 | rc = einj_check_table(einj_tab); | 712 | rc = einj_check_table(einj_tab); |
| 712 | if (rc) { | 713 | if (rc) { |
| 713 | pr_warning(FW_BUG EINJ_PFX "EINJ table is invalid\n"); | 714 | pr_warn(FW_BUG "Invalid EINJ table.n"); |
| 714 | return -EINVAL; | 715 | return -EINVAL; |
| 715 | } | 716 | } |
| 716 | 717 | ||
| 717 | rc = -ENOMEM; | 718 | rc = -ENOMEM; |
| 718 | einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir()); | 719 | einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir()); |
| 719 | if (!einj_debug_dir) | 720 | if (!einj_debug_dir) { |
| 721 | pr_err("Error creating debugfs node.\n"); | ||
| 720 | goto err_cleanup; | 722 | goto err_cleanup; |
| 723 | } | ||
| 724 | |||
| 721 | fentry = debugfs_create_file("available_error_type", S_IRUSR, | 725 | fentry = debugfs_create_file("available_error_type", S_IRUSR, |
| 722 | einj_debug_dir, NULL, | 726 | einj_debug_dir, NULL, |
| 723 | &available_error_type_fops); | 727 | &available_error_type_fops); |
| 724 | if (!fentry) | 728 | if (!fentry) |
| 725 | goto err_cleanup; | 729 | goto err_cleanup; |
| 730 | |||
| 726 | fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR, | 731 | fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR, |
| 727 | einj_debug_dir, NULL, &error_type_fops); | 732 | einj_debug_dir, NULL, &error_type_fops); |
| 728 | if (!fentry) | 733 | if (!fentry) |
| @@ -735,14 +740,22 @@ static int __init einj_init(void) | |||
| 735 | apei_resources_init(&einj_resources); | 740 | apei_resources_init(&einj_resources); |
| 736 | einj_exec_ctx_init(&ctx); | 741 | einj_exec_ctx_init(&ctx); |
| 737 | rc = apei_exec_collect_resources(&ctx, &einj_resources); | 742 | rc = apei_exec_collect_resources(&ctx, &einj_resources); |
| 738 | if (rc) | 743 | if (rc) { |
| 744 | pr_err("Error collecting EINJ resources.\n"); | ||
| 739 | goto err_fini; | 745 | goto err_fini; |
| 746 | } | ||
| 747 | |||
| 740 | rc = apei_resources_request(&einj_resources, "APEI EINJ"); | 748 | rc = apei_resources_request(&einj_resources, "APEI EINJ"); |
| 741 | if (rc) | 749 | if (rc) { |
| 750 | pr_err("Error requesting memory/port resources.\n"); | ||
| 742 | goto err_fini; | 751 | goto err_fini; |
| 752 | } | ||
| 753 | |||
| 743 | rc = apei_exec_pre_map_gars(&ctx); | 754 | rc = apei_exec_pre_map_gars(&ctx); |
| 744 | if (rc) | 755 | if (rc) { |
| 756 | pr_err("Error pre-mapping GARs.\n"); | ||
| 745 | goto err_release; | 757 | goto err_release; |
| 758 | } | ||
| 746 | 759 | ||
| 747 | rc = -ENOMEM; | 760 | rc = -ENOMEM; |
| 748 | einj_param = einj_get_parameter_address(); | 761 | einj_param = einj_get_parameter_address(); |
| @@ -787,7 +800,7 @@ static int __init einj_init(void) | |||
| 787 | goto err_unmap; | 800 | goto err_unmap; |
| 788 | } | 801 | } |
| 789 | 802 | ||
| 790 | pr_info(EINJ_PFX "Error INJection is initialized.\n"); | 803 | pr_info("Error INJection is initialized.\n"); |
| 791 | 804 | ||
| 792 | return 0; | 805 | return 0; |
| 793 | 806 | ||
| @@ -798,6 +811,7 @@ err_unmap: | |||
| 798 | sizeof(struct einj_parameter); | 811 | sizeof(struct einj_parameter); |
| 799 | 812 | ||
| 800 | acpi_os_unmap_iomem(einj_param, size); | 813 | acpi_os_unmap_iomem(einj_param, size); |
| 814 | pr_err("Error creating param extension debugfs nodes.\n"); | ||
| 801 | } | 815 | } |
| 802 | apei_exec_post_unmap_gars(&ctx); | 816 | apei_exec_post_unmap_gars(&ctx); |
| 803 | err_release: | 817 | err_release: |
| @@ -805,6 +819,7 @@ err_release: | |||
| 805 | err_fini: | 819 | err_fini: |
| 806 | apei_resources_fini(&einj_resources); | 820 | apei_resources_fini(&einj_resources); |
| 807 | err_cleanup: | 821 | err_cleanup: |
| 822 | pr_err("Error creating primary debugfs nodes.\n"); | ||
| 808 | debugfs_remove_recursive(einj_debug_dir); | 823 | debugfs_remove_recursive(einj_debug_dir); |
| 809 | 824 | ||
| 810 | return rc; | 825 | return rc; |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 262ca31b86d9..85b7d07fe5c8 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
| @@ -30,6 +30,9 @@ | |||
| 30 | #include <linux/acpi.h> | 30 | #include <linux/acpi.h> |
| 31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 32 | #include <linux/regulator/machine.h> | 32 | #include <linux/regulator/machine.h> |
| 33 | #include <linux/workqueue.h> | ||
| 34 | #include <linux/reboot.h> | ||
| 35 | #include <linux/delay.h> | ||
| 33 | #ifdef CONFIG_X86 | 36 | #ifdef CONFIG_X86 |
| 34 | #include <asm/mpspec.h> | 37 | #include <asm/mpspec.h> |
| 35 | #endif | 38 | #endif |
| @@ -174,22 +177,17 @@ void acpi_bus_detach_private_data(acpi_handle handle) | |||
| 174 | EXPORT_SYMBOL_GPL(acpi_bus_detach_private_data); | 177 | EXPORT_SYMBOL_GPL(acpi_bus_detach_private_data); |
| 175 | 178 | ||
| 176 | static void acpi_print_osc_error(acpi_handle handle, | 179 | static void acpi_print_osc_error(acpi_handle handle, |
| 177 | struct acpi_osc_context *context, char *error) | 180 | struct acpi_osc_context *context, char *error) |
| 178 | { | 181 | { |
| 179 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER}; | ||
| 180 | int i; | 182 | int i; |
| 181 | 183 | ||
| 182 | if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) | 184 | acpi_handle_debug(handle, "(%s): %s\n", context->uuid_str, error); |
| 183 | printk(KERN_DEBUG "%s: %s\n", context->uuid_str, error); | 185 | |
| 184 | else { | 186 | pr_debug("_OSC request data:"); |
| 185 | printk(KERN_DEBUG "%s (%s): %s\n", | ||
| 186 | (char *)buffer.pointer, context->uuid_str, error); | ||
| 187 | kfree(buffer.pointer); | ||
| 188 | } | ||
| 189 | printk(KERN_DEBUG "_OSC request data:"); | ||
| 190 | for (i = 0; i < context->cap.length; i += sizeof(u32)) | 187 | for (i = 0; i < context->cap.length; i += sizeof(u32)) |
| 191 | printk(" %x", *((u32 *)(context->cap.pointer + i))); | 188 | pr_debug(" %x", *((u32 *)(context->cap.pointer + i))); |
| 192 | printk("\n"); | 189 | |
| 190 | pr_debug("\n"); | ||
| 193 | } | 191 | } |
| 194 | 192 | ||
| 195 | acpi_status acpi_str_to_uuid(char *str, u8 *uuid) | 193 | acpi_status acpi_str_to_uuid(char *str, u8 *uuid) |
| @@ -302,6 +300,14 @@ out_kfree: | |||
| 302 | EXPORT_SYMBOL(acpi_run_osc); | 300 | EXPORT_SYMBOL(acpi_run_osc); |
| 303 | 301 | ||
| 304 | bool osc_sb_apei_support_acked; | 302 | bool osc_sb_apei_support_acked; |
| 303 | |||
| 304 | /* | ||
| 305 | * ACPI 6.0 Section 8.4.4.2 Idle State Coordination | ||
| 306 | * OSPM supports platform coordinated low power idle(LPI) states | ||
| 307 | */ | ||
| 308 | bool osc_pc_lpi_support_confirmed; | ||
| 309 | EXPORT_SYMBOL_GPL(osc_pc_lpi_support_confirmed); | ||
| 310 | |||
| 305 | static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; | 311 | static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; |
| 306 | static void acpi_bus_osc_support(void) | 312 | static void acpi_bus_osc_support(void) |
| 307 | { | 313 | { |
| @@ -322,6 +328,7 @@ static void acpi_bus_osc_support(void) | |||
| 322 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT; | 328 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT; |
| 323 | 329 | ||
| 324 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT; | 330 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT; |
| 331 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT; | ||
| 325 | 332 | ||
| 326 | if (!ghes_disable) | 333 | if (!ghes_disable) |
| 327 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT; | 334 | capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT; |
| @@ -329,9 +336,12 @@ static void acpi_bus_osc_support(void) | |||
| 329 | return; | 336 | return; |
| 330 | if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) { | 337 | if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) { |
| 331 | u32 *capbuf_ret = context.ret.pointer; | 338 | u32 *capbuf_ret = context.ret.pointer; |
| 332 | if (context.ret.length > OSC_SUPPORT_DWORD) | 339 | if (context.ret.length > OSC_SUPPORT_DWORD) { |
| 333 | osc_sb_apei_support_acked = | 340 | osc_sb_apei_support_acked = |
| 334 | capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT; | 341 | capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT; |
| 342 | osc_pc_lpi_support_confirmed = | ||
| 343 | capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_PCLPI_SUPPORT; | ||
| 344 | } | ||
| 335 | kfree(context.ret.pointer); | 345 | kfree(context.ret.pointer); |
| 336 | } | 346 | } |
| 337 | /* do we need to check other returned cap? Sounds no */ | 347 | /* do we need to check other returned cap? Sounds no */ |
| @@ -475,6 +485,56 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device) | |||
| 475 | acpi_device_notify); | 485 | acpi_device_notify); |
| 476 | } | 486 | } |
| 477 | 487 | ||
| 488 | /* Handle events targeting \_SB device (at present only graceful shutdown) */ | ||
| 489 | |||
| 490 | #define ACPI_SB_NOTIFY_SHUTDOWN_REQUEST 0x81 | ||
| 491 | #define ACPI_SB_INDICATE_INTERVAL 10000 | ||
| 492 | |||
| 493 | static void sb_notify_work(struct work_struct *dummy) | ||
| 494 | { | ||
| 495 | acpi_handle sb_handle; | ||
| 496 | |||
| 497 | orderly_poweroff(true); | ||
| 498 | |||
| 499 | /* | ||
| 500 | * After initiating graceful shutdown, the ACPI spec requires OSPM | ||
| 501 | * to evaluate _OST method once every 10seconds to indicate that | ||
| 502 | * the shutdown is in progress | ||
| 503 | */ | ||
| 504 | acpi_get_handle(NULL, "\\_SB", &sb_handle); | ||
| 505 | while (1) { | ||
| 506 | pr_info("Graceful shutdown in progress.\n"); | ||
| 507 | acpi_evaluate_ost(sb_handle, ACPI_OST_EC_OSPM_SHUTDOWN, | ||
| 508 | ACPI_OST_SC_OS_SHUTDOWN_IN_PROGRESS, NULL); | ||
| 509 | msleep(ACPI_SB_INDICATE_INTERVAL); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 513 | static void acpi_sb_notify(acpi_handle handle, u32 event, void *data) | ||
| 514 | { | ||
| 515 | static DECLARE_WORK(acpi_sb_work, sb_notify_work); | ||
| 516 | |||
| 517 | if (event == ACPI_SB_NOTIFY_SHUTDOWN_REQUEST) { | ||
| 518 | if (!work_busy(&acpi_sb_work)) | ||
| 519 | schedule_work(&acpi_sb_work); | ||
| 520 | } else | ||
| 521 | pr_warn("event %x is not supported by \\_SB device\n", event); | ||
| 522 | } | ||
| 523 | |||
| 524 | static int __init acpi_setup_sb_notify_handler(void) | ||
| 525 | { | ||
| 526 | acpi_handle sb_handle; | ||
| 527 | |||
| 528 | if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &sb_handle))) | ||
| 529 | return -ENXIO; | ||
| 530 | |||
| 531 | if (ACPI_FAILURE(acpi_install_notify_handler(sb_handle, ACPI_DEVICE_NOTIFY, | ||
| 532 | acpi_sb_notify, NULL))) | ||
| 533 | return -EINVAL; | ||
| 534 | |||
| 535 | return 0; | ||
| 536 | } | ||
| 537 | |||
| 478 | /* -------------------------------------------------------------------------- | 538 | /* -------------------------------------------------------------------------- |
| 479 | Device Matching | 539 | Device Matching |
| 480 | -------------------------------------------------------------------------- */ | 540 | -------------------------------------------------------------------------- */ |
| @@ -961,8 +1021,7 @@ void __init acpi_early_init(void) | |||
| 961 | /** | 1021 | /** |
| 962 | * acpi_subsystem_init - Finalize the early initialization of ACPI. | 1022 | * acpi_subsystem_init - Finalize the early initialization of ACPI. |
| 963 | * | 1023 | * |
| 964 | * Switch over the platform to the ACPI mode (if possible), initialize the | 1024 | * Switch over the platform to the ACPI mode (if possible). |
| 965 | * handling of ACPI events, install the interrupt and global lock handlers. | ||
| 966 | * | 1025 | * |
| 967 | * Doing this too early is generally unsafe, but at the same time it needs to be | 1026 | * Doing this too early is generally unsafe, but at the same time it needs to be |
| 968 | * done before all things that really depend on ACPI. The right spot appears to | 1027 | * done before all things that really depend on ACPI. The right spot appears to |
| @@ -990,6 +1049,13 @@ void __init acpi_subsystem_init(void) | |||
| 990 | } | 1049 | } |
| 991 | } | 1050 | } |
| 992 | 1051 | ||
| 1052 | static acpi_status acpi_bus_table_handler(u32 event, void *table, void *context) | ||
| 1053 | { | ||
| 1054 | acpi_scan_table_handler(event, table, context); | ||
| 1055 | |||
| 1056 | return acpi_sysfs_table_handler(event, table, context); | ||
| 1057 | } | ||
| 1058 | |||
| 993 | static int __init acpi_bus_init(void) | 1059 | static int __init acpi_bus_init(void) |
| 994 | { | 1060 | { |
| 995 | int result; | 1061 | int result; |
| @@ -1043,6 +1109,8 @@ static int __init acpi_bus_init(void) | |||
| 1043 | * _PDC control method may load dynamic SSDT tables, | 1109 | * _PDC control method may load dynamic SSDT tables, |
| 1044 | * and we need to install the table handler before that. | 1110 | * and we need to install the table handler before that. |
| 1045 | */ | 1111 | */ |
| 1112 | status = acpi_install_table_handler(acpi_bus_table_handler, NULL); | ||
| 1113 | |||
| 1046 | acpi_sysfs_init(); | 1114 | acpi_sysfs_init(); |
| 1047 | 1115 | ||
| 1048 | acpi_early_processor_set_pdc(); | 1116 | acpi_early_processor_set_pdc(); |
| @@ -1124,6 +1192,7 @@ static int __init acpi_init(void) | |||
| 1124 | acpi_sleep_proc_init(); | 1192 | acpi_sleep_proc_init(); |
| 1125 | acpi_wakeup_device_init(); | 1193 | acpi_wakeup_device_init(); |
| 1126 | acpi_debugger_init(); | 1194 | acpi_debugger_init(); |
| 1195 | acpi_setup_sb_notify_handler(); | ||
| 1127 | return 0; | 1196 | return 0; |
| 1128 | } | 1197 | } |
| 1129 | 1198 | ||
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 5c3b0918d5fd..148f4e5ca104 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
| @@ -53,6 +53,10 @@ | |||
| 53 | #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" | 53 | #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" |
| 54 | #define ACPI_BUTTON_TYPE_LID 0x05 | 54 | #define ACPI_BUTTON_TYPE_LID 0x05 |
| 55 | 55 | ||
| 56 | #define ACPI_BUTTON_LID_INIT_IGNORE 0x00 | ||
| 57 | #define ACPI_BUTTON_LID_INIT_OPEN 0x01 | ||
| 58 | #define ACPI_BUTTON_LID_INIT_METHOD 0x02 | ||
| 59 | |||
| 56 | #define _COMPONENT ACPI_BUTTON_COMPONENT | 60 | #define _COMPONENT ACPI_BUTTON_COMPONENT |
| 57 | ACPI_MODULE_NAME("button"); | 61 | ACPI_MODULE_NAME("button"); |
| 58 | 62 | ||
| @@ -105,6 +109,7 @@ struct acpi_button { | |||
| 105 | 109 | ||
| 106 | static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); | 110 | static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); |
| 107 | static struct acpi_device *lid_device; | 111 | static struct acpi_device *lid_device; |
| 112 | static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; | ||
| 108 | 113 | ||
| 109 | /* -------------------------------------------------------------------------- | 114 | /* -------------------------------------------------------------------------- |
| 110 | FS Interface (/proc) | 115 | FS Interface (/proc) |
| @@ -113,16 +118,52 @@ static struct acpi_device *lid_device; | |||
| 113 | static struct proc_dir_entry *acpi_button_dir; | 118 | static struct proc_dir_entry *acpi_button_dir; |
| 114 | static struct proc_dir_entry *acpi_lid_dir; | 119 | static struct proc_dir_entry *acpi_lid_dir; |
| 115 | 120 | ||
| 121 | static int acpi_lid_evaluate_state(struct acpi_device *device) | ||
| 122 | { | ||
| 123 | unsigned long long lid_state; | ||
| 124 | acpi_status status; | ||
| 125 | |||
| 126 | status = acpi_evaluate_integer(device->handle, "_LID", NULL, &lid_state); | ||
| 127 | if (ACPI_FAILURE(status)) | ||
| 128 | return -ENODEV; | ||
| 129 | |||
| 130 | return lid_state ? 1 : 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int acpi_lid_notify_state(struct acpi_device *device, int state) | ||
| 134 | { | ||
| 135 | struct acpi_button *button = acpi_driver_data(device); | ||
| 136 | int ret; | ||
| 137 | |||
| 138 | /* input layer checks if event is redundant */ | ||
| 139 | input_report_switch(button->input, SW_LID, !state); | ||
| 140 | input_sync(button->input); | ||
| 141 | |||
| 142 | if (state) | ||
| 143 | pm_wakeup_event(&device->dev, 0); | ||
| 144 | |||
| 145 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); | ||
| 146 | if (ret == NOTIFY_DONE) | ||
| 147 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, | ||
| 148 | device); | ||
| 149 | if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { | ||
| 150 | /* | ||
| 151 | * It is also regarded as success if the notifier_chain | ||
| 152 | * returns NOTIFY_OK or NOTIFY_DONE. | ||
| 153 | */ | ||
| 154 | ret = 0; | ||
| 155 | } | ||
| 156 | return ret; | ||
| 157 | } | ||
| 158 | |||
| 116 | static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) | 159 | static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) |
| 117 | { | 160 | { |
| 118 | struct acpi_device *device = seq->private; | 161 | struct acpi_device *device = seq->private; |
| 119 | acpi_status status; | 162 | int state; |
| 120 | unsigned long long state; | ||
| 121 | 163 | ||
| 122 | status = acpi_evaluate_integer(device->handle, "_LID", NULL, &state); | 164 | state = acpi_lid_evaluate_state(device); |
| 123 | seq_printf(seq, "state: %s\n", | 165 | seq_printf(seq, "state: %s\n", |
| 124 | ACPI_FAILURE(status) ? "unsupported" : | 166 | state < 0 ? "unsupported" : (state ? "open" : "closed")); |
| 125 | (state ? "open" : "closed")); | ||
| 126 | return 0; | 167 | return 0; |
| 127 | } | 168 | } |
| 128 | 169 | ||
| @@ -231,51 +272,37 @@ EXPORT_SYMBOL(acpi_lid_notifier_unregister); | |||
| 231 | 272 | ||
| 232 | int acpi_lid_open(void) | 273 | int acpi_lid_open(void) |
| 233 | { | 274 | { |
| 234 | acpi_status status; | ||
| 235 | unsigned long long state; | ||
| 236 | |||
| 237 | if (!lid_device) | 275 | if (!lid_device) |
| 238 | return -ENODEV; | 276 | return -ENODEV; |
| 239 | 277 | ||
| 240 | status = acpi_evaluate_integer(lid_device->handle, "_LID", NULL, | 278 | return acpi_lid_evaluate_state(lid_device); |
| 241 | &state); | ||
| 242 | if (ACPI_FAILURE(status)) | ||
| 243 | return -ENODEV; | ||
| 244 | |||
| 245 | return !!state; | ||
| 246 | } | 279 | } |
| 247 | EXPORT_SYMBOL(acpi_lid_open); | 280 | EXPORT_SYMBOL(acpi_lid_open); |
| 248 | 281 | ||
| 249 | static int acpi_lid_send_state(struct acpi_device *device) | 282 | static int acpi_lid_update_state(struct acpi_device *device) |
| 250 | { | 283 | { |
| 251 | struct acpi_button *button = acpi_driver_data(device); | 284 | int state; |
| 252 | unsigned long long state; | ||
| 253 | acpi_status status; | ||
| 254 | int ret; | ||
| 255 | |||
| 256 | status = acpi_evaluate_integer(device->handle, "_LID", NULL, &state); | ||
| 257 | if (ACPI_FAILURE(status)) | ||
| 258 | return -ENODEV; | ||
| 259 | 285 | ||
| 260 | /* input layer checks if event is redundant */ | 286 | state = acpi_lid_evaluate_state(device); |
| 261 | input_report_switch(button->input, SW_LID, !state); | 287 | if (state < 0) |
| 262 | input_sync(button->input); | 288 | return state; |
| 263 | 289 | ||
| 264 | if (state) | 290 | return acpi_lid_notify_state(device, state); |
| 265 | pm_wakeup_event(&device->dev, 0); | 291 | } |
| 266 | 292 | ||
| 267 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); | 293 | static void acpi_lid_initialize_state(struct acpi_device *device) |
| 268 | if (ret == NOTIFY_DONE) | 294 | { |
| 269 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, | 295 | switch (lid_init_state) { |
| 270 | device); | 296 | case ACPI_BUTTON_LID_INIT_OPEN: |
| 271 | if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { | 297 | (void)acpi_lid_notify_state(device, 1); |
| 272 | /* | 298 | break; |
| 273 | * It is also regarded as success if the notifier_chain | 299 | case ACPI_BUTTON_LID_INIT_METHOD: |
| 274 | * returns NOTIFY_OK or NOTIFY_DONE. | 300 | (void)acpi_lid_update_state(device); |
| 275 | */ | 301 | break; |
| 276 | ret = 0; | 302 | case ACPI_BUTTON_LID_INIT_IGNORE: |
| 303 | default: | ||
| 304 | break; | ||
| 277 | } | 305 | } |
| 278 | return ret; | ||
| 279 | } | 306 | } |
| 280 | 307 | ||
| 281 | static void acpi_button_notify(struct acpi_device *device, u32 event) | 308 | static void acpi_button_notify(struct acpi_device *device, u32 event) |
| @@ -290,7 +317,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) | |||
| 290 | case ACPI_BUTTON_NOTIFY_STATUS: | 317 | case ACPI_BUTTON_NOTIFY_STATUS: |
| 291 | input = button->input; | 318 | input = button->input; |
| 292 | if (button->type == ACPI_BUTTON_TYPE_LID) { | 319 | if (button->type == ACPI_BUTTON_TYPE_LID) { |
| 293 | acpi_lid_send_state(device); | 320 | acpi_lid_update_state(device); |
| 294 | } else { | 321 | } else { |
| 295 | int keycode; | 322 | int keycode; |
| 296 | 323 | ||
| @@ -335,7 +362,7 @@ static int acpi_button_resume(struct device *dev) | |||
| 335 | 362 | ||
| 336 | button->suspended = false; | 363 | button->suspended = false; |
| 337 | if (button->type == ACPI_BUTTON_TYPE_LID) | 364 | if (button->type == ACPI_BUTTON_TYPE_LID) |
| 338 | return acpi_lid_send_state(device); | 365 | acpi_lid_initialize_state(device); |
| 339 | return 0; | 366 | return 0; |
| 340 | } | 367 | } |
| 341 | #endif | 368 | #endif |
| @@ -416,7 +443,7 @@ static int acpi_button_add(struct acpi_device *device) | |||
| 416 | if (error) | 443 | if (error) |
| 417 | goto err_remove_fs; | 444 | goto err_remove_fs; |
| 418 | if (button->type == ACPI_BUTTON_TYPE_LID) { | 445 | if (button->type == ACPI_BUTTON_TYPE_LID) { |
| 419 | acpi_lid_send_state(device); | 446 | acpi_lid_initialize_state(device); |
| 420 | /* | 447 | /* |
| 421 | * This assumes there's only one lid device, or if there are | 448 | * This assumes there's only one lid device, or if there are |
| 422 | * more we only care about the last one... | 449 | * more we only care about the last one... |
| @@ -446,4 +473,42 @@ static int acpi_button_remove(struct acpi_device *device) | |||
| 446 | return 0; | 473 | return 0; |
| 447 | } | 474 | } |
| 448 | 475 | ||
| 476 | static int param_set_lid_init_state(const char *val, struct kernel_param *kp) | ||
| 477 | { | ||
| 478 | int result = 0; | ||
| 479 | |||
| 480 | if (!strncmp(val, "open", sizeof("open") - 1)) { | ||
| 481 | lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; | ||
| 482 | pr_info("Notify initial lid state as open\n"); | ||
| 483 | } else if (!strncmp(val, "method", sizeof("method") - 1)) { | ||
| 484 | lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; | ||
| 485 | pr_info("Notify initial lid state with _LID return value\n"); | ||
| 486 | } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) { | ||
| 487 | lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE; | ||
| 488 | pr_info("Do not notify initial lid state\n"); | ||
| 489 | } else | ||
| 490 | result = -EINVAL; | ||
| 491 | return result; | ||
| 492 | } | ||
| 493 | |||
| 494 | static int param_get_lid_init_state(char *buffer, struct kernel_param *kp) | ||
| 495 | { | ||
| 496 | switch (lid_init_state) { | ||
| 497 | case ACPI_BUTTON_LID_INIT_OPEN: | ||
| 498 | return sprintf(buffer, "open"); | ||
| 499 | case ACPI_BUTTON_LID_INIT_METHOD: | ||
| 500 | return sprintf(buffer, "method"); | ||
| 501 | case ACPI_BUTTON_LID_INIT_IGNORE: | ||
| 502 | return sprintf(buffer, "ignore"); | ||
| 503 | default: | ||
| 504 | return sprintf(buffer, "invalid"); | ||
| 505 | } | ||
| 506 | return 0; | ||
| 507 | } | ||
| 508 | |||
| 509 | module_param_call(lid_init_state, | ||
| 510 | param_set_lid_init_state, param_get_lid_init_state, | ||
| 511 | NULL, 0644); | ||
| 512 | MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state"); | ||
| 513 | |||
| 449 | module_acpi_driver(acpi_button_driver); | 514 | module_acpi_driver(acpi_button_driver); |
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 8adac69dba3d..2e981732805b 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c | |||
| @@ -299,8 +299,10 @@ int acpi_get_psd_map(struct cpudata **all_cpu_data) | |||
| 299 | continue; | 299 | continue; |
| 300 | 300 | ||
| 301 | cpc_ptr = per_cpu(cpc_desc_ptr, i); | 301 | cpc_ptr = per_cpu(cpc_desc_ptr, i); |
| 302 | if (!cpc_ptr) | 302 | if (!cpc_ptr) { |
| 303 | continue; | 303 | retval = -EFAULT; |
| 304 | goto err_ret; | ||
| 305 | } | ||
| 304 | 306 | ||
| 305 | pdomain = &(cpc_ptr->domain_info); | 307 | pdomain = &(cpc_ptr->domain_info); |
| 306 | cpumask_set_cpu(i, pr->shared_cpu_map); | 308 | cpumask_set_cpu(i, pr->shared_cpu_map); |
| @@ -322,8 +324,10 @@ int acpi_get_psd_map(struct cpudata **all_cpu_data) | |||
| 322 | continue; | 324 | continue; |
| 323 | 325 | ||
| 324 | match_cpc_ptr = per_cpu(cpc_desc_ptr, j); | 326 | match_cpc_ptr = per_cpu(cpc_desc_ptr, j); |
| 325 | if (!match_cpc_ptr) | 327 | if (!match_cpc_ptr) { |
| 326 | continue; | 328 | retval = -EFAULT; |
| 329 | goto err_ret; | ||
| 330 | } | ||
| 327 | 331 | ||
| 328 | match_pdomain = &(match_cpc_ptr->domain_info); | 332 | match_pdomain = &(match_cpc_ptr->domain_info); |
| 329 | if (match_pdomain->domain != pdomain->domain) | 333 | if (match_pdomain->domain != pdomain->domain) |
| @@ -353,8 +357,10 @@ int acpi_get_psd_map(struct cpudata **all_cpu_data) | |||
| 353 | continue; | 357 | continue; |
| 354 | 358 | ||
| 355 | match_cpc_ptr = per_cpu(cpc_desc_ptr, j); | 359 | match_cpc_ptr = per_cpu(cpc_desc_ptr, j); |
| 356 | if (!match_cpc_ptr) | 360 | if (!match_cpc_ptr) { |
| 357 | continue; | 361 | retval = -EFAULT; |
| 362 | goto err_ret; | ||
| 363 | } | ||
| 358 | 364 | ||
| 359 | match_pdomain = &(match_cpc_ptr->domain_info); | 365 | match_pdomain = &(match_cpc_ptr->domain_info); |
| 360 | if (match_pdomain->domain != pdomain->domain) | 366 | if (match_pdomain->domain != pdomain->domain) |
| @@ -595,9 +601,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) | |||
| 595 | /* Store CPU Logical ID */ | 601 | /* Store CPU Logical ID */ |
| 596 | cpc_ptr->cpu_id = pr->id; | 602 | cpc_ptr->cpu_id = pr->id; |
| 597 | 603 | ||
| 598 | /* Plug it into this CPUs CPC descriptor. */ | ||
| 599 | per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr; | ||
| 600 | |||
| 601 | /* Parse PSD data for this CPU */ | 604 | /* Parse PSD data for this CPU */ |
| 602 | ret = acpi_get_psd(cpc_ptr, handle); | 605 | ret = acpi_get_psd(cpc_ptr, handle); |
| 603 | if (ret) | 606 | if (ret) |
| @@ -610,6 +613,9 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) | |||
| 610 | goto out_free; | 613 | goto out_free; |
| 611 | } | 614 | } |
| 612 | 615 | ||
| 616 | /* Plug PSD data into this CPUs CPC descriptor. */ | ||
| 617 | per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr; | ||
| 618 | |||
| 613 | /* Everything looks okay */ | 619 | /* Everything looks okay */ |
| 614 | pr_debug("Parsed CPC struct for CPU: %d\n", pr->id); | 620 | pr_debug("Parsed CPC struct for CPU: %d\n", pr->id); |
| 615 | 621 | ||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index e8e128dede29..0c00208b423e 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| 24 | #include <linux/module.h> | 24 | #include <linux/moduleparam.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
| @@ -33,12 +33,7 @@ | |||
| 33 | 33 | ||
| 34 | #include "internal.h" | 34 | #include "internal.h" |
| 35 | 35 | ||
| 36 | #define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" | ||
| 37 | |||
| 38 | ACPI_MODULE_NAME("dock"); | 36 | ACPI_MODULE_NAME("dock"); |
| 39 | MODULE_AUTHOR("Kristen Carlson Accardi"); | ||
| 40 | MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); | ||
| 41 | MODULE_LICENSE("GPL"); | ||
| 42 | 37 | ||
| 43 | static bool immediate_undock = 1; | 38 | static bool immediate_undock = 1; |
| 44 | module_param(immediate_undock, bool, 0644); | 39 | module_param(immediate_undock, bool, 0644); |
diff --git a/drivers/acpi/dptf/Kconfig b/drivers/acpi/dptf/Kconfig new file mode 100644 index 000000000000..ac0a6ed0cf46 --- /dev/null +++ b/drivers/acpi/dptf/Kconfig | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | config DPTF_POWER | ||
| 2 | tristate "DPTF Platform Power Participant" | ||
| 3 | depends on X86 | ||
| 4 | help | ||
| 5 | This driver adds support for Dynamic Platform and Thermal Framework | ||
| 6 | (DPTF) Platform Power Participant device (INT3407) support. | ||
| 7 | This participant is responsible for exposing platform telemetry: | ||
| 8 | max_platform_power | ||
| 9 | platform_power_source | ||
| 10 | adapter_rating | ||
| 11 | battery_steady_power | ||
| 12 | charger_type | ||
| 13 | |||
| 14 | To compile this driver as a module, choose M here: | ||
| 15 | the module will be called dptf_power. | ||
diff --git a/drivers/acpi/dptf/Makefile b/drivers/acpi/dptf/Makefile new file mode 100644 index 000000000000..06ea8809583d --- /dev/null +++ b/drivers/acpi/dptf/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | obj-$(CONFIG_ACPI) += int340x_thermal.o | ||
| 2 | obj-$(CONFIG_DPTF_POWER) += dptf_power.o | ||
| 3 | |||
| 4 | ccflags-y += -Idrivers/acpi | ||
diff --git a/drivers/acpi/dptf/dptf_power.c b/drivers/acpi/dptf/dptf_power.c new file mode 100644 index 000000000000..734642dc5008 --- /dev/null +++ b/drivers/acpi/dptf/dptf_power.c | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | /* | ||
| 2 | * dptf_power: DPTF platform power driver | ||
| 3 | * Copyright (c) 2016, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/acpi.h> | ||
| 19 | #include <linux/platform_device.h> | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Presentation of attributes which are defined for INT3407. They are: | ||
| 23 | * PMAX : Maximum platform powe | ||
| 24 | * PSRC : Platform power source | ||
| 25 | * ARTG : Adapter rating | ||
| 26 | * CTYP : Charger type | ||
| 27 | * PBSS : Battery steady power | ||
| 28 | */ | ||
| 29 | #define DPTF_POWER_SHOW(name, object) \ | ||
| 30 | static ssize_t name##_show(struct device *dev,\ | ||
| 31 | struct device_attribute *attr,\ | ||
| 32 | char *buf)\ | ||
| 33 | {\ | ||
| 34 | struct platform_device *pdev = to_platform_device(dev);\ | ||
| 35 | struct acpi_device *acpi_dev = platform_get_drvdata(pdev);\ | ||
| 36 | unsigned long long val;\ | ||
| 37 | acpi_status status;\ | ||
| 38 | \ | ||
| 39 | status = acpi_evaluate_integer(acpi_dev->handle, #object,\ | ||
| 40 | NULL, &val);\ | ||
| 41 | if (ACPI_SUCCESS(status))\ | ||
| 42 | return sprintf(buf, "%d\n", (int)val);\ | ||
| 43 | else \ | ||
| 44 | return -EINVAL;\ | ||
| 45 | } | ||
| 46 | |||
| 47 | DPTF_POWER_SHOW(max_platform_power_mw, PMAX) | ||
| 48 | DPTF_POWER_SHOW(platform_power_source, PSRC) | ||
| 49 | DPTF_POWER_SHOW(adapter_rating_mw, ARTG) | ||
| 50 | DPTF_POWER_SHOW(battery_steady_power_mw, PBSS) | ||
| 51 | DPTF_POWER_SHOW(charger_type, CTYP) | ||
| 52 | |||
| 53 | static DEVICE_ATTR_RO(max_platform_power_mw); | ||
| 54 | static DEVICE_ATTR_RO(platform_power_source); | ||
| 55 | static DEVICE_ATTR_RO(adapter_rating_mw); | ||
| 56 | static DEVICE_ATTR_RO(battery_steady_power_mw); | ||
| 57 | static DEVICE_ATTR_RO(charger_type); | ||
| 58 | |||
| 59 | static struct attribute *dptf_power_attrs[] = { | ||
| 60 | &dev_attr_max_platform_power_mw.attr, | ||
| 61 | &dev_attr_platform_power_source.attr, | ||
| 62 | &dev_attr_adapter_rating_mw.attr, | ||
| 63 | &dev_attr_battery_steady_power_mw.attr, | ||
| 64 | &dev_attr_charger_type.attr, | ||
| 65 | NULL | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct attribute_group dptf_power_attribute_group = { | ||
| 69 | .attrs = dptf_power_attrs, | ||
| 70 | .name = "dptf_power" | ||
| 71 | }; | ||
| 72 | |||
| 73 | static int dptf_power_add(struct platform_device *pdev) | ||
| 74 | { | ||
| 75 | struct acpi_device *acpi_dev; | ||
| 76 | acpi_status status; | ||
| 77 | unsigned long long ptype; | ||
| 78 | int result; | ||
| 79 | |||
| 80 | acpi_dev = ACPI_COMPANION(&(pdev->dev)); | ||
| 81 | if (!acpi_dev) | ||
| 82 | return -ENODEV; | ||
| 83 | |||
| 84 | status = acpi_evaluate_integer(acpi_dev->handle, "PTYP", NULL, &ptype); | ||
| 85 | if (ACPI_FAILURE(status)) | ||
| 86 | return -ENODEV; | ||
| 87 | |||
| 88 | if (ptype != 0x11) | ||
| 89 | return -ENODEV; | ||
| 90 | |||
| 91 | result = sysfs_create_group(&pdev->dev.kobj, | ||
| 92 | &dptf_power_attribute_group); | ||
| 93 | if (result) | ||
| 94 | return result; | ||
| 95 | |||
| 96 | platform_set_drvdata(pdev, acpi_dev); | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int dptf_power_remove(struct platform_device *pdev) | ||
| 102 | { | ||
| 103 | |||
| 104 | sysfs_remove_group(&pdev->dev.kobj, &dptf_power_attribute_group); | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | static const struct acpi_device_id int3407_device_ids[] = { | ||
| 110 | {"INT3407", 0}, | ||
| 111 | {"", 0}, | ||
| 112 | }; | ||
| 113 | MODULE_DEVICE_TABLE(acpi, int3407_device_ids); | ||
| 114 | |||
| 115 | static struct platform_driver dptf_power_driver = { | ||
| 116 | .probe = dptf_power_add, | ||
| 117 | .remove = dptf_power_remove, | ||
| 118 | .driver = { | ||
| 119 | .name = "DPTF Platform Power", | ||
| 120 | .acpi_match_table = int3407_device_ids, | ||
| 121 | }, | ||
| 122 | }; | ||
| 123 | |||
| 124 | module_platform_driver(dptf_power_driver); | ||
| 125 | |||
| 126 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | ||
| 127 | MODULE_LICENSE("GPL v2"); | ||
| 128 | MODULE_DESCRIPTION("ACPI DPTF platform power driver"); | ||
diff --git a/drivers/acpi/int340x_thermal.c b/drivers/acpi/dptf/int340x_thermal.c index 33505c651f62..33505c651f62 100644 --- a/drivers/acpi/int340x_thermal.c +++ b/drivers/acpi/dptf/int340x_thermal.c | |||
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 290d6f5be44b..999a10914678 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
| @@ -1359,13 +1359,9 @@ static void ec_remove_handlers(struct acpi_ec *ec) | |||
| 1359 | } | 1359 | } |
| 1360 | } | 1360 | } |
| 1361 | 1361 | ||
| 1362 | static int acpi_ec_add(struct acpi_device *device) | 1362 | static struct acpi_ec *acpi_ec_alloc(void) |
| 1363 | { | 1363 | { |
| 1364 | struct acpi_ec *ec = NULL; | 1364 | struct acpi_ec *ec; |
| 1365 | int ret; | ||
| 1366 | |||
| 1367 | strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); | ||
| 1368 | strcpy(acpi_device_class(device), ACPI_EC_CLASS); | ||
| 1369 | 1365 | ||
| 1370 | /* Check for boot EC */ | 1366 | /* Check for boot EC */ |
| 1371 | if (boot_ec) { | 1367 | if (boot_ec) { |
| @@ -1376,9 +1372,21 @@ static int acpi_ec_add(struct acpi_device *device) | |||
| 1376 | first_ec = NULL; | 1372 | first_ec = NULL; |
| 1377 | } else { | 1373 | } else { |
| 1378 | ec = make_acpi_ec(); | 1374 | ec = make_acpi_ec(); |
| 1379 | if (!ec) | ||
| 1380 | return -ENOMEM; | ||
| 1381 | } | 1375 | } |
| 1376 | return ec; | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | static int acpi_ec_add(struct acpi_device *device) | ||
| 1380 | { | ||
| 1381 | struct acpi_ec *ec = NULL; | ||
| 1382 | int ret; | ||
| 1383 | |||
| 1384 | strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME); | ||
| 1385 | strcpy(acpi_device_class(device), ACPI_EC_CLASS); | ||
| 1386 | |||
| 1387 | ec = acpi_ec_alloc(); | ||
| 1388 | if (!ec) | ||
| 1389 | return -ENOMEM; | ||
| 1382 | if (ec_parse_device(device->handle, 0, ec, NULL) != | 1390 | if (ec_parse_device(device->handle, 0, ec, NULL) != |
| 1383 | AE_CTRL_TERMINATE) { | 1391 | AE_CTRL_TERMINATE) { |
| 1384 | kfree(ec); | 1392 | kfree(ec); |
| @@ -1465,27 +1473,31 @@ static const struct acpi_device_id ec_device_ids[] = { | |||
| 1465 | int __init acpi_ec_dsdt_probe(void) | 1473 | int __init acpi_ec_dsdt_probe(void) |
| 1466 | { | 1474 | { |
| 1467 | acpi_status status; | 1475 | acpi_status status; |
| 1476 | struct acpi_ec *ec; | ||
| 1477 | int ret; | ||
| 1468 | 1478 | ||
| 1469 | if (boot_ec) | 1479 | ec = acpi_ec_alloc(); |
| 1470 | return 0; | 1480 | if (!ec) |
| 1471 | 1481 | return -ENOMEM; | |
| 1472 | /* | 1482 | /* |
| 1473 | * Finding EC from DSDT if there is no ECDT EC available. When this | 1483 | * Finding EC from DSDT if there is no ECDT EC available. When this |
| 1474 | * function is invoked, ACPI tables have been fully loaded, we can | 1484 | * function is invoked, ACPI tables have been fully loaded, we can |
| 1475 | * walk namespace now. | 1485 | * walk namespace now. |
| 1476 | */ | 1486 | */ |
| 1477 | boot_ec = make_acpi_ec(); | ||
| 1478 | if (!boot_ec) | ||
| 1479 | return -ENOMEM; | ||
| 1480 | status = acpi_get_devices(ec_device_ids[0].id, | 1487 | status = acpi_get_devices(ec_device_ids[0].id, |
| 1481 | ec_parse_device, boot_ec, NULL); | 1488 | ec_parse_device, ec, NULL); |
| 1482 | if (ACPI_FAILURE(status) || !boot_ec->handle) | 1489 | if (ACPI_FAILURE(status) || !ec->handle) { |
| 1483 | return -ENODEV; | 1490 | ret = -ENODEV; |
| 1484 | if (!ec_install_handlers(boot_ec)) { | 1491 | goto error; |
| 1485 | first_ec = boot_ec; | ||
| 1486 | return 0; | ||
| 1487 | } | 1492 | } |
| 1488 | return -EFAULT; | 1493 | ret = ec_install_handlers(ec); |
| 1494 | |||
| 1495 | error: | ||
| 1496 | if (ret) | ||
| 1497 | kfree(ec); | ||
| 1498 | else | ||
| 1499 | first_ec = boot_ec = ec; | ||
| 1500 | return ret; | ||
| 1489 | } | 1501 | } |
| 1490 | 1502 | ||
| 1491 | #if 0 | 1503 | #if 0 |
| @@ -1529,6 +1541,11 @@ static int ec_clear_on_resume(const struct dmi_system_id *id) | |||
| 1529 | return 0; | 1541 | return 0; |
| 1530 | } | 1542 | } |
| 1531 | 1543 | ||
| 1544 | /* | ||
| 1545 | * Some ECDTs contain wrong register addresses. | ||
| 1546 | * MSI MS-171F | ||
| 1547 | * https://bugzilla.kernel.org/show_bug.cgi?id=12461 | ||
| 1548 | */ | ||
| 1532 | static int ec_correct_ecdt(const struct dmi_system_id *id) | 1549 | static int ec_correct_ecdt(const struct dmi_system_id *id) |
| 1533 | { | 1550 | { |
| 1534 | pr_debug("Detected system needing ECDT address correction.\n"); | 1551 | pr_debug("Detected system needing ECDT address correction.\n"); |
| @@ -1538,16 +1555,6 @@ static int ec_correct_ecdt(const struct dmi_system_id *id) | |||
| 1538 | 1555 | ||
| 1539 | static struct dmi_system_id ec_dmi_table[] __initdata = { | 1556 | static struct dmi_system_id ec_dmi_table[] __initdata = { |
| 1540 | { | 1557 | { |
| 1541 | ec_correct_ecdt, "Asus L4R", { | ||
| 1542 | DMI_MATCH(DMI_BIOS_VERSION, "1008.006"), | ||
| 1543 | DMI_MATCH(DMI_PRODUCT_NAME, "L4R"), | ||
| 1544 | DMI_MATCH(DMI_BOARD_NAME, "L4R") }, NULL}, | ||
| 1545 | { | ||
| 1546 | ec_correct_ecdt, "Asus M6R", { | ||
| 1547 | DMI_MATCH(DMI_BIOS_VERSION, "0207"), | ||
| 1548 | DMI_MATCH(DMI_PRODUCT_NAME, "M6R"), | ||
| 1549 | DMI_MATCH(DMI_BOARD_NAME, "M6R") }, NULL}, | ||
| 1550 | { | ||
| 1551 | ec_correct_ecdt, "MSI MS-171F", { | 1558 | ec_correct_ecdt, "MSI MS-171F", { |
| 1552 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"), | 1559 | DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"), |
| 1553 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL}, | 1560 | DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL}, |
| @@ -1559,12 +1566,13 @@ static struct dmi_system_id ec_dmi_table[] __initdata = { | |||
| 1559 | 1566 | ||
| 1560 | int __init acpi_ec_ecdt_probe(void) | 1567 | int __init acpi_ec_ecdt_probe(void) |
| 1561 | { | 1568 | { |
| 1562 | int ret = 0; | 1569 | int ret; |
| 1563 | acpi_status status; | 1570 | acpi_status status; |
| 1564 | struct acpi_table_ecdt *ecdt_ptr; | 1571 | struct acpi_table_ecdt *ecdt_ptr; |
| 1572 | struct acpi_ec *ec; | ||
| 1565 | 1573 | ||
| 1566 | boot_ec = make_acpi_ec(); | 1574 | ec = acpi_ec_alloc(); |
| 1567 | if (!boot_ec) | 1575 | if (!ec) |
| 1568 | return -ENOMEM; | 1576 | return -ENOMEM; |
| 1569 | /* | 1577 | /* |
| 1570 | * Generate a boot ec context | 1578 | * Generate a boot ec context |
| @@ -1588,28 +1596,20 @@ int __init acpi_ec_ecdt_probe(void) | |||
| 1588 | 1596 | ||
| 1589 | pr_info("EC description table is found, configuring boot EC\n"); | 1597 | pr_info("EC description table is found, configuring boot EC\n"); |
| 1590 | if (EC_FLAGS_CORRECT_ECDT) { | 1598 | if (EC_FLAGS_CORRECT_ECDT) { |
| 1591 | /* | 1599 | ec->command_addr = ecdt_ptr->data.address; |
| 1592 | * Asus L4R, Asus M6R | 1600 | ec->data_addr = ecdt_ptr->control.address; |
| 1593 | * https://bugzilla.kernel.org/show_bug.cgi?id=9399 | ||
| 1594 | * MSI MS-171F | ||
| 1595 | * https://bugzilla.kernel.org/show_bug.cgi?id=12461 | ||
| 1596 | */ | ||
| 1597 | boot_ec->command_addr = ecdt_ptr->data.address; | ||
| 1598 | boot_ec->data_addr = ecdt_ptr->control.address; | ||
| 1599 | } else { | 1601 | } else { |
| 1600 | boot_ec->command_addr = ecdt_ptr->control.address; | 1602 | ec->command_addr = ecdt_ptr->control.address; |
| 1601 | boot_ec->data_addr = ecdt_ptr->data.address; | 1603 | ec->data_addr = ecdt_ptr->data.address; |
| 1602 | } | 1604 | } |
| 1603 | boot_ec->gpe = ecdt_ptr->gpe; | 1605 | ec->gpe = ecdt_ptr->gpe; |
| 1604 | boot_ec->handle = ACPI_ROOT_OBJECT; | 1606 | ec->handle = ACPI_ROOT_OBJECT; |
| 1605 | ret = ec_install_handlers(boot_ec); | 1607 | ret = ec_install_handlers(ec); |
| 1606 | if (!ret) | ||
| 1607 | first_ec = boot_ec; | ||
| 1608 | error: | 1608 | error: |
| 1609 | if (ret) { | 1609 | if (ret) |
| 1610 | kfree(boot_ec); | 1610 | kfree(ec); |
| 1611 | boot_ec = NULL; | 1611 | else |
| 1612 | } | 1612 | first_ec = boot_ec = ec; |
| 1613 | return ret; | 1613 | return ret; |
| 1614 | } | 1614 | } |
| 1615 | 1615 | ||
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 27cc7feabfe4..940218ff0193 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
| @@ -87,6 +87,9 @@ bool acpi_queue_hotplug_work(struct work_struct *work); | |||
| 87 | void acpi_device_hotplug(struct acpi_device *adev, u32 src); | 87 | void acpi_device_hotplug(struct acpi_device *adev, u32 src); |
| 88 | bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); | 88 | bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); |
| 89 | 89 | ||
| 90 | acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context); | ||
| 91 | void acpi_scan_table_handler(u32 event, void *table, void *context); | ||
| 92 | |||
| 90 | /* -------------------------------------------------------------------------- | 93 | /* -------------------------------------------------------------------------- |
| 91 | Device Node Initialization / Removal | 94 | Device Node Initialization / Removal |
| 92 | -------------------------------------------------------------------------- */ | 95 | -------------------------------------------------------------------------- */ |
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index d176e0ece470..ce3a7a16f03f 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c | |||
| @@ -18,22 +18,21 @@ | |||
| 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 19 | * | 19 | * |
| 20 | */ | 20 | */ |
| 21 | |||
| 22 | #define pr_fmt(fmt) "ACPI: " fmt | ||
| 23 | |||
| 21 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 22 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 23 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
| 24 | #include <linux/types.h> | 27 | #include <linux/types.h> |
| 25 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
| 26 | #include <linux/acpi.h> | 29 | #include <linux/acpi.h> |
| 30 | #include <linux/bootmem.h> | ||
| 31 | #include <linux/memblock.h> | ||
| 27 | #include <linux/numa.h> | 32 | #include <linux/numa.h> |
| 28 | #include <linux/nodemask.h> | 33 | #include <linux/nodemask.h> |
| 29 | #include <linux/topology.h> | 34 | #include <linux/topology.h> |
| 30 | 35 | ||
| 31 | #define PREFIX "ACPI: " | ||
| 32 | |||
| 33 | #define ACPI_NUMA 0x80000000 | ||
| 34 | #define _COMPONENT ACPI_NUMA | ||
| 35 | ACPI_MODULE_NAME("numa"); | ||
| 36 | |||
| 37 | static nodemask_t nodes_found_map = NODE_MASK_NONE; | 36 | static nodemask_t nodes_found_map = NODE_MASK_NONE; |
| 38 | 37 | ||
| 39 | /* maps to convert between proximity domain and logical node ID */ | 38 | /* maps to convert between proximity domain and logical node ID */ |
| @@ -43,6 +42,7 @@ static int node_to_pxm_map[MAX_NUMNODES] | |||
| 43 | = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; | 42 | = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; |
| 44 | 43 | ||
| 45 | unsigned char acpi_srat_revision __initdata; | 44 | unsigned char acpi_srat_revision __initdata; |
| 45 | int acpi_numa __initdata; | ||
| 46 | 46 | ||
| 47 | int pxm_to_node(int pxm) | 47 | int pxm_to_node(int pxm) |
| 48 | { | 48 | { |
| @@ -128,68 +128,63 @@ EXPORT_SYMBOL(acpi_map_pxm_to_online_node); | |||
| 128 | static void __init | 128 | static void __init |
| 129 | acpi_table_print_srat_entry(struct acpi_subtable_header *header) | 129 | acpi_table_print_srat_entry(struct acpi_subtable_header *header) |
| 130 | { | 130 | { |
| 131 | |||
| 132 | ACPI_FUNCTION_NAME("acpi_table_print_srat_entry"); | ||
| 133 | |||
| 134 | if (!header) | ||
| 135 | return; | ||
| 136 | |||
| 137 | switch (header->type) { | 131 | switch (header->type) { |
| 138 | |||
| 139 | case ACPI_SRAT_TYPE_CPU_AFFINITY: | 132 | case ACPI_SRAT_TYPE_CPU_AFFINITY: |
| 140 | #ifdef ACPI_DEBUG_OUTPUT | ||
| 141 | { | 133 | { |
| 142 | struct acpi_srat_cpu_affinity *p = | 134 | struct acpi_srat_cpu_affinity *p = |
| 143 | (struct acpi_srat_cpu_affinity *)header; | 135 | (struct acpi_srat_cpu_affinity *)header; |
| 144 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 136 | pr_debug("SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", |
| 145 | "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n", | 137 | p->apic_id, p->local_sapic_eid, |
| 146 | p->apic_id, p->local_sapic_eid, | 138 | p->proximity_domain_lo, |
| 147 | p->proximity_domain_lo, | 139 | (p->flags & ACPI_SRAT_CPU_ENABLED) ? |
| 148 | (p->flags & ACPI_SRAT_CPU_ENABLED)? | 140 | "enabled" : "disabled"); |
| 149 | "enabled" : "disabled")); | ||
| 150 | } | 141 | } |
| 151 | #endif /* ACPI_DEBUG_OUTPUT */ | ||
| 152 | break; | 142 | break; |
| 153 | 143 | ||
| 154 | case ACPI_SRAT_TYPE_MEMORY_AFFINITY: | 144 | case ACPI_SRAT_TYPE_MEMORY_AFFINITY: |
| 155 | #ifdef ACPI_DEBUG_OUTPUT | ||
| 156 | { | 145 | { |
| 157 | struct acpi_srat_mem_affinity *p = | 146 | struct acpi_srat_mem_affinity *p = |
| 158 | (struct acpi_srat_mem_affinity *)header; | 147 | (struct acpi_srat_mem_affinity *)header; |
| 159 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 148 | pr_debug("SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s%s\n", |
| 160 | "SRAT Memory (0x%lx length 0x%lx) in proximity domain %d %s%s%s\n", | 149 | (unsigned long)p->base_address, |
| 161 | (unsigned long)p->base_address, | 150 | (unsigned long)p->length, |
| 162 | (unsigned long)p->length, | 151 | p->proximity_domain, |
| 163 | p->proximity_domain, | 152 | (p->flags & ACPI_SRAT_MEM_ENABLED) ? |
| 164 | (p->flags & ACPI_SRAT_MEM_ENABLED)? | 153 | "enabled" : "disabled", |
| 165 | "enabled" : "disabled", | 154 | (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ? |
| 166 | (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)? | 155 | " hot-pluggable" : "", |
| 167 | " hot-pluggable" : "", | 156 | (p->flags & ACPI_SRAT_MEM_NON_VOLATILE) ? |
| 168 | (p->flags & ACPI_SRAT_MEM_NON_VOLATILE)? | 157 | " non-volatile" : ""); |
| 169 | " non-volatile" : "")); | ||
| 170 | } | 158 | } |
| 171 | #endif /* ACPI_DEBUG_OUTPUT */ | ||
| 172 | break; | 159 | break; |
| 173 | 160 | ||
| 174 | case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: | 161 | case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: |
| 175 | #ifdef ACPI_DEBUG_OUTPUT | ||
| 176 | { | 162 | { |
| 177 | struct acpi_srat_x2apic_cpu_affinity *p = | 163 | struct acpi_srat_x2apic_cpu_affinity *p = |
| 178 | (struct acpi_srat_x2apic_cpu_affinity *)header; | 164 | (struct acpi_srat_x2apic_cpu_affinity *)header; |
| 179 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 165 | pr_debug("SRAT Processor (x2apicid[0x%08x]) in proximity domain %d %s\n", |
| 180 | "SRAT Processor (x2apicid[0x%08x]) in" | 166 | p->apic_id, |
| 181 | " proximity domain %d %s\n", | 167 | p->proximity_domain, |
| 182 | p->apic_id, | 168 | (p->flags & ACPI_SRAT_CPU_ENABLED) ? |
| 183 | p->proximity_domain, | 169 | "enabled" : "disabled"); |
| 184 | (p->flags & ACPI_SRAT_CPU_ENABLED) ? | ||
| 185 | "enabled" : "disabled")); | ||
| 186 | } | 170 | } |
| 187 | #endif /* ACPI_DEBUG_OUTPUT */ | ||
| 188 | break; | 171 | break; |
| 172 | |||
| 173 | case ACPI_SRAT_TYPE_GICC_AFFINITY: | ||
| 174 | { | ||
| 175 | struct acpi_srat_gicc_affinity *p = | ||
| 176 | (struct acpi_srat_gicc_affinity *)header; | ||
| 177 | pr_debug("SRAT Processor (acpi id[0x%04x]) in proximity domain %d %s\n", | ||
| 178 | p->acpi_processor_uid, | ||
| 179 | p->proximity_domain, | ||
| 180 | (p->flags & ACPI_SRAT_GICC_ENABLED) ? | ||
| 181 | "enabled" : "disabled"); | ||
| 182 | } | ||
| 183 | break; | ||
| 184 | |||
| 189 | default: | 185 | default: |
| 190 | printk(KERN_WARNING PREFIX | 186 | pr_warn("Found unsupported SRAT entry (type = 0x%x)\n", |
| 191 | "Found unsupported SRAT entry (type = 0x%x)\n", | 187 | header->type); |
| 192 | header->type); | ||
| 193 | break; | 188 | break; |
| 194 | } | 189 | } |
| 195 | } | 190 | } |
| @@ -217,12 +212,117 @@ static int __init slit_valid(struct acpi_table_slit *slit) | |||
| 217 | return 1; | 212 | return 1; |
| 218 | } | 213 | } |
| 219 | 214 | ||
| 215 | void __init bad_srat(void) | ||
| 216 | { | ||
| 217 | pr_err("SRAT: SRAT not used.\n"); | ||
| 218 | acpi_numa = -1; | ||
| 219 | } | ||
| 220 | |||
| 221 | int __init srat_disabled(void) | ||
| 222 | { | ||
| 223 | return acpi_numa < 0; | ||
| 224 | } | ||
| 225 | |||
| 226 | #if defined(CONFIG_X86) || defined(CONFIG_ARM64) | ||
| 227 | /* | ||
| 228 | * Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for | ||
| 229 | * I/O localities since SRAT does not list them. I/O localities are | ||
| 230 | * not supported at this point. | ||
| 231 | */ | ||
| 232 | void __init acpi_numa_slit_init(struct acpi_table_slit *slit) | ||
| 233 | { | ||
| 234 | int i, j; | ||
| 235 | |||
| 236 | for (i = 0; i < slit->locality_count; i++) { | ||
| 237 | const int from_node = pxm_to_node(i); | ||
| 238 | |||
| 239 | if (from_node == NUMA_NO_NODE) | ||
| 240 | continue; | ||
| 241 | |||
| 242 | for (j = 0; j < slit->locality_count; j++) { | ||
| 243 | const int to_node = pxm_to_node(j); | ||
| 244 | |||
| 245 | if (to_node == NUMA_NO_NODE) | ||
| 246 | continue; | ||
| 247 | |||
| 248 | numa_set_distance(from_node, to_node, | ||
| 249 | slit->entry[slit->locality_count * i + j]); | ||
| 250 | } | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | /* | ||
| 255 | * Default callback for parsing of the Proximity Domain <-> Memory | ||
| 256 | * Area mappings | ||
| 257 | */ | ||
| 258 | int __init | ||
| 259 | acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) | ||
| 260 | { | ||
| 261 | u64 start, end; | ||
| 262 | u32 hotpluggable; | ||
| 263 | int node, pxm; | ||
| 264 | |||
| 265 | if (srat_disabled()) | ||
| 266 | goto out_err; | ||
| 267 | if (ma->header.length < sizeof(struct acpi_srat_mem_affinity)) { | ||
| 268 | pr_err("SRAT: Unexpected header length: %d\n", | ||
| 269 | ma->header.length); | ||
| 270 | goto out_err_bad_srat; | ||
| 271 | } | ||
| 272 | if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0) | ||
| 273 | goto out_err; | ||
| 274 | hotpluggable = ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE; | ||
| 275 | if (hotpluggable && !IS_ENABLED(CONFIG_MEMORY_HOTPLUG)) | ||
| 276 | goto out_err; | ||
| 277 | |||
| 278 | start = ma->base_address; | ||
| 279 | end = start + ma->length; | ||
| 280 | pxm = ma->proximity_domain; | ||
| 281 | if (acpi_srat_revision <= 1) | ||
| 282 | pxm &= 0xff; | ||
| 283 | |||
| 284 | node = acpi_map_pxm_to_node(pxm); | ||
| 285 | if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) { | ||
| 286 | pr_err("SRAT: Too many proximity domains.\n"); | ||
| 287 | goto out_err_bad_srat; | ||
| 288 | } | ||
| 289 | |||
| 290 | if (numa_add_memblk(node, start, end) < 0) { | ||
| 291 | pr_err("SRAT: Failed to add memblk to node %u [mem %#010Lx-%#010Lx]\n", | ||
| 292 | node, (unsigned long long) start, | ||
| 293 | (unsigned long long) end - 1); | ||
| 294 | goto out_err_bad_srat; | ||
| 295 | } | ||
| 296 | |||
| 297 | node_set(node, numa_nodes_parsed); | ||
| 298 | |||
| 299 | pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n", | ||
| 300 | node, pxm, | ||
| 301 | (unsigned long long) start, (unsigned long long) end - 1, | ||
| 302 | hotpluggable ? " hotplug" : "", | ||
| 303 | ma->flags & ACPI_SRAT_MEM_NON_VOLATILE ? " non-volatile" : ""); | ||
| 304 | |||
| 305 | /* Mark hotplug range in memblock. */ | ||
| 306 | if (hotpluggable && memblock_mark_hotplug(start, ma->length)) | ||
| 307 | pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n", | ||
| 308 | (unsigned long long)start, (unsigned long long)end - 1); | ||
| 309 | |||
| 310 | max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1)); | ||
| 311 | |||
| 312 | return 0; | ||
| 313 | out_err_bad_srat: | ||
| 314 | bad_srat(); | ||
| 315 | out_err: | ||
| 316 | return -EINVAL; | ||
| 317 | } | ||
| 318 | #endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */ | ||
| 319 | |||
| 220 | static int __init acpi_parse_slit(struct acpi_table_header *table) | 320 | static int __init acpi_parse_slit(struct acpi_table_header *table) |
| 221 | { | 321 | { |
| 222 | struct acpi_table_slit *slit = (struct acpi_table_slit *)table; | 322 | struct acpi_table_slit *slit = (struct acpi_table_slit *)table; |
| 223 | 323 | ||
| 224 | if (!slit_valid(slit)) { | 324 | if (!slit_valid(slit)) { |
| 225 | printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n"); | 325 | pr_info("SLIT table looks invalid. Not used.\n"); |
| 226 | return -EINVAL; | 326 | return -EINVAL; |
| 227 | } | 327 | } |
| 228 | acpi_numa_slit_init(slit); | 328 | acpi_numa_slit_init(slit); |
| @@ -233,12 +333,9 @@ static int __init acpi_parse_slit(struct acpi_table_header *table) | |||
| 233 | void __init __weak | 333 | void __init __weak |
| 234 | acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) | 334 | acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) |
| 235 | { | 335 | { |
| 236 | printk(KERN_WARNING PREFIX | 336 | pr_warn("Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id); |
| 237 | "Found unsupported x2apic [0x%08x] SRAT entry\n", pa->apic_id); | ||
| 238 | return; | ||
| 239 | } | 337 | } |
| 240 | 338 | ||
| 241 | |||
| 242 | static int __init | 339 | static int __init |
| 243 | acpi_parse_x2apic_affinity(struct acpi_subtable_header *header, | 340 | acpi_parse_x2apic_affinity(struct acpi_subtable_header *header, |
| 244 | const unsigned long end) | 341 | const unsigned long end) |
| @@ -275,6 +372,24 @@ acpi_parse_processor_affinity(struct acpi_subtable_header *header, | |||
| 275 | return 0; | 372 | return 0; |
| 276 | } | 373 | } |
| 277 | 374 | ||
| 375 | static int __init | ||
| 376 | acpi_parse_gicc_affinity(struct acpi_subtable_header *header, | ||
| 377 | const unsigned long end) | ||
| 378 | { | ||
| 379 | struct acpi_srat_gicc_affinity *processor_affinity; | ||
| 380 | |||
| 381 | processor_affinity = (struct acpi_srat_gicc_affinity *)header; | ||
| 382 | if (!processor_affinity) | ||
| 383 | return -EINVAL; | ||
| 384 | |||
| 385 | acpi_table_print_srat_entry(header); | ||
| 386 | |||
| 387 | /* let architecture-dependent part to do it */ | ||
| 388 | acpi_numa_gicc_affinity_init(processor_affinity); | ||
| 389 | |||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 278 | static int __initdata parsed_numa_memblks; | 393 | static int __initdata parsed_numa_memblks; |
| 279 | 394 | ||
| 280 | static int __init | 395 | static int __init |
| @@ -319,6 +434,9 @@ int __init acpi_numa_init(void) | |||
| 319 | { | 434 | { |
| 320 | int cnt = 0; | 435 | int cnt = 0; |
| 321 | 436 | ||
| 437 | if (acpi_disabled) | ||
| 438 | return -EINVAL; | ||
| 439 | |||
| 322 | /* | 440 | /* |
| 323 | * Should not limit number with cpu num that is from NR_CPUS or nr_cpus= | 441 | * Should not limit number with cpu num that is from NR_CPUS or nr_cpus= |
| 324 | * SRAT cpu entries could have different order with that in MADT. | 442 | * SRAT cpu entries could have different order with that in MADT. |
| @@ -327,13 +445,15 @@ int __init acpi_numa_init(void) | |||
| 327 | 445 | ||
| 328 | /* SRAT: Static Resource Affinity Table */ | 446 | /* SRAT: Static Resource Affinity Table */ |
| 329 | if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { | 447 | if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { |
| 330 | struct acpi_subtable_proc srat_proc[2]; | 448 | struct acpi_subtable_proc srat_proc[3]; |
| 331 | 449 | ||
| 332 | memset(srat_proc, 0, sizeof(srat_proc)); | 450 | memset(srat_proc, 0, sizeof(srat_proc)); |
| 333 | srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY; | 451 | srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY; |
| 334 | srat_proc[0].handler = acpi_parse_processor_affinity; | 452 | srat_proc[0].handler = acpi_parse_processor_affinity; |
| 335 | srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY; | 453 | srat_proc[1].id = ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY; |
| 336 | srat_proc[1].handler = acpi_parse_x2apic_affinity; | 454 | srat_proc[1].handler = acpi_parse_x2apic_affinity; |
| 455 | srat_proc[2].id = ACPI_SRAT_TYPE_GICC_AFFINITY; | ||
| 456 | srat_proc[2].handler = acpi_parse_gicc_affinity; | ||
| 337 | 457 | ||
| 338 | acpi_table_parse_entries_array(ACPI_SIG_SRAT, | 458 | acpi_table_parse_entries_array(ACPI_SIG_SRAT, |
| 339 | sizeof(struct acpi_table_srat), | 459 | sizeof(struct acpi_table_srat), |
| @@ -347,8 +467,6 @@ int __init acpi_numa_init(void) | |||
| 347 | /* SLIT: System Locality Information Table */ | 467 | /* SLIT: System Locality Information Table */ |
| 348 | acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); | 468 | acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); |
| 349 | 469 | ||
| 350 | acpi_numa_arch_fixup(); | ||
| 351 | |||
| 352 | if (cnt < 0) | 470 | if (cnt < 0) |
| 353 | return cnt; | 471 | return cnt; |
| 354 | else if (!parsed_numa_memblks) | 472 | else if (!parsed_numa_memblks) |
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 7188e53b6b7c..f62c68e24317 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c | |||
| @@ -22,8 +22,9 @@ | |||
| 22 | * General Public License for more details. | 22 | * General Public License for more details. |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 26 | |||
| 25 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/init.h> | 28 | #include <linux/init.h> |
| 28 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 29 | #include <linux/types.h> | 30 | #include <linux/types.h> |
| @@ -33,30 +34,11 @@ | |||
| 33 | #include <linux/dmi.h> | 34 | #include <linux/dmi.h> |
| 34 | #include <linux/pci-acpi.h> | 35 | #include <linux/pci-acpi.h> |
| 35 | 36 | ||
| 36 | static bool debug; | ||
| 37 | static int check_sta_before_sun; | 37 | static int check_sta_before_sun; |
| 38 | 38 | ||
| 39 | #define DRIVER_VERSION "0.1" | ||
| 40 | #define DRIVER_AUTHOR "Alex Chiang <achiang@hp.com>" | ||
| 41 | #define DRIVER_DESC "ACPI PCI Slot Detection Driver" | ||
| 42 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 43 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 44 | MODULE_LICENSE("GPL"); | ||
| 45 | MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); | ||
| 46 | module_param(debug, bool, 0644); | ||
| 47 | |||
| 48 | #define _COMPONENT ACPI_PCI_COMPONENT | 39 | #define _COMPONENT ACPI_PCI_COMPONENT |
| 49 | ACPI_MODULE_NAME("pci_slot"); | 40 | ACPI_MODULE_NAME("pci_slot"); |
| 50 | 41 | ||
| 51 | #define MY_NAME "pci_slot" | ||
| 52 | #define err(format, arg...) pr_err("%s: " format , MY_NAME , ## arg) | ||
| 53 | #define info(format, arg...) pr_info("%s: " format , MY_NAME , ## arg) | ||
| 54 | #define dbg(format, arg...) \ | ||
| 55 | do { \ | ||
| 56 | if (debug) \ | ||
| 57 | pr_debug("%s: " format, MY_NAME , ## arg); \ | ||
| 58 | } while (0) | ||
| 59 | |||
| 60 | #define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */ | 42 | #define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */ |
| 61 | 43 | ||
| 62 | struct acpi_pci_slot { | 44 | struct acpi_pci_slot { |
| @@ -76,7 +58,7 @@ check_slot(acpi_handle handle, unsigned long long *sun) | |||
| 76 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 58 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 77 | 59 | ||
| 78 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | 60 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); |
| 79 | dbg("Checking slot on path: %s\n", (char *)buffer.pointer); | 61 | pr_debug("Checking slot on path: %s\n", (char *)buffer.pointer); |
| 80 | 62 | ||
| 81 | if (check_sta_before_sun) { | 63 | if (check_sta_before_sun) { |
| 82 | /* If SxFy doesn't have _STA, we just assume it's there */ | 64 | /* If SxFy doesn't have _STA, we just assume it's there */ |
| @@ -87,14 +69,16 @@ check_slot(acpi_handle handle, unsigned long long *sun) | |||
| 87 | 69 | ||
| 88 | status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); | 70 | status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); |
| 89 | if (ACPI_FAILURE(status)) { | 71 | if (ACPI_FAILURE(status)) { |
| 90 | dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer); | 72 | pr_debug("_ADR returned %d on %s\n", |
| 73 | status, (char *)buffer.pointer); | ||
| 91 | goto out; | 74 | goto out; |
| 92 | } | 75 | } |
| 93 | 76 | ||
| 94 | /* No _SUN == not a slot == bail */ | 77 | /* No _SUN == not a slot == bail */ |
| 95 | status = acpi_evaluate_integer(handle, "_SUN", NULL, sun); | 78 | status = acpi_evaluate_integer(handle, "_SUN", NULL, sun); |
| 96 | if (ACPI_FAILURE(status)) { | 79 | if (ACPI_FAILURE(status)) { |
| 97 | dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer); | 80 | pr_debug("_SUN returned %d on %s\n", |
| 81 | status, (char *)buffer.pointer); | ||
| 98 | goto out; | 82 | goto out; |
| 99 | } | 83 | } |
| 100 | 84 | ||
| @@ -132,15 +116,13 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 132 | } | 116 | } |
| 133 | 117 | ||
| 134 | slot = kmalloc(sizeof(*slot), GFP_KERNEL); | 118 | slot = kmalloc(sizeof(*slot), GFP_KERNEL); |
| 135 | if (!slot) { | 119 | if (!slot) |
| 136 | err("%s: cannot allocate memory\n", __func__); | ||
| 137 | return AE_OK; | 120 | return AE_OK; |
| 138 | } | ||
| 139 | 121 | ||
| 140 | snprintf(name, sizeof(name), "%llu", sun); | 122 | snprintf(name, sizeof(name), "%llu", sun); |
| 141 | pci_slot = pci_create_slot(pci_bus, device, name, NULL); | 123 | pci_slot = pci_create_slot(pci_bus, device, name, NULL); |
| 142 | if (IS_ERR(pci_slot)) { | 124 | if (IS_ERR(pci_slot)) { |
| 143 | err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot)); | 125 | pr_err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot)); |
| 144 | kfree(slot); | 126 | kfree(slot); |
| 145 | return AE_OK; | 127 | return AE_OK; |
| 146 | } | 128 | } |
| @@ -150,8 +132,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 150 | 132 | ||
| 151 | get_device(&pci_bus->dev); | 133 | get_device(&pci_bus->dev); |
| 152 | 134 | ||
| 153 | dbg("pci_slot: %p, pci_bus: %x, device: %d, name: %s\n", | 135 | pr_debug("%p, pci_bus: %x, device: %d, name: %s\n", |
| 154 | pci_slot, pci_bus->number, device, name); | 136 | pci_slot, pci_bus->number, device, name); |
| 155 | 137 | ||
| 156 | return AE_OK; | 138 | return AE_OK; |
| 157 | } | 139 | } |
| @@ -186,7 +168,8 @@ void acpi_pci_slot_remove(struct pci_bus *bus) | |||
| 186 | 168 | ||
| 187 | static int do_sta_before_sun(const struct dmi_system_id *d) | 169 | static int do_sta_before_sun(const struct dmi_system_id *d) |
| 188 | { | 170 | { |
| 189 | info("%s detected: will evaluate _STA before calling _SUN\n", d->ident); | 171 | pr_info("%s detected: will evaluate _STA before calling _SUN\n", |
| 172 | d->ident); | ||
| 190 | check_sta_before_sun = 1; | 173 | check_sta_before_sun = 1; |
| 191 | return 0; | 174 | return 0; |
| 192 | } | 175 | } |
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c index bd772cd56494..ca18e0d23df9 100644 --- a/drivers/acpi/pmic/intel_pmic.c +++ b/drivers/acpi/pmic/intel_pmic.c | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/module.h> | 16 | #include <linux/export.h> |
| 17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
| 18 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
| 19 | #include <acpi/acpi_lpat.h> | 19 | #include <acpi/acpi_lpat.h> |
| @@ -21,12 +21,19 @@ | |||
| 21 | 21 | ||
| 22 | #define PMIC_POWER_OPREGION_ID 0x8d | 22 | #define PMIC_POWER_OPREGION_ID 0x8d |
| 23 | #define PMIC_THERMAL_OPREGION_ID 0x8c | 23 | #define PMIC_THERMAL_OPREGION_ID 0x8c |
| 24 | #define PMIC_REGS_OPREGION_ID 0x8f | ||
| 25 | |||
| 26 | struct intel_pmic_regs_handler_ctx { | ||
| 27 | unsigned int val; | ||
| 28 | u16 addr; | ||
| 29 | }; | ||
| 24 | 30 | ||
| 25 | struct intel_pmic_opregion { | 31 | struct intel_pmic_opregion { |
| 26 | struct mutex lock; | 32 | struct mutex lock; |
| 27 | struct acpi_lpat_conversion_table *lpat_table; | 33 | struct acpi_lpat_conversion_table *lpat_table; |
| 28 | struct regmap *regmap; | 34 | struct regmap *regmap; |
| 29 | struct intel_pmic_opregion_data *data; | 35 | struct intel_pmic_opregion_data *data; |
| 36 | struct intel_pmic_regs_handler_ctx ctx; | ||
| 30 | }; | 37 | }; |
| 31 | 38 | ||
| 32 | static int pmic_get_reg_bit(int address, struct pmic_table *table, | 39 | static int pmic_get_reg_bit(int address, struct pmic_table *table, |
| @@ -131,7 +138,7 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg, | |||
| 131 | } | 138 | } |
| 132 | 139 | ||
| 133 | static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg, | 140 | static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg, |
| 134 | u32 function, u64 *value) | 141 | int bit, u32 function, u64 *value) |
| 135 | { | 142 | { |
| 136 | struct intel_pmic_opregion_data *d = opregion->data; | 143 | struct intel_pmic_opregion_data *d = opregion->data; |
| 137 | struct regmap *regmap = opregion->regmap; | 144 | struct regmap *regmap = opregion->regmap; |
| @@ -140,12 +147,12 @@ static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg, | |||
| 140 | return -ENXIO; | 147 | return -ENXIO; |
| 141 | 148 | ||
| 142 | if (function == ACPI_READ) | 149 | if (function == ACPI_READ) |
| 143 | return d->get_policy(regmap, reg, value); | 150 | return d->get_policy(regmap, reg, bit, value); |
| 144 | 151 | ||
| 145 | if (*value != 0 && *value != 1) | 152 | if (*value != 0 && *value != 1) |
| 146 | return -EINVAL; | 153 | return -EINVAL; |
| 147 | 154 | ||
| 148 | return d->update_policy(regmap, reg, *value); | 155 | return d->update_policy(regmap, reg, bit, *value); |
| 149 | } | 156 | } |
| 150 | 157 | ||
| 151 | static bool pmic_thermal_is_temp(int address) | 158 | static bool pmic_thermal_is_temp(int address) |
| @@ -170,13 +177,13 @@ static acpi_status intel_pmic_thermal_handler(u32 function, | |||
| 170 | { | 177 | { |
| 171 | struct intel_pmic_opregion *opregion = region_context; | 178 | struct intel_pmic_opregion *opregion = region_context; |
| 172 | struct intel_pmic_opregion_data *d = opregion->data; | 179 | struct intel_pmic_opregion_data *d = opregion->data; |
| 173 | int reg, result; | 180 | int reg, bit, result; |
| 174 | 181 | ||
| 175 | if (bits != 32 || !value64) | 182 | if (bits != 32 || !value64) |
| 176 | return AE_BAD_PARAMETER; | 183 | return AE_BAD_PARAMETER; |
| 177 | 184 | ||
| 178 | result = pmic_get_reg_bit(address, d->thermal_table, | 185 | result = pmic_get_reg_bit(address, d->thermal_table, |
| 179 | d->thermal_table_count, ®, NULL); | 186 | d->thermal_table_count, ®, &bit); |
| 180 | if (result == -ENOENT) | 187 | if (result == -ENOENT) |
| 181 | return AE_BAD_PARAMETER; | 188 | return AE_BAD_PARAMETER; |
| 182 | 189 | ||
| @@ -187,7 +194,8 @@ static acpi_status intel_pmic_thermal_handler(u32 function, | |||
| 187 | else if (pmic_thermal_is_aux(address)) | 194 | else if (pmic_thermal_is_aux(address)) |
| 188 | result = pmic_thermal_aux(opregion, reg, function, value64); | 195 | result = pmic_thermal_aux(opregion, reg, function, value64); |
| 189 | else if (pmic_thermal_is_pen(address)) | 196 | else if (pmic_thermal_is_pen(address)) |
| 190 | result = pmic_thermal_pen(opregion, reg, function, value64); | 197 | result = pmic_thermal_pen(opregion, reg, bit, |
| 198 | function, value64); | ||
| 191 | else | 199 | else |
| 192 | result = -EINVAL; | 200 | result = -EINVAL; |
| 193 | 201 | ||
| @@ -203,6 +211,48 @@ static acpi_status intel_pmic_thermal_handler(u32 function, | |||
| 203 | return AE_OK; | 211 | return AE_OK; |
| 204 | } | 212 | } |
| 205 | 213 | ||
| 214 | static acpi_status intel_pmic_regs_handler(u32 function, | ||
| 215 | acpi_physical_address address, u32 bits, u64 *value64, | ||
| 216 | void *handler_context, void *region_context) | ||
| 217 | { | ||
| 218 | struct intel_pmic_opregion *opregion = region_context; | ||
| 219 | int result = 0; | ||
| 220 | |||
| 221 | switch (address) { | ||
| 222 | case 0: | ||
| 223 | return AE_OK; | ||
| 224 | case 1: | ||
| 225 | opregion->ctx.addr |= (*value64 & 0xff) << 8; | ||
| 226 | return AE_OK; | ||
| 227 | case 2: | ||
| 228 | opregion->ctx.addr |= *value64 & 0xff; | ||
| 229 | return AE_OK; | ||
| 230 | case 3: | ||
| 231 | opregion->ctx.val = *value64 & 0xff; | ||
| 232 | return AE_OK; | ||
| 233 | case 4: | ||
| 234 | if (*value64) { | ||
| 235 | result = regmap_write(opregion->regmap, opregion->ctx.addr, | ||
| 236 | opregion->ctx.val); | ||
| 237 | } else { | ||
| 238 | result = regmap_read(opregion->regmap, opregion->ctx.addr, | ||
| 239 | &opregion->ctx.val); | ||
| 240 | if (result == 0) | ||
| 241 | *value64 = opregion->ctx.val; | ||
| 242 | } | ||
| 243 | memset(&opregion->ctx, 0x00, sizeof(opregion->ctx)); | ||
| 244 | } | ||
| 245 | |||
| 246 | if (result < 0) { | ||
| 247 | if (result == -EINVAL) | ||
| 248 | return AE_BAD_PARAMETER; | ||
| 249 | else | ||
| 250 | return AE_ERROR; | ||
| 251 | } | ||
| 252 | |||
| 253 | return AE_OK; | ||
| 254 | } | ||
| 255 | |||
| 206 | int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, | 256 | int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, |
| 207 | struct regmap *regmap, | 257 | struct regmap *regmap, |
| 208 | struct intel_pmic_opregion_data *d) | 258 | struct intel_pmic_opregion_data *d) |
| @@ -242,16 +292,30 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, | |||
| 242 | acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, | 292 | acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, |
| 243 | intel_pmic_power_handler); | 293 | intel_pmic_power_handler); |
| 244 | ret = -ENODEV; | 294 | ret = -ENODEV; |
| 245 | goto out_error; | 295 | goto out_remove_power_handler; |
| 296 | } | ||
| 297 | |||
| 298 | status = acpi_install_address_space_handler(handle, | ||
| 299 | PMIC_REGS_OPREGION_ID, intel_pmic_regs_handler, NULL, | ||
| 300 | opregion); | ||
| 301 | if (ACPI_FAILURE(status)) { | ||
| 302 | ret = -ENODEV; | ||
| 303 | goto out_remove_thermal_handler; | ||
| 246 | } | 304 | } |
| 247 | 305 | ||
| 248 | opregion->data = d; | 306 | opregion->data = d; |
| 249 | return 0; | 307 | return 0; |
| 250 | 308 | ||
| 309 | out_remove_thermal_handler: | ||
| 310 | acpi_remove_address_space_handler(handle, PMIC_THERMAL_OPREGION_ID, | ||
| 311 | intel_pmic_thermal_handler); | ||
| 312 | |||
| 313 | out_remove_power_handler: | ||
| 314 | acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, | ||
| 315 | intel_pmic_power_handler); | ||
| 316 | |||
| 251 | out_error: | 317 | out_error: |
| 252 | acpi_lpat_free_conversion_table(opregion->lpat_table); | 318 | acpi_lpat_free_conversion_table(opregion->lpat_table); |
| 253 | return ret; | 319 | return ret; |
| 254 | } | 320 | } |
| 255 | EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); | 321 | EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); |
| 256 | |||
| 257 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/acpi/pmic/intel_pmic.h b/drivers/acpi/pmic/intel_pmic.h index d4e90af8f0dd..e8bfa7b865a5 100644 --- a/drivers/acpi/pmic/intel_pmic.h +++ b/drivers/acpi/pmic/intel_pmic.h | |||
| @@ -12,8 +12,8 @@ struct intel_pmic_opregion_data { | |||
| 12 | int (*update_power)(struct regmap *r, int reg, int bit, bool on); | 12 | int (*update_power)(struct regmap *r, int reg, int bit, bool on); |
| 13 | int (*get_raw_temp)(struct regmap *r, int reg); | 13 | int (*get_raw_temp)(struct regmap *r, int reg); |
| 14 | int (*update_aux)(struct regmap *r, int reg, int raw_temp); | 14 | int (*update_aux)(struct regmap *r, int reg, int raw_temp); |
| 15 | int (*get_policy)(struct regmap *r, int reg, u64 *value); | 15 | int (*get_policy)(struct regmap *r, int reg, int bit, u64 *value); |
| 16 | int (*update_policy)(struct regmap *r, int reg, int enable); | 16 | int (*update_policy)(struct regmap *r, int reg, int bit, int enable); |
| 17 | struct pmic_table *power_table; | 17 | struct pmic_table *power_table; |
| 18 | int power_table_count; | 18 | int power_table_count; |
| 19 | struct pmic_table *thermal_table; | 19 | struct pmic_table *thermal_table; |
diff --git a/drivers/acpi/pmic/intel_pmic_bxtwc.c b/drivers/acpi/pmic/intel_pmic_bxtwc.c new file mode 100644 index 000000000000..90011aad4d20 --- /dev/null +++ b/drivers/acpi/pmic/intel_pmic_bxtwc.c | |||
| @@ -0,0 +1,420 @@ | |||
| 1 | /* | ||
| 2 | * intel_pmic_bxtwc.c - Intel BXT WhiskeyCove PMIC operation region driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2015 Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/acpi.h> | ||
| 18 | #include <linux/mfd/intel_soc_pmic.h> | ||
| 19 | #include <linux/regmap.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include "intel_pmic.h" | ||
| 22 | |||
| 23 | #define WHISKEY_COVE_ALRT_HIGH_BIT_MASK 0x0F | ||
| 24 | #define WHISKEY_COVE_ADC_HIGH_BIT(x) (((x & 0x0F) << 8)) | ||
| 25 | #define WHISKEY_COVE_ADC_CURSRC(x) (((x & 0xF0) >> 4)) | ||
| 26 | #define VR_MODE_DISABLED 0 | ||
| 27 | #define VR_MODE_AUTO BIT(0) | ||
| 28 | #define VR_MODE_NORMAL BIT(1) | ||
| 29 | #define VR_MODE_SWITCH BIT(2) | ||
| 30 | #define VR_MODE_ECO (BIT(0)|BIT(1)) | ||
| 31 | #define VSWITCH2_OUTPUT BIT(5) | ||
| 32 | #define VSWITCH1_OUTPUT BIT(4) | ||
| 33 | #define VUSBPHY_CHARGE BIT(1) | ||
| 34 | |||
| 35 | static struct pmic_table power_table[] = { | ||
| 36 | { | ||
| 37 | .address = 0x0, | ||
| 38 | .reg = 0x63, | ||
| 39 | .bit = VR_MODE_AUTO, | ||
| 40 | }, /* VDD1 -> VDD1CNT */ | ||
| 41 | { | ||
| 42 | .address = 0x04, | ||
| 43 | .reg = 0x65, | ||
| 44 | .bit = VR_MODE_AUTO, | ||
| 45 | }, /* VDD2 -> VDD2CNT */ | ||
| 46 | { | ||
| 47 | .address = 0x08, | ||
| 48 | .reg = 0x67, | ||
| 49 | .bit = VR_MODE_AUTO, | ||
| 50 | }, /* VDD3 -> VDD3CNT */ | ||
| 51 | { | ||
| 52 | .address = 0x0c, | ||
| 53 | .reg = 0x6d, | ||
| 54 | .bit = VR_MODE_AUTO, | ||
| 55 | }, /* VLFX -> VFLEXCNT */ | ||
| 56 | { | ||
| 57 | .address = 0x10, | ||
| 58 | .reg = 0x6f, | ||
| 59 | .bit = VR_MODE_NORMAL, | ||
| 60 | }, /* VP1A -> VPROG1ACNT */ | ||
| 61 | { | ||
| 62 | .address = 0x14, | ||
| 63 | .reg = 0x70, | ||
| 64 | .bit = VR_MODE_NORMAL, | ||
| 65 | }, /* VP1B -> VPROG1BCNT */ | ||
| 66 | { | ||
| 67 | .address = 0x18, | ||
| 68 | .reg = 0x71, | ||
| 69 | .bit = VR_MODE_NORMAL, | ||
| 70 | }, /* VP1C -> VPROG1CCNT */ | ||
| 71 | { | ||
| 72 | .address = 0x1c, | ||
| 73 | .reg = 0x72, | ||
| 74 | .bit = VR_MODE_NORMAL, | ||
| 75 | }, /* VP1D -> VPROG1DCNT */ | ||
| 76 | { | ||
| 77 | .address = 0x20, | ||
| 78 | .reg = 0x73, | ||
| 79 | .bit = VR_MODE_NORMAL, | ||
| 80 | }, /* VP2A -> VPROG2ACNT */ | ||
| 81 | { | ||
| 82 | .address = 0x24, | ||
| 83 | .reg = 0x74, | ||
| 84 | .bit = VR_MODE_NORMAL, | ||
| 85 | }, /* VP2B -> VPROG2BCNT */ | ||
| 86 | { | ||
| 87 | .address = 0x28, | ||
| 88 | .reg = 0x75, | ||
| 89 | .bit = VR_MODE_NORMAL, | ||
| 90 | }, /* VP2C -> VPROG2CCNT */ | ||
| 91 | { | ||
| 92 | .address = 0x2c, | ||
| 93 | .reg = 0x76, | ||
| 94 | .bit = VR_MODE_NORMAL, | ||
| 95 | }, /* VP3A -> VPROG3ACNT */ | ||
| 96 | { | ||
| 97 | .address = 0x30, | ||
| 98 | .reg = 0x77, | ||
| 99 | .bit = VR_MODE_NORMAL, | ||
| 100 | }, /* VP3B -> VPROG3BCNT */ | ||
| 101 | { | ||
| 102 | .address = 0x34, | ||
| 103 | .reg = 0x78, | ||
| 104 | .bit = VSWITCH2_OUTPUT, | ||
| 105 | }, /* VSW2 -> VLD0CNT Bit 5*/ | ||
| 106 | { | ||
| 107 | .address = 0x38, | ||
| 108 | .reg = 0x78, | ||
| 109 | .bit = VSWITCH1_OUTPUT, | ||
| 110 | }, /* VSW1 -> VLD0CNT Bit 4 */ | ||
| 111 | { | ||
| 112 | .address = 0x3c, | ||
| 113 | .reg = 0x78, | ||
| 114 | .bit = VUSBPHY_CHARGE, | ||
| 115 | }, /* VUPY -> VLDOCNT Bit 1 */ | ||
| 116 | { | ||
| 117 | .address = 0x40, | ||
| 118 | .reg = 0x7b, | ||
| 119 | .bit = VR_MODE_NORMAL, | ||
| 120 | }, /* VRSO -> VREFSOCCNT*/ | ||
| 121 | { | ||
| 122 | .address = 0x44, | ||
| 123 | .reg = 0xA0, | ||
| 124 | .bit = VR_MODE_NORMAL, | ||
| 125 | }, /* VP1E -> VPROG1ECNT */ | ||
| 126 | { | ||
| 127 | .address = 0x48, | ||
| 128 | .reg = 0xA1, | ||
| 129 | .bit = VR_MODE_NORMAL, | ||
| 130 | }, /* VP1F -> VPROG1FCNT */ | ||
| 131 | { | ||
| 132 | .address = 0x4c, | ||
| 133 | .reg = 0xA2, | ||
| 134 | .bit = VR_MODE_NORMAL, | ||
| 135 | }, /* VP2D -> VPROG2DCNT */ | ||
| 136 | { | ||
| 137 | .address = 0x50, | ||
| 138 | .reg = 0xA3, | ||
| 139 | .bit = VR_MODE_NORMAL, | ||
| 140 | }, /* VP4A -> VPROG4ACNT */ | ||
| 141 | { | ||
| 142 | .address = 0x54, | ||
| 143 | .reg = 0xA4, | ||
| 144 | .bit = VR_MODE_NORMAL, | ||
| 145 | }, /* VP4B -> VPROG4BCNT */ | ||
| 146 | { | ||
| 147 | .address = 0x58, | ||
| 148 | .reg = 0xA5, | ||
| 149 | .bit = VR_MODE_NORMAL, | ||
| 150 | }, /* VP4C -> VPROG4CCNT */ | ||
| 151 | { | ||
| 152 | .address = 0x5c, | ||
| 153 | .reg = 0xA6, | ||
| 154 | .bit = VR_MODE_NORMAL, | ||
| 155 | }, /* VP4D -> VPROG4DCNT */ | ||
| 156 | { | ||
| 157 | .address = 0x60, | ||
| 158 | .reg = 0xA7, | ||
| 159 | .bit = VR_MODE_NORMAL, | ||
| 160 | }, /* VP5A -> VPROG5ACNT */ | ||
| 161 | { | ||
| 162 | .address = 0x64, | ||
| 163 | .reg = 0xA8, | ||
| 164 | .bit = VR_MODE_NORMAL, | ||
| 165 | }, /* VP5B -> VPROG5BCNT */ | ||
| 166 | { | ||
| 167 | .address = 0x68, | ||
| 168 | .reg = 0xA9, | ||
| 169 | .bit = VR_MODE_NORMAL, | ||
| 170 | }, /* VP6A -> VPROG6ACNT */ | ||
| 171 | { | ||
| 172 | .address = 0x6c, | ||
| 173 | .reg = 0xAA, | ||
| 174 | .bit = VR_MODE_NORMAL, | ||
| 175 | }, /* VP6B -> VPROG6BCNT */ | ||
| 176 | { | ||
| 177 | .address = 0x70, | ||
| 178 | .reg = 0x36, | ||
| 179 | .bit = BIT(2), | ||
| 180 | }, /* SDWN_N -> MODEMCTRL Bit 2 */ | ||
| 181 | { | ||
| 182 | .address = 0x74, | ||
| 183 | .reg = 0x36, | ||
| 184 | .bit = BIT(0), | ||
| 185 | } /* MOFF -> MODEMCTRL Bit 0 */ | ||
| 186 | }; | ||
| 187 | |||
| 188 | static struct pmic_table thermal_table[] = { | ||
| 189 | { | ||
| 190 | .address = 0x00, | ||
| 191 | .reg = 0x4F39 | ||
| 192 | }, | ||
| 193 | { | ||
| 194 | .address = 0x04, | ||
| 195 | .reg = 0x4F24 | ||
| 196 | }, | ||
| 197 | { | ||
| 198 | .address = 0x08, | ||
| 199 | .reg = 0x4F26 | ||
| 200 | }, | ||
| 201 | { | ||
| 202 | .address = 0x0c, | ||
| 203 | .reg = 0x4F3B | ||
| 204 | }, | ||
| 205 | { | ||
| 206 | .address = 0x10, | ||
| 207 | .reg = 0x4F28 | ||
| 208 | }, | ||
| 209 | { | ||
| 210 | .address = 0x14, | ||
| 211 | .reg = 0x4F2A | ||
| 212 | }, | ||
| 213 | { | ||
| 214 | .address = 0x18, | ||
| 215 | .reg = 0x4F3D | ||
| 216 | }, | ||
| 217 | { | ||
| 218 | .address = 0x1c, | ||
| 219 | .reg = 0x4F2C | ||
| 220 | }, | ||
| 221 | { | ||
| 222 | .address = 0x20, | ||
| 223 | .reg = 0x4F2E | ||
| 224 | }, | ||
| 225 | { | ||
| 226 | .address = 0x24, | ||
| 227 | .reg = 0x4F3F | ||
| 228 | }, | ||
| 229 | { | ||
| 230 | .address = 0x28, | ||
| 231 | .reg = 0x4F30 | ||
| 232 | }, | ||
| 233 | { | ||
| 234 | .address = 0x30, | ||
| 235 | .reg = 0x4F41 | ||
| 236 | }, | ||
| 237 | { | ||
| 238 | .address = 0x34, | ||
| 239 | .reg = 0x4F32 | ||
| 240 | }, | ||
| 241 | { | ||
| 242 | .address = 0x3c, | ||
| 243 | .reg = 0x4F43 | ||
| 244 | }, | ||
| 245 | { | ||
| 246 | .address = 0x40, | ||
| 247 | .reg = 0x4F34 | ||
| 248 | }, | ||
| 249 | { | ||
| 250 | .address = 0x48, | ||
| 251 | .reg = 0x4F6A, | ||
| 252 | .bit = 0, | ||
| 253 | }, | ||
| 254 | { | ||
| 255 | .address = 0x4C, | ||
| 256 | .reg = 0x4F6A, | ||
| 257 | .bit = 1 | ||
| 258 | }, | ||
| 259 | { | ||
| 260 | .address = 0x50, | ||
| 261 | .reg = 0x4F6A, | ||
| 262 | .bit = 2 | ||
| 263 | }, | ||
| 264 | { | ||
| 265 | .address = 0x54, | ||
| 266 | .reg = 0x4F6A, | ||
| 267 | .bit = 4 | ||
| 268 | }, | ||
| 269 | { | ||
| 270 | .address = 0x58, | ||
| 271 | .reg = 0x4F6A, | ||
| 272 | .bit = 5 | ||
| 273 | }, | ||
| 274 | { | ||
| 275 | .address = 0x5C, | ||
| 276 | .reg = 0x4F6A, | ||
| 277 | .bit = 3 | ||
| 278 | }, | ||
| 279 | }; | ||
| 280 | |||
| 281 | static int intel_bxtwc_pmic_get_power(struct regmap *regmap, int reg, | ||
| 282 | int bit, u64 *value) | ||
| 283 | { | ||
| 284 | int data; | ||
| 285 | |||
| 286 | if (regmap_read(regmap, reg, &data)) | ||
| 287 | return -EIO; | ||
| 288 | |||
| 289 | *value = (data & bit) ? 1 : 0; | ||
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | static int intel_bxtwc_pmic_update_power(struct regmap *regmap, int reg, | ||
| 294 | int bit, bool on) | ||
| 295 | { | ||
| 296 | u8 val, mask = bit; | ||
| 297 | |||
| 298 | if (on) | ||
| 299 | val = 0xFF; | ||
| 300 | else | ||
| 301 | val = 0x0; | ||
| 302 | |||
| 303 | return regmap_update_bits(regmap, reg, mask, val); | ||
| 304 | } | ||
| 305 | |||
| 306 | static int intel_bxtwc_pmic_get_raw_temp(struct regmap *regmap, int reg) | ||
| 307 | { | ||
| 308 | unsigned int val, adc_val, reg_val; | ||
| 309 | u8 temp_l, temp_h, cursrc; | ||
| 310 | unsigned long rlsb; | ||
| 311 | static const unsigned long rlsb_array[] = { | ||
| 312 | 0, 260420, 130210, 65100, 32550, 16280, | ||
| 313 | 8140, 4070, 2030, 0, 260420, 130210 }; | ||
| 314 | |||
| 315 | if (regmap_read(regmap, reg, &val)) | ||
| 316 | return -EIO; | ||
| 317 | temp_l = (u8) val; | ||
| 318 | |||
| 319 | if (regmap_read(regmap, (reg - 1), &val)) | ||
| 320 | return -EIO; | ||
| 321 | temp_h = (u8) val; | ||
| 322 | |||
| 323 | reg_val = temp_l | WHISKEY_COVE_ADC_HIGH_BIT(temp_h); | ||
| 324 | cursrc = WHISKEY_COVE_ADC_CURSRC(temp_h); | ||
| 325 | rlsb = rlsb_array[cursrc]; | ||
| 326 | adc_val = reg_val * rlsb / 1000; | ||
| 327 | |||
| 328 | return adc_val; | ||
| 329 | } | ||
| 330 | |||
| 331 | static int | ||
| 332 | intel_bxtwc_pmic_update_aux(struct regmap *regmap, int reg, int raw) | ||
| 333 | { | ||
| 334 | u32 bsr_num; | ||
| 335 | u16 resi_val, count = 0, thrsh = 0; | ||
| 336 | u8 alrt_h, alrt_l, cursel = 0; | ||
| 337 | |||
| 338 | bsr_num = raw; | ||
| 339 | bsr_num /= (1 << 5); | ||
| 340 | |||
| 341 | count = fls(bsr_num) - 1; | ||
| 342 | |||
| 343 | cursel = clamp_t(s8, (count - 7), 0, 7); | ||
| 344 | thrsh = raw / (1 << (4 + cursel)); | ||
| 345 | |||
| 346 | resi_val = (cursel << 9) | thrsh; | ||
| 347 | alrt_h = (resi_val >> 8) & WHISKEY_COVE_ALRT_HIGH_BIT_MASK; | ||
| 348 | if (regmap_update_bits(regmap, | ||
| 349 | reg - 1, | ||
| 350 | WHISKEY_COVE_ALRT_HIGH_BIT_MASK, | ||
| 351 | alrt_h)) | ||
| 352 | return -EIO; | ||
| 353 | |||
| 354 | alrt_l = (u8)resi_val; | ||
| 355 | return regmap_write(regmap, reg, alrt_l); | ||
| 356 | } | ||
| 357 | |||
| 358 | static int | ||
| 359 | intel_bxtwc_pmic_get_policy(struct regmap *regmap, int reg, int bit, u64 *value) | ||
| 360 | { | ||
| 361 | u8 mask = BIT(bit); | ||
| 362 | unsigned int val; | ||
| 363 | |||
| 364 | if (regmap_read(regmap, reg, &val)) | ||
| 365 | return -EIO; | ||
| 366 | |||
| 367 | *value = (val & mask) >> bit; | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | static int | ||
| 372 | intel_bxtwc_pmic_update_policy(struct regmap *regmap, | ||
| 373 | int reg, int bit, int enable) | ||
| 374 | { | ||
| 375 | u8 mask = BIT(bit), val = enable << bit; | ||
| 376 | |||
| 377 | return regmap_update_bits(regmap, reg, mask, val); | ||
| 378 | } | ||
| 379 | |||
| 380 | static struct intel_pmic_opregion_data intel_bxtwc_pmic_opregion_data = { | ||
| 381 | .get_power = intel_bxtwc_pmic_get_power, | ||
| 382 | .update_power = intel_bxtwc_pmic_update_power, | ||
| 383 | .get_raw_temp = intel_bxtwc_pmic_get_raw_temp, | ||
| 384 | .update_aux = intel_bxtwc_pmic_update_aux, | ||
| 385 | .get_policy = intel_bxtwc_pmic_get_policy, | ||
| 386 | .update_policy = intel_bxtwc_pmic_update_policy, | ||
| 387 | .power_table = power_table, | ||
| 388 | .power_table_count = ARRAY_SIZE(power_table), | ||
| 389 | .thermal_table = thermal_table, | ||
| 390 | .thermal_table_count = ARRAY_SIZE(thermal_table), | ||
| 391 | }; | ||
| 392 | |||
| 393 | static int intel_bxtwc_pmic_opregion_probe(struct platform_device *pdev) | ||
| 394 | { | ||
| 395 | struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); | ||
| 396 | |||
| 397 | return intel_pmic_install_opregion_handler(&pdev->dev, | ||
| 398 | ACPI_HANDLE(pdev->dev.parent), | ||
| 399 | pmic->regmap, | ||
| 400 | &intel_bxtwc_pmic_opregion_data); | ||
| 401 | } | ||
| 402 | |||
| 403 | static struct platform_device_id bxt_wc_opregion_id_table[] = { | ||
| 404 | { .name = "bxt_wcove_region" }, | ||
| 405 | {}, | ||
| 406 | }; | ||
| 407 | |||
| 408 | static struct platform_driver intel_bxtwc_pmic_opregion_driver = { | ||
| 409 | .probe = intel_bxtwc_pmic_opregion_probe, | ||
| 410 | .driver = { | ||
| 411 | .name = "bxt_whiskey_cove_pmic", | ||
| 412 | }, | ||
| 413 | .id_table = bxt_wc_opregion_id_table, | ||
| 414 | }; | ||
| 415 | |||
| 416 | static int __init intel_bxtwc_pmic_opregion_driver_init(void) | ||
| 417 | { | ||
| 418 | return platform_driver_register(&intel_bxtwc_pmic_opregion_driver); | ||
| 419 | } | ||
| 420 | device_initcall(intel_bxtwc_pmic_opregion_driver_init); | ||
diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c index fcd1852dcdee..d7f1761ab1bc 100644 --- a/drivers/acpi/pmic/intel_pmic_crc.c +++ b/drivers/acpi/pmic/intel_pmic_crc.c | |||
| @@ -141,7 +141,8 @@ static int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw) | |||
| 141 | regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0; | 141 | regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static int intel_crc_pmic_get_policy(struct regmap *regmap, int reg, u64 *value) | 144 | static int intel_crc_pmic_get_policy(struct regmap *regmap, |
| 145 | int reg, int bit, u64 *value) | ||
| 145 | { | 146 | { |
| 146 | int pen; | 147 | int pen; |
| 147 | 148 | ||
| @@ -152,7 +153,7 @@ static int intel_crc_pmic_get_policy(struct regmap *regmap, int reg, u64 *value) | |||
| 152 | } | 153 | } |
| 153 | 154 | ||
| 154 | static int intel_crc_pmic_update_policy(struct regmap *regmap, | 155 | static int intel_crc_pmic_update_policy(struct regmap *regmap, |
| 155 | int reg, int enable) | 156 | int reg, int bit, int enable) |
| 156 | { | 157 | { |
| 157 | int alert0; | 158 | int alert0; |
| 158 | 159 | ||
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index 6a082d4de12c..e6e991ac20f3 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/module.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
| 18 | #include <linux/mfd/axp20x.h> | 18 | #include <linux/mfd/axp20x.h> |
| 19 | #include <linux/regmap.h> | 19 | #include <linux/regmap.h> |
| @@ -262,7 +262,4 @@ static int __init intel_xpower_pmic_opregion_driver_init(void) | |||
| 262 | { | 262 | { |
| 263 | return platform_driver_register(&intel_xpower_pmic_opregion_driver); | 263 | return platform_driver_register(&intel_xpower_pmic_opregion_driver); |
| 264 | } | 264 | } |
| 265 | module_init(intel_xpower_pmic_opregion_driver_init); | 265 | device_initcall(intel_xpower_pmic_opregion_driver_init); |
| 266 | |||
| 267 | MODULE_DESCRIPTION("XPower AXP288 ACPI operation region driver"); | ||
| 268 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 33a38d604630..9125d7d96372 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
| @@ -108,13 +108,12 @@ static int map_gicc_mpidr(struct acpi_subtable_header *entry, | |||
| 108 | return -EINVAL; | 108 | return -EINVAL; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static phys_cpuid_t map_madt_entry(int type, u32 acpi_id) | 111 | static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt, |
| 112 | int type, u32 acpi_id) | ||
| 112 | { | 113 | { |
| 113 | unsigned long madt_end, entry; | 114 | unsigned long madt_end, entry; |
| 114 | phys_cpuid_t phys_id = PHYS_CPUID_INVALID; /* CPU hardware ID */ | 115 | phys_cpuid_t phys_id = PHYS_CPUID_INVALID; /* CPU hardware ID */ |
| 115 | struct acpi_table_madt *madt; | ||
| 116 | 116 | ||
| 117 | madt = get_madt_table(); | ||
| 118 | if (!madt) | 117 | if (!madt) |
| 119 | return phys_id; | 118 | return phys_id; |
| 120 | 119 | ||
| @@ -145,6 +144,25 @@ static phys_cpuid_t map_madt_entry(int type, u32 acpi_id) | |||
| 145 | return phys_id; | 144 | return phys_id; |
| 146 | } | 145 | } |
| 147 | 146 | ||
| 147 | phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id) | ||
| 148 | { | ||
| 149 | struct acpi_table_madt *madt = NULL; | ||
| 150 | acpi_size tbl_size; | ||
| 151 | phys_cpuid_t rv; | ||
| 152 | |||
| 153 | acpi_get_table_with_size(ACPI_SIG_MADT, 0, | ||
| 154 | (struct acpi_table_header **)&madt, | ||
| 155 | &tbl_size); | ||
| 156 | if (!madt) | ||
| 157 | return PHYS_CPUID_INVALID; | ||
| 158 | |||
| 159 | rv = map_madt_entry(madt, 1, acpi_id); | ||
| 160 | |||
| 161 | early_acpi_os_unmap_memory(madt, tbl_size); | ||
| 162 | |||
| 163 | return rv; | ||
| 164 | } | ||
| 165 | |||
| 148 | static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id) | 166 | static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id) |
| 149 | { | 167 | { |
| 150 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 168 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
| @@ -185,7 +203,7 @@ phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id) | |||
| 185 | 203 | ||
| 186 | phys_id = map_mat_entry(handle, type, acpi_id); | 204 | phys_id = map_mat_entry(handle, type, acpi_id); |
| 187 | if (invalid_phys_cpuid(phys_id)) | 205 | if (invalid_phys_cpuid(phys_id)) |
| 188 | phys_id = map_madt_entry(type, acpi_id); | 206 | phys_id = map_madt_entry(get_madt_table(), type, acpi_id); |
| 189 | 207 | ||
| 190 | return phys_id; | 208 | return phys_id; |
| 191 | } | 209 | } |
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index d2fa8cb82d2b..0ca14ac7bb28 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c | |||
| @@ -90,7 +90,7 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) | |||
| 90 | pr->performance_platform_limit); | 90 | pr->performance_platform_limit); |
| 91 | break; | 91 | break; |
| 92 | case ACPI_PROCESSOR_NOTIFY_POWER: | 92 | case ACPI_PROCESSOR_NOTIFY_POWER: |
| 93 | acpi_processor_cst_has_changed(pr); | 93 | acpi_processor_power_state_has_changed(pr); |
| 94 | acpi_bus_generate_netlink_event(device->pnp.device_class, | 94 | acpi_bus_generate_netlink_event(device->pnp.device_class, |
| 95 | dev_name(&device->dev), event, 0); | 95 | dev_name(&device->dev), event, 0); |
| 96 | break; | 96 | break; |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 444e3745c8b3..cea52528aa18 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
| @@ -59,6 +59,12 @@ module_param(latency_factor, uint, 0644); | |||
| 59 | 59 | ||
| 60 | static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device); | 60 | static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device); |
| 61 | 61 | ||
| 62 | struct cpuidle_driver acpi_idle_driver = { | ||
| 63 | .name = "acpi_idle", | ||
| 64 | .owner = THIS_MODULE, | ||
| 65 | }; | ||
| 66 | |||
| 67 | #ifdef CONFIG_ACPI_PROCESSOR_CSTATE | ||
| 62 | static | 68 | static |
| 63 | DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX], acpi_cstate); | 69 | DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX], acpi_cstate); |
| 64 | 70 | ||
| @@ -297,7 +303,6 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) | |||
| 297 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 303 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 298 | union acpi_object *cst; | 304 | union acpi_object *cst; |
| 299 | 305 | ||
| 300 | |||
| 301 | if (nocst) | 306 | if (nocst) |
| 302 | return -ENODEV; | 307 | return -ENODEV; |
| 303 | 308 | ||
| @@ -570,7 +575,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) | |||
| 570 | return (working); | 575 | return (working); |
| 571 | } | 576 | } |
| 572 | 577 | ||
| 573 | static int acpi_processor_get_power_info(struct acpi_processor *pr) | 578 | static int acpi_processor_get_cstate_info(struct acpi_processor *pr) |
| 574 | { | 579 | { |
| 575 | unsigned int i; | 580 | unsigned int i; |
| 576 | int result; | 581 | int result; |
| @@ -804,36 +809,12 @@ static void acpi_idle_enter_freeze(struct cpuidle_device *dev, | |||
| 804 | acpi_idle_do_entry(cx); | 809 | acpi_idle_do_entry(cx); |
| 805 | } | 810 | } |
| 806 | 811 | ||
| 807 | struct cpuidle_driver acpi_idle_driver = { | ||
| 808 | .name = "acpi_idle", | ||
| 809 | .owner = THIS_MODULE, | ||
| 810 | }; | ||
| 811 | |||
| 812 | /** | ||
| 813 | * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE | ||
| 814 | * device i.e. per-cpu data | ||
| 815 | * | ||
| 816 | * @pr: the ACPI processor | ||
| 817 | * @dev : the cpuidle device | ||
| 818 | */ | ||
| 819 | static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, | 812 | static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, |
| 820 | struct cpuidle_device *dev) | 813 | struct cpuidle_device *dev) |
| 821 | { | 814 | { |
| 822 | int i, count = CPUIDLE_DRIVER_STATE_START; | 815 | int i, count = CPUIDLE_DRIVER_STATE_START; |
| 823 | struct acpi_processor_cx *cx; | 816 | struct acpi_processor_cx *cx; |
| 824 | 817 | ||
| 825 | if (!pr->flags.power_setup_done) | ||
| 826 | return -EINVAL; | ||
| 827 | |||
| 828 | if (pr->flags.power == 0) { | ||
| 829 | return -EINVAL; | ||
| 830 | } | ||
| 831 | |||
| 832 | if (!dev) | ||
| 833 | return -EINVAL; | ||
| 834 | |||
| 835 | dev->cpu = pr->id; | ||
| 836 | |||
| 837 | if (max_cstate == 0) | 818 | if (max_cstate == 0) |
| 838 | max_cstate = 1; | 819 | max_cstate = 1; |
| 839 | 820 | ||
| @@ -856,31 +837,13 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, | |||
| 856 | return 0; | 837 | return 0; |
| 857 | } | 838 | } |
| 858 | 839 | ||
| 859 | /** | 840 | static int acpi_processor_setup_cstates(struct acpi_processor *pr) |
| 860 | * acpi_processor_setup_cpuidle states- prepares and configures cpuidle | ||
| 861 | * global state data i.e. idle routines | ||
| 862 | * | ||
| 863 | * @pr: the ACPI processor | ||
| 864 | */ | ||
| 865 | static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) | ||
| 866 | { | 841 | { |
| 867 | int i, count = CPUIDLE_DRIVER_STATE_START; | 842 | int i, count = CPUIDLE_DRIVER_STATE_START; |
| 868 | struct acpi_processor_cx *cx; | 843 | struct acpi_processor_cx *cx; |
| 869 | struct cpuidle_state *state; | 844 | struct cpuidle_state *state; |
| 870 | struct cpuidle_driver *drv = &acpi_idle_driver; | 845 | struct cpuidle_driver *drv = &acpi_idle_driver; |
| 871 | 846 | ||
| 872 | if (!pr->flags.power_setup_done) | ||
| 873 | return -EINVAL; | ||
| 874 | |||
| 875 | if (pr->flags.power == 0) | ||
| 876 | return -EINVAL; | ||
| 877 | |||
| 878 | drv->safe_state_index = -1; | ||
| 879 | for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) { | ||
| 880 | drv->states[i].name[0] = '\0'; | ||
| 881 | drv->states[i].desc[0] = '\0'; | ||
| 882 | } | ||
| 883 | |||
| 884 | if (max_cstate == 0) | 847 | if (max_cstate == 0) |
| 885 | max_cstate = 1; | 848 | max_cstate = 1; |
| 886 | 849 | ||
| @@ -892,7 +855,7 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) | |||
| 892 | 855 | ||
| 893 | state = &drv->states[count]; | 856 | state = &drv->states[count]; |
| 894 | snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); | 857 | snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); |
| 895 | strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); | 858 | strlcpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); |
| 896 | state->exit_latency = cx->latency; | 859 | state->exit_latency = cx->latency; |
| 897 | state->target_residency = cx->latency * latency_factor; | 860 | state->target_residency = cx->latency * latency_factor; |
| 898 | state->enter = acpi_idle_enter; | 861 | state->enter = acpi_idle_enter; |
| @@ -925,6 +888,450 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) | |||
| 925 | return 0; | 888 | return 0; |
| 926 | } | 889 | } |
| 927 | 890 | ||
| 891 | static inline void acpi_processor_cstate_first_run_checks(void) | ||
| 892 | { | ||
| 893 | acpi_status status; | ||
| 894 | static int first_run; | ||
| 895 | |||
| 896 | if (first_run) | ||
| 897 | return; | ||
| 898 | dmi_check_system(processor_power_dmi_table); | ||
| 899 | max_cstate = acpi_processor_cstate_check(max_cstate); | ||
| 900 | if (max_cstate < ACPI_C_STATES_MAX) | ||
| 901 | pr_notice("ACPI: processor limited to max C-state %d\n", | ||
| 902 | max_cstate); | ||
| 903 | first_run++; | ||
| 904 | |||
| 905 | if (acpi_gbl_FADT.cst_control && !nocst) { | ||
| 906 | status = acpi_os_write_port(acpi_gbl_FADT.smi_command, | ||
| 907 | acpi_gbl_FADT.cst_control, 8); | ||
| 908 | if (ACPI_FAILURE(status)) | ||
| 909 | ACPI_EXCEPTION((AE_INFO, status, | ||
| 910 | "Notifying BIOS of _CST ability failed")); | ||
| 911 | } | ||
| 912 | } | ||
| 913 | #else | ||
| 914 | |||
| 915 | static inline int disabled_by_idle_boot_param(void) { return 0; } | ||
| 916 | static inline void acpi_processor_cstate_first_run_checks(void) { } | ||
| 917 | static int acpi_processor_get_cstate_info(struct acpi_processor *pr) | ||
| 918 | { | ||
| 919 | return -ENODEV; | ||
| 920 | } | ||
| 921 | |||
| 922 | static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr, | ||
| 923 | struct cpuidle_device *dev) | ||
| 924 | { | ||
| 925 | return -EINVAL; | ||
| 926 | } | ||
| 927 | |||
| 928 | static int acpi_processor_setup_cstates(struct acpi_processor *pr) | ||
| 929 | { | ||
| 930 | return -EINVAL; | ||
| 931 | } | ||
| 932 | |||
| 933 | #endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ | ||
| 934 | |||
| 935 | struct acpi_lpi_states_array { | ||
| 936 | unsigned int size; | ||
| 937 | unsigned int composite_states_size; | ||
| 938 | struct acpi_lpi_state *entries; | ||
| 939 | struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER]; | ||
| 940 | }; | ||
| 941 | |||
| 942 | static int obj_get_integer(union acpi_object *obj, u32 *value) | ||
| 943 | { | ||
| 944 | if (obj->type != ACPI_TYPE_INTEGER) | ||
| 945 | return -EINVAL; | ||
| 946 | |||
| 947 | *value = obj->integer.value; | ||
| 948 | return 0; | ||
| 949 | } | ||
| 950 | |||
| 951 | static int acpi_processor_evaluate_lpi(acpi_handle handle, | ||
| 952 | struct acpi_lpi_states_array *info) | ||
| 953 | { | ||
| 954 | acpi_status status; | ||
| 955 | int ret = 0; | ||
| 956 | int pkg_count, state_idx = 1, loop; | ||
| 957 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 958 | union acpi_object *lpi_data; | ||
| 959 | struct acpi_lpi_state *lpi_state; | ||
| 960 | |||
| 961 | status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer); | ||
| 962 | if (ACPI_FAILURE(status)) { | ||
| 963 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _LPI, giving up\n")); | ||
| 964 | return -ENODEV; | ||
| 965 | } | ||
| 966 | |||
| 967 | lpi_data = buffer.pointer; | ||
| 968 | |||
| 969 | /* There must be at least 4 elements = 3 elements + 1 package */ | ||
| 970 | if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE || | ||
| 971 | lpi_data->package.count < 4) { | ||
| 972 | pr_debug("not enough elements in _LPI\n"); | ||
| 973 | ret = -ENODATA; | ||
| 974 | goto end; | ||
| 975 | } | ||
| 976 | |||
| 977 | pkg_count = lpi_data->package.elements[2].integer.value; | ||
| 978 | |||
| 979 | /* Validate number of power states. */ | ||
| 980 | if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) { | ||
| 981 | pr_debug("count given by _LPI is not valid\n"); | ||
| 982 | ret = -ENODATA; | ||
| 983 | goto end; | ||
| 984 | } | ||
| 985 | |||
| 986 | lpi_state = kcalloc(pkg_count, sizeof(*lpi_state), GFP_KERNEL); | ||
| 987 | if (!lpi_state) { | ||
| 988 | ret = -ENOMEM; | ||
| 989 | goto end; | ||
| 990 | } | ||
| 991 | |||
| 992 | info->size = pkg_count; | ||
| 993 | info->entries = lpi_state; | ||
| 994 | |||
| 995 | /* LPI States start at index 3 */ | ||
| 996 | for (loop = 3; state_idx <= pkg_count; loop++, state_idx++, lpi_state++) { | ||
| 997 | union acpi_object *element, *pkg_elem, *obj; | ||
| 998 | |||
| 999 | element = &lpi_data->package.elements[loop]; | ||
| 1000 | if (element->type != ACPI_TYPE_PACKAGE || element->package.count < 7) | ||
| 1001 | continue; | ||
| 1002 | |||
| 1003 | pkg_elem = element->package.elements; | ||
| 1004 | |||
| 1005 | obj = pkg_elem + 6; | ||
| 1006 | if (obj->type == ACPI_TYPE_BUFFER) { | ||
| 1007 | struct acpi_power_register *reg; | ||
| 1008 | |||
| 1009 | reg = (struct acpi_power_register *)obj->buffer.pointer; | ||
| 1010 | if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO && | ||
| 1011 | reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) | ||
| 1012 | continue; | ||
| 1013 | |||
| 1014 | lpi_state->address = reg->address; | ||
| 1015 | lpi_state->entry_method = | ||
| 1016 | reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE ? | ||
| 1017 | ACPI_CSTATE_FFH : ACPI_CSTATE_SYSTEMIO; | ||
| 1018 | } else if (obj->type == ACPI_TYPE_INTEGER) { | ||
| 1019 | lpi_state->entry_method = ACPI_CSTATE_INTEGER; | ||
| 1020 | lpi_state->address = obj->integer.value; | ||
| 1021 | } else { | ||
| 1022 | continue; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | /* elements[7,8] skipped for now i.e. Residency/Usage counter*/ | ||
| 1026 | |||
| 1027 | obj = pkg_elem + 9; | ||
| 1028 | if (obj->type == ACPI_TYPE_STRING) | ||
| 1029 | strlcpy(lpi_state->desc, obj->string.pointer, | ||
| 1030 | ACPI_CX_DESC_LEN); | ||
| 1031 | |||
| 1032 | lpi_state->index = state_idx; | ||
| 1033 | if (obj_get_integer(pkg_elem + 0, &lpi_state->min_residency)) { | ||
| 1034 | pr_debug("No min. residency found, assuming 10 us\n"); | ||
| 1035 | lpi_state->min_residency = 10; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | if (obj_get_integer(pkg_elem + 1, &lpi_state->wake_latency)) { | ||
| 1039 | pr_debug("No wakeup residency found, assuming 10 us\n"); | ||
| 1040 | lpi_state->wake_latency = 10; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | if (obj_get_integer(pkg_elem + 2, &lpi_state->flags)) | ||
| 1044 | lpi_state->flags = 0; | ||
| 1045 | |||
| 1046 | if (obj_get_integer(pkg_elem + 3, &lpi_state->arch_flags)) | ||
| 1047 | lpi_state->arch_flags = 0; | ||
| 1048 | |||
| 1049 | if (obj_get_integer(pkg_elem + 4, &lpi_state->res_cnt_freq)) | ||
| 1050 | lpi_state->res_cnt_freq = 1; | ||
| 1051 | |||
| 1052 | if (obj_get_integer(pkg_elem + 5, &lpi_state->enable_parent_state)) | ||
| 1053 | lpi_state->enable_parent_state = 0; | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | acpi_handle_debug(handle, "Found %d power states\n", state_idx); | ||
| 1057 | end: | ||
| 1058 | kfree(buffer.pointer); | ||
| 1059 | return ret; | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | /* | ||
| 1063 | * flat_state_cnt - the number of composite LPI states after the process of flattening | ||
| 1064 | */ | ||
| 1065 | static int flat_state_cnt; | ||
| 1066 | |||
| 1067 | /** | ||
| 1068 | * combine_lpi_states - combine local and parent LPI states to form a composite LPI state | ||
| 1069 | * | ||
| 1070 | * @local: local LPI state | ||
| 1071 | * @parent: parent LPI state | ||
| 1072 | * @result: composite LPI state | ||
| 1073 | */ | ||
| 1074 | static bool combine_lpi_states(struct acpi_lpi_state *local, | ||
| 1075 | struct acpi_lpi_state *parent, | ||
| 1076 | struct acpi_lpi_state *result) | ||
| 1077 | { | ||
| 1078 | if (parent->entry_method == ACPI_CSTATE_INTEGER) { | ||
| 1079 | if (!parent->address) /* 0 means autopromotable */ | ||
| 1080 | return false; | ||
| 1081 | result->address = local->address + parent->address; | ||
| 1082 | } else { | ||
| 1083 | result->address = parent->address; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | result->min_residency = max(local->min_residency, parent->min_residency); | ||
| 1087 | result->wake_latency = local->wake_latency + parent->wake_latency; | ||
| 1088 | result->enable_parent_state = parent->enable_parent_state; | ||
| 1089 | result->entry_method = local->entry_method; | ||
| 1090 | |||
| 1091 | result->flags = parent->flags; | ||
| 1092 | result->arch_flags = parent->arch_flags; | ||
| 1093 | result->index = parent->index; | ||
| 1094 | |||
| 1095 | strlcpy(result->desc, local->desc, ACPI_CX_DESC_LEN); | ||
| 1096 | strlcat(result->desc, "+", ACPI_CX_DESC_LEN); | ||
| 1097 | strlcat(result->desc, parent->desc, ACPI_CX_DESC_LEN); | ||
| 1098 | return true; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | #define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0) | ||
| 1102 | |||
| 1103 | static void stash_composite_state(struct acpi_lpi_states_array *curr_level, | ||
| 1104 | struct acpi_lpi_state *t) | ||
| 1105 | { | ||
| 1106 | curr_level->composite_states[curr_level->composite_states_size++] = t; | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | static int flatten_lpi_states(struct acpi_processor *pr, | ||
| 1110 | struct acpi_lpi_states_array *curr_level, | ||
| 1111 | struct acpi_lpi_states_array *prev_level) | ||
| 1112 | { | ||
| 1113 | int i, j, state_count = curr_level->size; | ||
| 1114 | struct acpi_lpi_state *p, *t = curr_level->entries; | ||
| 1115 | |||
| 1116 | curr_level->composite_states_size = 0; | ||
| 1117 | for (j = 0; j < state_count; j++, t++) { | ||
| 1118 | struct acpi_lpi_state *flpi; | ||
| 1119 | |||
| 1120 | if (!(t->flags & ACPI_LPI_STATE_FLAGS_ENABLED)) | ||
| 1121 | continue; | ||
| 1122 | |||
| 1123 | if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER) { | ||
| 1124 | pr_warn("Limiting number of LPI states to max (%d)\n", | ||
| 1125 | ACPI_PROCESSOR_MAX_POWER); | ||
| 1126 | pr_warn("Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n"); | ||
| 1127 | break; | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | flpi = &pr->power.lpi_states[flat_state_cnt]; | ||
| 1131 | |||
| 1132 | if (!prev_level) { /* leaf/processor node */ | ||
| 1133 | memcpy(flpi, t, sizeof(*t)); | ||
| 1134 | stash_composite_state(curr_level, flpi); | ||
| 1135 | flat_state_cnt++; | ||
| 1136 | continue; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | for (i = 0; i < prev_level->composite_states_size; i++) { | ||
| 1140 | p = prev_level->composite_states[i]; | ||
| 1141 | if (t->index <= p->enable_parent_state && | ||
| 1142 | combine_lpi_states(p, t, flpi)) { | ||
| 1143 | stash_composite_state(curr_level, flpi); | ||
| 1144 | flat_state_cnt++; | ||
| 1145 | flpi++; | ||
| 1146 | } | ||
| 1147 | } | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | kfree(curr_level->entries); | ||
| 1151 | return 0; | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | static int acpi_processor_get_lpi_info(struct acpi_processor *pr) | ||
| 1155 | { | ||
| 1156 | int ret, i; | ||
| 1157 | acpi_status status; | ||
| 1158 | acpi_handle handle = pr->handle, pr_ahandle; | ||
| 1159 | struct acpi_device *d = NULL; | ||
| 1160 | struct acpi_lpi_states_array info[2], *tmp, *prev, *curr; | ||
| 1161 | |||
| 1162 | if (!osc_pc_lpi_support_confirmed) | ||
| 1163 | return -EOPNOTSUPP; | ||
| 1164 | |||
| 1165 | if (!acpi_has_method(handle, "_LPI")) | ||
| 1166 | return -EINVAL; | ||
| 1167 | |||
| 1168 | flat_state_cnt = 0; | ||
| 1169 | prev = &info[0]; | ||
| 1170 | curr = &info[1]; | ||
| 1171 | handle = pr->handle; | ||
| 1172 | ret = acpi_processor_evaluate_lpi(handle, prev); | ||
| 1173 | if (ret) | ||
| 1174 | return ret; | ||
| 1175 | flatten_lpi_states(pr, prev, NULL); | ||
| 1176 | |||
| 1177 | status = acpi_get_parent(handle, &pr_ahandle); | ||
| 1178 | while (ACPI_SUCCESS(status)) { | ||
| 1179 | acpi_bus_get_device(pr_ahandle, &d); | ||
| 1180 | handle = pr_ahandle; | ||
| 1181 | |||
| 1182 | if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID)) | ||
| 1183 | break; | ||
| 1184 | |||
| 1185 | /* can be optional ? */ | ||
| 1186 | if (!acpi_has_method(handle, "_LPI")) | ||
| 1187 | break; | ||
| 1188 | |||
| 1189 | ret = acpi_processor_evaluate_lpi(handle, curr); | ||
| 1190 | if (ret) | ||
| 1191 | break; | ||
| 1192 | |||
| 1193 | /* flatten all the LPI states in this level of hierarchy */ | ||
| 1194 | flatten_lpi_states(pr, curr, prev); | ||
| 1195 | |||
| 1196 | tmp = prev, prev = curr, curr = tmp; | ||
| 1197 | |||
| 1198 | status = acpi_get_parent(handle, &pr_ahandle); | ||
| 1199 | } | ||
| 1200 | |||
| 1201 | pr->power.count = flat_state_cnt; | ||
| 1202 | /* reset the index after flattening */ | ||
| 1203 | for (i = 0; i < pr->power.count; i++) | ||
| 1204 | pr->power.lpi_states[i].index = i; | ||
| 1205 | |||
| 1206 | /* Tell driver that _LPI is supported. */ | ||
| 1207 | pr->flags.has_lpi = 1; | ||
| 1208 | pr->flags.power = 1; | ||
| 1209 | |||
| 1210 | return 0; | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | int __weak acpi_processor_ffh_lpi_probe(unsigned int cpu) | ||
| 1214 | { | ||
| 1215 | return -ENODEV; | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi) | ||
| 1219 | { | ||
| 1220 | return -ENODEV; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | /** | ||
| 1224 | * acpi_idle_lpi_enter - enters an ACPI any LPI state | ||
| 1225 | * @dev: the target CPU | ||
| 1226 | * @drv: cpuidle driver containing cpuidle state info | ||
| 1227 | * @index: index of target state | ||
| 1228 | * | ||
| 1229 | * Return: 0 for success or negative value for error | ||
| 1230 | */ | ||
| 1231 | static int acpi_idle_lpi_enter(struct cpuidle_device *dev, | ||
| 1232 | struct cpuidle_driver *drv, int index) | ||
| 1233 | { | ||
| 1234 | struct acpi_processor *pr; | ||
| 1235 | struct acpi_lpi_state *lpi; | ||
| 1236 | |||
| 1237 | pr = __this_cpu_read(processors); | ||
| 1238 | |||
| 1239 | if (unlikely(!pr)) | ||
| 1240 | return -EINVAL; | ||
| 1241 | |||
| 1242 | lpi = &pr->power.lpi_states[index]; | ||
| 1243 | if (lpi->entry_method == ACPI_CSTATE_FFH) | ||
| 1244 | return acpi_processor_ffh_lpi_enter(lpi); | ||
| 1245 | |||
| 1246 | return -EINVAL; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) | ||
| 1250 | { | ||
| 1251 | int i; | ||
| 1252 | struct acpi_lpi_state *lpi; | ||
| 1253 | struct cpuidle_state *state; | ||
| 1254 | struct cpuidle_driver *drv = &acpi_idle_driver; | ||
| 1255 | |||
| 1256 | if (!pr->flags.has_lpi) | ||
| 1257 | return -EOPNOTSUPP; | ||
| 1258 | |||
| 1259 | for (i = 0; i < pr->power.count && i < CPUIDLE_STATE_MAX; i++) { | ||
| 1260 | lpi = &pr->power.lpi_states[i]; | ||
| 1261 | |||
| 1262 | state = &drv->states[i]; | ||
| 1263 | snprintf(state->name, CPUIDLE_NAME_LEN, "LPI-%d", i); | ||
| 1264 | strlcpy(state->desc, lpi->desc, CPUIDLE_DESC_LEN); | ||
| 1265 | state->exit_latency = lpi->wake_latency; | ||
| 1266 | state->target_residency = lpi->min_residency; | ||
| 1267 | if (lpi->arch_flags) | ||
| 1268 | state->flags |= CPUIDLE_FLAG_TIMER_STOP; | ||
| 1269 | state->enter = acpi_idle_lpi_enter; | ||
| 1270 | drv->safe_state_index = i; | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | drv->state_count = i; | ||
| 1274 | |||
| 1275 | return 0; | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | /** | ||
| 1279 | * acpi_processor_setup_cpuidle_states- prepares and configures cpuidle | ||
| 1280 | * global state data i.e. idle routines | ||
| 1281 | * | ||
| 1282 | * @pr: the ACPI processor | ||
| 1283 | */ | ||
| 1284 | static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) | ||
| 1285 | { | ||
| 1286 | int i; | ||
| 1287 | struct cpuidle_driver *drv = &acpi_idle_driver; | ||
| 1288 | |||
| 1289 | if (!pr->flags.power_setup_done || !pr->flags.power) | ||
| 1290 | return -EINVAL; | ||
| 1291 | |||
| 1292 | drv->safe_state_index = -1; | ||
| 1293 | for (i = CPUIDLE_DRIVER_STATE_START; i < CPUIDLE_STATE_MAX; i++) { | ||
| 1294 | drv->states[i].name[0] = '\0'; | ||
| 1295 | drv->states[i].desc[0] = '\0'; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | if (pr->flags.has_lpi) | ||
| 1299 | return acpi_processor_setup_lpi_states(pr); | ||
| 1300 | |||
| 1301 | return acpi_processor_setup_cstates(pr); | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | /** | ||
| 1305 | * acpi_processor_setup_cpuidle_dev - prepares and configures CPUIDLE | ||
| 1306 | * device i.e. per-cpu data | ||
| 1307 | * | ||
| 1308 | * @pr: the ACPI processor | ||
| 1309 | * @dev : the cpuidle device | ||
| 1310 | */ | ||
| 1311 | static int acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr, | ||
| 1312 | struct cpuidle_device *dev) | ||
| 1313 | { | ||
| 1314 | if (!pr->flags.power_setup_done || !pr->flags.power || !dev) | ||
| 1315 | return -EINVAL; | ||
| 1316 | |||
| 1317 | dev->cpu = pr->id; | ||
| 1318 | if (pr->flags.has_lpi) | ||
| 1319 | return acpi_processor_ffh_lpi_probe(pr->id); | ||
| 1320 | |||
| 1321 | return acpi_processor_setup_cpuidle_cx(pr, dev); | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | static int acpi_processor_get_power_info(struct acpi_processor *pr) | ||
| 1325 | { | ||
| 1326 | int ret; | ||
| 1327 | |||
| 1328 | ret = acpi_processor_get_lpi_info(pr); | ||
| 1329 | if (ret) | ||
| 1330 | ret = acpi_processor_get_cstate_info(pr); | ||
| 1331 | |||
| 1332 | return ret; | ||
| 1333 | } | ||
| 1334 | |||
| 928 | int acpi_processor_hotplug(struct acpi_processor *pr) | 1335 | int acpi_processor_hotplug(struct acpi_processor *pr) |
| 929 | { | 1336 | { |
| 930 | int ret = 0; | 1337 | int ret = 0; |
| @@ -933,18 +1340,15 @@ int acpi_processor_hotplug(struct acpi_processor *pr) | |||
| 933 | if (disabled_by_idle_boot_param()) | 1340 | if (disabled_by_idle_boot_param()) |
| 934 | return 0; | 1341 | return 0; |
| 935 | 1342 | ||
| 936 | if (nocst) | ||
| 937 | return -ENODEV; | ||
| 938 | |||
| 939 | if (!pr->flags.power_setup_done) | 1343 | if (!pr->flags.power_setup_done) |
| 940 | return -ENODEV; | 1344 | return -ENODEV; |
| 941 | 1345 | ||
| 942 | dev = per_cpu(acpi_cpuidle_device, pr->id); | 1346 | dev = per_cpu(acpi_cpuidle_device, pr->id); |
| 943 | cpuidle_pause_and_lock(); | 1347 | cpuidle_pause_and_lock(); |
| 944 | cpuidle_disable_device(dev); | 1348 | cpuidle_disable_device(dev); |
| 945 | acpi_processor_get_power_info(pr); | 1349 | ret = acpi_processor_get_power_info(pr); |
| 946 | if (pr->flags.power) { | 1350 | if (!ret && pr->flags.power) { |
| 947 | acpi_processor_setup_cpuidle_cx(pr, dev); | 1351 | acpi_processor_setup_cpuidle_dev(pr, dev); |
| 948 | ret = cpuidle_enable_device(dev); | 1352 | ret = cpuidle_enable_device(dev); |
| 949 | } | 1353 | } |
| 950 | cpuidle_resume_and_unlock(); | 1354 | cpuidle_resume_and_unlock(); |
| @@ -952,7 +1356,7 @@ int acpi_processor_hotplug(struct acpi_processor *pr) | |||
| 952 | return ret; | 1356 | return ret; |
| 953 | } | 1357 | } |
| 954 | 1358 | ||
| 955 | int acpi_processor_cst_has_changed(struct acpi_processor *pr) | 1359 | int acpi_processor_power_state_has_changed(struct acpi_processor *pr) |
| 956 | { | 1360 | { |
| 957 | int cpu; | 1361 | int cpu; |
| 958 | struct acpi_processor *_pr; | 1362 | struct acpi_processor *_pr; |
| @@ -961,9 +1365,6 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) | |||
| 961 | if (disabled_by_idle_boot_param()) | 1365 | if (disabled_by_idle_boot_param()) |
| 962 | return 0; | 1366 | return 0; |
| 963 | 1367 | ||
| 964 | if (nocst) | ||
| 965 | return -ENODEV; | ||
| 966 | |||
| 967 | if (!pr->flags.power_setup_done) | 1368 | if (!pr->flags.power_setup_done) |
| 968 | return -ENODEV; | 1369 | return -ENODEV; |
| 969 | 1370 | ||
| @@ -1000,7 +1401,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) | |||
| 1000 | acpi_processor_get_power_info(_pr); | 1401 | acpi_processor_get_power_info(_pr); |
| 1001 | if (_pr->flags.power) { | 1402 | if (_pr->flags.power) { |
| 1002 | dev = per_cpu(acpi_cpuidle_device, cpu); | 1403 | dev = per_cpu(acpi_cpuidle_device, cpu); |
| 1003 | acpi_processor_setup_cpuidle_cx(_pr, dev); | 1404 | acpi_processor_setup_cpuidle_dev(_pr, dev); |
| 1004 | cpuidle_enable_device(dev); | 1405 | cpuidle_enable_device(dev); |
| 1005 | } | 1406 | } |
| 1006 | } | 1407 | } |
| @@ -1015,35 +1416,16 @@ static int acpi_processor_registered; | |||
| 1015 | 1416 | ||
| 1016 | int acpi_processor_power_init(struct acpi_processor *pr) | 1417 | int acpi_processor_power_init(struct acpi_processor *pr) |
| 1017 | { | 1418 | { |
| 1018 | acpi_status status; | ||
| 1019 | int retval; | 1419 | int retval; |
| 1020 | struct cpuidle_device *dev; | 1420 | struct cpuidle_device *dev; |
| 1021 | static int first_run; | ||
| 1022 | 1421 | ||
| 1023 | if (disabled_by_idle_boot_param()) | 1422 | if (disabled_by_idle_boot_param()) |
| 1024 | return 0; | 1423 | return 0; |
| 1025 | 1424 | ||
| 1026 | if (!first_run) { | 1425 | acpi_processor_cstate_first_run_checks(); |
| 1027 | dmi_check_system(processor_power_dmi_table); | ||
| 1028 | max_cstate = acpi_processor_cstate_check(max_cstate); | ||
| 1029 | if (max_cstate < ACPI_C_STATES_MAX) | ||
| 1030 | printk(KERN_NOTICE | ||
| 1031 | "ACPI: processor limited to max C-state %d\n", | ||
| 1032 | max_cstate); | ||
| 1033 | first_run++; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | if (acpi_gbl_FADT.cst_control && !nocst) { | ||
| 1037 | status = | ||
| 1038 | acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8); | ||
| 1039 | if (ACPI_FAILURE(status)) { | ||
| 1040 | ACPI_EXCEPTION((AE_INFO, status, | ||
| 1041 | "Notifying BIOS of _CST ability failed")); | ||
| 1042 | } | ||
| 1043 | } | ||
| 1044 | 1426 | ||
| 1045 | acpi_processor_get_power_info(pr); | 1427 | if (!acpi_processor_get_power_info(pr)) |
| 1046 | pr->flags.power_setup_done = 1; | 1428 | pr->flags.power_setup_done = 1; |
| 1047 | 1429 | ||
| 1048 | /* | 1430 | /* |
| 1049 | * Install the idle handler if processor power management is supported. | 1431 | * Install the idle handler if processor power management is supported. |
| @@ -1066,7 +1448,7 @@ int acpi_processor_power_init(struct acpi_processor *pr) | |||
| 1066 | return -ENOMEM; | 1448 | return -ENOMEM; |
| 1067 | per_cpu(acpi_cpuidle_device, pr->id) = dev; | 1449 | per_cpu(acpi_cpuidle_device, pr->id) = dev; |
| 1068 | 1450 | ||
| 1069 | acpi_processor_setup_cpuidle_cx(pr, dev); | 1451 | acpi_processor_setup_cpuidle_dev(pr, dev); |
| 1070 | 1452 | ||
| 1071 | /* Register per-cpu cpuidle_device. Cpuidle driver | 1453 | /* Register per-cpu cpuidle_device. Cpuidle driver |
| 1072 | * must already be registered before registering device | 1454 | * must already be registered before registering device |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5f28cf778349..405056b95b05 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
| @@ -494,6 +494,8 @@ static void acpi_device_del(struct acpi_device *device) | |||
| 494 | device_del(&device->dev); | 494 | device_del(&device->dev); |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | static BLOCKING_NOTIFIER_HEAD(acpi_reconfig_chain); | ||
| 498 | |||
| 497 | static LIST_HEAD(acpi_device_del_list); | 499 | static LIST_HEAD(acpi_device_del_list); |
| 498 | static DEFINE_MUTEX(acpi_device_del_lock); | 500 | static DEFINE_MUTEX(acpi_device_del_lock); |
| 499 | 501 | ||
| @@ -514,6 +516,9 @@ static void acpi_device_del_work_fn(struct work_struct *work_not_used) | |||
| 514 | 516 | ||
| 515 | mutex_unlock(&acpi_device_del_lock); | 517 | mutex_unlock(&acpi_device_del_lock); |
| 516 | 518 | ||
| 519 | blocking_notifier_call_chain(&acpi_reconfig_chain, | ||
| 520 | ACPI_RECONFIG_DEVICE_REMOVE, adev); | ||
| 521 | |||
| 517 | acpi_device_del(adev); | 522 | acpi_device_del(adev); |
| 518 | /* | 523 | /* |
| 519 | * Drop references to all power resources that might have been | 524 | * Drop references to all power resources that might have been |
| @@ -1406,7 +1411,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, | |||
| 1406 | acpi_bus_get_flags(device); | 1411 | acpi_bus_get_flags(device); |
| 1407 | device->flags.match_driver = false; | 1412 | device->flags.match_driver = false; |
| 1408 | device->flags.initialized = true; | 1413 | device->flags.initialized = true; |
| 1409 | device->flags.visited = false; | 1414 | acpi_device_clear_enumerated(device); |
| 1410 | device_initialize(&device->dev); | 1415 | device_initialize(&device->dev); |
| 1411 | dev_set_uevent_suppress(&device->dev, true); | 1416 | dev_set_uevent_suppress(&device->dev, true); |
| 1412 | acpi_init_coherency(device); | 1417 | acpi_init_coherency(device); |
| @@ -1676,15 +1681,20 @@ static void acpi_default_enumeration(struct acpi_device *device) | |||
| 1676 | bool is_spi_i2c_slave = false; | 1681 | bool is_spi_i2c_slave = false; |
| 1677 | 1682 | ||
| 1678 | /* | 1683 | /* |
| 1679 | * Do not enemerate SPI/I2C slaves as they will be enuerated by their | 1684 | * Do not enumerate SPI/I2C slaves as they will be enumerated by their |
| 1680 | * respective parents. | 1685 | * respective parents. |
| 1681 | */ | 1686 | */ |
| 1682 | INIT_LIST_HEAD(&resource_list); | 1687 | INIT_LIST_HEAD(&resource_list); |
| 1683 | acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave, | 1688 | acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave, |
| 1684 | &is_spi_i2c_slave); | 1689 | &is_spi_i2c_slave); |
| 1685 | acpi_dev_free_resource_list(&resource_list); | 1690 | acpi_dev_free_resource_list(&resource_list); |
| 1686 | if (!is_spi_i2c_slave) | 1691 | if (!is_spi_i2c_slave) { |
| 1687 | acpi_create_platform_device(device); | 1692 | acpi_create_platform_device(device); |
| 1693 | acpi_device_set_enumerated(device); | ||
| 1694 | } else { | ||
| 1695 | blocking_notifier_call_chain(&acpi_reconfig_chain, | ||
| 1696 | ACPI_RECONFIG_DEVICE_ADD, device); | ||
| 1697 | } | ||
| 1688 | } | 1698 | } |
| 1689 | 1699 | ||
| 1690 | static const struct acpi_device_id generic_device_ids[] = { | 1700 | static const struct acpi_device_id generic_device_ids[] = { |
| @@ -1751,7 +1761,7 @@ static void acpi_bus_attach(struct acpi_device *device) | |||
| 1751 | acpi_bus_get_status(device); | 1761 | acpi_bus_get_status(device); |
| 1752 | /* Skip devices that are not present. */ | 1762 | /* Skip devices that are not present. */ |
| 1753 | if (!acpi_device_is_present(device)) { | 1763 | if (!acpi_device_is_present(device)) { |
| 1754 | device->flags.visited = false; | 1764 | acpi_device_clear_enumerated(device); |
| 1755 | device->flags.power_manageable = 0; | 1765 | device->flags.power_manageable = 0; |
| 1756 | return; | 1766 | return; |
| 1757 | } | 1767 | } |
| @@ -1766,7 +1776,7 @@ static void acpi_bus_attach(struct acpi_device *device) | |||
| 1766 | 1776 | ||
| 1767 | device->flags.initialized = true; | 1777 | device->flags.initialized = true; |
| 1768 | } | 1778 | } |
| 1769 | device->flags.visited = false; | 1779 | |
| 1770 | ret = acpi_scan_attach_handler(device); | 1780 | ret = acpi_scan_attach_handler(device); |
| 1771 | if (ret < 0) | 1781 | if (ret < 0) |
| 1772 | return; | 1782 | return; |
| @@ -1780,7 +1790,6 @@ static void acpi_bus_attach(struct acpi_device *device) | |||
| 1780 | if (!ret && device->pnp.type.platform_id) | 1790 | if (!ret && device->pnp.type.platform_id) |
| 1781 | acpi_default_enumeration(device); | 1791 | acpi_default_enumeration(device); |
| 1782 | } | 1792 | } |
| 1783 | device->flags.visited = true; | ||
| 1784 | 1793 | ||
| 1785 | ok: | 1794 | ok: |
| 1786 | list_for_each_entry(child, &device->children, node) | 1795 | list_for_each_entry(child, &device->children, node) |
| @@ -1872,7 +1881,7 @@ void acpi_bus_trim(struct acpi_device *adev) | |||
| 1872 | */ | 1881 | */ |
| 1873 | acpi_device_set_power(adev, ACPI_STATE_D3_COLD); | 1882 | acpi_device_set_power(adev, ACPI_STATE_D3_COLD); |
| 1874 | adev->flags.initialized = false; | 1883 | adev->flags.initialized = false; |
| 1875 | adev->flags.visited = false; | 1884 | acpi_device_clear_enumerated(adev); |
| 1876 | } | 1885 | } |
| 1877 | EXPORT_SYMBOL_GPL(acpi_bus_trim); | 1886 | EXPORT_SYMBOL_GPL(acpi_bus_trim); |
| 1878 | 1887 | ||
| @@ -1916,6 +1925,8 @@ static int acpi_bus_scan_fixed(void) | |||
| 1916 | return result < 0 ? result : 0; | 1925 | return result < 0 ? result : 0; |
| 1917 | } | 1926 | } |
| 1918 | 1927 | ||
| 1928 | static bool acpi_scan_initialized; | ||
| 1929 | |||
| 1919 | int __init acpi_scan_init(void) | 1930 | int __init acpi_scan_init(void) |
| 1920 | { | 1931 | { |
| 1921 | int result; | 1932 | int result; |
| @@ -1960,6 +1971,8 @@ int __init acpi_scan_init(void) | |||
| 1960 | 1971 | ||
| 1961 | acpi_update_all_gpes(); | 1972 | acpi_update_all_gpes(); |
| 1962 | 1973 | ||
| 1974 | acpi_scan_initialized = true; | ||
| 1975 | |||
| 1963 | out: | 1976 | out: |
| 1964 | mutex_unlock(&acpi_scan_lock); | 1977 | mutex_unlock(&acpi_scan_lock); |
| 1965 | return result; | 1978 | return result; |
| @@ -2003,3 +2016,57 @@ int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr) | |||
| 2003 | 2016 | ||
| 2004 | return count; | 2017 | return count; |
| 2005 | } | 2018 | } |
| 2019 | |||
| 2020 | struct acpi_table_events_work { | ||
| 2021 | struct work_struct work; | ||
| 2022 | void *table; | ||
| 2023 | u32 event; | ||
| 2024 | }; | ||
| 2025 | |||
| 2026 | static void acpi_table_events_fn(struct work_struct *work) | ||
| 2027 | { | ||
| 2028 | struct acpi_table_events_work *tew; | ||
| 2029 | |||
| 2030 | tew = container_of(work, struct acpi_table_events_work, work); | ||
| 2031 | |||
| 2032 | if (tew->event == ACPI_TABLE_EVENT_LOAD) { | ||
| 2033 | acpi_scan_lock_acquire(); | ||
| 2034 | acpi_bus_scan(ACPI_ROOT_OBJECT); | ||
| 2035 | acpi_scan_lock_release(); | ||
| 2036 | } | ||
| 2037 | |||
| 2038 | kfree(tew); | ||
| 2039 | } | ||
| 2040 | |||
| 2041 | void acpi_scan_table_handler(u32 event, void *table, void *context) | ||
| 2042 | { | ||
| 2043 | struct acpi_table_events_work *tew; | ||
| 2044 | |||
| 2045 | if (!acpi_scan_initialized) | ||
| 2046 | return; | ||
| 2047 | |||
| 2048 | if (event != ACPI_TABLE_EVENT_LOAD) | ||
| 2049 | return; | ||
| 2050 | |||
| 2051 | tew = kmalloc(sizeof(*tew), GFP_KERNEL); | ||
| 2052 | if (!tew) | ||
| 2053 | return; | ||
| 2054 | |||
| 2055 | INIT_WORK(&tew->work, acpi_table_events_fn); | ||
| 2056 | tew->table = table; | ||
| 2057 | tew->event = event; | ||
| 2058 | |||
| 2059 | schedule_work(&tew->work); | ||
| 2060 | } | ||
| 2061 | |||
| 2062 | int acpi_reconfig_notifier_register(struct notifier_block *nb) | ||
| 2063 | { | ||
| 2064 | return blocking_notifier_chain_register(&acpi_reconfig_chain, nb); | ||
| 2065 | } | ||
| 2066 | EXPORT_SYMBOL(acpi_reconfig_notifier_register); | ||
| 2067 | |||
| 2068 | int acpi_reconfig_notifier_unregister(struct notifier_block *nb) | ||
| 2069 | { | ||
| 2070 | return blocking_notifier_chain_unregister(&acpi_reconfig_chain, nb); | ||
| 2071 | } | ||
| 2072 | EXPORT_SYMBOL(acpi_reconfig_notifier_unregister); | ||
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 7a2e4d45b266..2b38c1bb0446 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
| @@ -47,15 +47,32 @@ static void acpi_sleep_tts_switch(u32 acpi_state) | |||
| 47 | } | 47 | } |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static int tts_notify_reboot(struct notifier_block *this, | 50 | static void acpi_sleep_pts_switch(u32 acpi_state) |
| 51 | { | ||
| 52 | acpi_status status; | ||
| 53 | |||
| 54 | status = acpi_execute_simple_method(NULL, "\\_PTS", acpi_state); | ||
| 55 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||
| 56 | /* | ||
| 57 | * OS can't evaluate the _PTS object correctly. Some warning | ||
| 58 | * message will be printed. But it won't break anything. | ||
| 59 | */ | ||
| 60 | printk(KERN_NOTICE "Failure in evaluating _PTS object\n"); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | static int sleep_notify_reboot(struct notifier_block *this, | ||
| 51 | unsigned long code, void *x) | 65 | unsigned long code, void *x) |
| 52 | { | 66 | { |
| 53 | acpi_sleep_tts_switch(ACPI_STATE_S5); | 67 | acpi_sleep_tts_switch(ACPI_STATE_S5); |
| 68 | |||
| 69 | acpi_sleep_pts_switch(ACPI_STATE_S5); | ||
| 70 | |||
| 54 | return NOTIFY_DONE; | 71 | return NOTIFY_DONE; |
| 55 | } | 72 | } |
| 56 | 73 | ||
| 57 | static struct notifier_block tts_notifier = { | 74 | static struct notifier_block sleep_notifier = { |
| 58 | .notifier_call = tts_notify_reboot, | 75 | .notifier_call = sleep_notify_reboot, |
| 59 | .next = NULL, | 76 | .next = NULL, |
| 60 | .priority = 0, | 77 | .priority = 0, |
| 61 | }; | 78 | }; |
| @@ -899,9 +916,9 @@ int __init acpi_sleep_init(void) | |||
| 899 | pr_info(PREFIX "(supports%s)\n", supported); | 916 | pr_info(PREFIX "(supports%s)\n", supported); |
| 900 | 917 | ||
| 901 | /* | 918 | /* |
| 902 | * Register the tts_notifier to reboot notifier list so that the _TTS | 919 | * Register the sleep_notifier to reboot notifier list so that the _TTS |
| 903 | * object can also be evaluated when the system enters S5. | 920 | * and _PTS object can also be evaluated when the system enters S5. |
| 904 | */ | 921 | */ |
| 905 | register_reboot_notifier(&tts_notifier); | 922 | register_reboot_notifier(&sleep_notifier); |
| 906 | return 0; | 923 | return 0; |
| 907 | } | 924 | } |
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 4b3a9e27f1b6..358165e9f5b8 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c | |||
| @@ -378,8 +378,7 @@ static void acpi_table_attr_init(struct acpi_table_attr *table_attr, | |||
| 378 | return; | 378 | return; |
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | static acpi_status | 381 | acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context) |
| 382 | acpi_sysfs_table_handler(u32 event, void *table, void *context) | ||
| 383 | { | 382 | { |
| 384 | struct acpi_table_attr *table_attr; | 383 | struct acpi_table_attr *table_attr; |
| 385 | 384 | ||
| @@ -452,9 +451,8 @@ static int acpi_tables_sysfs_init(void) | |||
| 452 | 451 | ||
| 453 | kobject_uevent(tables_kobj, KOBJ_ADD); | 452 | kobject_uevent(tables_kobj, KOBJ_ADD); |
| 454 | kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); | 453 | kobject_uevent(dynamic_tables_kobj, KOBJ_ADD); |
| 455 | status = acpi_install_table_handler(acpi_sysfs_table_handler, NULL); | ||
| 456 | 454 | ||
| 457 | return ACPI_FAILURE(status) ? -EINVAL : 0; | 455 | return 0; |
| 458 | err_dynamic_tables: | 456 | err_dynamic_tables: |
| 459 | kobject_put(tables_kobj); | 457 | kobject_put(tables_kobj); |
| 460 | err: | 458 | err: |
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index a372f9eaa15d..9f0ad6ebb368 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c | |||
| @@ -34,6 +34,8 @@ | |||
| 34 | #include <linux/bootmem.h> | 34 | #include <linux/bootmem.h> |
| 35 | #include <linux/earlycpio.h> | 35 | #include <linux/earlycpio.h> |
| 36 | #include <linux/memblock.h> | 36 | #include <linux/memblock.h> |
| 37 | #include <linux/initrd.h> | ||
| 38 | #include <linux/acpi.h> | ||
| 37 | #include "internal.h" | 39 | #include "internal.h" |
| 38 | 40 | ||
| 39 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 41 | #ifdef CONFIG_ACPI_CUSTOM_DSDT |
| @@ -481,8 +483,10 @@ static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES); | |||
| 481 | 483 | ||
| 482 | #define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) | 484 | #define MAP_CHUNK_SIZE (NR_FIX_BTMAPS << PAGE_SHIFT) |
| 483 | 485 | ||
| 484 | static void __init acpi_table_initrd_init(void *data, size_t size) | 486 | void __init acpi_table_upgrade(void) |
| 485 | { | 487 | { |
| 488 | void *data = (void *)initrd_start; | ||
| 489 | size_t size = initrd_end - initrd_start; | ||
| 486 | int sig, no, table_nr = 0, total_offset = 0; | 490 | int sig, no, table_nr = 0, total_offset = 0; |
| 487 | long offset = 0; | 491 | long offset = 0; |
| 488 | struct acpi_table_header *table; | 492 | struct acpi_table_header *table; |
| @@ -540,7 +544,7 @@ static void __init acpi_table_initrd_init(void *data, size_t size) | |||
| 540 | return; | 544 | return; |
| 541 | 545 | ||
| 542 | acpi_tables_addr = | 546 | acpi_tables_addr = |
| 543 | memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT, | 547 | memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS, |
| 544 | all_tables_size, PAGE_SIZE); | 548 | all_tables_size, PAGE_SIZE); |
| 545 | if (!acpi_tables_addr) { | 549 | if (!acpi_tables_addr) { |
| 546 | WARN_ON(1); | 550 | WARN_ON(1); |
| @@ -578,10 +582,10 @@ static void __init acpi_table_initrd_init(void *data, size_t size) | |||
| 578 | clen = size; | 582 | clen = size; |
| 579 | if (clen > MAP_CHUNK_SIZE - slop) | 583 | if (clen > MAP_CHUNK_SIZE - slop) |
| 580 | clen = MAP_CHUNK_SIZE - slop; | 584 | clen = MAP_CHUNK_SIZE - slop; |
| 581 | dest_p = early_ioremap(dest_addr & PAGE_MASK, | 585 | dest_p = early_memremap(dest_addr & PAGE_MASK, |
| 582 | clen + slop); | 586 | clen + slop); |
| 583 | memcpy(dest_p + slop, src_p, clen); | 587 | memcpy(dest_p + slop, src_p, clen); |
| 584 | early_iounmap(dest_p, clen + slop); | 588 | early_memunmap(dest_p, clen + slop); |
| 585 | src_p += clen; | 589 | src_p += clen; |
| 586 | dest_addr += clen; | 590 | dest_addr += clen; |
| 587 | size -= clen; | 591 | size -= clen; |
| @@ -696,10 +700,6 @@ next_table: | |||
| 696 | } | 700 | } |
| 697 | } | 701 | } |
| 698 | #else | 702 | #else |
| 699 | static void __init acpi_table_initrd_init(void *data, size_t size) | ||
| 700 | { | ||
| 701 | } | ||
| 702 | |||
| 703 | static acpi_status | 703 | static acpi_status |
| 704 | acpi_table_initrd_override(struct acpi_table_header *existing_table, | 704 | acpi_table_initrd_override(struct acpi_table_header *existing_table, |
| 705 | acpi_physical_address *address, | 705 | acpi_physical_address *address, |
| @@ -742,11 +742,6 @@ acpi_os_table_override(struct acpi_table_header *existing_table, | |||
| 742 | return AE_OK; | 742 | return AE_OK; |
| 743 | } | 743 | } |
| 744 | 744 | ||
| 745 | void __init early_acpi_table_init(void *data, size_t size) | ||
| 746 | { | ||
| 747 | acpi_table_initrd_init(data, size); | ||
| 748 | } | ||
| 749 | |||
| 750 | /* | 745 | /* |
| 751 | * acpi_table_init() | 746 | * acpi_table_init() |
| 752 | * | 747 | * |
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 82707f9824ca..f4ebe39539af 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
| @@ -1259,7 +1259,8 @@ static int __init acpi_thermal_init(void) | |||
| 1259 | return -ENODEV; | 1259 | return -ENODEV; |
| 1260 | } | 1260 | } |
| 1261 | 1261 | ||
| 1262 | acpi_thermal_pm_queue = create_workqueue("acpi_thermal_pm"); | 1262 | acpi_thermal_pm_queue = alloc_workqueue("acpi_thermal_pm", |
| 1263 | WQ_HIGHPRI | WQ_MEM_RECLAIM, 0); | ||
| 1263 | if (!acpi_thermal_pm_queue) | 1264 | if (!acpi_thermal_pm_queue) |
| 1264 | return -ENODEV; | 1265 | return -ENODEV; |
| 1265 | 1266 | ||
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 3d1327615f72..a6b36fc53aec 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c | |||
| @@ -167,6 +167,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { | |||
| 167 | DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"), | 167 | DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"), |
| 168 | }, | 168 | }, |
| 169 | }, | 169 | }, |
| 170 | { | ||
| 171 | .callback = video_detect_force_video, | ||
| 172 | .ident = "ThinkPad X201T", | ||
| 173 | .matches = { | ||
| 174 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), | ||
| 175 | DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"), | ||
| 176 | }, | ||
| 177 | }, | ||
| 170 | 178 | ||
| 171 | /* The native backlight controls do not work on some older machines */ | 179 | /* The native backlight controls do not work on some older machines */ |
| 172 | { | 180 | { |
diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index e342565e8715..4ba3d3fe142f 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c | |||
| @@ -36,26 +36,12 @@ | |||
| 36 | static int arm_enter_idle_state(struct cpuidle_device *dev, | 36 | static int arm_enter_idle_state(struct cpuidle_device *dev, |
| 37 | struct cpuidle_driver *drv, int idx) | 37 | struct cpuidle_driver *drv, int idx) |
| 38 | { | 38 | { |
| 39 | int ret; | 39 | /* |
| 40 | 40 | * Pass idle state index to arm_cpuidle_suspend which in turn | |
| 41 | if (!idx) { | 41 | * will call the CPU ops suspend protocol with idle index as a |
| 42 | cpu_do_idle(); | 42 | * parameter. |
| 43 | return idx; | 43 | */ |
| 44 | } | 44 | return CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, idx); |
| 45 | |||
| 46 | ret = cpu_pm_enter(); | ||
| 47 | if (!ret) { | ||
| 48 | /* | ||
| 49 | * Pass idle state index to cpu_suspend which in turn will | ||
| 50 | * call the CPU ops suspend protocol with idle index as a | ||
| 51 | * parameter. | ||
| 52 | */ | ||
| 53 | ret = arm_cpuidle_suspend(idx); | ||
| 54 | |||
| 55 | cpu_pm_exit(); | ||
| 56 | } | ||
| 57 | |||
| 58 | return ret ? -1 : idx; | ||
| 59 | } | 45 | } |
| 60 | 46 | ||
| 61 | static struct cpuidle_driver arm_idle_driver = { | 47 | static struct cpuidle_driver arm_idle_driver = { |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 05509f3aaee8..8730fd475bf3 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
| @@ -24,6 +24,9 @@ | |||
| 24 | #include <linux/of_fdt.h> | 24 | #include <linux/of_fdt.h> |
| 25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
| 26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/acpi.h> | ||
| 29 | #include <linux/ucs2_string.h> | ||
| 27 | 30 | ||
| 28 | #include <asm/early_ioremap.h> | 31 | #include <asm/early_ioremap.h> |
| 29 | 32 | ||
| @@ -195,6 +198,96 @@ static void generic_ops_unregister(void) | |||
| 195 | efivars_unregister(&generic_efivars); | 198 | efivars_unregister(&generic_efivars); |
| 196 | } | 199 | } |
| 197 | 200 | ||
| 201 | #if IS_ENABLED(CONFIG_ACPI) | ||
| 202 | #define EFIVAR_SSDT_NAME_MAX 16 | ||
| 203 | static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata; | ||
| 204 | static int __init efivar_ssdt_setup(char *str) | ||
| 205 | { | ||
| 206 | if (strlen(str) < sizeof(efivar_ssdt)) | ||
| 207 | memcpy(efivar_ssdt, str, strlen(str)); | ||
| 208 | else | ||
| 209 | pr_warn("efivar_ssdt: name too long: %s\n", str); | ||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | __setup("efivar_ssdt=", efivar_ssdt_setup); | ||
| 213 | |||
| 214 | static __init int efivar_ssdt_iter(efi_char16_t *name, efi_guid_t vendor, | ||
| 215 | unsigned long name_size, void *data) | ||
| 216 | { | ||
| 217 | struct efivar_entry *entry; | ||
| 218 | struct list_head *list = data; | ||
| 219 | char utf8_name[EFIVAR_SSDT_NAME_MAX]; | ||
| 220 | int limit = min_t(unsigned long, EFIVAR_SSDT_NAME_MAX, name_size); | ||
| 221 | |||
| 222 | ucs2_as_utf8(utf8_name, name, limit - 1); | ||
| 223 | if (strncmp(utf8_name, efivar_ssdt, limit) != 0) | ||
| 224 | return 0; | ||
| 225 | |||
| 226 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 227 | if (!entry) | ||
| 228 | return 0; | ||
| 229 | |||
| 230 | memcpy(entry->var.VariableName, name, name_size); | ||
| 231 | memcpy(&entry->var.VendorGuid, &vendor, sizeof(efi_guid_t)); | ||
| 232 | |||
| 233 | efivar_entry_add(entry, list); | ||
| 234 | |||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | static __init int efivar_ssdt_load(void) | ||
| 239 | { | ||
| 240 | LIST_HEAD(entries); | ||
| 241 | struct efivar_entry *entry, *aux; | ||
| 242 | unsigned long size; | ||
| 243 | void *data; | ||
| 244 | int ret; | ||
| 245 | |||
| 246 | ret = efivar_init(efivar_ssdt_iter, &entries, true, &entries); | ||
| 247 | |||
| 248 | list_for_each_entry_safe(entry, aux, &entries, list) { | ||
| 249 | pr_info("loading SSDT from variable %s-%pUl\n", efivar_ssdt, | ||
| 250 | &entry->var.VendorGuid); | ||
| 251 | |||
| 252 | list_del(&entry->list); | ||
| 253 | |||
| 254 | ret = efivar_entry_size(entry, &size); | ||
| 255 | if (ret) { | ||
| 256 | pr_err("failed to get var size\n"); | ||
| 257 | goto free_entry; | ||
| 258 | } | ||
| 259 | |||
| 260 | data = kmalloc(size, GFP_KERNEL); | ||
| 261 | if (!data) | ||
| 262 | goto free_entry; | ||
| 263 | |||
| 264 | ret = efivar_entry_get(entry, NULL, &size, data); | ||
| 265 | if (ret) { | ||
| 266 | pr_err("failed to get var data\n"); | ||
| 267 | goto free_data; | ||
| 268 | } | ||
| 269 | |||
| 270 | ret = acpi_load_table(data); | ||
| 271 | if (ret) { | ||
| 272 | pr_err("failed to load table: %d\n", ret); | ||
| 273 | goto free_data; | ||
| 274 | } | ||
| 275 | |||
| 276 | goto free_entry; | ||
| 277 | |||
| 278 | free_data: | ||
| 279 | kfree(data); | ||
| 280 | |||
| 281 | free_entry: | ||
| 282 | kfree(entry); | ||
| 283 | } | ||
| 284 | |||
| 285 | return ret; | ||
| 286 | } | ||
| 287 | #else | ||
| 288 | static inline int efivar_ssdt_load(void) { return 0; } | ||
| 289 | #endif | ||
| 290 | |||
| 198 | /* | 291 | /* |
| 199 | * We register the efi subsystem with the firmware subsystem and the | 292 | * We register the efi subsystem with the firmware subsystem and the |
| 200 | * efivars subsystem with the efi subsystem, if the system was booted with | 293 | * efivars subsystem with the efi subsystem, if the system was booted with |
| @@ -218,6 +311,9 @@ static int __init efisubsys_init(void) | |||
| 218 | if (error) | 311 | if (error) |
| 219 | goto err_put; | 312 | goto err_put; |
| 220 | 313 | ||
| 314 | if (efi_enabled(EFI_RUNTIME_SERVICES)) | ||
| 315 | efivar_ssdt_load(); | ||
| 316 | |||
| 221 | error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); | 317 | error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); |
| 222 | if (error) { | 318 | if (error) { |
| 223 | pr_err("efi: Sysfs attribute export failed with error %d.\n", | 319 | pr_err("efi: Sysfs attribute export failed with error %d.\n", |
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 03e04582791c..8263429e21b8 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #define pr_fmt(fmt) "psci: " fmt | 14 | #define pr_fmt(fmt) "psci: " fmt |
| 15 | 15 | ||
| 16 | #include <linux/acpi.h> | ||
| 16 | #include <linux/arm-smccc.h> | 17 | #include <linux/arm-smccc.h> |
| 17 | #include <linux/cpuidle.h> | 18 | #include <linux/cpuidle.h> |
| 18 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
| @@ -256,13 +257,6 @@ static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu) | |||
| 256 | u32 *psci_states; | 257 | u32 *psci_states; |
| 257 | struct device_node *state_node; | 258 | struct device_node *state_node; |
| 258 | 259 | ||
| 259 | /* | ||
| 260 | * If the PSCI cpu_suspend function hook has not been initialized | ||
| 261 | * idle states must not be enabled, so bail out | ||
| 262 | */ | ||
| 263 | if (!psci_ops.cpu_suspend) | ||
| 264 | return -EOPNOTSUPP; | ||
| 265 | |||
| 266 | /* Count idle states */ | 260 | /* Count idle states */ |
| 267 | while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", | 261 | while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", |
| 268 | count))) { | 262 | count))) { |
| @@ -310,11 +304,69 @@ free_mem: | |||
| 310 | return ret; | 304 | return ret; |
| 311 | } | 305 | } |
| 312 | 306 | ||
| 307 | #ifdef CONFIG_ACPI | ||
| 308 | #include <acpi/processor.h> | ||
| 309 | |||
| 310 | static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu) | ||
| 311 | { | ||
| 312 | int i, count; | ||
| 313 | u32 *psci_states; | ||
| 314 | struct acpi_lpi_state *lpi; | ||
| 315 | struct acpi_processor *pr = per_cpu(processors, cpu); | ||
| 316 | |||
| 317 | if (unlikely(!pr || !pr->flags.has_lpi)) | ||
| 318 | return -EINVAL; | ||
| 319 | |||
| 320 | count = pr->power.count - 1; | ||
| 321 | if (count <= 0) | ||
| 322 | return -ENODEV; | ||
| 323 | |||
| 324 | psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); | ||
| 325 | if (!psci_states) | ||
| 326 | return -ENOMEM; | ||
| 327 | |||
| 328 | for (i = 0; i < count; i++) { | ||
| 329 | u32 state; | ||
| 330 | |||
| 331 | lpi = &pr->power.lpi_states[i + 1]; | ||
| 332 | /* | ||
| 333 | * Only bits[31:0] represent a PSCI power_state while | ||
| 334 | * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification | ||
| 335 | */ | ||
| 336 | state = lpi->address; | ||
| 337 | if (!psci_power_state_is_valid(state)) { | ||
| 338 | pr_warn("Invalid PSCI power state %#x\n", state); | ||
| 339 | kfree(psci_states); | ||
| 340 | return -EINVAL; | ||
| 341 | } | ||
| 342 | psci_states[i] = state; | ||
| 343 | } | ||
| 344 | /* Idle states parsed correctly, initialize per-cpu pointer */ | ||
| 345 | per_cpu(psci_power_state, cpu) = psci_states; | ||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | #else | ||
| 349 | static int __maybe_unused psci_acpi_cpu_init_idle(unsigned int cpu) | ||
| 350 | { | ||
| 351 | return -EINVAL; | ||
| 352 | } | ||
| 353 | #endif | ||
| 354 | |||
| 313 | int psci_cpu_init_idle(unsigned int cpu) | 355 | int psci_cpu_init_idle(unsigned int cpu) |
| 314 | { | 356 | { |
| 315 | struct device_node *cpu_node; | 357 | struct device_node *cpu_node; |
| 316 | int ret; | 358 | int ret; |
| 317 | 359 | ||
| 360 | /* | ||
| 361 | * If the PSCI cpu_suspend function hook has not been initialized | ||
| 362 | * idle states must not be enabled, so bail out | ||
| 363 | */ | ||
| 364 | if (!psci_ops.cpu_suspend) | ||
| 365 | return -EOPNOTSUPP; | ||
| 366 | |||
| 367 | if (!acpi_disabled) | ||
| 368 | return psci_acpi_cpu_init_idle(cpu); | ||
| 369 | |||
| 318 | cpu_node = of_get_cpu_node(cpu, NULL); | 370 | cpu_node = of_get_cpu_node(cpu, NULL); |
| 319 | if (!cpu_node) | 371 | if (!cpu_node) |
| 320 | return -ENODEV; | 372 | return -ENODEV; |
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index af11b658984d..74e5aeaf84f9 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
| @@ -107,12 +107,11 @@ struct acpi_i2c_lookup { | |||
| 107 | acpi_handle device_handle; | 107 | acpi_handle device_handle; |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) | 110 | static int acpi_i2c_fill_info(struct acpi_resource *ares, void *data) |
| 111 | { | 111 | { |
| 112 | struct acpi_i2c_lookup *lookup = data; | 112 | struct acpi_i2c_lookup *lookup = data; |
| 113 | struct i2c_board_info *info = lookup->info; | 113 | struct i2c_board_info *info = lookup->info; |
| 114 | struct acpi_resource_i2c_serialbus *sb; | 114 | struct acpi_resource_i2c_serialbus *sb; |
| 115 | acpi_handle adapter_handle; | ||
| 116 | acpi_status status; | 115 | acpi_status status; |
| 117 | 116 | ||
| 118 | if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) | 117 | if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) |
| @@ -122,80 +121,102 @@ static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) | |||
| 122 | if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) | 121 | if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) |
| 123 | return 1; | 122 | return 1; |
| 124 | 123 | ||
| 125 | /* | ||
| 126 | * Extract the ResourceSource and make sure that the handle matches | ||
| 127 | * with the I2C adapter handle. | ||
| 128 | */ | ||
| 129 | status = acpi_get_handle(lookup->device_handle, | 124 | status = acpi_get_handle(lookup->device_handle, |
| 130 | sb->resource_source.string_ptr, | 125 | sb->resource_source.string_ptr, |
| 131 | &adapter_handle); | 126 | &lookup->adapter_handle); |
| 132 | if (ACPI_SUCCESS(status) && adapter_handle == lookup->adapter_handle) { | 127 | if (!ACPI_SUCCESS(status)) |
| 133 | info->addr = sb->slave_address; | 128 | return 1; |
| 134 | if (sb->access_mode == ACPI_I2C_10BIT_MODE) | 129 | |
| 135 | info->flags |= I2C_CLIENT_TEN; | 130 | info->addr = sb->slave_address; |
| 136 | } | 131 | if (sb->access_mode == ACPI_I2C_10BIT_MODE) |
| 132 | info->flags |= I2C_CLIENT_TEN; | ||
| 137 | 133 | ||
| 138 | return 1; | 134 | return 1; |
| 139 | } | 135 | } |
| 140 | 136 | ||
| 141 | static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, | 137 | static int acpi_i2c_get_info(struct acpi_device *adev, |
| 142 | void *data, void **return_value) | 138 | struct i2c_board_info *info, |
| 139 | acpi_handle *adapter_handle) | ||
| 143 | { | 140 | { |
| 144 | struct i2c_adapter *adapter = data; | ||
| 145 | struct list_head resource_list; | 141 | struct list_head resource_list; |
| 146 | struct acpi_i2c_lookup lookup; | ||
| 147 | struct resource_entry *entry; | 142 | struct resource_entry *entry; |
| 148 | struct i2c_board_info info; | 143 | struct acpi_i2c_lookup lookup; |
| 149 | struct acpi_device *adev; | ||
| 150 | int ret; | 144 | int ret; |
| 151 | 145 | ||
| 152 | if (acpi_bus_get_device(handle, &adev)) | 146 | if (acpi_bus_get_status(adev) || !adev->status.present || |
| 153 | return AE_OK; | 147 | acpi_device_enumerated(adev)) |
| 154 | if (acpi_bus_get_status(adev) || !adev->status.present) | 148 | return -EINVAL; |
| 155 | return AE_OK; | ||
| 156 | 149 | ||
| 157 | memset(&info, 0, sizeof(info)); | 150 | memset(info, 0, sizeof(*info)); |
| 158 | info.fwnode = acpi_fwnode_handle(adev); | 151 | info->fwnode = acpi_fwnode_handle(adev); |
| 159 | 152 | ||
| 160 | memset(&lookup, 0, sizeof(lookup)); | 153 | memset(&lookup, 0, sizeof(lookup)); |
| 161 | lookup.adapter_handle = ACPI_HANDLE(&adapter->dev); | 154 | lookup.device_handle = acpi_device_handle(adev); |
| 162 | lookup.device_handle = handle; | 155 | lookup.info = info; |
| 163 | lookup.info = &info; | ||
| 164 | 156 | ||
| 165 | /* | 157 | /* Look up for I2cSerialBus resource */ |
| 166 | * Look up for I2cSerialBus resource with ResourceSource that | ||
| 167 | * matches with this adapter. | ||
| 168 | */ | ||
| 169 | INIT_LIST_HEAD(&resource_list); | 158 | INIT_LIST_HEAD(&resource_list); |
| 170 | ret = acpi_dev_get_resources(adev, &resource_list, | 159 | ret = acpi_dev_get_resources(adev, &resource_list, |
| 171 | acpi_i2c_find_address, &lookup); | 160 | acpi_i2c_fill_info, &lookup); |
| 172 | acpi_dev_free_resource_list(&resource_list); | 161 | acpi_dev_free_resource_list(&resource_list); |
| 173 | 162 | ||
| 174 | if (ret < 0 || !info.addr) | 163 | if (ret < 0 || !info->addr) |
| 175 | return AE_OK; | 164 | return -EINVAL; |
| 165 | |||
| 166 | *adapter_handle = lookup.adapter_handle; | ||
| 176 | 167 | ||
| 177 | /* Then fill IRQ number if any */ | 168 | /* Then fill IRQ number if any */ |
| 178 | ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); | 169 | ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); |
| 179 | if (ret < 0) | 170 | if (ret < 0) |
| 180 | return AE_OK; | 171 | return -EINVAL; |
| 181 | 172 | ||
| 182 | resource_list_for_each_entry(entry, &resource_list) { | 173 | resource_list_for_each_entry(entry, &resource_list) { |
| 183 | if (resource_type(entry->res) == IORESOURCE_IRQ) { | 174 | if (resource_type(entry->res) == IORESOURCE_IRQ) { |
| 184 | info.irq = entry->res->start; | 175 | info->irq = entry->res->start; |
| 185 | break; | 176 | break; |
| 186 | } | 177 | } |
| 187 | } | 178 | } |
| 188 | 179 | ||
| 189 | acpi_dev_free_resource_list(&resource_list); | 180 | acpi_dev_free_resource_list(&resource_list); |
| 190 | 181 | ||
| 182 | strlcpy(info->type, dev_name(&adev->dev), sizeof(info->type)); | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static void acpi_i2c_register_device(struct i2c_adapter *adapter, | ||
| 188 | struct acpi_device *adev, | ||
| 189 | struct i2c_board_info *info) | ||
| 190 | { | ||
| 191 | adev->power.flags.ignore_parent = true; | 191 | adev->power.flags.ignore_parent = true; |
| 192 | strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); | 192 | acpi_device_set_enumerated(adev); |
| 193 | if (!i2c_new_device(adapter, &info)) { | 193 | |
| 194 | if (!i2c_new_device(adapter, info)) { | ||
| 194 | adev->power.flags.ignore_parent = false; | 195 | adev->power.flags.ignore_parent = false; |
| 195 | dev_err(&adapter->dev, | 196 | dev_err(&adapter->dev, |
| 196 | "failed to add I2C device %s from ACPI\n", | 197 | "failed to add I2C device %s from ACPI\n", |
| 197 | dev_name(&adev->dev)); | 198 | dev_name(&adev->dev)); |
| 198 | } | 199 | } |
| 200 | } | ||
| 201 | |||
| 202 | static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, | ||
| 203 | void *data, void **return_value) | ||
| 204 | { | ||
| 205 | struct i2c_adapter *adapter = data; | ||
| 206 | struct acpi_device *adev; | ||
| 207 | acpi_handle adapter_handle; | ||
| 208 | struct i2c_board_info info; | ||
| 209 | |||
| 210 | if (acpi_bus_get_device(handle, &adev)) | ||
| 211 | return AE_OK; | ||
| 212 | |||
| 213 | if (acpi_i2c_get_info(adev, &info, &adapter_handle)) | ||
| 214 | return AE_OK; | ||
| 215 | |||
| 216 | if (adapter_handle != ACPI_HANDLE(&adapter->dev)) | ||
| 217 | return AE_OK; | ||
| 218 | |||
| 219 | acpi_i2c_register_device(adapter, adev, &info); | ||
| 199 | 220 | ||
| 200 | return AE_OK; | 221 | return AE_OK; |
| 201 | } | 222 | } |
| @@ -225,8 +246,80 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap) | |||
| 225 | dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); | 246 | dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); |
| 226 | } | 247 | } |
| 227 | 248 | ||
| 249 | static int acpi_i2c_match_adapter(struct device *dev, void *data) | ||
| 250 | { | ||
| 251 | struct i2c_adapter *adapter = i2c_verify_adapter(dev); | ||
| 252 | |||
| 253 | if (!adapter) | ||
| 254 | return 0; | ||
| 255 | |||
| 256 | return ACPI_HANDLE(dev) == (acpi_handle)data; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int acpi_i2c_match_device(struct device *dev, void *data) | ||
| 260 | { | ||
| 261 | return ACPI_COMPANION(dev) == data; | ||
| 262 | } | ||
| 263 | |||
| 264 | static struct i2c_adapter *acpi_i2c_find_adapter_by_handle(acpi_handle handle) | ||
| 265 | { | ||
| 266 | struct device *dev; | ||
| 267 | |||
| 268 | dev = bus_find_device(&i2c_bus_type, NULL, handle, | ||
| 269 | acpi_i2c_match_adapter); | ||
| 270 | return dev ? i2c_verify_adapter(dev) : NULL; | ||
| 271 | } | ||
| 272 | |||
| 273 | static struct i2c_client *acpi_i2c_find_client_by_adev(struct acpi_device *adev) | ||
| 274 | { | ||
| 275 | struct device *dev; | ||
| 276 | |||
| 277 | dev = bus_find_device(&i2c_bus_type, NULL, adev, acpi_i2c_match_device); | ||
| 278 | return dev ? i2c_verify_client(dev) : NULL; | ||
| 279 | } | ||
| 280 | |||
| 281 | static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value, | ||
| 282 | void *arg) | ||
| 283 | { | ||
| 284 | struct acpi_device *adev = arg; | ||
| 285 | struct i2c_board_info info; | ||
| 286 | acpi_handle adapter_handle; | ||
| 287 | struct i2c_adapter *adapter; | ||
| 288 | struct i2c_client *client; | ||
| 289 | |||
| 290 | switch (value) { | ||
| 291 | case ACPI_RECONFIG_DEVICE_ADD: | ||
| 292 | if (acpi_i2c_get_info(adev, &info, &adapter_handle)) | ||
| 293 | break; | ||
| 294 | |||
| 295 | adapter = acpi_i2c_find_adapter_by_handle(adapter_handle); | ||
| 296 | if (!adapter) | ||
| 297 | break; | ||
| 298 | |||
| 299 | acpi_i2c_register_device(adapter, adev, &info); | ||
| 300 | break; | ||
| 301 | case ACPI_RECONFIG_DEVICE_REMOVE: | ||
| 302 | if (!acpi_device_enumerated(adev)) | ||
| 303 | break; | ||
| 304 | |||
| 305 | client = acpi_i2c_find_client_by_adev(adev); | ||
| 306 | if (!client) | ||
| 307 | break; | ||
| 308 | |||
| 309 | i2c_unregister_device(client); | ||
| 310 | put_device(&client->dev); | ||
| 311 | break; | ||
| 312 | } | ||
| 313 | |||
| 314 | return NOTIFY_OK; | ||
| 315 | } | ||
| 316 | |||
| 317 | static struct notifier_block i2c_acpi_notifier = { | ||
| 318 | .notifier_call = acpi_i2c_notify, | ||
| 319 | }; | ||
| 228 | #else /* CONFIG_ACPI */ | 320 | #else /* CONFIG_ACPI */ |
| 229 | static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } | 321 | static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } |
| 322 | extern struct notifier_block i2c_acpi_notifier; | ||
| 230 | #endif /* CONFIG_ACPI */ | 323 | #endif /* CONFIG_ACPI */ |
| 231 | 324 | ||
| 232 | #ifdef CONFIG_ACPI_I2C_OPREGION | 325 | #ifdef CONFIG_ACPI_I2C_OPREGION |
| @@ -1089,6 +1182,8 @@ void i2c_unregister_device(struct i2c_client *client) | |||
| 1089 | { | 1182 | { |
| 1090 | if (client->dev.of_node) | 1183 | if (client->dev.of_node) |
| 1091 | of_node_clear_flag(client->dev.of_node, OF_POPULATED); | 1184 | of_node_clear_flag(client->dev.of_node, OF_POPULATED); |
| 1185 | if (ACPI_COMPANION(&client->dev)) | ||
| 1186 | acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); | ||
| 1092 | device_unregister(&client->dev); | 1187 | device_unregister(&client->dev); |
| 1093 | } | 1188 | } |
| 1094 | EXPORT_SYMBOL_GPL(i2c_unregister_device); | 1189 | EXPORT_SYMBOL_GPL(i2c_unregister_device); |
| @@ -2117,6 +2212,8 @@ static int __init i2c_init(void) | |||
| 2117 | 2212 | ||
| 2118 | if (IS_ENABLED(CONFIG_OF_DYNAMIC)) | 2213 | if (IS_ENABLED(CONFIG_OF_DYNAMIC)) |
| 2119 | WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier)); | 2214 | WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier)); |
| 2215 | if (IS_ENABLED(CONFIG_ACPI)) | ||
| 2216 | WARN_ON(acpi_reconfig_notifier_register(&i2c_acpi_notifier)); | ||
| 2120 | 2217 | ||
| 2121 | return 0; | 2218 | return 0; |
| 2122 | 2219 | ||
| @@ -2132,6 +2229,8 @@ bus_err: | |||
| 2132 | 2229 | ||
| 2133 | static void __exit i2c_exit(void) | 2230 | static void __exit i2c_exit(void) |
| 2134 | { | 2231 | { |
| 2232 | if (IS_ENABLED(CONFIG_ACPI)) | ||
| 2233 | WARN_ON(acpi_reconfig_notifier_unregister(&i2c_acpi_notifier)); | ||
| 2135 | if (IS_ENABLED(CONFIG_OF_DYNAMIC)) | 2234 | if (IS_ENABLED(CONFIG_OF_DYNAMIC)) |
| 2136 | WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier)); | 2235 | WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier)); |
| 2137 | i2c_del_driver(&dummy_driver); | 2236 | i2c_del_driver(&dummy_driver); |
diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index 0f2784bc1874..ed5a097f0801 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c | |||
| @@ -91,8 +91,8 @@ static int __init of_numa_parse_memory_nodes(void) | |||
| 91 | pr_debug("NUMA: base = %llx len = %llx, node = %u\n", | 91 | pr_debug("NUMA: base = %llx len = %llx, node = %u\n", |
| 92 | rsrc.start, rsrc.end - rsrc.start + 1, nid); | 92 | rsrc.start, rsrc.end - rsrc.start + 1, nid); |
| 93 | 93 | ||
| 94 | r = numa_add_memblk(nid, rsrc.start, | 94 | |
| 95 | rsrc.end - rsrc.start + 1); | 95 | r = numa_add_memblk(nid, rsrc.start, rsrc.end + 1); |
| 96 | if (r) | 96 | if (r) |
| 97 | break; | 97 | break; |
| 98 | } | 98 | } |
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 77e6e45951f4..7589c8af4368 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
| @@ -622,6 +622,8 @@ void spi_unregister_device(struct spi_device *spi) | |||
| 622 | 622 | ||
| 623 | if (spi->dev.of_node) | 623 | if (spi->dev.of_node) |
| 624 | of_node_clear_flag(spi->dev.of_node, OF_POPULATED); | 624 | of_node_clear_flag(spi->dev.of_node, OF_POPULATED); |
| 625 | if (ACPI_COMPANION(&spi->dev)) | ||
| 626 | acpi_device_clear_enumerated(ACPI_COMPANION(&spi->dev)); | ||
| 625 | device_unregister(&spi->dev); | 627 | device_unregister(&spi->dev); |
| 626 | } | 628 | } |
| 627 | EXPORT_SYMBOL_GPL(spi_unregister_device); | 629 | EXPORT_SYMBOL_GPL(spi_unregister_device); |
| @@ -1646,18 +1648,15 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) | |||
| 1646 | return 1; | 1648 | return 1; |
| 1647 | } | 1649 | } |
| 1648 | 1650 | ||
| 1649 | static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, | 1651 | static acpi_status acpi_register_spi_device(struct spi_master *master, |
| 1650 | void *data, void **return_value) | 1652 | struct acpi_device *adev) |
| 1651 | { | 1653 | { |
| 1652 | struct spi_master *master = data; | ||
| 1653 | struct list_head resource_list; | 1654 | struct list_head resource_list; |
| 1654 | struct acpi_device *adev; | ||
| 1655 | struct spi_device *spi; | 1655 | struct spi_device *spi; |
| 1656 | int ret; | 1656 | int ret; |
| 1657 | 1657 | ||
| 1658 | if (acpi_bus_get_device(handle, &adev)) | 1658 | if (acpi_bus_get_status(adev) || !adev->status.present || |
| 1659 | return AE_OK; | 1659 | acpi_device_enumerated(adev)) |
| 1660 | if (acpi_bus_get_status(adev) || !adev->status.present) | ||
| 1661 | return AE_OK; | 1660 | return AE_OK; |
| 1662 | 1661 | ||
| 1663 | spi = spi_alloc_device(master); | 1662 | spi = spi_alloc_device(master); |
| @@ -1683,6 +1682,8 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, | |||
| 1683 | if (spi->irq < 0) | 1682 | if (spi->irq < 0) |
| 1684 | spi->irq = acpi_dev_gpio_irq_get(adev, 0); | 1683 | spi->irq = acpi_dev_gpio_irq_get(adev, 0); |
| 1685 | 1684 | ||
| 1685 | acpi_device_set_enumerated(adev); | ||
| 1686 | |||
| 1686 | adev->power.flags.ignore_parent = true; | 1687 | adev->power.flags.ignore_parent = true; |
| 1687 | strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias)); | 1688 | strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias)); |
| 1688 | if (spi_add_device(spi)) { | 1689 | if (spi_add_device(spi)) { |
| @@ -1695,6 +1696,18 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, | |||
| 1695 | return AE_OK; | 1696 | return AE_OK; |
| 1696 | } | 1697 | } |
| 1697 | 1698 | ||
| 1699 | static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, | ||
| 1700 | void *data, void **return_value) | ||
| 1701 | { | ||
| 1702 | struct spi_master *master = data; | ||
| 1703 | struct acpi_device *adev; | ||
| 1704 | |||
| 1705 | if (acpi_bus_get_device(handle, &adev)) | ||
| 1706 | return AE_OK; | ||
| 1707 | |||
| 1708 | return acpi_register_spi_device(master, adev); | ||
| 1709 | } | ||
| 1710 | |||
| 1698 | static void acpi_register_spi_devices(struct spi_master *master) | 1711 | static void acpi_register_spi_devices(struct spi_master *master) |
| 1699 | { | 1712 | { |
| 1700 | acpi_status status; | 1713 | acpi_status status; |
| @@ -3107,6 +3120,77 @@ static struct notifier_block spi_of_notifier = { | |||
| 3107 | extern struct notifier_block spi_of_notifier; | 3120 | extern struct notifier_block spi_of_notifier; |
| 3108 | #endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ | 3121 | #endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ |
| 3109 | 3122 | ||
| 3123 | #if IS_ENABLED(CONFIG_ACPI) | ||
| 3124 | static int spi_acpi_master_match(struct device *dev, const void *data) | ||
| 3125 | { | ||
| 3126 | return ACPI_COMPANION(dev->parent) == data; | ||
| 3127 | } | ||
| 3128 | |||
| 3129 | static int spi_acpi_device_match(struct device *dev, void *data) | ||
| 3130 | { | ||
| 3131 | return ACPI_COMPANION(dev) == data; | ||
| 3132 | } | ||
| 3133 | |||
| 3134 | static struct spi_master *acpi_spi_find_master_by_adev(struct acpi_device *adev) | ||
| 3135 | { | ||
| 3136 | struct device *dev; | ||
| 3137 | |||
| 3138 | dev = class_find_device(&spi_master_class, NULL, adev, | ||
| 3139 | spi_acpi_master_match); | ||
| 3140 | if (!dev) | ||
| 3141 | return NULL; | ||
| 3142 | |||
| 3143 | return container_of(dev, struct spi_master, dev); | ||
| 3144 | } | ||
| 3145 | |||
| 3146 | static struct spi_device *acpi_spi_find_device_by_adev(struct acpi_device *adev) | ||
| 3147 | { | ||
| 3148 | struct device *dev; | ||
| 3149 | |||
| 3150 | dev = bus_find_device(&spi_bus_type, NULL, adev, spi_acpi_device_match); | ||
| 3151 | |||
| 3152 | return dev ? to_spi_device(dev) : NULL; | ||
| 3153 | } | ||
| 3154 | |||
| 3155 | static int acpi_spi_notify(struct notifier_block *nb, unsigned long value, | ||
| 3156 | void *arg) | ||
| 3157 | { | ||
| 3158 | struct acpi_device *adev = arg; | ||
| 3159 | struct spi_master *master; | ||
| 3160 | struct spi_device *spi; | ||
| 3161 | |||
| 3162 | switch (value) { | ||
| 3163 | case ACPI_RECONFIG_DEVICE_ADD: | ||
| 3164 | master = acpi_spi_find_master_by_adev(adev->parent); | ||
| 3165 | if (!master) | ||
| 3166 | break; | ||
| 3167 | |||
| 3168 | acpi_register_spi_device(master, adev); | ||
| 3169 | put_device(&master->dev); | ||
| 3170 | break; | ||
| 3171 | case ACPI_RECONFIG_DEVICE_REMOVE: | ||
| 3172 | if (!acpi_device_enumerated(adev)) | ||
| 3173 | break; | ||
| 3174 | |||
| 3175 | spi = acpi_spi_find_device_by_adev(adev); | ||
| 3176 | if (!spi) | ||
| 3177 | break; | ||
| 3178 | |||
| 3179 | spi_unregister_device(spi); | ||
| 3180 | put_device(&spi->dev); | ||
| 3181 | break; | ||
| 3182 | } | ||
| 3183 | |||
| 3184 | return NOTIFY_OK; | ||
| 3185 | } | ||
| 3186 | |||
| 3187 | static struct notifier_block spi_acpi_notifier = { | ||
| 3188 | .notifier_call = acpi_spi_notify, | ||
| 3189 | }; | ||
| 3190 | #else | ||
| 3191 | extern struct notifier_block spi_acpi_notifier; | ||
| 3192 | #endif | ||
| 3193 | |||
| 3110 | static int __init spi_init(void) | 3194 | static int __init spi_init(void) |
| 3111 | { | 3195 | { |
| 3112 | int status; | 3196 | int status; |
| @@ -3127,6 +3211,8 @@ static int __init spi_init(void) | |||
| 3127 | 3211 | ||
| 3128 | if (IS_ENABLED(CONFIG_OF_DYNAMIC)) | 3212 | if (IS_ENABLED(CONFIG_OF_DYNAMIC)) |
| 3129 | WARN_ON(of_reconfig_notifier_register(&spi_of_notifier)); | 3213 | WARN_ON(of_reconfig_notifier_register(&spi_of_notifier)); |
| 3214 | if (IS_ENABLED(CONFIG_ACPI)) | ||
| 3215 | WARN_ON(acpi_reconfig_notifier_register(&spi_acpi_notifier)); | ||
| 3130 | 3216 | ||
| 3131 | return 0; | 3217 | return 0; |
| 3132 | 3218 | ||
diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h index 94a37cd7fbda..d4b72944ccda 100644 --- a/include/acpi/acpi_numa.h +++ b/include/acpi/acpi_numa.h | |||
| @@ -15,6 +15,10 @@ extern int pxm_to_node(int); | |||
| 15 | extern int node_to_pxm(int); | 15 | extern int node_to_pxm(int); |
| 16 | extern int acpi_map_pxm_to_node(int); | 16 | extern int acpi_map_pxm_to_node(int); |
| 17 | extern unsigned char acpi_srat_revision; | 17 | extern unsigned char acpi_srat_revision; |
| 18 | extern int acpi_numa __initdata; | ||
| 19 | |||
| 20 | extern void bad_srat(void); | ||
| 21 | extern int srat_disabled(void); | ||
| 18 | 22 | ||
| 19 | #endif /* CONFIG_ACPI_NUMA */ | 23 | #endif /* CONFIG_ACPI_NUMA */ |
| 20 | #endif /* __ACP_NUMA_H */ | 24 | #endif /* __ACP_NUMA_H */ |
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index dad8af3ebeb5..284965cbc9af 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h | |||
| @@ -15,10 +15,9 @@ | |||
| 15 | #define _CPPC_ACPI_H | 15 | #define _CPPC_ACPI_H |
| 16 | 16 | ||
| 17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
| 18 | #include <linux/mailbox_controller.h> | ||
| 19 | #include <linux/mailbox_client.h> | ||
| 20 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 21 | 19 | ||
| 20 | #include <acpi/pcc.h> | ||
| 22 | #include <acpi/processor.h> | 21 | #include <acpi/processor.h> |
| 23 | 22 | ||
| 24 | /* Only support CPPCv2 for now. */ | 23 | /* Only support CPPCv2 for now. */ |
| @@ -130,8 +129,4 @@ extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); | |||
| 130 | extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); | 129 | extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); |
| 131 | extern int acpi_get_psd_map(struct cpudata **); | 130 | extern int acpi_get_psd_map(struct cpudata **); |
| 132 | 131 | ||
| 133 | /* Methods to interact with the PCC mailbox controller. */ | ||
| 134 | extern struct mbox_chan * | ||
| 135 | pcc_mbox_request_channel(struct mbox_client *, unsigned int); | ||
| 136 | |||
| 137 | #endif /* _CPPC_ACPI_H*/ | 132 | #endif /* _CPPC_ACPI_H*/ |
diff --git a/include/acpi/pcc.h b/include/acpi/pcc.h new file mode 100644 index 000000000000..17a940a14477 --- /dev/null +++ b/include/acpi/pcc.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * PCC (Platform Communications Channel) methods | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; version 2 | ||
| 7 | * of the License. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef _PCC_H | ||
| 11 | #define _PCC_H | ||
| 12 | |||
| 13 | #include <linux/mailbox_controller.h> | ||
| 14 | #include <linux/mailbox_client.h> | ||
| 15 | |||
| 16 | #ifdef CONFIG_PCC | ||
| 17 | extern struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, | ||
| 18 | int subspace_id); | ||
| 19 | extern void pcc_mbox_free_channel(struct mbox_chan *chan); | ||
| 20 | #else | ||
| 21 | static inline struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl, | ||
| 22 | int subspace_id) | ||
| 23 | { | ||
| 24 | return NULL; | ||
| 25 | } | ||
| 26 | static inline void pcc_mbox_free_channel(struct mbox_chan *chan) { } | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #endif /* _PCC_H */ | ||
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h index 45c2d6528829..93b61b1f2beb 100644 --- a/include/acpi/platform/aclinux.h +++ b/include/acpi/platform/aclinux.h | |||
| @@ -73,6 +73,10 @@ | |||
| 73 | #define ACPI_DEBUGGER | 73 | #define ACPI_DEBUGGER |
| 74 | #endif | 74 | #endif |
| 75 | 75 | ||
| 76 | #ifdef CONFIG_ACPI_DEBUG | ||
| 77 | #define ACPI_MUTEX_DEBUG | ||
| 78 | #endif | ||
| 79 | |||
| 76 | #include <linux/string.h> | 80 | #include <linux/string.h> |
| 77 | #include <linux/kernel.h> | 81 | #include <linux/kernel.h> |
| 78 | #include <linux/ctype.h> | 82 | #include <linux/ctype.h> |
diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 6f1805dd5d3c..bfe6b2e10f3a 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #define ACPI_CSTATE_SYSTEMIO 0 | 39 | #define ACPI_CSTATE_SYSTEMIO 0 |
| 40 | #define ACPI_CSTATE_FFH 1 | 40 | #define ACPI_CSTATE_FFH 1 |
| 41 | #define ACPI_CSTATE_HALT 2 | 41 | #define ACPI_CSTATE_HALT 2 |
| 42 | #define ACPI_CSTATE_INTEGER 3 | ||
| 42 | 43 | ||
| 43 | #define ACPI_CX_DESC_LEN 32 | 44 | #define ACPI_CX_DESC_LEN 32 |
| 44 | 45 | ||
| @@ -67,9 +68,25 @@ struct acpi_processor_cx { | |||
| 67 | char desc[ACPI_CX_DESC_LEN]; | 68 | char desc[ACPI_CX_DESC_LEN]; |
| 68 | }; | 69 | }; |
| 69 | 70 | ||
| 71 | struct acpi_lpi_state { | ||
| 72 | u32 min_residency; | ||
| 73 | u32 wake_latency; /* worst case */ | ||
| 74 | u32 flags; | ||
| 75 | u32 arch_flags; | ||
| 76 | u32 res_cnt_freq; | ||
| 77 | u32 enable_parent_state; | ||
| 78 | u64 address; | ||
| 79 | u8 index; | ||
| 80 | u8 entry_method; | ||
| 81 | char desc[ACPI_CX_DESC_LEN]; | ||
| 82 | }; | ||
| 83 | |||
| 70 | struct acpi_processor_power { | 84 | struct acpi_processor_power { |
| 71 | int count; | 85 | int count; |
| 72 | struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER]; | 86 | union { |
| 87 | struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER]; | ||
| 88 | struct acpi_lpi_state lpi_states[ACPI_PROCESSOR_MAX_POWER]; | ||
| 89 | }; | ||
| 73 | int timer_broadcast_on_state; | 90 | int timer_broadcast_on_state; |
| 74 | }; | 91 | }; |
| 75 | 92 | ||
| @@ -189,6 +206,7 @@ struct acpi_processor_flags { | |||
| 189 | u8 bm_control:1; | 206 | u8 bm_control:1; |
| 190 | u8 bm_check:1; | 207 | u8 bm_check:1; |
| 191 | u8 has_cst:1; | 208 | u8 has_cst:1; |
| 209 | u8 has_lpi:1; | ||
| 192 | u8 power_setup_done:1; | 210 | u8 power_setup_done:1; |
| 193 | u8 bm_rld_set:1; | 211 | u8 bm_rld_set:1; |
| 194 | u8 need_hotplug_init:1; | 212 | u8 need_hotplug_init:1; |
| @@ -242,7 +260,7 @@ extern int acpi_processor_get_performance_info(struct acpi_processor *pr); | |||
| 242 | DECLARE_PER_CPU(struct acpi_processor *, processors); | 260 | DECLARE_PER_CPU(struct acpi_processor *, processors); |
| 243 | extern struct acpi_processor_errata errata; | 261 | extern struct acpi_processor_errata errata; |
| 244 | 262 | ||
| 245 | #ifdef ARCH_HAS_POWER_INIT | 263 | #if defined(ARCH_HAS_POWER_INIT) && defined(CONFIG_ACPI_PROCESSOR_CSTATE) |
| 246 | void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, | 264 | void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, |
| 247 | unsigned int cpu); | 265 | unsigned int cpu); |
| 248 | int acpi_processor_ffh_cstate_probe(unsigned int cpu, | 266 | int acpi_processor_ffh_cstate_probe(unsigned int cpu, |
| @@ -309,6 +327,7 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) | |||
| 309 | 327 | ||
| 310 | /* in processor_core.c */ | 328 | /* in processor_core.c */ |
| 311 | phys_cpuid_t acpi_get_phys_id(acpi_handle, int type, u32 acpi_id); | 329 | phys_cpuid_t acpi_get_phys_id(acpi_handle, int type, u32 acpi_id); |
| 330 | phys_cpuid_t acpi_map_madt_entry(u32 acpi_id); | ||
| 312 | int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id); | 331 | int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id); |
| 313 | int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id); | 332 | int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id); |
| 314 | 333 | ||
| @@ -371,7 +390,7 @@ extern struct cpuidle_driver acpi_idle_driver; | |||
| 371 | #ifdef CONFIG_ACPI_PROCESSOR_IDLE | 390 | #ifdef CONFIG_ACPI_PROCESSOR_IDLE |
| 372 | int acpi_processor_power_init(struct acpi_processor *pr); | 391 | int acpi_processor_power_init(struct acpi_processor *pr); |
| 373 | int acpi_processor_power_exit(struct acpi_processor *pr); | 392 | int acpi_processor_power_exit(struct acpi_processor *pr); |
| 374 | int acpi_processor_cst_has_changed(struct acpi_processor *pr); | 393 | int acpi_processor_power_state_has_changed(struct acpi_processor *pr); |
| 375 | int acpi_processor_hotplug(struct acpi_processor *pr); | 394 | int acpi_processor_hotplug(struct acpi_processor *pr); |
| 376 | #else | 395 | #else |
| 377 | static inline int acpi_processor_power_init(struct acpi_processor *pr) | 396 | static inline int acpi_processor_power_init(struct acpi_processor *pr) |
| @@ -384,7 +403,7 @@ static inline int acpi_processor_power_exit(struct acpi_processor *pr) | |||
| 384 | return -ENODEV; | 403 | return -ENODEV; |
| 385 | } | 404 | } |
| 386 | 405 | ||
| 387 | static inline int acpi_processor_cst_has_changed(struct acpi_processor *pr) | 406 | static inline int acpi_processor_power_state_has_changed(struct acpi_processor *pr) |
| 388 | { | 407 | { |
| 389 | return -ENODEV; | 408 | return -ENODEV; |
| 390 | } | 409 | } |
diff --git a/include/acpi/video.h b/include/acpi/video.h index 5731ccb42585..4536bd345ab4 100644 --- a/include/acpi/video.h +++ b/include/acpi/video.h | |||
| @@ -54,7 +54,7 @@ extern int acpi_video_get_levels(struct acpi_device *device, | |||
| 54 | struct acpi_video_device_brightness **dev_br, | 54 | struct acpi_video_device_brightness **dev_br, |
| 55 | int *pmax_level); | 55 | int *pmax_level); |
| 56 | #else | 56 | #else |
| 57 | static inline int acpi_video_register(void) { return 0; } | 57 | static inline int acpi_video_register(void) { return -ENODEV; } |
| 58 | static inline void acpi_video_unregister(void) { return; } | 58 | static inline void acpi_video_unregister(void) { return; } |
| 59 | static inline int acpi_video_get_edid(struct acpi_device *device, int type, | 59 | static inline int acpi_video_get_edid(struct acpi_device *device, int type, |
| 60 | int device_id, void **edid) | 60 | int device_id, void **edid) |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 288fac5294f5..cc63aef07249 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
| @@ -208,7 +208,6 @@ void acpi_boot_table_init (void); | |||
| 208 | int acpi_mps_check (void); | 208 | int acpi_mps_check (void); |
| 209 | int acpi_numa_init (void); | 209 | int acpi_numa_init (void); |
| 210 | 210 | ||
| 211 | void early_acpi_table_init(void *data, size_t size); | ||
| 212 | int acpi_table_init (void); | 211 | int acpi_table_init (void); |
| 213 | int acpi_table_parse(char *id, acpi_tbl_table_handler handler); | 212 | int acpi_table_parse(char *id, acpi_tbl_table_handler handler); |
| 214 | int __init acpi_parse_entries(char *id, unsigned long table_size, | 213 | int __init acpi_parse_entries(char *id, unsigned long table_size, |
| @@ -232,12 +231,26 @@ int acpi_table_parse_madt(enum acpi_madt_type id, | |||
| 232 | int acpi_parse_mcfg (struct acpi_table_header *header); | 231 | int acpi_parse_mcfg (struct acpi_table_header *header); |
| 233 | void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); | 232 | void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); |
| 234 | 233 | ||
| 235 | /* the following four functions are architecture-dependent */ | 234 | /* the following numa functions are architecture-dependent */ |
| 236 | void acpi_numa_slit_init (struct acpi_table_slit *slit); | 235 | void acpi_numa_slit_init (struct acpi_table_slit *slit); |
| 236 | |||
| 237 | #if defined(CONFIG_X86) || defined(CONFIG_IA64) | ||
| 237 | void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); | 238 | void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); |
| 239 | #else | ||
| 240 | static inline void | ||
| 241 | acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) { } | ||
| 242 | #endif | ||
| 243 | |||
| 238 | void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa); | 244 | void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa); |
| 245 | |||
| 246 | #ifdef CONFIG_ARM64 | ||
| 247 | void acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa); | ||
| 248 | #else | ||
| 249 | static inline void | ||
| 250 | acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa) { } | ||
| 251 | #endif | ||
| 252 | |||
| 239 | int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); | 253 | int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); |
| 240 | void acpi_numa_arch_fixup(void); | ||
| 241 | 254 | ||
| 242 | #ifndef PHYS_CPUID_INVALID | 255 | #ifndef PHYS_CPUID_INVALID |
| 243 | typedef u32 phys_cpuid_t; | 256 | typedef u32 phys_cpuid_t; |
| @@ -444,8 +457,12 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); | |||
| 444 | #define OSC_SB_HOTPLUG_OST_SUPPORT 0x00000008 | 457 | #define OSC_SB_HOTPLUG_OST_SUPPORT 0x00000008 |
| 445 | #define OSC_SB_APEI_SUPPORT 0x00000010 | 458 | #define OSC_SB_APEI_SUPPORT 0x00000010 |
| 446 | #define OSC_SB_CPC_SUPPORT 0x00000020 | 459 | #define OSC_SB_CPC_SUPPORT 0x00000020 |
| 460 | #define OSC_SB_CPCV2_SUPPORT 0x00000040 | ||
| 461 | #define OSC_SB_PCLPI_SUPPORT 0x00000080 | ||
| 462 | #define OSC_SB_OSLPI_SUPPORT 0x00000100 | ||
| 447 | 463 | ||
| 448 | extern bool osc_sb_apei_support_acked; | 464 | extern bool osc_sb_apei_support_acked; |
| 465 | extern bool osc_pc_lpi_support_confirmed; | ||
| 449 | 466 | ||
| 450 | /* PCI Host Bridge _OSC: Capabilities DWORD 2: Support Field */ | 467 | /* PCI Host Bridge _OSC: Capabilities DWORD 2: Support Field */ |
| 451 | #define OSC_PCI_EXT_CONFIG_SUPPORT 0x00000001 | 468 | #define OSC_PCI_EXT_CONFIG_SUPPORT 0x00000001 |
| @@ -532,6 +549,24 @@ void acpi_walk_dep_device_list(acpi_handle handle); | |||
| 532 | struct platform_device *acpi_create_platform_device(struct acpi_device *); | 549 | struct platform_device *acpi_create_platform_device(struct acpi_device *); |
| 533 | #define ACPI_PTR(_ptr) (_ptr) | 550 | #define ACPI_PTR(_ptr) (_ptr) |
| 534 | 551 | ||
| 552 | static inline void acpi_device_set_enumerated(struct acpi_device *adev) | ||
| 553 | { | ||
| 554 | adev->flags.visited = true; | ||
| 555 | } | ||
| 556 | |||
| 557 | static inline void acpi_device_clear_enumerated(struct acpi_device *adev) | ||
| 558 | { | ||
| 559 | adev->flags.visited = false; | ||
| 560 | } | ||
| 561 | |||
| 562 | enum acpi_reconfig_event { | ||
| 563 | ACPI_RECONFIG_DEVICE_ADD = 0, | ||
| 564 | ACPI_RECONFIG_DEVICE_REMOVE, | ||
| 565 | }; | ||
| 566 | |||
| 567 | int acpi_reconfig_notifier_register(struct notifier_block *nb); | ||
| 568 | int acpi_reconfig_notifier_unregister(struct notifier_block *nb); | ||
| 569 | |||
| 535 | #else /* !CONFIG_ACPI */ | 570 | #else /* !CONFIG_ACPI */ |
| 536 | 571 | ||
| 537 | #define acpi_disabled 1 | 572 | #define acpi_disabled 1 |
| @@ -588,7 +623,6 @@ static inline const char *acpi_dev_name(struct acpi_device *adev) | |||
| 588 | return NULL; | 623 | return NULL; |
| 589 | } | 624 | } |
| 590 | 625 | ||
| 591 | static inline void early_acpi_table_init(void *data, size_t size) { } | ||
| 592 | static inline void acpi_early_init(void) { } | 626 | static inline void acpi_early_init(void) { } |
| 593 | static inline void acpi_subsystem_init(void) { } | 627 | static inline void acpi_subsystem_init(void) { } |
| 594 | 628 | ||
| @@ -678,6 +712,24 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) | |||
| 678 | 712 | ||
| 679 | #define ACPI_PTR(_ptr) (NULL) | 713 | #define ACPI_PTR(_ptr) (NULL) |
| 680 | 714 | ||
| 715 | static inline void acpi_device_set_enumerated(struct acpi_device *adev) | ||
| 716 | { | ||
| 717 | } | ||
| 718 | |||
| 719 | static inline void acpi_device_clear_enumerated(struct acpi_device *adev) | ||
| 720 | { | ||
| 721 | } | ||
| 722 | |||
| 723 | static inline int acpi_reconfig_notifier_register(struct notifier_block *nb) | ||
| 724 | { | ||
| 725 | return -EINVAL; | ||
| 726 | } | ||
| 727 | |||
| 728 | static inline int acpi_reconfig_notifier_unregister(struct notifier_block *nb) | ||
| 729 | { | ||
| 730 | return -EINVAL; | ||
| 731 | } | ||
| 732 | |||
| 681 | #endif /* !CONFIG_ACPI */ | 733 | #endif /* !CONFIG_ACPI */ |
| 682 | 734 | ||
| 683 | #ifdef CONFIG_ACPI | 735 | #ifdef CONFIG_ACPI |
| @@ -997,4 +1049,10 @@ static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev, | |||
| 997 | #define acpi_probe_device_table(t) ({ int __r = 0; __r;}) | 1049 | #define acpi_probe_device_table(t) ({ int __r = 0; __r;}) |
| 998 | #endif | 1050 | #endif |
| 999 | 1051 | ||
| 1052 | #ifdef CONFIG_ACPI_TABLE_UPGRADE | ||
| 1053 | void acpi_table_upgrade(void); | ||
| 1054 | #else | ||
| 1055 | static inline void acpi_table_upgrade(void) { } | ||
| 1056 | #endif | ||
| 1057 | |||
| 1000 | #endif /*_LINUX_ACPI_H*/ | 1058 | #endif /*_LINUX_ACPI_H*/ |
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 07b83d32f66c..bb31373c3478 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h | |||
| @@ -252,4 +252,22 @@ static inline int cpuidle_register_governor(struct cpuidle_governor *gov) | |||
| 252 | #define CPUIDLE_DRIVER_STATE_START 0 | 252 | #define CPUIDLE_DRIVER_STATE_START 0 |
| 253 | #endif | 253 | #endif |
| 254 | 254 | ||
| 255 | #define CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx) \ | ||
| 256 | ({ \ | ||
| 257 | int __ret; \ | ||
| 258 | \ | ||
| 259 | if (!idx) { \ | ||
| 260 | cpu_do_idle(); \ | ||
| 261 | return idx; \ | ||
| 262 | } \ | ||
| 263 | \ | ||
| 264 | __ret = cpu_pm_enter(); \ | ||
| 265 | if (!__ret) { \ | ||
| 266 | __ret = low_level_idle_enter(idx); \ | ||
| 267 | cpu_pm_exit(); \ | ||
| 268 | } \ | ||
| 269 | \ | ||
| 270 | __ret ? -1 : idx; \ | ||
| 271 | }) | ||
| 272 | |||
| 255 | #endif /* _LINUX_CPUIDLE_H */ | 273 | #endif /* _LINUX_CPUIDLE_H */ |
diff --git a/tools/power/acpi/Makefile.config b/tools/power/acpi/Makefile.config index 552af68d5414..a538ff44b108 100644 --- a/tools/power/acpi/Makefile.config +++ b/tools/power/acpi/Makefile.config | |||
| @@ -54,9 +54,10 @@ INSTALL_SCRIPT = ${INSTALL_PROGRAM} | |||
| 54 | # to something more interesting, like "arm-linux-". If you want | 54 | # to something more interesting, like "arm-linux-". If you want |
| 55 | # to compile vs uClibc, that can be done here as well. | 55 | # to compile vs uClibc, that can be done here as well. |
| 56 | CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- | 56 | CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- |
| 57 | CC = $(CROSS)gcc | 57 | CROSS_COMPILE ?= $(CROSS) |
| 58 | LD = $(CROSS)gcc | 58 | CC = $(CROSS_COMPILE)gcc |
| 59 | STRIP = $(CROSS)strip | 59 | LD = $(CROSS_COMPILE)gcc |
| 60 | STRIP = $(CROSS_COMPILE)strip | ||
| 60 | HOSTCC = gcc | 61 | HOSTCC = gcc |
| 61 | 62 | ||
| 62 | # check if compiler option is supported | 63 | # check if compiler option is supported |
