Difference between revisions of "R-Car/I2C-Virtualization"

From eLinux.org
Jump to: navigation, search
(first half of first rc)
 
(v1)
 
(2 intermediate revisions by the same user not shown)
Line 2: Line 2:
  
 
This document is about using and testing the experimental full virtualization patch for I2C pass-through devices using QEMU+KVM.
 
This document is about using and testing the experimental full virtualization patch for I2C pass-through devices using QEMU+KVM.
 +
Please note also that this document is only about QEMU+KVM. Other hypervisors would need a seperate document.
  
For the basic setup, Geert Uytterhoeven did an [https://elinux.org/R-Car/Virtualization introduction] how to setup QEMU+KVM on R-Car Gen3.
+
For security reasons, this pass through only supports reading. Writing works basically the same and would be trivial to add.
  
Please note also that this document is only about QEMU+KVM. Other hypervisors would need a seperate document.
+
Currently, this description is for x86_64 based systems. R-Car Gen3 might be added later, though no major differences are expected.
  
 
= Context =
 
= Context =
  
This patch was created when researching pass-through techniques suitable for I2C devices. One outcome of this research is that "full virtualization" has severe limits and other approaches like virtio sound more reasonable. From the patch header
+
This patch was created when researching pass-through techniques suitable for I2C devices. One outcome of this research is that "full virtualization" has severe limits and other approaches like virtio sound more reasonable. From the patch header:
  
 
<pre>
 
<pre>
    Full virtualization
+
Full virtualization
    -------------------
+
-------------------
   
+
 
    Would be nice to have because it would work with all virtual I2C
+
Would be nice to have because it would work with all virtual I2C
    adapters instantly, however there come problems with it. For that to
+
adapters instantly, however there come problems with it. For that to
    work, we would need to be able to transmit the QEMU I2C primitives from
+
work, we would need to be able to transmit the QEMU I2C primitives from
    userspace to the kernel. There is currently no such interface for that.
+
userspace to the kernel. There is currently no such interface for that.
    As of today, there is only the i2c-dev interface which allows to send
+
As of today, there is only the i2c-dev interface which allows to send
    a complete transfer (which may consist of multiple, combined messages)
+
a complete transfer (which may consist of multiple, combined messages)
    or SMBus commands. There is no way to send more primitive commands like
+
or SMBus commands. There is no way to send more primitive commands like
    "send {start|stop|acknowledge}-bit". Even if there was, most hardware I
+
"send {start|stop|acknowledge}-bit". Even if there was, most hardware I
    know of wouldn't work well with this. We often need a-priori knowledge
+
know of wouldn't work well with this. We often need a-priori knowledge
    like length of the message to program the controller. Such information
+
like length of the message to program the controller. Such information
    is not available when working with such primitives. On top of that, that
+
is not available when working with such primitives. On top of that, that
    approach would cause quite some overhead, so performance regressions for
+
approach would cause quite some overhead, so performance regressions for
    drivers which use other devices on the same bus are likely.
+
drivers which use other devices on the same bus are likely.
   
+
 
    virtio?
+
virtio?
    -------
+
-------
   
+
 
    From what I understood so far, virtio could help here. Yes, we would
+
From what I understood so far, virtio could help here. Yes, we would
    need seperate drivers, yet data transfer could be super simple. If we
+
need separate drivers, yet data transfer could be super simple. If we
    had a simple virtio-PCI I2C master device, it could have a really simple
+
had a simple virtio-PCI I2C master device, it could have a really simple
    kernel driver. It basically takes the I2C transfer it gets, does some
+
kernel driver. It basically takes the I2C transfer it gets, does some
    sanity checking so no other devices are accessed, and then passes it
+
sanity checking so no other devices are accessed, and then passes it
    to the kernel. I have not fully understood yet, if the virtio
+
to the kernel. I have not fully understood yet, if the virtio
    transportation mechanism is better/required here, or if we can/should
+
transportation mechanism is better/required here, or if we can/should
    still use the existing i2c-dev character interface.
+
still use the existing i2c-dev character interface.
 +
 
 +
Other problems found
 +
--------------------
 +
 
 +
Here is a list of other problems I discovered which need addressing in
 +
one way or the other:
 +
 
 +
* exclusive access to I2C devices
 +
 
 +
We currently don't have a way to mark devices as being "in use, don't
 +
touch" from userspace. This could be added but we need to decide on the
 +
transportation layer first (i2c-dev vs. virtio).
 +
 
 +
* no generic I2C master (at least for x86)
  
    Other problems found
+
Unless I overlooked something, we currently can't simply add a new I2C
    --------------------
+
bus on x86 because there is no virtual hardware encoded just doing that.
   
+
I found patches for a USB-to-I2C bridge floating around. USB is nicely
    Here is a list of other problems I discovered which need addressing in
+
generic, so probably worth evaluating those again if this task is to be
    one way or the other:
+
continued.
   
 
    * exclusive access to I2C devices
 
   
 
    We currently don't have a way to mark devices as being "in use, don't
 
    touch" from userspace. This could be added but we need to decide on the
 
    transportation layer first (i2c-dev vs. virtio).
 
   
 
    * no generic I2C master (at least for x86)
 
   
 
    Unless I overlooked something, we currently can't simply add a new I2C
 
    bus on x86 because there is no virtual hardware encoded just doing that.
 
    I found patches for a USB-to-I2C bridge floating around. USB is nicely
 
    generic, so probably worth evaluating those again if this task is to be
 
    continued.
 
   
 
    * re-definition of I2C_SLAVE
 
   
 
    QEMU defines I2C_SLAVE as well as <linux/i2c-dev.h>. So, if that
 
    interface is going to be used, we need something to fix this.
 
   
 
    * likely improvements to the QEMU I2C core
 
   
 
    From visual review, I am quite sure QEMU I2C core does not suport
 
    'repeated start' with the following message having a different I2C
 
    destination address than the previous one. This is legal, but up to
 
    now very rarely seen in practice. However, with deivces becoming more
 
    complex and those devices maybe being passed-through as well, more
 
    improvements to the QEMU I2C core might be needed as well.
 
   
 
    Conclusion
 
    ----------
 
   
 
    These are my finding regarding I2C device passthrough with QEMU. The
 
    below patch is a very first step in the "full virtualization" direction
 
    because it transports every byte access directly to the host (totally
 
    missing proper I2C start/stop/ack generation). As described above,
 
    I would not recommend this approach any further. My staring point now
 
    would be a simplified virtio or virtio-alike device where the transfer
 
    is passed-through as such to the host, and not split up into primitives.
 
    So the patch itself is already obsolete, but it served well for gaining
 
    experience.
 
  
 +
* re-definition of I2C_SLAVE
 +
 +
QEMU defines I2C_SLAVE as well as <linux/i2c-dev.h>. So, if that
 +
interface is going to be used, we need something to fix this.
 +
 +
* likely improvements to the QEMU I2C core
 +
 +
From visual review, I am quite sure QEMU I2C core does not support
 +
'repeated start' with the following message having a different I2C
 +
destination address than the previous one. This is legal, but up to
 +
now very rarely seen in practice. However, with devices becoming more
 +
complex and those devices maybe being passed-through as well, more
 +
improvements to the QEMU I2C core might be needed as well.
 
</pre>
 
</pre>
  
 
= Setup =
 
= Setup =
  
The patch can be found here: <FIXME>
+
The patch can be found here: https://git.kernel.org/pub/scm/virt/qemu/wsa/qemu.git/log/?h=i2c-passthrough
  
The patch is very self-contained and should easily be applicable to various versions of QEMU.
+
The patch is very self-contained and should easily be applicable to older versions of QEMU.
 +
 
 +
Other than a version of QEMU with the patch applied, you will need ''CONFIG_I2C_CHARDEV'' enabled in the host-kernel. Also, the user running QEMU should have
 +
access to that character device which can be achieved by adding the user to the ''i2c'' group.
 +
 
 +
You should have the ''i2c-tools'' package installed on the host and the client to verify the results.
 +
 
 +
= Getting reference data from the host =
 +
 
 +
First, we read out a device on the host directly. For this, I use an SPD EEPROM of a memory module which sits on bus 0, addr 0x52 on the host.
 +
Although this is pretty common, it may be different on your system, so please double check beforehand. For easier comparison, we calculate a
 +
hashsum over the dump:
 +
 
 +
<pre>
 +
$ sudo i2cdump -y 0 0x52 | md5sum
 +
No size specified (using byte-data access)
 +
2bfd553791d86fcc7d850528033a08c9  -
 +
</pre>
 +
 
 +
= Passing through the I2C device =
 +
 
 +
For the above combination of bus number and address, add this snipplet to your standard QEMU command line to have the SPD EEPROM mapped at address 0x42 (or adapt the parameters to your needs):
 +
 
 +
<code>
 +
-device host-i2cdev,address=0x42,file=/dev/i2c-0,hostaddr=0x52
 +
</code>
 +
 
 +
Then boot into the QEMU machine and execute as root:
 +
 
 +
<pre>
 +
# i2cdump -y 0 0x42 | md5sum
 +
No size specified (using byte-data access)
 +
2bfd553791d86fcc7d850528033a08c9  -
 +
</pre>
  
Other than a version of QEMU with the patch applied, you need 'CONFIG_I2C_CHARDEV' enabled in the host-kernel. You should have the 'i2c-tools' package installed on the host and the client to verify the results.
+
The equal md5sum outputs show that the dump matches and we have successfully read from the host-device.

Latest revision as of 11:50, 13 March 2018

Introduction

This document is about using and testing the experimental full virtualization patch for I2C pass-through devices using QEMU+KVM. Please note also that this document is only about QEMU+KVM. Other hypervisors would need a seperate document.

For security reasons, this pass through only supports reading. Writing works basically the same and would be trivial to add.

Currently, this description is for x86_64 based systems. R-Car Gen3 might be added later, though no major differences are expected.

Context

This patch was created when researching pass-through techniques suitable for I2C devices. One outcome of this research is that "full virtualization" has severe limits and other approaches like virtio sound more reasonable. From the patch header:

Full virtualization
-------------------

Would be nice to have because it would work with all virtual I2C
adapters instantly, however there come problems with it. For that to
work, we would need to be able to transmit the QEMU I2C primitives from
userspace to the kernel. There is currently no such interface for that.
As of today, there is only the i2c-dev interface which allows to send
a complete transfer (which may consist of multiple, combined messages)
or SMBus commands. There is no way to send more primitive commands like
"send {start|stop|acknowledge}-bit". Even if there was, most hardware I
know of wouldn't work well with this. We often need a-priori knowledge
like length of the message to program the controller. Such information
is not available when working with such primitives. On top of that, that
approach would cause quite some overhead, so performance regressions for
drivers which use other devices on the same bus are likely.

virtio?
-------

From what I understood so far, virtio could help here. Yes, we would
need separate drivers, yet data transfer could be super simple. If we
had a simple virtio-PCI I2C master device, it could have a really simple
kernel driver. It basically takes the I2C transfer it gets, does some
sanity checking so no other devices are accessed, and then passes it
to the kernel. I have not fully understood yet, if the virtio
transportation mechanism is better/required here, or if we can/should
still use the existing i2c-dev character interface.

Other problems found
--------------------

Here is a list of other problems I discovered which need addressing in
one way or the other:

* exclusive access to I2C devices

We currently don't have a way to mark devices as being "in use, don't
touch" from userspace. This could be added but we need to decide on the
transportation layer first (i2c-dev vs. virtio).

* no generic I2C master (at least for x86)

Unless I overlooked something, we currently can't simply add a new I2C
bus on x86 because there is no virtual hardware encoded just doing that.
I found patches for a USB-to-I2C bridge floating around. USB is nicely
generic, so probably worth evaluating those again if this task is to be
continued.

* re-definition of I2C_SLAVE

QEMU defines I2C_SLAVE as well as <linux/i2c-dev.h>. So, if that
interface is going to be used, we need something to fix this.

* likely improvements to the QEMU I2C core

From visual review, I am quite sure QEMU I2C core does not support
'repeated start' with the following message having a different I2C
destination address than the previous one. This is legal, but up to
now very rarely seen in practice. However, with devices becoming more
complex and those devices maybe being passed-through as well, more
improvements to the QEMU I2C core might be needed as well.

Setup

The patch can be found here: https://git.kernel.org/pub/scm/virt/qemu/wsa/qemu.git/log/?h=i2c-passthrough

The patch is very self-contained and should easily be applicable to older versions of QEMU.

Other than a version of QEMU with the patch applied, you will need CONFIG_I2C_CHARDEV enabled in the host-kernel. Also, the user running QEMU should have access to that character device which can be achieved by adding the user to the i2c group.

You should have the i2c-tools package installed on the host and the client to verify the results.

Getting reference data from the host

First, we read out a device on the host directly. For this, I use an SPD EEPROM of a memory module which sits on bus 0, addr 0x52 on the host. Although this is pretty common, it may be different on your system, so please double check beforehand. For easier comparison, we calculate a hashsum over the dump:

$ sudo i2cdump -y 0 0x52 | md5sum
No size specified (using byte-data access)
2bfd553791d86fcc7d850528033a08c9  -

Passing through the I2C device

For the above combination of bus number and address, add this snipplet to your standard QEMU command line to have the SPD EEPROM mapped at address 0x42 (or adapt the parameters to your needs):

-device host-i2cdev,address=0x42,file=/dev/i2c-0,hostaddr=0x52

Then boot into the QEMU machine and execute as root:

# i2cdump -y 0 0x42 | md5sum
No size specified (using byte-data access)
2bfd553791d86fcc7d850528033a08c9  -

The equal md5sum outputs show that the dump matches and we have successfully read from the host-device.