I2C kernel driver testing using virtme
The last few days I worked on the MCP23017 kernel driver and wondered about a good method to test my changes in a comfortable way. Fortunately I built myself an i2c-tiny-usb adapter some time ago, which is supported by mainline Linux. Thus any system with USB host support could be used for testing the above chip. My minimal test-setup can be seen in the image below. Basically I supplied 5V, Ground, SCL & SDA from the adapter to MCP23017, connected the low-active reset pin to 5V and the address-selection pins to Ground.
The obvious platform would be my development notebook, but rebooting for every test is a annoying. Kernel developers working on scheduler e.t.c. often use qemu for testing, so I wondered if I could do the same by forwarding the USB device. Also I do not want to spend time for configuring a rootfs for the emulated system. Thankfully Andy Lutomirski wrote virtme, which takes care of this by using the normal rootfs. I created a Debian package, which can be found on the following git repository at collabora.
$ cd ~/src/collabora/linux $ # edit .config for usage with qemu (enable VIRTIO & 9P related options) $ make -j4 ... Kernel: arch/x86/boot/bzImage is ready (#13) MODPOST 3326 modules $ # ensure your user has permissions for USB device, so that qemu can grab it $ virtme-run --kdir ~/src/collabora/linux --qemu-opts -usb -usbdevice host:0403:c631 kernel boot messages... [ 3.044289] virtme-init: udevd not found [ 3.126059] usb 1-1: New USB device found, idVendor=0403, idProduct=c631 [ 3.127210] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 3.127837] usb 1-1: Product: i2c-tiny-usb [ 3.128336] usb 1-1: Manufacturer: Till Harbaum [ 3.131808] i2c-tiny-usb 1-1:1.0: version 1.05 found at bus 001 address 002 [ 3.138173] i2c i2c-0: connected i2c-tiny-usb device virtme-init: console is ttyS0 root@(none):/# i2cdetect -l i2c-0 i2c i2c-tiny-usb at bus 001 device 003 I2C adapter root@(none):/# i2cdetect -y 0 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- root@(none):/# echo mcp23017 0x20 > /sys/bus/i2c/devices/i2c-0/new_device [ 71.762916] i2c i2c-0: new_device: Instantiated device mcp23017 at 0x20 root@(none):/# cat /sys/kernel/debug/gpio gpiochip0: GPIOs 496-511, parent: i2c/0-0020, mcp23017, can sleep: root@(none):/# echo 496 > /sys/class/gpio/export root@(none):/# echo 497 > /sys/class/gpio/export root@(none):/# echo 498 > /sys/class/gpio/export root@(none):/# echo out > /sys/class/gpio/gpio497/direction root@(none):/# echo out > /sys/class/gpio/gpio498/direction root@(none):/# echo 1 > /sys/class/gpio/gpio498/value root@(none):/# cat /sys/kernel/debug/gpio gpiochip0: GPIOs 496-511, parent: i2c/0-0020, mcp23017, can sleep: gpio-496 P0.0 (sysfs ) in lo gpio-497 P0.1 (sysfs ) out lo gpio-498 P0.2 (sysfs ) out hi root@(none):/# cat /sys/kernel/debug/regmap/0-0020/registers 00: fff9 02: 0000 04: 0000 06: 0000 08: 0000 0a: 0808 0c: 0000 0e: 0000 10: 0000 14: 0004 # emulating short power-loss by pulling reset to low for some seconds root@(none):/# cat /sys/kernel/debug/regmap/0-0020/registers 00: fff9 02: 0000 04: 0000 06: 0000 08: 0000 0a: 0808 0c: 0000 0e: 0000 10: 0000 14: 0004 # that's not what is in the registers after power-loss, its from regmap # cache, since regmap does not know about the power-loss. root@(none):/# cat /sys/kernel/debug/gpio [ 170.011018] mcp230xx 0-0020: restoring reg 0x00 from 0xffff to 0xfff9 (power-loss?) [ 170.098648] mcp230xx 0-0020: restoring reg 0x05 from 0x0000 to 0x0808 (power-loss?) gpiochip0: GPIOs 496-511, parent: i2c/0-0020, mcp23017, can sleep: gpio-496 P0.0 (sysfs ) in lo gpio-497 P0.1 (sysfs ) out lo gpio-498 P0.2 (sysfs ) out lo
So my patch moving to regmap based caching work as expected and surpass the original driver, since it can detect & fix context-loss scenarios in debugfs :) While those are quite unlikely to appear on production hardware, MCP23xxx is commonly used by hobbyists and their hardware is often less stable.
As a by-product of my work on mcp23xxx I also had to fix i2c-tiny-usb, though. Before kernel 4.9 the driver worked flawlessly, but since then it will complain, that the transfer buffers are not DMA capable. A patch for that has been sent and will hopefully be backported.
All in all I must say the virtme based testing was really nice and I hope I can use it again.
– Sebastian