Herostratus’ legacy

words from a lazy coder

Enabling HuC for SKL/KBL in Debian/testing

Recently, our friend Florent complained that it was impossible to set a constant bitrate when encoding H.264 using low-power profile with gstreamer-vaapi .Low-power (LP) profiles are VA-API entry points, available in Intel SkyLake-based processor and successors, which provide video encoding with low power consumption.

Later on, Ullysses and Sree, pointed out that CBR in LP is ony possible if HuC is enabled in the kernel.

HuC is a firmware, loaded by i915 kernel module, designed to offload some of the media functions from the CPU to GPU. One of these functions is bitrate control when encoding. HuC saves unnecessary CPU-GPU synchronization.

In order to load HuC, it is required first to load GuC, another Intel’s firmware designed to perform graphics workload scheduling on the various graphics parallel engines.

How we can install and configure these firmwares to enable CBR in low-power profile, among other things, in Debian/testing?

Check i915 parameters #

First we shall confirm that our kernel and our i915 kernel module is capable to handle this functionality:

$ sudo modinfo i915 | egrep -i "guc|huc|dmc"
firmware: i915/bxt_dmc_ver1_07.bin
firmware: i915/skl_dmc_ver1_26.bin
firmware: i915/kbl_dmc_ver1_01.bin
firmware: i915/kbl_guc_ver9_14.bin
firmware: i915/bxt_guc_ver8_7.bin
firmware: i915/skl_guc_ver6_1.bin
firmware: i915/kbl_huc_ver02_00_1810.bin
firmware: i915/bxt_huc_ver01_07_1398.bin
firmware: i915/skl_huc_ver01_07_1398.bin
parm: enable_guc_loading:Enable GuC firmware loading (-1=auto, 0=never [default], 1=if available, 2=required) (int)
parm: enable_guc_submission:Enable GuC submission (-1=auto, 0=never [default], 1=if available, 2=required) (int)
parm: guc_log_level:GuC firmware logging level (-1:disabled (default), 0-3:enabled) (int)
parm: guc_firmware_path:GuC firmware path to use instead of the default one (charp)
parm: huc_firmware_path:HuC firmware path to use instead of the default one (charp)

Install firmware #

sudo apt install firmware-misc-nonfree

UPDATE: In order to install this Debian package, you should have enabled the non-free apt repository in your sources list.

Verify the firmware are installed:

$ ls -1 /lib/firmware/i915/

Update modprobe configuration #

Edit or create the configuration file /etc/modprobe.d/i915.con

$ sudo vim /etc/modprobe.d/i915.conf
$ cat /etc/modprobe.d/i915.conf
options i915 enable_guc_loading=1 enable_guc_submission=1

Reboot #

sudo systemctl reboot

Verification #

Now it is possible to verify that the i915 module kernel loaded the firmware correctly by looking at the kernel logs:

$ journalctl -b -o short-monotonic -k | egrep -i "i915|dmr|dmc|guc|huc"
[ 10.303849] miau kernel: Setting dangerous option enable_guc_loading - tainting kernel
[ 10.303852] miau kernel: Setting dangerous option enable_guc_submission - tainting kernel
[ 10.336318] miau kernel: i915 0000:00:02.0: vgaarb: changed VGA decodes: olddecodes=io+mem,decodes=io+mem:owns=io+mem
[ 10.338664] miau kernel: i915 0000:00:02.0: firmware: direct-loading firmware i915/kbl_dmc_ver1_01.bin
[ 10.339635] miau kernel: [drm] Finished loading DMC firmware i915/kbl_dmc_ver1_01.bin (v1.1)
[ 10.361811] miau kernel: i915 0000:00:02.0: firmware: direct-loading firmware i915/kbl_huc_ver02_00_1810.bin
[ 10.362422] miau kernel: i915 0000:00:02.0: firmware: direct-loading firmware i915/kbl_guc_ver9_14.bin
[ 10.393117] miau kernel: [drm] GuC submission enabled (firmware i915/kbl_guc_ver9_14.bin [version 9.14])
[ 10.410008] miau kernel: [drm] Initialized i915 1.6.0 20170619 for 0000:00:02.0 on minor 0
[ 10.559614] miau kernel: snd_hda_intel 0000:00:1f.3: bound 0000:00:02.0 (ops i915_audio_component_bind_ops [i915])
[ 11.937413] miau kernel: i915 0000:00:02.0: fb0: inteldrmfb frame buffer device

That means that HuC and GuC firmwares were loaded successfully.

Now we can check the status of the modules using sysfs

$ sudo cat /sys/kernel/debug/dri/0/i915_guc_load_status
GuC firmware status:
path: i915/kbl_guc_ver9_14.bin
fetch: SUCCESS
version wanted: 9.14
version found: 9.14
header: offset is 0; size = 128
uCode: offset is 128; size = 142272
RSA: offset is 142400; size = 256

GuC status 0x800330ed:
Bootrom status = 0x76
uKernel status = 0x30
MIA Core status = 0x3

Scratch registers:
0: 0xf0000000
1: 0x0
2: 0x0
3: 0x5f5e100
4: 0x600
5: 0xd5fd3
6: 0x0
7: 0x8
8: 0x3
9: 0x74240
10: 0x0
11: 0x0
12: 0x0
13: 0x0
14: 0x0
15: 0x0
$ sudo cat /sys/kernel/debug/dri/0/i915_huc_load_status
HuC firmware status:
path: i915/kbl_huc_ver02_00_1810.bin
fetch: SUCCESS
version wanted: 2.0
version found: 2.0
header: offset is 0; size = 128
uCode: offset is 128; size = 218304
RSA: offset is 218432; size = 256

HuC status 0x00006080:

Test GStreamer #

$ gst-launch-1.0 videotestsrc num-buffers=1000 ! video/x-raw, format=NV12, width=1920, height=1080, framerate=\(fraction\)30/1 ! vaapih264enc bitrate=8000 keyframe-period=30 tune=low-power rate-control=cbr ! mp4mux ! filesink location=test.mp4
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
Got context from element 'vaapiencodeh264-0': gst.vaapi.Display=context, gst.vaapi.Display=(GstVaapiDisplay)"\(GstVaapiDisplayGLX\)\ vaapidisplayglx0";
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Got EOS from element "pipeline0".
Execution ended after 0:00:11.620036001
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...
$ gst-discoverer-1.0 test.mp4
Analyzing file:///home/vjaquez/gst/master/intel-vaapi-driver/test.mp4
Done discovering file:///home/vjaquez/test.mp4

container: Quicktime
video: H.264 (High Profile)

Duration: 0:00:33.333333333
Seekable: yes
Live: no
video codec: H.264 / AVC
bitrate: 8084005
encoder: VA-API H264 encoder
datetime: 2017-12-07T14:29:23Z
container format: ISO MP4/M4A

Mission accomplished!

References #