static int br_do_rx_and_pkt_phy_parse()

in regmap/regmap-spi-avmm.c [365:500]


static int br_do_rx_and_pkt_phy_parse(struct spi_avmm_bridge *br)
{
	bool eop_found = false, channel_found = false, esc_found = false;
	bool valid_word = false, last_try = false;
	struct device *dev = &br->spi->dev;
	char *pb, *tb_limit, *tb = NULL;
	unsigned long poll_timeout;
	int ret, i;

	tb_limit = br->trans_buf + ARRAY_SIZE(br->trans_buf);
	pb = br->phy_buf;
	poll_timeout = jiffies + SPI_AVMM_XFER_TIMEOUT;
	while (tb < tb_limit) {
		ret = spi_read(br->spi, pb, br->word_len);
		if (ret)
			return ret;

		/* reorder the word back */
		if (br->swap_words)
			br->swap_words(pb, br->word_len);

		valid_word = false;
		for (i = 0; i < br->word_len; i++) {
			/* drop everything before first SOP */
			if (!tb && pb[i] != PKT_SOP)
				continue;

			/* drop PHY_IDLE */
			if (pb[i] == PHY_IDLE)
				continue;

			valid_word = true;

			/*
			 * We don't support multiple channels, so error out if
			 * a non-zero channel number is found.
			 */
			if (channel_found) {
				if (pb[i] != 0) {
					dev_err(dev, "%s channel num != 0\n",
						__func__);
					return -EFAULT;
				}

				channel_found = false;
				continue;
			}

			switch (pb[i]) {
			case PKT_SOP:
				/*
				 * reset the parsing if a second SOP appears.
				 */
				tb = br->trans_buf;
				eop_found = false;
				channel_found = false;
				esc_found = false;
				break;
			case PKT_EOP:
				/*
				 * No special char is expected after ESC char.
				 * No special char (except ESC & PHY_IDLE) is
				 * expected after EOP char.
				 *
				 * The special chars are all dropped.
				 */
				if (esc_found || eop_found)
					return -EFAULT;

				eop_found = true;
				break;
			case PKT_CHANNEL:
				if (esc_found || eop_found)
					return -EFAULT;

				channel_found = true;
				break;
			case PKT_ESC:
			case PHY_ESC:
				if (esc_found)
					return -EFAULT;

				esc_found = true;
				break;
			default:
				/* Record the normal byte in trans_buf. */
				if (esc_found) {
					*tb++ = pb[i] ^ 0x20;
					esc_found = false;
				} else {
					*tb++ = pb[i];
				}

				/*
				 * We get the last normal byte after EOP, it is
				 * time we finish. Normally the function should
				 * return here.
				 */
				if (eop_found) {
					br->trans_len = tb - br->trans_buf;
					return 0;
				}
			}
		}

		if (valid_word) {
			/* update poll timeout when we get valid word */
			poll_timeout = jiffies + SPI_AVMM_XFER_TIMEOUT;
			last_try = false;
		} else {
			/*
			 * We timeout when rx keeps invalid for some time. But
			 * it is possible we are scheduled out for long time
			 * after a spi_read. So when we are scheduled in, a SW
			 * timeout happens. But actually HW may have worked fine and
			 * has been ready long time ago. So we need to do an extra
			 * read, if we get a valid word then we could continue rx,
			 * otherwise real a HW issue happens.
			 */
			if (last_try)
				return -ETIMEDOUT;

			if (time_after(jiffies, poll_timeout))
				last_try = true;
		}
	}

	/*
	 * We have used out all transfer layer buffer but cannot find the end
	 * of the byte stream.
	 */
	dev_err(dev, "%s transfer buffer is full but rx doesn't end\n",
		__func__);

	return -EFAULT;
}