ACPI and power management updates for 3.16-rc1

- ACPICA update to upstream version 20140424.  That includes a
    number of fixes and improvements related to things like GPE
    handling, table loading, headers, memory mapping and unmapping,
    DSDT/SSDT overriding, and the Unload() operator.  The acpidump
    utility from upstream ACPICA is included too.  From Bob Moore,
    Lv Zheng, David Box, David Binderman, and Colin Ian King.
 
  - Fixes and cleanups related to ACPI video and backlight interfaces
    from Hans de Goede.  That includes blacklist entries for some new
    machines and using native backlight by default.
 
  - ACPI device enumeration changes to create platform devices
    rather than PNP devices for ACPI device objects with _HID by
    default.  PNP devices will still be created for the ACPI device
    object with device IDs corresponding to real PNP devices, so
    that change should not break things left and right, and we're
    expecting to see more and more ACPI-enumerated platform devices
    in the future.  From Zhang Rui and Rafael J Wysocki.
 
  - Updates for the ACPI LPSS (Low-Power Subsystem) driver allowing
    it to handle system suspend/resume on Asus T100 correctly.
    From Heikki Krogerus and Rafael J Wysocki.
 
  - PM core update introducing a mechanism to allow runtime-suspended
    devices to stay suspended over system suspend/resume transitions
    if certain additional conditions related to coordination within
    device hierarchy are met.  Related PM documentation update and
    ACPI PM domain support for the new feature.  From Rafael J Wysocki.
 
  - Fixes and improvements related to the "freeze" sleep state. They
    affect several places including cpuidle, PM core, ACPI core, and
    the ACPI battery driver.  From Rafael J Wysocki and Zhang Rui.
 
  - Miscellaneous fixes and updates of the ACPI core from Aaron Lu,
    Bjørn Mork, Hanjun Guo, Lan Tianyu, and Rafael J Wysocki.
 
  - Fixes and cleanups for the ACPI processor and ACPI PAD (Processor
    Aggregator Device) drivers from Baoquan He, Manuel Schölling,
    Tony Camuso, and Toshi Kani.
 
  - System suspend/resume optimization in the ACPI battery driver from
    Lan Tianyu.
 
  - OPP (Operating Performance Points) subsystem updates from
    Chander Kashyap, Mark Brown, and Nishanth Menon.
 
  - cpufreq core fixes, updates and cleanups from Srivatsa S Bhat,
    Stratos Karafotis, and Viresh Kumar.
 
  - Updates, fixes and cleanups for the Tegra, powernow-k8, imx6q,
    s5pv210, nforce2, and powernv cpufreq drivers from Brian Norris,
    Jingoo Han, Paul Bolle, Philipp Zabel, Stratos Karafotis, and
    Viresh Kumar.
 
  - intel_pstate driver fixes and cleanups from Dirk Brandewie,
    Doug Smythies, and Stratos Karafotis.
 
  - Enabling the big.LITTLE cpufreq driver on arm64 from Mark Brown.
 
  - Fix for the cpuidle menu governor from Chander Kashyap.
 
  - New ARM clps711x cpuidle driver from Alexander Shiyan.
 
  - Hibernate core fixes and cleanups from Chen Gang, Dan Carpenter,
    Fabian Frederick, Pali Rohár, and Sebastian Capella.
 
  - Intel RAPL (Running Average Power Limit) driver updates from
    Jacob Pan.
 
  - PNP subsystem updates from Bjorn Helgaas and Fabian Frederick.
 
  - devfreq core updates from Chanwoo Choi and Paul Bolle.
 
  - devfreq updates for exynos4 and exynos5 from Chanwoo Choi and
    Bartlomiej Zolnierkiewicz.
 
  - turbostat tool fix from Jean Delvare.
 
  - cpupower tool updates from Prarit Bhargava, Ramkumar Ramachandra
    and Thomas Renninger.
 
  - New ACPI ec_access.c tool for poking at the EC in a safe way
    from Thomas Renninger.
 
 /
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCAAGBQJTjl16AAoJEILEb/54YlRxeKgP/RRQSV7lFtf582Dw/5M/iWOg
 qYeNtuYFLArEmJ7SpxHdKsU1ZRm3CahAS1j7grvQMQasUxTzoavMcSBNZefeaoNK
 d01LVNqcyKCZs3+izRezk5N1IY+AjdrOcqCdIk8rfgFnc6kOttYUrVcIzKuIKAvJ
 MsJ5s/uqP8G69FsAA3Ttdtr0HKiQhN4skSt424wntQRDeJNZPBs74mPKBGh8bxlO
 Zr/VCDibKQ2Z8jS7x+TzwZrOxgE1/9x0Cub6GAdTvAfS8A+utPwSkneUyopNqpQ+
 tJ5rz5R+HpmPMerizBuU+5s+tvjDPtH4/OZvOPSpYraQSFLOwx3hAm+a5k7fOGmc
 XWjXnXWT0i0V3iQkwrspTNjX1RgywbsHbmXrcWn192HResvMQ9zk2gH2ch6m8JhN
 yTV5V51dOZicpPuaTCvIkJpsV33p6vRz+EdPBiXoEdua5KKtOg8EnQ470dNaMR92
 3ZtWmIvSgGlyPyHlSHLfGXbPUwTYvDNV3aheIoXp9E6WY3WJN9J3WXm4EHKBNVaI
 H83kwuk1s92cgqh22H5Pcb0CmDcrbkUdP6hhsPS/aL80/EJMljRP2AYW1Y+l1LAf
 pzMLmekHFqQEDjFQltwGvFV/EjFeMHnqOgQONx9ygMaayCGGTYSDx3FbRDesf8t9
 qhoFcTPSxoo0XjrGrR6b
 =tpdF
 -----END PGP SIGNATURE-----

Merge tag 'pm+acpi-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm into next

Pull ACPI and power management updates from Rafael Wysocki:
 "ACPICA is the leader this time (63 commits), followed by cpufreq (28
  commits), devfreq (15 commits), system suspend/hibernation (12
  commits), ACPI video and ACPI device enumeration (10 commits each).

  We have no major new features this time, but there are a few
  significant changes of how things work.  The most visible one will
  probably be that we are now going to create platform devices rather
  than PNP devices by default for ACPI device objects with _HID.  That
  was long overdue and will be really necessary to be able to use the
  same drivers for the same hardware blocks on ACPI and DT-based systems
  going forward.  We're not expecting fallout from this one (as usual),
  but it's something to watch nevertheless.

  The second change having a chance to be visible is that ACPI video
  will now default to using native backlight rather than the ACPI
  backlight interface which should generally help systems with broken
  Win8 BIOSes.  We're hoping that all problems with the native backlight
  handling that we had previously have been addressed and we are in a
  good enough shape to flip the default, but this change should be easy
  enough to revert if need be.

  In addition to that, the system suspend core has a new mechanism to
  allow runtime-suspended devices to stay suspended throughout system
  suspend/resume transitions if some extra conditions are met
  (generally, they are related to coordination within device hierarchy).
  However, enabling this feature requires cooperation from the bus type
  layer and for now it has only been implemented for the ACPI PM domain
  (used by ACPI-enumerated platform devices mostly today).

  Also, the acpidump utility that was previously shipped as a separate
  tool will now be provided by the upstream ACPICA along with the rest
  of ACPICA code, which will allow it to be more up to date and better
  supported, and we have one new cpuidle driver (ARM clps711x).

  The rest is improvements related to certain specific use cases,
  cleanups and fixes all over the place.

  Specifics:

   - ACPICA update to upstream version 20140424.  That includes a number
     of fixes and improvements related to things like GPE handling,
     table loading, headers, memory mapping and unmapping, DSDT/SSDT
     overriding, and the Unload() operator.  The acpidump utility from
     upstream ACPICA is included too.  From Bob Moore, Lv Zheng, David
     Box, David Binderman, and Colin Ian King.

   - Fixes and cleanups related to ACPI video and backlight interfaces
     from Hans de Goede.  That includes blacklist entries for some new
     machines and using native backlight by default.

   - ACPI device enumeration changes to create platform devices rather
     than PNP devices for ACPI device objects with _HID by default.  PNP
     devices will still be created for the ACPI device object with
     device IDs corresponding to real PNP devices, so that change should
     not break things left and right, and we're expecting to see more
     and more ACPI-enumerated platform devices in the future.  From
     Zhang Rui and Rafael J Wysocki.

   - Updates for the ACPI LPSS (Low-Power Subsystem) driver allowing it
     to handle system suspend/resume on Asus T100 correctly.  From
     Heikki Krogerus and Rafael J Wysocki.

   - PM core update introducing a mechanism to allow runtime-suspended
     devices to stay suspended over system suspend/resume transitions if
     certain additional conditions related to coordination within device
     hierarchy are met.  Related PM documentation update and ACPI PM
     domain support for the new feature.  From Rafael J Wysocki.

   - Fixes and improvements related to the "freeze" sleep state.  They
     affect several places including cpuidle, PM core, ACPI core, and
     the ACPI battery driver.  From Rafael J Wysocki and Zhang Rui.

   - Miscellaneous fixes and updates of the ACPI core from Aaron Lu,
     Bjørn Mork, Hanjun Guo, Lan Tianyu, and Rafael J Wysocki.

   - Fixes and cleanups for the ACPI processor and ACPI PAD (Processor
     Aggregator Device) drivers from Baoquan He, Manuel Schölling, Tony
     Camuso, and Toshi Kani.

   - System suspend/resume optimization in the ACPI battery driver from
     Lan Tianyu.

   - OPP (Operating Performance Points) subsystem updates from Chander
     Kashyap, Mark Brown, and Nishanth Menon.

   - cpufreq core fixes, updates and cleanups from Srivatsa S Bhat,
     Stratos Karafotis, and Viresh Kumar.

   - Updates, fixes and cleanups for the Tegra, powernow-k8, imx6q,
     s5pv210, nforce2, and powernv cpufreq drivers from Brian Norris,
     Jingoo Han, Paul Bolle, Philipp Zabel, Stratos Karafotis, and
     Viresh Kumar.

   - intel_pstate driver fixes and cleanups from Dirk Brandewie, Doug
     Smythies, and Stratos Karafotis.

   - Enabling the big.LITTLE cpufreq driver on arm64 from Mark Brown.

   - Fix for the cpuidle menu governor from Chander Kashyap.

   - New ARM clps711x cpuidle driver from Alexander Shiyan.

   - Hibernate core fixes and cleanups from Chen Gang, Dan Carpenter,
     Fabian Frederick, Pali Rohár, and Sebastian Capella.

   - Intel RAPL (Running Average Power Limit) driver updates from Jacob
     Pan.

   - PNP subsystem updates from Bjorn Helgaas and Fabian Frederick.

   - devfreq core updates from Chanwoo Choi and Paul Bolle.

   - devfreq updates for exynos4 and exynos5 from Chanwoo Choi and
     Bartlomiej Zolnierkiewicz.

   - turbostat tool fix from Jean Delvare.

   - cpupower tool updates from Prarit Bhargava, Ramkumar Ramachandra
     and Thomas Renninger.

   - New ACPI ec_access.c tool for poking at the EC in a safe way from
     Thomas Renninger"

* tag 'pm+acpi-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (187 commits)
  ACPICA: Namespace: Remove _PRP method support.
  intel_pstate: Improve initial busy calculation
  intel_pstate: add sample time scaling
  intel_pstate: Correct rounding in busy calculation
  intel_pstate: Remove C0 tracking
  PM / hibernate: fixed typo in comment
  ACPI: Fix x86 regression related to early mapping size limitation
  ACPICA: Tables: Add mechanism to control early table checksum verification.
  ACPI / scan: use platform bus type by default for _HID enumeration
  ACPI / scan: always register ACPI LPSS scan handler
  ACPI / scan: always register memory hotplug scan handler
  ACPI / scan: always register container scan handler
  ACPI / scan: Change the meaning of missing .attach() in scan handlers
  ACPI / scan: introduce platform_id device PNP type flag
  ACPI / scan: drop unsupported serial IDs from PNP ACPI scan handler ID list
  ACPI / scan: drop IDs that do not comply with the ACPI PNP ID rule
  ACPI / PNP: use device ID list for PNPACPI device enumeration
  ACPI / scan: .match() callback for ACPI scan handlers
  ACPI / battery: wakeup the system only when necessary
  power_supply: allow power supply devices registered w/o wakeup source
  ...
This commit is contained in:
Linus Torvalds 2014-06-04 08:57:16 -07:00
commit 4dc4226f99
188 changed files with 9460 additions and 3810 deletions

View file

@ -128,7 +128,7 @@ Description: Discover cpuidle policy and mechanism
What: /sys/devices/system/cpu/cpu#/cpufreq/* What: /sys/devices/system/cpu/cpu#/cpufreq/*
Date: pre-git history Date: pre-git history
Contact: cpufreq@vger.kernel.org Contact: linux-pm@vger.kernel.org
Description: Discover and change clock speed of CPUs Description: Discover and change clock speed of CPUs
Clock scaling allows you to change the clock speed of the Clock scaling allows you to change the clock speed of the
@ -146,7 +146,7 @@ Description: Discover and change clock speed of CPUs
What: /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus What: /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus
Date: June 2013 Date: June 2013
Contact: cpufreq@vger.kernel.org Contact: linux-pm@vger.kernel.org
Description: Discover CPUs in the same CPU frequency coordination domain Description: Discover CPUs in the same CPU frequency coordination domain
freqdomain_cpus is the list of CPUs (online+offline) that share freqdomain_cpus is the list of CPUs (online+offline) that share

View file

@ -7,19 +7,30 @@ Description:
subsystem. subsystem.
What: /sys/power/state What: /sys/power/state
Date: August 2006 Date: May 2014
Contact: Rafael J. Wysocki <rjw@rjwysocki.net> Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
Description: Description:
The /sys/power/state file controls the system power state. The /sys/power/state file controls system sleep states.
Reading from this file returns what states are supported, Reading from this file returns the available sleep state
which is hard-coded to 'freeze' (Low-Power Idle), 'standby' labels, which may be "mem", "standby", "freeze" and "disk"
(Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk' (hibernation). The meanings of the first three labels depend on
(Suspend-to-Disk). the relative_sleep_states command line argument as follows:
1) relative_sleep_states = 1
"mem", "standby", "freeze" represent non-hibernation sleep
states from the deepest ("mem", always present) to the
shallowest ("freeze"). "standby" and "freeze" may or may
not be present depending on the capabilities of the
platform. "freeze" can only be present if "standby" is
present.
2) relative_sleep_states = 0 (default)
"mem" - "suspend-to-RAM", present if supported.
"standby" - "power-on suspend", present if supported.
"freeze" - "suspend-to-idle", always present.
Writing to this file one of these strings causes the system to Writing to this file one of these strings causes the system to
transition into that state. Please see the file transition into the corresponding state, if available. See
Documentation/power/states.txt for a description of each of Documentation/power/states.txt for a description of what
these states. "suspend-to-RAM", "power-on suspend" and "suspend-to-idle" mean.
What: /sys/power/disk What: /sys/power/disk
Date: September 2006 Date: September 2006

View file

@ -20,6 +20,7 @@ Contents:
--------- ---------
1. CPUFreq core and interfaces 1. CPUFreq core and interfaces
2. CPUFreq notifiers 2. CPUFreq notifiers
3. CPUFreq Table Generation with Operating Performance Point (OPP)
1. General Information 1. General Information
======================= =======================
@ -92,3 +93,31 @@ values:
cpu - number of the affected CPU cpu - number of the affected CPU
old - old frequency old - old frequency
new - new frequency new - new frequency
3. CPUFreq Table Generation with Operating Performance Point (OPP)
==================================================================
For details about OPP, see Documentation/power/opp.txt
dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with
cpufreq_frequency_table_cpuinfo which is provided with the list of
frequencies that are available for operation. This function provides
a ready to use conversion routine to translate the OPP layer's internal
information about the available frequencies into a format readily
providable to cpufreq.
WARNING: Do not use this function in interrupt context.
Example:
soc_pm_init()
{
/* Do things */
r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
if (!r)
cpufreq_frequency_table_cpuinfo(policy, freq_table);
/* Do other things */
}
NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
addition to CONFIG_PM_OPP.
dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table

View file

@ -228,3 +228,22 @@ is the corresponding frequency table helper for the ->target
stage. Just pass the values to this function, and the unsigned int stage. Just pass the values to this function, and the unsigned int
index returns the number of the frequency table entry which contains index returns the number of the frequency table entry which contains
the frequency the CPU shall be set to. the frequency the CPU shall be set to.
The following macros can be used as iterators over cpufreq_frequency_table:
cpufreq_for_each_entry(pos, table) - iterates over all entries of frequency
table.
cpufreq-for_each_valid_entry(pos, table) - iterates over all entries,
excluding CPUFREQ_ENTRY_INVALID frequencies.
Use arguments "pos" - a cpufreq_frequency_table * as a loop cursor and
"table" - the cpufreq_frequency_table * you want to iterate over.
For example:
struct cpufreq_frequency_table *pos, *driver_freq_table;
cpufreq_for_each_entry(pos, driver_freq_table) {
/* Do something with pos */
pos->frequency = ...
}

View file

@ -35,8 +35,8 @@ Mailing List
------------ ------------
There is a CPU frequency changing CVS commit and general list where There is a CPU frequency changing CVS commit and general list where
you can report bugs, problems or submit patches. To post a message, you can report bugs, problems or submit patches. To post a message,
send an email to cpufreq@vger.kernel.org, to subscribe go to send an email to linux-pm@vger.kernel.org, to subscribe go to
http://vger.kernel.org/vger-lists.html#cpufreq and follow the http://vger.kernel.org/vger-lists.html#linux-pm and follow the
instructions there. instructions there.
Links Links

View file

@ -214,6 +214,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
unusable. The "log_buf_len" parameter may be useful unusable. The "log_buf_len" parameter may be useful
if you need to capture more output. if you need to capture more output.
acpi_force_table_verification [HW,ACPI]
Enable table checksum verification during early stage.
By default, this is disabled due to x86 early mapping
size limitation.
acpi_irq_balance [HW,ACPI] acpi_irq_balance [HW,ACPI]
ACPI will balance active IRQs ACPI will balance active IRQs
default in APIC mode default in APIC mode
@ -237,7 +242,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
This feature is enabled by default. This feature is enabled by default.
This option allows to turn off the feature. This option allows to turn off the feature.
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT acpi_no_static_ssdt [HW,ACPI]
Disable installation of static SSDTs at early boot time
By default, SSDTs contained in the RSDT/XSDT will be
installed automatically and they will appear under
/sys/firmware/acpi/tables.
This option turns off this feature.
Note that specifying this option does not affect
dynamic table installation which will install SSDT
tables to /sys/firmware/acpi/tables/dynamic.
acpica_no_return_repair [HW, ACPI] acpica_no_return_repair [HW, ACPI]
Disable AML predefined validation mechanism Disable AML predefined validation mechanism
@ -2898,6 +2911,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
[KNL, SMP] Set scheduler's default relax_domain_level. [KNL, SMP] Set scheduler's default relax_domain_level.
See Documentation/cgroups/cpusets.txt. See Documentation/cgroups/cpusets.txt.
relative_sleep_states=
[SUSPEND] Use sleep state labeling where the deepest
state available other than hibernation is always "mem".
Format: { "0" | "1" }
0 -- Traditional sleep state labels.
1 -- Relative sleep state labels.
reserve= [KNL,BUGS] Force the kernel to ignore some iomem area reserve= [KNL,BUGS] Force the kernel to ignore some iomem area
reservetop= [X86-32] reservetop= [X86-32]
@ -3470,7 +3490,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
the allocated input device; If set to 0, video driver the allocated input device; If set to 0, video driver
will only send out the event without touching backlight will only send out the event without touching backlight
brightness level. brightness level.
default: 1 default: 0
virtio_mmio.device= virtio_mmio.device=
[VMMIO] Memory mapped virtio (platform) device. [VMMIO] Memory mapped virtio (platform) device.

View file

@ -2,6 +2,7 @@ Device Power Management
Copyright (c) 2010-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. Copyright (c) 2010-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
Copyright (c) 2010 Alan Stern <stern@rowland.harvard.edu> Copyright (c) 2010 Alan Stern <stern@rowland.harvard.edu>
Copyright (c) 2014 Intel Corp., Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Most of the code in Linux is device drivers, so most of the Linux power Most of the code in Linux is device drivers, so most of the Linux power
@ -326,6 +327,20 @@ the phases are:
driver in some way for the upcoming system power transition, but it driver in some way for the upcoming system power transition, but it
should not put the device into a low-power state. should not put the device into a low-power state.
For devices supporting runtime power management, the return value of the
prepare callback can be used to indicate to the PM core that it may
safely leave the device in runtime suspend (if runtime-suspended
already), provided that all of the device's descendants are also left in
runtime suspend. Namely, if the prepare callback returns a positive
number and that happens for all of the descendants of the device too,
and all of them (including the device itself) are runtime-suspended, the
PM core will skip the suspend, suspend_late and suspend_noirq suspend
phases as well as the resume_noirq, resume_early and resume phases of
the following system resume for all of these devices. In that case,
the complete callback will be called directly after the prepare callback
and is entirely responsible for bringing the device back to the
functional state as appropriate.
2. The suspend methods should quiesce the device to stop it from performing 2. The suspend methods should quiesce the device to stop it from performing
I/O. They also may save the device registers and put it into the I/O. They also may save the device registers and put it into the
appropriate low-power state, depending on the bus type the device is on, appropriate low-power state, depending on the bus type the device is on,
@ -400,12 +415,23 @@ When resuming from freeze, standby or memory sleep, the phases are:
the resume callbacks occur; it's not necessary to wait until the the resume callbacks occur; it's not necessary to wait until the
complete phase. complete phase.
Moreover, if the preceding prepare callback returned a positive number,
the device may have been left in runtime suspend throughout the whole
system suspend and resume (the suspend, suspend_late, suspend_noirq
phases of system suspend and the resume_noirq, resume_early, resume
phases of system resume may have been skipped for it). In that case,
the complete callback is entirely responsible for bringing the device
back to the functional state after system suspend if necessary. [For
example, it may need to queue up a runtime resume request for the device
for this purpose.] To check if that is the case, the complete callback
can consult the device's power.direct_complete flag. Namely, if that
flag is set when the complete callback is being run, it has been called
directly after the preceding prepare and special action may be required
to make the device work correctly afterward.
At the end of these phases, drivers should be as functional as they were before At the end of these phases, drivers should be as functional as they were before
suspending: I/O can be performed using DMA and IRQs, and the relevant clocks are suspending: I/O can be performed using DMA and IRQs, and the relevant clocks are
gated on. Even if the device was in a low-power state before the system sleep gated on.
because of runtime power management, afterwards it should be back in its
full-power state. There are multiple reasons why it's best to do this; they are
discussed in more detail in Documentation/power/runtime_pm.txt.
However, the details here may again be platform-specific. For example, However, the details here may again be platform-specific. For example,
some systems support multiple "run" states, and the mode in effect at some systems support multiple "run" states, and the mode in effect at

View file

@ -10,8 +10,7 @@ Contents
3. OPP Search Functions 3. OPP Search Functions
4. OPP Availability Control Functions 4. OPP Availability Control Functions
5. OPP Data Retrieval Functions 5. OPP Data Retrieval Functions
6. Cpufreq Table Generation 6. Data Structures
7. Data Structures
1. Introduction 1. Introduction
=============== ===============
@ -72,7 +71,6 @@ operations until that OPP could be re-enabled if possible.
OPP library facilitates this concept in it's implementation. The following OPP library facilitates this concept in it's implementation. The following
operational functions operate only on available opps: operational functions operate only on available opps:
opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq, dev_pm_opp_get_opp_count opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq, dev_pm_opp_get_opp_count
and dev_pm_opp_init_cpufreq_table
dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer which can then dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer which can then
be used for dev_pm_opp_enable/disable functions to make an opp available as required. be used for dev_pm_opp_enable/disable functions to make an opp available as required.
@ -96,10 +94,9 @@ using RCU read locks. The opp_find_freq_{exact,ceil,floor},
opp_get_{voltage, freq, opp_count} fall into this category. opp_get_{voltage, freq, opp_count} fall into this category.
opp_{add,enable,disable} are updaters which use mutex and implement it's own opp_{add,enable,disable} are updaters which use mutex and implement it's own
RCU locking mechanisms. dev_pm_opp_init_cpufreq_table acts as an updater and uses RCU locking mechanisms. These functions should *NOT* be called under RCU locks
mutex to implment RCU updater strategy. These functions should *NOT* be called and other contexts that prevent blocking functions in RCU or mutex operations
under RCU locks and other contexts that prevent blocking functions in RCU or from working.
mutex operations from working.
2. Initial OPP List Registration 2. Initial OPP List Registration
================================ ================================
@ -311,34 +308,7 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
/* Do other things */ /* Do other things */
} }
6. Cpufreq Table Generation 6. Data Structures
===========================
dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with
cpufreq_frequency_table_cpuinfo which is provided with the list of
frequencies that are available for operation. This function provides
a ready to use conversion routine to translate the OPP layer's internal
information about the available frequencies into a format readily
providable to cpufreq.
WARNING: Do not use this function in interrupt context.
Example:
soc_pm_init()
{
/* Do things */
r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
if (!r)
cpufreq_frequency_table_cpuinfo(policy, freq_table);
/* Do other things */
}
NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
addition to CONFIG_PM as power management feature is required to
dynamically scale voltage and frequency in a system.
dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table
7. Data Structures
================== ==================
Typically an SoC contains multiple voltage domains which are variable. Each Typically an SoC contains multiple voltage domains which are variable. Each
domain is represented by a device pointer. The relationship to OPP can be domain is represented by a device pointer. The relationship to OPP can be

View file

@ -2,6 +2,7 @@ Runtime Power Management Framework for I/O Devices
(C) 2009-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. (C) 2009-2011 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
(C) 2010 Alan Stern <stern@rowland.harvard.edu> (C) 2010 Alan Stern <stern@rowland.harvard.edu>
(C) 2014 Intel Corp., Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1. Introduction 1. Introduction
@ -444,6 +445,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
bool pm_runtime_status_suspended(struct device *dev); bool pm_runtime_status_suspended(struct device *dev);
- return true if the device's runtime PM status is 'suspended' - return true if the device's runtime PM status is 'suspended'
bool pm_runtime_suspended_if_enabled(struct device *dev);
- return true if the device's runtime PM status is 'suspended' and its
'power.disable_depth' field is equal to 1
void pm_runtime_allow(struct device *dev); void pm_runtime_allow(struct device *dev);
- set the power.runtime_auto flag for the device and decrease its usage - set the power.runtime_auto flag for the device and decrease its usage
counter (used by the /sys/devices/.../power/control interface to counter (used by the /sys/devices/.../power/control interface to
@ -644,19 +649,33 @@ place (in particular, if the system is not waking up from hibernation), it may
be more efficient to leave the devices that had been suspended before the system be more efficient to leave the devices that had been suspended before the system
suspend began in the suspended state. suspend began in the suspended state.
To this end, the PM core provides a mechanism allowing some coordination between
different levels of device hierarchy. Namely, if a system suspend .prepare()
callback returns a positive number for a device, that indicates to the PM core
that the device appears to be runtime-suspended and its state is fine, so it
may be left in runtime suspend provided that all of its descendants are also
left in runtime suspend. If that happens, the PM core will not execute any
system suspend and resume callbacks for all of those devices, except for the
complete callback, which is then entirely responsible for handling the device
as appropriate. This only applies to system suspend transitions that are not
related to hibernation (see Documentation/power/devices.txt for more
information).
The PM core does its best to reduce the probability of race conditions between The PM core does its best to reduce the probability of race conditions between
the runtime PM and system suspend/resume (and hibernation) callbacks by carrying the runtime PM and system suspend/resume (and hibernation) callbacks by carrying
out the following operations: out the following operations:
* During system suspend it calls pm_runtime_get_noresume() and * During system suspend pm_runtime_get_noresume() is called for every device
pm_runtime_barrier() for every device right before executing the right before executing the subsystem-level .prepare() callback for it and
subsystem-level .suspend() callback for it. In addition to that it calls pm_runtime_barrier() is called for every device right before executing the
__pm_runtime_disable() with 'false' as the second argument for every device subsystem-level .suspend() callback for it. In addition to that the PM core
right before executing the subsystem-level .suspend_late() callback for it. calls __pm_runtime_disable() with 'false' as the second argument for every
device right before executing the subsystem-level .suspend_late() callback
for it.
* During system resume it calls pm_runtime_enable() and pm_runtime_put() * During system resume pm_runtime_enable() and pm_runtime_put() are called for
for every device right after executing the subsystem-level .resume_early() every device right after executing the subsystem-level .resume_early()
callback and right after executing the subsystem-level .resume() callback callback and right after executing the subsystem-level .complete() callback
for it, respectively. for it, respectively.
7. Generic subsystem callbacks 7. Generic subsystem callbacks

View file

@ -1,62 +1,87 @@
System Power Management Sleep States
System Power Management States (C) 2014 Intel Corp., Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The kernel supports up to four system sleep states generically, although three
of them depend on the platform support code to implement the low-level details
for each state.
The kernel supports four power management states generically, though The states are represented by strings that can be read or written to the
one is generic and the other three are dependent on platform support /sys/power/state file. Those strings may be "mem", "standby", "freeze" and
code to implement the low-level details for each state. "disk", where the last one always represents hibernation (Suspend-To-Disk) and
This file describes each state, what they are the meaning of the remaining ones depends on the relative_sleep_states command
commonly called, what ACPI state they map to, and what string to write line argument.
to /sys/power/state to enter that state
state: Freeze / Low-Power Idle For relative_sleep_states=1, the strings "mem", "standby" and "freeze" label the
available non-hibernation sleep states from the deepest to the shallowest,
respectively. In that case, "mem" is always present in /sys/power/state,
because there is at least one non-hibernation sleep state in every system. If
the given system supports two non-hibernation sleep states, "standby" is present
in /sys/power/state in addition to "mem". If the system supports three
non-hibernation sleep states, "freeze" will be present in /sys/power/state in
addition to "mem" and "standby".
For relative_sleep_states=0, which is the default, the following descriptions
apply.
state: Suspend-To-Idle
ACPI state: S0 ACPI state: S0
String: "freeze" Label: "freeze"
This state is a generic, pure software, light-weight, low-power state. This state is a generic, pure software, light-weight, system sleep state.
It allows more energy to be saved relative to idle by freezing user It allows more energy to be saved relative to runtime idle by freezing user
space and putting all I/O devices into low-power states (possibly space and putting all I/O devices into low-power states (possibly
lower-power than available at run time), such that the processors can lower-power than available at run time), such that the processors can
spend more time in their idle states. spend more time in their idle states.
This state can be used for platforms without Standby/Suspend-to-RAM
This state can be used for platforms without Power-On Suspend/Suspend-to-RAM
support, or it can be used in addition to Suspend-to-RAM (memory sleep) support, or it can be used in addition to Suspend-to-RAM (memory sleep)
to provide reduced resume latency. to provide reduced resume latency. It is always supported.
State: Standby / Power-On Suspend State: Standby / Power-On Suspend
ACPI State: S1 ACPI State: S1
String: "standby" Label: "standby"
This state offers minimal, though real, power savings, while providing This state, if supported, offers moderate, though real, power savings, while
a very low-latency transition back to a working system. No operating providing a relatively low-latency transition back to a working system. No
state is lost (the CPU retains power), so the system easily starts up operating state is lost (the CPU retains power), so the system easily starts up
again where it left off. again where it left off.
We try to put devices in a low-power state equivalent to D1, which In addition to freezing user space and putting all I/O devices into low-power
also offers low power savings, but low resume latency. Not all devices states, which is done for Suspend-To-Idle too, nonboot CPUs are taken offline
support D1, and those that don't are left on. and all low-level system functions are suspended during transitions into this
state. For this reason, it should allow more energy to be saved relative to
Suspend-To-Idle, but the resume latency will generally be greater than for that
state.
State: Suspend-to-RAM State: Suspend-to-RAM
ACPI State: S3 ACPI State: S3
String: "mem" Label: "mem"
This state offers significant power savings as everything in the This state, if supported, offers significant power savings as everything in the
system is put into a low-power state, except for memory, which is system is put into a low-power state, except for memory, which should be placed
placed in self-refresh mode to retain its contents. into the self-refresh mode to retain its contents. All of the steps carried out
when entering Power-On Suspend are also carried out during transitions to STR.
Additional operations may take place depending on the platform capabilities. In
particular, on ACPI systems the kernel passes control to the BIOS (platform
firmware) as the last step during STR transitions and that usually results in
powering down some more low-level components that aren't directly controlled by
the kernel.
System and device state is saved and kept in memory. All devices are System and device state is saved and kept in memory. All devices are suspended
suspended and put into D3. In many cases, all peripheral buses lose and put into low-power states. In many cases, all peripheral buses lose power
power when entering STR, so devices must be able to handle the when entering STR, so devices must be able to handle the transition back to the
transition back to the On state. "on" state.
For at least ACPI, STR requires some minimal boot-strapping code to For at least ACPI, STR requires some minimal boot-strapping code to resume the
resume the system from STR. This may be true on other platforms. system from it. This may be the case on other platforms too.
State: Suspend-to-disk State: Suspend-to-disk
ACPI State: S4 ACPI State: S4
String: "disk" Label: "disk"
This state offers the greatest power savings, and can be used even in This state offers the greatest power savings, and can be used even in
the absence of low-level platform support for power management. This the absence of low-level platform support for power management. This

View file

@ -220,7 +220,10 @@ Q: After resuming, system is paging heavily, leading to very bad interactivity.
A: Try running A: Try running
cat `cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u` > /dev/null cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u | while read file
do
test -f "$file" && cat "$file" > /dev/null
done
after resume. swapoff -a; swapon -a may also be useful. after resume. swapoff -a; swapon -a may also be useful.

View file

@ -2405,7 +2405,6 @@ F: drivers/net/ethernet/ti/cpmac.c
CPU FREQUENCY DRIVERS CPU FREQUENCY DRIVERS
M: Rafael J. Wysocki <rjw@rjwysocki.net> M: Rafael J. Wysocki <rjw@rjwysocki.net>
M: Viresh Kumar <viresh.kumar@linaro.org> M: Viresh Kumar <viresh.kumar@linaro.org>
L: cpufreq@vger.kernel.org
L: linux-pm@vger.kernel.org L: linux-pm@vger.kernel.org
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
@ -2416,7 +2415,6 @@ F: include/linux/cpufreq.h
CPU FREQUENCY DRIVERS - ARM BIG LITTLE CPU FREQUENCY DRIVERS - ARM BIG LITTLE
M: Viresh Kumar <viresh.kumar@linaro.org> M: Viresh Kumar <viresh.kumar@linaro.org>
M: Sudeep Holla <sudeep.holla@arm.com> M: Sudeep Holla <sudeep.holla@arm.com>
L: cpufreq@vger.kernel.org
L: linux-pm@vger.kernel.org L: linux-pm@vger.kernel.org
W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php
S: Maintained S: Maintained
@ -6947,7 +6945,6 @@ F: drivers/power/
PNP SUPPORT PNP SUPPORT
M: Rafael J. Wysocki <rafael.j.wysocki@intel.com> M: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
M: Bjorn Helgaas <bhelgaas@google.com>
S: Maintained S: Maintained
F: drivers/pnp/ F: drivers/pnp/

View file

@ -1092,20 +1092,21 @@ int da850_register_cpufreq(char *async_clk)
static int da850_round_armrate(struct clk *clk, unsigned long rate) static int da850_round_armrate(struct clk *clk, unsigned long rate)
{ {
int i, ret = 0, diff; int ret = 0, diff;
unsigned int best = (unsigned int) -1; unsigned int best = (unsigned int) -1;
struct cpufreq_frequency_table *table = cpufreq_info.freq_table; struct cpufreq_frequency_table *table = cpufreq_info.freq_table;
struct cpufreq_frequency_table *pos;
rate /= 1000; /* convert to kHz */ rate /= 1000; /* convert to kHz */
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { cpufreq_for_each_entry(pos, table) {
diff = table[i].frequency - rate; diff = pos->frequency - rate;
if (diff < 0) if (diff < 0)
diff = -diff; diff = -diff;
if (diff < best) { if (diff < best) {
best = diff; best = diff;
ret = table[i].frequency; ret = pos->frequency;
} }
} }

View file

@ -0,0 +1,56 @@
/*
* IA64 specific ACPICA environments and implementation
*
* Copyright (C) 2014, Intel Corporation
* Author: Lv Zheng <lv.zheng@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_IA64_ACENV_H
#define _ASM_IA64_ACENV_H
#include <asm/intrinsics.h>
#define COMPILER_DEPENDENT_INT64 long
#define COMPILER_DEPENDENT_UINT64 unsigned long
/* Asm macros */
#ifdef CONFIG_ACPI
static inline int
ia64_acpi_acquire_global_lock(unsigned int *lock)
{
unsigned int old, new, val;
do {
old = *lock;
new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
val = ia64_cmpxchg4_acq(lock, new, old);
} while (unlikely (val != old));
return (new < 3) ? -1 : 0;
}
static inline int
ia64_acpi_release_global_lock(unsigned int *lock)
{
unsigned int old, new, val;
do {
old = *lock;
new = old & ~0x3;
val = ia64_cmpxchg4_acq(lock, new, old);
} while (unlikely (val != old));
return old & 0x1;
}
#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
((Acq) = ia64_acpi_acquire_global_lock(&facs->global_lock))
#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
((Acq) = ia64_acpi_release_global_lock(&facs->global_lock))
#endif
#endif /* _ASM_IA64_ACENV_H */

View file

@ -34,57 +34,8 @@
#include <linux/numa.h> #include <linux/numa.h>
#include <asm/numa.h> #include <asm/numa.h>
#define COMPILER_DEPENDENT_INT64 long
#define COMPILER_DEPENDENT_UINT64 unsigned long
/*
* Calling conventions:
*
* ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads)
* ACPI_EXTERNAL_XFACE - External ACPI interfaces
* ACPI_INTERNAL_XFACE - Internal ACPI interfaces
* ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces
*/
#define ACPI_SYSTEM_XFACE
#define ACPI_EXTERNAL_XFACE
#define ACPI_INTERNAL_XFACE
#define ACPI_INTERNAL_VAR_XFACE
/* Asm macros */
#define ACPI_FLUSH_CPU_CACHE()
static inline int
ia64_acpi_acquire_global_lock (unsigned int *lock)
{
unsigned int old, new, val;
do {
old = *lock;
new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
val = ia64_cmpxchg4_acq(lock, new, old);
} while (unlikely (val != old));
return (new < 3) ? -1 : 0;
}
static inline int
ia64_acpi_release_global_lock (unsigned int *lock)
{
unsigned int old, new, val;
do {
old = *lock;
new = old & ~0x3;
val = ia64_cmpxchg4_acq(lock, new, old);
} while (unlikely (val != old));
return old & 0x1;
}
#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
((Acq) = ia64_acpi_acquire_global_lock(&facs->global_lock))
#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
((Acq) = ia64_acpi_release_global_lock(&facs->global_lock))
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
extern int acpi_lapic;
#define acpi_disabled 0 /* ACPI always enabled on IA64 */ #define acpi_disabled 0 /* ACPI always enabled on IA64 */
#define acpi_noirq 0 /* ACPI always enabled on IA64 */ #define acpi_noirq 0 /* ACPI always enabled on IA64 */
#define acpi_pci_disabled 0 /* ACPI PCI always enabled on IA64 */ #define acpi_pci_disabled 0 /* ACPI PCI always enabled on IA64 */
@ -92,7 +43,6 @@ ia64_acpi_release_global_lock (unsigned int *lock)
#endif #endif
#define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */ #define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */
static inline void disable_acpi(void) { } static inline void disable_acpi(void) { }
static inline void pci_acpi_crs_quirks(void) { }
#ifdef CONFIG_IA64_GENERIC #ifdef CONFIG_IA64_GENERIC
const char *acpi_get_sysname (void); const char *acpi_get_sysname (void);

View file

@ -56,6 +56,7 @@
#define PREFIX "ACPI: " #define PREFIX "ACPI: "
int acpi_lapic;
unsigned int acpi_cpei_override; unsigned int acpi_cpei_override;
unsigned int acpi_cpei_phys_cpuid; unsigned int acpi_cpei_phys_cpuid;
@ -676,6 +677,8 @@ int __init early_acpi_boot_init(void)
if (ret < 1) if (ret < 1)
printk(KERN_ERR PREFIX printk(KERN_ERR PREFIX
"Error parsing MADT - no LAPIC entries\n"); "Error parsing MADT - no LAPIC entries\n");
else
acpi_lapic = 1;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (available_cpus == 0) { if (available_cpus == 0) {

View file

@ -91,10 +91,9 @@ EXPORT_SYMBOL(clk_put);
int clk_set_rate(struct clk *clk, unsigned long rate) int clk_set_rate(struct clk *clk, unsigned long rate)
{ {
unsigned int rate_khz = rate / 1000; struct cpufreq_frequency_table *pos;
int ret = 0; int ret = 0;
int regval; int regval;
int i;
if (likely(clk->ops && clk->ops->set_rate)) { if (likely(clk->ops && clk->ops->set_rate)) {
unsigned long flags; unsigned long flags;
@ -107,22 +106,16 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
propagate_rate(clk); propagate_rate(clk);
for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END; cpufreq_for_each_valid_entry(pos, loongson2_clockmod_table)
i++) { if (rate == pos->frequency)
if (loongson2_clockmod_table[i].frequency ==
CPUFREQ_ENTRY_INVALID)
continue;
if (rate_khz == loongson2_clockmod_table[i].frequency)
break; break;
} if (rate != pos->frequency)
if (rate_khz != loongson2_clockmod_table[i].frequency)
return -ENOTSUPP; return -ENOTSUPP;
clk->rate = rate; clk->rate = rate;
regval = LOONGSON_CHIPCFG0; regval = LOONGSON_CHIPCFG0;
regval = (regval & ~0x7) | regval = (regval & ~0x7) | (pos->driver_data - 1);
(loongson2_clockmod_table[i].driver_data - 1);
LOONGSON_CHIPCFG0 = regval; LOONGSON_CHIPCFG0 = regval;
return ret; return ret;

View file

@ -0,0 +1,49 @@
/*
* X86 specific ACPICA environments and implementation
*
* Copyright (C) 2014, Intel Corporation
* Author: Lv Zheng <lv.zheng@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _ASM_X86_ACENV_H
#define _ASM_X86_ACENV_H
#include <asm/special_insns.h>
/* Asm macros */
#define ACPI_FLUSH_CPU_CACHE() wbinvd()
#ifdef CONFIG_ACPI
int __acpi_acquire_global_lock(unsigned int *lock);
int __acpi_release_global_lock(unsigned int *lock);
#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
((Acq) = __acpi_release_global_lock(&facs->global_lock))
/*
* Math helper asm macros
*/
#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \
asm("divl %2;" \
: "=a"(q32), "=d"(r32) \
: "r"(d32), \
"0"(n_lo), "1"(n_hi))
#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \
asm("shrl $1,%2 ;" \
"rcrl $1,%3;" \
: "=r"(n_hi), "=r"(n_lo) \
: "0"(n_hi), "1"(n_lo))
#endif
#endif /* _ASM_X86_ACENV_H */

View file

@ -32,51 +32,6 @@
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/realmode.h> #include <asm/realmode.h>
#define COMPILER_DEPENDENT_INT64 long long
#define COMPILER_DEPENDENT_UINT64 unsigned long long
/*
* Calling conventions:
*
* ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads)
* ACPI_EXTERNAL_XFACE - External ACPI interfaces
* ACPI_INTERNAL_XFACE - Internal ACPI interfaces
* ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces
*/
#define ACPI_SYSTEM_XFACE
#define ACPI_EXTERNAL_XFACE
#define ACPI_INTERNAL_XFACE
#define ACPI_INTERNAL_VAR_XFACE
/* Asm macros */
#define ACPI_FLUSH_CPU_CACHE() wbinvd()
int __acpi_acquire_global_lock(unsigned int *lock);
int __acpi_release_global_lock(unsigned int *lock);
#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
((Acq) = __acpi_release_global_lock(&facs->global_lock))
/*
* Math helper asm macros
*/
#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \
asm("divl %2;" \
: "=a"(q32), "=d"(r32) \
: "r"(d32), \
"0"(n_lo), "1"(n_hi))
#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \
asm("shrl $1,%2 ;" \
"rcrl $1,%3;" \
: "=r"(n_hi), "=r"(n_lo) \
: "0"(n_hi), "1"(n_lo))
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
extern int acpi_lapic; extern int acpi_lapic;
extern int acpi_ioapic; extern int acpi_ioapic;

View file

@ -39,8 +39,9 @@ acpi-y += processor_core.o
acpi-y += ec.o acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o acpi-y += pci_root.o pci_link.o pci_irq.o
acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o acpi-y += acpi_lpss.o
acpi-y += acpi_platform.o acpi-y += acpi_platform.o
acpi-y += acpi_pnp.o
acpi-y += power.o acpi-y += power.o
acpi-y += event.o acpi-y += event.o
acpi-y += sysfs.o acpi-y += sysfs.o
@ -63,9 +64,9 @@ obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_VIDEO) += video.o obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
obj-$(CONFIG_ACPI_CONTAINER) += container.o obj-y += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-y += acpi_memhotplug.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_SBS) += sbshc.o obj-$(CONFIG_ACPI_SBS) += sbshc.o
obj-$(CONFIG_ACPI_SBS) += sbs.o obj-$(CONFIG_ACPI_SBS) += sbs.o

View file

@ -68,7 +68,7 @@ static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
return -ENODEV; return -ENODEV;
} }
return 0; return 1;
} }
static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev) static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)

View file

@ -220,13 +220,13 @@ static int __init extlog_init(void)
goto err; goto err;
} }
extlog_l1_hdr = acpi_os_map_memory(l1_dirbase, l1_hdr_size); extlog_l1_hdr = acpi_os_map_iomem(l1_dirbase, l1_hdr_size);
l1_head = (struct extlog_l1_head *)extlog_l1_hdr; l1_head = (struct extlog_l1_head *)extlog_l1_hdr;
l1_size = l1_head->total_len; l1_size = l1_head->total_len;
l1_percpu_entry = l1_head->entries; l1_percpu_entry = l1_head->entries;
elog_base = l1_head->elog_base; elog_base = l1_head->elog_base;
elog_size = l1_head->elog_len; elog_size = l1_head->elog_len;
acpi_os_unmap_memory(extlog_l1_hdr, l1_hdr_size); acpi_os_unmap_iomem(extlog_l1_hdr, l1_hdr_size);
release_mem_region(l1_dirbase, l1_hdr_size); release_mem_region(l1_dirbase, l1_hdr_size);
/* remap L1 header again based on completed information */ /* remap L1 header again based on completed information */
@ -237,7 +237,7 @@ static int __init extlog_init(void)
(unsigned long long)l1_dirbase + l1_size); (unsigned long long)l1_dirbase + l1_size);
goto err; goto err;
} }
extlog_l1_addr = acpi_os_map_memory(l1_dirbase, l1_size); extlog_l1_addr = acpi_os_map_iomem(l1_dirbase, l1_size);
l1_entry_base = (u64 *)((u8 *)extlog_l1_addr + l1_hdr_size); l1_entry_base = (u64 *)((u8 *)extlog_l1_addr + l1_hdr_size);
/* remap elog table */ /* remap elog table */
@ -248,7 +248,7 @@ static int __init extlog_init(void)
(unsigned long long)elog_base + elog_size); (unsigned long long)elog_base + elog_size);
goto err_release_l1_dir; goto err_release_l1_dir;
} }
elog_addr = acpi_os_map_memory(elog_base, elog_size); elog_addr = acpi_os_map_iomem(elog_base, elog_size);
rc = -ENOMEM; rc = -ENOMEM;
/* allocate buffer to save elog record */ /* allocate buffer to save elog record */
@ -270,11 +270,11 @@ static int __init extlog_init(void)
err_release_elog: err_release_elog:
if (elog_addr) if (elog_addr)
acpi_os_unmap_memory(elog_addr, elog_size); acpi_os_unmap_iomem(elog_addr, elog_size);
release_mem_region(elog_base, elog_size); release_mem_region(elog_base, elog_size);
err_release_l1_dir: err_release_l1_dir:
if (extlog_l1_addr) if (extlog_l1_addr)
acpi_os_unmap_memory(extlog_l1_addr, l1_size); acpi_os_unmap_iomem(extlog_l1_addr, l1_size);
release_mem_region(l1_dirbase, l1_size); release_mem_region(l1_dirbase, l1_size);
err: err:
pr_warn(FW_BUG "Extended error log disabled because of problems parsing f/w tables\n"); pr_warn(FW_BUG "Extended error log disabled because of problems parsing f/w tables\n");
@ -287,9 +287,9 @@ static void __exit extlog_exit(void)
mce_unregister_decode_chain(&extlog_mce_dec); mce_unregister_decode_chain(&extlog_mce_dec);
((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
if (extlog_l1_addr) if (extlog_l1_addr)
acpi_os_unmap_memory(extlog_l1_addr, l1_size); acpi_os_unmap_iomem(extlog_l1_addr, l1_size);
if (elog_addr) if (elog_addr)
acpi_os_unmap_memory(elog_addr, elog_size); acpi_os_unmap_iomem(elog_addr, elog_size);
release_mem_region(elog_base, elog_size); release_mem_region(elog_base, elog_size);
release_mem_region(l1_dirbase, l1_size); release_mem_region(l1_dirbase, l1_size);
kfree(elog_buf); kfree(elog_buf);

View file

@ -19,15 +19,21 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h> #include <linux/platform_data/clk-lpss.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/delay.h>
#include "internal.h" #include "internal.h"
ACPI_MODULE_NAME("acpi_lpss"); ACPI_MODULE_NAME("acpi_lpss");
#ifdef CONFIG_X86_INTEL_LPSS
#define LPSS_ADDR(desc) ((unsigned long)&desc)
#define LPSS_CLK_SIZE 0x04 #define LPSS_CLK_SIZE 0x04
#define LPSS_LTR_SIZE 0x18 #define LPSS_LTR_SIZE 0x18
/* Offsets relative to LPSS_PRIVATE_OFFSET */ /* Offsets relative to LPSS_PRIVATE_OFFSET */
#define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16))
#define LPSS_GENERAL 0x08 #define LPSS_GENERAL 0x08
#define LPSS_GENERAL_LTR_MODE_SW BIT(2) #define LPSS_GENERAL_LTR_MODE_SW BIT(2)
#define LPSS_GENERAL_UART_RTS_OVRD BIT(3) #define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
@ -43,6 +49,8 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_TX_INT 0x20 #define LPSS_TX_INT 0x20
#define LPSS_TX_INT_MASK BIT(1) #define LPSS_TX_INT_MASK BIT(1)
#define LPSS_PRV_REG_COUNT 9
struct lpss_shared_clock { struct lpss_shared_clock {
const char *name; const char *name;
unsigned long rate; unsigned long rate;
@ -57,7 +65,9 @@ struct lpss_device_desc {
bool ltr_required; bool ltr_required;
unsigned int prv_offset; unsigned int prv_offset;
size_t prv_size_override; size_t prv_size_override;
bool clk_divider;
bool clk_gate; bool clk_gate;
bool save_ctx;
struct lpss_shared_clock *shared_clock; struct lpss_shared_clock *shared_clock;
void (*setup)(struct lpss_private_data *pdata); void (*setup)(struct lpss_private_data *pdata);
}; };
@ -72,6 +82,7 @@ struct lpss_private_data {
resource_size_t mmio_size; resource_size_t mmio_size;
struct clk *clk; struct clk *clk;
const struct lpss_device_desc *dev_desc; const struct lpss_device_desc *dev_desc;
u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
}; };
static void lpss_uart_setup(struct lpss_private_data *pdata) static void lpss_uart_setup(struct lpss_private_data *pdata)
@ -89,6 +100,14 @@ static void lpss_uart_setup(struct lpss_private_data *pdata)
} }
static struct lpss_device_desc lpt_dev_desc = { static struct lpss_device_desc lpt_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.ltr_required = true,
.clk_divider = true,
.clk_gate = true,
};
static struct lpss_device_desc lpt_i2c_dev_desc = {
.clk_required = true, .clk_required = true,
.prv_offset = 0x800, .prv_offset = 0x800,
.ltr_required = true, .ltr_required = true,
@ -99,6 +118,7 @@ static struct lpss_device_desc lpt_uart_dev_desc = {
.clk_required = true, .clk_required = true,
.prv_offset = 0x800, .prv_offset = 0x800,
.ltr_required = true, .ltr_required = true,
.clk_divider = true,
.clk_gate = true, .clk_gate = true,
.setup = lpss_uart_setup, .setup = lpss_uart_setup,
}; };
@ -116,32 +136,25 @@ static struct lpss_shared_clock pwm_clock = {
static struct lpss_device_desc byt_pwm_dev_desc = { static struct lpss_device_desc byt_pwm_dev_desc = {
.clk_required = true, .clk_required = true,
.save_ctx = true,
.shared_clock = &pwm_clock, .shared_clock = &pwm_clock,
}; };
static struct lpss_shared_clock uart_clock = {
.name = "uart_clk",
.rate = 44236800,
};
static struct lpss_device_desc byt_uart_dev_desc = { static struct lpss_device_desc byt_uart_dev_desc = {
.clk_required = true, .clk_required = true,
.prv_offset = 0x800, .prv_offset = 0x800,
.clk_divider = true,
.clk_gate = true, .clk_gate = true,
.shared_clock = &uart_clock, .save_ctx = true,
.setup = lpss_uart_setup, .setup = lpss_uart_setup,
}; };
static struct lpss_shared_clock spi_clock = {
.name = "spi_clk",
.rate = 50000000,
};
static struct lpss_device_desc byt_spi_dev_desc = { static struct lpss_device_desc byt_spi_dev_desc = {
.clk_required = true, .clk_required = true,
.prv_offset = 0x400, .prv_offset = 0x400,
.clk_divider = true,
.clk_gate = true, .clk_gate = true,
.shared_clock = &spi_clock, .save_ctx = true,
}; };
static struct lpss_device_desc byt_sdio_dev_desc = { static struct lpss_device_desc byt_sdio_dev_desc = {
@ -156,44 +169,53 @@ static struct lpss_shared_clock i2c_clock = {
static struct lpss_device_desc byt_i2c_dev_desc = { static struct lpss_device_desc byt_i2c_dev_desc = {
.clk_required = true, .clk_required = true,
.prv_offset = 0x800, .prv_offset = 0x800,
.save_ctx = true,
.shared_clock = &i2c_clock, .shared_clock = &i2c_clock,
}; };
#else
#define LPSS_ADDR(desc) (0UL)
#endif /* CONFIG_X86_INTEL_LPSS */
static const struct acpi_device_id acpi_lpss_device_ids[] = { static const struct acpi_device_id acpi_lpss_device_ids[] = {
/* Generic LPSS devices */ /* Generic LPSS devices */
{ "INTL9C60", (unsigned long)&lpss_dma_desc }, { "INTL9C60", LPSS_ADDR(lpss_dma_desc) },
/* Lynxpoint LPSS devices */ /* Lynxpoint LPSS devices */
{ "INT33C0", (unsigned long)&lpt_dev_desc }, { "INT33C0", LPSS_ADDR(lpt_dev_desc) },
{ "INT33C1", (unsigned long)&lpt_dev_desc }, { "INT33C1", LPSS_ADDR(lpt_dev_desc) },
{ "INT33C2", (unsigned long)&lpt_dev_desc }, { "INT33C2", LPSS_ADDR(lpt_i2c_dev_desc) },
{ "INT33C3", (unsigned long)&lpt_dev_desc }, { "INT33C3", LPSS_ADDR(lpt_i2c_dev_desc) },
{ "INT33C4", (unsigned long)&lpt_uart_dev_desc }, { "INT33C4", LPSS_ADDR(lpt_uart_dev_desc) },
{ "INT33C5", (unsigned long)&lpt_uart_dev_desc }, { "INT33C5", LPSS_ADDR(lpt_uart_dev_desc) },
{ "INT33C6", (unsigned long)&lpt_sdio_dev_desc }, { "INT33C6", LPSS_ADDR(lpt_sdio_dev_desc) },
{ "INT33C7", }, { "INT33C7", },
/* BayTrail LPSS devices */ /* BayTrail LPSS devices */
{ "80860F09", (unsigned long)&byt_pwm_dev_desc }, { "80860F09", LPSS_ADDR(byt_pwm_dev_desc) },
{ "80860F0A", (unsigned long)&byt_uart_dev_desc }, { "80860F0A", LPSS_ADDR(byt_uart_dev_desc) },
{ "80860F0E", (unsigned long)&byt_spi_dev_desc }, { "80860F0E", LPSS_ADDR(byt_spi_dev_desc) },
{ "80860F14", (unsigned long)&byt_sdio_dev_desc }, { "80860F14", LPSS_ADDR(byt_sdio_dev_desc) },
{ "80860F41", (unsigned long)&byt_i2c_dev_desc }, { "80860F41", LPSS_ADDR(byt_i2c_dev_desc) },
{ "INT33B2", }, { "INT33B2", },
{ "INT33FC", }, { "INT33FC", },
{ "INT3430", (unsigned long)&lpt_dev_desc }, { "INT3430", LPSS_ADDR(lpt_dev_desc) },
{ "INT3431", (unsigned long)&lpt_dev_desc }, { "INT3431", LPSS_ADDR(lpt_dev_desc) },
{ "INT3432", (unsigned long)&lpt_dev_desc }, { "INT3432", LPSS_ADDR(lpt_i2c_dev_desc) },
{ "INT3433", (unsigned long)&lpt_dev_desc }, { "INT3433", LPSS_ADDR(lpt_i2c_dev_desc) },
{ "INT3434", (unsigned long)&lpt_uart_dev_desc }, { "INT3434", LPSS_ADDR(lpt_uart_dev_desc) },
{ "INT3435", (unsigned long)&lpt_uart_dev_desc }, { "INT3435", LPSS_ADDR(lpt_uart_dev_desc) },
{ "INT3436", (unsigned long)&lpt_sdio_dev_desc }, { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) },
{ "INT3437", }, { "INT3437", },
{ } { }
}; };
#ifdef CONFIG_X86_INTEL_LPSS
static int is_memory(struct acpi_resource *res, void *not_used) static int is_memory(struct acpi_resource *res, void *not_used)
{ {
struct resource r; struct resource r;
@ -213,9 +235,11 @@ static int register_device_clock(struct acpi_device *adev,
{ {
const struct lpss_device_desc *dev_desc = pdata->dev_desc; const struct lpss_device_desc *dev_desc = pdata->dev_desc;
struct lpss_shared_clock *shared_clock = dev_desc->shared_clock; struct lpss_shared_clock *shared_clock = dev_desc->shared_clock;
const char *devname = dev_name(&adev->dev);
struct clk *clk = ERR_PTR(-ENODEV); struct clk *clk = ERR_PTR(-ENODEV);
struct lpss_clk_data *clk_data; struct lpss_clk_data *clk_data;
const char *parent; const char *parent, *clk_name;
void __iomem *prv_base;
if (!lpss_clk_dev) if (!lpss_clk_dev)
lpt_register_clock_device(); lpt_register_clock_device();
@ -226,7 +250,7 @@ static int register_device_clock(struct acpi_device *adev,
if (dev_desc->clkdev_name) { if (dev_desc->clkdev_name) {
clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name, clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name,
dev_name(&adev->dev)); devname);
return 0; return 0;
} }
@ -235,6 +259,7 @@ static int register_device_clock(struct acpi_device *adev,
return -ENODATA; return -ENODATA;
parent = clk_data->name; parent = clk_data->name;
prv_base = pdata->mmio_base + dev_desc->prv_offset;
if (shared_clock) { if (shared_clock) {
clk = shared_clock->clk; clk = shared_clock->clk;
@ -248,16 +273,41 @@ static int register_device_clock(struct acpi_device *adev,
} }
if (dev_desc->clk_gate) { if (dev_desc->clk_gate) {
clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0, clk = clk_register_gate(NULL, devname, parent, 0,
pdata->mmio_base + dev_desc->prv_offset, prv_base, 0, 0, NULL);
0, 0, NULL); parent = devname;
pdata->clk = clk; }
if (dev_desc->clk_divider) {
/* Prevent division by zero */
if (!readl(prv_base))
writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base);
clk_name = kasprintf(GFP_KERNEL, "%s-div", devname);
if (!clk_name)
return -ENOMEM;
clk = clk_register_fractional_divider(NULL, clk_name, parent,
0, prv_base,
1, 15, 16, 15, 0, NULL);
parent = clk_name;
clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
if (!clk_name) {
kfree(parent);
return -ENOMEM;
}
clk = clk_register_gate(NULL, clk_name, parent,
CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
prv_base, 31, 0, NULL);
kfree(parent);
kfree(clk_name);
} }
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);
clk_register_clkdev(clk, NULL, dev_name(&adev->dev)); pdata->clk = clk;
clk_register_clkdev(clk, NULL, devname);
return 0; return 0;
} }
@ -268,12 +318,14 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
struct lpss_private_data *pdata; struct lpss_private_data *pdata;
struct resource_list_entry *rentry; struct resource_list_entry *rentry;
struct list_head resource_list; struct list_head resource_list;
struct platform_device *pdev;
int ret; int ret;
dev_desc = (struct lpss_device_desc *)id->driver_data; dev_desc = (struct lpss_device_desc *)id->driver_data;
if (!dev_desc) if (!dev_desc) {
return acpi_create_platform_device(adev, id); pdev = acpi_create_platform_device(adev);
return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
}
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
return -ENOMEM; return -ENOMEM;
@ -323,10 +375,13 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
dev_desc->setup(pdata); dev_desc->setup(pdata);
adev->driver_data = pdata; adev->driver_data = pdata;
ret = acpi_create_platform_device(adev, id); pdev = acpi_create_platform_device(adev);
if (ret > 0) if (!IS_ERR_OR_NULL(pdev)) {
return ret; device_enable_async_suspend(&pdev->dev);
return 1;
}
ret = PTR_ERR(pdev);
adev->driver_data = NULL; adev->driver_data = NULL;
err_out: err_out:
@ -450,6 +505,126 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val)
} }
} }
#ifdef CONFIG_PM
/**
* acpi_lpss_save_ctx() - Save the private registers of LPSS device
* @dev: LPSS device
*
* Most LPSS devices have private registers which may loose their context when
* the device is powered down. acpi_lpss_save_ctx() saves those registers into
* prv_reg_ctx array.
*/
static void acpi_lpss_save_ctx(struct device *dev)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
unsigned int i;
for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
unsigned long offset = i * sizeof(u32);
pdata->prv_reg_ctx[i] = __lpss_reg_read(pdata, offset);
dev_dbg(dev, "saving 0x%08x from LPSS reg at offset 0x%02lx\n",
pdata->prv_reg_ctx[i], offset);
}
}
/**
* acpi_lpss_restore_ctx() - Restore the private registers of LPSS device
* @dev: LPSS device
*
* Restores the registers that were previously stored with acpi_lpss_save_ctx().
*/
static void acpi_lpss_restore_ctx(struct device *dev)
{
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
unsigned int i;
/*
* The following delay is needed or the subsequent write operations may
* fail. The LPSS devices are actually PCI devices and the PCI spec
* expects 10ms delay before the device can be accessed after D3 to D0
* transition.
*/
msleep(10);
for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
unsigned long offset = i * sizeof(u32);
__lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset);
dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n",
pdata->prv_reg_ctx[i], offset);
}
}
#ifdef CONFIG_PM_SLEEP
static int acpi_lpss_suspend_late(struct device *dev)
{
int ret = pm_generic_suspend_late(dev);
if (ret)
return ret;
acpi_lpss_save_ctx(dev);
return acpi_dev_suspend_late(dev);
}
static int acpi_lpss_restore_early(struct device *dev)
{
int ret = acpi_dev_resume_early(dev);
if (ret)
return ret;
acpi_lpss_restore_ctx(dev);
return pm_generic_resume_early(dev);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_RUNTIME
static int acpi_lpss_runtime_suspend(struct device *dev)
{
int ret = pm_generic_runtime_suspend(dev);
if (ret)
return ret;
acpi_lpss_save_ctx(dev);
return acpi_dev_runtime_suspend(dev);
}
static int acpi_lpss_runtime_resume(struct device *dev)
{
int ret = acpi_dev_runtime_resume(dev);
if (ret)
return ret;
acpi_lpss_restore_ctx(dev);
return pm_generic_runtime_resume(dev);
}
#endif /* CONFIG_PM_RUNTIME */
#endif /* CONFIG_PM */
static struct dev_pm_domain acpi_lpss_pm_domain = {
.ops = {
#ifdef CONFIG_PM_SLEEP
.suspend_late = acpi_lpss_suspend_late,
.restore_early = acpi_lpss_restore_early,
.prepare = acpi_subsys_prepare,
.complete = acpi_subsys_complete,
.suspend = acpi_subsys_suspend,
.resume_early = acpi_subsys_resume_early,
.freeze = acpi_subsys_freeze,
.poweroff = acpi_subsys_suspend,
.poweroff_late = acpi_subsys_suspend_late,
#endif
#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = acpi_lpss_runtime_suspend,
.runtime_resume = acpi_lpss_runtime_resume,
#endif
},
};
static int acpi_lpss_platform_notify(struct notifier_block *nb, static int acpi_lpss_platform_notify(struct notifier_block *nb,
unsigned long action, void *data) unsigned long action, void *data)
{ {
@ -457,7 +632,6 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
struct lpss_private_data *pdata; struct lpss_private_data *pdata;
struct acpi_device *adev; struct acpi_device *adev;
const struct acpi_device_id *id; const struct acpi_device_id *id;
int ret = 0;
id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev); id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev);
if (!id || !id->driver_data) if (!id || !id->driver_data)
@ -467,7 +641,7 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
return 0; return 0;
pdata = acpi_driver_data(adev); pdata = acpi_driver_data(adev);
if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required) if (!pdata || !pdata->mmio_base)
return 0; return 0;
if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
@ -475,12 +649,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
return 0; return 0;
} }
if (action == BUS_NOTIFY_ADD_DEVICE) switch (action) {
ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group); case BUS_NOTIFY_BOUND_DRIVER:
else if (action == BUS_NOTIFY_DEL_DEVICE) if (pdata->dev_desc->save_ctx)
sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); pdev->dev.pm_domain = &acpi_lpss_pm_domain;
break;
case BUS_NOTIFY_UNBOUND_DRIVER:
if (pdata->dev_desc->save_ctx)
pdev->dev.pm_domain = NULL;
break;
case BUS_NOTIFY_ADD_DEVICE:
if (pdata->dev_desc->ltr_required)
return sysfs_create_group(&pdev->dev.kobj,
&lpss_attr_group);
case BUS_NOTIFY_DEL_DEVICE:
if (pdata->dev_desc->ltr_required)
sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
default:
break;
}
return ret; return 0;
} }
static struct notifier_block acpi_lpss_nb = { static struct notifier_block acpi_lpss_nb = {
@ -519,3 +708,16 @@ void __init acpi_lpss_init(void)
acpi_scan_add_handler(&lpss_handler); acpi_scan_add_handler(&lpss_handler);
} }
} }
#else
static struct acpi_scan_handler lpss_handler = {
.ids = acpi_lpss_device_ids,
};
void __init acpi_lpss_init(void)
{
acpi_scan_add_handler(&lpss_handler);
}
#endif /* CONFIG_X86_INTEL_LPSS */

View file

@ -44,6 +44,13 @@
ACPI_MODULE_NAME("acpi_memhotplug"); ACPI_MODULE_NAME("acpi_memhotplug");
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
{"", 0},
};
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
/* Memory Device States */ /* Memory Device States */
#define MEMORY_INVALID_STATE 0 #define MEMORY_INVALID_STATE 0
#define MEMORY_POWER_ON_STATE 1 #define MEMORY_POWER_ON_STATE 1
@ -53,11 +60,6 @@ static int acpi_memory_device_add(struct acpi_device *device,
const struct acpi_device_id *not_used); const struct acpi_device_id *not_used);
static void acpi_memory_device_remove(struct acpi_device *device); static void acpi_memory_device_remove(struct acpi_device *device);
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
{"", 0},
};
static struct acpi_scan_handler memory_device_handler = { static struct acpi_scan_handler memory_device_handler = {
.ids = memory_device_ids, .ids = memory_device_ids,
.attach = acpi_memory_device_add, .attach = acpi_memory_device_add,
@ -364,9 +366,11 @@ static bool __initdata acpi_no_memhotplug;
void __init acpi_memory_hotplug_init(void) void __init acpi_memory_hotplug_init(void)
{ {
if (acpi_no_memhotplug) if (acpi_no_memhotplug) {
memory_device_handler.attach = NULL;
acpi_scan_add_handler(&memory_device_handler);
return; return;
}
acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory"); acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
} }
@ -376,3 +380,16 @@ static int __init disable_acpi_memory_hotplug(char *str)
return 1; return 1;
} }
__setup("acpi_no_memhotplug", disable_acpi_memory_hotplug); __setup("acpi_no_memhotplug", disable_acpi_memory_hotplug);
#else
static struct acpi_scan_handler memory_device_handler = {
.ids = memory_device_ids,
};
void __init acpi_memory_hotplug_init(void)
{
acpi_scan_add_handler(&memory_device_handler);
}
#endif /* CONFIG_ACPI_HOTPLUG_MEMORY */

View file

@ -156,12 +156,13 @@ static int power_saving_thread(void *data)
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
int cpu; int cpu;
u64 expire_time; unsigned long expire_time;
try_to_freeze(); try_to_freeze();
/* round robin to cpus */ /* round robin to cpus */
if (last_jiffies + round_robin_time * HZ < jiffies) { expire_time = last_jiffies + round_robin_time * HZ;
if (time_before(expire_time, jiffies)) {
last_jiffies = jiffies; last_jiffies = jiffies;
round_robin_cpu(tsk_index); round_robin_cpu(tsk_index);
} }
@ -200,7 +201,7 @@ static int power_saving_thread(void *data)
CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
local_irq_enable(); local_irq_enable();
if (jiffies > expire_time) { if (time_before(expire_time, jiffies)) {
do_sleep = 1; do_sleep = 1;
break; break;
} }
@ -215,8 +216,15 @@ static int power_saving_thread(void *data)
* borrow CPU time from this CPU and cause RT task use > 95% * borrow CPU time from this CPU and cause RT task use > 95%
* CPU time. To make 'avoid starvation' work, takes a nap here. * CPU time. To make 'avoid starvation' work, takes a nap here.
*/ */
if (do_sleep) if (unlikely(do_sleep))
schedule_timeout_killable(HZ * idle_pct / 100); schedule_timeout_killable(HZ * idle_pct / 100);
/* If an external event has set the need_resched flag, then
* we need to deal with it, or this loop will continue to
* spin without calling __mwait().
*/
if (unlikely(need_resched()))
schedule();
} }
exit_round_robin(tsk_index); exit_round_robin(tsk_index);

View file

@ -22,27 +22,16 @@
ACPI_MODULE_NAME("platform"); ACPI_MODULE_NAME("platform");
/* static const struct acpi_device_id forbidden_id_list[] = {
* The following ACPI IDs are known to be suitable for representing as {"PNP0000", 0}, /* PIC */
* platform devices. {"PNP0100", 0}, /* Timer */
*/ {"PNP0200", 0}, /* AT DMA Controller */
static const struct acpi_device_id acpi_platform_device_ids[] = { {"", 0},
{ "PNP0D40" },
{ "VPC2004" },
{ "BCM4752" },
/* Intel Smart Sound Technology */
{ "INT33C8" },
{ "80860F28" },
{ }
}; };
/** /**
* acpi_create_platform_device - Create platform device for ACPI device node * acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for. * @adev: ACPI device node to create a platform device for.
* @id: ACPI device ID used to match @adev.
* *
* Check if the given @adev can be represented as a platform device and, if * Check if the given @adev can be represented as a platform device and, if
* that's the case, create and register a platform device, populate its common * that's the case, create and register a platform device, populate its common
@ -50,8 +39,7 @@ static const struct acpi_device_id acpi_platform_device_ids[] = {
* *
* Name of the platform device will be the same as @adev's. * Name of the platform device will be the same as @adev's.
*/ */
int acpi_create_platform_device(struct acpi_device *adev, struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
const struct acpi_device_id *id)
{ {
struct platform_device *pdev = NULL; struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent; struct acpi_device *acpi_parent;
@ -63,19 +51,22 @@ int acpi_create_platform_device(struct acpi_device *adev,
/* If the ACPI node already has a physical device attached, skip it. */ /* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count) if (adev->physical_node_count)
return 0; return NULL;
if (!acpi_match_device_ids(adev, forbidden_id_list))
return ERR_PTR(-EINVAL);
INIT_LIST_HEAD(&resource_list); INIT_LIST_HEAD(&resource_list);
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (count < 0) { if (count < 0) {
return 0; return NULL;
} else if (count > 0) { } else if (count > 0) {
resources = kmalloc(count * sizeof(struct resource), resources = kmalloc(count * sizeof(struct resource),
GFP_KERNEL); GFP_KERNEL);
if (!resources) { if (!resources) {
dev_err(&adev->dev, "No memory for resources\n"); dev_err(&adev->dev, "No memory for resources\n");
acpi_dev_free_resource_list(&resource_list); acpi_dev_free_resource_list(&resource_list);
return -ENOMEM; return ERR_PTR(-ENOMEM);
} }
count = 0; count = 0;
list_for_each_entry(rentry, &resource_list, node) list_for_each_entry(rentry, &resource_list, node)
@ -112,25 +103,13 @@ int acpi_create_platform_device(struct acpi_device *adev,
pdevinfo.num_res = count; pdevinfo.num_res = count;
pdevinfo.acpi_node.companion = adev; pdevinfo.acpi_node.companion = adev;
pdev = platform_device_register_full(&pdevinfo); pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev)) { if (IS_ERR(pdev))
dev_err(&adev->dev, "platform device creation failed: %ld\n", dev_err(&adev->dev, "platform device creation failed: %ld\n",
PTR_ERR(pdev)); PTR_ERR(pdev));
pdev = NULL; else
} else {
dev_dbg(&adev->dev, "created platform device %s\n", dev_dbg(&adev->dev, "created platform device %s\n",
dev_name(&pdev->dev)); dev_name(&pdev->dev));
}
kfree(resources); kfree(resources);
return 1; return pdev;
}
static struct acpi_scan_handler platform_handler = {
.ids = acpi_platform_device_ids,
.attach = acpi_create_platform_device,
};
void __init acpi_platform_init(void)
{
acpi_scan_add_handler(&platform_handler);
} }

395
drivers/acpi/acpi_pnp.c Normal file
View file

@ -0,0 +1,395 @@
/*
* ACPI support for PNP bus type
*
* Copyright (C) 2014, Intel Corporation
* Authors: Zhang Rui <rui.zhang@intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/module.h>
static const struct acpi_device_id acpi_pnp_device_ids[] = {
/* pata_isapnp */
{"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */
/* floppy */
{"PNP0700"},
/* ipmi_si */
{"IPI0001"},
/* tpm_inf_pnp */
{"IFX0101"}, /* Infineon TPMs */
{"IFX0102"}, /* Infineon TPMs */
/*tpm_tis */
{"PNP0C31"}, /* TPM */
{"ATM1200"}, /* Atmel */
{"IFX0102"}, /* Infineon */
{"BCM0101"}, /* Broadcom */
{"BCM0102"}, /* Broadcom */
{"NSC1200"}, /* National */
{"ICO0102"}, /* Intel */
/* ide */
{"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */
/* ns558 */
{"ASB16fd"}, /* AdLib NSC16 */
{"AZT3001"}, /* AZT1008 */
{"CDC0001"}, /* Opl3-SAx */
{"CSC0001"}, /* CS4232 */
{"CSC000f"}, /* CS4236 */
{"CSC0101"}, /* CS4327 */
{"CTL7001"}, /* SB16 */
{"CTL7002"}, /* AWE64 */
{"CTL7005"}, /* Vibra16 */
{"ENS2020"}, /* SoundscapeVIVO */
{"ESS0001"}, /* ES1869 */
{"ESS0005"}, /* ES1878 */
{"ESS6880"}, /* ES688 */
{"IBM0012"}, /* CS4232 */
{"OPT0001"}, /* OPTi Audio16 */
{"YMH0006"}, /* Opl3-SA */
{"YMH0022"}, /* Opl3-SAx */
{"PNPb02f"}, /* Generic */
/* i8042 kbd */
{"PNP0300"},
{"PNP0301"},
{"PNP0302"},
{"PNP0303"},
{"PNP0304"},
{"PNP0305"},
{"PNP0306"},
{"PNP0309"},
{"PNP030a"},
{"PNP030b"},
{"PNP0320"},
{"PNP0343"},
{"PNP0344"},
{"PNP0345"},
{"CPQA0D7"},
/* i8042 aux */
{"AUI0200"},
{"FJC6000"},
{"FJC6001"},
{"PNP0f03"},
{"PNP0f0b"},
{"PNP0f0e"},
{"PNP0f12"},
{"PNP0f13"},
{"PNP0f19"},
{"PNP0f1c"},
{"SYN0801"},
/* fcpnp */
{"AVM0900"},
/* radio-cadet */
{"MSM0c24"}, /* ADS Cadet AM/FM Radio Card */
/* radio-gemtek */
{"ADS7183"}, /* AOpen FX-3D/Pro Radio */
/* radio-sf16fmr2 */
{"MFRad13"}, /* tuner subdevice of SF16-FMD2 */
/* ene_ir */
{"ENE0100"},
{"ENE0200"},
{"ENE0201"},
{"ENE0202"},
/* fintek-cir */
{"FIT0002"}, /* CIR */
/* ite-cir */
{"ITE8704"}, /* Default model */
{"ITE8713"}, /* CIR found in EEEBox 1501U */
{"ITE8708"}, /* Bridged IT8512 */
{"ITE8709"}, /* SRAM-Bridged IT8512 */
/* nuvoton-cir */
{"WEC0530"}, /* CIR */
{"NTN0530"}, /* CIR for new chip's pnp id */
/* Winbond CIR */
{"WEC1022"},
/* wbsd */
{"WEC0517"},
{"WEC0518"},
/* Winbond CIR */
{"TCM5090"}, /* 3Com Etherlink III (TP) */
{"TCM5091"}, /* 3Com Etherlink III */
{"TCM5094"}, /* 3Com Etherlink III (combo) */
{"TCM5095"}, /* 3Com Etherlink III (TPO) */
{"TCM5098"}, /* 3Com Etherlink III (TPC) */
{"PNP80f7"}, /* 3Com Etherlink III compatible */
{"PNP80f8"}, /* 3Com Etherlink III compatible */
/* nsc-ircc */
{"NSC6001"},
{"HWPC224"},
{"IBM0071"},
/* smsc-ircc2 */
{"SMCf010"},
/* sb1000 */
{"GIC1000"},
/* parport_pc */
{"PNP0400"}, /* Standard LPT Printer Port */
{"PNP0401"}, /* ECP Printer Port */
/* apple-gmux */
{"APP000B"},
/* fujitsu-laptop.c */
{"FUJ02bf"},
{"FUJ02B1"},
{"FUJ02E3"},
/* system */
{"PNP0c02"}, /* General ID for reserving resources */
{"PNP0c01"}, /* memory controller */
/* rtc_cmos */
{"PNP0b00"},
{"PNP0b01"},
{"PNP0b02"},
/* c6xdigio */
{"PNP0400"}, /* Standard LPT Printer Port */
{"PNP0401"}, /* ECP Printer Port */
/* ni_atmio.c */
{"NIC1900"},
{"NIC2400"},
{"NIC2500"},
{"NIC2600"},
{"NIC2700"},
/* serial */
{"AAC000F"}, /* Archtek America Corp. Archtek SmartLink Modem 3334BT Plug & Play */
{"ADC0001"}, /* Anchor Datacomm BV. SXPro 144 External Data Fax Modem Plug & Play */
{"ADC0002"}, /* SXPro 288 External Data Fax Modem Plug & Play */
{"AEI0250"}, /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
{"AEI1240"}, /* Actiontec ISA PNP 56K X2 Fax Modem */
{"AKY1021"}, /* Rockwell 56K ACF II Fax+Data+Voice Modem */
{"AZT4001"}, /* AZT3005 PnP SOUND DEVICE */
{"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */
{"BRI0A49"}, /* Boca Complete Ofc Communicator 14.4 Data-FAX */
{"BRI1400"}, /* Boca Research 33,600 ACF Modem */
{"BRI3400"}, /* Boca 33.6 Kbps Internal FD34FSVD */
{"BRI0A49"}, /* Boca 33.6 Kbps Internal FD34FSVD */
{"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */
{"CPI4050"}, /* Computer Peripherals Inc. EuroViVa CommCenter-33.6 SP PnP */
{"CTL3001"}, /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
{"CTL3011"}, /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
{"DAV0336"}, /* Davicom ISA 33.6K Modem */
{"DMB1032"}, /* Creative Modem Blaster Flash56 DI5601-1 */
{"DMB2001"}, /* Creative Modem Blaster V.90 DI5660 */
{"ETT0002"}, /* E-Tech CyberBULLET PC56RVP */
{"FUJ0202"}, /* Fujitsu 33600 PnP-I2 R Plug & Play */
{"FUJ0205"}, /* Fujitsu FMV-FX431 Plug & Play */
{"FUJ0206"}, /* Fujitsu 33600 PnP-I4 R Plug & Play */
{"FUJ0209"}, /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
{"GVC000F"}, /* Archtek SmartLink Modem 3334BT Plug & Play */
{"GVC0303"}, /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */
{"HAY0001"}, /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
{"HAY000C"}, /* Hayes Optima 336 V.34 + FAX + Voice PnP */
{"HAY000D"}, /* Hayes Optima 336B V.34 + FAX + Voice PnP */
{"HAY5670"}, /* Hayes Accura 56K Ext Fax Modem PnP */
{"HAY5674"}, /* Hayes Accura 56K Ext Fax Modem PnP */
{"HAY5675"}, /* Hayes Accura 56K Fax Modem PnP */
{"HAYF000"}, /* Hayes 288, V.34 + FAX */
{"HAYF001"}, /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
{"IBM0033"}, /* IBM Thinkpad 701 Internal Modem Voice */
{"PNP4972"}, /* Intermec CV60 touchscreen port */
{"IXDC801"}, /* Intertex 28k8 33k6 Voice EXT PnP */
{"IXDC901"}, /* Intertex 33k6 56k Voice EXT PnP */
{"IXDD801"}, /* Intertex 28k8 33k6 Voice SP EXT PnP */
{"IXDD901"}, /* Intertex 33k6 56k Voice SP EXT PnP */
{"IXDF401"}, /* Intertex 28k8 33k6 Voice SP INT PnP */
{"IXDF801"}, /* Intertex 28k8 33k6 Voice SP EXT PnP */
{"IXDF901"}, /* Intertex 33k6 56k Voice SP EXT PnP */
{"KOR4522"}, /* KORTEX 28800 Externe PnP */
{"KORF661"}, /* KXPro 33.6 Vocal ASVD PnP */
{"LAS4040"}, /* LASAT Internet 33600 PnP */
{"LAS4540"}, /* Lasat Safire 560 PnP */
{"LAS5440"}, /* Lasat Safire 336 PnP */
{"MNP0281"}, /* Microcom TravelPorte FAST V.34 Plug & Play */
{"MNP0336"}, /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
{"MNP0339"}, /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
{"MNP0342"}, /* Microcom DeskPorte 28.8P Plug & Play */
{"MNP0500"}, /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
{"MNP0501"}, /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
{"MNP0502"}, /* Microcom DeskPorte 28.8S Internal Plug & Play */
{"MOT1105"}, /* Motorola BitSURFR Plug & Play */
{"MOT1111"}, /* Motorola TA210 Plug & Play */
{"MOT1114"}, /* Motorola HMTA 200 (ISDN) Plug & Play */
{"MOT1115"}, /* Motorola BitSURFR Plug & Play */
{"MOT1190"}, /* Motorola Lifestyle 28.8 Internal */
{"MOT1501"}, /* Motorola V.3400 Plug & Play */
{"MOT1502"}, /* Motorola Lifestyle 28.8 V.34 Plug & Play */
{"MOT1505"}, /* Motorola Power 28.8 V.34 Plug & Play */
{"MOT1509"}, /* Motorola ModemSURFR External 28.8 Plug & Play */
{"MOT150A"}, /* Motorola Premier 33.6 Desktop Plug & Play */
{"MOT150F"}, /* Motorola VoiceSURFR 56K External PnP */
{"MOT1510"}, /* Motorola ModemSURFR 56K External PnP */
{"MOT1550"}, /* Motorola ModemSURFR 56K Internal PnP */
{"MOT1560"}, /* Motorola ModemSURFR Internal 28.8 Plug & Play */
{"MOT1580"}, /* Motorola Premier 33.6 Internal Plug & Play */
{"MOT15B0"}, /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
{"MOT15F0"}, /* Motorola VoiceSURFR 56K Internal PnP */
{"MVX00A1"}, /* Deskline K56 Phone System PnP */
{"MVX00F2"}, /* PC Rider K56 Phone System PnP */
{"nEC8241"}, /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
{"PMC2430"}, /* Pace 56 Voice Internal Plug & Play Modem */
{"PNP0500"}, /* Generic standard PC COM port */
{"PNP0501"}, /* Generic 16550A-compatible COM port */
{"PNPC000"}, /* Compaq 14400 Modem */
{"PNPC001"}, /* Compaq 2400/9600 Modem */
{"PNPC031"}, /* Dial-Up Networking Serial Cable between 2 PCs */
{"PNPC032"}, /* Dial-Up Networking Parallel Cable between 2 PCs */
{"PNPC100"}, /* Standard 9600 bps Modem */
{"PNPC101"}, /* Standard 14400 bps Modem */
{"PNPC102"}, /* Standard 28800 bps Modem */
{"PNPC103"}, /* Standard Modem */
{"PNPC104"}, /* Standard 9600 bps Modem */
{"PNPC105"}, /* Standard 14400 bps Modem */
{"PNPC106"}, /* Standard 28800 bps Modem */
{"PNPC107"}, /* Standard Modem */
{"PNPC108"}, /* Standard 9600 bps Modem */
{"PNPC109"}, /* Standard 14400 bps Modem */
{"PNPC10A"}, /* Standard 28800 bps Modem */
{"PNPC10B"}, /* Standard Modem */
{"PNPC10C"}, /* Standard 9600 bps Modem */
{"PNPC10D"}, /* Standard 14400 bps Modem */
{"PNPC10E"}, /* Standard 28800 bps Modem */
{"PNPC10F"}, /* Standard Modem */
{"PNP2000"}, /* Standard PCMCIA Card Modem */
{"ROK0030"}, /* Rockwell 33.6 DPF Internal PnP, Modular Technology 33.6 Internal PnP */
{"ROK0100"}, /* KORTEX 14400 Externe PnP */
{"ROK4120"}, /* Rockwell 28.8 */
{"ROK4920"}, /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
{"RSS00A0"}, /* Rockwell 33.6 DPF External PnP, BT Prologue 33.6 External PnP, Modular Technology 33.6 External PnP */
{"RSS0262"}, /* Viking 56K FAX INT */
{"RSS0250"}, /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
{"SUP1310"}, /* SupraExpress 28.8 Data/Fax PnP modem */
{"SUP1381"}, /* SupraExpress 336i PnP Voice Modem */
{"SUP1421"}, /* SupraExpress 33.6 Data/Fax PnP modem */
{"SUP1590"}, /* SupraExpress 33.6 Data/Fax PnP modem */
{"SUP1620"}, /* SupraExpress 336i Sp ASVD */
{"SUP1760"}, /* SupraExpress 33.6 Data/Fax PnP modem */
{"SUP2171"}, /* SupraExpress 56i Sp Intl */
{"TEX0011"}, /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
{"UAC000F"}, /* Archtek SmartLink Modem 3334BT Plug & Play */
{"USR0000"}, /* 3Com Corp. Gateway Telepath IIvi 33.6 */
{"USR0002"}, /* U.S. Robotics Sporster 33.6K Fax INT PnP */
{"USR0004"}, /* Sportster Vi 14.4 PnP FAX Voicemail */
{"USR0006"}, /* U.S. Robotics 33.6K Voice INT PnP */
{"USR0007"}, /* U.S. Robotics 33.6K Voice EXT PnP */
{"USR0009"}, /* U.S. Robotics Courier V.Everything INT PnP */
{"USR2002"}, /* U.S. Robotics 33.6K Voice INT PnP */
{"USR2070"}, /* U.S. Robotics 56K Voice INT PnP */
{"USR2080"}, /* U.S. Robotics 56K Voice EXT PnP */
{"USR3031"}, /* U.S. Robotics 56K FAX INT */
{"USR3050"}, /* U.S. Robotics 56K FAX INT */
{"USR3070"}, /* U.S. Robotics 56K Voice INT PnP */
{"USR3080"}, /* U.S. Robotics 56K Voice EXT PnP */
{"USR3090"}, /* U.S. Robotics 56K Voice INT PnP */
{"USR9100"}, /* U.S. Robotics 56K Message */
{"USR9160"}, /* U.S. Robotics 56K FAX EXT PnP */
{"USR9170"}, /* U.S. Robotics 56K FAX INT PnP */
{"USR9180"}, /* U.S. Robotics 56K Voice EXT PnP */
{"USR9190"}, /* U.S. Robotics 56K Voice INT PnP */
{"WACFXXX"}, /* Wacom tablets */
{"FPI2002"}, /* Compaq touchscreen */
{"FUJ02B2"}, /* Fujitsu Stylistic touchscreens */
{"FUJ02B3"},
{"FUJ02B4"}, /* Fujitsu Stylistic LT touchscreens */
{"FUJ02B6"}, /* Passive Fujitsu Stylistic touchscreens */
{"FUJ02B7"},
{"FUJ02B8"},
{"FUJ02B9"},
{"FUJ02BC"},
{"FUJ02E5"}, /* Fujitsu Wacom Tablet PC device */
{"FUJ02E6"}, /* Fujitsu P-series tablet PC device */
{"FUJ02E7"}, /* Fujitsu Wacom 2FGT Tablet PC device */
{"FUJ02E9"}, /* Fujitsu Wacom 1FGT Tablet PC device */
{"LTS0001"}, /* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in disguise) */
{"WCI0003"}, /* Rockwell's (PORALiNK) 33600 INT PNP */
{"WEC1022"}, /* Winbond CIR port, should not be probed. We should keep track of it to prevent the legacy serial driver from probing it */
/* scl200wdt */
{"NSC0800"}, /* National Semiconductor PC87307/PC97307 watchdog component */
/* mpu401 */
{"PNPb006"},
/* cs423x-pnpbios */
{"CSC0100"},
{"CSC0000"},
{"GIM0100"}, /* Guillemot Turtlebeach something appears to be cs4232 compatible */
/* es18xx-pnpbios */
{"ESS1869"},
{"ESS1879"},
/* snd-opl3sa2-pnpbios */
{"YMH0021"},
{"NMX2210"}, /* Gateway Solo 2500 */
{""},
};
static bool is_hex_digit(char c)
{
return (c >= 0 && c <= '9') || (c >= 'A' && c <= 'F');
}
static bool matching_id(char *idstr, char *list_id)
{
int i;
if (memcmp(idstr, list_id, 3))
return false;
for (i = 3; i < 7; i++) {
char c = toupper(idstr[i]);
if (!is_hex_digit(c)
|| (list_id[i] != 'X' && c != toupper(list_id[i])))
return false;
}
return true;
}
static bool acpi_pnp_match(char *idstr, const struct acpi_device_id **matchid)
{
const struct acpi_device_id *devid;
for (devid = acpi_pnp_device_ids; devid->id[0]; devid++)
if (matching_id(idstr, (char *)devid->id)) {
if (matchid)
*matchid = devid;
return true;
}
return false;
}
static int acpi_pnp_attach(struct acpi_device *adev,
const struct acpi_device_id *id)
{
return 1;
}
static struct acpi_scan_handler acpi_pnp_handler = {
.ids = acpi_pnp_device_ids,
.match = acpi_pnp_match,
.attach = acpi_pnp_attach,
};
/*
* For CMOS RTC devices, the PNP ACPI scan handler does not work, because
* there is a CMOS RTC ACPI scan handler installed already, so we need to
* check those devices and enumerate them to the PNP bus directly.
*/
static int is_cmos_rtc_device(struct acpi_device *adev)
{
struct acpi_device_id ids[] = {
{ "PNP0B00" },
{ "PNP0B01" },
{ "PNP0B02" },
{""},
};
return !acpi_match_device_ids(adev, ids);
}
bool acpi_is_pnp_device(struct acpi_device *adev)
{
return adev->handler == &acpi_pnp_handler || is_cmos_rtc_device(adev);
}
EXPORT_SYMBOL_GPL(acpi_is_pnp_device);
void __init acpi_pnp_init(void)
{
acpi_scan_add_handler(&acpi_pnp_handler);
}

View file

@ -268,7 +268,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
pr->apic_id = apic_id; pr->apic_id = apic_id;
cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id); cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);
if (!cpu0_initialized) { if (!cpu0_initialized && !acpi_lapic) {
cpu0_initialized = 1; cpu0_initialized = 1;
/* Handle UP system running SMP kernel, with no LAPIC in MADT */ /* Handle UP system running SMP kernel, with no LAPIC in MADT */
if ((cpu_index == -1) && (num_online_cpus() == 1)) if ((cpu_index == -1) && (num_online_cpus() == 1))

View file

@ -135,6 +135,7 @@ acpi-y += \
rsxface.o rsxface.o
acpi-y += \ acpi-y += \
tbdata.o \
tbfadt.o \ tbfadt.o \
tbfind.o \ tbfind.o \
tbinstal.o \ tbinstal.o \

View file

@ -0,0 +1,170 @@
/******************************************************************************
*
* Module Name: acapps - common include for ACPI applications/tools
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the "NO WARRANTY" disclaimer below
* ("Disclaimer") and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*/
#ifndef _ACAPPS
#define _ACAPPS
/* Common info for tool signons */
#define ACPICA_NAME "Intel ACPI Component Architecture"
#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2014 Intel Corporation"
#if ACPI_MACHINE_WIDTH == 64
#define ACPI_WIDTH "-64"
#elif ACPI_MACHINE_WIDTH == 32
#define ACPI_WIDTH "-32"
#else
#error unknown ACPI_MACHINE_WIDTH
#define ACPI_WIDTH "-??"
#endif
/* Macros for signons and file headers */
#define ACPI_COMMON_SIGNON(utility_name) \
"\n%s\n%s version %8.8X%s [%s]\n%s\n\n", \
ACPICA_NAME, \
utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \
ACPICA_COPYRIGHT
#define ACPI_COMMON_HEADER(utility_name, prefix) \
"%s%s\n%s%s version %8.8X%s [%s]\n%s%s\n%s\n", \
prefix, ACPICA_NAME, \
prefix, utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \
prefix, ACPICA_COPYRIGHT, \
prefix
/* Macros for usage messages */
#define ACPI_USAGE_HEADER(usage) \
printf ("Usage: %s\nOptions:\n", usage);
#define ACPI_OPTION(name, description) \
printf (" %-18s%s\n", name, description);
#define FILE_SUFFIX_DISASSEMBLY "dsl"
#define ACPI_TABLE_FILE_SUFFIX ".dat"
/*
* getopt
*/
int acpi_getopt(int argc, char **argv, char *opts);
int acpi_getopt_argument(int argc, char **argv);
extern int acpi_gbl_optind;
extern int acpi_gbl_opterr;
extern int acpi_gbl_sub_opt_char;
extern char *acpi_gbl_optarg;
/*
* cmfsize - Common get file size function
*/
u32 cm_get_file_size(FILE * file);
#ifndef ACPI_DUMP_APP
/*
* adisasm
*/
acpi_status
ad_aml_disassemble(u8 out_to_file,
char *filename, char *prefix, char **out_filename);
void ad_print_statistics(void);
acpi_status ad_find_dsdt(u8 **dsdt_ptr, u32 *dsdt_length);
void ad_dump_tables(void);
acpi_status ad_get_local_tables(void);
acpi_status
ad_parse_table(struct acpi_table_header *table,
acpi_owner_id * owner_id, u8 load_table, u8 external);
acpi_status ad_display_tables(char *filename, struct acpi_table_header *table);
acpi_status ad_display_statistics(void);
/*
* adwalk
*/
void
acpi_dm_cross_reference_namespace(union acpi_parse_object *parse_tree_root,
struct acpi_namespace_node *namespace_root,
acpi_owner_id owner_id);
void acpi_dm_dump_tree(union acpi_parse_object *origin);
void acpi_dm_find_orphan_methods(union acpi_parse_object *origin);
void
acpi_dm_finish_namespace_load(union acpi_parse_object *parse_tree_root,
struct acpi_namespace_node *namespace_root,
acpi_owner_id owner_id);
void
acpi_dm_convert_resource_indexes(union acpi_parse_object *parse_tree_root,
struct acpi_namespace_node *namespace_root);
/*
* adfile
*/
acpi_status ad_initialize(void);
char *fl_generate_filename(char *input_filename, char *suffix);
acpi_status
fl_split_input_pathname(char *input_path,
char **out_directory_path, char **out_filename);
char *ad_generate_filename(char *prefix, char *table_id);
void
ad_write_table(struct acpi_table_header *table,
u32 length, char *table_name, char *oem_table_id);
#endif
#endif /* _ACAPPS */

View file

@ -104,9 +104,10 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info);
*/ */
acpi_status acpi_status
acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
struct acpi_generic_address *gpe_block_address, u64 address,
u8 space_id,
u32 register_count, u32 register_count,
u8 gpe_block_base_number, u16 gpe_block_base_number,
u32 interrupt_number, u32 interrupt_number,
struct acpi_gpe_block_info **return_gpe_block); struct acpi_gpe_block_info **return_gpe_block);

View file

@ -44,144 +44,14 @@
#ifndef __ACGLOBAL_H__ #ifndef __ACGLOBAL_H__
#define __ACGLOBAL_H__ #define __ACGLOBAL_H__
/*
* Ensure that the globals are actually defined and initialized only once.
*
* The use of these macros allows a single list of globals (here) in order
* to simplify maintenance of the code.
*/
#ifdef DEFINE_ACPI_GLOBALS
#define ACPI_GLOBAL(type,name) \
extern type name; \
type name
#define ACPI_INIT_GLOBAL(type,name,value) \
type name=value
#else
#define ACPI_GLOBAL(type,name) \
extern type name
#define ACPI_INIT_GLOBAL(type,name,value) \
extern type name
#endif
#ifdef DEFINE_ACPI_GLOBALS
/* Public globals, available from outside ACPICA subsystem */
/***************************************************************************** /*****************************************************************************
* *
* Runtime configuration (static defaults that can be overriden at runtime) * Globals related to the ACPI tables
* *
****************************************************************************/ ****************************************************************************/
/* /* Master list of all ACPI tables that were found in the RSDT/XSDT */
* Enable "slack" in the AML interpreter? Default is FALSE, and the
* interpreter strictly follows the ACPI specification. Setting to TRUE
* allows the interpreter to ignore certain errors and/or bad AML constructs.
*
* Currently, these features are enabled by this flag:
*
* 1) Allow "implicit return" of last value in a control method
* 2) Allow access beyond the end of an operation region
* 3) Allow access to uninitialized locals/args (auto-init to integer 0)
* 4) Allow ANY object type to be a source operand for the Store() operator
* 5) Allow unresolved references (invalid target name) in package objects
* 6) Enable warning messages for behavior that is not ACPI spec compliant
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE);
/*
* Automatically serialize all methods that create named objects? Default
* is TRUE, meaning that all non_serialized methods are scanned once at
* table load time to determine those that create named objects. Methods
* that create named objects are marked Serialized in order to prevent
* possible run-time problems if they are entered by more than one thread.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE);
/*
* Create the predefined _OSI method in the namespace? Default is TRUE
* because ACPI CA is fully compatible with other ACPI implementations.
* Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE);
/*
* Optionally use default values for the ACPI register widths. Set this to
* TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE);
/*
* Optionally enable output from the AML Debug Object.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE);
/*
* Optionally copy the entire DSDT to local memory (instead of simply
* mapping it.) There are some BIOSs that corrupt or replace the original
* DSDT, creating the need for this option. Default is FALSE, do not copy
* the DSDT.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE);
/*
* Optionally ignore an XSDT if present and use the RSDT instead.
* Although the ACPI specification requires that an XSDT be used instead
* of the RSDT, the XSDT has been found to be corrupt or ill-formed on
* some machines. Default behavior is to use the XSDT if present.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE);
/*
* Optionally use 32-bit FADT addresses if and when there is a conflict
* (address mismatch) between the 32-bit and 64-bit versions of the
* address. Although ACPICA adheres to the ACPI specification which
* requires the use of the corresponding 64-bit address if it is non-zero,
* some machines have been found to have a corrupted non-zero 64-bit
* address. Default is TRUE, favor the 32-bit addresses.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, TRUE);
/*
* Optionally truncate I/O addresses to 16 bits. Provides compatibility
* with other ACPI implementations. NOTE: During ACPICA initialization,
* this value is set to TRUE if any Windows OSI strings have been
* requested by the BIOS.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE);
/*
* Disable runtime checking and repair of values returned by control methods.
* Use only if the repair is causing a problem on a particular machine.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE);
/*
* Optionally do not load any SSDTs from the RSDT/XSDT during initialization.
* This can be useful for debugging ACPI problems on some machines.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_load, FALSE);
/*
* We keep track of the latest version of Windows that has been requested by
* the BIOS.
*/
ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0);
#endif /* DEFINE_ACPI_GLOBALS */
/*****************************************************************************
*
* ACPI Table globals
*
****************************************************************************/
/*
* Master list of all ACPI tables that were found in the RSDT/XSDT.
*/
ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list); ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list);
/* DSDT information. Used to check for DSDT corruption */ /* DSDT information. Used to check for DSDT corruption */
@ -279,7 +149,6 @@ ACPI_GLOBAL(acpi_exception_handler, acpi_gbl_exception_handler);
ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler); ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler);
ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler); ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler);
ACPI_GLOBAL(void *, acpi_gbl_table_handler_context); ACPI_GLOBAL(void *, acpi_gbl_table_handler_context);
ACPI_GLOBAL(struct acpi_walk_state *, acpi_gbl_breakpoint_walk);
ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler); ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler);
ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list); ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list);
@ -296,7 +165,6 @@ ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed);
/* Misc */ /* Misc */
ACPI_GLOBAL(u32, acpi_gbl_original_mode); ACPI_GLOBAL(u32, acpi_gbl_original_mode);
ACPI_GLOBAL(u32, acpi_gbl_rsdp_original_location);
ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count); ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count);
ACPI_GLOBAL(u32, acpi_gbl_ps_find_count); ACPI_GLOBAL(u32, acpi_gbl_ps_find_count);
ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save); ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save);
@ -483,11 +351,6 @@ ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc);
ACPI_GLOBAL(u32, acpi_gbl_num_nodes); ACPI_GLOBAL(u32, acpi_gbl_num_nodes);
ACPI_GLOBAL(u32, acpi_gbl_num_objects); ACPI_GLOBAL(u32, acpi_gbl_num_objects);
ACPI_GLOBAL(u32, acpi_gbl_size_of_parse_tree);
ACPI_GLOBAL(u32, acpi_gbl_size_of_method_trees);
ACPI_GLOBAL(u32, acpi_gbl_size_of_node_entries);
ACPI_GLOBAL(u32, acpi_gbl_size_of_acpi_objects);
#endif /* ACPI_DEBUGGER */ #endif /* ACPI_DEBUGGER */
/***************************************************************************** /*****************************************************************************
@ -509,5 +372,6 @@ ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL);
****************************************************************************/ ****************************************************************************/
extern const struct ah_predefined_name asl_predefined_info[]; extern const struct ah_predefined_name asl_predefined_info[];
extern const struct ah_device_id asl_device_ids[];
#endif /* __ACGLOBAL_H__ */ #endif /* __ACGLOBAL_H__ */

View file

@ -450,9 +450,9 @@ struct acpi_gpe_event_info {
struct acpi_gpe_register_info { struct acpi_gpe_register_info {
struct acpi_generic_address status_address; /* Address of status reg */ struct acpi_generic_address status_address; /* Address of status reg */
struct acpi_generic_address enable_address; /* Address of enable reg */ struct acpi_generic_address enable_address; /* Address of enable reg */
u16 base_gpe_number; /* Base GPE number for this register */
u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ u8 enable_for_wake; /* GPEs to keep enabled when sleeping */
u8 enable_for_run; /* GPEs to keep enabled when running */ u8 enable_for_run; /* GPEs to keep enabled when running */
u8 base_gpe_number; /* Base GPE number for this register */
}; };
/* /*
@ -466,11 +466,12 @@ struct acpi_gpe_block_info {
struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */ struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */
struct acpi_gpe_register_info *register_info; /* One per GPE register pair */ struct acpi_gpe_register_info *register_info; /* One per GPE register pair */
struct acpi_gpe_event_info *event_info; /* One for each GPE */ struct acpi_gpe_event_info *event_info; /* One for each GPE */
struct acpi_generic_address block_address; /* Base address of the block */ u64 address; /* Base address of the block */
u32 register_count; /* Number of register pairs in block */ u32 register_count; /* Number of register pairs in block */
u16 gpe_count; /* Number of individual GPEs in block */ u16 gpe_count; /* Number of individual GPEs in block */
u8 block_base_number; /* Base GPE number for this block */ u16 block_base_number; /* Base GPE number for this block */
u8 initialized; /* TRUE if this block is initialized */ u8 space_id;
u8 initialized; /* TRUE if this block is initialized */
}; };
/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */ /* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */
@ -733,7 +734,8 @@ union acpi_parse_value {
#define ACPI_DASM_MATCHOP 0x06 /* Parent opcode is a Match() operator */ #define ACPI_DASM_MATCHOP 0x06 /* Parent opcode is a Match() operator */
#define ACPI_DASM_LNOT_PREFIX 0x07 /* Start of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_LNOT_PREFIX 0x07 /* Start of a Lnot_equal (etc.) pair of opcodes */
#define ACPI_DASM_LNOT_SUFFIX 0x08 /* End of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_LNOT_SUFFIX 0x08 /* End of a Lnot_equal (etc.) pair of opcodes */
#define ACPI_DASM_IGNORE 0x09 /* Not used at this time */ #define ACPI_DASM_HID_STRING 0x09 /* String is a _HID or _CID */
#define ACPI_DASM_IGNORE 0x0A /* Not used at this time */
/* /*
* Generic operation (for example: If, While, Store) * Generic operation (for example: If, While, Store)
@ -1147,4 +1149,9 @@ struct ah_predefined_name {
#endif #endif
}; };
struct ah_device_id {
char *name;
char *description;
};
#endif /* __ACLOCAL_H__ */ #endif /* __ACLOCAL_H__ */

View file

@ -586,6 +586,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_LID", METHOD_0ARGS, {{"_LID", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
{{"_LPD", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */
PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0),
{{"_MAT", METHOD_0ARGS, {{"_MAT", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
@ -698,12 +702,6 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0), PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
{{"_PRP", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Str, 1 Int/Str/Pkg */
PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_STRING, 1,
ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING |
ACPI_RTYPE_PACKAGE | ACPI_RTYPE_REFERENCE, 1, 0),
{{"_PRS", METHOD_0ARGS, {{"_PRS", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}}, METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},

View file

@ -53,6 +53,31 @@ acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length); u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length);
/*
* tbdata - table data structure management
*/
acpi_status acpi_tb_get_next_root_index(u32 *table_index);
void
acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc,
acpi_physical_address address,
u8 flags, struct acpi_table_header *table);
acpi_status
acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc,
acpi_physical_address address, u8 flags);
void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc);
acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc);
acpi_status
acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature);
u8 acpi_tb_is_table_loaded(u32 table_index);
void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded);
/* /*
* tbfadt - FADT parse/convert/validate * tbfadt - FADT parse/convert/validate
*/ */
@ -72,22 +97,32 @@ acpi_tb_find_table(char *signature,
*/ */
acpi_status acpi_tb_resize_root_table_list(void); acpi_status acpi_tb_resize_root_table_list(void);
acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc); acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc);
struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc);
*table_header,
struct acpi_table_desc void acpi_tb_override_table(struct acpi_table_desc *old_table_desc);
*table_desc);
acpi_status acpi_status
acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index); acpi_tb_acquire_table(struct acpi_table_desc *table_desc,
struct acpi_table_header **table_ptr,
u32 *table_length, u8 *table_flags);
void
acpi_tb_release_table(struct acpi_table_header *table,
u32 table_length, u8 table_flags);
acpi_status
acpi_tb_install_standard_table(acpi_physical_address address,
u8 flags,
u8 reload, u8 override, u32 *table_index);
acpi_status acpi_status
acpi_tb_store_table(acpi_physical_address address, acpi_tb_store_table(acpi_physical_address address,
struct acpi_table_header *table, struct acpi_table_header *table,
u32 length, u8 flags, u32 *table_index); u32 length, u8 flags, u32 *table_index);
void acpi_tb_delete_table(struct acpi_table_desc *table_desc); void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc);
void acpi_tb_terminate(void); void acpi_tb_terminate(void);
@ -99,10 +134,6 @@ acpi_status acpi_tb_release_owner_id(u32 table_index);
acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id); acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id);
u8 acpi_tb_is_table_loaded(u32 table_index);
void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded);
/* /*
* tbutils - table manager utilities * tbutils - table manager utilities
*/ */
@ -124,8 +155,13 @@ void acpi_tb_check_dsdt_header(void);
struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index); struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index);
void void
acpi_tb_install_table(acpi_physical_address address, acpi_tb_install_table_with_override(u32 table_index,
char *signature, u32 table_index); struct acpi_table_desc *new_table_desc,
u8 override);
acpi_status
acpi_tb_install_fixed_table(acpi_physical_address address,
char *signature, u32 table_index);
acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address); acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address);

View file

@ -176,8 +176,7 @@ acpi_status acpi_ut_init_globals(void);
char *acpi_ut_get_mutex_name(u32 mutex_id); char *acpi_ut_get_mutex_name(u32 mutex_id);
const char *acpi_ut_get_notify_name(u32 notify_value); const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type);
#endif #endif
char *acpi_ut_get_type_name(acpi_object_type type); char *acpi_ut_get_type_name(acpi_object_type type);
@ -737,4 +736,11 @@ acpi_ut_method_error(const char *module_name,
struct acpi_namespace_node *node, struct acpi_namespace_node *node,
const char *path, acpi_status lookup_status); const char *path, acpi_status lookup_status);
/*
* Utility functions for ACPI names and IDs
*/
const struct ah_predefined_name *acpi_ah_match_predefined_name(char *nameseg);
const struct ah_device_id *acpi_ah_match_hardware_id(char *hid);
#endif /* _ACUTILS_H */ #endif /* _ACUTILS_H */

View file

@ -383,7 +383,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
if (!(gpe_register_info->enable_for_run | if (!(gpe_register_info->enable_for_run |
gpe_register_info->enable_for_wake)) { gpe_register_info->enable_for_wake)) {
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
"Ignore disabled registers for GPE%02X-GPE%02X: " "Ignore disabled registers for GPE %02X-%02X: "
"RunEnable=%02X, WakeEnable=%02X\n", "RunEnable=%02X, WakeEnable=%02X\n",
gpe_register_info-> gpe_register_info->
base_gpe_number, base_gpe_number,
@ -416,7 +416,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
} }
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
"Read registers for GPE%02X-GPE%02X: Status=%02X, Enable=%02X, " "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, "
"RunEnable=%02X, WakeEnable=%02X\n", "RunEnable=%02X, WakeEnable=%02X\n",
gpe_register_info->base_gpe_number, gpe_register_info->base_gpe_number,
gpe_register_info->base_gpe_number + gpe_register_info->base_gpe_number +
@ -706,7 +706,8 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
status = acpi_hw_clear_gpe(gpe_event_info); status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, ACPI_EXCEPTION((AE_INFO, status,
"Unable to clear GPE%02X", gpe_number)); "Unable to clear GPE %02X",
gpe_number));
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
} }
} }
@ -723,7 +724,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, ACPI_EXCEPTION((AE_INFO, status,
"Unable to disable GPE%02X", gpe_number)); "Unable to disable GPE %02X", gpe_number));
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
} }
@ -764,7 +765,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
gpe_event_info); gpe_event_info);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, ACPI_EXCEPTION((AE_INFO, status,
"Unable to queue handler for GPE%02X - event disabled", "Unable to queue handler for GPE %02X - event disabled",
gpe_number)); gpe_number));
} }
break; break;
@ -776,7 +777,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
* a GPE to be enabled if it has no handler or method. * a GPE to be enabled if it has no handler or method.
*/ */
ACPI_ERROR((AE_INFO, ACPI_ERROR((AE_INFO,
"No handler or method for GPE%02X, disabling event", "No handler or method for GPE %02X, disabling event",
gpe_number)); gpe_number));
break; break;

View file

@ -252,21 +252,17 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
/* Init the register_info for this GPE register (8 GPEs) */ /* Init the register_info for this GPE register (8 GPEs) */
this_register->base_gpe_number = this_register->base_gpe_number = (u16)
(u8) (gpe_block->block_base_number + (gpe_block->block_base_number +
(i * ACPI_GPE_REGISTER_WIDTH)); (i * ACPI_GPE_REGISTER_WIDTH));
this_register->status_address.address = this_register->status_address.address = gpe_block->address + i;
gpe_block->block_address.address + i;
this_register->enable_address.address = this_register->enable_address.address =
gpe_block->block_address.address + i + gpe_block->address + i + gpe_block->register_count;
gpe_block->register_count;
this_register->status_address.space_id = this_register->status_address.space_id = gpe_block->space_id;
gpe_block->block_address.space_id; this_register->enable_address.space_id = gpe_block->space_id;
this_register->enable_address.space_id =
gpe_block->block_address.space_id;
this_register->status_address.bit_width = this_register->status_address.bit_width =
ACPI_GPE_REGISTER_WIDTH; ACPI_GPE_REGISTER_WIDTH;
this_register->enable_address.bit_width = this_register->enable_address.bit_width =
@ -334,9 +330,10 @@ error_exit:
acpi_status acpi_status
acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
struct acpi_generic_address *gpe_block_address, u64 address,
u8 space_id,
u32 register_count, u32 register_count,
u8 gpe_block_base_number, u16 gpe_block_base_number,
u32 interrupt_number, u32 interrupt_number,
struct acpi_gpe_block_info **return_gpe_block) struct acpi_gpe_block_info **return_gpe_block)
{ {
@ -359,15 +356,14 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
/* Initialize the new GPE block */ /* Initialize the new GPE block */
gpe_block->address = address;
gpe_block->space_id = space_id;
gpe_block->node = gpe_device; gpe_block->node = gpe_device;
gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH); gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
gpe_block->initialized = FALSE; gpe_block->initialized = FALSE;
gpe_block->register_count = register_count; gpe_block->register_count = register_count;
gpe_block->block_base_number = gpe_block_base_number; gpe_block->block_base_number = gpe_block_base_number;
ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address,
sizeof(struct acpi_generic_address));
/* /*
* Create the register_info and event_info sub-structures * Create the register_info and event_info sub-structures
* Note: disables and clears all GPEs in the block * Note: disables and clears all GPEs in the block
@ -408,12 +404,14 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
} }
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
" Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X\n", " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
(u32)gpe_block->block_base_number, (u32)gpe_block->block_base_number,
(u32)(gpe_block->block_base_number + (u32)(gpe_block->block_base_number +
(gpe_block->gpe_count - 1)), (gpe_block->gpe_count - 1)),
gpe_device->name.ascii, gpe_block->register_count, gpe_device->name.ascii, gpe_block->register_count,
interrupt_number)); interrupt_number,
interrupt_number ==
acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));
/* Update global count of currently available GPEs */ /* Update global count of currently available GPEs */

View file

@ -131,8 +131,10 @@ acpi_status acpi_ev_gpe_initialize(void)
/* Install GPE Block 0 */ /* Install GPE Block 0 */
status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
&acpi_gbl_FADT.xgpe0_block, acpi_gbl_FADT.xgpe0_block.
register_count0, 0, address,
acpi_gbl_FADT.xgpe0_block.
space_id, register_count0, 0,
acpi_gbl_FADT.sci_interrupt, acpi_gbl_FADT.sci_interrupt,
&acpi_gbl_gpe_fadt_blocks[0]); &acpi_gbl_gpe_fadt_blocks[0]);
@ -169,8 +171,10 @@ acpi_status acpi_ev_gpe_initialize(void)
status = status =
acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
&acpi_gbl_FADT.xgpe1_block, acpi_gbl_FADT.xgpe1_block.
register_count1, address,
acpi_gbl_FADT.xgpe1_block.
space_id, register_count1,
acpi_gbl_FADT.gpe1_base, acpi_gbl_FADT.gpe1_base,
acpi_gbl_FADT. acpi_gbl_FADT.
sci_interrupt, sci_interrupt,

View file

@ -167,7 +167,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
"Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n", "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
acpi_ut_get_node_name(node), acpi_ut_get_node_name(node),
acpi_ut_get_type_name(node->type), notify_value, acpi_ut_get_type_name(node->type), notify_value,
acpi_ut_get_notify_name(notify_value), node)); acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY),
node));
status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
info); info);

View file

@ -117,7 +117,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler); ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler);
/* /*
* We are guaranteed by the ACPI CA initialization/shutdown code that * We are guaranteed by the ACPICA initialization/shutdown code that
* if this interrupt handler is installed, ACPI is enabled. * if this interrupt handler is installed, ACPI is enabled.
*/ */

View file

@ -239,7 +239,7 @@ acpi_remove_notify_handler(acpi_handle device,
union acpi_operand_object *obj_desc; union acpi_operand_object *obj_desc;
union acpi_operand_object *handler_obj; union acpi_operand_object *handler_obj;
union acpi_operand_object *previous_handler_obj; union acpi_operand_object *previous_handler_obj;
acpi_status status; acpi_status status = AE_OK;
u32 i; u32 i;
ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
@ -251,20 +251,17 @@ acpi_remove_notify_handler(acpi_handle device,
return_ACPI_STATUS(AE_BAD_PARAMETER); return_ACPI_STATUS(AE_BAD_PARAMETER);
} }
/* Make sure all deferred notify tasks are completed */
acpi_os_wait_events_complete();
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Root Object. Global handlers are removed here */ /* Root Object. Global handlers are removed here */
if (device == ACPI_ROOT_OBJECT) { if (device == ACPI_ROOT_OBJECT) {
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
if (handler_type & (i + 1)) { if (handler_type & (i + 1)) {
status =
acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (!acpi_gbl_global_notify[i].handler || if (!acpi_gbl_global_notify[i].handler ||
(acpi_gbl_global_notify[i].handler != (acpi_gbl_global_notify[i].handler !=
handler)) { handler)) {
@ -277,31 +274,40 @@ acpi_remove_notify_handler(acpi_handle device,
acpi_gbl_global_notify[i].handler = NULL; acpi_gbl_global_notify[i].handler = NULL;
acpi_gbl_global_notify[i].context = NULL; acpi_gbl_global_notify[i].context = NULL;
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
/* Make sure all deferred notify tasks are completed */
acpi_os_wait_events_complete();
} }
} }
goto unlock_and_exit; return_ACPI_STATUS(AE_OK);
} }
/* All other objects: Are Notifies allowed on this object? */ /* All other objects: Are Notifies allowed on this object? */
if (!acpi_ev_is_notify_object(node)) { if (!acpi_ev_is_notify_object(node)) {
status = AE_TYPE; return_ACPI_STATUS(AE_TYPE);
goto unlock_and_exit;
} }
/* Must have an existing internal object */ /* Must have an existing internal object */
obj_desc = acpi_ns_get_attached_object(node); obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) { if (!obj_desc) {
status = AE_NOT_EXIST; return_ACPI_STATUS(AE_NOT_EXIST);
goto unlock_and_exit;
} }
/* Internal object exists. Find the handler and remove it */ /* Internal object exists. Find the handler and remove it */
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
if (handler_type & (i + 1)) { if (handler_type & (i + 1)) {
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
handler_obj = obj_desc->common_notify.notify_list[i]; handler_obj = obj_desc->common_notify.notify_list[i];
previous_handler_obj = NULL; previous_handler_obj = NULL;
@ -329,10 +335,17 @@ acpi_remove_notify_handler(acpi_handle device,
handler_obj->notify.next[i]; handler_obj->notify.next[i];
} }
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
/* Make sure all deferred notify tasks are completed */
acpi_os_wait_events_complete();
acpi_ut_remove_reference(handler_obj); acpi_ut_remove_reference(handler_obj);
} }
} }
return_ACPI_STATUS(status);
unlock_and_exit: unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
@ -457,6 +470,8 @@ exit:
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
ACPI_EXPORT_SYMBOL(acpi_install_sci_handler)
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_remove_sci_handler * FUNCTION: acpi_remove_sci_handler
@ -468,7 +483,6 @@ exit:
* DESCRIPTION: Remove a handler for a System Control Interrupt. * DESCRIPTION: Remove a handler for a System Control Interrupt.
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_remove_sci_handler(acpi_sci_handler address) acpi_status acpi_remove_sci_handler(acpi_sci_handler address)
{ {
struct acpi_sci_handler_info *prev_sci_handler; struct acpi_sci_handler_info *prev_sci_handler;
@ -522,6 +536,8 @@ unlock_and_exit:
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler)
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_install_global_event_handler * FUNCTION: acpi_install_global_event_handler
@ -537,7 +553,6 @@ unlock_and_exit:
* Can be used to update event counters, etc. * Can be used to update event counters, etc.
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context) acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context)
{ {
@ -840,10 +855,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
return_ACPI_STATUS(AE_BAD_PARAMETER); return_ACPI_STATUS(AE_BAD_PARAMETER);
} }
/* Make sure all deferred GPE tasks are completed */
acpi_os_wait_events_complete();
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
@ -895,9 +906,17 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
(void)acpi_ev_add_gpe_reference(gpe_event_info); (void)acpi_ev_add_gpe_reference(gpe_event_info);
} }
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
/* Make sure all deferred GPE tasks are completed */
acpi_os_wait_events_complete();
/* Now we can free the handler object */ /* Now we can free the handler object */
ACPI_FREE(handler); ACPI_FREE(handler);
return_ACPI_STATUS(status);
unlock_and_exit: unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags); acpi_os_release_lock(acpi_gbl_gpe_lock, flags);

View file

@ -599,9 +599,10 @@ acpi_install_gpe_block(acpi_handle gpe_device,
* For user-installed GPE Block Devices, the gpe_block_base_number * For user-installed GPE Block Devices, the gpe_block_base_number
* is always zero * is always zero
*/ */
status = status = acpi_ev_create_gpe_block(node, gpe_block_address->address,
acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0, gpe_block_address->space_id,
interrupt_number, &gpe_block); register_count, 0, interrupt_number,
&gpe_block);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
goto unlock_and_exit; goto unlock_and_exit;
} }

View file

@ -343,16 +343,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state) struct acpi_walk_state *walk_state)
{ {
union acpi_operand_object *ddb_handle; union acpi_operand_object *ddb_handle;
struct acpi_table_header *table_header;
struct acpi_table_header *table; struct acpi_table_header *table;
struct acpi_table_desc table_desc;
u32 table_index; u32 table_index;
acpi_status status; acpi_status status;
u32 length; u32 length;
ACPI_FUNCTION_TRACE(ex_load_op); ACPI_FUNCTION_TRACE(ex_load_op);
ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
/* Source Object can be either an op_region or a Buffer/Field */ /* Source Object can be either an op_region or a Buffer/Field */
switch (obj_desc->common.type) { switch (obj_desc->common.type) {
@ -380,17 +378,17 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Get the table header first so we can get the table length */ /* Get the table header first so we can get the table length */
table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); table_header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
if (!table) { if (!table_header) {
return_ACPI_STATUS(AE_NO_MEMORY); return_ACPI_STATUS(AE_NO_MEMORY);
} }
status = status =
acpi_ex_region_read(obj_desc, acpi_ex_region_read(obj_desc,
sizeof(struct acpi_table_header), sizeof(struct acpi_table_header),
ACPI_CAST_PTR(u8, table)); ACPI_CAST_PTR(u8, table_header));
length = table->length; length = table_header->length;
ACPI_FREE(table); ACPI_FREE(table_header);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
@ -420,22 +418,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Allocate a buffer for the table */ /* Allocate a buffer for the table */
table_desc.pointer = ACPI_ALLOCATE(length); table = ACPI_ALLOCATE(length);
if (!table_desc.pointer) { if (!table) {
return_ACPI_STATUS(AE_NO_MEMORY); return_ACPI_STATUS(AE_NO_MEMORY);
} }
/* Read the entire table */ /* Read the entire table */
status = acpi_ex_region_read(obj_desc, length, status = acpi_ex_region_read(obj_desc, length,
ACPI_CAST_PTR(u8, ACPI_CAST_PTR(u8, table));
table_desc.pointer));
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_FREE(table_desc.pointer); ACPI_FREE(table);
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
table_desc.address = obj_desc->region.address;
break; break;
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */ case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
@ -452,10 +447,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Get the actual table length from the table header */ /* Get the actual table length from the table header */
table = table_header =
ACPI_CAST_PTR(struct acpi_table_header, ACPI_CAST_PTR(struct acpi_table_header,
obj_desc->buffer.pointer); obj_desc->buffer.pointer);
length = table->length; length = table_header->length;
/* Table cannot extend beyond the buffer */ /* Table cannot extend beyond the buffer */
@ -470,13 +465,12 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
* Copy the table from the buffer because the buffer could be modified * Copy the table from the buffer because the buffer could be modified
* or even deleted in the future * or even deleted in the future
*/ */
table_desc.pointer = ACPI_ALLOCATE(length); table = ACPI_ALLOCATE(length);
if (!table_desc.pointer) { if (!table) {
return_ACPI_STATUS(AE_NO_MEMORY); return_ACPI_STATUS(AE_NO_MEMORY);
} }
ACPI_MEMCPY(table_desc.pointer, table, length); ACPI_MEMCPY(table, table_header, length);
table_desc.address = ACPI_TO_INTEGER(table_desc.pointer);
break; break;
default: default:
@ -484,27 +478,32 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_OPERAND_TYPE); return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
} }
/* Validate table checksum (will not get validated in tb_add_table) */
status = acpi_tb_verify_checksum(table_desc.pointer, length);
if (ACPI_FAILURE(status)) {
ACPI_FREE(table_desc.pointer);
return_ACPI_STATUS(status);
}
/* Complete the table descriptor */
table_desc.length = length;
table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
/* Install the new table into the local data structures */ /* Install the new table into the local data structures */
status = acpi_tb_add_table(&table_desc, &table_index); ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:"));
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
TRUE, TRUE, &table_index);
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
/* Delete allocated table buffer */ /* Delete allocated table buffer */
acpi_tb_delete_table(&table_desc); ACPI_FREE(table);
return_ACPI_STATUS(status);
}
/*
* Note: Now table is "INSTALLED", it must be validated before
* loading.
*/
status =
acpi_tb_validate_table(&acpi_gbl_root_table_list.
tables[table_index]);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
@ -536,9 +535,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:"));
acpi_tb_print_table_header(0, table_desc.pointer);
/* Remove the reference by added by acpi_ex_store above */ /* Remove the reference by added by acpi_ex_store above */
acpi_ut_remove_reference(ddb_handle); acpi_ut_remove_reference(ddb_handle);
@ -546,8 +542,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Invoke table handler if present */ /* Invoke table handler if present */
if (acpi_gbl_table_handler) { if (acpi_gbl_table_handler) {
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
table_desc.pointer,
acpi_gbl_table_handler_context); acpi_gbl_table_handler_context);
} }
@ -575,6 +570,13 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
ACPI_FUNCTION_TRACE(ex_unload_table); ACPI_FUNCTION_TRACE(ex_unload_table);
/*
* Temporarily emit a warning so that the ASL for the machine can be
* hopefully obtained. This is to say that the Unload() operator is
* extremely rare if not completely unused.
*/
ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table"));
/* /*
* Validate the handle * Validate the handle
* Although the handle is partially validated in acpi_ex_reconfiguration() * Although the handle is partially validated in acpi_ex_reconfiguration()

View file

@ -134,9 +134,11 @@ static struct acpi_exdump_info acpi_ex_dump_method[9] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.aml_start), "Aml Start"} {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.aml_start), "Aml Start"}
}; };
static struct acpi_exdump_info acpi_ex_dump_mutex[5] = { static struct acpi_exdump_info acpi_ex_dump_mutex[6] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL}, {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.original_sync_level),
"Original Sync Level"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"},
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth), {ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
"Acquire Depth"}, "Acquire Depth"},

View file

@ -140,11 +140,12 @@ acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
/* Walk the list, updating the PCI device/function/bus numbers */ /* Walk the list, updating the PCI device/function/bus numbers */
status = acpi_hw_process_pci_list(pci_id, list_head); status = acpi_hw_process_pci_list(pci_id, list_head);
/* Delete the list */
acpi_hw_delete_pci_list(list_head);
} }
/* Always delete the list */
acpi_hw_delete_pci_list(list_head);
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
@ -187,6 +188,10 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
while (1) { while (1) {
status = acpi_get_parent(current_device, &parent_device); status = acpi_get_parent(current_device, &parent_device);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
/* Must delete the list before exit */
acpi_hw_delete_pci_list(*return_list_head);
return (status); return (status);
} }
@ -199,6 +204,10 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device)); list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
if (!list_element) { if (!list_element) {
/* Must delete the list before exit */
acpi_hw_delete_pci_list(*return_list_head);
return (AE_NO_MEMORY); return (AE_NO_MEMORY);
} }

View file

@ -72,6 +72,8 @@ acpi_buffer_to_resource(u8 *aml_buffer,
void *resource; void *resource;
void *current_resource_ptr; void *current_resource_ptr;
ACPI_FUNCTION_TRACE(acpi_buffer_to_resource);
/* /*
* Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag * Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag
* is not required here. * is not required here.
@ -85,7 +87,7 @@ acpi_buffer_to_resource(u8 *aml_buffer,
status = AE_OK; status = AE_OK;
} }
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return (status); return_ACPI_STATUS(status);
} }
/* Allocate a buffer for the converted resource */ /* Allocate a buffer for the converted resource */
@ -93,7 +95,7 @@ acpi_buffer_to_resource(u8 *aml_buffer,
resource = ACPI_ALLOCATE_ZEROED(list_size_needed); resource = ACPI_ALLOCATE_ZEROED(list_size_needed);
current_resource_ptr = resource; current_resource_ptr = resource;
if (!resource) { if (!resource) {
return (AE_NO_MEMORY); return_ACPI_STATUS(AE_NO_MEMORY);
} }
/* Perform the AML-to-Resource conversion */ /* Perform the AML-to-Resource conversion */
@ -110,9 +112,11 @@ acpi_buffer_to_resource(u8 *aml_buffer,
*resource_ptr = resource; *resource_ptr = resource;
} }
return (status); return_ACPI_STATUS(status);
} }
ACPI_EXPORT_SYMBOL(acpi_buffer_to_resource)
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_rs_create_resource_list * FUNCTION: acpi_rs_create_resource_list
@ -130,10 +134,9 @@ acpi_buffer_to_resource(u8 *aml_buffer,
* of device resources. * of device resources.
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
struct acpi_buffer * output_buffer) struct acpi_buffer *output_buffer)
{ {
acpi_status status; acpi_status status;

View file

@ -0,0 +1,760 @@
/******************************************************************************
*
* Module Name: tbdata - Table manager data structure functions
*
*****************************************************************************/
/*
* Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the "NO WARRANTY" disclaimer below
* ("Disclaimer") and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution.
* 3. Neither the names of the above-listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*/
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
#include "actables.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbdata")
/*******************************************************************************
*
* FUNCTION: acpi_tb_init_table_descriptor
*
* PARAMETERS: table_desc - Table descriptor
* address - Physical address of the table
* flags - Allocation flags of the table
* table - Pointer to the table
*
* RETURN: None
*
* DESCRIPTION: Initialize a new table descriptor
*
******************************************************************************/
void
acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc,
acpi_physical_address address,
u8 flags, struct acpi_table_header *table)
{
/*
* Initialize the table descriptor. Set the pointer to NULL, since the
* table is not fully mapped at this time.
*/
ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc));
table_desc->address = address;
table_desc->length = table->length;
table_desc->flags = flags;
ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_acquire_table
*
* PARAMETERS: table_desc - Table descriptor
* table_ptr - Where table is returned
* table_length - Where table length is returned
* table_flags - Where table allocation flags are returned
*
* RETURN: Status
*
* DESCRIPTION: Acquire an ACPI table. It can be used for tables not
* maintained in the acpi_gbl_root_table_list.
*
******************************************************************************/
acpi_status
acpi_tb_acquire_table(struct acpi_table_desc *table_desc,
struct acpi_table_header **table_ptr,
u32 *table_length, u8 *table_flags)
{
struct acpi_table_header *table = NULL;
switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
table =
acpi_os_map_memory(table_desc->address, table_desc->length);
break;
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
table =
ACPI_CAST_PTR(struct acpi_table_header,
table_desc->address);
break;
default:
break;
}
/* Table is not valid yet */
if (!table) {
return (AE_NO_MEMORY);
}
/* Fill the return values */
*table_ptr = table;
*table_length = table_desc->length;
*table_flags = table_desc->flags;
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_release_table
*
* PARAMETERS: table - Pointer for the table
* table_length - Length for the table
* table_flags - Allocation flags for the table
*
* RETURN: None
*
* DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table().
*
******************************************************************************/
void
acpi_tb_release_table(struct acpi_table_header *table,
u32 table_length, u8 table_flags)
{
switch (table_flags & ACPI_TABLE_ORIGIN_MASK) {
case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
acpi_os_unmap_memory(table, table_length);
break;
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
default:
break;
}
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_acquire_temp_table
*
* PARAMETERS: table_desc - Table descriptor to be acquired
* address - Address of the table
* flags - Allocation flags of the table
*
* RETURN: Status
*
* DESCRIPTION: This function validates the table header to obtain the length
* of a table and fills the table descriptor to make its state as
* "INSTALLED". Such a table descriptor is only used for verified
* installation.
*
******************************************************************************/
acpi_status
acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc,
acpi_physical_address address, u8 flags)
{
struct acpi_table_header *table_header;
switch (flags & ACPI_TABLE_ORIGIN_MASK) {
case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
/* Get the length of the full table from the header */
table_header =
acpi_os_map_memory(address,
sizeof(struct acpi_table_header));
if (!table_header) {
return (AE_NO_MEMORY);
}
acpi_tb_init_table_descriptor(table_desc, address, flags,
table_header);
acpi_os_unmap_memory(table_header,
sizeof(struct acpi_table_header));
return (AE_OK);
case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
table_header = ACPI_CAST_PTR(struct acpi_table_header, address);
if (!table_header) {
return (AE_NO_MEMORY);
}
acpi_tb_init_table_descriptor(table_desc, address, flags,
table_header);
return (AE_OK);
default:
break;
}
/* Table is not valid yet */
return (AE_NO_MEMORY);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_release_temp_table
*
* PARAMETERS: table_desc - Table descriptor to be released
*
* RETURN: Status
*
* DESCRIPTION: The inverse of acpi_tb_acquire_temp_table().
*
*****************************************************************************/
void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc)
{
/*
* Note that the .Address is maintained by the callers of
* acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table()
* where .Address will be freed.
*/
acpi_tb_invalidate_table(table_desc);
}
/******************************************************************************
*
* FUNCTION: acpi_tb_validate_table
*
* PARAMETERS: table_desc - Table descriptor
*
* RETURN: Status
*
* DESCRIPTION: This function is called to validate the table, the returned
* table descriptor is in "VALIDATED" state.
*
*****************************************************************************/
acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(tb_validate_table);
/* Validate the table if necessary */
if (!table_desc->pointer) {
status = acpi_tb_acquire_table(table_desc, &table_desc->pointer,
&table_desc->length,
&table_desc->flags);
if (!table_desc->pointer) {
status = AE_NO_MEMORY;
}
}
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_invalidate_table
*
* PARAMETERS: table_desc - Table descriptor
*
* RETURN: None
*
* DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of
* acpi_tb_validate_table().
*
******************************************************************************/
void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc)
{
ACPI_FUNCTION_TRACE(tb_invalidate_table);
/* Table must be validated */
if (!table_desc->pointer) {
return_VOID;
}
acpi_tb_release_table(table_desc->pointer, table_desc->length,
table_desc->flags);
table_desc->pointer = NULL;
return_VOID;
}
/******************************************************************************
*
* FUNCTION: acpi_tb_validate_temp_table
*
* PARAMETERS: table_desc - Table descriptor
*
* RETURN: Status
*
* DESCRIPTION: This function is called to validate the table, the returned
* table descriptor is in "VALIDATED" state.
*
*****************************************************************************/
acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc)
{
if (!table_desc->pointer && !acpi_gbl_verify_table_checksum) {
/*
* Only validates the header of the table.
* Note that Length contains the size of the mapping after invoking
* this work around, this value is required by
* acpi_tb_release_temp_table().
* We can do this because in acpi_init_table_descriptor(), the Length
* field of the installed descriptor is filled with the actual
* table length obtaining from the table header.
*/
table_desc->length = sizeof(struct acpi_table_header);
}
return (acpi_tb_validate_table(table_desc));
}
/******************************************************************************
*
* FUNCTION: acpi_tb_verify_temp_table
*
* PARAMETERS: table_desc - Table descriptor
* signature - Table signature to verify
*
* RETURN: Status
*
* DESCRIPTION: This function is called to validate and verify the table, the
* returned table descriptor is in "VALIDATED" state.
*
*****************************************************************************/
acpi_status
acpi_tb_verify_temp_table(struct acpi_table_desc * table_desc, char *signature)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(tb_verify_temp_table);
/* Validate the table */
status = acpi_tb_validate_temp_table(table_desc);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
/* If a particular signature is expected (DSDT/FACS), it must match */
if (signature && !ACPI_COMPARE_NAME(&table_desc->signature, signature)) {
ACPI_BIOS_ERROR((AE_INFO,
"Invalid signature 0x%X for ACPI table, expected [%s]",
table_desc->signature.integer, signature));
status = AE_BAD_SIGNATURE;
goto invalidate_and_exit;
}
/* Verify the checksum */
if (acpi_gbl_verify_table_checksum) {
status =
acpi_tb_verify_checksum(table_desc->pointer,
table_desc->length);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
"%4.4s " ACPI_PRINTF_UINT
" Attempted table install failed",
acpi_ut_valid_acpi_name(table_desc->
signature.
ascii) ?
table_desc->signature.ascii : "????",
ACPI_FORMAT_TO_UINT(table_desc->
address)));
goto invalidate_and_exit;
}
}
return_ACPI_STATUS(AE_OK);
invalidate_and_exit:
acpi_tb_invalidate_table(table_desc);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_resize_root_table_list
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Expand the size of global table array
*
******************************************************************************/
acpi_status acpi_tb_resize_root_table_list(void)
{
struct acpi_table_desc *tables;
u32 table_count;
ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
/* allow_resize flag is a parameter to acpi_initialize_tables */
if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
ACPI_ERROR((AE_INFO,
"Resize of Root Table Array is not allowed"));
return_ACPI_STATUS(AE_SUPPORT);
}
/* Increase the Table Array size */
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
table_count = acpi_gbl_root_table_list.max_table_count;
} else {
table_count = acpi_gbl_root_table_list.current_table_count;
}
tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count +
ACPI_ROOT_TABLE_SIZE_INCREMENT) *
sizeof(struct acpi_table_desc));
if (!tables) {
ACPI_ERROR((AE_INFO,
"Could not allocate new root table array"));
return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Copy and free the previous table array */
if (acpi_gbl_root_table_list.tables) {
ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
(acpi_size) table_count *
sizeof(struct acpi_table_desc));
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
ACPI_FREE(acpi_gbl_root_table_list.tables);
}
}
acpi_gbl_root_table_list.tables = tables;
acpi_gbl_root_table_list.max_table_count =
table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT;
acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED;
return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_get_next_root_index
*
* PARAMETERS: table_index - Where table index is returned
*
* RETURN: Status and table index.
*
* DESCRIPTION: Allocate a new ACPI table entry to the global table list
*
******************************************************************************/
acpi_status acpi_tb_get_next_root_index(u32 *table_index)
{
acpi_status status;
/* Ensure that there is room for the table in the Root Table List */
if (acpi_gbl_root_table_list.current_table_count >=
acpi_gbl_root_table_list.max_table_count) {
status = acpi_tb_resize_root_table_list();
if (ACPI_FAILURE(status)) {
return (status);
}
}
*table_index = acpi_gbl_root_table_list.current_table_count;
acpi_gbl_root_table_list.current_table_count++;
return (AE_OK);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_terminate
*
* PARAMETERS: None
*
* RETURN: None
*
* DESCRIPTION: Delete all internal ACPI tables
*
******************************************************************************/
void acpi_tb_terminate(void)
{
u32 i;
ACPI_FUNCTION_TRACE(tb_terminate);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
/* Delete the individual tables */
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]);
}
/*
* Delete the root table array if allocated locally. Array cannot be
* mapped, so we don't need to check for that flag.
*/
if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
ACPI_FREE(acpi_gbl_root_table_list.tables);
}
acpi_gbl_root_table_list.tables = NULL;
acpi_gbl_root_table_list.flags = 0;
acpi_gbl_root_table_list.current_table_count = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_VOID;
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_delete_namespace_by_owner
*
* PARAMETERS: table_index - Table index
*
* RETURN: Status
*
* DESCRIPTION: Delete all namespace objects created when this table was loaded.
*
******************************************************************************/
acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index)
{
acpi_owner_id owner_id;
acpi_status status;
ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner);
status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (table_index >= acpi_gbl_root_table_list.current_table_count) {
/* The table index does not exist */
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(AE_NOT_EXIST);
}
/* Get the owner ID for this table, used to delete namespace nodes */
owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id;
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
/*
* Need to acquire the namespace writer lock to prevent interference
* with any concurrent namespace walks. The interpreter must be
* released during the deletion since the acquisition of the deletion
* lock may block, and also since the execution of a namespace walk
* must be allowed to use the interpreter.
*/
(void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock);
acpi_ns_delete_namespace_by_owner(owner_id);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock);
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_allocate_owner_id
*
* PARAMETERS: table_index - Table index
*
* RETURN: Status
*
* DESCRIPTION: Allocates owner_id in table_desc
*
******************************************************************************/
acpi_status acpi_tb_allocate_owner_id(u32 table_index)
{
acpi_status status = AE_BAD_PARAMETER;
ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.current_table_count) {
status =
acpi_ut_allocate_owner_id(&
(acpi_gbl_root_table_list.
tables[table_index].owner_id));
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_release_owner_id
*
* PARAMETERS: table_index - Table index
*
* RETURN: Status
*
* DESCRIPTION: Releases owner_id in table_desc
*
******************************************************************************/
acpi_status acpi_tb_release_owner_id(u32 table_index)
{
acpi_status status = AE_BAD_PARAMETER;
ACPI_FUNCTION_TRACE(tb_release_owner_id);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.current_table_count) {
acpi_ut_release_owner_id(&
(acpi_gbl_root_table_list.
tables[table_index].owner_id));
status = AE_OK;
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_get_owner_id
*
* PARAMETERS: table_index - Table index
* owner_id - Where the table owner_id is returned
*
* RETURN: Status
*
* DESCRIPTION: returns owner_id for the ACPI table
*
******************************************************************************/
acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id)
{
acpi_status status = AE_BAD_PARAMETER;
ACPI_FUNCTION_TRACE(tb_get_owner_id);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.current_table_count) {
*owner_id =
acpi_gbl_root_table_list.tables[table_index].owner_id;
status = AE_OK;
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_is_table_loaded
*
* PARAMETERS: table_index - Index into the root table
*
* RETURN: Table Loaded Flag
*
******************************************************************************/
u8 acpi_tb_is_table_loaded(u32 table_index)
{
u8 is_loaded = FALSE;
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.current_table_count) {
is_loaded = (u8)
(acpi_gbl_root_table_list.tables[table_index].flags &
ACPI_TABLE_IS_LOADED);
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return (is_loaded);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_set_table_loaded_flag
*
* PARAMETERS: table_index - Table index
* is_loaded - TRUE if table is loaded, FALSE otherwise
*
* RETURN: None
*
* DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
*
******************************************************************************/
void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded)
{
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (table_index < acpi_gbl_root_table_list.current_table_count) {
if (is_loaded) {
acpi_gbl_root_table_list.tables[table_index].flags |=
ACPI_TABLE_IS_LOADED;
} else {
acpi_gbl_root_table_list.tables[table_index].flags &=
~ACPI_TABLE_IS_LOADED;
}
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
}

View file

@ -52,7 +52,8 @@ ACPI_MODULE_NAME("tbfadt")
static void static void
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
u8 space_id, u8 space_id,
u8 byte_width, u64 address, char *register_name); u8 byte_width,
u64 address, char *register_name, u8 flags);
static void acpi_tb_convert_fadt(void); static void acpi_tb_convert_fadt(void);
@ -69,13 +70,14 @@ typedef struct acpi_fadt_info {
u16 address32; u16 address32;
u16 length; u16 length;
u8 default_length; u8 default_length;
u8 type; u8 flags;
} acpi_fadt_info; } acpi_fadt_info;
#define ACPI_FADT_OPTIONAL 0 #define ACPI_FADT_OPTIONAL 0
#define ACPI_FADT_REQUIRED 1 #define ACPI_FADT_REQUIRED 1
#define ACPI_FADT_SEPARATE_LENGTH 2 #define ACPI_FADT_SEPARATE_LENGTH 2
#define ACPI_FADT_GPE_REGISTER 4
static struct acpi_fadt_info fadt_info_table[] = { static struct acpi_fadt_info fadt_info_table[] = {
{"Pm1aEventBlock", {"Pm1aEventBlock",
@ -125,14 +127,14 @@ static struct acpi_fadt_info fadt_info_table[] = {
ACPI_FADT_OFFSET(gpe0_block), ACPI_FADT_OFFSET(gpe0_block),
ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_OFFSET(gpe0_block_length),
0, 0,
ACPI_FADT_SEPARATE_LENGTH}, ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER},
{"Gpe1Block", {"Gpe1Block",
ACPI_FADT_OFFSET(xgpe1_block), ACPI_FADT_OFFSET(xgpe1_block),
ACPI_FADT_OFFSET(gpe1_block), ACPI_FADT_OFFSET(gpe1_block),
ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_OFFSET(gpe1_block_length),
0, 0,
ACPI_FADT_SEPARATE_LENGTH} ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER}
}; };
#define ACPI_FADT_INFO_ENTRIES \ #define ACPI_FADT_INFO_ENTRIES \
@ -189,19 +191,29 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
static void static void
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
u8 space_id, u8 space_id,
u8 byte_width, u64 address, char *register_name) u8 byte_width,
u64 address, char *register_name, u8 flags)
{ {
u8 bit_width; u8 bit_width;
/* Bit width field in the GAS is only one byte long, 255 max */ /*
* Bit width field in the GAS is only one byte long, 255 max.
* Check for bit_width overflow in GAS.
*/
bit_width = (u8)(byte_width * 8); bit_width = (u8)(byte_width * 8);
if (byte_width > 31) { /* (31*8)=248, (32*8)=256 */
if (byte_width > 31) { /* (31*8)=248 */ /*
ACPI_ERROR((AE_INFO, * No error for GPE blocks, because we do not use the bit_width
"%s - 32-bit FADT register is too long (%u bytes, %u bits) " * for GPEs, the legacy length (byte_width) is used instead to
"to convert to GAS struct - 255 bits max, truncating", * allow for a large number of GPEs.
register_name, byte_width, (byte_width * 8))); */
if (!(flags & ACPI_FADT_GPE_REGISTER)) {
ACPI_ERROR((AE_INFO,
"%s - 32-bit FADT register is too long (%u bytes, %u bits) "
"to convert to GAS struct - 255 bits max, truncating",
register_name, byte_width,
(byte_width * 8)));
}
bit_width = 255; bit_width = 255;
} }
@ -332,15 +344,15 @@ void acpi_tb_parse_fadt(u32 table_index)
/* Obtain the DSDT and FACS tables via their addresses within the FADT */ /* Obtain the DSDT and FACS tables via their addresses within the FADT */
acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
/* If Hardware Reduced flag is set, there is no FACS */ /* If Hardware Reduced flag is set, there is no FACS */
if (!acpi_gbl_reduced_hardware) { if (!acpi_gbl_reduced_hardware) {
acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT. acpi_tb_install_fixed_table((acpi_physical_address)
Xfacs, ACPI_SIG_FACS, acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS,
ACPI_TABLE_INDEX_FACS); ACPI_TABLE_INDEX_FACS);
} }
} }
@ -450,6 +462,7 @@ static void acpi_tb_convert_fadt(void)
struct acpi_generic_address *address64; struct acpi_generic_address *address64;
u32 address32; u32 address32;
u8 length; u8 length;
u8 flags;
u32 i; u32 i;
/* /*
@ -515,6 +528,7 @@ static void acpi_tb_convert_fadt(void)
fadt_info_table[i].length); fadt_info_table[i].length);
name = fadt_info_table[i].name; name = fadt_info_table[i].name;
flags = fadt_info_table[i].flags;
/* /*
* Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X"
@ -554,7 +568,7 @@ static void acpi_tb_convert_fadt(void)
[i]. [i].
length), length),
(u64)address32, (u64)address32,
name); name, flags);
} else if (address64->address != (u64)address32) { } else if (address64->address != (u64)address32) {
/* Address mismatch */ /* Address mismatch */
@ -582,7 +596,8 @@ static void acpi_tb_convert_fadt(void)
length), length),
(u64) (u64)
address32, address32,
name); name,
flags);
} }
} }
} }
@ -603,7 +618,7 @@ static void acpi_tb_convert_fadt(void)
address64->bit_width)); address64->bit_width));
} }
if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { if (fadt_info_table[i].flags & ACPI_FADT_REQUIRED) {
/* /*
* Field is required (Pm1a_event, Pm1a_control). * Field is required (Pm1a_event, Pm1a_control).
* Both the address and length must be non-zero. * Both the address and length must be non-zero.
@ -617,7 +632,7 @@ static void acpi_tb_convert_fadt(void)
address), address),
length)); length));
} }
} else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) { } else if (fadt_info_table[i].flags & ACPI_FADT_SEPARATE_LENGTH) {
/* /*
* Field is optional (Pm2_control, GPE0, GPE1) AND has its own * Field is optional (Pm2_control, GPE0, GPE1) AND has its own
* length field. If present, both the address and length must * length field. If present, both the address and length must
@ -726,7 +741,7 @@ static void acpi_tb_setup_fadt_registers(void)
(fadt_pm_info_table[i]. (fadt_pm_info_table[i].
register_num * register_num *
pm1_register_byte_width), pm1_register_byte_width),
"PmRegisters"); "PmRegisters", 0);
} }
} }
} }

View file

@ -99,8 +99,8 @@ acpi_tb_find_table(char *signature,
/* Table is not currently mapped, map it */ /* Table is not currently mapped, map it */
status = status =
acpi_tb_verify_table(&acpi_gbl_root_table_list. acpi_tb_validate_table(&acpi_gbl_root_table_list.
tables[i]); tables[i]);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }

File diff suppressed because it is too large Load diff

View file

@ -49,8 +49,6 @@
ACPI_MODULE_NAME("tbutils") ACPI_MODULE_NAME("tbutils")
/* Local prototypes */ /* Local prototypes */
static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address);
static acpi_physical_address static acpi_physical_address
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
@ -178,9 +176,13 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
} }
ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length); ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length);
acpi_tb_delete_table(table_desc); acpi_tb_uninstall_table(table_desc);
table_desc->pointer = new_table;
table_desc->flags = ACPI_TABLE_ORIGIN_ALLOCATED; acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT],
ACPI_PTR_TO_PHYSADDR(new_table),
ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
new_table);
ACPI_INFO((AE_INFO, ACPI_INFO((AE_INFO,
"Forced DSDT copy: length 0x%05X copied locally, original unmapped", "Forced DSDT copy: length 0x%05X copied locally, original unmapped",
@ -189,116 +191,6 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
return (new_table); return (new_table);
} }
/*******************************************************************************
*
* FUNCTION: acpi_tb_install_table
*
* PARAMETERS: address - Physical address of DSDT or FACS
* signature - Table signature, NULL if no need to
* match
* table_index - Index into root table array
*
* RETURN: None
*
* DESCRIPTION: Install an ACPI table into the global data structure. The
* table override mechanism is called to allow the host
* OS to replace any table before it is installed in the root
* table array.
*
******************************************************************************/
void
acpi_tb_install_table(acpi_physical_address address,
char *signature, u32 table_index)
{
struct acpi_table_header *table;
struct acpi_table_header *final_table;
struct acpi_table_desc *table_desc;
if (!address) {
ACPI_ERROR((AE_INFO,
"Null physical address for ACPI table [%s]",
signature));
return;
}
/* Map just the table header */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
if (!table) {
ACPI_ERROR((AE_INFO,
"Could not map memory for table [%s] at %p",
signature, ACPI_CAST_PTR(void, address)));
return;
}
/* If a particular signature is expected (DSDT/FACS), it must match */
if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
ACPI_BIOS_ERROR((AE_INFO,
"Invalid signature 0x%X for ACPI table, expected [%s]",
*ACPI_CAST_PTR(u32, table->signature),
signature));
goto unmap_and_exit;
}
/*
* Initialize the table entry. Set the pointer to NULL, since the
* table is not fully mapped at this time.
*/
table_desc = &acpi_gbl_root_table_list.tables[table_index];
table_desc->address = address;
table_desc->pointer = NULL;
table_desc->length = table->length;
table_desc->flags = ACPI_TABLE_ORIGIN_MAPPED;
ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature);
/*
* ACPI Table Override:
*
* Before we install the table, let the host OS override it with a new
* one if desired. Any table within the RSDT/XSDT can be replaced,
* including the DSDT which is pointed to by the FADT.
*
* NOTE: If the table is overridden, then final_table will contain a
* mapped pointer to the full new table. If the table is not overridden,
* or if there has been a physical override, then the table will be
* fully mapped later (in verify table). In any case, we must
* unmap the header that was mapped above.
*/
final_table = acpi_tb_table_override(table, table_desc);
if (!final_table) {
final_table = table; /* There was no override */
}
acpi_tb_print_table_header(table_desc->address, final_table);
/* Set the global integer width (based upon revision of the DSDT) */
if (table_index == ACPI_TABLE_INDEX_DSDT) {
acpi_ut_set_integer_width(final_table->revision);
}
/*
* If we have a physical override during this early loading of the ACPI
* tables, unmap the table for now. It will be mapped again later when
* it is actually used. This supports very early loading of ACPI tables,
* before virtual memory is fully initialized and running within the
* host OS. Note: A logical override has the ACPI_TABLE_ORIGIN_OVERRIDE
* flag set and will not be deleted below.
*/
if (final_table != table) {
acpi_tb_delete_table(table_desc);
}
unmap_and_exit:
/* Always unmap the table header that we mapped above */
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
}
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_tb_get_root_table_entry * FUNCTION: acpi_tb_get_root_table_entry
@ -355,87 +247,6 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
} }
} }
/*******************************************************************************
*
* FUNCTION: acpi_tb_validate_xsdt
*
* PARAMETERS: address - Physical address of the XSDT (from RSDP)
*
* RETURN: Status. AE_OK if the table appears to be valid.
*
* DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does
* not contain any NULL entries. A problem that is seen in the
* field is that the XSDT exists, but is actually useless because
* of one or more (or all) NULL entries.
*
******************************************************************************/
static acpi_status acpi_tb_validate_xsdt(acpi_physical_address xsdt_address)
{
struct acpi_table_header *table;
u8 *next_entry;
acpi_physical_address address;
u32 length;
u32 entry_count;
acpi_status status;
u32 i;
/* Get the XSDT length */
table =
acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header));
if (!table) {
return (AE_NO_MEMORY);
}
length = table->length;
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
/*
* Minimum XSDT length is the size of the standard ACPI header
* plus one physical address entry
*/
if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) {
return (AE_INVALID_TABLE_LENGTH);
}
/* Map the entire XSDT */
table = acpi_os_map_memory(xsdt_address, length);
if (!table) {
return (AE_NO_MEMORY);
}
/* Get the number of entries and pointer to first entry */
status = AE_OK;
next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
ACPI_XSDT_ENTRY_SIZE);
/* Validate each entry (physical address) within the XSDT */
for (i = 0; i < entry_count; i++) {
address =
acpi_tb_get_root_table_entry(next_entry,
ACPI_XSDT_ENTRY_SIZE);
if (!address) {
/* Detected a NULL entry, XSDT is invalid */
status = AE_NULL_ENTRY;
break;
}
next_entry += ACPI_XSDT_ENTRY_SIZE;
}
/* Unmap table */
acpi_os_unmap_memory(table, length);
return (status);
}
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_tb_parse_root_table * FUNCTION: acpi_tb_parse_root_table
@ -461,10 +272,10 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
u32 table_count; u32 table_count;
struct acpi_table_header *table; struct acpi_table_header *table;
acpi_physical_address address; acpi_physical_address address;
acpi_physical_address rsdt_address;
u32 length; u32 length;
u8 *table_entry; u8 *table_entry;
acpi_status status; acpi_status status;
u32 table_index;
ACPI_FUNCTION_TRACE(tb_parse_root_table); ACPI_FUNCTION_TRACE(tb_parse_root_table);
@ -489,14 +300,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
* as per the ACPI specification. * as per the ACPI specification.
*/ */
address = (acpi_physical_address) rsdp->xsdt_physical_address; address = (acpi_physical_address) rsdp->xsdt_physical_address;
rsdt_address =
(acpi_physical_address) rsdp->rsdt_physical_address;
table_entry_size = ACPI_XSDT_ENTRY_SIZE; table_entry_size = ACPI_XSDT_ENTRY_SIZE;
} else { } else {
/* Root table is an RSDT (32-bit physical addresses) */ /* Root table is an RSDT (32-bit physical addresses) */
address = (acpi_physical_address) rsdp->rsdt_physical_address; address = (acpi_physical_address) rsdp->rsdt_physical_address;
rsdt_address = address;
table_entry_size = ACPI_RSDT_ENTRY_SIZE; table_entry_size = ACPI_RSDT_ENTRY_SIZE;
} }
@ -506,24 +314,6 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
*/ */
acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp)); acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
/*
* If it is present and used, validate the XSDT for access/size
* and ensure that all table entries are at least non-NULL
*/
if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) {
status = acpi_tb_validate_xsdt(address);
if (ACPI_FAILURE(status)) {
ACPI_BIOS_WARNING((AE_INFO,
"XSDT is invalid (%s), using RSDT",
acpi_format_exception(status)));
/* Fall back to the RSDT */
address = rsdt_address;
table_entry_size = ACPI_RSDT_ENTRY_SIZE;
}
}
/* Map the RSDT/XSDT table header to get the full table length */ /* Map the RSDT/XSDT table header to get the full table length */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header)); table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
@ -576,55 +366,36 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
/* Initialize the root table array from the RSDT/XSDT */ /* Initialize the root table array from the RSDT/XSDT */
for (i = 0; i < table_count; i++) { for (i = 0; i < table_count; i++) {
if (acpi_gbl_root_table_list.current_table_count >=
acpi_gbl_root_table_list.max_table_count) {
/* There is no more room in the root table array, attempt resize */
status = acpi_tb_resize_root_table_list();
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO,
"Truncating %u table entries!",
(unsigned) (table_count -
(acpi_gbl_root_table_list.
current_table_count -
2))));
break;
}
}
/* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list. address =
current_table_count].address =
acpi_tb_get_root_table_entry(table_entry, table_entry_size); acpi_tb_get_root_table_entry(table_entry, table_entry_size);
table_entry += table_entry_size; /* Skip NULL entries in RSDT/XSDT */
acpi_gbl_root_table_list.current_table_count++;
}
/* if (!address) {
* It is not possible to map more than one entry in some environments, goto next_table;
* so unmap the root table here before mapping other tables
*/
acpi_os_unmap_memory(table, length);
/*
* Complete the initialization of the root table array by examining
* the header of each table
*/
for (i = 2; i < acpi_gbl_root_table_list.current_table_count; i++) {
acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
address, NULL, i);
/* Special case for FADT - validate it then get the DSDT and FACS */
if (ACPI_COMPARE_NAME
(&acpi_gbl_root_table_list.tables[i].signature,
ACPI_SIG_FADT)) {
acpi_tb_parse_fadt(i);
} }
status = acpi_tb_install_standard_table(address,
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
FALSE, TRUE,
&table_index);
if (ACPI_SUCCESS(status) &&
ACPI_COMPARE_NAME(&acpi_gbl_root_table_list.
tables[table_index].signature,
ACPI_SIG_FADT)) {
acpi_tb_parse_fadt(table_index);
}
next_table:
table_entry += table_entry_size;
} }
acpi_os_unmap_memory(table, length);
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
} }

View file

@ -206,8 +206,8 @@ acpi_status
acpi_get_table_header(char *signature, acpi_get_table_header(char *signature,
u32 instance, struct acpi_table_header *out_table_header) u32 instance, struct acpi_table_header *out_table_header)
{ {
u32 i; u32 i;
u32 j; u32 j;
struct acpi_table_header *header; struct acpi_table_header *header;
/* Parameter validation */ /* Parameter validation */
@ -233,7 +233,7 @@ acpi_get_table_header(char *signature,
if (!acpi_gbl_root_table_list.tables[i].pointer) { if (!acpi_gbl_root_table_list.tables[i].pointer) {
if ((acpi_gbl_root_table_list.tables[i].flags & if ((acpi_gbl_root_table_list.tables[i].flags &
ACPI_TABLE_ORIGIN_MASK) == ACPI_TABLE_ORIGIN_MASK) ==
ACPI_TABLE_ORIGIN_MAPPED) { ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) {
header = header =
acpi_os_map_memory(acpi_gbl_root_table_list. acpi_os_map_memory(acpi_gbl_root_table_list.
tables[i].address, tables[i].address,
@ -321,8 +321,8 @@ acpi_get_table_with_size(char *signature,
u32 instance, struct acpi_table_header **out_table, u32 instance, struct acpi_table_header **out_table,
acpi_size *tbl_size) acpi_size *tbl_size)
{ {
u32 i; u32 i;
u32 j; u32 j;
acpi_status status; acpi_status status;
/* Parameter validation */ /* Parameter validation */
@ -346,7 +346,7 @@ acpi_get_table_with_size(char *signature,
} }
status = status =
acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]); acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
*out_table = acpi_gbl_root_table_list.tables[i].pointer; *out_table = acpi_gbl_root_table_list.tables[i].pointer;
*tbl_size = acpi_gbl_root_table_list.tables[i].length; *tbl_size = acpi_gbl_root_table_list.tables[i].length;
@ -390,7 +390,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table)
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table) acpi_get_table_by_index(u32 table_index, struct acpi_table_header ** table)
{ {
acpi_status status; acpi_status status;
@ -416,8 +416,8 @@ acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
/* Table is not mapped, map it */ /* Table is not mapped, map it */
status = status =
acpi_tb_verify_table(&acpi_gbl_root_table_list. acpi_tb_validate_table(&acpi_gbl_root_table_list.
tables[table_index]); tables[table_index]);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status); return_ACPI_STATUS(status);

View file

@ -117,7 +117,7 @@ static acpi_status acpi_tb_load_namespace(void)
tables[ACPI_TABLE_INDEX_DSDT].signature), tables[ACPI_TABLE_INDEX_DSDT].signature),
ACPI_SIG_DSDT) ACPI_SIG_DSDT)
|| ||
ACPI_FAILURE(acpi_tb_verify_table ACPI_FAILURE(acpi_tb_validate_table
(&acpi_gbl_root_table_list. (&acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT]))) { tables[ACPI_TABLE_INDEX_DSDT]))) {
status = AE_NO_ACPI_TABLES; status = AE_NO_ACPI_TABLES;
@ -128,7 +128,7 @@ static acpi_status acpi_tb_load_namespace(void)
* Save the DSDT pointer for simple access. This is the mapped memory * Save the DSDT pointer for simple access. This is the mapped memory
* address. We must take care here because the address of the .Tables * address. We must take care here because the address of the .Tables
* array can change dynamically as tables are loaded at run-time. Note: * array can change dynamically as tables are loaded at run-time. Note:
* .Pointer field is not validated until after call to acpi_tb_verify_table. * .Pointer field is not validated until after call to acpi_tb_validate_table.
*/ */
acpi_gbl_DSDT = acpi_gbl_DSDT =
acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer; acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer;
@ -174,24 +174,11 @@ static acpi_status acpi_tb_load_namespace(void)
(acpi_gbl_root_table_list.tables[i]. (acpi_gbl_root_table_list.tables[i].
signature), ACPI_SIG_PSDT)) signature), ACPI_SIG_PSDT))
|| ||
ACPI_FAILURE(acpi_tb_verify_table ACPI_FAILURE(acpi_tb_validate_table
(&acpi_gbl_root_table_list.tables[i]))) { (&acpi_gbl_root_table_list.tables[i]))) {
continue; continue;
} }
/*
* Optionally do not load any SSDTs from the RSDT/XSDT. This can
* be useful for debugging ACPI problems on some machines.
*/
if (acpi_gbl_disable_ssdt_table_load) {
ACPI_INFO((AE_INFO, "Ignoring %4.4s at %p",
acpi_gbl_root_table_list.tables[i].signature.
ascii, ACPI_CAST_PTR(void,
acpi_gbl_root_table_list.
tables[i].address)));
continue;
}
/* Ignore errors while loading tables, get as many as possible */ /* Ignore errors while loading tables, get as many as possible */
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
@ -206,6 +193,45 @@ unlock_and_exit:
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
/*******************************************************************************
*
* FUNCTION: acpi_install_table
*
* PARAMETERS: address - Address of the ACPI table to be installed.
* physical - Whether the address is a physical table
* address or not
*
* RETURN: Status
*
* DESCRIPTION: Dynamically install an ACPI table.
* Note: This function should only be invoked after
* acpi_initialize_tables() and before acpi_load_tables().
*
******************************************************************************/
acpi_status __init
acpi_install_table(acpi_physical_address address, u8 physical)
{
acpi_status status;
u8 flags;
u32 table_index;
ACPI_FUNCTION_TRACE(acpi_install_table);
if (physical) {
flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL;
} else {
flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL;
}
status = acpi_tb_install_standard_table(address, flags,
FALSE, FALSE, &table_index);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL_INIT(acpi_install_table)
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_load_table * FUNCTION: acpi_load_table
@ -222,11 +248,9 @@ unlock_and_exit:
* to ensure that the table is not deleted or unmapped. * to ensure that the table is not deleted or unmapped.
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_load_table(struct acpi_table_header *table) acpi_status acpi_load_table(struct acpi_table_header *table)
{ {
acpi_status status; acpi_status status;
struct acpi_table_desc table_desc;
u32 table_index; u32 table_index;
ACPI_FUNCTION_TRACE(acpi_load_table); ACPI_FUNCTION_TRACE(acpi_load_table);
@ -237,14 +261,6 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
return_ACPI_STATUS(AE_BAD_PARAMETER); return_ACPI_STATUS(AE_BAD_PARAMETER);
} }
/* Init local table descriptor */
ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
table_desc.address = ACPI_PTR_TO_PHYSADDR(table);
table_desc.pointer = table;
table_desc.length = table->length;
table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
/* Must acquire the interpreter lock during this operation */ /* Must acquire the interpreter lock during this operation */
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER); status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
@ -255,7 +271,24 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
/* Install the table and load it into the namespace */ /* Install the table and load it into the namespace */
ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:")); ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:"));
status = acpi_tb_add_table(&table_desc, &table_index); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
TRUE, FALSE, &table_index);
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
/*
* Note: Now table is "INSTALLED", it must be validated before
* using.
*/
status =
acpi_tb_validate_table(&acpi_gbl_root_table_list.
tables[table_index]);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
goto unlock_and_exit; goto unlock_and_exit;
} }

View file

@ -462,7 +462,7 @@ char *acpi_ut_get_mutex_name(u32 mutex_id)
/* Names for Notify() values, used for debug output */ /* Names for Notify() values, used for debug output */
static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = { static const char *acpi_gbl_generic_notify[ACPI_NOTIFY_MAX + 1] = {
/* 00 */ "Bus Check", /* 00 */ "Bus Check",
/* 01 */ "Device Check", /* 01 */ "Device Check",
/* 02 */ "Device Wake", /* 02 */ "Device Wake",
@ -473,23 +473,75 @@ static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = {
/* 07 */ "Power Fault", /* 07 */ "Power Fault",
/* 08 */ "Capabilities Check", /* 08 */ "Capabilities Check",
/* 09 */ "Device PLD Check", /* 09 */ "Device PLD Check",
/* 10 */ "Reserved", /* 0A */ "Reserved",
/* 11 */ "System Locality Update", /* 0B */ "System Locality Update",
/* 12 */ "Shutdown Request" /* 0C */ "Shutdown Request"
}; };
const char *acpi_ut_get_notify_name(u32 notify_value) static const char *acpi_gbl_device_notify[4] = {
/* 80 */ "Status Change",
/* 81 */ "Information Change",
/* 82 */ "Device-Specific Change",
/* 83 */ "Device-Specific Change"
};
static const char *acpi_gbl_processor_notify[4] = {
/* 80 */ "Performance Capability Change",
/* 81 */ "C-State Change",
/* 82 */ "Throttling Capability Change",
/* 83 */ "Device-Specific Change"
};
static const char *acpi_gbl_thermal_notify[4] = {
/* 80 */ "Thermal Status Change",
/* 81 */ "Thermal Trip Point Change",
/* 82 */ "Thermal Device List Change",
/* 83 */ "Thermal Relationship Change"
};
const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type)
{ {
/* 00 - 0C are common to all object types */
if (notify_value <= ACPI_NOTIFY_MAX) { if (notify_value <= ACPI_NOTIFY_MAX) {
return (acpi_gbl_notify_value_names[notify_value]); return (acpi_gbl_generic_notify[notify_value]);
} else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
return ("Reserved");
} else if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) {
return ("Device Specific");
} else {
return ("Hardware Specific");
} }
/* 0D - 7F are reserved */
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
return ("Reserved");
}
/* 80 - 83 are per-object-type */
if (notify_value <= 0x83) {
switch (type) {
case ACPI_TYPE_ANY:
case ACPI_TYPE_DEVICE:
return (acpi_gbl_device_notify[notify_value - 0x80]);
case ACPI_TYPE_PROCESSOR:
return (acpi_gbl_processor_notify[notify_value - 0x80]);
case ACPI_TYPE_THERMAL:
return (acpi_gbl_thermal_notify[notify_value - 0x80]);
default:
return ("Target object type does not support notifies");
}
}
/* 84 - BF are device-specific */
if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) {
return ("Device-Specific");
}
/* C0 and above are hardware-specific */
return ("Hardware-Specific");
} }
#endif #endif

View file

@ -55,28 +55,7 @@ ACPI_MODULE_NAME("utglobal")
* Static global variable initialization. * Static global variable initialization.
* *
******************************************************************************/ ******************************************************************************/
/* Debug output control masks */
u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
u32 acpi_dbg_layer = 0;
/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
struct acpi_table_fadt acpi_gbl_FADT;
u32 acpi_gbl_trace_flags;
acpi_name acpi_gbl_trace_method_name;
u8 acpi_gbl_system_awake_and_running;
u32 acpi_current_gpe_count;
/*
* ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
* that the ACPI hardware is no longer required. A flag in the FADT indicates
* a reduced HW machine, and that flag is duplicated here for convenience.
*/
u8 acpi_gbl_reduced_hardware;
/* Various state name strings */ /* Various state name strings */
const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = { const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S0_", "\\_S0_",
"\\_S1_", "\\_S1_",
@ -337,7 +316,6 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_acpi_hardware_present = TRUE; acpi_gbl_acpi_hardware_present = TRUE;
acpi_gbl_last_owner_id_index = 0; acpi_gbl_last_owner_id_index = 0;
acpi_gbl_next_owner_id_offset = 0; acpi_gbl_next_owner_id_offset = 0;
acpi_gbl_trace_method_name = 0;
acpi_gbl_trace_dbg_level = 0; acpi_gbl_trace_dbg_level = 0;
acpi_gbl_trace_dbg_layer = 0; acpi_gbl_trace_dbg_layer = 0;
acpi_gbl_debugger_configuration = DEBUGGER_THREADING; acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
@ -377,9 +355,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_disable_mem_tracking = FALSE; acpi_gbl_disable_mem_tracking = FALSE;
#endif #endif
#ifdef ACPI_DEBUGGER ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE);
acpi_gbl_db_terminate_threads = FALSE;
#endif
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
} }

View file

@ -353,7 +353,7 @@ void acpi_ut_print_string(char *string, u16 max_length)
} }
acpi_os_printf("\""); acpi_os_printf("\"");
for (i = 0; string[i] && (i < max_length); i++) { for (i = 0; (i < max_length) && string[i]; i++) {
/* Escape sequences */ /* Escape sequences */

View file

@ -53,6 +53,7 @@ ACPI_MODULE_NAME("utxferror")
* This module is used for the in-kernel ACPICA as well as the ACPICA * This module is used for the in-kernel ACPICA as well as the ACPICA
* tools/applications. * tools/applications.
*/ */
#ifndef ACPI_NO_ERROR_MESSAGES /* Entire module */
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_error * FUNCTION: acpi_error
@ -249,3 +250,4 @@ acpi_bios_warning(const char *module_name,
} }
ACPI_EXPORT_SYMBOL(acpi_bios_warning) ACPI_EXPORT_SYMBOL(acpi_bios_warning)
#endif /* ACPI_NO_ERROR_MESSAGES */

View file

@ -202,7 +202,7 @@ static void check_vendor_extension(u64 paddr,
if (!offset) if (!offset)
return; return;
v = acpi_os_map_memory(paddr + offset, sizeof(*v)); v = acpi_os_map_iomem(paddr + offset, sizeof(*v));
if (!v) if (!v)
return; return;
sbdf = v->pcie_sbdf; sbdf = v->pcie_sbdf;
@ -210,7 +210,7 @@ static void check_vendor_extension(u64 paddr,
sbdf >> 24, (sbdf >> 16) & 0xff, sbdf >> 24, (sbdf >> 16) & 0xff,
(sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7, (sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7,
v->vendor_id, v->device_id, v->rev_id); v->vendor_id, v->device_id, v->rev_id);
acpi_os_unmap_memory(v, sizeof(*v)); acpi_os_unmap_iomem(v, sizeof(*v));
} }
static void *einj_get_parameter_address(void) static void *einj_get_parameter_address(void)
@ -236,7 +236,7 @@ static void *einj_get_parameter_address(void)
if (pa_v5) { if (pa_v5) {
struct set_error_type_with_address *v5param; struct set_error_type_with_address *v5param;
v5param = acpi_os_map_memory(pa_v5, sizeof(*v5param)); v5param = acpi_os_map_iomem(pa_v5, sizeof(*v5param));
if (v5param) { if (v5param) {
acpi5 = 1; acpi5 = 1;
check_vendor_extension(pa_v5, v5param); check_vendor_extension(pa_v5, v5param);
@ -246,11 +246,11 @@ static void *einj_get_parameter_address(void)
if (param_extension && pa_v4) { if (param_extension && pa_v4) {
struct einj_parameter *v4param; struct einj_parameter *v4param;
v4param = acpi_os_map_memory(pa_v4, sizeof(*v4param)); v4param = acpi_os_map_iomem(pa_v4, sizeof(*v4param));
if (!v4param) if (!v4param)
return NULL; return NULL;
if (v4param->reserved1 || v4param->reserved2) { if (v4param->reserved1 || v4param->reserved2) {
acpi_os_unmap_memory(v4param, sizeof(*v4param)); acpi_os_unmap_iomem(v4param, sizeof(*v4param));
return NULL; return NULL;
} }
return v4param; return v4param;
@ -794,7 +794,7 @@ err_unmap:
sizeof(struct set_error_type_with_address) : sizeof(struct set_error_type_with_address) :
sizeof(struct einj_parameter); sizeof(struct einj_parameter);
acpi_os_unmap_memory(einj_param, size); acpi_os_unmap_iomem(einj_param, size);
} }
apei_exec_post_unmap_gars(&ctx); apei_exec_post_unmap_gars(&ctx);
err_release: err_release:
@ -816,7 +816,7 @@ static void __exit einj_exit(void)
sizeof(struct set_error_type_with_address) : sizeof(struct set_error_type_with_address) :
sizeof(struct einj_parameter); sizeof(struct einj_parameter);
acpi_os_unmap_memory(einj_param, size); acpi_os_unmap_iomem(einj_param, size);
} }
einj_exec_ctx_init(&ctx); einj_exec_ctx_init(&ctx);
apei_exec_post_unmap_gars(&ctx); apei_exec_post_unmap_gars(&ctx);

View file

@ -56,6 +56,10 @@
/* Battery power unit: 0 means mW, 1 means mA */ /* Battery power unit: 0 means mW, 1 means mA */
#define ACPI_BATTERY_POWER_UNIT_MA 1 #define ACPI_BATTERY_POWER_UNIT_MA 1
#define ACPI_BATTERY_STATE_DISCHARGING 0x1
#define ACPI_BATTERY_STATE_CHARGING 0x2
#define ACPI_BATTERY_STATE_CRITICAL 0x4
#define _COMPONENT ACPI_BATTERY_COMPONENT #define _COMPONENT ACPI_BATTERY_COMPONENT
ACPI_MODULE_NAME("battery"); ACPI_MODULE_NAME("battery");
@ -169,7 +173,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery);
static int acpi_battery_is_charged(struct acpi_battery *battery) static int acpi_battery_is_charged(struct acpi_battery *battery)
{ {
/* either charging or discharging */ /* charging, discharging or critical low */
if (battery->state != 0) if (battery->state != 0)
return 0; return 0;
@ -204,9 +208,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
return -ENODEV; return -ENODEV;
switch (psp) { switch (psp) {
case POWER_SUPPLY_PROP_STATUS: case POWER_SUPPLY_PROP_STATUS:
if (battery->state & 0x01) if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
val->intval = POWER_SUPPLY_STATUS_DISCHARGING; val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
else if (battery->state & 0x02) else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
val->intval = POWER_SUPPLY_STATUS_CHARGING; val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (acpi_battery_is_charged(battery)) else if (acpi_battery_is_charged(battery))
val->intval = POWER_SUPPLY_STATUS_FULL; val->intval = POWER_SUPPLY_STATUS_FULL;
@ -269,6 +273,17 @@ static int acpi_battery_get_property(struct power_supply *psy,
else else
val->intval = 0; val->intval = 0;
break; break;
case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
else if (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
(battery->capacity_now <= battery->alarm))
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
else if (acpi_battery_is_charged(battery))
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
else
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
break;
case POWER_SUPPLY_PROP_MODEL_NAME: case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = battery->model_number; val->strval = battery->model_number;
break; break;
@ -296,6 +311,7 @@ static enum power_supply_property charge_battery_props[] = {
POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER, POWER_SUPPLY_PROP_SERIAL_NUMBER,
@ -313,6 +329,7 @@ static enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_ENERGY_FULL, POWER_SUPPLY_PROP_ENERGY_FULL,
POWER_SUPPLY_PROP_ENERGY_NOW, POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER, POWER_SUPPLY_PROP_SERIAL_NUMBER,
@ -605,7 +622,8 @@ static int sysfs_add_battery(struct acpi_battery *battery)
battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
battery->bat.get_property = acpi_battery_get_property; battery->bat.get_property = acpi_battery_get_property;
result = power_supply_register(&battery->device->dev, &battery->bat); result = power_supply_register_no_ws(&battery->device->dev, &battery->bat);
if (result) if (result)
return result; return result;
return device_create_file(battery->bat.dev, &alarm_attr); return device_create_file(battery->bat.dev, &alarm_attr);
@ -696,7 +714,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
} }
} }
static int acpi_battery_update(struct acpi_battery *battery) static int acpi_battery_update(struct acpi_battery *battery, bool resume)
{ {
int result, old_present = acpi_battery_present(battery); int result, old_present = acpi_battery_present(battery);
result = acpi_battery_get_status(battery); result = acpi_battery_get_status(battery);
@ -707,6 +725,10 @@ static int acpi_battery_update(struct acpi_battery *battery)
battery->update_time = 0; battery->update_time = 0;
return 0; return 0;
} }
if (resume)
return 0;
if (!battery->update_time || if (!battery->update_time ||
old_present != acpi_battery_present(battery)) { old_present != acpi_battery_present(battery)) {
result = acpi_battery_get_info(battery); result = acpi_battery_get_info(battery);
@ -720,7 +742,19 @@ static int acpi_battery_update(struct acpi_battery *battery)
return result; return result;
} }
result = acpi_battery_get_state(battery); result = acpi_battery_get_state(battery);
if (result)
return result;
acpi_battery_quirks(battery); acpi_battery_quirks(battery);
/*
* Wakeup the system if battery is critical low
* or lower than the alarm level
*/
if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
(test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
(battery->capacity_now <= battery->alarm)))
pm_wakeup_event(&battery->device->dev, 0);
return result; return result;
} }
@ -915,7 +949,7 @@ static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = {
static int acpi_battery_read(int fid, struct seq_file *seq) static int acpi_battery_read(int fid, struct seq_file *seq)
{ {
struct acpi_battery *battery = seq->private; struct acpi_battery *battery = seq->private;
int result = acpi_battery_update(battery); int result = acpi_battery_update(battery, false);
return acpi_print_funcs[fid](seq, result); return acpi_print_funcs[fid](seq, result);
} }
@ -1030,7 +1064,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
old = battery->bat.dev; old = battery->bat.dev;
if (event == ACPI_BATTERY_NOTIFY_INFO) if (event == ACPI_BATTERY_NOTIFY_INFO)
acpi_battery_refresh(battery); acpi_battery_refresh(battery);
acpi_battery_update(battery); acpi_battery_update(battery, false);
acpi_bus_generate_netlink_event(device->pnp.device_class, acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, dev_name(&device->dev), event,
acpi_battery_present(battery)); acpi_battery_present(battery));
@ -1045,13 +1079,27 @@ static int battery_notify(struct notifier_block *nb,
{ {
struct acpi_battery *battery = container_of(nb, struct acpi_battery, struct acpi_battery *battery = container_of(nb, struct acpi_battery,
pm_nb); pm_nb);
int result;
switch (mode) { switch (mode) {
case PM_POST_HIBERNATION: case PM_POST_HIBERNATION:
case PM_POST_SUSPEND: case PM_POST_SUSPEND:
if (battery->bat.dev) { if (!acpi_battery_present(battery))
sysfs_remove_battery(battery); return 0;
sysfs_add_battery(battery);
} if (!battery->bat.dev) {
result = acpi_battery_get_info(battery);
if (result)
return result;
result = sysfs_add_battery(battery);
if (result)
return result;
} else
acpi_battery_refresh(battery);
acpi_battery_init_alarm(battery);
acpi_battery_get_state(battery);
break; break;
} }
@ -1087,7 +1135,7 @@ static int acpi_battery_add(struct acpi_device *device)
mutex_init(&battery->sysfs_lock); mutex_init(&battery->sysfs_lock);
if (acpi_has_method(battery->device->handle, "_BIX")) if (acpi_has_method(battery->device->handle, "_BIX"))
set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
result = acpi_battery_update(battery); result = acpi_battery_update(battery, false);
if (result) if (result)
goto fail; goto fail;
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER
@ -1107,6 +1155,8 @@ static int acpi_battery_add(struct acpi_device *device)
battery->pm_nb.notifier_call = battery_notify; battery->pm_nb.notifier_call = battery_notify;
register_pm_notifier(&battery->pm_nb); register_pm_notifier(&battery->pm_nb);
device_init_wakeup(&device->dev, 1);
return result; return result;
fail: fail:
@ -1123,6 +1173,7 @@ static int acpi_battery_remove(struct acpi_device *device)
if (!device || !acpi_driver_data(device)) if (!device || !acpi_driver_data(device))
return -EINVAL; return -EINVAL;
device_init_wakeup(&device->dev, 0);
battery = acpi_driver_data(device); battery = acpi_driver_data(device);
unregister_pm_notifier(&battery->pm_nb); unregister_pm_notifier(&battery->pm_nb);
#ifdef CONFIG_ACPI_PROCFS_POWER #ifdef CONFIG_ACPI_PROCFS_POWER
@ -1149,7 +1200,7 @@ static int acpi_battery_resume(struct device *dev)
return -EINVAL; return -EINVAL;
battery->update_time = 0; battery->update_time = 0;
acpi_battery_update(battery); acpi_battery_update(battery, true);
return 0; return 0;
} }
#else #else

View file

@ -52,6 +52,12 @@ struct proc_dir_entry *acpi_root_dir;
EXPORT_SYMBOL(acpi_root_dir); EXPORT_SYMBOL(acpi_root_dir);
#ifdef CONFIG_X86 #ifdef CONFIG_X86
#ifdef CONFIG_ACPI_CUSTOM_DSDT
static inline int set_copy_dsdt(const struct dmi_system_id *id)
{
return 0;
}
#else
static int set_copy_dsdt(const struct dmi_system_id *id) static int set_copy_dsdt(const struct dmi_system_id *id)
{ {
printk(KERN_NOTICE "%s detected - " printk(KERN_NOTICE "%s detected - "
@ -59,6 +65,7 @@ static int set_copy_dsdt(const struct dmi_system_id *id)
acpi_gbl_copy_dsdt_locally = 1; acpi_gbl_copy_dsdt_locally = 1;
return 0; return 0;
} }
#endif
static struct dmi_system_id dsdt_dmi_table[] __initdata = { static struct dmi_system_id dsdt_dmi_table[] __initdata = {
/* /*
@ -132,6 +139,21 @@ void acpi_bus_private_data_handler(acpi_handle handle,
} }
EXPORT_SYMBOL(acpi_bus_private_data_handler); EXPORT_SYMBOL(acpi_bus_private_data_handler);
int acpi_bus_attach_private_data(acpi_handle handle, void *data)
{
acpi_status status;
status = acpi_attach_data(handle,
acpi_bus_private_data_handler, data);
if (ACPI_FAILURE(status)) {
acpi_handle_debug(handle, "Error attaching device data\n");
return -ENODEV;
}
return 0;
}
EXPORT_SYMBOL_GPL(acpi_bus_attach_private_data);
int acpi_bus_get_private_data(acpi_handle handle, void **data) int acpi_bus_get_private_data(acpi_handle handle, void **data)
{ {
acpi_status status; acpi_status status;
@ -140,15 +162,20 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data)
return -EINVAL; return -EINVAL;
status = acpi_get_data(handle, acpi_bus_private_data_handler, data); status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
if (ACPI_FAILURE(status) || !*data) { if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", acpi_handle_debug(handle, "No context for object\n");
handle));
return -ENODEV; return -ENODEV;
} }
return 0; return 0;
} }
EXPORT_SYMBOL(acpi_bus_get_private_data); EXPORT_SYMBOL_GPL(acpi_bus_get_private_data);
void acpi_bus_detach_private_data(acpi_handle handle)
{
acpi_detach_data(handle, acpi_bus_private_data_handler);
}
EXPORT_SYMBOL_GPL(acpi_bus_detach_private_data);
void acpi_bus_no_hotplug(acpi_handle handle) void acpi_bus_no_hotplug(acpi_handle handle)
{ {
@ -340,16 +367,18 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{ {
struct acpi_device *adev; struct acpi_device *adev;
struct acpi_driver *driver; struct acpi_driver *driver;
acpi_status status;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
bool hotplug_event = false;
switch (type) { switch (type) {
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n"); acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
hotplug_event = true;
break; break;
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n"); acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
hotplug_event = true;
break; break;
case ACPI_NOTIFY_DEVICE_WAKE: case ACPI_NOTIFY_DEVICE_WAKE:
@ -358,6 +387,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n"); acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
hotplug_event = true;
break; break;
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT: case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
@ -393,16 +423,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS)) (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
driver->ops.notify(adev, type); driver->ops.notify(adev, type);
switch (type) { if (hotplug_event && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type)))
case ACPI_NOTIFY_BUS_CHECK: return;
case ACPI_NOTIFY_DEVICE_CHECK:
case ACPI_NOTIFY_EJECT_REQUEST:
status = acpi_hotplug_schedule(adev, type);
if (ACPI_SUCCESS(status))
return;
default:
break;
}
acpi_bus_put_acpi_device(adev); acpi_bus_put_acpi_device(adev);
return; return;
@ -466,6 +489,9 @@ void __init acpi_early_init(void)
printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION); printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);
/* It's safe to verify table checksums during late stage */
acpi_gbl_verify_table_checksum = TRUE;
/* enable workarounds, unless strict ACPI spec. compliance */ /* enable workarounds, unless strict ACPI spec. compliance */
if (!acpi_strict) if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE; acpi_gbl_enable_interpreter_slack = TRUE;

View file

@ -41,6 +41,8 @@ static const struct acpi_device_id container_device_ids[] = {
{"", 0}, {"", 0},
}; };
#ifdef CONFIG_ACPI_CONTAINER
static int acpi_container_offline(struct container_dev *cdev) static int acpi_container_offline(struct container_dev *cdev)
{ {
struct acpi_device *adev = ACPI_COMPANION(&cdev->dev); struct acpi_device *adev = ACPI_COMPANION(&cdev->dev);
@ -107,7 +109,20 @@ static struct acpi_scan_handler container_handler = {
}, },
}; };
void __init acpi_container_init(void)
{
acpi_scan_add_handler(&container_handler);
}
#else
static struct acpi_scan_handler container_handler = {
.ids = container_device_ids,
};
void __init acpi_container_init(void) void __init acpi_container_init(void)
{ {
acpi_scan_add_handler_with_hotplug(&container_handler, "container"); acpi_scan_add_handler_with_hotplug(&container_handler, "container");
} }
#endif /* CONFIG_ACPI_CONTAINER */

View file

@ -900,17 +900,46 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
*/ */
int acpi_subsys_prepare(struct device *dev) int acpi_subsys_prepare(struct device *dev)
{ {
/* struct acpi_device *adev = ACPI_COMPANION(dev);
* Devices having power.ignore_children set may still be necessary for u32 sys_target;
* suspending their children in the next phase of device suspend. int ret, state;
*/
if (dev->power.ignore_children)
pm_runtime_resume(dev);
return pm_generic_prepare(dev); ret = pm_generic_prepare(dev);
if (ret < 0)
return ret;
if (!adev || !pm_runtime_suspended(dev)
|| device_may_wakeup(dev) != !!adev->wakeup.prepare_count)
return 0;
sys_target = acpi_target_system_state();
if (sys_target == ACPI_STATE_S0)
return 1;
if (adev->power.flags.dsw_present)
return 0;
ret = acpi_dev_pm_get_state(dev, adev, sys_target, NULL, &state);
return !ret && state == adev->power.state;
} }
EXPORT_SYMBOL_GPL(acpi_subsys_prepare); EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
/**
* acpi_subsys_complete - Finalize device's resume during system resume.
* @dev: Device to handle.
*/
void acpi_subsys_complete(struct device *dev)
{
/*
* If the device had been runtime-suspended before the system went into
* the sleep state it is going out of and it has never been resumed till
* now, resume it in case the firmware powered it up.
*/
if (dev->power.direct_complete)
pm_request_resume(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_complete);
/** /**
* acpi_subsys_suspend - Run the device driver's suspend callback. * acpi_subsys_suspend - Run the device driver's suspend callback.
* @dev: Device to handle. * @dev: Device to handle.
@ -923,6 +952,7 @@ int acpi_subsys_suspend(struct device *dev)
pm_runtime_resume(dev); pm_runtime_resume(dev);
return pm_generic_suspend(dev); return pm_generic_suspend(dev);
} }
EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
/** /**
* acpi_subsys_suspend_late - Suspend device using ACPI. * acpi_subsys_suspend_late - Suspend device using ACPI.
@ -968,6 +998,7 @@ int acpi_subsys_freeze(struct device *dev)
pm_runtime_resume(dev); pm_runtime_resume(dev);
return pm_generic_freeze(dev); return pm_generic_freeze(dev);
} }
EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
@ -979,6 +1010,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
#endif #endif
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare, .prepare = acpi_subsys_prepare,
.complete = acpi_subsys_complete,
.suspend = acpi_subsys_suspend, .suspend = acpi_subsys_suspend,
.suspend_late = acpi_subsys_suspend_late, .suspend_late = acpi_subsys_suspend_late,
.resume_early = acpi_subsys_resume_early, .resume_early = acpi_subsys_resume_early,

View file

@ -30,12 +30,10 @@ void acpi_pci_root_init(void);
void acpi_pci_link_init(void); void acpi_pci_link_init(void);
void acpi_processor_init(void); void acpi_processor_init(void);
void acpi_platform_init(void); void acpi_platform_init(void);
void acpi_pnp_init(void);
int acpi_sysfs_init(void); int acpi_sysfs_init(void);
#ifdef CONFIG_ACPI_CONTAINER
void acpi_container_init(void); void acpi_container_init(void);
#else void acpi_memory_hotplug_init(void);
static inline void acpi_container_init(void) {}
#endif
#ifdef CONFIG_ACPI_DOCK #ifdef CONFIG_ACPI_DOCK
void register_dock_dependent_device(struct acpi_device *adev, void register_dock_dependent_device(struct acpi_device *adev,
acpi_handle dshandle); acpi_handle dshandle);
@ -47,11 +45,6 @@ static inline void register_dock_dependent_device(struct acpi_device *adev,
static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; } static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; }
static inline void acpi_dock_add(struct acpi_device *adev) {} static inline void acpi_dock_add(struct acpi_device *adev) {}
#endif #endif
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
void acpi_memory_hotplug_init(void);
#else
static inline void acpi_memory_hotplug_init(void) {}
#endif
#ifdef CONFIG_X86 #ifdef CONFIG_X86
void acpi_cmos_rtc_init(void); void acpi_cmos_rtc_init(void);
#else #else
@ -72,11 +65,7 @@ int acpi_debugfs_init(void);
#else #else
static inline void acpi_debugfs_init(void) { return; } static inline void acpi_debugfs_init(void) { return; }
#endif #endif
#ifdef CONFIG_X86_INTEL_LPSS
void acpi_lpss_init(void); void acpi_lpss_init(void);
#else
static inline void acpi_lpss_init(void) {}
#endif
acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src); acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src);
bool acpi_queue_hotplug_work(struct work_struct *work); bool acpi_queue_hotplug_work(struct work_struct *work);
@ -180,8 +169,7 @@ static inline void suspend_nvs_restore(void) {}
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
struct platform_device; struct platform_device;
int acpi_create_platform_device(struct acpi_device *adev, struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
const struct acpi_device_id *id);
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
Video Video

View file

@ -139,8 +139,8 @@ void suspend_nvs_free(void)
iounmap(entry->kaddr); iounmap(entry->kaddr);
entry->unmap = false; entry->unmap = false;
} else { } else {
acpi_os_unmap_memory(entry->kaddr, acpi_os_unmap_iomem(entry->kaddr,
entry->size); entry->size);
} }
entry->kaddr = NULL; entry->kaddr = NULL;
} }

View file

@ -355,7 +355,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
} }
void __iomem *__init_refok void __iomem *__init_refok
acpi_os_map_memory(acpi_physical_address phys, acpi_size size) acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
{ {
struct acpi_ioremap *map; struct acpi_ioremap *map;
void __iomem *virt; void __iomem *virt;
@ -401,10 +401,17 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
list_add_tail_rcu(&map->list, &acpi_ioremaps); list_add_tail_rcu(&map->list, &acpi_ioremaps);
out: out:
mutex_unlock(&acpi_ioremap_lock); mutex_unlock(&acpi_ioremap_lock);
return map->virt + (phys - map->phys); return map->virt + (phys - map->phys);
} }
EXPORT_SYMBOL_GPL(acpi_os_map_iomem);
void *__init_refok
acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
return (void *)acpi_os_map_iomem(phys, size);
}
EXPORT_SYMBOL_GPL(acpi_os_map_memory); EXPORT_SYMBOL_GPL(acpi_os_map_memory);
static void acpi_os_drop_map_ref(struct acpi_ioremap *map) static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
@ -422,7 +429,7 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map)
} }
} }
void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
{ {
struct acpi_ioremap *map; struct acpi_ioremap *map;
@ -443,6 +450,12 @@ void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
acpi_os_map_cleanup(map); acpi_os_map_cleanup(map);
} }
EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem);
void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
{
return acpi_os_unmap_iomem((void __iomem *)virt, size);
}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
@ -464,7 +477,7 @@ int acpi_os_map_generic_address(struct acpi_generic_address *gas)
if (!addr || !gas->bit_width) if (!addr || !gas->bit_width)
return -EINVAL; return -EINVAL;
virt = acpi_os_map_memory(addr, gas->bit_width / 8); virt = acpi_os_map_iomem(addr, gas->bit_width / 8);
if (!virt) if (!virt)
return -EIO; return -EIO;
@ -1770,16 +1783,15 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
} }
#endif #endif
static int __init acpi_no_auto_ssdt_setup(char *s) static int __init acpi_no_static_ssdt_setup(char *s)
{ {
printk(KERN_NOTICE PREFIX "SSDT auto-load disabled\n"); acpi_gbl_disable_ssdt_table_install = TRUE;
pr_info("ACPI: static SSDT installation disabled\n");
acpi_gbl_disable_ssdt_table_load = TRUE; return 0;
return 1;
} }
__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup); early_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup);
static int __init acpi_disable_return_repair(char *s) static int __init acpi_disable_return_repair(char *s)
{ {

View file

@ -121,6 +121,13 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
struct acpi_processor *pr = per_cpu(processors, cpu); struct acpi_processor *pr = per_cpu(processors, cpu);
struct acpi_device *device; struct acpi_device *device;
/*
* CPU_STARTING and CPU_DYING must not sleep. Return here since
* acpi_bus_get_device() may sleep.
*/
if (action == CPU_STARTING || action == CPU_DYING)
return NOTIFY_DONE;
if (!pr || acpi_bus_get_device(pr->handle, &device)) if (!pr || acpi_bus_get_device(pr->handle, &device))
return NOTIFY_DONE; return NOTIFY_DONE;

View file

@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(acpi_initialize_hp_context);
int acpi_scan_add_handler(struct acpi_scan_handler *handler) int acpi_scan_add_handler(struct acpi_scan_handler *handler)
{ {
if (!handler || !handler->attach) if (!handler)
return -EINVAL; return -EINVAL;
list_add_tail(&handler->list_node, &acpi_scan_handlers_list); list_add_tail(&handler->list_node, &acpi_scan_handlers_list);
@ -1551,9 +1551,13 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
*/ */
if (acpi_has_method(device->handle, "_PSC")) if (acpi_has_method(device->handle, "_PSC"))
device->power.flags.explicit_get = 1; device->power.flags.explicit_get = 1;
if (acpi_has_method(device->handle, "_IRC")) if (acpi_has_method(device->handle, "_IRC"))
device->power.flags.inrush_current = 1; device->power.flags.inrush_current = 1;
if (acpi_has_method(device->handle, "_DSW"))
device->power.flags.dsw_present = 1;
/* /*
* Enumerate supported power management states * Enumerate supported power management states
*/ */
@ -1793,8 +1797,10 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
return; return;
} }
if (info->valid & ACPI_VALID_HID) if (info->valid & ACPI_VALID_HID) {
acpi_add_id(pnp, info->hardware_id.string); acpi_add_id(pnp, info->hardware_id.string);
pnp->type.platform_id = 1;
}
if (info->valid & ACPI_VALID_CID) { if (info->valid & ACPI_VALID_CID) {
cid_list = &info->compatible_id_list; cid_list = &info->compatible_id_list;
for (i = 0; i < cid_list->count; i++) for (i = 0; i < cid_list->count; i++)
@ -1973,6 +1979,9 @@ static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
{ {
const struct acpi_device_id *devid; const struct acpi_device_id *devid;
if (handler->match)
return handler->match(idstr, matchid);
for (devid = handler->ids; devid->id[0]; devid++) for (devid = handler->ids; devid->id[0]; devid++)
if (!strcmp((char *)devid->id, idstr)) { if (!strcmp((char *)devid->id, idstr)) {
if (matchid) if (matchid)
@ -2061,6 +2070,44 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK; return AE_OK;
} }
static int acpi_check_spi_i2c_slave(struct acpi_resource *ares, void *data)
{
bool *is_spi_i2c_slave_p = data;
if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
return 1;
/*
* devices that are connected to UART still need to be enumerated to
* platform bus
*/
if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART)
*is_spi_i2c_slave_p = true;
/* no need to do more checking */
return -1;
}
static void acpi_default_enumeration(struct acpi_device *device)
{
struct list_head resource_list;
bool is_spi_i2c_slave = false;
if (!device->pnp.type.platform_id || device->handler)
return;
/*
* Do not enemerate SPI/I2C slaves as they will be enuerated by their
* respective parents.
*/
INIT_LIST_HEAD(&resource_list);
acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave,
&is_spi_i2c_slave);
acpi_dev_free_resource_list(&resource_list);
if (!is_spi_i2c_slave)
acpi_create_platform_device(device);
}
static int acpi_scan_attach_handler(struct acpi_device *device) static int acpi_scan_attach_handler(struct acpi_device *device)
{ {
struct acpi_hardware_id *hwid; struct acpi_hardware_id *hwid;
@ -2072,6 +2119,10 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
handler = acpi_scan_match_handler(hwid->id, &devid); handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) { if (handler) {
if (!handler->attach) {
device->pnp.type.platform_id = 0;
continue;
}
device->handler = handler; device->handler = handler;
ret = handler->attach(device, devid); ret = handler->attach(device, devid);
if (ret > 0) if (ret > 0)
@ -2082,6 +2133,9 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
break; break;
} }
} }
if (!ret)
acpi_default_enumeration(device);
return ret; return ret;
} }
@ -2241,11 +2295,11 @@ int __init acpi_scan_init(void)
acpi_pci_root_init(); acpi_pci_root_init();
acpi_pci_link_init(); acpi_pci_link_init();
acpi_processor_init(); acpi_processor_init();
acpi_platform_init();
acpi_lpss_init(); acpi_lpss_init();
acpi_cmos_rtc_init(); acpi_cmos_rtc_init();
acpi_container_init(); acpi_container_init();
acpi_memory_hotplug_init(); acpi_memory_hotplug_init();
acpi_pnp_init();
mutex_lock(&acpi_scan_lock); mutex_lock(&acpi_scan_lock);
/* /*
@ -2259,12 +2313,16 @@ int __init acpi_scan_init(void)
if (result) if (result)
goto out; goto out;
result = acpi_bus_scan_fixed(); /* Fixed feature devices do not exist on HW-reduced platform */
if (result) { if (!acpi_gbl_reduced_hardware) {
acpi_detach_data(acpi_root->handle, acpi_scan_drop_device); result = acpi_bus_scan_fixed();
acpi_device_del(acpi_root); if (result) {
put_device(&acpi_root->dev); acpi_detach_data(acpi_root->handle,
goto out; acpi_scan_drop_device);
acpi_device_del(acpi_root);
put_device(&acpi_root->dev);
goto out;
}
} }
acpi_update_all_gpes(); acpi_update_all_gpes();

View file

@ -89,6 +89,7 @@ u32 acpi_target_system_state(void)
{ {
return acpi_target_sleep_state; return acpi_target_sleep_state;
} }
EXPORT_SYMBOL_GPL(acpi_target_system_state);
static bool pwr_btn_event_pending; static bool pwr_btn_event_pending;
@ -611,6 +612,22 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
.recover = acpi_pm_finish, .recover = acpi_pm_finish,
}; };
static int acpi_freeze_begin(void)
{
acpi_scan_lock_acquire();
return 0;
}
static void acpi_freeze_end(void)
{
acpi_scan_lock_release();
}
static const struct platform_freeze_ops acpi_freeze_ops = {
.begin = acpi_freeze_begin,
.end = acpi_freeze_end,
};
static void acpi_sleep_suspend_setup(void) static void acpi_sleep_suspend_setup(void)
{ {
int i; int i;
@ -621,7 +638,9 @@ static void acpi_sleep_suspend_setup(void)
suspend_set_ops(old_suspend_ordering ? suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops); &acpi_suspend_ops_old : &acpi_suspend_ops);
freeze_set_ops(&acpi_freeze_ops);
} }
#else /* !CONFIG_SUSPEND */ #else /* !CONFIG_SUSPEND */
static inline void acpi_sleep_suspend_setup(void) {} static inline void acpi_sleep_suspend_setup(void) {}
#endif /* !CONFIG_SUSPEND */ #endif /* !CONFIG_SUSPEND */

View file

@ -44,6 +44,12 @@ static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
static int acpi_apic_instance __initdata; static int acpi_apic_instance __initdata;
/*
* Disable table checksum verification for the early stage due to the size
* limitation of the current x86 early mapping implementation.
*/
static bool acpi_verify_table_checksum __initdata = false;
void acpi_table_print_madt_entry(struct acpi_subtable_header *header) void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{ {
if (!header) if (!header)
@ -333,6 +339,14 @@ int __init acpi_table_init(void)
{ {
acpi_status status; acpi_status status;
if (acpi_verify_table_checksum) {
pr_info("Early table checksum verification enabled\n");
acpi_gbl_verify_table_checksum = TRUE;
} else {
pr_info("Early table checksum verification disabled\n");
acpi_gbl_verify_table_checksum = FALSE;
}
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0); status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return -EINVAL; return -EINVAL;
@ -354,3 +368,12 @@ static int __init acpi_parse_apic_instance(char *str)
} }
early_param("acpi_apic_instance", acpi_parse_apic_instance); early_param("acpi_apic_instance", acpi_parse_apic_instance);
static int __init acpi_force_table_verification_setup(char *s)
{
acpi_verify_table_checksum = true;
return 0;
}
early_param("acpi_force_table_verification", acpi_force_table_verification_setup);

View file

@ -925,13 +925,10 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
if (result) if (result)
return result; return result;
status = acpi_attach_data(tz->device->handle, status = acpi_bus_attach_private_data(tz->device->handle,
acpi_bus_private_data_handler, tz->thermal_zone);
tz->thermal_zone); if (ACPI_FAILURE(status))
if (ACPI_FAILURE(status)) {
pr_err(PREFIX "Error attaching device data\n");
return -ENODEV; return -ENODEV;
}
tz->tz_enabled = 1; tz->tz_enabled = 1;
@ -946,7 +943,7 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
sysfs_remove_link(&tz->thermal_zone->device.kobj, "device"); sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
thermal_zone_device_unregister(tz->thermal_zone); thermal_zone_device_unregister(tz->thermal_zone);
tz->thermal_zone = NULL; tz->thermal_zone = NULL;
acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler); acpi_bus_detach_private_data(tz->device->handle);
} }

View file

@ -30,6 +30,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/dynamic_debug.h>
#include "internal.h" #include "internal.h"
@ -456,6 +457,24 @@ acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
} }
EXPORT_SYMBOL(acpi_evaluate_ost); EXPORT_SYMBOL(acpi_evaluate_ost);
/**
* acpi_handle_path: Return the object path of handle
*
* Caller must free the returned buffer
*/
static char *acpi_handle_path(acpi_handle handle)
{
struct acpi_buffer buffer = {
.length = ACPI_ALLOCATE_BUFFER,
.pointer = NULL
};
if (in_interrupt() ||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK)
return NULL;
return buffer.pointer;
}
/** /**
* acpi_handle_printk: Print message with ACPI prefix and object path * acpi_handle_printk: Print message with ACPI prefix and object path
* *
@ -469,29 +488,50 @@ acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
{ {
struct va_format vaf; struct va_format vaf;
va_list args; va_list args;
struct acpi_buffer buffer = {
.length = ACPI_ALLOCATE_BUFFER,
.pointer = NULL
};
const char *path; const char *path;
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
if (in_interrupt() || path = acpi_handle_path(handle);
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK) printk("%sACPI: %s: %pV", level, path ? path : "<n/a>" , &vaf);
path = "<n/a>";
else
path = buffer.pointer;
printk("%sACPI: %s: %pV", level, path, &vaf);
va_end(args); va_end(args);
kfree(buffer.pointer); kfree(path);
} }
EXPORT_SYMBOL(acpi_handle_printk); EXPORT_SYMBOL(acpi_handle_printk);
#if defined(CONFIG_DYNAMIC_DEBUG)
/**
* __acpi_handle_debug: pr_debug with ACPI prefix and object path
*
* This function is called through acpi_handle_debug macro and debug
* prints a message with ACPI prefix and object path. This function
* acquires the global namespace mutex to obtain an object path. In
* interrupt context, it shows the object path as <n/a>.
*/
void
__acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle,
const char *fmt, ...)
{
struct va_format vaf;
va_list args;
const char *path;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
path = acpi_handle_path(handle);
__dynamic_pr_debug(descriptor, "ACPI: %s: %pV", path ? path : "<n/a>", &vaf);
va_end(args);
kfree(path);
}
EXPORT_SYMBOL(__acpi_handle_debug);
#endif
/** /**
* acpi_has_method: Check whether @handle has a method named @name * acpi_has_method: Check whether @handle has a method named @name
* @handle: ACPI device handle * @handle: ACPI device handle

View file

@ -68,7 +68,7 @@ MODULE_AUTHOR("Bruno Ducrot");
MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_DESCRIPTION("ACPI Video Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static bool brightness_switch_enabled = 1; static bool brightness_switch_enabled;
module_param(brightness_switch_enabled, bool, 0644); module_param(brightness_switch_enabled, bool, 0644);
/* /*
@ -150,6 +150,8 @@ struct acpi_video_enumerated_device {
struct acpi_video_bus { struct acpi_video_bus {
struct acpi_device *device; struct acpi_device *device;
bool backlight_registered;
bool backlight_notifier_registered;
u8 dos_setting; u8 dos_setting;
struct acpi_video_enumerated_device *attached_array; struct acpi_video_enumerated_device *attached_array;
u8 attached_count; u8 attached_count;
@ -161,6 +163,7 @@ struct acpi_video_bus {
struct input_dev *input; struct input_dev *input;
char phys[32]; /* for input device */ char phys[32]; /* for input device */
struct notifier_block pm_nb; struct notifier_block pm_nb;
struct notifier_block backlight_nb;
}; };
struct acpi_video_device_flags { struct acpi_video_device_flags {
@ -471,6 +474,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"), DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"),
}, },
}, },
{
.callback = video_set_use_native_backlight,
.ident = "ThinkPad W530",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"),
},
},
{ {
.callback = video_set_use_native_backlight, .callback = video_set_use_native_backlight,
.ident = "ThinkPad X1 Carbon", .ident = "ThinkPad X1 Carbon",
@ -487,6 +498,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"), DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
}, },
}, },
{
.callback = video_set_use_native_backlight,
.ident = "Lenovo Yoga 2 11",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"),
},
},
{ {
.callback = video_set_use_native_backlight, .callback = video_set_use_native_backlight,
.ident = "Thinkpad Helix", .ident = "Thinkpad Helix",
@ -519,6 +538,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5742G"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5742G"),
}, },
}, },
{
.callback = video_set_use_native_backlight,
.ident = "Acer Aspire V5-171",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "V5-171"),
},
},
{ {
.callback = video_set_use_native_backlight, .callback = video_set_use_native_backlight,
.ident = "Acer Aspire V5-431", .ident = "Acer Aspire V5-431",
@ -527,6 +554,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"), DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"),
}, },
}, },
{
.callback = video_set_use_native_backlight,
.ident = "Acer Aspire V5-471G",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-471G"),
},
},
{ {
.callback = video_set_use_native_backlight, .callback = video_set_use_native_backlight,
.ident = "HP ProBook 4340s", .ident = "HP ProBook 4340s",
@ -579,6 +614,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
}, },
{ {
.callback = video_set_use_native_backlight, .callback = video_set_use_native_backlight,
.ident = "HP EliteBook 8470p",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8470p"),
},
},
{
.callback = video_set_use_native_backlight,
.ident = "HP EliteBook 8780w", .ident = "HP EliteBook 8780w",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
@ -1658,88 +1701,92 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
static void acpi_video_dev_register_backlight(struct acpi_video_device *device) static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
{ {
if (acpi_video_verify_backlight_support()) { struct backlight_properties props;
struct backlight_properties props; struct pci_dev *pdev;
struct pci_dev *pdev; acpi_handle acpi_parent;
acpi_handle acpi_parent; struct device *parent = NULL;
struct device *parent = NULL; int result;
int result; static int count;
static int count; char *name;
char *name;
result = acpi_video_init_brightness(device); result = acpi_video_init_brightness(device);
if (result) if (result)
return; return;
name = kasprintf(GFP_KERNEL, "acpi_video%d", count); name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
if (!name) if (!name)
return; return;
count++; count++;
acpi_get_parent(device->dev->handle, &acpi_parent); acpi_get_parent(device->dev->handle, &acpi_parent);
pdev = acpi_get_pci_dev(acpi_parent); pdev = acpi_get_pci_dev(acpi_parent);
if (pdev) { if (pdev) {
parent = &pdev->dev; parent = &pdev->dev;
pci_dev_put(pdev); pci_dev_put(pdev);
}
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_FIRMWARE;
props.max_brightness = device->brightness->count - 3;
device->backlight = backlight_device_register(name,
parent,
device,
&acpi_backlight_ops,
&props);
kfree(name);
if (IS_ERR(device->backlight))
return;
/*
* Save current brightness level in case we have to restore it
* before acpi_video_device_lcd_set_level() is called next time.
*/
device->backlight->props.brightness =
acpi_video_get_brightness(device->backlight);
device->cooling_dev = thermal_cooling_device_register("LCD",
device->dev, &video_cooling_ops);
if (IS_ERR(device->cooling_dev)) {
/*
* Set cooling_dev to NULL so we don't crash trying to
* free it.
* Also, why the hell we are returning early and
* not attempt to register video output if cooling
* device registration failed?
* -- dtor
*/
device->cooling_dev = NULL;
return;
}
dev_info(&device->dev->dev, "registered as cooling_device%d\n",
device->cooling_dev->id);
result = sysfs_create_link(&device->dev->dev.kobj,
&device->cooling_dev->device.kobj,
"thermal_cooling");
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
result = sysfs_create_link(&device->cooling_dev->device.kobj,
&device->dev->dev.kobj, "device");
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
} }
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_FIRMWARE;
props.max_brightness = device->brightness->count - 3;
device->backlight = backlight_device_register(name,
parent,
device,
&acpi_backlight_ops,
&props);
kfree(name);
if (IS_ERR(device->backlight))
return;
/*
* Save current brightness level in case we have to restore it
* before acpi_video_device_lcd_set_level() is called next time.
*/
device->backlight->props.brightness =
acpi_video_get_brightness(device->backlight);
device->cooling_dev = thermal_cooling_device_register("LCD",
device->dev, &video_cooling_ops);
if (IS_ERR(device->cooling_dev)) {
/*
* Set cooling_dev to NULL so we don't crash trying to free it.
* Also, why the hell we are returning early and not attempt to
* register video output if cooling device registration failed?
* -- dtor
*/
device->cooling_dev = NULL;
return;
}
dev_info(&device->dev->dev, "registered as cooling_device%d\n",
device->cooling_dev->id);
result = sysfs_create_link(&device->dev->dev.kobj,
&device->cooling_dev->device.kobj,
"thermal_cooling");
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
result = sysfs_create_link(&device->cooling_dev->device.kobj,
&device->dev->dev.kobj, "device");
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
} }
static int acpi_video_bus_register_backlight(struct acpi_video_bus *video) static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
{ {
struct acpi_video_device *dev; struct acpi_video_device *dev;
if (video->backlight_registered)
return 0;
if (!acpi_video_verify_backlight_support())
return 0;
mutex_lock(&video->device_list_lock); mutex_lock(&video->device_list_lock);
list_for_each_entry(dev, &video->video_device_list, entry) list_for_each_entry(dev, &video->video_device_list, entry)
acpi_video_dev_register_backlight(dev); acpi_video_dev_register_backlight(dev);
mutex_unlock(&video->device_list_lock); mutex_unlock(&video->device_list_lock);
video->backlight_registered = true;
video->pm_nb.notifier_call = acpi_video_resume; video->pm_nb.notifier_call = acpi_video_resume;
video->pm_nb.priority = 0; video->pm_nb.priority = 0;
return register_pm_notifier(&video->pm_nb); return register_pm_notifier(&video->pm_nb);
@ -1767,13 +1814,20 @@ static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device
static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video) static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video)
{ {
struct acpi_video_device *dev; struct acpi_video_device *dev;
int error = unregister_pm_notifier(&video->pm_nb); int error;
if (!video->backlight_registered)
return 0;
error = unregister_pm_notifier(&video->pm_nb);
mutex_lock(&video->device_list_lock); mutex_lock(&video->device_list_lock);
list_for_each_entry(dev, &video->video_device_list, entry) list_for_each_entry(dev, &video->video_device_list, entry)
acpi_video_dev_unregister_backlight(dev); acpi_video_dev_unregister_backlight(dev);
mutex_unlock(&video->device_list_lock); mutex_unlock(&video->device_list_lock);
video->backlight_registered = false;
return error; return error;
} }
@ -1867,6 +1921,56 @@ static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video)
video->input = NULL; video->input = NULL;
} }
static int acpi_video_backlight_notify(struct notifier_block *nb,
unsigned long val, void *bd)
{
struct backlight_device *backlight = bd;
struct acpi_video_bus *video;
/* acpi_video_verify_backlight_support only cares about raw devices */
if (backlight->props.type != BACKLIGHT_RAW)
return NOTIFY_DONE;
video = container_of(nb, struct acpi_video_bus, backlight_nb);
switch (val) {
case BACKLIGHT_REGISTERED:
if (!acpi_video_verify_backlight_support())
acpi_video_bus_unregister_backlight(video);
break;
case BACKLIGHT_UNREGISTERED:
acpi_video_bus_register_backlight(video);
break;
}
return NOTIFY_OK;
}
static int acpi_video_bus_add_backlight_notify_handler(
struct acpi_video_bus *video)
{
int error;
video->backlight_nb.notifier_call = acpi_video_backlight_notify;
video->backlight_nb.priority = 0;
error = backlight_register_notifier(&video->backlight_nb);
if (error == 0)
video->backlight_notifier_registered = true;
return error;
}
static int acpi_video_bus_remove_backlight_notify_handler(
struct acpi_video_bus *video)
{
if (!video->backlight_notifier_registered)
return 0;
video->backlight_notifier_registered = false;
return backlight_unregister_notifier(&video->backlight_nb);
}
static int acpi_video_bus_put_devices(struct acpi_video_bus *video) static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
{ {
struct acpi_video_device *dev, *next; struct acpi_video_device *dev, *next;
@ -1948,6 +2052,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_video_bus_register_backlight(video); acpi_video_bus_register_backlight(video);
acpi_video_bus_add_notify_handler(video); acpi_video_bus_add_notify_handler(video);
acpi_video_bus_add_backlight_notify_handler(video);
return 0; return 0;
@ -1971,6 +2076,7 @@ static int acpi_video_bus_remove(struct acpi_device *device)
video = acpi_driver_data(device); video = acpi_driver_data(device);
acpi_video_bus_remove_backlight_notify_handler(video);
acpi_video_bus_remove_notify_handler(video); acpi_video_bus_remove_notify_handler(video);
acpi_video_bus_unregister_backlight(video); acpi_video_bus_unregister_backlight(video);
acpi_video_bus_put_devices(video); acpi_video_bus_put_devices(video);
@ -2061,6 +2167,20 @@ void acpi_video_unregister(void)
} }
EXPORT_SYMBOL(acpi_video_unregister); EXPORT_SYMBOL(acpi_video_unregister);
void acpi_video_unregister_backlight(void)
{
struct acpi_video_bus *video;
if (!register_count)
return;
mutex_lock(&video_list_lock);
list_for_each_entry(video, &video_bus_head, entry)
acpi_video_bus_unregister_backlight(video);
mutex_unlock(&video_list_lock);
}
EXPORT_SYMBOL(acpi_video_unregister_backlight);
/* /*
* This is kind of nasty. Hardware using Intel chipsets may require * This is kind of nasty. Hardware using Intel chipsets may require
* the video opregion code to be run first in order to initialise * the video opregion code to be run first in order to initialise

View file

@ -479,7 +479,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
TRACE_DEVICE(dev); TRACE_DEVICE(dev);
TRACE_RESUME(0); TRACE_RESUME(0);
if (dev->power.syscore) if (dev->power.syscore || dev->power.direct_complete)
goto Out; goto Out;
if (!dev->power.is_noirq_suspended) if (!dev->power.is_noirq_suspended)
@ -605,7 +605,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
TRACE_DEVICE(dev); TRACE_DEVICE(dev);
TRACE_RESUME(0); TRACE_RESUME(0);
if (dev->power.syscore) if (dev->power.syscore || dev->power.direct_complete)
goto Out; goto Out;
if (!dev->power.is_late_suspended) if (!dev->power.is_late_suspended)
@ -735,6 +735,12 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
if (dev->power.syscore) if (dev->power.syscore)
goto Complete; goto Complete;
if (dev->power.direct_complete) {
/* Match the pm_runtime_disable() in __device_suspend(). */
pm_runtime_enable(dev);
goto Complete;
}
dpm_wait(dev->parent, async); dpm_wait(dev->parent, async);
dpm_watchdog_set(&wd, dev); dpm_watchdog_set(&wd, dev);
device_lock(dev); device_lock(dev);
@ -1007,7 +1013,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
goto Complete; goto Complete;
} }
if (dev->power.syscore) if (dev->power.syscore || dev->power.direct_complete)
goto Complete; goto Complete;
dpm_wait_for_children(dev, async); dpm_wait_for_children(dev, async);
@ -1146,7 +1152,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
goto Complete; goto Complete;
} }
if (dev->power.syscore) if (dev->power.syscore || dev->power.direct_complete)
goto Complete; goto Complete;
dpm_wait_for_children(dev, async); dpm_wait_for_children(dev, async);
@ -1332,6 +1338,17 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (dev->power.syscore) if (dev->power.syscore)
goto Complete; goto Complete;
if (dev->power.direct_complete) {
if (pm_runtime_status_suspended(dev)) {
pm_runtime_disable(dev);
if (pm_runtime_suspended_if_enabled(dev))
goto Complete;
pm_runtime_enable(dev);
}
dev->power.direct_complete = false;
}
dpm_watchdog_set(&wd, dev); dpm_watchdog_set(&wd, dev);
device_lock(dev); device_lock(dev);
@ -1382,10 +1399,19 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
End: End:
if (!error) { if (!error) {
struct device *parent = dev->parent;
dev->power.is_suspended = true; dev->power.is_suspended = true;
if (dev->power.wakeup_path if (parent) {
&& dev->parent && !dev->parent->power.ignore_children) spin_lock_irq(&parent->power.lock);
dev->parent->power.wakeup_path = true;
dev->parent->power.direct_complete = false;
if (dev->power.wakeup_path
&& !dev->parent->power.ignore_children)
dev->parent->power.wakeup_path = true;
spin_unlock_irq(&parent->power.lock);
}
} }
device_unlock(dev); device_unlock(dev);
@ -1487,7 +1513,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
{ {
int (*callback)(struct device *) = NULL; int (*callback)(struct device *) = NULL;
char *info = NULL; char *info = NULL;
int error = 0; int ret = 0;
if (dev->power.syscore) if (dev->power.syscore)
return 0; return 0;
@ -1523,17 +1549,27 @@ static int device_prepare(struct device *dev, pm_message_t state)
callback = dev->driver->pm->prepare; callback = dev->driver->pm->prepare;
} }
if (callback) { if (callback)
error = callback(dev); ret = callback(dev);
suspend_report_result(callback, error);
}
device_unlock(dev); device_unlock(dev);
if (error) if (ret < 0) {
suspend_report_result(callback, ret);
pm_runtime_put(dev); pm_runtime_put(dev);
return ret;
return error; }
/*
* A positive return value from ->prepare() means "this device appears
* to be runtime-suspended and its state is fine, so if it really is
* runtime-suspended, you can leave it in that state provided that you
* will do the same thing with all of its descendants". This only
* applies to suspend transitions, however.
*/
spin_lock_irq(&dev->power.lock);
dev->power.direct_complete = ret > 0 && state.event == PM_EVENT_SUSPEND;
spin_unlock_irq(&dev->power.lock);
return 0;
} }
/** /**

View file

@ -15,7 +15,6 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpufreq.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/rculist.h> #include <linux/rculist.h>
@ -394,6 +393,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
* to keep the integrity of the internal data structures. Callers should ensure * to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where * that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked. * mutex cannot be locked.
*
* Return:
* 0: On success OR
* Duplicate OPPs (both freq and volt are same) and opp->available
* -EEXIST: Freq are same and volt are different OR
* Duplicate OPPs (both freq and volt are same) and !opp->available
* -ENOMEM: Memory allocation failure
*/ */
int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
{ {
@ -443,15 +449,31 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
new_opp->u_volt = u_volt; new_opp->u_volt = u_volt;
new_opp->available = true; new_opp->available = true;
/* Insert new OPP in order of increasing frequency */ /*
* Insert new OPP in order of increasing frequency
* and discard if already present
*/
head = &dev_opp->opp_list; head = &dev_opp->opp_list;
list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) { list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) {
if (new_opp->rate < opp->rate) if (new_opp->rate <= opp->rate)
break; break;
else else
head = &opp->node; head = &opp->node;
} }
/* Duplicate OPPs ? */
if (new_opp->rate == opp->rate) {
int ret = opp->available && new_opp->u_volt == opp->u_volt ?
0 : -EEXIST;
dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
__func__, opp->rate, opp->u_volt, opp->available,
new_opp->rate, new_opp->u_volt, new_opp->available);
mutex_unlock(&dev_opp_list_lock);
kfree(new_opp);
return ret;
}
list_add_rcu(&new_opp->node, head); list_add_rcu(&new_opp->node, head);
mutex_unlock(&dev_opp_list_lock); mutex_unlock(&dev_opp_list_lock);
@ -596,96 +618,6 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq)
} }
EXPORT_SYMBOL_GPL(dev_pm_opp_disable); EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
#ifdef CONFIG_CPU_FREQ
/**
* dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
* @dev: device for which we do this operation
* @table: Cpufreq table returned back to caller
*
* Generate a cpufreq table for a provided device- this assumes that the
* opp list is already initialized and ready for usage.
*
* This function allocates required memory for the cpufreq table. It is
* expected that the caller does the required maintenance such as freeing
* the table as required.
*
* Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
* if no memory available for the operation (table is not populated), returns 0
* if successful and table is populated.
*
* WARNING: It is important for the callers to ensure refreshing their copy of
* the table if any of the mentioned functions have been invoked in the interim.
*
* Locking: The internal device_opp and opp structures are RCU protected.
* To simplify the logic, we pretend we are updater and hold relevant mutex here
* Callers should ensure that this function is *NOT* called under RCU protection
* or in contexts where mutex locking cannot be used.
*/
int dev_pm_opp_init_cpufreq_table(struct device *dev,
struct cpufreq_frequency_table **table)
{
struct device_opp *dev_opp;
struct dev_pm_opp *opp;
struct cpufreq_frequency_table *freq_table;
int i = 0;
/* Pretend as if I am an updater */
mutex_lock(&dev_opp_list_lock);
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp)) {
int r = PTR_ERR(dev_opp);
mutex_unlock(&dev_opp_list_lock);
dev_err(dev, "%s: Device OPP not found (%d)\n", __func__, r);
return r;
}
freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
(dev_pm_opp_get_opp_count(dev) + 1), GFP_KERNEL);
if (!freq_table) {
mutex_unlock(&dev_opp_list_lock);
dev_warn(dev, "%s: Unable to allocate frequency table\n",
__func__);
return -ENOMEM;
}
list_for_each_entry(opp, &dev_opp->opp_list, node) {
if (opp->available) {
freq_table[i].driver_data = i;
freq_table[i].frequency = opp->rate / 1000;
i++;
}
}
mutex_unlock(&dev_opp_list_lock);
freq_table[i].driver_data = i;
freq_table[i].frequency = CPUFREQ_TABLE_END;
*table = &freq_table[0];
return 0;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
/**
* dev_pm_opp_free_cpufreq_table() - free the cpufreq table
* @dev: device for which we do this operation
* @table: table to free
*
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
*/
void dev_pm_opp_free_cpufreq_table(struct device *dev,
struct cpufreq_frequency_table **table)
{
if (!table)
return;
kfree(*table);
*table = NULL;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
#endif /* CONFIG_CPU_FREQ */
/** /**
* dev_pm_opp_get_notifier() - find notifier_head of the device with opp * dev_pm_opp_get_notifier() - find notifier_head of the device with opp
* @dev: device pointer used to lookup device OPPs. * @dev: device pointer used to lookup device OPPs.
@ -734,11 +666,9 @@ int of_init_opp_table(struct device *dev)
unsigned long freq = be32_to_cpup(val++) * 1000; unsigned long freq = be32_to_cpup(val++) * 1000;
unsigned long volt = be32_to_cpup(val++); unsigned long volt = be32_to_cpup(val++);
if (dev_pm_opp_add(dev, freq, volt)) { if (dev_pm_opp_add(dev, freq, volt))
dev_warn(dev, "%s: Failed to add OPP %ld\n", dev_warn(dev, "%s: Failed to add OPP %ld\n",
__func__, freq); __func__, freq);
continue;
}
nr -= 2; nr -= 2;
} }

View file

@ -318,10 +318,16 @@ int device_init_wakeup(struct device *dev, bool enable)
{ {
int ret = 0; int ret = 0;
if (!dev)
return -EINVAL;
if (enable) { if (enable) {
device_set_wakeup_capable(dev, true); device_set_wakeup_capable(dev, true);
ret = device_wakeup_enable(dev); ret = device_wakeup_enable(dev);
} else { } else {
if (dev->power.can_wakeup)
device_wakeup_disable(dev);
device_set_wakeup_capable(dev, false); device_set_wakeup_capable(dev, false);
} }

View file

@ -95,7 +95,7 @@ int read_log(struct tpm_bios_log *log)
log->bios_event_log_end = log->bios_event_log + len; log->bios_event_log_end = log->bios_event_log + len;
virt = acpi_os_map_memory(start, len); virt = acpi_os_map_iomem(start, len);
if (!virt) { if (!virt) {
kfree(log->bios_event_log); kfree(log->bios_event_log);
printk("%s: ERROR - Unable to map memory\n", __func__); printk("%s: ERROR - Unable to map memory\n", __func__);
@ -104,6 +104,6 @@ int read_log(struct tpm_bios_log *log)
memcpy_fromio(log->bios_event_log, virt, len); memcpy_fromio(log->bios_event_log, virt, len);
acpi_os_unmap_memory(virt, len); acpi_os_unmap_iomem(virt, len);
return 0; return 0;
} }

View file

@ -8,6 +8,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_COMMON_CLK) += clk-gate.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o obj-$(CONFIG_COMMON_CLK) += clk-mux.o
obj-$(CONFIG_COMMON_CLK) += clk-composite.o obj-$(CONFIG_COMMON_CLK) += clk-composite.o
obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
# hardware specific clock types # hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name # please keep this section sorted lexicographically by file/directory path name

View file

@ -0,0 +1,135 @@
/*
* Copyright (C) 2014 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Adjustable fractional divider clock implementation.
* Output rate = (m / n) * parent_rate.
*/
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/gcd.h>
#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long flags = 0;
u32 val, m, n;
u64 ret;
if (fd->lock)
spin_lock_irqsave(fd->lock, flags);
val = clk_readl(fd->reg);
if (fd->lock)
spin_unlock_irqrestore(fd->lock, flags);
m = (val & fd->mmask) >> fd->mshift;
n = (val & fd->nmask) >> fd->nshift;
ret = parent_rate * m;
do_div(ret, n);
return ret;
}
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned maxn = (fd->nmask >> fd->nshift) + 1;
unsigned div;
if (!rate || rate >= *prate)
return *prate;
div = gcd(*prate, rate);
while ((*prate / div) > maxn) {
div <<= 1;
rate <<= 1;
}
return rate;
}
static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long flags = 0;
unsigned long div;
unsigned n, m;
u32 val;
div = gcd(parent_rate, rate);
m = rate / div;
n = parent_rate / div;
if (fd->lock)
spin_lock_irqsave(fd->lock, flags);
val = clk_readl(fd->reg);
val &= ~(fd->mmask | fd->nmask);
val |= (m << fd->mshift) | (n << fd->nshift);
clk_writel(val, fd->reg);
if (fd->lock)
spin_unlock_irqrestore(fd->lock, flags);
return 0;
}
const struct clk_ops clk_fractional_divider_ops = {
.recalc_rate = clk_fd_recalc_rate,
.round_rate = clk_fd_round_rate,
.set_rate = clk_fd_set_rate,
};
EXPORT_SYMBOL_GPL(clk_fractional_divider_ops);
struct clk *clk_register_fractional_divider(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
u8 clk_divider_flags, spinlock_t *lock)
{
struct clk_fractional_divider *fd;
struct clk_init_data init;
struct clk *clk;
fd = kzalloc(sizeof(*fd), GFP_KERNEL);
if (!fd) {
dev_err(dev, "could not allocate fractional divider clk\n");
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &clk_fractional_divider_ops;
init.flags = flags | CLK_IS_BASIC;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
fd->reg = reg;
fd->mshift = mshift;
fd->mmask = (BIT(mwidth) - 1) << mshift;
fd->nshift = nshift;
fd->nmask = (BIT(nwidth) - 1) << nshift;
fd->flags = clk_divider_flags;
fd->lock = lock;
fd->hw.init = &init;
clk = clk_register(dev, &fd->hw);
if (IS_ERR(clk))
kfree(fd);
return clk;
}
EXPORT_SYMBOL_GPL(clk_register_fractional_divider);

View file

@ -5,7 +5,8 @@
# big LITTLE core layer and glue drivers # big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver" tristate "Generic ARM big LITTLE CPUfreq driver"
depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK depends on (BIG_LITTLE && ARM_CPU_TOPOLOGY) || (ARM64 && SMP)
depends on HAVE_CLK
select PM_OPP select PM_OPP
help help
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
@ -85,7 +86,7 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW
It allows usage of special frequencies for Samsung Exynos It allows usage of special frequencies for Samsung Exynos
processors if thermal conditions are appropriate. processors if thermal conditions are appropriate.
It reguires, for safe operation, thermal framework with properly It requires, for safe operation, thermal framework with properly
defined trip points. defined trip points.
If in doubt, say N. If in doubt, say N.
@ -186,7 +187,7 @@ config ARM_S3C2416_CPUFREQ
S3C2450 SoC. The S3C2416 supports changing the rate of the S3C2450 SoC. The S3C2416 supports changing the rate of the
armdiv clock source and also entering a so called dynamic armdiv clock source and also entering a so called dynamic
voltage scaling mode in which it is possible to reduce the voltage scaling mode in which it is possible to reduce the
core voltage of the cpu. core voltage of the CPU.
If in doubt, say N. If in doubt, say N.

View file

@ -10,7 +10,7 @@ config X86_INTEL_PSTATE
The driver implements an internal governor and will become The driver implements an internal governor and will become
the scaling driver and governor for Sandy bridge processors. the scaling driver and governor for Sandy bridge processors.
When this driver is enabled it will become the perferred When this driver is enabled it will become the preferred
scaling driver for Sandy bridge processors. scaling driver for Sandy bridge processors.
If in doubt, say N. If in doubt, say N.
@ -52,7 +52,7 @@ config X86_ACPI_CPUFREQ_CPB
help help
The powernow-k8 driver used to provide a sysfs knob called "cpb" The powernow-k8 driver used to provide a sysfs knob called "cpb"
to disable the Core Performance Boosting feature of AMD CPUs. This to disable the Core Performance Boosting feature of AMD CPUs. This
file has now been superseeded by the more generic "boost" entry. file has now been superseded by the more generic "boost" entry.
By enabling this option the acpi_cpufreq driver provides the old By enabling this option the acpi_cpufreq driver provides the old
entry in addition to the new boost ones, for compatibility reasons. entry in addition to the new boost ones, for compatibility reasons.

View file

@ -1,5 +1,7 @@
# CPUfreq core # CPUfreq core
obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o
obj-$(CONFIG_PM_OPP) += cpufreq_opp.o
# CPUfreq stats # CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o

View file

@ -213,7 +213,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
{ {
int i; struct cpufreq_frequency_table *pos;
struct acpi_processor_performance *perf; struct acpi_processor_performance *perf;
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
@ -223,10 +223,9 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
perf = data->acpi_data; perf = data->acpi_data;
for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { cpufreq_for_each_entry(pos, data->freq_table)
if (msr == perf->states[data->freq_table[i].driver_data].status) if (msr == perf->states[pos->driver_data].status)
return data->freq_table[i].frequency; return pos->frequency;
}
return data->freq_table[0].frequency; return data->freq_table[0].frequency;
} }

View file

@ -226,22 +226,22 @@ static inline u32 get_table_count(struct cpufreq_frequency_table *table)
/* get the minimum frequency in the cpufreq_frequency_table */ /* get the minimum frequency in the cpufreq_frequency_table */
static inline u32 get_table_min(struct cpufreq_frequency_table *table) static inline u32 get_table_min(struct cpufreq_frequency_table *table)
{ {
int i; struct cpufreq_frequency_table *pos;
uint32_t min_freq = ~0; uint32_t min_freq = ~0;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) cpufreq_for_each_entry(pos, table)
if (table[i].frequency < min_freq) if (pos->frequency < min_freq)
min_freq = table[i].frequency; min_freq = pos->frequency;
return min_freq; return min_freq;
} }
/* get the maximum frequency in the cpufreq_frequency_table */ /* get the maximum frequency in the cpufreq_frequency_table */
static inline u32 get_table_max(struct cpufreq_frequency_table *table) static inline u32 get_table_max(struct cpufreq_frequency_table *table)
{ {
int i; struct cpufreq_frequency_table *pos;
uint32_t max_freq = 0; uint32_t max_freq = 0;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) cpufreq_for_each_entry(pos, table)
if (table[i].frequency > max_freq) if (pos->frequency > max_freq)
max_freq = table[i].frequency; max_freq = pos->frequency;
return max_freq; return max_freq;
} }

View file

@ -379,7 +379,7 @@ static struct cpufreq_driver nforce2_driver = {
}; };
#ifdef MODULE #ifdef MODULE
static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = { static const struct pci_device_id nforce2_ids[] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 },
{} {}
}; };

View file

@ -354,6 +354,18 @@ static void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs) struct cpufreq_freqs *freqs)
{ {
/*
* Catch double invocations of _begin() which lead to self-deadlock.
* ASYNC_NOTIFICATION drivers are left out because the cpufreq core
* doesn't invoke _begin() on their behalf, and hence the chances of
* double invocations are very low. Moreover, there are scenarios
* where these checks can emit false-positive warnings in these
* drivers; so we avoid that by skipping them altogether.
*/
WARN_ON(!(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION)
&& current == policy->transition_task);
wait: wait:
wait_event(policy->transition_wait, !policy->transition_ongoing); wait_event(policy->transition_wait, !policy->transition_ongoing);
@ -365,6 +377,7 @@ wait:
} }
policy->transition_ongoing = true; policy->transition_ongoing = true;
policy->transition_task = current;
spin_unlock(&policy->transition_lock); spin_unlock(&policy->transition_lock);
@ -381,6 +394,7 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
cpufreq_notify_post_transition(policy, freqs, transition_failed); cpufreq_notify_post_transition(policy, freqs, transition_failed);
policy->transition_ongoing = false; policy->transition_ongoing = false;
policy->transition_task = NULL;
wake_up(&policy->transition_wait); wake_up(&policy->transition_wait);
} }
@ -1802,12 +1816,43 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
* GOVERNORS * * GOVERNORS *
*********************************************************************/ *********************************************************************/
static int __target_index(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *freq_table, int index)
{
struct cpufreq_freqs freqs;
int retval = -EINVAL;
bool notify;
notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
if (notify) {
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
freqs.flags = 0;
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
__func__, policy->cpu, freqs.old, freqs.new);
cpufreq_freq_transition_begin(policy, &freqs);
}
retval = cpufreq_driver->target_index(policy, index);
if (retval)
pr_err("%s: Failed to change cpu frequency: %d\n", __func__,
retval);
if (notify)
cpufreq_freq_transition_end(policy, &freqs, retval);
return retval;
}
int __cpufreq_driver_target(struct cpufreq_policy *policy, int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int target_freq,
unsigned int relation) unsigned int relation)
{ {
int retval = -EINVAL;
unsigned int old_target_freq = target_freq; unsigned int old_target_freq = target_freq;
int retval = -EINVAL;
if (cpufreq_disabled()) if (cpufreq_disabled())
return -ENODEV; return -ENODEV;
@ -1834,8 +1879,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
retval = cpufreq_driver->target(policy, target_freq, relation); retval = cpufreq_driver->target(policy, target_freq, relation);
else if (cpufreq_driver->target_index) { else if (cpufreq_driver->target_index) {
struct cpufreq_frequency_table *freq_table; struct cpufreq_frequency_table *freq_table;
struct cpufreq_freqs freqs;
bool notify;
int index; int index;
freq_table = cpufreq_frequency_get_table(policy->cpu); freq_table = cpufreq_frequency_get_table(policy->cpu);
@ -1856,26 +1899,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
goto out; goto out;
} }
notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION); retval = __target_index(policy, freq_table, index);
if (notify) {
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
freqs.flags = 0;
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
__func__, policy->cpu, freqs.old, freqs.new);
cpufreq_freq_transition_begin(policy, &freqs);
}
retval = cpufreq_driver->target_index(policy, index);
if (retval)
pr_err("%s: Failed to change cpu frequency: %d\n",
__func__, retval);
if (notify)
cpufreq_freq_transition_end(policy, &freqs, retval);
} }
out: out:

View file

@ -0,0 +1,110 @@
/*
* Generic OPP helper interface for CPUFreq drivers
*
* Copyright (C) 2009-2014 Texas Instruments Incorporated.
* Nishanth Menon
* Romit Dasgupta
* Kevin Hilman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/pm_opp.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
/**
* dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
* @dev: device for which we do this operation
* @table: Cpufreq table returned back to caller
*
* Generate a cpufreq table for a provided device- this assumes that the
* opp list is already initialized and ready for usage.
*
* This function allocates required memory for the cpufreq table. It is
* expected that the caller does the required maintenance such as freeing
* the table as required.
*
* Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
* if no memory available for the operation (table is not populated), returns 0
* if successful and table is populated.
*
* WARNING: It is important for the callers to ensure refreshing their copy of
* the table if any of the mentioned functions have been invoked in the interim.
*
* Locking: The internal device_opp and opp structures are RCU protected.
* Since we just use the regular accessor functions to access the internal data
* structures, we use RCU read lock inside this function. As a result, users of
* this function DONOT need to use explicit locks for invoking.
*/
int dev_pm_opp_init_cpufreq_table(struct device *dev,
struct cpufreq_frequency_table **table)
{
struct dev_pm_opp *opp;
struct cpufreq_frequency_table *freq_table = NULL;
int i, max_opps, ret = 0;
unsigned long rate;
rcu_read_lock();
max_opps = dev_pm_opp_get_opp_count(dev);
if (max_opps <= 0) {
ret = max_opps ? max_opps : -ENODATA;
goto out;
}
freq_table = kzalloc(sizeof(*freq_table) * (max_opps + 1), GFP_KERNEL);
if (!freq_table) {
ret = -ENOMEM;
goto out;
}
for (i = 0, rate = 0; i < max_opps; i++, rate++) {
/* find next rate */
opp = dev_pm_opp_find_freq_ceil(dev, &rate);
if (IS_ERR(opp)) {
ret = PTR_ERR(opp);
goto out;
}
freq_table[i].driver_data = i;
freq_table[i].frequency = rate / 1000;
}
freq_table[i].driver_data = i;
freq_table[i].frequency = CPUFREQ_TABLE_END;
*table = &freq_table[0];
out:
rcu_read_unlock();
if (ret)
kfree(freq_table);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
/**
* dev_pm_opp_free_cpufreq_table() - free the cpufreq table
* @dev: device for which we do this operation
* @table: table to free
*
* Free up the table allocated by dev_pm_opp_init_cpufreq_table
*/
void dev_pm_opp_free_cpufreq_table(struct device *dev,
struct cpufreq_frequency_table **table)
{
if (!table)
return;
kfree(*table);
*table = NULL;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);

View file

@ -182,11 +182,11 @@ static void cpufreq_stats_free_table(unsigned int cpu)
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
{ {
unsigned int i, j, count = 0, ret = 0; unsigned int i, count = 0, ret = 0;
struct cpufreq_stats *stat; struct cpufreq_stats *stat;
unsigned int alloc_size; unsigned int alloc_size;
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
struct cpufreq_frequency_table *table; struct cpufreq_frequency_table *pos, *table;
table = cpufreq_frequency_get_table(cpu); table = cpufreq_frequency_get_table(cpu);
if (unlikely(!table)) if (unlikely(!table))
@ -205,12 +205,8 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
stat->cpu = cpu; stat->cpu = cpu;
per_cpu(cpufreq_stats_table, cpu) = stat; per_cpu(cpufreq_stats_table, cpu) = stat;
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { cpufreq_for_each_valid_entry(pos, table)
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue;
count++; count++;
}
alloc_size = count * sizeof(int) + count * sizeof(u64); alloc_size = count * sizeof(int) + count * sizeof(u64);
@ -228,15 +224,11 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stat->trans_table = stat->freq_table + count; stat->trans_table = stat->freq_table + count;
#endif #endif
j = 0; i = 0;
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { cpufreq_for_each_valid_entry(pos, table)
unsigned int freq = table[i].frequency; if (freq_table_get_index(stat, pos->frequency) == -1)
if (freq == CPUFREQ_ENTRY_INVALID) stat->freq_table[i++] = pos->frequency;
continue; stat->state_num = i;
if (freq_table_get_index(stat, freq) == -1)
stat->freq_table[j++] = freq;
}
stat->state_num = j;
spin_lock(&cpufreq_stats_lock); spin_lock(&cpufreq_stats_lock);
stat->last_time = get_jiffies_64(); stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur); stat->last_index = freq_table_get_index(stat, policy->cur);

View file

@ -45,7 +45,7 @@ static struct cpufreq_driver dbx500_cpufreq_driver = {
static int dbx500_cpufreq_probe(struct platform_device *pdev) static int dbx500_cpufreq_probe(struct platform_device *pdev)
{ {
int i = 0; struct cpufreq_frequency_table *pos;
freq_table = dev_get_platdata(&pdev->dev); freq_table = dev_get_platdata(&pdev->dev);
if (!freq_table) { if (!freq_table) {
@ -60,10 +60,8 @@ static int dbx500_cpufreq_probe(struct platform_device *pdev)
} }
pr_info("dbx500-cpufreq: Available frequencies:\n"); pr_info("dbx500-cpufreq: Available frequencies:\n");
while (freq_table[i].frequency != CPUFREQ_TABLE_END) { cpufreq_for_each_entry(pos, freq_table)
pr_info(" %d Mhz\n", freq_table[i].frequency/1000); pr_info(" %d Mhz\n", pos->frequency / 1000);
i++;
}
return cpufreq_register_driver(&dbx500_cpufreq_driver); return cpufreq_register_driver(&dbx500_cpufreq_driver);
} }

View file

@ -147,7 +147,7 @@ static int elanfreq_target(struct cpufreq_policy *policy,
static int elanfreq_cpu_init(struct cpufreq_policy *policy) static int elanfreq_cpu_init(struct cpufreq_policy *policy)
{ {
struct cpuinfo_x86 *c = &cpu_data(0); struct cpuinfo_x86 *c = &cpu_data(0);
unsigned int i; struct cpufreq_frequency_table *pos;
/* capability check */ /* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) || if ((c->x86_vendor != X86_VENDOR_AMD) ||
@ -159,10 +159,9 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
max_freq = elanfreq_get_cpu_frequency(0); max_freq = elanfreq_get_cpu_frequency(0);
/* table init */ /* table init */
for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) { cpufreq_for_each_entry(pos, elanfreq_table)
if (elanfreq_table[i].frequency > max_freq) if (pos->frequency > max_freq)
elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID; pos->frequency = CPUFREQ_ENTRY_INVALID;
}
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;

View file

@ -28,17 +28,16 @@ static unsigned int locking_frequency;
static int exynos_cpufreq_get_index(unsigned int freq) static int exynos_cpufreq_get_index(unsigned int freq)
{ {
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
int index; struct cpufreq_frequency_table *pos;
for (index = 0; cpufreq_for_each_entry(pos, freq_table)
freq_table[index].frequency != CPUFREQ_TABLE_END; index++) if (pos->frequency == freq)
if (freq_table[index].frequency == freq)
break; break;
if (freq_table[index].frequency == CPUFREQ_TABLE_END) if (pos->frequency == CPUFREQ_TABLE_END)
return -EINVAL; return -EINVAL;
return index; return pos - freq_table;
} }
static int exynos_cpufreq_scale(unsigned int target_freq) static int exynos_cpufreq_scale(unsigned int target_freq)
@ -48,6 +47,7 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
struct cpufreq_policy *policy = cpufreq_cpu_get(0); struct cpufreq_policy *policy = cpufreq_cpu_get(0);
unsigned int arm_volt, safe_arm_volt = 0; unsigned int arm_volt, safe_arm_volt = 0;
unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz; unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
struct device *dev = exynos_info->dev;
unsigned int old_freq; unsigned int old_freq;
int index, old_index; int index, old_index;
int ret = 0; int ret = 0;
@ -89,8 +89,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
/* Firstly, voltage up to increase frequency */ /* Firstly, voltage up to increase frequency */
ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
if (ret) { if (ret) {
pr_err("%s: failed to set cpu voltage to %d\n", dev_err(dev, "failed to set cpu voltage to %d\n",
__func__, arm_volt); arm_volt);
return ret; return ret;
} }
} }
@ -99,8 +99,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
ret = regulator_set_voltage(arm_regulator, safe_arm_volt, ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
safe_arm_volt); safe_arm_volt);
if (ret) { if (ret) {
pr_err("%s: failed to set cpu voltage to %d\n", dev_err(dev, "failed to set cpu voltage to %d\n",
__func__, safe_arm_volt); safe_arm_volt);
return ret; return ret;
} }
} }
@ -114,8 +114,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
ret = regulator_set_voltage(arm_regulator, arm_volt, ret = regulator_set_voltage(arm_regulator, arm_volt,
arm_volt); arm_volt);
if (ret) { if (ret) {
pr_err("%s: failed to set cpu voltage to %d\n", dev_err(dev, "failed to set cpu voltage to %d\n",
__func__, arm_volt); arm_volt);
goto out; goto out;
} }
} }
@ -162,6 +162,8 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
if (!exynos_info) if (!exynos_info)
return -ENOMEM; return -ENOMEM;
exynos_info->dev = &pdev->dev;
if (of_machine_is_compatible("samsung,exynos4210")) { if (of_machine_is_compatible("samsung,exynos4210")) {
exynos_info->type = EXYNOS_SOC_4210; exynos_info->type = EXYNOS_SOC_4210;
ret = exynos4210_cpufreq_init(exynos_info); ret = exynos4210_cpufreq_init(exynos_info);
@ -183,13 +185,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
goto err_vdd_arm; goto err_vdd_arm;
if (exynos_info->set_freq == NULL) { if (exynos_info->set_freq == NULL) {
pr_err("%s: No set_freq function (ERR)\n", __func__); dev_err(&pdev->dev, "No set_freq function (ERR)\n");
goto err_vdd_arm; goto err_vdd_arm;
} }
arm_regulator = regulator_get(NULL, "vdd_arm"); arm_regulator = regulator_get(NULL, "vdd_arm");
if (IS_ERR(arm_regulator)) { if (IS_ERR(arm_regulator)) {
pr_err("%s: failed to get resource vdd_arm\n", __func__); dev_err(&pdev->dev, "failed to get resource vdd_arm\n");
goto err_vdd_arm; goto err_vdd_arm;
} }
@ -199,7 +201,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
if (!cpufreq_register_driver(&exynos_driver)) if (!cpufreq_register_driver(&exynos_driver))
return 0; return 0;
pr_err("%s: failed to register cpufreq driver\n", __func__); dev_err(&pdev->dev, "failed to register cpufreq driver\n");
regulator_put(arm_regulator); regulator_put(arm_regulator);
err_vdd_arm: err_vdd_arm:
kfree(exynos_info); kfree(exynos_info);

View file

@ -42,6 +42,7 @@ struct apll_freq {
struct exynos_dvfs_info { struct exynos_dvfs_info {
enum exynos_soc_type type; enum exynos_soc_type type;
struct device *dev;
unsigned long mpll_freq_khz; unsigned long mpll_freq_khz;
unsigned int pll_safe_idx; unsigned int pll_safe_idx;
struct clk *cpu_clk; struct clk *cpu_clk;

View file

@ -114,25 +114,23 @@ static struct cpufreq_freqs freqs;
static int init_div_table(void) static int init_div_table(void)
{ {
struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table; struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table;
unsigned int tmp, clk_div, ema_div, freq, volt_id; unsigned int tmp, clk_div, ema_div, freq, volt_id;
int i = 0;
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
rcu_read_lock(); rcu_read_lock();
for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) { cpufreq_for_each_entry(pos, freq_tbl) {
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev, opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
freq_tbl[i].frequency * 1000, true); pos->frequency * 1000, true);
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock(); rcu_read_unlock();
dev_err(dvfs_info->dev, dev_err(dvfs_info->dev,
"failed to find valid OPP for %u KHZ\n", "failed to find valid OPP for %u KHZ\n",
freq_tbl[i].frequency); pos->frequency);
return PTR_ERR(opp); return PTR_ERR(opp);
} }
freq = freq_tbl[i].frequency / 1000; /* In MHZ */ freq = pos->frequency / 1000; /* In MHZ */
clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK) clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
<< P0_7_CPUCLKDEV_SHIFT; << P0_7_CPUCLKDEV_SHIFT;
clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK) clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
@ -157,7 +155,8 @@ static int init_div_table(void)
tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT) tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
| ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT)); | ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT));
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * i); __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
(pos - freq_tbl));
} }
rcu_read_unlock(); rcu_read_unlock();
@ -166,8 +165,9 @@ static int init_div_table(void)
static void exynos_enable_dvfs(unsigned int cur_frequency) static void exynos_enable_dvfs(unsigned int cur_frequency)
{ {
unsigned int tmp, i, cpu; unsigned int tmp, cpu;
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
struct cpufreq_frequency_table *pos;
/* Disable DVFS */ /* Disable DVFS */
__raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL); __raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
@ -182,15 +182,15 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN); __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
/* Set initial performance index */ /* Set initial performance index */
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) cpufreq_for_each_entry(pos, freq_table)
if (freq_table[i].frequency == cur_frequency) if (pos->frequency == cur_frequency)
break; break;
if (freq_table[i].frequency == CPUFREQ_TABLE_END) { if (pos->frequency == CPUFREQ_TABLE_END) {
dev_crit(dvfs_info->dev, "Boot up frequency not supported\n"); dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
/* Assign the highest frequency */ /* Assign the highest frequency */
i = 0; pos = freq_table;
cur_frequency = freq_table[i].frequency; cur_frequency = pos->frequency;
} }
dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ", dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
@ -199,7 +199,7 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) { for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT); tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
tmp |= (i << C0_3_PSTATE_NEW_SHIFT); tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT);
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
} }

View file

@ -21,22 +21,19 @@
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table) struct cpufreq_frequency_table *table)
{ {
struct cpufreq_frequency_table *pos;
unsigned int min_freq = ~0; unsigned int min_freq = ~0;
unsigned int max_freq = 0; unsigned int max_freq = 0;
unsigned int i; unsigned int freq;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { cpufreq_for_each_valid_entry(pos, table) {
unsigned int freq = table[i].frequency; freq = pos->frequency;
if (freq == CPUFREQ_ENTRY_INVALID) {
pr_debug("table entry %u is invalid, skipping\n", i);
continue;
}
if (!cpufreq_boost_enabled() if (!cpufreq_boost_enabled()
&& (table[i].flags & CPUFREQ_BOOST_FREQ)) && (pos->flags & CPUFREQ_BOOST_FREQ))
continue; continue;
pr_debug("table entry %u: %u kHz\n", i, freq); pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
if (freq < min_freq) if (freq < min_freq)
min_freq = freq; min_freq = freq;
if (freq > max_freq) if (freq > max_freq)
@ -57,7 +54,8 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table) struct cpufreq_frequency_table *table)
{ {
unsigned int next_larger = ~0, freq, i = 0; struct cpufreq_frequency_table *pos;
unsigned int freq, next_larger = ~0;
bool found = false; bool found = false;
pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n", pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
@ -65,9 +63,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
cpufreq_verify_within_cpu_limits(policy); cpufreq_verify_within_cpu_limits(policy);
for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) { cpufreq_for_each_valid_entry(pos, table) {
if (freq == CPUFREQ_ENTRY_INVALID) freq = pos->frequency;
continue;
if ((freq >= policy->min) && (freq <= policy->max)) { if ((freq >= policy->min) && (freq <= policy->max)) {
found = true; found = true;
break; break;
@ -118,7 +116,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
.driver_data = ~0, .driver_data = ~0,
.frequency = 0, .frequency = 0,
}; };
unsigned int i; struct cpufreq_frequency_table *pos;
unsigned int freq, i = 0;
pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
target_freq, relation, policy->cpu); target_freq, relation, policy->cpu);
@ -132,15 +131,19 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
break; break;
} }
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { cpufreq_for_each_valid_entry(pos, table) {
unsigned int freq = table[i].frequency; freq = pos->frequency;
if (freq == CPUFREQ_ENTRY_INVALID)
continue; i = pos - table;
if ((freq < policy->min) || (freq > policy->max)) if ((freq < policy->min) || (freq > policy->max))
continue; continue;
if (freq == target_freq) {
optimal.driver_data = i;
break;
}
switch (relation) { switch (relation) {
case CPUFREQ_RELATION_H: case CPUFREQ_RELATION_H:
if (freq <= target_freq) { if (freq < target_freq) {
if (freq >= optimal.frequency) { if (freq >= optimal.frequency) {
optimal.frequency = freq; optimal.frequency = freq;
optimal.driver_data = i; optimal.driver_data = i;
@ -153,7 +156,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
} }
break; break;
case CPUFREQ_RELATION_L: case CPUFREQ_RELATION_L:
if (freq >= target_freq) { if (freq > target_freq) {
if (freq <= optimal.frequency) { if (freq <= optimal.frequency) {
optimal.frequency = freq; optimal.frequency = freq;
optimal.driver_data = i; optimal.driver_data = i;
@ -184,8 +187,7 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
unsigned int freq) unsigned int freq)
{ {
struct cpufreq_frequency_table *table; struct cpufreq_frequency_table *pos, *table;
int i;
table = cpufreq_frequency_get_table(policy->cpu); table = cpufreq_frequency_get_table(policy->cpu);
if (unlikely(!table)) { if (unlikely(!table)) {
@ -193,10 +195,9 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
return -ENOENT; return -ENOENT;
} }
for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { cpufreq_for_each_valid_entry(pos, table)
if (table[i].frequency == freq) if (pos->frequency == freq)
return i; return pos - table;
}
return -EINVAL; return -EINVAL;
} }
@ -208,16 +209,13 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
bool show_boost) bool show_boost)
{ {
unsigned int i = 0;
ssize_t count = 0; ssize_t count = 0;
struct cpufreq_frequency_table *table = policy->freq_table; struct cpufreq_frequency_table *pos, *table = policy->freq_table;
if (!table) if (!table)
return -ENODEV; return -ENODEV;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { cpufreq_for_each_valid_entry(pos, table) {
if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
continue;
/* /*
* show_boost = true and driver_data = BOOST freq * show_boost = true and driver_data = BOOST freq
* display BOOST freqs * display BOOST freqs
@ -229,10 +227,10 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
* show_boost = false and driver_data != BOOST freq * show_boost = false and driver_data != BOOST freq
* display NON BOOST freqs * display NON BOOST freqs
*/ */
if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ)) if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
continue; continue;
count += sprintf(&buf[count], "%d ", table[i].frequency); count += sprintf(&buf[count], "%d ", pos->frequency);
} }
count += sprintf(&buf[count], "\n"); count += sprintf(&buf[count], "\n");

View file

@ -9,7 +9,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
@ -170,25 +169,25 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
return -ENOENT; return -ENOENT;
} }
arm_clk = devm_clk_get(cpu_dev, "arm"); arm_clk = clk_get(cpu_dev, "arm");
pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys"); pll1_sys_clk = clk_get(cpu_dev, "pll1_sys");
pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw"); pll1_sw_clk = clk_get(cpu_dev, "pll1_sw");
step_clk = devm_clk_get(cpu_dev, "step"); step_clk = clk_get(cpu_dev, "step");
pll2_pfd2_396m_clk = devm_clk_get(cpu_dev, "pll2_pfd2_396m"); pll2_pfd2_396m_clk = clk_get(cpu_dev, "pll2_pfd2_396m");
if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) || if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) ||
IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) { IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) {
dev_err(cpu_dev, "failed to get clocks\n"); dev_err(cpu_dev, "failed to get clocks\n");
ret = -ENOENT; ret = -ENOENT;
goto put_node; goto put_clk;
} }
arm_reg = devm_regulator_get(cpu_dev, "arm"); arm_reg = regulator_get(cpu_dev, "arm");
pu_reg = devm_regulator_get(cpu_dev, "pu"); pu_reg = regulator_get(cpu_dev, "pu");
soc_reg = devm_regulator_get(cpu_dev, "soc"); soc_reg = regulator_get(cpu_dev, "soc");
if (IS_ERR(arm_reg) || IS_ERR(pu_reg) || IS_ERR(soc_reg)) { if (IS_ERR(arm_reg) || IS_ERR(pu_reg) || IS_ERR(soc_reg)) {
dev_err(cpu_dev, "failed to get regulators\n"); dev_err(cpu_dev, "failed to get regulators\n");
ret = -ENOENT; ret = -ENOENT;
goto put_node; goto put_reg;
} }
/* /*
@ -201,21 +200,21 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
ret = of_init_opp_table(cpu_dev); ret = of_init_opp_table(cpu_dev);
if (ret < 0) { if (ret < 0) {
dev_err(cpu_dev, "failed to init OPP table: %d\n", ret); dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
goto put_node; goto put_reg;
} }
num = dev_pm_opp_get_opp_count(cpu_dev); num = dev_pm_opp_get_opp_count(cpu_dev);
if (num < 0) { if (num < 0) {
ret = num; ret = num;
dev_err(cpu_dev, "no OPP table is found: %d\n", ret); dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
goto put_node; goto put_reg;
} }
} }
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) { if (ret) {
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
goto put_node; goto put_reg;
} }
/* Make imx6_soc_volt array's size same as arm opp number */ /* Make imx6_soc_volt array's size same as arm opp number */
@ -301,7 +300,24 @@ soc_opp_out:
free_freq_table: free_freq_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
put_node: put_reg:
if (!IS_ERR(arm_reg))
regulator_put(arm_reg);
if (!IS_ERR(pu_reg))
regulator_put(pu_reg);
if (!IS_ERR(soc_reg))
regulator_put(soc_reg);
put_clk:
if (!IS_ERR(arm_clk))
clk_put(arm_clk);
if (!IS_ERR(pll1_sys_clk))
clk_put(pll1_sys_clk);
if (!IS_ERR(pll1_sw_clk))
clk_put(pll1_sw_clk);
if (!IS_ERR(step_clk))
clk_put(step_clk);
if (!IS_ERR(pll2_pfd2_396m_clk))
clk_put(pll2_pfd2_396m_clk);
of_node_put(np); of_node_put(np);
return ret; return ret;
} }
@ -310,6 +326,14 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
{ {
cpufreq_unregister_driver(&imx6q_cpufreq_driver); cpufreq_unregister_driver(&imx6q_cpufreq_driver);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
regulator_put(arm_reg);
regulator_put(pu_reg);
regulator_put(soc_reg);
clk_put(arm_clk);
clk_put(pll1_sys_clk);
clk_put(pll1_sw_clk);
clk_put(step_clk);
clk_put(pll2_pfd2_396m_clk);
return 0; return 0;
} }

View file

@ -32,18 +32,16 @@
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/cpu_device_id.h> #include <asm/cpu_device_id.h>
#define SAMPLE_COUNT 3
#define BYT_RATIOS 0x66a #define BYT_RATIOS 0x66a
#define BYT_VIDS 0x66b #define BYT_VIDS 0x66b
#define BYT_TURBO_RATIOS 0x66c #define BYT_TURBO_RATIOS 0x66c
#define BYT_TURBO_VIDS 0x66d #define BYT_TURBO_VIDS 0x66d
#define FRAC_BITS 6 #define FRAC_BITS 8
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS) #define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
#define fp_toint(X) ((X) >> FRAC_BITS) #define fp_toint(X) ((X) >> FRAC_BITS)
#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS)
static inline int32_t mul_fp(int32_t x, int32_t y) static inline int32_t mul_fp(int32_t x, int32_t y)
{ {
@ -59,8 +57,8 @@ struct sample {
int32_t core_pct_busy; int32_t core_pct_busy;
u64 aperf; u64 aperf;
u64 mperf; u64 mperf;
unsigned long long tsc;
int freq; int freq;
ktime_t time;
}; };
struct pstate_data { struct pstate_data {
@ -90,17 +88,15 @@ struct _pid {
struct cpudata { struct cpudata {
int cpu; int cpu;
char name[64];
struct timer_list timer; struct timer_list timer;
struct pstate_data pstate; struct pstate_data pstate;
struct vid_data vid; struct vid_data vid;
struct _pid pid; struct _pid pid;
ktime_t last_sample_time;
u64 prev_aperf; u64 prev_aperf;
u64 prev_mperf; u64 prev_mperf;
unsigned long long prev_tsc;
struct sample sample; struct sample sample;
}; };
@ -200,7 +196,10 @@ static signed int pid_calc(struct _pid *pid, int32_t busy)
pid->last_err = fp_error; pid->last_err = fp_error;
result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm; result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm;
if (result >= 0)
result = result + (1 << (FRAC_BITS-1));
else
result = result - (1 << (FRAC_BITS-1));
return (signed int)fp_toint(result); return (signed int)fp_toint(result);
} }
@ -546,8 +545,6 @@ static inline void intel_pstate_pstate_decrease(struct cpudata *cpu, int steps)
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{ {
sprintf(cpu->name, "Intel 2nd generation core");
cpu->pstate.min_pstate = pstate_funcs.get_min(); cpu->pstate.min_pstate = pstate_funcs.get_min();
cpu->pstate.max_pstate = pstate_funcs.get_max(); cpu->pstate.max_pstate = pstate_funcs.get_max();
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(); cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
@ -557,50 +554,45 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate); intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
} }
static inline void intel_pstate_calc_busy(struct cpudata *cpu, static inline void intel_pstate_calc_busy(struct cpudata *cpu)
struct sample *sample)
{ {
int32_t core_pct; struct sample *sample = &cpu->sample;
int32_t c0_pct; int64_t core_pct;
int32_t rem;
core_pct = div_fp(int_tofp((sample->aperf)), core_pct = int_tofp(sample->aperf) * int_tofp(100);
int_tofp((sample->mperf))); core_pct = div_u64_rem(core_pct, int_tofp(sample->mperf), &rem);
core_pct = mul_fp(core_pct, int_tofp(100));
FP_ROUNDUP(core_pct);
c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc)); if ((rem << 1) >= int_tofp(sample->mperf))
core_pct += 1;
sample->freq = fp_toint( sample->freq = fp_toint(
mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct));
sample->core_pct_busy = mul_fp(core_pct, c0_pct); sample->core_pct_busy = (int32_t)core_pct;
} }
static inline void intel_pstate_sample(struct cpudata *cpu) static inline void intel_pstate_sample(struct cpudata *cpu)
{ {
u64 aperf, mperf; u64 aperf, mperf;
unsigned long long tsc;
rdmsrl(MSR_IA32_APERF, aperf); rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf); rdmsrl(MSR_IA32_MPERF, mperf);
tsc = native_read_tsc();
aperf = aperf >> FRAC_BITS; aperf = aperf >> FRAC_BITS;
mperf = mperf >> FRAC_BITS; mperf = mperf >> FRAC_BITS;
tsc = tsc >> FRAC_BITS;
cpu->last_sample_time = cpu->sample.time;
cpu->sample.time = ktime_get();
cpu->sample.aperf = aperf; cpu->sample.aperf = aperf;
cpu->sample.mperf = mperf; cpu->sample.mperf = mperf;
cpu->sample.tsc = tsc;
cpu->sample.aperf -= cpu->prev_aperf; cpu->sample.aperf -= cpu->prev_aperf;
cpu->sample.mperf -= cpu->prev_mperf; cpu->sample.mperf -= cpu->prev_mperf;
cpu->sample.tsc -= cpu->prev_tsc;
intel_pstate_calc_busy(cpu, &cpu->sample); intel_pstate_calc_busy(cpu);
cpu->prev_aperf = aperf; cpu->prev_aperf = aperf;
cpu->prev_mperf = mperf; cpu->prev_mperf = mperf;
cpu->prev_tsc = tsc;
} }
static inline void intel_pstate_set_sample_time(struct cpudata *cpu) static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
@ -614,13 +606,25 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
{ {
int32_t core_busy, max_pstate, current_pstate; int32_t core_busy, max_pstate, current_pstate, sample_ratio;
u32 duration_us;
u32 sample_time;
core_busy = cpu->sample.core_pct_busy; core_busy = cpu->sample.core_pct_busy;
max_pstate = int_tofp(cpu->pstate.max_pstate); max_pstate = int_tofp(cpu->pstate.max_pstate);
current_pstate = int_tofp(cpu->pstate.current_pstate); current_pstate = int_tofp(cpu->pstate.current_pstate);
core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
return FP_ROUNDUP(core_busy);
sample_time = (pid_params.sample_rate_ms * USEC_PER_MSEC);
duration_us = (u32) ktime_us_delta(cpu->sample.time,
cpu->last_sample_time);
if (duration_us > sample_time * 3) {
sample_ratio = div_fp(int_tofp(sample_time),
int_tofp(duration_us));
core_busy = mul_fp(core_busy, sample_ratio);
}
return core_busy;
} }
static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
@ -674,10 +678,13 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(0x37, byt_params), ICPU(0x37, byt_params),
ICPU(0x3a, core_params), ICPU(0x3a, core_params),
ICPU(0x3c, core_params), ICPU(0x3c, core_params),
ICPU(0x3d, core_params),
ICPU(0x3e, core_params), ICPU(0x3e, core_params),
ICPU(0x3f, core_params), ICPU(0x3f, core_params),
ICPU(0x45, core_params), ICPU(0x45, core_params),
ICPU(0x46, core_params), ICPU(0x46, core_params),
ICPU(0x4f, core_params),
ICPU(0x56, core_params),
{} {}
}; };
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);

View file

@ -530,6 +530,7 @@ static int longhaul_get_ranges(void)
static void longhaul_setup_voltagescaling(void) static void longhaul_setup_voltagescaling(void)
{ {
struct cpufreq_frequency_table *freq_pos;
union msr_longhaul longhaul; union msr_longhaul longhaul;
struct mV_pos minvid, maxvid, vid; struct mV_pos minvid, maxvid, vid;
unsigned int j, speed, pos, kHz_step, numvscales; unsigned int j, speed, pos, kHz_step, numvscales;
@ -608,18 +609,16 @@ static void longhaul_setup_voltagescaling(void)
/* Calculate kHz for one voltage step */ /* Calculate kHz for one voltage step */
kHz_step = (highest_speed - min_vid_speed) / numvscales; kHz_step = (highest_speed - min_vid_speed) / numvscales;
j = 0; cpufreq_for_each_entry(freq_pos, longhaul_table) {
while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) { speed = freq_pos->frequency;
speed = longhaul_table[j].frequency;
if (speed > min_vid_speed) if (speed > min_vid_speed)
pos = (speed - min_vid_speed) / kHz_step + minvid.pos; pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
else else
pos = minvid.pos; pos = minvid.pos;
longhaul_table[j].driver_data |= mV_vrm_table[pos] << 8; freq_pos->driver_data |= mV_vrm_table[pos] << 8;
vid = vrm_mV_table[mV_vrm_table[pos]]; vid = vrm_mV_table[mV_vrm_table[pos]];
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
speed, j, vid.mV); speed, (int)(freq_pos - longhaul_table), vid.mV);
j++;
} }
can_scale_voltage = 1; can_scale_voltage = 1;

View file

@ -136,9 +136,10 @@ void restore_astate(int cpu)
static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
{ {
struct cpufreq_frequency_table *pos;
const u32 *max_freqp; const u32 *max_freqp;
u32 max_freq; u32 max_freq;
int i, cur_astate; int cur_astate;
struct resource res; struct resource res;
struct device_node *cpu, *dn; struct device_node *cpu, *dn;
int err = -ENODEV; int err = -ENODEV;
@ -197,10 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("initializing frequency table\n"); pr_debug("initializing frequency table\n");
/* initialize frequency table */ /* initialize frequency table */
for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { cpufreq_for_each_entry(pos, pas_freqs) {
pas_freqs[i].frequency = pos->frequency = get_astate_freq(pos->driver_data) * 100000;
get_astate_freq(pas_freqs[i].driver_data) * 100000; pr_debug("%d: %d\n", (int)(pos - pas_freqs), pos->frequency);
pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
} }
cur_astate = get_cur_astate(policy->cpu); cur_astate = get_cur_astate(policy->cpu);

View file

@ -151,6 +151,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
static int powernow_k6_cpu_init(struct cpufreq_policy *policy) static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
{ {
struct cpufreq_frequency_table *pos;
unsigned int i, f; unsigned int i, f;
unsigned khz; unsigned khz;
@ -168,12 +169,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
} }
} }
if (param_max_multiplier) { if (param_max_multiplier) {
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { cpufreq_for_each_entry(pos, clock_ratio)
if (clock_ratio[i].driver_data == param_max_multiplier) { if (pos->driver_data == param_max_multiplier) {
max_multiplier = param_max_multiplier; max_multiplier = param_max_multiplier;
goto have_max_multiplier; goto have_max_multiplier;
} }
}
printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n"); printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
return -EINVAL; return -EINVAL;
} }
@ -201,12 +201,12 @@ have_busfreq:
param_busfreq = busfreq * 10; param_busfreq = busfreq * 10;
/* table init */ /* table init */
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { cpufreq_for_each_entry(pos, clock_ratio) {
f = clock_ratio[i].driver_data; f = pos->driver_data;
if (f > max_multiplier) if (f > max_multiplier)
clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID; pos->frequency = CPUFREQ_ENTRY_INVALID;
else else
clock_ratio[i].frequency = busfreq * f; pos->frequency = busfreq * f;
} }
/* cpuinfo and default policy values */ /* cpuinfo and default policy values */

View file

@ -27,6 +27,8 @@
* power and thermal data sheets, (e.g. 30417.pdf, 30430.pdf, 43375.pdf) * power and thermal data sheets, (e.g. 30417.pdf, 30430.pdf, 43375.pdf)
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/module.h> #include <linux/module.h>
@ -45,7 +47,6 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <acpi/processor.h> #include <acpi/processor.h>
#define PFX "powernow-k8: "
#define VERSION "version 2.20.00" #define VERSION "version 2.20.00"
#include "powernow-k8.h" #include "powernow-k8.h"
@ -161,7 +162,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
u32 i = 0; u32 i = 0;
if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) { if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) {
printk(KERN_ERR PFX "internal error - overflow on fid write\n"); pr_err("internal error - overflow on fid write\n");
return 1; return 1;
} }
@ -175,9 +176,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
do { do {
wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION); wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
if (i++ > 100) { if (i++ > 100) {
printk(KERN_ERR PFX pr_err("Hardware error - pending bit very stuck - no further pstate changes possible\n");
"Hardware error - pending bit very stuck - "
"no further pstate changes possible\n");
return 1; return 1;
} }
} while (query_current_values_with_pending_wait(data)); } while (query_current_values_with_pending_wait(data));
@ -185,15 +184,13 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
count_off_irt(data); count_off_irt(data);
if (savevid != data->currvid) { if (savevid != data->currvid) {
printk(KERN_ERR PFX pr_err("vid change on fid trans, old 0x%x, new 0x%x\n",
"vid change on fid trans, old 0x%x, new 0x%x\n", savevid, data->currvid);
savevid, data->currvid);
return 1; return 1;
} }
if (fid != data->currfid) { if (fid != data->currfid) {
printk(KERN_ERR PFX pr_err("fid trans failed, fid 0x%x, curr 0x%x\n", fid,
"fid trans failed, fid 0x%x, curr 0x%x\n", fid,
data->currfid); data->currfid);
return 1; return 1;
} }
@ -209,7 +206,7 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
int i = 0; int i = 0;
if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) { if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) {
printk(KERN_ERR PFX "internal error - overflow on vid write\n"); pr_err("internal error - overflow on vid write\n");
return 1; return 1;
} }
@ -223,23 +220,19 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
do { do {
wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS); wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
if (i++ > 100) { if (i++ > 100) {
printk(KERN_ERR PFX "internal error - pending bit " pr_err("internal error - pending bit very stuck - no further pstate changes possible\n");
"very stuck - no further pstate "
"changes possible\n");
return 1; return 1;
} }
} while (query_current_values_with_pending_wait(data)); } while (query_current_values_with_pending_wait(data));
if (savefid != data->currfid) { if (savefid != data->currfid) {
printk(KERN_ERR PFX "fid changed on vid trans, old " pr_err("fid changed on vid trans, old 0x%x new 0x%x\n",
"0x%x new 0x%x\n", savefid, data->currfid);
savefid, data->currfid);
return 1; return 1;
} }
if (vid != data->currvid) { if (vid != data->currvid) {
printk(KERN_ERR PFX "vid trans failed, vid 0x%x, " pr_err("vid trans failed, vid 0x%x, curr 0x%x\n",
"curr 0x%x\n",
vid, data->currvid); vid, data->currvid);
return 1; return 1;
} }
@ -283,8 +276,7 @@ static int transition_fid_vid(struct powernow_k8_data *data,
return 1; return 1;
if ((reqfid != data->currfid) || (reqvid != data->currvid)) { if ((reqfid != data->currfid) || (reqvid != data->currvid)) {
printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, " pr_err("failed (cpu%d): req 0x%x 0x%x, curr 0x%x 0x%x\n",
"curr 0x%x 0x%x\n",
smp_processor_id(), smp_processor_id(),
reqfid, reqvid, data->currfid, data->currvid); reqfid, reqvid, data->currfid, data->currvid);
return 1; return 1;
@ -304,8 +296,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
u32 savefid = data->currfid; u32 savefid = data->currfid;
u32 maxvid, lo, rvomult = 1; u32 maxvid, lo, rvomult = 1;
pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, " pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n",
"reqvid 0x%x, rvo 0x%x\n",
smp_processor_id(), smp_processor_id(),
data->currfid, data->currvid, reqvid, data->rvo); data->currfid, data->currvid, reqvid, data->rvo);
@ -342,8 +333,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
return 1; return 1;
if (savefid != data->currfid) { if (savefid != data->currfid) {
printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n", pr_err("ph1 err, currfid changed 0x%x\n", data->currfid);
data->currfid);
return 1; return 1;
} }
@ -360,13 +350,11 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
u32 fid_interval, savevid = data->currvid; u32 fid_interval, savevid = data->currvid;
if (data->currfid == reqfid) { if (data->currfid == reqfid) {
printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n", pr_err("ph2 null fid transition 0x%x\n", data->currfid);
data->currfid);
return 0; return 0;
} }
pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, " pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n",
"reqfid 0x%x\n",
smp_processor_id(), smp_processor_id(),
data->currfid, data->currvid, reqfid); data->currfid, data->currvid, reqfid);
@ -409,15 +397,13 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
return 1; return 1;
if (data->currfid != reqfid) { if (data->currfid != reqfid) {
printk(KERN_ERR PFX pr_err("ph2: mismatch, failed fid transition, curr 0x%x, req 0x%x\n",
"ph2: mismatch, failed fid transition, "
"curr 0x%x, req 0x%x\n",
data->currfid, reqfid); data->currfid, reqfid);
return 1; return 1;
} }
if (savevid != data->currvid) { if (savevid != data->currvid) {
printk(KERN_ERR PFX "ph2: vid changed, save 0x%x, curr 0x%x\n", pr_err("ph2: vid changed, save 0x%x, curr 0x%x\n",
savevid, data->currvid); savevid, data->currvid);
return 1; return 1;
} }
@ -444,17 +430,14 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
return 1; return 1;
if (savefid != data->currfid) { if (savefid != data->currfid) {
printk(KERN_ERR PFX pr_err("ph3: bad fid change, save 0x%x, curr 0x%x\n",
"ph3: bad fid change, save 0x%x, curr 0x%x\n", savefid, data->currfid);
savefid, data->currfid);
return 1; return 1;
} }
if (data->currvid != reqvid) { if (data->currvid != reqvid) {
printk(KERN_ERR PFX pr_err("ph3: failed vid transition\n, req 0x%x, curr 0x%x",
"ph3: failed vid transition\n, " reqvid, data->currvid);
"req 0x%x, curr 0x%x",
reqvid, data->currvid);
return 1; return 1;
} }
} }
@ -498,23 +481,20 @@ static void check_supported_cpu(void *_rc)
if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) { if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) || if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) { ((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) {
printk(KERN_INFO PFX pr_info("Processor cpuid %x not supported\n", eax);
"Processor cpuid %x not supported\n", eax);
return; return;
} }
eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES); eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
if (eax < CPUID_FREQ_VOLT_CAPABILITIES) { if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
printk(KERN_INFO PFX pr_info("No frequency change capabilities detected\n");
"No frequency change capabilities detected\n");
return; return;
} }
cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx); cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
if ((edx & P_STATE_TRANSITION_CAPABLE) if ((edx & P_STATE_TRANSITION_CAPABLE)
!= P_STATE_TRANSITION_CAPABLE) { != P_STATE_TRANSITION_CAPABLE) {
printk(KERN_INFO PFX pr_info("Power state transitions not supported\n");
"Power state transitions not supported\n");
return; return;
} }
*rc = 0; *rc = 0;
@ -529,43 +509,39 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst,
for (j = 0; j < data->numps; j++) { for (j = 0; j < data->numps; j++) {
if (pst[j].vid > LEAST_VID) { if (pst[j].vid > LEAST_VID) {
printk(KERN_ERR FW_BUG PFX "vid %d invalid : 0x%x\n", pr_err(FW_BUG "vid %d invalid : 0x%x\n", j,
j, pst[j].vid); pst[j].vid);
return -EINVAL; return -EINVAL;
} }
if (pst[j].vid < data->rvo) { if (pst[j].vid < data->rvo) {
/* vid + rvo >= 0 */ /* vid + rvo >= 0 */
printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate" pr_err(FW_BUG "0 vid exceeded with pstate %d\n", j);
" %d\n", j);
return -ENODEV; return -ENODEV;
} }
if (pst[j].vid < maxvid + data->rvo) { if (pst[j].vid < maxvid + data->rvo) {
/* vid + rvo >= maxvid */ /* vid + rvo >= maxvid */
printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate" pr_err(FW_BUG "maxvid exceeded with pstate %d\n", j);
" %d\n", j);
return -ENODEV; return -ENODEV;
} }
if (pst[j].fid > MAX_FID) { if (pst[j].fid > MAX_FID) {
printk(KERN_ERR FW_BUG PFX "maxfid exceeded with pstate" pr_err(FW_BUG "maxfid exceeded with pstate %d\n", j);
" %d\n", j);
return -ENODEV; return -ENODEV;
} }
if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) { if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) {
/* Only first fid is allowed to be in "low" range */ /* Only first fid is allowed to be in "low" range */
printk(KERN_ERR FW_BUG PFX "two low fids - %d : " pr_err(FW_BUG "two low fids - %d : 0x%x\n", j,
"0x%x\n", j, pst[j].fid); pst[j].fid);
return -EINVAL; return -EINVAL;
} }
if (pst[j].fid < lastfid) if (pst[j].fid < lastfid)
lastfid = pst[j].fid; lastfid = pst[j].fid;
} }
if (lastfid & 1) { if (lastfid & 1) {
printk(KERN_ERR FW_BUG PFX "lastfid invalid\n"); pr_err(FW_BUG "lastfid invalid\n");
return -EINVAL; return -EINVAL;
} }
if (lastfid > LO_FID_TABLE_TOP) if (lastfid > LO_FID_TABLE_TOP)
printk(KERN_INFO FW_BUG PFX pr_info(FW_BUG "first fid not from lo freq table\n");
"first fid not from lo freq table\n");
return 0; return 0;
} }
@ -582,16 +558,14 @@ static void print_basics(struct powernow_k8_data *data)
for (j = 0; j < data->numps; j++) { for (j = 0; j < data->numps; j++) {
if (data->powernow_table[j].frequency != if (data->powernow_table[j].frequency !=
CPUFREQ_ENTRY_INVALID) { CPUFREQ_ENTRY_INVALID) {
printk(KERN_INFO PFX pr_info("fid 0x%x (%d MHz), vid 0x%x\n",
"fid 0x%x (%d MHz), vid 0x%x\n", data->powernow_table[j].driver_data & 0xff,
data->powernow_table[j].driver_data & 0xff, data->powernow_table[j].frequency/1000,
data->powernow_table[j].frequency/1000, data->powernow_table[j].driver_data >> 8);
data->powernow_table[j].driver_data >> 8);
} }
} }
if (data->batps) if (data->batps)
printk(KERN_INFO PFX "Only %d pstates on battery\n", pr_info("Only %d pstates on battery\n", data->batps);
data->batps);
} }
static int fill_powernow_table(struct powernow_k8_data *data, static int fill_powernow_table(struct powernow_k8_data *data,
@ -602,21 +576,20 @@ static int fill_powernow_table(struct powernow_k8_data *data,
if (data->batps) { if (data->batps) {
/* use ACPI support to get full speed on mains power */ /* use ACPI support to get full speed on mains power */
printk(KERN_WARNING PFX pr_warn("Only %d pstates usable (use ACPI driver for full range\n",
"Only %d pstates usable (use ACPI driver for full " data->batps);
"range\n", data->batps);
data->numps = data->batps; data->numps = data->batps;
} }
for (j = 1; j < data->numps; j++) { for (j = 1; j < data->numps; j++) {
if (pst[j-1].fid >= pst[j].fid) { if (pst[j-1].fid >= pst[j].fid) {
printk(KERN_ERR PFX "PST out of sequence\n"); pr_err("PST out of sequence\n");
return -EINVAL; return -EINVAL;
} }
} }
if (data->numps < 2) { if (data->numps < 2) {
printk(KERN_ERR PFX "no p states to transition\n"); pr_err("no p states to transition\n");
return -ENODEV; return -ENODEV;
} }
@ -626,7 +599,7 @@ static int fill_powernow_table(struct powernow_k8_data *data,
powernow_table = kzalloc((sizeof(*powernow_table) powernow_table = kzalloc((sizeof(*powernow_table)
* (data->numps + 1)), GFP_KERNEL); * (data->numps + 1)), GFP_KERNEL);
if (!powernow_table) { if (!powernow_table) {
printk(KERN_ERR PFX "powernow_table memory alloc failure\n"); pr_err("powernow_table memory alloc failure\n");
return -ENOMEM; return -ENOMEM;
} }
@ -681,13 +654,13 @@ static int find_psb_table(struct powernow_k8_data *data)
pr_debug("table vers: 0x%x\n", psb->tableversion); pr_debug("table vers: 0x%x\n", psb->tableversion);
if (psb->tableversion != PSB_VERSION_1_4) { if (psb->tableversion != PSB_VERSION_1_4) {
printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n"); pr_err(FW_BUG "PSB table is not v1.4\n");
return -ENODEV; return -ENODEV;
} }
pr_debug("flags: 0x%x\n", psb->flags1); pr_debug("flags: 0x%x\n", psb->flags1);
if (psb->flags1) { if (psb->flags1) {
printk(KERN_ERR FW_BUG PFX "unknown flags\n"); pr_err(FW_BUG "unknown flags\n");
return -ENODEV; return -ENODEV;
} }
@ -716,7 +689,7 @@ static int find_psb_table(struct powernow_k8_data *data)
cpst = 1; cpst = 1;
} }
if (cpst != 1) { if (cpst != 1) {
printk(KERN_ERR FW_BUG PFX "numpst must be 1\n"); pr_err(FW_BUG "numpst must be 1\n");
return -ENODEV; return -ENODEV;
} }
@ -742,9 +715,8 @@ static int find_psb_table(struct powernow_k8_data *data)
* BIOS and Kernel Developer's Guide, which is available on * BIOS and Kernel Developer's Guide, which is available on
* www.amd.com * www.amd.com
*/ */
printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n"); pr_err(FW_BUG "No PSB or ACPI _PSS objects\n");
printk(KERN_ERR PFX "Make sure that your BIOS is up to date" pr_err("Make sure that your BIOS is up to date and Cool'N'Quiet support is enabled in BIOS setup\n");
" and Cool'N'Quiet support is enabled in BIOS setup\n");
return -ENODEV; return -ENODEV;
} }
@ -819,8 +791,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
acpi_processor_notify_smm(THIS_MODULE); acpi_processor_notify_smm(THIS_MODULE);
if (!zalloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) { if (!zalloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) {
printk(KERN_ERR PFX pr_err("unable to alloc powernow_k8_data cpumask\n");
"unable to alloc powernow_k8_data cpumask\n");
ret_val = -ENOMEM; ret_val = -ENOMEM;
goto err_out_mem; goto err_out_mem;
} }
@ -885,9 +856,8 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
} }
if (freq != (data->acpi_data.states[i].core_frequency * 1000)) { if (freq != (data->acpi_data.states[i].core_frequency * 1000)) {
printk(KERN_INFO PFX "invalid freq entries " pr_info("invalid freq entries %u kHz vs. %u kHz\n",
"%u kHz vs. %u kHz\n", freq, freq, (unsigned int)
(unsigned int)
(data->acpi_data.states[i].core_frequency (data->acpi_data.states[i].core_frequency
* 1000)); * 1000));
invalidate_entry(powernow_table, i); invalidate_entry(powernow_table, i);
@ -916,7 +886,7 @@ static int get_transition_latency(struct powernow_k8_data *data)
max_latency = cur_latency; max_latency = cur_latency;
} }
if (max_latency == 0) { if (max_latency == 0) {
pr_err(FW_WARN PFX "Invalid zero transition latency\n"); pr_err(FW_WARN "Invalid zero transition latency\n");
max_latency = 1; max_latency = 1;
} }
/* value in usecs, needs to be in nanoseconds */ /* value in usecs, needs to be in nanoseconds */
@ -991,7 +961,7 @@ static long powernowk8_target_fn(void *arg)
checkvid = data->currvid; checkvid = data->currvid;
if (pending_bit_stuck()) { if (pending_bit_stuck()) {
printk(KERN_ERR PFX "failing targ, change pending bit set\n"); pr_err("failing targ, change pending bit set\n");
return -EIO; return -EIO;
} }
@ -1003,12 +973,11 @@ static long powernowk8_target_fn(void *arg)
return -EIO; return -EIO;
pr_debug("targ: curr fid 0x%x, vid 0x%x\n", pr_debug("targ: curr fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid); data->currfid, data->currvid);
if ((checkvid != data->currvid) || if ((checkvid != data->currvid) ||
(checkfid != data->currfid)) { (checkfid != data->currfid)) {
pr_info(PFX pr_info("error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
"error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
checkfid, data->currfid, checkfid, data->currfid,
checkvid, data->currvid); checkvid, data->currvid);
} }
@ -1020,7 +989,7 @@ static long powernowk8_target_fn(void *arg)
ret = transition_frequency_fidvid(data, newstate); ret = transition_frequency_fidvid(data, newstate);
if (ret) { if (ret) {
printk(KERN_ERR PFX "transition frequency failed\n"); pr_err("transition frequency failed\n");
mutex_unlock(&fidvid_mutex); mutex_unlock(&fidvid_mutex);
return 1; return 1;
} }
@ -1049,7 +1018,7 @@ static void powernowk8_cpu_init_on_cpu(void *_init_on_cpu)
struct init_on_cpu *init_on_cpu = _init_on_cpu; struct init_on_cpu *init_on_cpu = _init_on_cpu;
if (pending_bit_stuck()) { if (pending_bit_stuck()) {
printk(KERN_ERR PFX "failing init, change pending bit set\n"); pr_err("failing init, change pending bit set\n");
init_on_cpu->rc = -ENODEV; init_on_cpu->rc = -ENODEV;
return; return;
} }
@ -1064,11 +1033,10 @@ static void powernowk8_cpu_init_on_cpu(void *_init_on_cpu)
init_on_cpu->rc = 0; init_on_cpu->rc = 0;
} }
static const char missing_pss_msg[] = #define MISSING_PSS_MSG \
KERN_ERR FW_BUG "No compatible ACPI _PSS objects found.\n" \
FW_BUG PFX "No compatible ACPI _PSS objects found.\n" FW_BUG "First, make sure Cool'N'Quiet is enabled in the BIOS.\n" \
FW_BUG PFX "First, make sure Cool'N'Quiet is enabled in the BIOS.\n" FW_BUG "If that doesn't help, try upgrading your BIOS.\n"
FW_BUG PFX "If that doesn't help, try upgrading your BIOS.\n";
/* per CPU init entry point to the driver */ /* per CPU init entry point to the driver */
static int powernowk8_cpu_init(struct cpufreq_policy *pol) static int powernowk8_cpu_init(struct cpufreq_policy *pol)
@ -1083,7 +1051,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
data = kzalloc(sizeof(*data), GFP_KERNEL); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) { if (!data) {
printk(KERN_ERR PFX "unable to alloc powernow_k8_data"); pr_err("unable to alloc powernow_k8_data");
return -ENOMEM; return -ENOMEM;
} }
@ -1095,13 +1063,11 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
* an UP version, and is deprecated by AMD. * an UP version, and is deprecated by AMD.
*/ */
if (num_online_cpus() != 1) { if (num_online_cpus() != 1) {
printk_once(missing_pss_msg); pr_err_once(MISSING_PSS_MSG);
goto err_out; goto err_out;
} }
if (pol->cpu != 0) { if (pol->cpu != 0) {
printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for " pr_err(FW_BUG "No ACPI _PSS objects for CPU other than CPU0. Complain to your BIOS vendor.\n");
"CPU other than CPU0. Complain to your BIOS "
"vendor.\n");
goto err_out; goto err_out;
} }
rc = find_psb_table(data); rc = find_psb_table(data);
@ -1129,7 +1095,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
/* min/max the cpu is capable of */ /* min/max the cpu is capable of */
if (cpufreq_table_validate_and_show(pol, data->powernow_table)) { if (cpufreq_table_validate_and_show(pol, data->powernow_table)) {
printk(KERN_ERR FW_BUG PFX "invalid powernow_table\n"); pr_err(FW_BUG "invalid powernow_table\n");
powernow_k8_cpu_exit_acpi(data); powernow_k8_cpu_exit_acpi(data);
kfree(data->powernow_table); kfree(data->powernow_table);
kfree(data); kfree(data);
@ -1137,7 +1103,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
} }
pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid); data->currfid, data->currvid);
/* Point all the CPUs in this policy to the same data */ /* Point all the CPUs in this policy to the same data */
for_each_cpu(cpu, pol->cpus) for_each_cpu(cpu, pol->cpus)
@ -1220,12 +1186,12 @@ static void __request_acpi_cpufreq(void)
goto request; goto request;
if (strncmp(cur_drv, drv, min_t(size_t, strlen(cur_drv), strlen(drv)))) if (strncmp(cur_drv, drv, min_t(size_t, strlen(cur_drv), strlen(drv))))
pr_warn(PFX "WTF driver: %s\n", cur_drv); pr_warn("WTF driver: %s\n", cur_drv);
return; return;
request: request:
pr_warn(PFX "This CPU is not supported anymore, using acpi-cpufreq instead.\n"); pr_warn("This CPU is not supported anymore, using acpi-cpufreq instead.\n");
request_module(drv); request_module(drv);
} }
@ -1260,7 +1226,7 @@ static int powernowk8_init(void)
if (ret) if (ret)
return ret; return ret;
pr_info(PFX "Found %d %s (%d cpu cores) (" VERSION ")\n", pr_info("Found %d %s (%d cpu cores) (" VERSION ")\n",
num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus); num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus);
return ret; return ret;
@ -1274,8 +1240,8 @@ static void __exit powernowk8_exit(void)
cpufreq_unregister_driver(&cpufreq_amd64_driver); cpufreq_unregister_driver(&cpufreq_amd64_driver);
} }
MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and " MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com>");
"Mark Langsdorf <mark.langsdorf@amd.com>"); MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@amd.com>");
MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver."); MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

Some files were not shown because too many files have changed in this diff Show more