Hi,

> -----Original Message-----
> From: Huang, Wei <wei.hu...@intel.com>
> Sent: Wednesday, January 19, 2022 9:45
> To: dev@dpdk.org; Xu, Rosen <rosen...@intel.com>; Zhang, Qi Z
> <qi.z.zh...@intel.com>
> Cc: sta...@dpdk.org; Zhang, Tianfei <tianfei.zh...@intel.com>; Yigit, Ferruh
> <ferruh.yi...@intel.com>
> Subject: [PATCH v1] raw/ifpga/base: fix SPI transaction
> 
> From: Tianfei Zhang <tianfei.zh...@intel.com>
> 
> When EOP is detected, 2 more bytes should be received (may be a
> SPI_PACKET_ESC before last valid byte) then rx should be finished.
> 
> Fixes: 96ebfcf8 ("raw/ifpga/base: add SPI and MAX10 device driver")
> Cc: sta...@dpdk.org
> 
> Signed-off-by: Tianfei Zhang <tianfei.zh...@intel.com>
> ---
>  drivers/raw/ifpga/base/opae_spi.c             |  12 ++
>  drivers/raw/ifpga/base/opae_spi.h             |   4 +
>  drivers/raw/ifpga/base/opae_spi_transaction.c | 215 +++++++++++++++------
> -----
>  3 files changed, 140 insertions(+), 91 deletions(-)
> 
> diff --git a/drivers/raw/ifpga/base/opae_spi.c
> b/drivers/raw/ifpga/base/opae_spi.c
> index 9efeecb..ca3d41f 100644
> --- a/drivers/raw/ifpga/base/opae_spi.c
> +++ b/drivers/raw/ifpga/base/opae_spi.c
> @@ -239,6 +239,18 @@ int spi_command(struct altera_spi_device *dev,
> unsigned int chip_select,
>       return 0;
>  }
> 
> +int spi_write(struct altera_spi_device *dev, unsigned int chip_select,
> +             unsigned int wlen, void *wdata)
> +{
> +     return spi_command(dev, chip_select, wlen, wdata, 0, NULL); }
> +
> +int spi_read(struct altera_spi_device *dev, unsigned int chip_select,
> +             unsigned int rlen, void *rdata)
> +{
> +     return spi_command(dev, chip_select, 0, NULL, rlen, rdata); }
> +
>  struct altera_spi_device *altera_spi_alloc(void *base, int type)  {
>       struct altera_spi_device *spi_dev =
> diff --git a/drivers/raw/ifpga/base/opae_spi.h
> b/drivers/raw/ifpga/base/opae_spi.h
> index af11656..bcff67d 100644
> --- a/drivers/raw/ifpga/base/opae_spi.h
> +++ b/drivers/raw/ifpga/base/opae_spi.h
> @@ -117,6 +117,10 @@ struct spi_tran_header {
>       u32 addr;
>  };
> 
> +int spi_read(struct altera_spi_device *dev, unsigned int chip_select,
> +             unsigned int rlen, void *rdata);
> +int spi_write(struct altera_spi_device *dev, unsigned int chip_select,
> +             unsigned int wlen, void *wdata);
>  int spi_command(struct altera_spi_device *dev, unsigned int chip_select,
>               unsigned int wlen, void *wdata, unsigned int rlen, void
> *rdata);  void spi_cs_deactivate(struct altera_spi_device *dev); diff --git
> a/drivers/raw/ifpga/base/opae_spi_transaction.c
> b/drivers/raw/ifpga/base/opae_spi_transaction.c
> index 006cdb4..cd50d40 100644
> --- a/drivers/raw/ifpga/base/opae_spi_transaction.c
> +++ b/drivers/raw/ifpga/base/opae_spi_transaction.c
> @@ -40,7 +40,7 @@ static void print_buffer(const char *string, void *buffer,
> int len)
>       printf("%s print buffer, len=%d\n", string, len);
> 
>       for (i = 0; i < len; i++)
> -             printf("%x ", *(p+i));
> +             printf("%02x ", *(p+i));
>       printf("\n");
>  }
>  #else
> @@ -72,43 +72,6 @@ static void reorder_phy_data(u8 bits_per_word,
>       }
>  }
> 
> -enum {
> -     SPI_FOUND_SOP,
> -     SPI_FOUND_EOP,
> -     SPI_NOT_FOUND,
> -};
> -
> -static int resp_find_sop_eop(unsigned char *resp, unsigned int len,
> -             int flags)
> -{
> -     int ret = SPI_NOT_FOUND;
> -
> -     unsigned char *b = resp;
> -
> -     /* find SOP */
> -     if (flags != SPI_FOUND_SOP) {
> -             while (b < resp + len && *b != SPI_PACKET_SOP)
> -                     b++;
> -
> -             if (*b != SPI_PACKET_SOP)
> -                     goto done;
> -
> -             ret = SPI_FOUND_SOP;
> -     }
> -
> -     /* find EOP */
> -     while (b < resp + len && *b != SPI_PACKET_EOP)
> -             b++;
> -
> -     if (*b != SPI_PACKET_EOP)
> -             goto done;
> -
> -     ret = SPI_FOUND_EOP;
> -
> -done:
> -     return ret;
> -}
> -
>  static void phy_tx_pad(unsigned char *phy_buf, unsigned int phy_buf_len,
>               unsigned int *aligned_len)
>  {
> @@ -137,6 +100,104 @@ static void phy_tx_pad(unsigned char *phy_buf,
> unsigned int phy_buf_len,
>               *p++ = SPI_BYTE_IDLE;
>  }
> 
> +#define RX_ALL_IDLE_DATA (SPI_BYTE_IDLE << 24 | SPI_BYTE_IDLE << 16 |
>       \
> +                      SPI_BYTE_IDLE << 8 | SPI_BYTE_IDLE)
> +
> +static bool all_idle_data(u8 *rxbuf)
> +{
> +     return *(u32 *)rxbuf == RX_ALL_IDLE_DATA; }
> +
> +static unsigned char *find_eop(u8 *rxbuf, u32 BPW) {
> +     return memchr(rxbuf, SPI_PACKET_EOP, BPW); }
> +
> +static int do_spi_txrx(struct spi_transaction_dev *dev,
> +             unsigned char *tx_buffer,
> +             unsigned int tx_len, unsigned char *rx_buffer,
> +             unsigned int rx_len,
> +             unsigned int *actual_rx)
> +{
> +     unsigned int rx_cnt = 0;
> +     int ret = 0;
> +     unsigned int BPW = 4;
> +     bool eop_found = false;
> +     unsigned char *eop;
> +     unsigned char *ptr;
> +     unsigned char *rxbuf = rx_buffer;
> +     int add_byte = 0;
> +     unsigned long ticks;
> +     unsigned long timeout;
> +
> +     /* send command */
> +     ret = spi_write(dev->dev, dev->chipselect, tx_len, tx_buffer);
> +     if (ret)
> +             return -EBUSY;
> +
> +     timeout = rte_get_timer_cycles() +
> +                             msecs_to_timer_cycles(2000);
> +
> +     /* read out data */
> +     while (rx_cnt < rx_len) {
> +             ret = spi_read(dev->dev, dev->chipselect, BPW, rxbuf);
> +             if (ret)
> +                     return -EBUSY;
> +
> +             /* skip all of invalid data */
> +             if (!eop_found && all_idle_data(rxbuf)) {
> +                     ticks = rte_get_timer_cycles();
> +                     if (!time_after(ticks, timeout)) {
> +                             continue;
> +                     } else {
> +                             dev_err(dev, "read spi data timeout\n");
> +                             return -ETIMEDOUT;
> +                     }
> +             }
> +
> +             rx_cnt += BPW;
> +             if (!eop_found) {
> +                     /* EOP is found, we read 2 more bytes and exit. */
> +                     eop = find_eop(rxbuf, BPW);
> +                     if (eop) {
> +                             if ((BPW + rxbuf - eop) > 2) {
> +                                     /*
> +                                      * check if the last 2 bytes are already
> +                                      * received in current word.
> +                                      */
> +                                     break;
> +                             } else if ((BPW + rxbuf - eop) == 2) {
> +                                     /*
> +                                      * skip if last byte is not SPI_BYTE_ESC
> +                                      * or SPI_PACKET_ESC. this is the valid
> +                                      * end of a response too.
> +                                      */
> +                                     ptr = eop + 1;
> +
> +                                     if (*ptr != SPI_BYTE_ESC &&
> +                                                     *ptr !=
> SPI_PACKET_ESC)
> +                                             break;
> +
> +                                     add_byte = 1;
> +                             } else {
> +                                     add_byte = 2;
> +                             }
> +
> +                             rx_len = min(rx_len,
> +                                             IFPGA_ALIGN(rx_cnt +
> +                                                     add_byte, BPW));
> +                             eop_found = true;
> +                     }
> +             }
> +             rxbuf += BPW;
> +     }
> +
> +     *actual_rx = rx_cnt;
> +     print_buffer("found valid data:", rx_buffer, rx_cnt);
> +
> +     return ret;
> +}
> +
>  static int byte_to_core_convert(struct spi_transaction_dev *dev,
>               unsigned int send_len, unsigned char *send_data,
>               unsigned int resp_len, unsigned char *resp_data, @@ -
> 148,15 +209,9 @@ static int byte_to_core_convert(struct
> spi_transaction_dev *dev,
>       unsigned char *resp_packet = dev->buffer->bytes_resp;
>       unsigned char *p;
>       unsigned char current_byte;
> -     unsigned char *tx_buffer;
>       unsigned int tx_len = 0;
> -     unsigned char *rx_buffer;
> -     unsigned int rx_len = 0;
> -     int retry = 0;
> -     int spi_flags;
> -     unsigned long timeout = msecs_to_timer_cycles(1000);
> -     unsigned long ticks;
>       unsigned int resp_max_len = 2 * resp_len;
> +     unsigned int actual_rx;
> 
>       print_buffer("before bytes:", send_data, send_len);
> 
> @@ -190,48 +245,15 @@ static int byte_to_core_convert(struct
> spi_transaction_dev *dev,
> 
>       print_buffer("after order to spi:", send_packet, tx_len);
> 
> -     /* call spi */
> -     tx_buffer = send_packet;
> -     rx_buffer = resp_packet;
> -     rx_len = resp_max_len;
> -     spi_flags = SPI_NOT_FOUND;
> -
> -read_again:
> -     ret = spi_command(dev->dev, dev->chipselect, tx_len, tx_buffer,
> -                     rx_len, rx_buffer);
> +     ret = do_spi_txrx(dev, send_packet, tx_len, resp_packet,
> +                     resp_max_len, &actual_rx);
>       if (ret)
> -             return -EBUSY;
> -
> -     print_buffer("read from spi:", rx_buffer, rx_len);
> -
> -     /* look for SOP firstly*/
> -     ret = resp_find_sop_eop(rx_buffer, rx_len - 1, spi_flags);
> -     if (ret != SPI_FOUND_EOP) {
> -             tx_buffer = NULL;
> -             tx_len = 0;
> -             ticks = rte_get_timer_cycles();
> -             if (time_after(ticks, timeout) &&
> -                             retry++ > SPI_MAX_RETRY) {
> -                     dev_err(NULL, "Have retry %d, found invalid packet
> data\n",
> -                             retry);
> -                     return -EBUSY;
> -             }
> -
> -             if (ret == SPI_FOUND_SOP) {
> -                     rx_buffer += rx_len;
> -                     resp_max_len += rx_len;
> -             }
> -
> -             spi_flags = ret;
> -             goto read_again;
> -     }
> -
> -     print_buffer("found valid data:", resp_packet, resp_max_len);
> +             return ret;
> 
>       /* analyze response packet */
>       i = 0;
>       p = resp_data;
> -     while (i < resp_max_len) {
> +     while (i < actual_rx) {
>               current_byte = resp_packet[i];
>               switch (current_byte) {
>               case SPI_BYTE_IDLE:
> @@ -337,9 +359,13 @@ static int packet_to_byte_conver(struct
> spi_transaction_dev *dev,
>               current_byte = resp_packet[i];
> 
>               switch (current_byte) {
> -             case SPI_PACKET_ESC:
> -             case SPI_PACKET_CHANNEL:
>               case SPI_PACKET_SOP:
> +                     dev_err(dev, "error on get SOP after SOP\n");
> +                     return -EINVAL;
> +             case SPI_PACKET_CHANNEL:
> +                     i += 2;
> +                     break;
> +             case SPI_PACKET_ESC:
>                       i++;
>                       current_byte = resp_packet[i];
>                       *p++ = xor_20(current_byte);
> @@ -348,23 +374,30 @@ static int packet_to_byte_conver(struct
> spi_transaction_dev *dev,
>               case SPI_PACKET_EOP:
>                       i++;
>                       current_byte = resp_packet[i];
> -                     if (current_byte == SPI_PACKET_ESC ||
> -                                     current_byte ==
> SPI_PACKET_CHANNEL ||
> -                                     current_byte == SPI_PACKET_SOP) {
> +                     switch (current_byte) {
> +                     case SPI_PACKET_ESC:
>                               i++;
>                               current_byte = resp_packet[i];
>                               *p++ = xor_20(current_byte);
> -                     } else
> +                             break;
> +                     case SPI_PACKET_CHANNEL:
> +                     case SPI_PACKET_SOP:
> +                     case SPI_PACKET_EOP:
> +                             dev_err(dev, "error get SOP/EOP after
> EOP\n");
> +                             return -EINVAL;
> +                     default:
>                               *p++ = current_byte;
> -                     i = valid_resp_len;
> -                     break;
> +                             break;
> +                     }
> +                     goto done;
> +
>               default:
>                       *p++ = current_byte;
>                       i++;
>               }
> -
>       }
> 
> +done:
>       *valid = p - resp_buf;
> 
>       print_buffer("after packet:", resp_buf, *valid);
> --
> 1.8.3.1

Acked-by: Rosen Xu <rosen...@intel.com>

Reply via email to