Hi Harald Mommer,

    Thank you for your comments and please refer to my following replies.

On 8/10/2023 6:40 PM, Harald Mommer wrote:
Hello,

a quick incomplete on. I'm currently with both hands in an attempt to implement a virtio SPI device for our proprietary hypervisor based on the draft specification and your E-Mail. Means I see now some more things while implementing.

u32 len; /* @len: transfer length.*/

is this a byte or a word count?

The comment in Linux for the length field in struct spi_ioc_transfer is

/* @len: Length of tx and rx buffers, in bytes. */ so I assume this here is also a byte count.

As we have only one len I think it's still needed to look at the device readable and device writable descriptor sizes to decide on half duplex read, half duplex write or full duplex. Having still to do this the transfer length in the len field may be redundant (superfluous) information.

"len" is byte count.

You are right, "len" parameter seems redundant. Virtqueue used to pass parameters between front-end and back-end and its descriptor is defined as follows(refer to: https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/listings/virtio_queue.h):

struct virtq_desc {
        /* Address (guest-physical). */
        le64 addr;
        /* Length. */
        le32 len;
        /* The flags as indicated above. */
        le16 flags;
        /* We chain unused descriptors via this, too */
        le16 next;
};

For the rx_buf or tx_buf descriptor, len member shows the transfer length, so it is not necessary to pass "len" in the head structure.
I will remove "len" in next version.



No problem with this, I'm now only at a point where I want to be sure whether this is meant as a byte length (vs. a word length).

Then there is no u32. There is le32. Only RPMB uses be32 but they have a special reason to do this. The byte order must be defined for 16 and 32 bit values!

Yes! Use "le32" instead of "u32" in next patch.


On 20.07.23 09:50, Haixu Cui wrote:
Hi Harald Mommer,

    Thank you so much for all your helpful advice and info!

    I have updated the transfer request as follows:

    struct spi_transfer_head {
          u8 slave_id;
          u8 bits_per_word;
          u8 cs_change;
          u8 tx_nbits;
          u8 rx_nbits;
          u8 reserved[3];
          u32 len;
          u32 mode;
          u32 freq;
          u32 word_delay_ns;
          u32 cs_setup_ns;
          u32 cs_delay_hold_ns;
          u32 cs_change_delay_inactive_ns;
    };

    struct spi_transfer_end {
          u8 result;
    };
May become "struct spi_transfer_result result" for naming reasons with same content, see below. Just a proposal which may not be followed, see below.

    struct virtio_spi_transfer_req {
        struct spi_transfer_head head;
        u8 rx_buf[];
        u8 tx_buf[];
        struct spi_end end;
Above this was "struct spi_transfer_end"

    };

Agreed! Will change to "struct spi_transfer_result".


Device readable must go before device writable. So rx_buf[] and tx_buf[] still have to be swapped.

Yes, rx_buf and tx_buf should be swapped.


I need to separate struct virtio_spi_transfer_req in my C implementation to

struct virtio_spi_transfer_req_out { /* Device readable */
     struct spi_transfer_head head;
    u8 tx_buf[]; /* Variable array at the end of the structure, gcc is happy */
};

struct virtio_spi_transfer_req_in { /* Device writable */
     u8 rx_buf[];
    /* "struct spi_transfer_end result;" is behind rx_buf but variable array must be last element for gcc for reasons */
};

Means you have to calculate the address where the result code is to be written from some length information. Can be done. But then I should be sure about the address. And this I can only be after all the length information (head, device writable) are checked for consistency. Clumsy and asking for mistakes.

However what also could be done (but you may have to obey alignment requirement for rx_buf[] when words are transferred and may have to add some padding in "struct spi_transfer_result", I don't know this currently):

struct virtio_spi_transfer_req_in { /* Device writable */
    struct spi_transfer_result result; /* The result code is the 1st device writable byte */
     u8 rx_buf[];
};

With this definition there was no need to calculate the address of the result byte. Just a thought to make life easier.

As I just mentioned, front-end sends the buffer base address and transfer length to the back-end using virtq_desc structure, rather than sending the data directly. And the virtq_desc length is always 16 bytes, so there has nothing to do with the sending order.


Also I add the member and field definition as follows:

    @slave_id: chipselect index the SPI transfer used.

    @bits_per_word: the number of bits in each SPI transfer word.

    @cs_change: whether to deselect device after finishing this transfer
        before starting the next transfer, 0 means cs keep asserted and
        1 means cs deasserted then asserted again.

    @tx_nbits: bus width for write transfer.
        0,1: bus width is 1, also known as SINGLE
        2  : bus width is 2, also known as DUAL
        4  : bus width is 4, also known as QUAD
        8  : bus width is 8, also known as OCTAL
        other values are invalid.

    @rx_nbits: bus width for read transfer.
        0,1: bus width is 1, also known as SINGLE
        2  : bus width is 2, also known as DUAL
        4  : bus width is 4, also known as QUAD
        8  : bus width is 8, also known as OCTAL
        other values are invalid.

    @reserved: for future use.

    @len: transfer length.
Improve comment!

Actually, it is byte count.
len will be removed.


    @mode: SPI transfer mode.
        bit 0: CPHA, determines the timing (i.e. phase) of the data
            bits relative to the clock pulses.For CPHA=0, the
            "out" side changes the data on the trailing edge of the
            preceding clock cycle, while the "in" side captures the data
            on (or shortly after) the leading edge of the clock cycle.
            For CPHA=1, the "out" side changes the data on the leading
            edge of the current clock cycle, while the "in" side
            captures the data on (or shortly after) the trailing edge of
            the clock cycle.
        bit 1: CPOL, determines the polarity of the clock. CPOL=0 is a
            clock which idles at 0, and each cycle consists of a pulse
            of 1. CPOL=1 is a clock which idles at 1, and each cycle
            consists of a pulse of 0.
        bit 2: CS_HIGH, if 1, chip select active high, else active low.
        bit 3: LSB_FIRST, determines per-word bits-on-wire, if 0, MSB
            first, else LSB first.
        bit 4: LOOP, loopback mode.

    @freq: the transfer speed in Hz.

    @word_delay_ns: delay to be inserted between consecutive words of a
        transfer, in ns unit.
    @cs_setup_ns: delay to be introduced after CS is asserted, in ns
        unit.
    @cs_delay_hold_ns: delay to be introduced before CS is deasserted
        for each transfer, in ns unit.
    @cs_change_delay_inactive_ns: delay to be introduced after CS is
        deasserted and before next asserted, in ns unit.


    Could you please help review the transfer request above again to check if the interface is clear and enough for back-end to perform SPI transfers. Thank you again for your comments.
I'm working and I'll come back on this.
Best Regards
Haixu Cui

Regards
Harald Mommer



According to your helpful comments and suggestion, I will submit another patch as soon as possible.

Best Regards & Thanks
Haixu Cui


---------------------------------------------------------------------
To unsubscribe, e-mail: virtio-dev-unsubscr...@lists.oasis-open.org
For additional commands, e-mail: virtio-dev-h...@lists.oasis-open.org


---------------------------------------------------------------------
To unsubscribe, e-mail: virtio-dev-unsubscr...@lists.oasis-open.org
For additional commands, e-mail: virtio-dev-h...@lists.oasis-open.org

Reply via email to