code:
==========================================
Reducing OS jitter due to per-cpu kthreads
==========================================

This document lists per-CPU kthreads in the Linux kernel and presents
options to control their OS jitter.  Note that non-per-CPU kthreads are
not listed here.  To reduce OS jitter from non-per-CPU kthreads, bind
them to a "housekeeping" CPU dedicated to such work.

References
==========

-	Documentation/core-api/irq/irq-affinity.rst:  Binding interrupts to sets of CPUs.

-	Documentation/admin-guide/cgroup-v1:  Using cgroups to bind tasks to sets of CPUs.

-	man taskset:  Using the taskset command to bind tasks to sets
	of CPUs.

-	man sched_setaffinity:  Using the sched_setaffinity() system
	call to bind tasks to sets of CPUs.

-	/sys/devices/system/cpu/cpuN/online:  Control CPU N's hotplug state,
	writing "0" to offline and "1" to online.

-	In order to locate kernel-generated OS jitter on CPU N:

		cd /sys/kernel/debug/tracing
		echo 1 > max_graph_depth # Increase the "1" for more detail
		echo function_graph > current_tracer
		# run workload
		cat per_cpu/cpuN/trace

kthreads
========

Name:
  ehca_comp/%u

Purpose:
  Periodically process Infiniband-related work.

To reduce its OS jitter, do any of the following:

1.	Don't use eHCA Infiniband hardware, instead choosing hardware
	that does not require per-CPU kthreads.  This will prevent these
	kthreads from being created in the first place.  (This will
	work for most people, as this hardware, though important, is
	relatively old and is produced in relatively low unit volumes.)
2.	Do all eHCA-Infiniband-related work on other CPUs, including
	interrupts.
3.	Rework the eHCA driver so that its per-CPU kthreads are
	provisioned only on selected CPUs.

Name:
  irq/%d-%s

Purpose:
  Handle threaded interrupts.

To reduce its OS jitter, do the following:

1.	Use irq affinity to force the irq threads to execute on
	some other CPU.

Name:
  kcmtpd_ctr_%d

Purpose:
  Handle Bluetooth work.

To reduce its OS jitter, do one of the following:

1.	Don't use Bluetooth, in which case these kthreads won't be
	created in the first place.
2.	Use irq affinity to force Bluetooth-related interrupts to
	occur on some other CPU and furthermore initiate all
	Bluetooth activity on some other CPU.

Name:
  ksoftirqd/%u

Purpose:
  Execute softirq handlers when threaded or when under heavy load.

To reduce its OS jitter, each softirq vector must be handled
separately as follows:

TIMER_SOFTIRQ
-------------

Do all of the following:

1.	To the extent possible, keep the CPU out of the kernel when it
	is non-idle, for example, by avoiding system calls and by forcing
	both kernel threads and interrupts to execute elsewhere.
2.	Build with CONFIG_HOTPLUG_CPU=y.  After boot completes, force
	the CPU offline, then bring it back online.  This forces
	recurring timers to migrate elsewhere.	If you are concerned
	with multiple CPUs, force them all offline before bringing the
	first one back online.  Once you have onlined the CPUs in question,
	do not offline any other CPUs, because doing so could force the
	timer back onto one of the CPUs in question.

NET_TX_SOFTIRQ and NET_RX_SOFTIRQ
---------------------------------

Do all of the following:

1.	Force networking interrupts onto other CPUs.
2.	Initiate any network I/O on other CPUs.
3.	Once your application has started, prevent CPU-hotplug operations
	from being initiated from tasks that might run on the CPU to
	be de-jittered.  (It is OK to force this CPU offline and then
	bring it back online before you start your application.)

BLOCK_SOFTIRQ
-------------

Do all of the following:

1.	Force block-device interrupts onto some other CPU.
2.	Initiate any block I/O on other CPUs.
3.	Once your application has started, prevent CPU-hotplug operations
	from being initiated from tasks that might run on the CPU to
	be de-jittered.  (It is OK to force this CPU offline and then
	bring it back online before you start your application.)

IRQ_POLL_SOFTIRQ
----------------

Do all of the following:

1.	Force block-device interrupts onto some other CPU.
2.	Initiate any block I/O and block-I/O polling on other CPUs.
3.	Once your application has started, prevent CPU-hotplug operations
	from being initiated from tasks that might run on the CPU to
	be de-jittered.  (It is OK to force this CPU offline and then
	bring it back online before you start your application.)

TASKLET_SOFTIRQ
---------------

Do one or more of the following:

1.	Avoid use of drivers that use tasklets.  (Such drivers will contain
	calls to things like tasklet_schedule().)
2.	Convert all drivers that you must use from tasklets to workqueues.
3.	Force interrupts for drivers using tasklets onto other CPUs,
	and also do I/O involving these drivers on other CPUs.

SCHED_SOFTIRQ
-------------

Do all of the following:

1.	Avoid sending scheduler IPIs to the CPU to be de-jittered,
	for example, ensure that at most one runnable kthread is present
	on that CPU.  If a thread that expects to run on the de-jittered
	CPU awakens, the scheduler will send an IPI that can result in
	a subsequent SCHED_SOFTIRQ.
2.	CONFIG_NO_HZ_FULL=y and ensure that the CPU to be de-jittered
	is marked as an adaptive-ticks CPU using the "nohz_full="
	boot parameter.  This reduces the number of scheduler-clock
	interrupts that the de-jittered CPU receives, minimizing its
	chances of being selected to do the load balancing work that
	runs in SCHED_SOFTIRQ context.
3.	To the extent possible, keep the CPU out of the kernel when it
	is non-idle, for example, by avoiding system calls and by
	forcing both kernel threads and interrupts to execute elsewhere.
	This further reduces the number of scheduler-clock interrupts
	received by the de-jittered CPU.

HRTIMER_SOFTIRQ
---------------

Do all of the following:

1.	To the extent possible, keep the CPU out of the kernel when it
	is non-idle.  For example, avoid system calls and force both
	kernel threads and interrupts to execute elsewhere.
2.	Build with CONFIG_HOTPLUG_CPU=y.  Once boot completes, force the
	CPU offline, then bring it back online.  This forces recurring
	timers to migrate elsewhere.  If you are concerned with multiple
	CPUs, force them all offline before bringing the first one
	back online.  Once you have onlined the CPUs in question, do not
	offline any other CPUs, because doing so could force the timer
	back onto one of the CPUs in question.

RCU_SOFTIRQ
-----------

Do at least one of the following:

1.	Offload callbacks and keep the CPU in either dyntick-idle or
	adaptive-ticks state by doing all of the following:

	a.	CONFIG_NO_HZ_FULL=y and ensure that the CPU to be
		de-jittered is marked as an adaptive-ticks CPU using the
		"nohz_full=" boot parameter.  Bind the rcuo kthreads to
		housekeeping CPUs, which can tolerate OS jitter.
	b.	To the extent possible, keep the CPU out of the kernel
		when it is non-idle, for example, by avoiding system
		calls and by forcing both kernel threads and interrupts
		to execute elsewhere.

2.	Enable RCU to do its processing remotely via dyntick-idle by
	doing all of the following:

	a.	Build with CONFIG_NO_HZ=y.
	b.	Ensure that the CPU goes idle frequently, allowing other
		CPUs to detect that it has passed through an RCU quiescent
		state.	If the kernel is built with CONFIG_NO_HZ_FULL=y,
		userspace execution also allows other CPUs to detect that
		the CPU in question has passed through a quiescent state.
	c.	To the extent possible, keep the CPU out of the kernel
		when it is non-idle, for example, by avoiding system
		calls and by forcing both kernel threads and interrupts
		to execute elsewhere.

Name:
  kworker/%u:%d%s (cpu, id, priority)

Purpose:
  Execute workqueue requests

To reduce its OS jitter, do any of the following:

1.	Run your workload at a real-time priority, which will allow
	preempting the kworker daemons.
2.	A given workqueue can be made visible in the sysfs filesystem
	by passing the WQ_SYSFS to that workqueue's alloc_workqueue().
	Such a workqueue can be confined to a given subset of the
	CPUs using the ``/sys/devices/virtual/workqueue/*/cpumask`` sysfs
	files.	The set of WQ_SYSFS workqueues can be displayed using
	"ls /sys/devices/virtual/workqueue".  That said, the workqueues
	maintainer would like to caution people against indiscriminately
	sprinkling WQ_SYSFS across all the workqueues.	The reason for
	caution is that it is easy to add WQ_SYSFS, but because sysfs is
	part of the formal user/kernel API, it can be nearly impossible
	to remove it, even if its addition was a mistake.
3.	Do any of the following needed to avoid jitter that your
	application cannot tolerate:

	a.	Build your kernel with CONFIG_SLUB=y rather than
		CONFIG_SLAB=y, thus avoiding the slab allocator's periodic
		use of each CPU's workqueues to run its cache_reap()
		function.
	b.	Avoid using oprofile, thus avoiding OS jitter from
		wq_sync_buffer().
	c.	Limit your CPU frequency so that a CPU-frequency
		governor is not required, possibly enlisting the aid of
		special heatsinks or other cooling technologies.  If done
		correctly, and if you CPU architecture permits, you should
		be able to build your kernel with CONFIG_CPU_FREQ=n to
		avoid the CPU-frequency governor periodically running
		on each CPU, including cs_dbs_timer() and od_dbs_timer().

		WARNING:  Please check your CPU specifications to
		make sure that this is safe on your particular system.
	d.	As of v3.18, Christoph Lameter's on-demand vmstat workers
		commit prevents OS jitter due to vmstat_update() on
		CONFIG_SMP=y systems.  Before v3.18, is not possible
		to entirely get rid of the OS jitter, but you can
		decrease its frequency by writing a large value to
		/proc/sys/vm/stat_interval.  The default value is HZ,
		for an interval of one second.	Of course, larger values
		will make your virtual-memory statistics update more
		slowly.  Of course, you can also run your workload at
		a real-time priority, thus preempting vmstat_update(),
		but if your workload is CPU-bound, this is a bad idea.
		However, there is an RFC patch from Christoph Lameter
		(based on an earlier one from Gilad Ben-Yossef) that
		reduces or even eliminates vmstat overhead for some
		workloads at https://lore.kernel.org/r/00000140e9dfd6bd-40db3d4f-c1be-434f-8132-7820f81bb586-000000@email.amazonses.com.
	e.	If running on high-end powerpc servers, build with
		CONFIG_PPC_RTAS_DAEMON=n.  This prevents the RTAS
		daemon from running on each CPU every second or so.
		(This will require editing Kconfig files and will defeat
		this platform's RAS functionality.)  This avoids jitter
		due to the rtas_event_scan() function.
		WARNING:  Please check your CPU specifications to
		make sure that this is safe on your particular system.
	f.	If running on Cell Processor, build your kernel with
		CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from
		spu_gov_work().
		WARNING:  Please check your CPU specifications to
		make sure that this is safe on your particular system.
	g.	If running on PowerMAC, build your kernel with
		CONFIG_PMAC_RACKMETER=n to disable the CPU-meter,
		avoiding OS jitter from rackmeter_do_timer().

Name:
  rcuc/%u

Purpose:
  Execute RCU callbacks in CONFIG_RCU_BOOST=y kernels.

To reduce its OS jitter, do at least one of the following:

1.	Build the kernel with CONFIG_PREEMPT=n.  This prevents these
	kthreads from being created in the first place, and also obviates
	the need for RCU priority boosting.  This approach is feasible
	for workloads that do not require high degrees of responsiveness.
2.	Build the kernel with CONFIG_RCU_BOOST=n.  This prevents these
	kthreads from being created in the first place.  This approach
	is feasible only if your workload never requires RCU priority
	boosting, for example, if you ensure frequent idle time on all
	CPUs that might execute within the kernel.
3.	Build with CONFIG_RCU_NOCB_CPU=y and boot with the rcu_nocbs=
	boot parameter offloading RCU callbacks from all CPUs susceptible
	to OS jitter.  This approach prevents the rcuc/%u kthreads from
	having any work to do, so that they are never awakened.
4.	Ensure that the CPU never enters the kernel, and, in particular,
	avoid initiating any CPU hotplug operations on this CPU.  This is
	another way of preventing any callbacks from being queued on the
	CPU, again preventing the rcuc/%u kthreads from having any work
	to do.

Name:
  rcuop/%d and rcuos/%d

Purpose:
  Offload RCU callbacks from the corresponding CPU.

To reduce its OS jitter, do at least one of the following:

1.	Use affinity, cgroups, or other mechanism to force these kthreads
	to execute on some other CPU.
2.	Build with CONFIG_RCU_NOCB_CPU=n, which will prevent these
	kthreads from being created in the first place.  However, please
	note that this will not eliminate OS jitter, but will instead
	shift it to RCU_SOFTIRQ.

repo_name: angery/linux


code:
==================
Asus Laptop Extras
==================

Version 0.1

August 6, 2009

Corentin Chary <corentincj@iksaif.net>
http://acpi4asus.sf.net/

 This driver provides support for extra features of ACPI-compatible ASUS laptops.
 It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or
 VICTOR XP7210 for example). It makes all the extra buttons generate input
 events (like keyboards).

 On some models adds support for changing the display brightness and output,
 switching the LCD backlight on and off, and most importantly, allows you to
 blink those fancy LEDs intended for reporting mail and wireless status.

This driver supersedes the old asus_acpi driver.

Requirements
------------

  Kernel 2.6.X sources, configured for your computer, with ACPI support.
  You also need CONFIG_INPUT and CONFIG_ACPI.

Status
------

 The features currently supported are the following (see below for
 detailed description):

 - Fn key combinations
 - Bluetooth enable and disable
 - Wlan enable and disable
 - GPS enable and disable
 - Video output switching
 - Ambient Light Sensor on and off
 - LED control
 - LED Display control
 - LCD brightness control
 - LCD on and off

 A compatibility table by model and feature is maintained on the web
 site, http://acpi4asus.sf.net/.

Usage
-----

  Try "modprobe asus-laptop". Check your dmesg (simply type dmesg). You should
  see some lines like this :

      Asus Laptop Extras version 0.42
        - L2D model detected.

  If it is not the output you have on your laptop, send it (and the laptop's
  DSDT) to me.

  That's all, now, all the events generated by the hotkeys of your laptop
  should be reported via netlink events. You can check with
  "acpi_genl monitor" (part of the acpica project).

  Hotkeys are also reported as input keys (like keyboards) you can check
  which key are supported using "xev" under X11.

  You can get information on the version of your DSDT table by reading the
  /sys/devices/platform/asus-laptop/infos entry. If you have a question or a
  bug report to do, please include the output of this entry.

LEDs
----

  You can modify LEDs be echoing values to `/sys/class/leds/asus/*/brightness`::

    echo 1 >  /sys/class/leds/asus::mail/brightness

  will switch the mail LED on.

  You can also know if they are on/off by reading their content and use
  kernel triggers like disk-activity or heartbeat.

Backlight
---------

  You can control lcd backlight power and brightness with
  /sys/class/backlight/asus-laptop/. Brightness Values are between 0 and 15.

Wireless devices
----------------

  You can turn the internal Bluetooth adapter on/off with the bluetooth entry
  (only on models with Bluetooth). This usually controls the associated LED.
  Same for Wlan adapter.

Display switching
-----------------

  Note: the display switching code is currently considered EXPERIMENTAL.

  Switching works for the following models:

    - L3800C
    - A2500H
    - L5800C
    - M5200N
    - W1000N (albeit with some glitches)
    - M6700R
    - A6JC
    - F3J

  Switching doesn't work for the following:

    - M3700N
    - L2X00D (locks the laptop under certain conditions)

  To switch the displays, echo values from 0 to 15 to
  /sys/devices/platform/asus-laptop/display. The significance of those values
  is as follows:

  +-------+-----+-----+-----+-----+-----+
  | Bin   | Val | DVI | TV  | CRT | LCD |
  +-------+-----+-----+-----+-----+-----+
  | 0000  |   0 |     |     |     |     |
  +-------+-----+-----+-----+-----+-----+
  | 0001  |   1 |     |     |     |  X  |
  +-------+-----+-----+-----+-----+-----+
  | 0010  |   2 |     |     |  X  |     |
  +-------+-----+-----+-----+-----+-----+
  | 0011  |   3 |     |     |  X  |  X  |
  +-------+-----+-----+-----+-----+-----+
  | 0100  |   4 |     |  X  |     |     |
  +-------+-----+-----+-----+-----+-----+
  | 0101  |   5 |     |  X  |     | X   |
  +-------+-----+-----+-----+-----+-----+
  | 0110  |   6 |     |  X  |  X  |     |
  +-------+-----+-----+-----+-----+-----+
  | 0111  |   7 |     |  X  |  X  |  X  |
  +-------+-----+-----+-----+-----+-----+
  | 1000  |   8 |  X  |     |     |     |
  +-------+-----+-----+-----+-----+-----+
  | 1001  |   9 |  X  |     |     |  X  |
  +-------+-----+-----+-----+-----+-----+
  | 1010  |  10 |  X  |     |  X  |     |
  +-------+-----+-----+-----+-----+-----+
  | 1011  |  11 |  X  |     |  X  |  X  |
  +-------+-----+-----+-----+-----+-----+
  | 1100  |  12 |  X  |  X  |     |     |
  +-------+-----+-----+-----+-----+-----+
  | 1101  |  13 |  X  |  X  |     |  X  |
  +-------+-----+-----+-----+-----+-----+
  | 1110  |  14 |  X  |  X  |  X  |     |
  +-------+-----+-----+-----+-----+-----+
  | 1111  |  15 |  X  |  X  |  X  |  X  |
  +-------+-----+-----+-----+-----+-----+

  In most cases, the appropriate displays must be plugged in for the above
  combinations to work. TV-Out may need to be initialized at boot time.

  Debugging:

  1) Check whether the Fn+F8 key:

     a) does not lock the laptop (try a boot with noapic / nolapic if it does)
     b) generates events (0x6n, where n is the value corresponding to the
        configuration above)
     c) actually works

     Record the disp value at every configuration.
  2) Echo values from 0 to 15 to /sys/devices/platform/asus-laptop/display.
     Record its value, note any change. If nothing changes, try a broader range,
     up to 65535.
  3) Send ANY output (both positive and negative reports are needed, unless your
     machine is already listed above) to the acpi4asus-user mailing list.

  Note: on some machines (e.g. L3C), after the module has been loaded, only 0x6n
  events are generated and no actual switching occurs. In such a case, a line
  like::

    echo $((10#$arg-60)) > /sys/devices/platform/asus-laptop/display

  will usually do the trick ($arg is the 0000006n-like event passed to acpid).

  Note: there is currently no reliable way to read display status on xxN
  (Centrino) models.

LED display
-----------

  Some models like the W1N have a LED display that can be used to display
  several items of information.

  LED display works for the following models:

    - W1000N
    - W1J

  To control the LED display, use the following::

    echo 0x0T000DDD > /sys/devices/platform/asus-laptop/

  where T control the 3 letters display, and DDD the 3 digits display,
  according to the tables below::

         DDD (digits)
         000 to 999 = display digits
         AAA        = ---
         BBB to FFF = turn-off

         T  (type)
         0 = off
         1 = dvd
         2 = vcd
         3 = mp3
         4 = cd
         5 = tv
         6 = cpu
         7 = vol

  For example "echo 0x01000001 >/sys/devices/platform/asus-laptop/ledd"
  would display "DVD001".

Driver options
--------------

 Options can be passed to the asus-laptop driver using the standard
 module argument syntax (<param>=<value> when passing the option to the
 module or asus-laptop.<param>=<value> on the kernel boot line when
 asus-laptop is statically linked into the kernel).

	     wapf: WAPF defines the behavior of the Fn+Fx wlan key
		   The significance of values is yet to be found, but
		   most of the time:

		   - 0x0 should do nothing
		   - 0x1 should allow to control the device with Fn+Fx key.
		   - 0x4 should send an ACPI event (0x88) while pressing the Fn+Fx key
		   - 0x5 like 0x1 or 0x4

 The default value is 0x1.

Unsupported models
------------------

 These models will never be supported by this module, as they use a completely
 different mechanism to handle LEDs and extra stuff (meaning we have no clue
 how it works):

 - ASUS A1300 (A1B), A1370D
 - ASUS L7300G
 - ASUS L8400

Patches, Errors, Questions
--------------------------

 I appreciate any success or failure
 reports, especially if they add to or correct the compatibility table.
 Please include the following information in your report:

 - Asus model name
 - a copy of your ACPI tables, using the "acpidump" utility
 - a copy of /sys/devices/platform/asus-laptop/infos
 - which driver features work and which don't
 - the observed behavior of non-working features

 Any other comments or patches are also more than welcome.

 acpi4asus-user@lists.sourceforge.net

 http://sourceforge.net/projects/acpi4asus


code:
==========================
Hard disk shock protection
==========================

Author: Elias Oltmanns <eo@nebensachen.de>

Last modified: 2008-10-03

.. 0. Contents

   1. Intro
   2. The interface
   3. References
   4. CREDITS

1. Intro
--------

ATA/ATAPI-7 specifies the IDLE IMMEDIATE command with unload feature.
Issuing this command should cause the drive to switch to idle mode and
unload disk heads. This feature is being used in modern laptops in
conjunction with accelerometers and appropriate software to implement
a shock protection facility. The idea is to stop all I/O operations on
the internal hard drive and park its heads on the ramp when critical
situations are anticipated. The desire to have such a feature
available on GNU/Linux systems has been the original motivation to
implement a generic disk head parking interface in the Linux kernel.
Please note, however, that other components have to be set up on your
system in order to get disk shock protection working (see
section 3. References below for pointers to more information about
that).

2. The interface
----------------

For each ATA device, the kernel exports the file
`block/*/device/unload_heads` in sysfs (here assumed to be mounted under
/sys). Access to `/sys/block/*/device/unload_heads` is denied with
-EOPNOTSUPP if the device does not support the unload feature.
Otherwise, writing an integer value to this file will take the heads
of the respective drive off the platter and block all I/O operations
for the specified number of milliseconds. When the timeout expires and
no further disk head park request has been issued in the meantime,
normal operation will be resumed. The maximal value accepted for a
timeout is 30000 milliseconds. Exceeding this limit will return
-EOVERFLOW, but heads will be parked anyway and the timeout will be
set to 30 seconds. However, you can always change a timeout to any
value between 0 and 30000 by issuing a subsequent head park request
before the timeout of the previous one has expired. In particular, the
total timeout can exceed 30 seconds and, more importantly, you can
cancel a previously set timeout and resume normal operation
immediately by specifying a timeout of 0. Values below -2 are rejected
with -EINVAL (see below for the special meaning of -1 and -2). If the
timeout specified for a recent head park request has not yet expired,
reading from `/sys/block/*/device/unload_heads` will report the number
of milliseconds remaining until normal operation will be resumed;
otherwise, reading the unload_heads attribute will return 0.

For example, do the following in order to park the heads of drive
/dev/sda and stop all I/O operations for five seconds::

	# echo 5000 > /sys/block/sda/device/unload_heads

A simple::

	# cat /sys/block/sda/device/unload_heads

will show you how many milliseconds are left before normal operation
will be resumed.

A word of caution: The fact that the interface operates on a basis of
milliseconds may raise expectations that cannot be satisfied in
reality. In fact, the ATA specs clearly state that the time for an
unload operation to complete is vendor specific. The hint in ATA-7
that this will typically be within 500 milliseconds apparently has
been dropped in ATA-8.

There is a technical detail of this implementation that may cause some
confusion and should be discussed here. When a head park request has
been issued to a device successfully, all I/O operations on the
controller port this device is attached to will be deferred. That is
to say, any other device that may be connected to the same port will
be affected too. The only exception is that a subsequent head unload
request to that other device will be executed immediately. Further
operations on that port will be deferred until the timeout specified
for either device on the port has expired. As far as PATA (old style
IDE) configurations are concerned, there can only be two devices
attached to any single port. In SATA world we have port multipliers
which means that a user-issued head parking request to one device may
actually result in stopping I/O to a whole bunch of devices. However,
since this feature is supposed to be used on laptops and does not seem
to be very useful in any other environment, there will be mostly one
device per port. Even if the CD/DVD writer happens to be connected to
the same port as the hard drive, it generally *should* recover just
fine from the occasional buffer under-run incurred by a head park
request to the HD. Actually, when you are using an ide driver rather
than its libata counterpart (i.e. your disk is called /dev/hda
instead of /dev/sda), then parking the heads of one drive (drive X)
will generally not affect the mode of operation of another drive
(drive Y) on the same port as described above. It is only when a port
reset is required to recover from an exception on drive Y that further
I/O operations on that drive (and the reset itself) will be delayed
until drive X is no longer in the parked state.

Finally, there are some hard drives that only comply with an earlier
version of the ATA standard than ATA-7, but do support the unload
feature nonetheless. Unfortunately, there is no safe way Linux can
detect these devices, so you won't be able to write to the
unload_heads attribute. If you know that your device really does
support the unload feature (for instance, because the vendor of your
laptop or the hard drive itself told you so), then you can tell the
kernel to enable the usage of this feature for that drive by writing
the special value -1 to the unload_heads attribute::

	# echo -1 > /sys/block/sda/device/unload_heads

will enable the feature for /dev/sda, and giving -2 instead of -1 will
disable it again.

3. References
-------------

There are several laptops from different vendors featuring shock
protection capabilities. As manufacturers have refused to support open
source development of the required software components so far, Linux
support for shock protection varies considerably between different
hardware implementations. Ideally, this section should contain a list
of pointers at different projects aiming at an implementation of shock
protection on different systems. Unfortunately, I only know of a
single project which, although still considered experimental, is fit
for use. Please feel free to add projects that have been the victims
of my ignorance.

- https://www.thinkwiki.org/wiki/HDAPS

  See this page for information about Linux support of the hard disk
  active protection system as implemented in IBM/Lenovo Thinkpads.

4. CREDITS
----------

This implementation of disk head parking has been inspired by a patch
originally published by Jon Escombe <lists@dresco.co.uk>. My efforts
to develop an implementation of this feature that is fit to be merged
into mainline have been aided by various kernel developers, in
particular by Tejun Heo and Bartlomiej Zolnierkiewicz.


code:
.. SPDX-License-Identifier: GPL-2.0

==============
Laptop Drivers
==============

.. toctree::
   :maxdepth: 1

   asus-laptop
   disk-shock-protection
   laptop-mode
   lg-laptop
   sony-laptop
   sonypi
   thinkpad-acpi
   toshiba_haps


code:
===============================================
How to conserve battery power using laptop-mode
===============================================

Document Author: Bart Samwel (bart@samwel.tk)

Date created: January 2, 2004

Last modified: December 06, 2004

Introduction
------------

Laptop mode is used to minimize the time that the hard disk needs to be spun up,
to conserve battery power on laptops. It has been reported to cause significant
power savings.

.. Contents

   * Introduction
   * Installation
   * Caveats
   * The Details
   * Tips & Tricks
   * Control script
   * ACPI integration
   * Monitoring tool

Installation
------------

To use laptop mode, you don't need to set any kernel configuration options
or anything. Simply install all the files included in this document, and
laptop mode will automatically be started when you're on battery. For
your convenience, a tarball containing an installer can be downloaded at:

	http://www.samwel.tk/laptop_mode/laptop_mode/

To configure laptop mode, you need to edit the configuration file, which is
located in /etc/default/laptop-mode on Debian-based systems, or in
/etc/sysconfig/laptop-mode on other systems.

Unfortunately, automatic enabling of laptop mode does not work for
laptops that don't have ACPI. On those laptops, you need to start laptop
mode manually. To start laptop mode, run "laptop_mode start", and to
stop it, run "laptop_mode stop". (Note: The laptop mode tools package now
has experimental support for APM, you might want to try that first.)

Caveats
-------

* The downside of laptop mode is that you have a chance of losing up to 10
  minutes of work. If you cannot afford this, don't use it! The supplied ACPI
  scripts automatically turn off laptop mode when the battery almost runs out,
  so that you won't lose any data at the end of your battery life.

* Most desktop hard drives have a very limited lifetime measured in spindown
  cycles, typically about 50.000 times (it's usually listed on the spec sheet).
  Check your drive's rating, and don't wear down your drive's lifetime if you
  don't need to.

* If you mount some of your ext3/reiserfs filesystems with the -n option, then
  the control script will not be able to remount them correctly. You must set
  DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
  wrong options -- or it will fail because it cannot write to /etc/mtab.

* If you have your filesystems listed as type "auto" in fstab, like I did, then
  the control script will not recognize them as filesystems that need remounting.
  You must list the filesystems with their true type instead.

* It has been reported that some versions of the mutt mail client use file access
  times to determine whether a folder contains new mail. If you use mutt and
  experience this, you must disable the noatime remounting by setting the option
  DO_REMOUNT_NOATIME to 0 in the configuration file.

The Details
-----------

Laptop mode is controlled by the knob /proc/sys/vm/laptop_mode. This knob is
present for all kernels that have the laptop mode patch, regardless of any
configuration options. When the knob is set, any physical disk I/O (that might
have caused the hard disk to spin up) causes Linux to flush all dirty blocks. The
result of this is that after a disk has spun down, it will not be spun up
anymore to write dirty blocks, because those blocks had already been written
immediately after the most recent read operation. The value of the laptop_mode
knob determines the time between the occurrence of disk I/O and when the flush
is triggered. A sensible value for the knob is 5 seconds. Setting the knob to
0 disables laptop mode.

To increase the effectiveness of the laptop_mode strategy, the laptop_mode
control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
/proc/sys/vm to about 10 minutes (by default), which means that pages that are
dirtied are not forced to be written to disk as often. The control script also
changes the dirty background ratio, so that background writeback of dirty pages
is not done anymore. Combined with a higher commit value (also 10 minutes) for
ext3 or ReiserFS filesystems (also done automatically by the control script),
this results in concentration of disk activity in a small time interval which
occurs only once every 10 minutes, or whenever the disk is forced to spin up by
a cache miss. The disk can then be spun down in the periods of inactivity.

Configuration
-------------

The laptop mode configuration file is located in /etc/default/laptop-mode on
Debian-based systems, or in /etc/sysconfig/laptop-mode on other systems. It
contains the following options:

MAX_AGE:

Maximum time, in seconds, of hard drive spindown time that you are
comfortable with. Worst case, it's possible that you could lose this
amount of work if your battery fails while you're in laptop mode.

MINIMUM_BATTERY_MINUTES:

Automatically disable laptop mode if the remaining number of minutes of
battery power is less than this value. Default is 10 minutes.

AC_HD/BATT_HD:

The idle timeout that should be set on your hard drive when laptop mode
is active (BATT_HD) and when it is not active (AC_HD). The defaults are
20 seconds (value 4) for BATT_HD  and 2 hours (value 244) for AC_HD. The
possible values are those listed in the manual page for "hdparm" for the
"-S" option.

HD:

The devices for which the spindown timeout should be adjusted by laptop mode.
Default is /dev/hda. If you specify multiple devices, separate them by a space.

READAHEAD:

Disk readahead, in 512-byte sectors, while laptop mode is active. A large
readahead can prevent disk accesses for things like executable pages (which are
loaded on demand while the application executes) and sequentially accessed data
(MP3s).

DO_REMOUNTS:

The control script automatically remounts any mounted journaled filesystems
with appropriate commit interval options. When this option is set to 0, this
feature is disabled.

DO_REMOUNT_NOATIME:

When remounting, should the filesystems be remounted with the noatime option?
Normally, this is set to "1" (enabled), but there may be programs that require
access time recording.

DIRTY_RATIO:

The percentage of memory that is allowed to contain "dirty" or unsaved data
before a writeback is forced, while laptop mode is active. Corresponds to
the /proc/sys/vm/dirty_ratio sysctl.

DIRTY_BACKGROUND_RATIO:

The percentage of memory that is allowed to contain "dirty" or unsaved data
after a forced writeback is done due to an exceeding of DIRTY_RATIO. Set
this nice and low. This corresponds to the /proc/sys/vm/dirty_background_ratio
sysctl.

Note that the behaviour of dirty_background_ratio is quite different
when laptop mode is active and when it isn't. When laptop mode is inactive,
dirty_background_ratio is the threshold percentage at which background writeouts
start taking place. When laptop mode is active, however, background writeouts
are disabled, and the dirty_background_ratio only determines how much writeback
is done when dirty_ratio is reached.

DO_CPU:

Enable CPU frequency scaling when in laptop mode. (Requires CPUFreq to be setup.
See Documentation/admin-guide/pm/cpufreq.rst for more info. Disabled by default.)

CPU_MAXFREQ:

When on battery, what is the maximum CPU speed that the system should use? Legal
values are "slowest" for the slowest speed that your CPU is able to operate at,
or a value listed in /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies.

Tips & Tricks
-------------

* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
  of his regular 3 to 3.5 hours) using a spindown time of 5 seconds (BATT_HD=1).

* You can spin down the disk while playing MP3, by setting disk readahead
  to 8MB (READAHEAD=16384). Effectively, the disk will read a complete MP3 at
  once, and will then spin down while the MP3 is playing. (Thanks to Bartek
  Kania.)

* Drew Scott Daniels observed: "I don't know why, but when I decrease the number
  of colours that my display uses it consumes less battery power. I've seen
  this on powerbooks too. I hope that this is a piece of information that
  might be useful to the Laptop Mode patch or its users."

* In syslog.conf, you can prefix entries with a dash `-` to omit syncing the
  file after every logging. When you're using laptop-mode and your disk doesn't
  spin down, this is a likely culprit.

* Richard Atterer observed that laptop mode does not work well with noflushd
  (http://noflushd.sourceforge.net/), it seems that noflushd prevents laptop-mode
  from doing its thing.

* If you're worried about your data, you might want to consider using a USB
  memory stick or something like that as a "working area". (Be aware though
  that flash memory can only handle a limited number of writes, and overuse
  may wear out your memory stick pretty quickly. Do _not_ use journalling
  filesystems on flash memory sticks.)

Configuration file for control and ACPI battery scripts
-------------------------------------------------------

This allows the tunables to be changed for the scripts via an external
configuration file

It should be installed as /etc/default/laptop-mode on Debian, and as
/etc/sysconfig/laptop-mode on Red Hat, SUSE, Mandrake, and other work-alikes.

Config file::

  # Maximum time, in seconds, of hard drive spindown time that you are
  # comfortable with. Worst case, it's possible that you could lose this
  # amount of work if your battery fails you while in laptop mode.
  #MAX_AGE=600

  # Automatically disable laptop mode when the number of minutes of battery
  # that you have left goes below this threshold.
  MINIMUM_BATTERY_MINUTES=10

  # Read-ahead, in 512-byte sectors. You can spin down the disk while playing MP3/OGG
  # by setting the disk readahead to 8MB (READAHEAD=16384). Effectively, the disk
  # will read a complete MP3 at once, and will then spin down while the MP3/OGG is
  # playing.
  #READAHEAD=4096

  # Shall we remount journaled fs. with appropriate commit interval? (1=yes)
  #DO_REMOUNTS=1

  # And shall we add the "noatime" option to that as well? (1=yes)
  #DO_REMOUNT_NOATIME=1

  # Dirty synchronous ratio.  At this percentage of dirty pages the process
  # which
  # calls write() does its own writeback
  #DIRTY_RATIO=40

  #
  # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
  # exceeded, the kernel will wake flusher threads which will then reduce the
  # amount of dirty memory to dirty_background_ratio.  Set this nice and low,
  # so once some writeout has commenced, we do a lot of it.
  #
  #DIRTY_BACKGROUND_RATIO=5

  # kernel default dirty buffer age
  #DEF_AGE=30
  #DEF_UPDATE=5
  #DEF_DIRTY_BACKGROUND_RATIO=10
  #DEF_DIRTY_RATIO=40
  #DEF_XFS_AGE_BUFFER=15
  #DEF_XFS_SYNC_INTERVAL=30
  #DEF_XFS_BUFD_INTERVAL=1

  # This must be adjusted manually to the value of HZ in the running kernel
  # on 2.4, until the XFS people change their 2.4 external interfaces to work in
  # centisecs. This can be automated, but it's a work in progress that still
  # needs# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for
  # external interfaces, and that is currently always set to 100. So you don't
  # need to change this on 2.6.
  #XFS_HZ=100

  # Should the maximum CPU frequency be adjusted down while on battery?
  # Requires CPUFreq to be setup.
  # See Documentation/admin-guide/pm/cpufreq.rst for more info
  #DO_CPU=0

  # When on battery what is the maximum CPU speed that the system should
  # use? Legal values are "slowest" for the slowest speed that your
  # CPU is able to operate at, or a value listed in:
  # /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
  # Only applicable if DO_CPU=1.
  #CPU_MAXFREQ=slowest

  # Idle timeout for your hard drive (man hdparm for valid values, -S option)
  # Default is 2 hours on AC (AC_HD=244) and 20 seconds for battery (BATT_HD=4).
  #AC_HD=244
  #BATT_HD=4

  # The drives for which to adjust the idle timeout. Separate them by a space,
  # e.g. HD="/dev/hda /dev/hdb".
  #HD="/dev/hda"

  # Set the spindown timeout on a hard drive?
  #DO_HD=1

Control script
--------------

Please note that this control script works for the Linux 2.4 and 2.6 series (thanks
to Kiko Piris).

Control script::

  #!/bin/bash

  # start or stop laptop_mode, best run by a power management daemon when
  # ac gets connected/disconnected from a laptop
  #
  # install as /sbin/laptop_mode
  #
  # Contributors to this script:   Kiko Piris
  #				 Bart Samwel
  #				 Micha Feigin
  #				 Andrew Morton
  #				 Herve Eychenne
  #				 Dax Kelson
  #
  # Original Linux 2.4 version by: Jens Axboe

  #############################################################################

  # Source config
  if [ -f /etc/default/laptop-mode ] ; then
	# Debian
	. /etc/default/laptop-mode
  elif [ -f /etc/sysconfig/laptop-mode ] ; then
	# Others
          . /etc/sysconfig/laptop-mode
  fi

  # Don't raise an error if the config file is incomplete
  # set defaults instead:

  # Maximum time, in seconds, of hard drive spindown time that you are
  # comfortable with. Worst case, it's possible that you could lose this
  # amount of work if your battery fails you while in laptop mode.
  MAX_AGE=${MAX_AGE:-'600'}

  # Read-ahead, in kilobytes
  READAHEAD=${READAHEAD:-'4096'}

  # Shall we remount journaled fs. with appropriate commit interval? (1=yes)
  DO_REMOUNTS=${DO_REMOUNTS:-'1'}

  # And shall we add the "noatime" option to that as well? (1=yes)
  DO_REMOUNT_NOATIME=${DO_REMOUNT_NOATIME:-'1'}

  # Shall we adjust the idle timeout on a hard drive?
  DO_HD=${DO_HD:-'1'}

  # Adjust idle timeout on which hard drive?
  HD="${HD:-'/dev/hda'}"

  # spindown time for HD (hdparm -S values)
  AC_HD=${AC_HD:-'244'}
  BATT_HD=${BATT_HD:-'4'}

  # Dirty synchronous ratio.  At this percentage of dirty pages the process which
  # calls write() does its own writeback
  DIRTY_RATIO=${DIRTY_RATIO:-'40'}

  # cpu frequency scaling
  # See Documentation/admin-guide/pm/cpufreq.rst for more info
  DO_CPU=${CPU_MANAGE:-'0'}
  CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}

  #
  # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
  # exceeded, the kernel will wake flusher threads which will then reduce the
  # amount of dirty memory to dirty_background_ratio.  Set this nice and low,
  # so once some writeout has commenced, we do a lot of it.
  #
  DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'}

  # kernel default dirty buffer age
  DEF_AGE=${DEF_AGE:-'30'}
  DEF_UPDATE=${DEF_UPDATE:-'5'}
  DEF_DIRTY_BACKGROUND_RATIO=${DEF_DIRTY_BACKGROUND_RATIO:-'10'}
  DEF_DIRTY_RATIO=${DEF_DIRTY_RATIO:-'40'}
  DEF_XFS_AGE_BUFFER=${DEF_XFS_AGE_BUFFER:-'15'}
  DEF_XFS_SYNC_INTERVAL=${DEF_XFS_SYNC_INTERVAL:-'30'}
  DEF_XFS_BUFD_INTERVAL=${DEF_XFS_BUFD_INTERVAL:-'1'}

  # This must be adjusted manually to the value of HZ in the running kernel
  # on 2.4, until the XFS people change their 2.4 external interfaces to work in
  # centisecs. This can be automated, but it's a work in progress that still needs
  # some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for external
  # interfaces, and that is currently always set to 100. So you don't need to
  # change this on 2.6.
  XFS_HZ=${XFS_HZ:-'100'}

  #############################################################################

  KLEVEL="$(uname -r |
               {
	       IFS='.' read a b c
	       echo $a.$b
	     }
  )"
  case "$KLEVEL" in
	"2.4"|"2.6")
		;;
	*)
		echo "Unhandled kernel version: $KLEVEL ('uname -r' = '$(uname -r)')" >&2
		exit 1
		;;
  esac

  if [ ! -e /proc/sys/vm/laptop_mode ] ; then
	echo "Kernel is not patched with laptop_mode patch." >&2
	exit 1
  fi

  if [ ! -w /proc/sys/vm/laptop_mode ] ; then
	echo "You do not have enough privileges to enable laptop_mode." >&2
	exit 1
  fi

  # Remove an option (the first parameter) of the form option=<number> from
  # a mount options string (the rest of the parameters).
  parse_mount_opts () {
	OPT="$1"
	shift
	echo ",$*," | sed		\
	 -e 's/,'"$OPT"'=[0-9]*,/,/g'	\
	 -e 's/,,*/,/g'			\
	 -e 's/^,//'			\
	 -e 's/,$//'
  }

  # Remove an option (the first parameter) without any arguments from
  # a mount option string (the rest of the parameters).
  parse_nonumber_mount_opts () {
	OPT="$1"
	shift
	echo ",$*," | sed		\
	 -e 's/,'"$OPT"',/,/g'		\
	 -e 's/,,*/,/g'			\
	 -e 's/^,//'			\
	 -e 's/,$//'
  }

  # Find out the state of a yes/no option (e.g. "atime"/"noatime") in
  # fstab for a given filesystem, and use this state to replace the
  # value of the option in another mount options string. The device
  # is the first argument, the option name the second, and the default
  # value the third. The remainder is the mount options string.
  #
  # Example:
  # parse_yesno_opts_wfstab /dev/hda1 atime atime defaults,noatime
  #
  # If fstab contains, say, "rw" for this filesystem, then the result
  # will be "defaults,atime".
  parse_yesno_opts_wfstab () {
	L_DEV="$1"
	OPT="$2"
	DEF_OPT="$3"
	shift 3
	L_OPTS="$*"
	PARSEDOPTS1="$(parse_nonumber_mount_opts $OPT $L_OPTS)"
	PARSEDOPTS1="$(parse_nonumber_mount_opts no$OPT $PARSEDOPTS1)"
	# Watch for a default atime in fstab
	FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
	if echo "$FSTAB_OPTS" | grep "$OPT" > /dev/null ; then
		# option specified in fstab: extract the value and use it
		if echo "$FSTAB_OPTS" | grep "no$OPT" > /dev/null ; then
			echo "$PARSEDOPTS1,no$OPT"
		else
			# no$OPT not found -- so we must have $OPT.
			echo "$PARSEDOPTS1,$OPT"
		fi
	else
		# option not specified in fstab -- choose the default.
		echo "$PARSEDOPTS1,$DEF_OPT"
	fi
  }

  # Find out the state of a numbered option (e.g. "commit=NNN") in
  # fstab for a given filesystem, and use this state to replace the
  # value of the option in another mount options string. The device
  # is the first argument, and the option name the second. The
  # remainder is the mount options string in which the replacement
  # must be done.
  #
  # Example:
  # parse_mount_opts_wfstab /dev/hda1 commit defaults,commit=7
  #
  # If fstab contains, say, "commit=3,rw" for this filesystem, then the
  # result will be "rw,commit=3".
  parse_mount_opts_wfstab () {
	L_DEV="$1"
	OPT="$2"
	shift 2
	L_OPTS="$*"
	PARSEDOPTS1="$(parse_mount_opts $OPT $L_OPTS)"
	# Watch for a default commit in fstab
	FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
	if echo "$FSTAB_OPTS" | grep "$OPT=" > /dev/null ; then
		# option specified in fstab: extract the value, and use it
		echo -n "$PARSEDOPTS1,$OPT="
		echo ",$FSTAB_OPTS," | sed \
		 -e 's/.*,'"$OPT"'=//'	\
		 -e 's/,.*//'
	else
		# option not specified in fstab: set it to 0
		echo "$PARSEDOPTS1,$OPT=0"
	fi
  }

  deduce_fstype () {
	MP="$1"
	# My root filesystem unfortunately has
	# type "unknown" in /etc/mtab. If we encounter
	# "unknown", we try to get the type from fstab.
	cat /etc/fstab |
	grep -v '^#' |
	while read FSTAB_DEV FSTAB_MP FSTAB_FST FSTAB_OPTS FSTAB_DUMP FSTAB_DUMP ; do
		if [ "$FSTAB_MP" = "$MP" ]; then
			echo $FSTAB_FST
			exit 0
		fi
	done
  }

  if [ $DO_REMOUNT_NOATIME -eq 1 ] ; then
	NOATIME_OPT=",noatime"
  fi

  case "$1" in
	start)
		AGE=$((100*$MAX_AGE))
		XFS_AGE=$(($XFS_HZ*$MAX_AGE))
		echo -n "Starting laptop_mode"

		if [ -d /proc/sys/vm/pagebuf ] ; then
			# (For 2.4 and early 2.6.)
			# This only needs to be set, not reset -- it is only used when
			# laptop mode is enabled.
			echo $XFS_AGE > /proc/sys/vm/pagebuf/lm_flush_age
			echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
		elif [ -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
			# (A couple of early 2.6 laptop mode patches had these.)
			# The same goes for these.
			echo $XFS_AGE > /proc/sys/fs/xfs/lm_age_buffer
			echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
		elif [ -f /proc/sys/fs/xfs/age_buffer ] ; then
			# (2.6.6)
			# But not for these -- they are also used in normal
			# operation.
			echo $XFS_AGE > /proc/sys/fs/xfs/age_buffer
			echo $XFS_AGE > /proc/sys/fs/xfs/sync_interval
		elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
			# (2.6.7 upwards)
			# And not for these either. These are in centisecs,
			# not USER_HZ, so we have to use $AGE, not $XFS_AGE.
			echo $AGE > /proc/sys/fs/xfs/age_buffer_centisecs
			echo $AGE > /proc/sys/fs/xfs/xfssyncd_centisecs
			echo 3000 > /proc/sys/fs/xfs/xfsbufd_centisecs
		fi

		case "$KLEVEL" in
			"2.4")
				echo 1					> /proc/sys/vm/laptop_mode
				echo "30 500 0 0 $AGE $AGE 60 20 0"	> /proc/sys/vm/bdflush
				;;
			"2.6")
				echo 5					> /proc/sys/vm/laptop_mode
				echo "$AGE"				> /proc/sys/vm/dirty_writeback_centisecs
				echo "$AGE"				> /proc/sys/vm/dirty_expire_centisecs
				echo "$DIRTY_RATIO"			> /proc/sys/vm/dirty_ratio
				echo "$DIRTY_BACKGROUND_RATIO"		> /proc/sys/vm/dirty_background_ratio
				;;
		esac
		if [ $DO_REMOUNTS -eq 1 ]; then
			cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
				PARSEDOPTS="$(parse_mount_opts "$OPTS")"
				if [ "$FST" = 'unknown' ]; then
					FST=$(deduce_fstype $MP)
				fi
				case "$FST" in
					"ext3"|"reiserfs")
						PARSEDOPTS="$(parse_mount_opts commit "$OPTS")"
						mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE$NOATIME_OPT
						;;
					"xfs")
						mount $DEV -t $FST $MP -o remount,$OPTS$NOATIME_OPT
						;;
				esac
				if [ -b $DEV ] ; then
					blockdev --setra $(($READAHEAD * 2)) $DEV
				fi
			done
		fi
		if [ $DO_HD -eq 1 ] ; then
			for THISHD in $HD ; do
				/sbin/hdparm -S $BATT_HD $THISHD > /dev/null 2>&1
				/sbin/hdparm -B 1 $THISHD > /dev/null 2>&1
			done
		fi
		if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
			if [ $CPU_MAXFREQ = 'slowest' ]; then
				CPU_MAXFREQ=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq`
			fi
			echo $CPU_MAXFREQ > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
		fi
		echo "."
		;;
	stop)
		U_AGE=$((100*$DEF_UPDATE))
		B_AGE=$((100*$DEF_AGE))
		echo -n "Stopping laptop_mode"
		echo 0 > /proc/sys/vm/laptop_mode
		if [ -f /proc/sys/fs/xfs/age_buffer -a ! -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
			# These need to be restored, if there are no lm_*.
			echo $(($XFS_HZ*$DEF_XFS_AGE_BUFFER))	 	> /proc/sys/fs/xfs/age_buffer
			echo $(($XFS_HZ*$DEF_XFS_SYNC_INTERVAL)) 	> /proc/sys/fs/xfs/sync_interval
		elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
			# These need to be restored as well.
			echo $((100*$DEF_XFS_AGE_BUFFER))	> /proc/sys/fs/xfs/age_buffer_centisecs
			echo $((100*$DEF_XFS_SYNC_INTERVAL))	> /proc/sys/fs/xfs/xfssyncd_centisecs
			echo $((100*$DEF_XFS_BUFD_INTERVAL))	> /proc/sys/fs/xfs/xfsbufd_centisecs
		fi
		case "$KLEVEL" in
			"2.4")
				echo "30 500 0 0 $U_AGE $B_AGE 60 20 0"	> /proc/sys/vm/bdflush
				;;
			"2.6")
				echo "$U_AGE"				> /proc/sys/vm/dirty_writeback_centisecs
				echo "$B_AGE"				> /proc/sys/vm/dirty_expire_centisecs
				echo "$DEF_DIRTY_RATIO"			> /proc/sys/vm/dirty_ratio
				echo "$DEF_DIRTY_BACKGROUND_RATIO"	> /proc/sys/vm/dirty_background_ratio
				;;
		esac
		if [ $DO_REMOUNTS -eq 1 ] ; then
			cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
				# Reset commit and atime options to defaults.
				if [ "$FST" = 'unknown' ]; then
					FST=$(deduce_fstype $MP)
				fi
				case "$FST" in
					"ext3"|"reiserfs")
						PARSEDOPTS="$(parse_mount_opts_wfstab $DEV commit $OPTS)"
						PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $PARSEDOPTS)"
						mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
						;;
					"xfs")
						PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $OPTS)"
						mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
						;;
				esac
				if [ -b $DEV ] ; then
					blockdev --setra 256 $DEV
				fi
			done
		fi
		if [ $DO_HD -eq 1 ] ; then
			for THISHD in $HD ; do
				/sbin/hdparm -S $AC_HD $THISHD > /dev/null 2>&1
				/sbin/hdparm -B 255 $THISHD > /dev/null 2>&1
			done
		fi
		if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
			echo `cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq` > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
		fi
		echo "."
		;;
	*)
		echo "Usage: $0 {start|stop}" 2>&1
		exit 1
		;;

  esac

  exit 0

ACPI integration
----------------

Dax Kelson submitted this so that the ACPI acpid daemon will
kick off the laptop_mode script and run hdparm. The part that
automatically disables laptop mode when the battery is low was
written by Jan Topinski.

/etc/acpi/events/ac_adapter::

	event=ac_adapter
	action=/etc/acpi/actions/ac.sh %e

/etc/acpi/events/battery::

	event=battery.*
	action=/etc/acpi/actions/battery.sh %e

/etc/acpi/actions/ac.sh::

  #!/bin/bash

  # ac on/offline event handler

  status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/$2/state`

  case $status in
          "on-line")
                  /sbin/laptop_mode stop
                  exit 0
          ;;
          "off-line")
                  /sbin/laptop_mode start
                  exit 0
          ;;
  esac

/etc/acpi/actions/battery.sh::

  #! /bin/bash

  # Automatically disable laptop mode when the battery almost runs out.

  BATT_INFO=/proc/acpi/battery/$2/state

  if [[ -f /proc/sys/vm/laptop_mode ]]
  then
     LM=`cat /proc/sys/vm/laptop_mode`
     if [[ $LM -gt 0 ]]
     then
       if [[ -f $BATT_INFO ]]
       then
          # Source the config file only now that we know we need
          if [ -f /etc/default/laptop-mode ] ; then
                  # Debian
                  . /etc/default/laptop-mode
          elif [ -f /etc/sysconfig/laptop-mode ] ; then
                  # Others
                  . /etc/sysconfig/laptop-mode
          fi
          MINIMUM_BATTERY_MINUTES=${MINIMUM_BATTERY_MINUTES:-'10'}

          ACTION="`cat $BATT_INFO | grep charging | cut -c 26-`"
          if [[ ACTION -eq "discharging" ]]
          then
             PRESENT_RATE=`cat $BATT_INFO | grep "present rate:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
             REMAINING=`cat $BATT_INFO | grep "remaining capacity:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
          fi
          if (($REMAINING * 60 / $PRESENT_RATE < $MINIMUM_BATTERY_MINUTES))
          then
             /sbin/laptop_mode stop
          fi
       else
         logger -p daemon.warning "You are using laptop mode and your battery interface $BATT_INFO is missing. This may lead to loss of data when the battery runs out. Check kernel ACPI support and /proc/acpi/battery folder, and edit /etc/acpi/battery.sh to set BATT_INFO to the correct path."
       fi
     fi
  fi

Monitoring tool
---------------

Bartek Kania submitted this, it can be used to measure how much time your disk
spends spun up/down.  See tools/laptop/dslm/dslm.c


code:
.. SPDX-License-Identifier: GPL-2.0+

LG Gram laptop extra features
=============================

By Matan Ziv-Av <matan@svgalib.org>

Hotkeys
-------

The following FN keys are ignored by the kernel without this driver:

- FN-F1 (LG control panel)   - Generates F15
- FN-F5 (Touchpad toggle)    - Generates F21
- FN-F6 (Airplane mode)      - Generates RFKILL
- FN-F9 (Reader mode)        - Generates F14

The rest of the FN keys work without a need for a special driver.

Reader mode
-----------

Writing 0/1 to /sys/devices/platform/lg-laptop/reader_mode disables/enables
reader mode. In this mode the screen colors change (blue color reduced),
and the reader mode indicator LED (on F9 key) turns on.

FN Lock
-------

Writing 0/1 to /sys/devices/platform/lg-laptop/fn_lock disables/enables
FN lock.

Battery care limit
------------------

Writing 80/100 to /sys/class/power_supply/CMB0/charge_control_end_threshold
sets the maximum capacity to charge the battery. Limiting the charge
reduces battery capacity loss over time.

This value is reset to 100 when the kernel boots.

Fan mode
--------

Writing 1/0 to /sys/devices/platform/lg-laptop/fan_mode disables/enables
the fan silent mode.

USB charge
----------

Writing 0/1 to /sys/devices/platform/lg-laptop/usb_charge disables/enables
charging another device from the USB port while the device is turned off.

This value is reset to 0 when the kernel boots.

LEDs
~~~~

The are two LED devices supported by the driver:

Keyboard backlight
------------------

A led device named kbd_led controls the keyboard backlight. There are three
lighting level: off (0), low (127) and high (255).

The keyboard backlight is also controlled by the key combination FN-F8
which cycles through those levels.

Touchpad indicator LED
----------------------

On the F5 key. Controlled by led device names tpad_led.


code:
=========================================
Sony Notebook Control Driver (SNC) Readme
=========================================

	- Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
	- Copyright (C) 2007 Mattia Dongili <malattia@linux.it>

This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the
Sony Vaio laptops. This driver mixes both devices functions under the same
(hopefully consistent) interface. This also means that the sonypi driver is
obsoleted by sony-laptop now.

Fn keys (hotkeys):
------------------

Some models report hotkeys through the SNC or SPIC devices, such events are
reported both through the ACPI subsystem as acpi events and through the INPUT
subsystem. See the logs of /proc/bus/input/devices to find out what those
events are and which input devices are created by the driver.
Additionally, loading the driver with the debug option will report all events
in the kernel log.

The "scancodes" passed to the input system (that can be remapped with udev)
are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c
module.  For example the "FN/E" key combination (EJECTCD on some models)
generates the scancode 20 (0x14).

Backlight control:
------------------
If your laptop model supports it, you will find sysfs files in the
/sys/class/backlight/sony/
directory. You will be able to query and set the current screen
brightness:

	======================	=========================================
	brightness		get/set screen brightness (an integer
				between 0 and 7)
	actual_brightness	reading from this file will query the HW
				to get real brightness value
	max_brightness		the maximum brightness value
	======================	=========================================

Platform specific:
------------------
Loading the sony-laptop module will create a
/sys/devices/platform/sony-laptop/
directory populated with some files.

You then read/write integer values from/to those files by using
standard UNIX tools.

The files are:

	======================	==========================================
	brightness_default	screen brightness which will be set
				when the laptop will be rebooted
	cdpower			power on/off the internal CD drive
	audiopower		power on/off the internal sound card
	lanpower		power on/off the internal ethernet card
				(only in debug mode)
	bluetoothpower		power on/off the internal bluetooth device
	fanspeed		get/set the fan speed
	======================	==========================================

Note that some files may be missing if they are not supported
by your particular laptop model.

Example usage::

	# echo "1" > /sys/devices/platform/sony-laptop/brightness_default

sets the lowest screen brightness for the next and later reboots

::

	# echo "8" > /sys/devices/platform/sony-laptop/brightness_default

sets the highest screen brightness for the next and later reboots

::

	# cat /sys/devices/platform/sony-laptop/brightness_default

retrieves the value

::

	# echo "0" > /sys/devices/platform/sony-laptop/audiopower

powers off the sound card

::

	# echo "1" > /sys/devices/platform/sony-laptop/audiopower

powers on the sound card.

RFkill control:
---------------
More recent Vaio models expose a consistent set of ACPI methods to
control radio frequency emitting devices. If you are a lucky owner of
such a laptop you will find the necessary rfkill devices under
/sys/class/rfkill. Check those starting with sony-* in::

	# grep . /sys/class/rfkill/*/{state,name}

Development:
------------

If you want to help with the development of this driver (and
you are not afraid of any side effects doing strange things with
your ACPI BIOS could have on your laptop), load the driver and
pass the option 'debug=1'.

REPEAT:
	**DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS.**

In your kernel logs you will find the list of all ACPI methods
the SNC device has on your laptop.

* For new models you will see a long list of meaningless method names,
  reading the DSDT table source should reveal that:

(1) the SNC device uses an internal capability lookup table
(2) SN00 is used to find values in the lookup table
(3) SN06 and SN07 are used to call into the real methods based on
    offsets you can obtain iterating the table using SN00
(4) SN02 used to enable events.

Some values in the capability lookup table are more or less known, see
the code for all sony_call_snc_handle calls, others are more obscure.

* For old models you can see the GCDP/GCDP methods used to pwer on/off
  the CD drive, but there are others and they are usually different from
  model to model.

**I HAVE NO IDEA WHAT THOSE METHODS DO.**

The sony-laptop driver creates, for some of those methods (the most
current ones found on several Vaio models), an entry under
/sys/devices/platform/sony-laptop, just like the 'cdpower' one.
You can create other entries corresponding to your own laptop methods by
further editing the source (see the 'sony_nc_values' table, and add a new
entry to this table with your get/set method names using the
SNC_HANDLE_NAMES macro).

Your mission, should you accept it, is to try finding out what
those entries are for, by reading/writing random values from/to those
files and find out what is the impact on your laptop.

Should you find anything interesting, please report it back to me,
I will not disavow all knowledge of your actions :)

See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other
useful info.

Bugs/Limitations:
-----------------

* This driver is not based on official documentation from Sony
  (because there is none), so there is no guarantee this driver
  will work at all, or do the right thing. Although this hasn't
  happened to me, this driver could do very bad things to your
  laptop, including permanent damage.

* The sony-laptop and sonypi drivers do not interact at all. In the
  future, sonypi will be removed and replaced by sony-laptop.

* spicctrl, which is the userspace tool used to communicate with the
  sonypi driver (through /dev/sonypi) is deprecated as well since all
  its features are now available under the sysfs tree via sony-laptop.


code:
==================================================
Sony Programmable I/O Control Device Driver Readme
==================================================

	- Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
	- Copyright (C) 2001-2002 Alcôve <www.alcove.com>
	- Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
	- Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
	- Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
	- Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>

This driver enables access to the Sony Programmable I/O Control Device which
can be found in many Sony Vaio laptops. Some newer Sony laptops (seems to be
limited to new FX series laptops, at least the FX501 and the FX702) lack a
sonypi device and are not supported at all by this driver.

It will give access (through a user space utility) to some events those laptops
generate, like:

	- jogdial events (the small wheel on the side of Vaios)
	- capture button events (only on Vaio Picturebook series)
	- Fn keys
	- bluetooth button (only on C1VR model)
	- programmable keys, back, help, zoom, thumbphrase buttons, etc.
	  (when available)

Those events (see linux/sonypi.h) can be polled using the character device node
/dev/sonypi (major 10, minor auto allocated or specified as a option).
A simple daemon which translates the jogdial movements into mouse wheel events
can be downloaded at: <http://popies.net/sonypi/>

Another option to intercept the events is to get them directly through the
input layer.

This driver supports also some ioctl commands for setting the LCD screen
brightness and querying the batteries charge information (some more
commands may be added in the future).

This driver can also be used to set the camera controls on Picturebook series
(brightness, contrast etc), and is used by the video4linux driver for the
Motion Eye camera.

Please note that this driver was created by reverse engineering the Windows
driver and the ACPI BIOS, because Sony doesn't agree to release any programming
specs for its laptops. If someone convinces them to do so, drop me a note.

Driver options:
---------------

Several options can be passed to the sonypi driver using the standard
module argument syntax (<param>=<value> when passing the option to the
module or sonypi.<param>=<value> on the kernel boot line when sonypi is
statically linked into the kernel). Those options are:

	=============== =======================================================
	minor:		minor number of the misc device /dev/sonypi,
			default is -1 (automatic allocation, see /proc/misc
			or kernel logs)

	camera:		if you have a PictureBook series Vaio (with the
			integrated MotionEye camera), set this parameter to 1
			in order to let the driver access to the camera

	fnkeyinit:	on some Vaios (C1VE, C1VR etc), the Fn key events don't
			get enabled unless you set this parameter to 1.
			Do not use this option unless it's actually necessary,
			some Vaio models don't deal well with this option.
			This option is available only if the kernel is
			compiled without ACPI support (since it conflicts
			with it and it shouldn't be required anyway if
			ACPI is already enabled).

	verbose:	set to 1 to print unknown events received from the
			sonypi device.
			set to 2 to print all events received from the
			sonypi device.

	compat:		uses some compatibility code for enabling the sonypi
			events. If the driver worked for you in the past
			(prior to version 1.5) and does not work anymore,
			add this option and report to the author.

	mask:		event mask telling the driver what events will be
			reported to the user. This parameter is required for
			some Vaio models where the hardware reuses values
			used in other Vaio models (like the FX series who does
			not have a jogdial but reuses the jogdial events for
			programmable keys events). The default event mask is
			set to 0xffffffff, meaning that all possible events
			will be tried. You can use the following bits to
			construct your own event mask (from
			drivers/char/sonypi.h)::

				SONYPI_JOGGER_MASK		0x0001
				SONYPI_CAPTURE_MASK		0x0002
				SONYPI_FNKEY_MASK		0x0004
				SONYPI_BLUETOOTH_MASK		0x0008
				SONYPI_PKEY_MASK		0x0010
				SONYPI_BACK_MASK		0x0020
				SONYPI_HELP_MASK		0x0040
				SONYPI_LID_MASK			0x0080
				SONYPI_ZOOM_MASK		0x0100
				SONYPI_THUMBPHRASE_MASK		0x0200
				SONYPI_MEYE_MASK		0x0400
				SONYPI_MEMORYSTICK_MASK		0x0800
				SONYPI_BATTERY_MASK		0x1000
				SONYPI_WIRELESS_MASK		0x2000

	useinput:	if set (which is the default) two input devices are
			created, one which interprets the jogdial events as
			mouse events, the other one which acts like a
			keyboard reporting the pressing of the special keys.
	=============== =======================================================

Module use:
-----------

In order to automatically load the sonypi module on use, you can put those
lines a configuration file in /etc/modprobe.d/::

	alias char-major-10-250 sonypi
	options sonypi minor=250

This supposes the use of minor 250 for the sonypi device::

	# mknod /dev/sonypi c 10 250

Bugs:
-----

	- several users reported that this driver disables the BIOS-managed
	  Fn-keys which put the laptop in sleeping state, or switch the
	  external monitor on/off. There is no workaround yet, since this
	  driver disables all APM management for those keys, by enabling the
	  ACPI management (and the ACPI core stuff is not complete yet). If
	  you have one of those laptops with working Fn keys and want to
	  continue to use them, don't use this driver.

	- some users reported that the laptop speed is lower (dhrystone
	  tested) when using the driver with the fnkeyinit parameter. I cannot
	  reproduce it on my laptop and not all users have this problem.
	  This happens because the fnkeyinit parameter enables the ACPI
	  mode (but without additional ACPI control, like processor
	  speed handling etc). Use ACPI instead of APM if it works on your
	  laptop.

	- sonypi lacks the ability to distinguish between certain key
	  events on some models.

	- some models with the nvidia card (geforce go 6200 tc) uses a
	  different way to adjust the backlighting of the screen. There
	  is a userspace utility to adjust the brightness on those models,
	  which can be downloaded from
	  https://www.acc.umu.se/~erikw/program/smartdimmer-0.1.tar.bz2

	- since all development was done by reverse engineering, there is
	  *absolutely no guarantee* that this driver will not crash your
	  laptop. Permanently.