Monday, November 11, 2013

[Presentation] BIOS, Linux and Firmware Test Suite in-between

I was invited to present "BIOS, Linux and Firmware Test Suite in-between" in Debian Taiwan's MiniDeb Conf in Taipei, Taiwan on Nov 9, 2013. The presentation is shared @ slideshare and can be viewed below:



Firmware Test Suite is an ongoing project that targets to automate firmware and hardware related tests. It receives some attentions from various parties including hardware, software and system vendors. (I also presented the similar topic in UEFI Plugfest in Sept, 2013, and the presentation slides are available @ http://uefi.org/learning_center/presentationsandvideos).

Friday, August 30, 2013

Info Session: Improving BIOS Compatibility on Linux

I had a chance to present a BIOS-related topic "Improving BIOS Compatibility on Linux" in workplace, and the presentation is publicly available. Hope it may interest someone. :-)



Tuesday, July 2, 2013

ACPI AC Adapter (2) - How does Linux handle it?

ACPI AC Adapter Implementation in Linux Kernel

ACPI AC Adapter (1) introduced the theory of interfaces between BIOS and an OS, but a real example is always more convincing than anything else.

SysFs Node

In Linux, one can find out whether a laptop PC has AC plugged in by "cat /sys/class/power_supply/online". Linux ACPI AC driver evaluates _PSR and returns 1 for "AC is online" and 0 for "AC is offline". The sysfs node is also used by user-space applications.

Supported Objects

Surprisingly (or not), not all control methods defined in ACPI AC are supported. In fact, only _PSR is evaluated in Linux ACPI AC driver.

As ACPI covers very broad and rich features, kernel developers may find some of them "uninteresting". For example. _PSR is required, in software's perspective, to know whether AC is online, but which parts of a system is powered (i.e. _PCL) may not be that useful for laptop PCs (which AC usually powers everything). In some other cases, few BIOS implements _PIF and there is hardly any reason that someone decides to add _PIF supports to Linux.

AC Events



It is very interesting to see how an driver responds to ACPI events. In the above source code it is obvious that the driver behaves the same for all events equals 0x80, 0x00, 0x01. It also responds the same to all other ACPI events with an additional error message.

For example, it was seen that some BIOSes issue Notify(AC, 0x81) when AC adapter is plugged or plugged. Apparently Linux kernel does not think 0x81 is a valid event (nor can I find any 0x81 for AC in ACPI); however, Linux still behaves as well with Notify(AC, 0x80).

Suspend and Resume



Another interesting part in ACPI AC driver is acpi_ac_resume called when a system resumes from suspend or hiberation. It compares the "before" and "after" _PSR and issues an uEvent if they are different. This implies BIOSes need not to issue a Notify(AC, 0x80) during waking up to save some CPU cycles; however, this may be specific to Linux. As there is no rule in ACPI spec, one may want to verify the behaviors of the target OSes (ex. Windows).

References

Linux kernel source code (3.10): ACPI AC adpater driver in drivers/acpi/ac.c

Sunday, June 23, 2013

ACPI AC Adapter (1) - Introduction

In ACPI Control Method Battery (2), we see how ACPI's definition for control method battery and read the data in Ubuntu Linux. However, battery does not usually go alone - ACPI AC Adapter always goes with it.

AC Adapter Interface

Unlike the complexity of a control method battery, AC adapter is much simpler and three objects are mandatory:
  • _HID (Hardware ID) - needs to be ACPI0003
  • _PSR (Power Source) - indicates whether AC is online
  • _PCL(1) (Power Consumer List) - refers what is powered by AC

Below is a sample for AC adapter that returns whether AC is online from an EC register in _PSR:



Plugging and Unplugging AC Adapter

When AC adapter is plugged or unplugged, BIOS needs to issue a notification event as the example:



It is worth noting that only 0x80 is needed. Some BIOS will also issue Notify(_SB.AC, 0x81) that is not only redundant but also incorrect. Some BIOS also issues Notify(_SB.BAT, 0x80) and Notify(_SB.BAT, 0x81). While OS is smart enough to know that battery status is also changed, one may argument that issuing notification to battery is correct and at least won't break anything.

In my opinions, it is not incorrect to issue Notify(_SB.BAT, 0x80) as Battery State in _BST is definitely changed to discharging, assuming only one AC source and one battery are present in a system; however, issuing Notify(_SB.BAT, 0x81) and asking OS to re-enumerate _BIF/_BIX is only a waste of CPU cycles.

What is ACPI AC Adapter Affecting?

It is definitely not surprising to know the little AC icon in OS's taskbar uses the return value of AC._PSR - that's  the only way that an OS knows whether a system is powered by an AC adapter. But... what else?

It is true that hardware state is different from powered-by-AC to powered-by-battery - at least from the viewpoint of the power circuit; however, this is only small part of the system board and we often see much more difference and affecting the system. When a system is powered by AC source, it is, in most cases, running at performance mode - CPU can spend more time in maximum frequency, power-saving features are less aggressive, fan runs at higher speed, and the panel may be brighter. All of these can be changed when OS finds out AC is offline from AC._PSR.

The implication? If one sees stability issues without AC only, playing around _PSR may help identify whether it is the power circuit or is an OS beahviours, i.e. one device and its driver are too aggressive with its power-saving features. One way to distinguish whether it is always reports 1 in _PSR - if the problem persists, it is the power circuit (hardware) that causes the problem. I have seem a number of times that bad-quality power components that hang the system and many other times that a device or its driver failed the system. This technique always helps a quick and good direction to real problems.

Next...

How does Linux kernel handle ACPI AC adapter?

Note

  1. It seems _PCL is defined but is not used in Linux kernel.

References

  • ACPI Specification 5.0 - Sec. 10.3
  • ACPI Specification 5.0 - Table 5-121
  • Linux kernel source code (3.10)

Thursday, June 20, 2013

ACPI Brightness Control (4) - Workaround for Brightness Problems in Ubuntu Linux

This blog discusses some common errors for brightness control and hotkeys. It will be updated from time to time.

Initial Zero Brightness

Some system BIOS reports zero in _BQC at boot-up, and it causes Linux kernel to dim the screen to minimum. In some cases, the panel is completely black out. This is because Linux's ACPI VGA driver does the following when it starts:

  1. Read _BQC for current brightness level
  2. Set brightness level to maximum - it is to verify whether brightness work
  3. Restore brightness level from 1
Aside from getting BIOS fixes which is usually close to impossible as the product is shipped (but I do encourage people to call customer services to complain!), there are three ways to fix it:

Kernel parameter

Edit /etc/default/grub
Add "video.use_bios_initl_backlight=0" to GRUB_CMDLINE_LINUX_DEFAULT
Run "sudo update-grub"
Reboot

Bootup script

Edit the file /etc/rc.local
Add a line "echo 4 > /sys/class/backlight/acpi_video0/brightness" before "exit 0"
Reboot

Quirk to acpi/video.c

If you are familiar with Linux kernel, you can develop a patch as in https://bugs.launchpad.net/bugs/1184501. If not, it is more than welcomed to file a bug like LP#1184501, run "sudo dmidecode > dmi.log", attach dmi.log and assign the bug to me. I am very happy to develop a patch for it, and you may help many others using Linux!

Brightness Fails to Work

If you are have laptop PC that BIOS fails to adjust brightness via acpi_video, you can try add the kernel parameter "acpi_backlight=vendor".

What the parameter does is to stop using acpi video to adjust the brightness - also skips creating sysfs nodes for acpi_videoX. As a result, a desktop daemon (like GSD) will find other brightness sysfs nodes created by other drivers, such as Intel_backlight, thinkpad_backlight and so on.

A Hotkey Press Changes Two Levels

In Figure 2 of ACPI Brightness Control (3) - Hotkeys in Ubuntu Linux, a solid and a dash line were draw to call to BIOS _BCM. This implies a hotkey can and may change a brightness twice. This is the case with Gnome-Setting-Daemon in Ubuntu.

If seeing this problem, one can add an kernel parameter to workaround it:
  • sudo vi /etc/default/grub
  • add brightness_switch_enabled=N to GRUB_CMDLINE_LINUX_DEFAULT
  • sudo update-grub
  • reboot

This will skip the dashed line call in ACPI Video driver:


References

  • https://wiki.archlinux.org/index.php/Backlight

ACPI Brightness Control (3) - Hotkeys in Ubuntu Linux

In ACPI Brightness Control (1) - Control Methods and ACPI Brightness Control (2) - Hotkeys, we understand how ACPI designs brightness from BIOS's perspectives. In this blog, we will see them in action using Ubuntu as an example.

Brightness Sysfs Nodes in Linux Kernel


When booting up, Linux's ACPI VGA driver (drivers/acpi/video.c) enumerates ACPI AML (DSDT and SSDT) to look for output devices that support brightness control. Once identified, it creates sysfs nodes in /sys/class/backlight/acpi_video0. If more than one output device is found, it creates acpi_video1 and so on.

FIgure 1 - Sysfs Nodes for Brightness
Figure 1 shows files in acpi_video0 directory. Three files are particularly important:

  • actual_brightness - implements _BQC
  • brightness - implements _BCM, and also record current brightness level
  • max_brightness - implements _BCL and converts it to number of levels
For example, the _BCL in this Thinkpad reports 16 brightness levels with Ubuntu 12.04, and therefore "cat max_brightness" returns 15. Current brightness can be read by executing "cat actual_brightness" or "cat brightness". In most cases, both max_brightness and brightness return the same value (this should not be surprising) - they are only different if something breaks in kernel or BIOS - such as _BQC does not change with _BCM.

To change brightness level, one writes a value to brightness, ranged from 0 to max_brightness. In this system, it is from 0 to 15. ACPI VGA driver will convert it to the actual value in _BCL and write to _BCM. 

Hotkey Implementation in Ubuntu Linux


Figure 2 - Overall Process for Brightness Hotkeys
Figure 2 is an expansion of ACPI Brightness Control (2) - Hotkeys. It shows that many tasks are done even with a single hotkey press, and it also shows separation between OS and BIOS is clear - the clean interface makes hotkey development easy and that's exactly what ACPI is for. Let's add more details to OS level as it is in Figure 3.

Figure 3 - Brightness and Desktop Daemon
Ubuntu ships with gnome-setting-daemon (GSD) that listens to keycode events. ACPI VGA driver converts ACPI notification events to keycodes, and GSD changes brightness via sysfs nodes according. GSD is also responsible for reading brightness levels from sysfs nodes to show OSD for users and to create slider for changing brightness. It is also worthy noting that ACPI VGA driver can also calls _BCM to change brightness without interacting with GSD, but no OSD may be shown.

As GSD is designed to listen to keycode, System vendor may design BIOS to generate other none-standard ACPI events, such as WMI events, as long as there is a kernel driver to do the conversion; however, this is not a suggested.

PS. Please note keycodes are not the same as KBC's scancode.

Debugging Brightness (Hotkey) Failures


From Figure 3, it becomes obvious brightness hotkeys can fail for two primary reasons:
  1. BIOS does not generate events
  2. _BCM fails to change brightness
In Linux, it is easy to verify whether ACPI VGA events and keycodes are generated:
  • Run "acpi_listen" to show ACPI standard events
  • Run "sudo showkey" to show keycodes
One can trigger writes to _BCM as in "Brightness Sysfs Nodes in Linux Kernel", if brightness is changed but LCD panel is not, BIOS did not implement _BCM correctly (or graphics drivers do not respond requests from BIOS in some cases).


Saturday, June 15, 2013

ACPI Brightness Control (2) - Hotkeys

Overview of Brightness Hotkeys


When a brightness up or down hotkey is pressed, the screen shows a OSD and panel brightness is changed accordingly. A simple action results a simple output, but what happens underneath is a lot of magic.

Figure 1 - Hotkeys Overview (Software)

Figure 1 shows a overview from software perspectives. When a hotkey is pressed, ACPI events are generates that triggers a series of actions specific to OS which eventually changes panel brightness. More information can be found in "ACPI Brightness Control (1) - Control Methods".

BIOS ASL for Brightness Up and Down


How does BIOS tell OS to change brightness? ACPI Appendix B.6 (Notifications Specific to Output Devices) defines five types of notification; however two of them are most commonly used:
  • Notify(LCD, 0x86) – increase brightness
  • Notify(LCD, 0x87) – decrease brightness
where LCD is a devices with _BCL, _BQC and _BCM as the below example:

Device (_SB.PCI0.GFX0.LCD) {
     ...
     Method (_BCL, 0) {
          ...
     }
     Method (_BQC, 0) {
          ...
     }
     Method (_BCM, 1) {
          ...
     }
}

The below is an ASL example of an EC handing Q events for brightness hotkeys:

Device (_SB.PCI0.LPC.EC) {
     Method (_Q12, 0) {
          Notify (_SB.PCI0.GFX0.LCD, 0x86)
     }

     Method (_Q13, 0) {
          Notify (_SB.PCI0.GFX0.LCD, 0x87)
     }
}

When Hotkeys Fail


Most of them, brightness hotkeys fail for two reasons: 

1) No events are triggered: 
On Ubuntu or many other Linux distro, running "acpi_listen" and pressing hotkeys shows standard ACPI events. If you don't see anything with hotkey presses, the system BIOS fails to issue events

2) _BCM fails to work
As Windows 8 no longer uses, many BIOS engineers never check whether _BCM works (please remember ACPI requires _BCM to present in order to support brightness controls). In Linux, you can and write to /sys/class/backlight/acpi_video0/brightness to verify whether _BCM works.