18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include "fm10k_common.h"
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/**
78c2ecf20Sopenharmony_ci *  fm10k_fifo_init - Initialize a message FIFO
88c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
98c2ecf20Sopenharmony_ci *  @buffer: pointer to memory to be used to store FIFO
108c2ecf20Sopenharmony_ci *  @size: maximum message size to store in FIFO, must be 2^n - 1
118c2ecf20Sopenharmony_ci **/
128c2ecf20Sopenharmony_cistatic void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	fifo->buffer = buffer;
158c2ecf20Sopenharmony_ci	fifo->size = size;
168c2ecf20Sopenharmony_ci	fifo->head = 0;
178c2ecf20Sopenharmony_ci	fifo->tail = 0;
188c2ecf20Sopenharmony_ci}
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/**
218c2ecf20Sopenharmony_ci *  fm10k_fifo_used - Retrieve used space in FIFO
228c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci *  This function returns the number of DWORDs used in the FIFO
258c2ecf20Sopenharmony_ci **/
268c2ecf20Sopenharmony_cistatic u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	return fifo->tail - fifo->head;
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/**
328c2ecf20Sopenharmony_ci *  fm10k_fifo_unused - Retrieve unused space in FIFO
338c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci *  This function returns the number of unused DWORDs in the FIFO
368c2ecf20Sopenharmony_ci **/
378c2ecf20Sopenharmony_cistatic u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	return fifo->size + fifo->head - fifo->tail;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/**
438c2ecf20Sopenharmony_ci *  fm10k_fifo_empty - Test to verify if FIFO is empty
448c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci *  This function returns true if the FIFO is empty, else false
478c2ecf20Sopenharmony_ci **/
488c2ecf20Sopenharmony_cistatic bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	return fifo->head == fifo->tail;
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci/**
548c2ecf20Sopenharmony_ci *  fm10k_fifo_head_offset - returns indices of head with given offset
558c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
568c2ecf20Sopenharmony_ci *  @offset: offset to add to head
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci *  This function returns the indices into the FIFO based on head + offset
598c2ecf20Sopenharmony_ci **/
608c2ecf20Sopenharmony_cistatic u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	return (fifo->head + offset) & (fifo->size - 1);
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/**
668c2ecf20Sopenharmony_ci *  fm10k_fifo_tail_offset - returns indices of tail with given offset
678c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
688c2ecf20Sopenharmony_ci *  @offset: offset to add to tail
698c2ecf20Sopenharmony_ci *
708c2ecf20Sopenharmony_ci *  This function returns the indices into the FIFO based on tail + offset
718c2ecf20Sopenharmony_ci **/
728c2ecf20Sopenharmony_cistatic u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	return (fifo->tail + offset) & (fifo->size - 1);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/**
788c2ecf20Sopenharmony_ci *  fm10k_fifo_head_len - Retrieve length of first message in FIFO
798c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
808c2ecf20Sopenharmony_ci *
818c2ecf20Sopenharmony_ci *  This function returns the size of the first message in the FIFO
828c2ecf20Sopenharmony_ci **/
838c2ecf20Sopenharmony_cistatic u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	u32 *head = fifo->buffer + fm10k_fifo_head_offset(fifo, 0);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	/* verify there is at least 1 DWORD in the fifo so *head is valid */
888c2ecf20Sopenharmony_ci	if (fm10k_fifo_empty(fifo))
898c2ecf20Sopenharmony_ci		return 0;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/* retieve the message length */
928c2ecf20Sopenharmony_ci	return FM10K_TLV_DWORD_LEN(*head);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/**
968c2ecf20Sopenharmony_ci *  fm10k_fifo_head_drop - Drop the first message in FIFO
978c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
988c2ecf20Sopenharmony_ci *
998c2ecf20Sopenharmony_ci *  This function returns the size of the message dropped from the FIFO
1008c2ecf20Sopenharmony_ci **/
1018c2ecf20Sopenharmony_cistatic u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	u16 len = fm10k_fifo_head_len(fifo);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* update head so it is at the start of next frame */
1068c2ecf20Sopenharmony_ci	fifo->head += len;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return len;
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/**
1128c2ecf20Sopenharmony_ci *  fm10k_fifo_drop_all - Drop all messages in FIFO
1138c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
1148c2ecf20Sopenharmony_ci *
1158c2ecf20Sopenharmony_ci *  This function resets the head pointer to drop all messages in the FIFO and
1168c2ecf20Sopenharmony_ci *  ensure the FIFO is empty.
1178c2ecf20Sopenharmony_ci **/
1188c2ecf20Sopenharmony_cistatic void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	fifo->head = fifo->tail;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci/**
1248c2ecf20Sopenharmony_ci *  fm10k_mbx_index_len - Convert a head/tail index into a length value
1258c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
1268c2ecf20Sopenharmony_ci *  @head: head index
1278c2ecf20Sopenharmony_ci *  @tail: head index
1288c2ecf20Sopenharmony_ci *
1298c2ecf20Sopenharmony_ci *  This function takes the head and tail index and determines the length
1308c2ecf20Sopenharmony_ci *  of the data indicated by this pair.
1318c2ecf20Sopenharmony_ci **/
1328c2ecf20Sopenharmony_cistatic u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	u16 len = tail - head;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* we wrapped so subtract 2, one for index 0, one for all 1s index */
1378c2ecf20Sopenharmony_ci	if (len > tail)
1388c2ecf20Sopenharmony_ci		len -= 2;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return len & ((mbx->mbmem_len << 1) - 1);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/**
1448c2ecf20Sopenharmony_ci *  fm10k_mbx_tail_add - Determine new tail value with added offset
1458c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
1468c2ecf20Sopenharmony_ci *  @offset: length to add to tail offset
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci *  This function takes the local tail index and recomputes it for
1498c2ecf20Sopenharmony_ci *  a given length added as an offset.
1508c2ecf20Sopenharmony_ci **/
1518c2ecf20Sopenharmony_cistatic u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	u16 tail = (mbx->tail + offset + 1) & ((mbx->mbmem_len << 1) - 1);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* add/sub 1 because we cannot have offset 0 or all 1s */
1568c2ecf20Sopenharmony_ci	return (tail > mbx->tail) ? --tail : ++tail;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/**
1608c2ecf20Sopenharmony_ci *  fm10k_mbx_tail_sub - Determine new tail value with subtracted offset
1618c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
1628c2ecf20Sopenharmony_ci *  @offset: length to add to tail offset
1638c2ecf20Sopenharmony_ci *
1648c2ecf20Sopenharmony_ci *  This function takes the local tail index and recomputes it for
1658c2ecf20Sopenharmony_ci *  a given length added as an offset.
1668c2ecf20Sopenharmony_ci **/
1678c2ecf20Sopenharmony_cistatic u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	u16 tail = (mbx->tail - offset - 1) & ((mbx->mbmem_len << 1) - 1);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* sub/add 1 because we cannot have offset 0 or all 1s */
1728c2ecf20Sopenharmony_ci	return (tail < mbx->tail) ? ++tail : --tail;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/**
1768c2ecf20Sopenharmony_ci *  fm10k_mbx_head_add - Determine new head value with added offset
1778c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
1788c2ecf20Sopenharmony_ci *  @offset: length to add to head offset
1798c2ecf20Sopenharmony_ci *
1808c2ecf20Sopenharmony_ci *  This function takes the local head index and recomputes it for
1818c2ecf20Sopenharmony_ci *  a given length added as an offset.
1828c2ecf20Sopenharmony_ci **/
1838c2ecf20Sopenharmony_cistatic u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	u16 head = (mbx->head + offset + 1) & ((mbx->mbmem_len << 1) - 1);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* add/sub 1 because we cannot have offset 0 or all 1s */
1888c2ecf20Sopenharmony_ci	return (head > mbx->head) ? --head : ++head;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci/**
1928c2ecf20Sopenharmony_ci *  fm10k_mbx_head_sub - Determine new head value with subtracted offset
1938c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
1948c2ecf20Sopenharmony_ci *  @offset: length to add to head offset
1958c2ecf20Sopenharmony_ci *
1968c2ecf20Sopenharmony_ci *  This function takes the local head index and recomputes it for
1978c2ecf20Sopenharmony_ci *  a given length added as an offset.
1988c2ecf20Sopenharmony_ci **/
1998c2ecf20Sopenharmony_cistatic u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	u16 head = (mbx->head - offset - 1) & ((mbx->mbmem_len << 1) - 1);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* sub/add 1 because we cannot have offset 0 or all 1s */
2048c2ecf20Sopenharmony_ci	return (head < mbx->head) ? ++head : --head;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/**
2088c2ecf20Sopenharmony_ci *  fm10k_mbx_pushed_tail_len - Retrieve the length of message being pushed
2098c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
2108c2ecf20Sopenharmony_ci *
2118c2ecf20Sopenharmony_ci *  This function will return the length of the message currently being
2128c2ecf20Sopenharmony_ci *  pushed onto the tail of the Rx queue.
2138c2ecf20Sopenharmony_ci **/
2148c2ecf20Sopenharmony_cistatic u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* pushed tail is only valid if pushed is set */
2198c2ecf20Sopenharmony_ci	if (!mbx->pushed)
2208c2ecf20Sopenharmony_ci		return 0;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	return FM10K_TLV_DWORD_LEN(*tail);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci/**
2268c2ecf20Sopenharmony_ci *  fm10k_fifo_write_copy - pulls data off of msg and places it in FIFO
2278c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
2288c2ecf20Sopenharmony_ci *  @msg: message array to populate
2298c2ecf20Sopenharmony_ci *  @tail_offset: additional offset to add to tail pointer
2308c2ecf20Sopenharmony_ci *  @len: length of FIFO to copy into message header
2318c2ecf20Sopenharmony_ci *
2328c2ecf20Sopenharmony_ci *  This function will take a message and copy it into a section of the
2338c2ecf20Sopenharmony_ci *  FIFO.  In order to get something into a location other than just
2348c2ecf20Sopenharmony_ci *  the tail you can use tail_offset to adjust the pointer.
2358c2ecf20Sopenharmony_ci **/
2368c2ecf20Sopenharmony_cistatic void fm10k_fifo_write_copy(struct fm10k_mbx_fifo *fifo,
2378c2ecf20Sopenharmony_ci				  const u32 *msg, u16 tail_offset, u16 len)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	u16 end = fm10k_fifo_tail_offset(fifo, tail_offset);
2408c2ecf20Sopenharmony_ci	u32 *tail = fifo->buffer + end;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* track when we should cross the end of the FIFO */
2438c2ecf20Sopenharmony_ci	end = fifo->size - end;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* copy end of message before start of message */
2468c2ecf20Sopenharmony_ci	if (end < len)
2478c2ecf20Sopenharmony_ci		memcpy(fifo->buffer, msg + end, (len - end) << 2);
2488c2ecf20Sopenharmony_ci	else
2498c2ecf20Sopenharmony_ci		end = len;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* Copy remaining message into Tx FIFO */
2528c2ecf20Sopenharmony_ci	memcpy(tail, msg, end << 2);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/**
2568c2ecf20Sopenharmony_ci *  fm10k_fifo_enqueue - Enqueues the message to the tail of the FIFO
2578c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
2588c2ecf20Sopenharmony_ci *  @msg: message array to read
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci *  This function enqueues a message up to the size specified by the length
2618c2ecf20Sopenharmony_ci *  contained in the first DWORD of the message and will place at the tail
2628c2ecf20Sopenharmony_ci *  of the FIFO.  It will return 0 on success, or a negative value on error.
2638c2ecf20Sopenharmony_ci **/
2648c2ecf20Sopenharmony_cistatic s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	u16 len = FM10K_TLV_DWORD_LEN(*msg);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* verify parameters */
2698c2ecf20Sopenharmony_ci	if (len > fifo->size)
2708c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_SIZE;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* verify there is room for the message */
2738c2ecf20Sopenharmony_ci	if (len > fm10k_fifo_unused(fifo))
2748c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_NO_SPACE;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	/* Copy message into FIFO */
2778c2ecf20Sopenharmony_ci	fm10k_fifo_write_copy(fifo, msg, 0, len);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* memory barrier to guarantee FIFO is written before tail update */
2808c2ecf20Sopenharmony_ci	wmb();
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	/* Update Tx FIFO tail */
2838c2ecf20Sopenharmony_ci	fifo->tail += len;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return 0;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/**
2898c2ecf20Sopenharmony_ci *  fm10k_mbx_validate_msg_size - Validate incoming message based on size
2908c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
2918c2ecf20Sopenharmony_ci *  @len: length of data pushed onto buffer
2928c2ecf20Sopenharmony_ci *
2938c2ecf20Sopenharmony_ci *  This function analyzes the frame and will return a non-zero value when
2948c2ecf20Sopenharmony_ci *  the start of a message larger than the mailbox is detected.
2958c2ecf20Sopenharmony_ci **/
2968c2ecf20Sopenharmony_cistatic u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->rx;
2998c2ecf20Sopenharmony_ci	u16 total_len = 0, msg_len;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* length should include previous amounts pushed */
3028c2ecf20Sopenharmony_ci	len += mbx->pushed;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* offset in message is based off of current message size */
3058c2ecf20Sopenharmony_ci	do {
3068c2ecf20Sopenharmony_ci		u32 *msg;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len);
3098c2ecf20Sopenharmony_ci		msg_len = FM10K_TLV_DWORD_LEN(*msg);
3108c2ecf20Sopenharmony_ci		total_len += msg_len;
3118c2ecf20Sopenharmony_ci	} while (total_len < len);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* message extends out of pushed section, but fits in FIFO */
3148c2ecf20Sopenharmony_ci	if ((len < total_len) && (msg_len <= mbx->max_size))
3158c2ecf20Sopenharmony_ci		return 0;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* return length of invalid section */
3188c2ecf20Sopenharmony_ci	return (len < total_len) ? len : (len - total_len);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/**
3228c2ecf20Sopenharmony_ci *  fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem
3238c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
3248c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
3258c2ecf20Sopenharmony_ci *
3268c2ecf20Sopenharmony_ci *  This function will take a section of the Tx FIFO and copy it into the
3278c2ecf20Sopenharmony_ci *  mailbox memory.  The offset in mbmem is based on the lower bits of the
3288c2ecf20Sopenharmony_ci *  tail and len determines the length to copy.
3298c2ecf20Sopenharmony_ci **/
3308c2ecf20Sopenharmony_cistatic void fm10k_mbx_write_copy(struct fm10k_hw *hw,
3318c2ecf20Sopenharmony_ci				 struct fm10k_mbx_info *mbx)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->tx;
3348c2ecf20Sopenharmony_ci	u32 mbmem = mbx->mbmem_reg;
3358c2ecf20Sopenharmony_ci	u32 *head = fifo->buffer;
3368c2ecf20Sopenharmony_ci	u16 end, len, tail, mask;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (!mbx->tail_len)
3398c2ecf20Sopenharmony_ci		return;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	/* determine data length and mbmem tail index */
3428c2ecf20Sopenharmony_ci	mask = mbx->mbmem_len - 1;
3438c2ecf20Sopenharmony_ci	len = mbx->tail_len;
3448c2ecf20Sopenharmony_ci	tail = fm10k_mbx_tail_sub(mbx, len);
3458c2ecf20Sopenharmony_ci	if (tail > mask)
3468c2ecf20Sopenharmony_ci		tail++;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* determine offset in the ring */
3498c2ecf20Sopenharmony_ci	end = fm10k_fifo_head_offset(fifo, mbx->pulled);
3508c2ecf20Sopenharmony_ci	head += end;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* memory barrier to guarantee data is ready to be read */
3538c2ecf20Sopenharmony_ci	rmb();
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/* Copy message from Tx FIFO */
3568c2ecf20Sopenharmony_ci	for (end = fifo->size - end; len; head = fifo->buffer) {
3578c2ecf20Sopenharmony_ci		do {
3588c2ecf20Sopenharmony_ci			/* adjust tail to match offset for FIFO */
3598c2ecf20Sopenharmony_ci			tail &= mask;
3608c2ecf20Sopenharmony_ci			if (!tail)
3618c2ecf20Sopenharmony_ci				tail++;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci			mbx->tx_mbmem_pulled++;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci			/* write message to hardware FIFO */
3668c2ecf20Sopenharmony_ci			fm10k_write_reg(hw, mbmem + tail++, *(head++));
3678c2ecf20Sopenharmony_ci		} while (--len && --end);
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/**
3728c2ecf20Sopenharmony_ci *  fm10k_mbx_pull_head - Pulls data off of head of Tx FIFO
3738c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
3748c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
3758c2ecf20Sopenharmony_ci *  @head: acknowledgement number last received
3768c2ecf20Sopenharmony_ci *
3778c2ecf20Sopenharmony_ci *  This function will push the tail index forward based on the remote
3788c2ecf20Sopenharmony_ci *  head index.  It will then pull up to mbmem_len DWORDs off of the
3798c2ecf20Sopenharmony_ci *  head of the FIFO and will place it in the MBMEM registers
3808c2ecf20Sopenharmony_ci *  associated with the mailbox.
3818c2ecf20Sopenharmony_ci **/
3828c2ecf20Sopenharmony_cistatic void fm10k_mbx_pull_head(struct fm10k_hw *hw,
3838c2ecf20Sopenharmony_ci				struct fm10k_mbx_info *mbx, u16 head)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	u16 mbmem_len, len, ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
3868c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->tx;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	/* update number of bytes pulled and update bytes in transit */
3898c2ecf20Sopenharmony_ci	mbx->pulled += mbx->tail_len - ack;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* determine length of data to pull, reserve space for mbmem header */
3928c2ecf20Sopenharmony_ci	mbmem_len = mbx->mbmem_len - 1;
3938c2ecf20Sopenharmony_ci	len = fm10k_fifo_used(fifo) - mbx->pulled;
3948c2ecf20Sopenharmony_ci	if (len > mbmem_len)
3958c2ecf20Sopenharmony_ci		len = mbmem_len;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	/* update tail and record number of bytes in transit */
3988c2ecf20Sopenharmony_ci	mbx->tail = fm10k_mbx_tail_add(mbx, len - ack);
3998c2ecf20Sopenharmony_ci	mbx->tail_len = len;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	/* drop pulled messages from the FIFO */
4028c2ecf20Sopenharmony_ci	for (len = fm10k_fifo_head_len(fifo);
4038c2ecf20Sopenharmony_ci	     len && (mbx->pulled >= len);
4048c2ecf20Sopenharmony_ci	     len = fm10k_fifo_head_len(fifo)) {
4058c2ecf20Sopenharmony_ci		mbx->pulled -= fm10k_fifo_head_drop(fifo);
4068c2ecf20Sopenharmony_ci		mbx->tx_messages++;
4078c2ecf20Sopenharmony_ci		mbx->tx_dwords += len;
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* Copy message out from the Tx FIFO */
4118c2ecf20Sopenharmony_ci	fm10k_mbx_write_copy(hw, mbx);
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci/**
4158c2ecf20Sopenharmony_ci *  fm10k_mbx_read_copy - pulls data off of mbmem and places it in Rx FIFO
4168c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
4178c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
4188c2ecf20Sopenharmony_ci *
4198c2ecf20Sopenharmony_ci *  This function will take a section of the mailbox memory and copy it
4208c2ecf20Sopenharmony_ci *  into the Rx FIFO.  The offset is based on the lower bits of the
4218c2ecf20Sopenharmony_ci *  head and len determines the length to copy.
4228c2ecf20Sopenharmony_ci **/
4238c2ecf20Sopenharmony_cistatic void fm10k_mbx_read_copy(struct fm10k_hw *hw,
4248c2ecf20Sopenharmony_ci				struct fm10k_mbx_info *mbx)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->rx;
4278c2ecf20Sopenharmony_ci	u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len;
4288c2ecf20Sopenharmony_ci	u32 *tail = fifo->buffer;
4298c2ecf20Sopenharmony_ci	u16 end, len, head;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/* determine data length and mbmem head index */
4328c2ecf20Sopenharmony_ci	len = mbx->head_len;
4338c2ecf20Sopenharmony_ci	head = fm10k_mbx_head_sub(mbx, len);
4348c2ecf20Sopenharmony_ci	if (head >= mbx->mbmem_len)
4358c2ecf20Sopenharmony_ci		head++;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/* determine offset in the ring */
4388c2ecf20Sopenharmony_ci	end = fm10k_fifo_tail_offset(fifo, mbx->pushed);
4398c2ecf20Sopenharmony_ci	tail += end;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/* Copy message into Rx FIFO */
4428c2ecf20Sopenharmony_ci	for (end = fifo->size - end; len; tail = fifo->buffer) {
4438c2ecf20Sopenharmony_ci		do {
4448c2ecf20Sopenharmony_ci			/* adjust head to match offset for FIFO */
4458c2ecf20Sopenharmony_ci			head &= mbx->mbmem_len - 1;
4468c2ecf20Sopenharmony_ci			if (!head)
4478c2ecf20Sopenharmony_ci				head++;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci			mbx->rx_mbmem_pushed++;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci			/* read message from hardware FIFO */
4528c2ecf20Sopenharmony_ci			*(tail++) = fm10k_read_reg(hw, mbmem + head++);
4538c2ecf20Sopenharmony_ci		} while (--len && --end);
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* memory barrier to guarantee FIFO is written before tail update */
4578c2ecf20Sopenharmony_ci	wmb();
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci/**
4618c2ecf20Sopenharmony_ci *  fm10k_mbx_push_tail - Pushes up to 15 DWORDs on to tail of FIFO
4628c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
4638c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
4648c2ecf20Sopenharmony_ci *  @tail: tail index of message
4658c2ecf20Sopenharmony_ci *
4668c2ecf20Sopenharmony_ci *  This function will first validate the tail index and size for the
4678c2ecf20Sopenharmony_ci *  incoming message.  It then updates the acknowledgment number and
4688c2ecf20Sopenharmony_ci *  copies the data into the FIFO.  It will return the number of messages
4698c2ecf20Sopenharmony_ci *  dequeued on success and a negative value on error.
4708c2ecf20Sopenharmony_ci **/
4718c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_push_tail(struct fm10k_hw *hw,
4728c2ecf20Sopenharmony_ci			       struct fm10k_mbx_info *mbx,
4738c2ecf20Sopenharmony_ci			       u16 tail)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->rx;
4768c2ecf20Sopenharmony_ci	u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/* determine length of data to push */
4798c2ecf20Sopenharmony_ci	len = fm10k_fifo_unused(fifo) - mbx->pushed;
4808c2ecf20Sopenharmony_ci	if (len > seq)
4818c2ecf20Sopenharmony_ci		len = seq;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/* update head and record bytes received */
4848c2ecf20Sopenharmony_ci	mbx->head = fm10k_mbx_head_add(mbx, len);
4858c2ecf20Sopenharmony_ci	mbx->head_len = len;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* nothing to do if there is no data */
4888c2ecf20Sopenharmony_ci	if (!len)
4898c2ecf20Sopenharmony_ci		return 0;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	/* Copy msg into Rx FIFO */
4928c2ecf20Sopenharmony_ci	fm10k_mbx_read_copy(hw, mbx);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* determine if there are any invalid lengths in message */
4958c2ecf20Sopenharmony_ci	if (fm10k_mbx_validate_msg_size(mbx, len))
4968c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_SIZE;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	/* Update pushed */
4998c2ecf20Sopenharmony_ci	mbx->pushed += len;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	/* flush any completed messages */
5028c2ecf20Sopenharmony_ci	for (len = fm10k_mbx_pushed_tail_len(mbx);
5038c2ecf20Sopenharmony_ci	     len && (mbx->pushed >= len);
5048c2ecf20Sopenharmony_ci	     len = fm10k_mbx_pushed_tail_len(mbx)) {
5058c2ecf20Sopenharmony_ci		fifo->tail += len;
5068c2ecf20Sopenharmony_ci		mbx->pushed -= len;
5078c2ecf20Sopenharmony_ci		mbx->rx_messages++;
5088c2ecf20Sopenharmony_ci		mbx->rx_dwords += len;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	return 0;
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci/* pre-generated data for generating the CRC based on the poly 0xAC9A. */
5158c2ecf20Sopenharmony_cistatic const u16 fm10k_crc_16b_table[256] = {
5168c2ecf20Sopenharmony_ci	0x0000, 0x7956, 0xF2AC, 0x8BFA, 0xBC6D, 0xC53B, 0x4EC1, 0x3797,
5178c2ecf20Sopenharmony_ci	0x21EF, 0x58B9, 0xD343, 0xAA15, 0x9D82, 0xE4D4, 0x6F2E, 0x1678,
5188c2ecf20Sopenharmony_ci	0x43DE, 0x3A88, 0xB172, 0xC824, 0xFFB3, 0x86E5, 0x0D1F, 0x7449,
5198c2ecf20Sopenharmony_ci	0x6231, 0x1B67, 0x909D, 0xE9CB, 0xDE5C, 0xA70A, 0x2CF0, 0x55A6,
5208c2ecf20Sopenharmony_ci	0x87BC, 0xFEEA, 0x7510, 0x0C46, 0x3BD1, 0x4287, 0xC97D, 0xB02B,
5218c2ecf20Sopenharmony_ci	0xA653, 0xDF05, 0x54FF, 0x2DA9, 0x1A3E, 0x6368, 0xE892, 0x91C4,
5228c2ecf20Sopenharmony_ci	0xC462, 0xBD34, 0x36CE, 0x4F98, 0x780F, 0x0159, 0x8AA3, 0xF3F5,
5238c2ecf20Sopenharmony_ci	0xE58D, 0x9CDB, 0x1721, 0x6E77, 0x59E0, 0x20B6, 0xAB4C, 0xD21A,
5248c2ecf20Sopenharmony_ci	0x564D, 0x2F1B, 0xA4E1, 0xDDB7, 0xEA20, 0x9376, 0x188C, 0x61DA,
5258c2ecf20Sopenharmony_ci	0x77A2, 0x0EF4, 0x850E, 0xFC58, 0xCBCF, 0xB299, 0x3963, 0x4035,
5268c2ecf20Sopenharmony_ci	0x1593, 0x6CC5, 0xE73F, 0x9E69, 0xA9FE, 0xD0A8, 0x5B52, 0x2204,
5278c2ecf20Sopenharmony_ci	0x347C, 0x4D2A, 0xC6D0, 0xBF86, 0x8811, 0xF147, 0x7ABD, 0x03EB,
5288c2ecf20Sopenharmony_ci	0xD1F1, 0xA8A7, 0x235D, 0x5A0B, 0x6D9C, 0x14CA, 0x9F30, 0xE666,
5298c2ecf20Sopenharmony_ci	0xF01E, 0x8948, 0x02B2, 0x7BE4, 0x4C73, 0x3525, 0xBEDF, 0xC789,
5308c2ecf20Sopenharmony_ci	0x922F, 0xEB79, 0x6083, 0x19D5, 0x2E42, 0x5714, 0xDCEE, 0xA5B8,
5318c2ecf20Sopenharmony_ci	0xB3C0, 0xCA96, 0x416C, 0x383A, 0x0FAD, 0x76FB, 0xFD01, 0x8457,
5328c2ecf20Sopenharmony_ci	0xAC9A, 0xD5CC, 0x5E36, 0x2760, 0x10F7, 0x69A1, 0xE25B, 0x9B0D,
5338c2ecf20Sopenharmony_ci	0x8D75, 0xF423, 0x7FD9, 0x068F, 0x3118, 0x484E, 0xC3B4, 0xBAE2,
5348c2ecf20Sopenharmony_ci	0xEF44, 0x9612, 0x1DE8, 0x64BE, 0x5329, 0x2A7F, 0xA185, 0xD8D3,
5358c2ecf20Sopenharmony_ci	0xCEAB, 0xB7FD, 0x3C07, 0x4551, 0x72C6, 0x0B90, 0x806A, 0xF93C,
5368c2ecf20Sopenharmony_ci	0x2B26, 0x5270, 0xD98A, 0xA0DC, 0x974B, 0xEE1D, 0x65E7, 0x1CB1,
5378c2ecf20Sopenharmony_ci	0x0AC9, 0x739F, 0xF865, 0x8133, 0xB6A4, 0xCFF2, 0x4408, 0x3D5E,
5388c2ecf20Sopenharmony_ci	0x68F8, 0x11AE, 0x9A54, 0xE302, 0xD495, 0xADC3, 0x2639, 0x5F6F,
5398c2ecf20Sopenharmony_ci	0x4917, 0x3041, 0xBBBB, 0xC2ED, 0xF57A, 0x8C2C, 0x07D6, 0x7E80,
5408c2ecf20Sopenharmony_ci	0xFAD7, 0x8381, 0x087B, 0x712D, 0x46BA, 0x3FEC, 0xB416, 0xCD40,
5418c2ecf20Sopenharmony_ci	0xDB38, 0xA26E, 0x2994, 0x50C2, 0x6755, 0x1E03, 0x95F9, 0xECAF,
5428c2ecf20Sopenharmony_ci	0xB909, 0xC05F, 0x4BA5, 0x32F3, 0x0564, 0x7C32, 0xF7C8, 0x8E9E,
5438c2ecf20Sopenharmony_ci	0x98E6, 0xE1B0, 0x6A4A, 0x131C, 0x248B, 0x5DDD, 0xD627, 0xAF71,
5448c2ecf20Sopenharmony_ci	0x7D6B, 0x043D, 0x8FC7, 0xF691, 0xC106, 0xB850, 0x33AA, 0x4AFC,
5458c2ecf20Sopenharmony_ci	0x5C84, 0x25D2, 0xAE28, 0xD77E, 0xE0E9, 0x99BF, 0x1245, 0x6B13,
5468c2ecf20Sopenharmony_ci	0x3EB5, 0x47E3, 0xCC19, 0xB54F, 0x82D8, 0xFB8E, 0x7074, 0x0922,
5478c2ecf20Sopenharmony_ci	0x1F5A, 0x660C, 0xEDF6, 0x94A0, 0xA337, 0xDA61, 0x519B, 0x28CD };
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci/**
5508c2ecf20Sopenharmony_ci *  fm10k_crc_16b - Generate a 16 bit CRC for a region of 16 bit data
5518c2ecf20Sopenharmony_ci *  @data: pointer to data to process
5528c2ecf20Sopenharmony_ci *  @seed: seed value for CRC
5538c2ecf20Sopenharmony_ci *  @len: length measured in 16 bits words
5548c2ecf20Sopenharmony_ci *
5558c2ecf20Sopenharmony_ci *  This function will generate a CRC based on the polynomial 0xAC9A and
5568c2ecf20Sopenharmony_ci *  whatever value is stored in the seed variable.  Note that this
5578c2ecf20Sopenharmony_ci *  value inverts the local seed and the result in order to capture all
5588c2ecf20Sopenharmony_ci *  leading and trailing zeros.
5598c2ecf20Sopenharmony_ci */
5608c2ecf20Sopenharmony_cistatic u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	u32 result = seed;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	while (len--) {
5658c2ecf20Sopenharmony_ci		result ^= *(data++);
5668c2ecf20Sopenharmony_ci		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
5678c2ecf20Sopenharmony_ci		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		if (!(len--))
5708c2ecf20Sopenharmony_ci			break;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
5738c2ecf20Sopenharmony_ci		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	return (u16)result;
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci/**
5808c2ecf20Sopenharmony_ci *  fm10k_fifo_crc - generate a CRC based off of FIFO data
5818c2ecf20Sopenharmony_ci *  @fifo: pointer to FIFO
5828c2ecf20Sopenharmony_ci *  @offset: offset point for start of FIFO
5838c2ecf20Sopenharmony_ci *  @len: number of DWORDS words to process
5848c2ecf20Sopenharmony_ci *  @seed: seed value for CRC
5858c2ecf20Sopenharmony_ci *
5868c2ecf20Sopenharmony_ci *  This function generates a CRC for some region of the FIFO
5878c2ecf20Sopenharmony_ci **/
5888c2ecf20Sopenharmony_cistatic u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset,
5898c2ecf20Sopenharmony_ci			  u16 len, u16 seed)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	u32 *data = fifo->buffer + offset;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	/* track when we should cross the end of the FIFO */
5948c2ecf20Sopenharmony_ci	offset = fifo->size - offset;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	/* if we are in 2 blocks process the end of the FIFO first */
5978c2ecf20Sopenharmony_ci	if (offset < len) {
5988c2ecf20Sopenharmony_ci		seed = fm10k_crc_16b(data, seed, offset * 2);
5998c2ecf20Sopenharmony_ci		data = fifo->buffer;
6008c2ecf20Sopenharmony_ci		len -= offset;
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	/* process any remaining bits */
6048c2ecf20Sopenharmony_ci	return fm10k_crc_16b(data, seed, len * 2);
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci/**
6088c2ecf20Sopenharmony_ci *  fm10k_mbx_update_local_crc - Update the local CRC for outgoing data
6098c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
6108c2ecf20Sopenharmony_ci *  @head: head index provided by remote mailbox
6118c2ecf20Sopenharmony_ci *
6128c2ecf20Sopenharmony_ci *  This function will generate the CRC for all data from the end of the
6138c2ecf20Sopenharmony_ci *  last head update to the current one.  It uses the result of the
6148c2ecf20Sopenharmony_ci *  previous CRC as the seed for this update.  The result is stored in
6158c2ecf20Sopenharmony_ci *  mbx->local.
6168c2ecf20Sopenharmony_ci **/
6178c2ecf20Sopenharmony_cistatic void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	u16 len = mbx->tail_len - fm10k_mbx_index_len(mbx, head, mbx->tail);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	/* determine the offset for the start of the region to be pulled */
6228c2ecf20Sopenharmony_ci	head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	/* update local CRC to include all of the pulled data */
6258c2ecf20Sopenharmony_ci	mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local);
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci/**
6298c2ecf20Sopenharmony_ci *  fm10k_mbx_verify_remote_crc - Verify the CRC is correct for current data
6308c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
6318c2ecf20Sopenharmony_ci *
6328c2ecf20Sopenharmony_ci *  This function will take all data that has been provided from the remote
6338c2ecf20Sopenharmony_ci *  end and generate a CRC for it.  This is stored in mbx->remote.  The
6348c2ecf20Sopenharmony_ci *  CRC for the header is then computed and if the result is non-zero this
6358c2ecf20Sopenharmony_ci *  is an error and we signal an error dropping all data and resetting the
6368c2ecf20Sopenharmony_ci *  connection.
6378c2ecf20Sopenharmony_ci */
6388c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->rx;
6418c2ecf20Sopenharmony_ci	u16 len = mbx->head_len;
6428c2ecf20Sopenharmony_ci	u16 offset = fm10k_fifo_tail_offset(fifo, mbx->pushed) - len;
6438c2ecf20Sopenharmony_ci	u16 crc;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	/* update the remote CRC if new data has been received */
6468c2ecf20Sopenharmony_ci	if (len)
6478c2ecf20Sopenharmony_ci		mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	/* process the full header as we have to validate the CRC */
6508c2ecf20Sopenharmony_ci	crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	/* notify other end if we have a problem */
6538c2ecf20Sopenharmony_ci	return crc ? FM10K_MBX_ERR_CRC : 0;
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci/**
6578c2ecf20Sopenharmony_ci *  fm10k_mbx_rx_ready - Indicates that a message is ready in the Rx FIFO
6588c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
6598c2ecf20Sopenharmony_ci *
6608c2ecf20Sopenharmony_ci *  This function returns true if there is a message in the Rx FIFO to dequeue.
6618c2ecf20Sopenharmony_ci **/
6628c2ecf20Sopenharmony_cistatic bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	u16 msg_size = fm10k_fifo_head_len(&mbx->rx);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	return msg_size && (fm10k_fifo_used(&mbx->rx) >= msg_size);
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci/**
6708c2ecf20Sopenharmony_ci *  fm10k_mbx_tx_ready - Indicates that the mailbox is in state ready for Tx
6718c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
6728c2ecf20Sopenharmony_ci *  @len: verify free space is >= this value
6738c2ecf20Sopenharmony_ci *
6748c2ecf20Sopenharmony_ci *  This function returns true if the mailbox is in a state ready to transmit.
6758c2ecf20Sopenharmony_ci **/
6768c2ecf20Sopenharmony_cistatic bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	u16 fifo_unused = fm10k_fifo_unused(&mbx->tx);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	return (mbx->state == FM10K_STATE_OPEN) && (fifo_unused >= len);
6818c2ecf20Sopenharmony_ci}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci/**
6848c2ecf20Sopenharmony_ci *  fm10k_mbx_tx_complete - Indicates that the Tx FIFO has been emptied
6858c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
6868c2ecf20Sopenharmony_ci *
6878c2ecf20Sopenharmony_ci *  This function returns true if the Tx FIFO is empty.
6888c2ecf20Sopenharmony_ci **/
6898c2ecf20Sopenharmony_cistatic bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx)
6908c2ecf20Sopenharmony_ci{
6918c2ecf20Sopenharmony_ci	return fm10k_fifo_empty(&mbx->tx);
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci/**
6958c2ecf20Sopenharmony_ci *  fm10k_mbx_deqeueue_rx - Dequeues the message from the head in the Rx FIFO
6968c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
6978c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
6988c2ecf20Sopenharmony_ci *
6998c2ecf20Sopenharmony_ci *  This function dequeues messages and hands them off to the TLV parser.
7008c2ecf20Sopenharmony_ci *  It will return the number of messages processed when called.
7018c2ecf20Sopenharmony_ci **/
7028c2ecf20Sopenharmony_cistatic u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw,
7038c2ecf20Sopenharmony_ci				struct fm10k_mbx_info *mbx)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->rx;
7068c2ecf20Sopenharmony_ci	s32 err;
7078c2ecf20Sopenharmony_ci	u16 cnt;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	/* parse Rx messages out of the Rx FIFO to empty it */
7108c2ecf20Sopenharmony_ci	for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) {
7118c2ecf20Sopenharmony_ci		err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head,
7128c2ecf20Sopenharmony_ci					  mbx, mbx->msg_data);
7138c2ecf20Sopenharmony_ci		if (err < 0)
7148c2ecf20Sopenharmony_ci			mbx->rx_parse_err++;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci		fm10k_fifo_head_drop(fifo);
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	/* shift remaining bytes back to start of FIFO */
7208c2ecf20Sopenharmony_ci	memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/* shift head and tail based on the memory we moved */
7238c2ecf20Sopenharmony_ci	fifo->tail -= fifo->head;
7248c2ecf20Sopenharmony_ci	fifo->head = 0;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	return cnt;
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci/**
7308c2ecf20Sopenharmony_ci *  fm10k_mbx_enqueue_tx - Enqueues the message to the tail of the Tx FIFO
7318c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
7328c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
7338c2ecf20Sopenharmony_ci *  @msg: message array to read
7348c2ecf20Sopenharmony_ci *
7358c2ecf20Sopenharmony_ci *  This function enqueues a message up to the size specified by the length
7368c2ecf20Sopenharmony_ci *  contained in the first DWORD of the message and will place at the tail
7378c2ecf20Sopenharmony_ci *  of the FIFO.  It will return 0 on success, or a negative value on error.
7388c2ecf20Sopenharmony_ci **/
7398c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw,
7408c2ecf20Sopenharmony_ci				struct fm10k_mbx_info *mbx, const u32 *msg)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	u32 countdown = mbx->timeout;
7438c2ecf20Sopenharmony_ci	s32 err;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	switch (mbx->state) {
7468c2ecf20Sopenharmony_ci	case FM10K_STATE_CLOSED:
7478c2ecf20Sopenharmony_ci	case FM10K_STATE_DISCONNECT:
7488c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_NO_MBX;
7498c2ecf20Sopenharmony_ci	default:
7508c2ecf20Sopenharmony_ci		break;
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	/* enqueue the message on the Tx FIFO */
7548c2ecf20Sopenharmony_ci	err = fm10k_fifo_enqueue(&mbx->tx, msg);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	/* if it failed give the FIFO a chance to drain */
7578c2ecf20Sopenharmony_ci	while (err && countdown) {
7588c2ecf20Sopenharmony_ci		countdown--;
7598c2ecf20Sopenharmony_ci		udelay(mbx->udelay);
7608c2ecf20Sopenharmony_ci		mbx->ops.process(hw, mbx);
7618c2ecf20Sopenharmony_ci		err = fm10k_fifo_enqueue(&mbx->tx, msg);
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	/* if we failed treat the error */
7658c2ecf20Sopenharmony_ci	if (err) {
7668c2ecf20Sopenharmony_ci		mbx->timeout = 0;
7678c2ecf20Sopenharmony_ci		mbx->tx_busy++;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	/* begin processing message, ignore errors as this is just meant
7718c2ecf20Sopenharmony_ci	 * to start the mailbox flow so we are not concerned if there
7728c2ecf20Sopenharmony_ci	 * is a bad error, or the mailbox is already busy with a request
7738c2ecf20Sopenharmony_ci	 */
7748c2ecf20Sopenharmony_ci	if (!mbx->tail_len)
7758c2ecf20Sopenharmony_ci		mbx->ops.process(hw, mbx);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	return 0;
7788c2ecf20Sopenharmony_ci}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci/**
7818c2ecf20Sopenharmony_ci *  fm10k_mbx_read - Copies the mbmem to local message buffer
7828c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
7838c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
7848c2ecf20Sopenharmony_ci *
7858c2ecf20Sopenharmony_ci *  This function copies the message from the mbmem to the message array
7868c2ecf20Sopenharmony_ci **/
7878c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	/* only allow one reader in here at a time */
7908c2ecf20Sopenharmony_ci	if (mbx->mbx_hdr)
7918c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_BUSY;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	/* read to capture initial interrupt bits */
7948c2ecf20Sopenharmony_ci	if (fm10k_read_reg(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT)
7958c2ecf20Sopenharmony_ci		mbx->mbx_lock = FM10K_MBX_ACK;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	/* write back interrupt bits to clear */
7988c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, mbx->mbx_reg,
7998c2ecf20Sopenharmony_ci			FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	/* read remote header */
8028c2ecf20Sopenharmony_ci	mbx->mbx_hdr = fm10k_read_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	return 0;
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci/**
8088c2ecf20Sopenharmony_ci *  fm10k_mbx_write - Copies the local message buffer to mbmem
8098c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
8108c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
8118c2ecf20Sopenharmony_ci *
8128c2ecf20Sopenharmony_ci *  This function copies the message from the the message array to mbmem
8138c2ecf20Sopenharmony_ci **/
8148c2ecf20Sopenharmony_cistatic void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	u32 mbmem = mbx->mbmem_reg;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	/* write new msg header to notify recipient of change */
8198c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, mbmem, mbx->mbx_hdr);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	/* write mailbox to send interrupt */
8228c2ecf20Sopenharmony_ci	if (mbx->mbx_lock)
8238c2ecf20Sopenharmony_ci		fm10k_write_reg(hw, mbx->mbx_reg, mbx->mbx_lock);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	/* we no longer are using the header so free it */
8268c2ecf20Sopenharmony_ci	mbx->mbx_hdr = 0;
8278c2ecf20Sopenharmony_ci	mbx->mbx_lock = 0;
8288c2ecf20Sopenharmony_ci}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci/**
8318c2ecf20Sopenharmony_ci *  fm10k_mbx_create_connect_hdr - Generate a connect mailbox header
8328c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
8338c2ecf20Sopenharmony_ci *
8348c2ecf20Sopenharmony_ci *  This function returns a connection mailbox header
8358c2ecf20Sopenharmony_ci **/
8368c2ecf20Sopenharmony_cistatic void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	mbx->mbx_lock |= FM10K_MBX_REQ;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) |
8418c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) |
8428c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE);
8438c2ecf20Sopenharmony_ci}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci/**
8468c2ecf20Sopenharmony_ci *  fm10k_mbx_create_data_hdr - Generate a data mailbox header
8478c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
8488c2ecf20Sopenharmony_ci *
8498c2ecf20Sopenharmony_ci *  This function returns a data mailbox header
8508c2ecf20Sopenharmony_ci **/
8518c2ecf20Sopenharmony_cistatic void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) |
8548c2ecf20Sopenharmony_ci		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
8558c2ecf20Sopenharmony_ci		  FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
8568c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->tx;
8578c2ecf20Sopenharmony_ci	u16 crc;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	if (mbx->tail_len)
8608c2ecf20Sopenharmony_ci		mbx->mbx_lock |= FM10K_MBX_REQ;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	/* generate CRC for data in flight and header */
8638c2ecf20Sopenharmony_ci	crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled),
8648c2ecf20Sopenharmony_ci			     mbx->tail_len, mbx->local);
8658c2ecf20Sopenharmony_ci	crc = fm10k_crc_16b(&hdr, crc, 1);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	/* load header to memory to be written */
8688c2ecf20Sopenharmony_ci	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci/**
8728c2ecf20Sopenharmony_ci *  fm10k_mbx_create_disconnect_hdr - Generate a disconnect mailbox header
8738c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
8748c2ecf20Sopenharmony_ci *
8758c2ecf20Sopenharmony_ci *  This function returns a disconnect mailbox header
8768c2ecf20Sopenharmony_ci **/
8778c2ecf20Sopenharmony_cistatic void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
8788c2ecf20Sopenharmony_ci{
8798c2ecf20Sopenharmony_ci	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
8808c2ecf20Sopenharmony_ci		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
8818c2ecf20Sopenharmony_ci		  FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
8828c2ecf20Sopenharmony_ci	u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	mbx->mbx_lock |= FM10K_MBX_ACK;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	/* load header to memory to be written */
8878c2ecf20Sopenharmony_ci	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci/**
8918c2ecf20Sopenharmony_ci *  fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mbox hdr
8928c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
8938c2ecf20Sopenharmony_ci *
8948c2ecf20Sopenharmony_ci *  This function creates a fake disconnect header for loading into remote
8958c2ecf20Sopenharmony_ci *  mailbox header. The primary purpose is to prevent errors on immediate
8968c2ecf20Sopenharmony_ci *  start up after mbx->connect.
8978c2ecf20Sopenharmony_ci **/
8988c2ecf20Sopenharmony_cistatic void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
9018c2ecf20Sopenharmony_ci		  FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
9028c2ecf20Sopenharmony_ci		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
9038c2ecf20Sopenharmony_ci	u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	mbx->mbx_lock |= FM10K_MBX_ACK;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	/* load header to memory to be written */
9088c2ecf20Sopenharmony_ci	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci/**
9128c2ecf20Sopenharmony_ci *  fm10k_mbx_create_error_msg - Generate an error message
9138c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
9148c2ecf20Sopenharmony_ci *  @err: local error encountered
9158c2ecf20Sopenharmony_ci *
9168c2ecf20Sopenharmony_ci *  This function will interpret the error provided by err, and based on
9178c2ecf20Sopenharmony_ci *  that it may shift the message by 1 DWORD and then place an error header
9188c2ecf20Sopenharmony_ci *  at the start of the message.
9198c2ecf20Sopenharmony_ci **/
9208c2ecf20Sopenharmony_cistatic void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
9218c2ecf20Sopenharmony_ci{
9228c2ecf20Sopenharmony_ci	/* only generate an error message for these types */
9238c2ecf20Sopenharmony_ci	switch (err) {
9248c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_TAIL:
9258c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_HEAD:
9268c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_TYPE:
9278c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_SIZE:
9288c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_RSVD0:
9298c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_CRC:
9308c2ecf20Sopenharmony_ci		break;
9318c2ecf20Sopenharmony_ci	default:
9328c2ecf20Sopenharmony_ci		return;
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	mbx->mbx_lock |= FM10K_MBX_REQ;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) |
9388c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) |
9398c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci/**
9438c2ecf20Sopenharmony_ci *  fm10k_mbx_validate_msg_hdr - Validate common fields in the message header
9448c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
9458c2ecf20Sopenharmony_ci *
9468c2ecf20Sopenharmony_ci *  This function will parse up the fields in the mailbox header and return
9478c2ecf20Sopenharmony_ci *  an error if the header contains any of a number of invalid configurations
9488c2ecf20Sopenharmony_ci *  including unrecognized type, invalid route, or a malformed message.
9498c2ecf20Sopenharmony_ci **/
9508c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_validate_msg_hdr(struct fm10k_mbx_info *mbx)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	u16 type, rsvd0, head, tail, size;
9538c2ecf20Sopenharmony_ci	const u32 *hdr = &mbx->mbx_hdr;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE);
9568c2ecf20Sopenharmony_ci	rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0);
9578c2ecf20Sopenharmony_ci	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
9588c2ecf20Sopenharmony_ci	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
9598c2ecf20Sopenharmony_ci	size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (rsvd0)
9628c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_RSVD0;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	switch (type) {
9658c2ecf20Sopenharmony_ci	case FM10K_MSG_DISCONNECT:
9668c2ecf20Sopenharmony_ci		/* validate that all data has been received */
9678c2ecf20Sopenharmony_ci		if (tail != mbx->head)
9688c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_TAIL;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci		fallthrough;
9718c2ecf20Sopenharmony_ci	case FM10K_MSG_DATA:
9728c2ecf20Sopenharmony_ci		/* validate that head is moving correctly */
9738c2ecf20Sopenharmony_ci		if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
9748c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_HEAD;
9758c2ecf20Sopenharmony_ci		if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
9768c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_HEAD;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci		/* validate that tail is moving correctly */
9798c2ecf20Sopenharmony_ci		if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL)))
9808c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_TAIL;
9818c2ecf20Sopenharmony_ci		if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
9828c2ecf20Sopenharmony_ci			break;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_TAIL;
9858c2ecf20Sopenharmony_ci	case FM10K_MSG_CONNECT:
9868c2ecf20Sopenharmony_ci		/* validate size is in range and is power of 2 mask */
9878c2ecf20Sopenharmony_ci		if ((size < FM10K_VFMBX_MSG_MTU) || (size & (size + 1)))
9888c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_SIZE;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci		fallthrough;
9918c2ecf20Sopenharmony_ci	case FM10K_MSG_ERROR:
9928c2ecf20Sopenharmony_ci		if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
9938c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_HEAD;
9948c2ecf20Sopenharmony_ci		/* neither create nor error include a tail offset */
9958c2ecf20Sopenharmony_ci		if (tail)
9968c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_TAIL;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci		break;
9998c2ecf20Sopenharmony_ci	default:
10008c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_TYPE;
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	return 0;
10048c2ecf20Sopenharmony_ci}
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci/**
10078c2ecf20Sopenharmony_ci *  fm10k_mbx_create_reply - Generate reply based on state and remote head
10088c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
10098c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
10108c2ecf20Sopenharmony_ci *  @head: acknowledgement number
10118c2ecf20Sopenharmony_ci *
10128c2ecf20Sopenharmony_ci *  This function will generate an outgoing message based on the current
10138c2ecf20Sopenharmony_ci *  mailbox state and the remote FIFO head.  It will return the length
10148c2ecf20Sopenharmony_ci *  of the outgoing message excluding header on success, and a negative value
10158c2ecf20Sopenharmony_ci *  on error.
10168c2ecf20Sopenharmony_ci **/
10178c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_create_reply(struct fm10k_hw *hw,
10188c2ecf20Sopenharmony_ci				  struct fm10k_mbx_info *mbx, u16 head)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	switch (mbx->state) {
10218c2ecf20Sopenharmony_ci	case FM10K_STATE_OPEN:
10228c2ecf20Sopenharmony_ci	case FM10K_STATE_DISCONNECT:
10238c2ecf20Sopenharmony_ci		/* update our checksum for the outgoing data */
10248c2ecf20Sopenharmony_ci		fm10k_mbx_update_local_crc(mbx, head);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci		/* as long as other end recognizes us keep sending data */
10278c2ecf20Sopenharmony_ci		fm10k_mbx_pull_head(hw, mbx, head);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci		/* generate new header based on data */
10308c2ecf20Sopenharmony_ci		if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN))
10318c2ecf20Sopenharmony_ci			fm10k_mbx_create_data_hdr(mbx);
10328c2ecf20Sopenharmony_ci		else
10338c2ecf20Sopenharmony_ci			fm10k_mbx_create_disconnect_hdr(mbx);
10348c2ecf20Sopenharmony_ci		break;
10358c2ecf20Sopenharmony_ci	case FM10K_STATE_CONNECT:
10368c2ecf20Sopenharmony_ci		/* send disconnect even if we aren't connected */
10378c2ecf20Sopenharmony_ci		fm10k_mbx_create_connect_hdr(mbx);
10388c2ecf20Sopenharmony_ci		break;
10398c2ecf20Sopenharmony_ci	case FM10K_STATE_CLOSED:
10408c2ecf20Sopenharmony_ci		/* generate new header based on data */
10418c2ecf20Sopenharmony_ci		fm10k_mbx_create_disconnect_hdr(mbx);
10428c2ecf20Sopenharmony_ci	default:
10438c2ecf20Sopenharmony_ci		break;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	return 0;
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci/**
10508c2ecf20Sopenharmony_ci *  fm10k_mbx_reset_work- Reset internal pointers for any pending work
10518c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
10528c2ecf20Sopenharmony_ci *
10538c2ecf20Sopenharmony_ci *  This function will reset all internal pointers so any work in progress
10548c2ecf20Sopenharmony_ci *  is dropped.  This call should occur every time we transition from the
10558c2ecf20Sopenharmony_ci *  open state to the connect state.
10568c2ecf20Sopenharmony_ci **/
10578c2ecf20Sopenharmony_cistatic void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx)
10588c2ecf20Sopenharmony_ci{
10598c2ecf20Sopenharmony_ci	u16 len, head, ack;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	/* reset our outgoing max size back to Rx limits */
10628c2ecf20Sopenharmony_ci	mbx->max_size = mbx->rx.size - 1;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	/* update mbx->pulled to account for tail_len and ack */
10658c2ecf20Sopenharmony_ci	head = FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, HEAD);
10668c2ecf20Sopenharmony_ci	ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
10678c2ecf20Sopenharmony_ci	mbx->pulled += mbx->tail_len - ack;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	/* now drop any messages which have started or finished transmitting */
10708c2ecf20Sopenharmony_ci	while (fm10k_fifo_head_len(&mbx->tx) && mbx->pulled) {
10718c2ecf20Sopenharmony_ci		len = fm10k_fifo_head_drop(&mbx->tx);
10728c2ecf20Sopenharmony_ci		mbx->tx_dropped++;
10738c2ecf20Sopenharmony_ci		if (mbx->pulled >= len)
10748c2ecf20Sopenharmony_ci			mbx->pulled -= len;
10758c2ecf20Sopenharmony_ci		else
10768c2ecf20Sopenharmony_ci			mbx->pulled = 0;
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	/* just do a quick resysnc to start of message */
10808c2ecf20Sopenharmony_ci	mbx->pushed = 0;
10818c2ecf20Sopenharmony_ci	mbx->pulled = 0;
10828c2ecf20Sopenharmony_ci	mbx->tail_len = 0;
10838c2ecf20Sopenharmony_ci	mbx->head_len = 0;
10848c2ecf20Sopenharmony_ci	mbx->rx.tail = 0;
10858c2ecf20Sopenharmony_ci	mbx->rx.head = 0;
10868c2ecf20Sopenharmony_ci}
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci/**
10898c2ecf20Sopenharmony_ci *  fm10k_mbx_update_max_size - Update the max_size and drop any large messages
10908c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
10918c2ecf20Sopenharmony_ci *  @size: new value for max_size
10928c2ecf20Sopenharmony_ci *
10938c2ecf20Sopenharmony_ci *  This function updates the max_size value and drops any outgoing messages
10948c2ecf20Sopenharmony_ci *  at the head of the Tx FIFO if they are larger than max_size. It does not
10958c2ecf20Sopenharmony_ci *  drop all messages, as this is too difficult to parse and remove them from
10968c2ecf20Sopenharmony_ci *  the FIFO. Instead, rely on the checking to ensure that messages larger
10978c2ecf20Sopenharmony_ci *  than max_size aren't pushed into the memory buffer.
10988c2ecf20Sopenharmony_ci **/
10998c2ecf20Sopenharmony_cistatic void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	u16 len;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	mbx->max_size = size;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	/* flush any oversized messages from the queue */
11068c2ecf20Sopenharmony_ci	for (len = fm10k_fifo_head_len(&mbx->tx);
11078c2ecf20Sopenharmony_ci	     len > size;
11088c2ecf20Sopenharmony_ci	     len = fm10k_fifo_head_len(&mbx->tx)) {
11098c2ecf20Sopenharmony_ci		fm10k_fifo_head_drop(&mbx->tx);
11108c2ecf20Sopenharmony_ci		mbx->tx_dropped++;
11118c2ecf20Sopenharmony_ci	}
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci/**
11158c2ecf20Sopenharmony_ci *  fm10k_mbx_connect_reset - Reset following request for reset
11168c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
11178c2ecf20Sopenharmony_ci *
11188c2ecf20Sopenharmony_ci *  This function resets the mailbox to either a disconnected state
11198c2ecf20Sopenharmony_ci *  or a connect state depending on the current mailbox state
11208c2ecf20Sopenharmony_ci **/
11218c2ecf20Sopenharmony_cistatic void fm10k_mbx_connect_reset(struct fm10k_mbx_info *mbx)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	/* just do a quick resysnc to start of frame */
11248c2ecf20Sopenharmony_ci	fm10k_mbx_reset_work(mbx);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	/* reset CRC seeds */
11278c2ecf20Sopenharmony_ci	mbx->local = FM10K_MBX_CRC_SEED;
11288c2ecf20Sopenharmony_ci	mbx->remote = FM10K_MBX_CRC_SEED;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	/* we cannot exit connect until the size is good */
11318c2ecf20Sopenharmony_ci	if (mbx->state == FM10K_STATE_OPEN)
11328c2ecf20Sopenharmony_ci		mbx->state = FM10K_STATE_CONNECT;
11338c2ecf20Sopenharmony_ci	else
11348c2ecf20Sopenharmony_ci		mbx->state = FM10K_STATE_CLOSED;
11358c2ecf20Sopenharmony_ci}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci/**
11388c2ecf20Sopenharmony_ci *  fm10k_mbx_process_connect - Process connect header
11398c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
11408c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
11418c2ecf20Sopenharmony_ci *
11428c2ecf20Sopenharmony_ci *  This function will read an incoming connect header and reply with the
11438c2ecf20Sopenharmony_ci *  appropriate message.  It will return a value indicating the number of
11448c2ecf20Sopenharmony_ci *  data DWORDs on success, or will return a negative value on failure.
11458c2ecf20Sopenharmony_ci **/
11468c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_process_connect(struct fm10k_hw *hw,
11478c2ecf20Sopenharmony_ci				     struct fm10k_mbx_info *mbx)
11488c2ecf20Sopenharmony_ci{
11498c2ecf20Sopenharmony_ci	const enum fm10k_mbx_state state = mbx->state;
11508c2ecf20Sopenharmony_ci	const u32 *hdr = &mbx->mbx_hdr;
11518c2ecf20Sopenharmony_ci	u16 size, head;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	/* we will need to pull all of the fields for verification */
11548c2ecf20Sopenharmony_ci	size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
11558c2ecf20Sopenharmony_ci	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	switch (state) {
11588c2ecf20Sopenharmony_ci	case FM10K_STATE_DISCONNECT:
11598c2ecf20Sopenharmony_ci	case FM10K_STATE_OPEN:
11608c2ecf20Sopenharmony_ci		/* reset any in-progress work */
11618c2ecf20Sopenharmony_ci		fm10k_mbx_connect_reset(mbx);
11628c2ecf20Sopenharmony_ci		break;
11638c2ecf20Sopenharmony_ci	case FM10K_STATE_CONNECT:
11648c2ecf20Sopenharmony_ci		/* we cannot exit connect until the size is good */
11658c2ecf20Sopenharmony_ci		if (size > mbx->rx.size) {
11668c2ecf20Sopenharmony_ci			mbx->max_size = mbx->rx.size - 1;
11678c2ecf20Sopenharmony_ci		} else {
11688c2ecf20Sopenharmony_ci			/* record the remote system requesting connection */
11698c2ecf20Sopenharmony_ci			mbx->state = FM10K_STATE_OPEN;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci			fm10k_mbx_update_max_size(mbx, size);
11728c2ecf20Sopenharmony_ci		}
11738c2ecf20Sopenharmony_ci		break;
11748c2ecf20Sopenharmony_ci	default:
11758c2ecf20Sopenharmony_ci		break;
11768c2ecf20Sopenharmony_ci	}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	/* align our tail index to remote head index */
11798c2ecf20Sopenharmony_ci	mbx->tail = head;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	return fm10k_mbx_create_reply(hw, mbx, head);
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci/**
11858c2ecf20Sopenharmony_ci *  fm10k_mbx_process_data - Process data header
11868c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
11878c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
11888c2ecf20Sopenharmony_ci *
11898c2ecf20Sopenharmony_ci *  This function will read an incoming data header and reply with the
11908c2ecf20Sopenharmony_ci *  appropriate message.  It will return a value indicating the number of
11918c2ecf20Sopenharmony_ci *  data DWORDs on success, or will return a negative value on failure.
11928c2ecf20Sopenharmony_ci **/
11938c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_process_data(struct fm10k_hw *hw,
11948c2ecf20Sopenharmony_ci				  struct fm10k_mbx_info *mbx)
11958c2ecf20Sopenharmony_ci{
11968c2ecf20Sopenharmony_ci	const u32 *hdr = &mbx->mbx_hdr;
11978c2ecf20Sopenharmony_ci	u16 head, tail;
11988c2ecf20Sopenharmony_ci	s32 err;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	/* we will need to pull all of the fields for verification */
12018c2ecf20Sopenharmony_ci	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
12028c2ecf20Sopenharmony_ci	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	/* if we are in connect just update our data and go */
12058c2ecf20Sopenharmony_ci	if (mbx->state == FM10K_STATE_CONNECT) {
12068c2ecf20Sopenharmony_ci		mbx->tail = head;
12078c2ecf20Sopenharmony_ci		mbx->state = FM10K_STATE_OPEN;
12088c2ecf20Sopenharmony_ci	}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	/* abort on message size errors */
12118c2ecf20Sopenharmony_ci	err = fm10k_mbx_push_tail(hw, mbx, tail);
12128c2ecf20Sopenharmony_ci	if (err < 0)
12138c2ecf20Sopenharmony_ci		return err;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	/* verify the checksum on the incoming data */
12168c2ecf20Sopenharmony_ci	err = fm10k_mbx_verify_remote_crc(mbx);
12178c2ecf20Sopenharmony_ci	if (err)
12188c2ecf20Sopenharmony_ci		return err;
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	/* process messages if we have received any */
12218c2ecf20Sopenharmony_ci	fm10k_mbx_dequeue_rx(hw, mbx);
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	return fm10k_mbx_create_reply(hw, mbx, head);
12248c2ecf20Sopenharmony_ci}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci/**
12278c2ecf20Sopenharmony_ci *  fm10k_mbx_process_disconnect - Process disconnect header
12288c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
12298c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
12308c2ecf20Sopenharmony_ci *
12318c2ecf20Sopenharmony_ci *  This function will read an incoming disconnect header and reply with the
12328c2ecf20Sopenharmony_ci *  appropriate message.  It will return a value indicating the number of
12338c2ecf20Sopenharmony_ci *  data DWORDs on success, or will return a negative value on failure.
12348c2ecf20Sopenharmony_ci **/
12358c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw,
12368c2ecf20Sopenharmony_ci					struct fm10k_mbx_info *mbx)
12378c2ecf20Sopenharmony_ci{
12388c2ecf20Sopenharmony_ci	const enum fm10k_mbx_state state = mbx->state;
12398c2ecf20Sopenharmony_ci	const u32 *hdr = &mbx->mbx_hdr;
12408c2ecf20Sopenharmony_ci	u16 head;
12418c2ecf20Sopenharmony_ci	s32 err;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	/* we will need to pull the header field for verification */
12448c2ecf20Sopenharmony_ci	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	/* We should not be receiving disconnect if Rx is incomplete */
12478c2ecf20Sopenharmony_ci	if (mbx->pushed)
12488c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_TAIL;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	/* we have already verified mbx->head == tail so we know this is 0 */
12518c2ecf20Sopenharmony_ci	mbx->head_len = 0;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	/* verify the checksum on the incoming header is correct */
12548c2ecf20Sopenharmony_ci	err = fm10k_mbx_verify_remote_crc(mbx);
12558c2ecf20Sopenharmony_ci	if (err)
12568c2ecf20Sopenharmony_ci		return err;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	switch (state) {
12598c2ecf20Sopenharmony_ci	case FM10K_STATE_DISCONNECT:
12608c2ecf20Sopenharmony_ci	case FM10K_STATE_OPEN:
12618c2ecf20Sopenharmony_ci		/* state doesn't change if we still have work to do */
12628c2ecf20Sopenharmony_ci		if (!fm10k_mbx_tx_complete(mbx))
12638c2ecf20Sopenharmony_ci			break;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci		/* verify the head indicates we completed all transmits */
12668c2ecf20Sopenharmony_ci		if (head != mbx->tail)
12678c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_HEAD;
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci		/* reset any in-progress work */
12708c2ecf20Sopenharmony_ci		fm10k_mbx_connect_reset(mbx);
12718c2ecf20Sopenharmony_ci		break;
12728c2ecf20Sopenharmony_ci	default:
12738c2ecf20Sopenharmony_ci		break;
12748c2ecf20Sopenharmony_ci	}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	return fm10k_mbx_create_reply(hw, mbx, head);
12778c2ecf20Sopenharmony_ci}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci/**
12808c2ecf20Sopenharmony_ci *  fm10k_mbx_process_error - Process error header
12818c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
12828c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
12838c2ecf20Sopenharmony_ci *
12848c2ecf20Sopenharmony_ci *  This function will read an incoming error header and reply with the
12858c2ecf20Sopenharmony_ci *  appropriate message.  It will return a value indicating the number of
12868c2ecf20Sopenharmony_ci *  data DWORDs on success, or will return a negative value on failure.
12878c2ecf20Sopenharmony_ci **/
12888c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_process_error(struct fm10k_hw *hw,
12898c2ecf20Sopenharmony_ci				   struct fm10k_mbx_info *mbx)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	const u32 *hdr = &mbx->mbx_hdr;
12928c2ecf20Sopenharmony_ci	u16 head;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	/* we will need to pull all of the fields for verification */
12958c2ecf20Sopenharmony_ci	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	switch (mbx->state) {
12988c2ecf20Sopenharmony_ci	case FM10K_STATE_OPEN:
12998c2ecf20Sopenharmony_ci	case FM10K_STATE_DISCONNECT:
13008c2ecf20Sopenharmony_ci		/* flush any uncompleted work */
13018c2ecf20Sopenharmony_ci		fm10k_mbx_reset_work(mbx);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci		/* reset CRC seeds */
13048c2ecf20Sopenharmony_ci		mbx->local = FM10K_MBX_CRC_SEED;
13058c2ecf20Sopenharmony_ci		mbx->remote = FM10K_MBX_CRC_SEED;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci		/* reset tail index and size to prepare for reconnect */
13088c2ecf20Sopenharmony_ci		mbx->tail = head;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci		/* if open then reset max_size and go back to connect */
13118c2ecf20Sopenharmony_ci		if (mbx->state == FM10K_STATE_OPEN) {
13128c2ecf20Sopenharmony_ci			mbx->state = FM10K_STATE_CONNECT;
13138c2ecf20Sopenharmony_ci			break;
13148c2ecf20Sopenharmony_ci		}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci		/* send a connect message to get data flowing again */
13178c2ecf20Sopenharmony_ci		fm10k_mbx_create_connect_hdr(mbx);
13188c2ecf20Sopenharmony_ci		return 0;
13198c2ecf20Sopenharmony_ci	default:
13208c2ecf20Sopenharmony_ci		break;
13218c2ecf20Sopenharmony_ci	}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	return fm10k_mbx_create_reply(hw, mbx, mbx->tail);
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci/**
13278c2ecf20Sopenharmony_ci *  fm10k_mbx_process - Process mailbox interrupt
13288c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
13298c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
13308c2ecf20Sopenharmony_ci *
13318c2ecf20Sopenharmony_ci *  This function will process incoming mailbox events and generate mailbox
13328c2ecf20Sopenharmony_ci *  replies.  It will return a value indicating the number of DWORDs
13338c2ecf20Sopenharmony_ci *  transmitted excluding header on success or a negative value on error.
13348c2ecf20Sopenharmony_ci **/
13358c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_process(struct fm10k_hw *hw,
13368c2ecf20Sopenharmony_ci			     struct fm10k_mbx_info *mbx)
13378c2ecf20Sopenharmony_ci{
13388c2ecf20Sopenharmony_ci	s32 err;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	/* we do not read mailbox if closed */
13418c2ecf20Sopenharmony_ci	if (mbx->state == FM10K_STATE_CLOSED)
13428c2ecf20Sopenharmony_ci		return 0;
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	/* copy data from mailbox */
13458c2ecf20Sopenharmony_ci	err = fm10k_mbx_read(hw, mbx);
13468c2ecf20Sopenharmony_ci	if (err)
13478c2ecf20Sopenharmony_ci		return err;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	/* validate type, source, and destination */
13508c2ecf20Sopenharmony_ci	err = fm10k_mbx_validate_msg_hdr(mbx);
13518c2ecf20Sopenharmony_ci	if (err < 0)
13528c2ecf20Sopenharmony_ci		goto msg_err;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, TYPE)) {
13558c2ecf20Sopenharmony_ci	case FM10K_MSG_CONNECT:
13568c2ecf20Sopenharmony_ci		err = fm10k_mbx_process_connect(hw, mbx);
13578c2ecf20Sopenharmony_ci		break;
13588c2ecf20Sopenharmony_ci	case FM10K_MSG_DATA:
13598c2ecf20Sopenharmony_ci		err = fm10k_mbx_process_data(hw, mbx);
13608c2ecf20Sopenharmony_ci		break;
13618c2ecf20Sopenharmony_ci	case FM10K_MSG_DISCONNECT:
13628c2ecf20Sopenharmony_ci		err = fm10k_mbx_process_disconnect(hw, mbx);
13638c2ecf20Sopenharmony_ci		break;
13648c2ecf20Sopenharmony_ci	case FM10K_MSG_ERROR:
13658c2ecf20Sopenharmony_ci		err = fm10k_mbx_process_error(hw, mbx);
13668c2ecf20Sopenharmony_ci		break;
13678c2ecf20Sopenharmony_ci	default:
13688c2ecf20Sopenharmony_ci		err = FM10K_MBX_ERR_TYPE;
13698c2ecf20Sopenharmony_ci		break;
13708c2ecf20Sopenharmony_ci	}
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_cimsg_err:
13738c2ecf20Sopenharmony_ci	/* notify partner of errors on our end */
13748c2ecf20Sopenharmony_ci	if (err < 0)
13758c2ecf20Sopenharmony_ci		fm10k_mbx_create_error_msg(mbx, err);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	/* copy data from mailbox */
13788c2ecf20Sopenharmony_ci	fm10k_mbx_write(hw, mbx);
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	return err;
13818c2ecf20Sopenharmony_ci}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci/**
13848c2ecf20Sopenharmony_ci *  fm10k_mbx_disconnect - Shutdown mailbox connection
13858c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
13868c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
13878c2ecf20Sopenharmony_ci *
13888c2ecf20Sopenharmony_ci *  This function will shut down the mailbox.  It places the mailbox first
13898c2ecf20Sopenharmony_ci *  in the disconnect state, it then allows up to a predefined timeout for
13908c2ecf20Sopenharmony_ci *  the mailbox to transition to close on its own.  If this does not occur
13918c2ecf20Sopenharmony_ci *  then the mailbox will be forced into the closed state.
13928c2ecf20Sopenharmony_ci *
13938c2ecf20Sopenharmony_ci *  Any mailbox transactions not completed before calling this function
13948c2ecf20Sopenharmony_ci *  are not guaranteed to complete and may be dropped.
13958c2ecf20Sopenharmony_ci **/
13968c2ecf20Sopenharmony_cistatic void fm10k_mbx_disconnect(struct fm10k_hw *hw,
13978c2ecf20Sopenharmony_ci				 struct fm10k_mbx_info *mbx)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	/* Place mbx in ready to disconnect state */
14028c2ecf20Sopenharmony_ci	mbx->state = FM10K_STATE_DISCONNECT;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	/* trigger interrupt to start shutdown process */
14058c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, mbx->mbx_reg, FM10K_MBX_REQ |
14068c2ecf20Sopenharmony_ci					  FM10K_MBX_INTERRUPT_DISABLE);
14078c2ecf20Sopenharmony_ci	do {
14088c2ecf20Sopenharmony_ci		udelay(FM10K_MBX_POLL_DELAY);
14098c2ecf20Sopenharmony_ci		mbx->ops.process(hw, mbx);
14108c2ecf20Sopenharmony_ci		timeout -= FM10K_MBX_POLL_DELAY;
14118c2ecf20Sopenharmony_ci	} while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	/* in case we didn't close, just force the mailbox into shutdown and
14148c2ecf20Sopenharmony_ci	 * drop all left over messages in the FIFO.
14158c2ecf20Sopenharmony_ci	 */
14168c2ecf20Sopenharmony_ci	fm10k_mbx_connect_reset(mbx);
14178c2ecf20Sopenharmony_ci	fm10k_fifo_drop_all(&mbx->tx);
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, mbx->mbmem_reg, 0);
14208c2ecf20Sopenharmony_ci}
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci/**
14238c2ecf20Sopenharmony_ci *  fm10k_mbx_connect - Start mailbox connection
14248c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
14258c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
14268c2ecf20Sopenharmony_ci *
14278c2ecf20Sopenharmony_ci *  This function will initiate a mailbox connection.  It will populate the
14288c2ecf20Sopenharmony_ci *  mailbox with a broadcast connect message and then initialize the lock.
14298c2ecf20Sopenharmony_ci *  This is safe since the connect message is a single DWORD so the mailbox
14308c2ecf20Sopenharmony_ci *  transaction is guaranteed to be atomic.
14318c2ecf20Sopenharmony_ci *
14328c2ecf20Sopenharmony_ci *  This function will return an error if the mailbox has not been initiated
14338c2ecf20Sopenharmony_ci *  or is currently in use.
14348c2ecf20Sopenharmony_ci **/
14358c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	/* we cannot connect an uninitialized mailbox */
14388c2ecf20Sopenharmony_ci	if (!mbx->rx.buffer)
14398c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_NO_SPACE;
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	/* we cannot connect an already connected mailbox */
14428c2ecf20Sopenharmony_ci	if (mbx->state != FM10K_STATE_CLOSED)
14438c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_BUSY;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	/* mailbox timeout can now become active */
14468c2ecf20Sopenharmony_ci	mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	/* Place mbx in ready to connect state */
14498c2ecf20Sopenharmony_ci	mbx->state = FM10K_STATE_CONNECT;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	fm10k_mbx_reset_work(mbx);
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	/* initialize header of remote mailbox */
14548c2ecf20Sopenharmony_ci	fm10k_mbx_create_fake_disconnect_hdr(mbx);
14558c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr);
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	/* enable interrupt and notify other party of new message */
14588c2ecf20Sopenharmony_ci	mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
14598c2ecf20Sopenharmony_ci			FM10K_MBX_INTERRUPT_ENABLE;
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	/* generate and load connect header into mailbox */
14628c2ecf20Sopenharmony_ci	fm10k_mbx_create_connect_hdr(mbx);
14638c2ecf20Sopenharmony_ci	fm10k_mbx_write(hw, mbx);
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	return 0;
14668c2ecf20Sopenharmony_ci}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci/**
14698c2ecf20Sopenharmony_ci *  fm10k_mbx_validate_handlers - Validate layout of message parsing data
14708c2ecf20Sopenharmony_ci *  @msg_data: handlers for mailbox events
14718c2ecf20Sopenharmony_ci *
14728c2ecf20Sopenharmony_ci *  This function validates the layout of the message parsing data.  This
14738c2ecf20Sopenharmony_ci *  should be mostly static, but it is important to catch any errors that
14748c2ecf20Sopenharmony_ci *  are made when constructing the parsers.
14758c2ecf20Sopenharmony_ci **/
14768c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_validate_handlers(const struct fm10k_msg_data *msg_data)
14778c2ecf20Sopenharmony_ci{
14788c2ecf20Sopenharmony_ci	const struct fm10k_tlv_attr *attr;
14798c2ecf20Sopenharmony_ci	unsigned int id;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	/* Allow NULL mailboxes that transmit but don't receive */
14828c2ecf20Sopenharmony_ci	if (!msg_data)
14838c2ecf20Sopenharmony_ci		return 0;
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	while (msg_data->id != FM10K_TLV_ERROR) {
14868c2ecf20Sopenharmony_ci		/* all messages should have a function handler */
14878c2ecf20Sopenharmony_ci		if (!msg_data->func)
14888c2ecf20Sopenharmony_ci			return FM10K_ERR_PARAM;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci		/* parser is optional */
14918c2ecf20Sopenharmony_ci		attr = msg_data->attr;
14928c2ecf20Sopenharmony_ci		if (attr) {
14938c2ecf20Sopenharmony_ci			while (attr->id != FM10K_TLV_ERROR) {
14948c2ecf20Sopenharmony_ci				id = attr->id;
14958c2ecf20Sopenharmony_ci				attr++;
14968c2ecf20Sopenharmony_ci				/* ID should always be increasing */
14978c2ecf20Sopenharmony_ci				if (id >= attr->id)
14988c2ecf20Sopenharmony_ci					return FM10K_ERR_PARAM;
14998c2ecf20Sopenharmony_ci				/* ID should fit in results array */
15008c2ecf20Sopenharmony_ci				if (id >= FM10K_TLV_RESULTS_MAX)
15018c2ecf20Sopenharmony_ci					return FM10K_ERR_PARAM;
15028c2ecf20Sopenharmony_ci			}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci			/* verify terminator is in the list */
15058c2ecf20Sopenharmony_ci			if (attr->id != FM10K_TLV_ERROR)
15068c2ecf20Sopenharmony_ci				return FM10K_ERR_PARAM;
15078c2ecf20Sopenharmony_ci		}
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci		id = msg_data->id;
15108c2ecf20Sopenharmony_ci		msg_data++;
15118c2ecf20Sopenharmony_ci		/* ID should always be increasing */
15128c2ecf20Sopenharmony_ci		if (id >= msg_data->id)
15138c2ecf20Sopenharmony_ci			return FM10K_ERR_PARAM;
15148c2ecf20Sopenharmony_ci	}
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	/* verify terminator is in the list */
15178c2ecf20Sopenharmony_ci	if ((msg_data->id != FM10K_TLV_ERROR) || !msg_data->func)
15188c2ecf20Sopenharmony_ci		return FM10K_ERR_PARAM;
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	return 0;
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci/**
15248c2ecf20Sopenharmony_ci *  fm10k_mbx_register_handlers - Register a set of handler ops for mailbox
15258c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
15268c2ecf20Sopenharmony_ci *  @msg_data: handlers for mailbox events
15278c2ecf20Sopenharmony_ci *
15288c2ecf20Sopenharmony_ci *  This function associates a set of message handling ops with a mailbox.
15298c2ecf20Sopenharmony_ci **/
15308c2ecf20Sopenharmony_cistatic s32 fm10k_mbx_register_handlers(struct fm10k_mbx_info *mbx,
15318c2ecf20Sopenharmony_ci				       const struct fm10k_msg_data *msg_data)
15328c2ecf20Sopenharmony_ci{
15338c2ecf20Sopenharmony_ci	/* validate layout of handlers before assigning them */
15348c2ecf20Sopenharmony_ci	if (fm10k_mbx_validate_handlers(msg_data))
15358c2ecf20Sopenharmony_ci		return FM10K_ERR_PARAM;
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	/* initialize the message handlers */
15388c2ecf20Sopenharmony_ci	mbx->msg_data = msg_data;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	return 0;
15418c2ecf20Sopenharmony_ci}
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci/**
15448c2ecf20Sopenharmony_ci *  fm10k_pfvf_mbx_init - Initialize mailbox memory for PF/VF mailbox
15458c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
15468c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
15478c2ecf20Sopenharmony_ci *  @msg_data: handlers for mailbox events
15488c2ecf20Sopenharmony_ci *  @id: ID reference for PF as it supports up to 64 PF/VF mailboxes
15498c2ecf20Sopenharmony_ci *
15508c2ecf20Sopenharmony_ci *  This function initializes the mailbox for use.  It will split the
15518c2ecf20Sopenharmony_ci *  buffer provided and use that to populate both the Tx and Rx FIFO by
15528c2ecf20Sopenharmony_ci *  evenly splitting it.  In order to allow for easy masking of head/tail
15538c2ecf20Sopenharmony_ci *  the value reported in size must be a power of 2 and is reported in
15548c2ecf20Sopenharmony_ci *  DWORDs, not bytes.  Any invalid values will cause the mailbox to return
15558c2ecf20Sopenharmony_ci *  error.
15568c2ecf20Sopenharmony_ci **/
15578c2ecf20Sopenharmony_cis32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
15588c2ecf20Sopenharmony_ci			const struct fm10k_msg_data *msg_data, u8 id)
15598c2ecf20Sopenharmony_ci{
15608c2ecf20Sopenharmony_ci	/* initialize registers */
15618c2ecf20Sopenharmony_ci	switch (hw->mac.type) {
15628c2ecf20Sopenharmony_ci	case fm10k_mac_vf:
15638c2ecf20Sopenharmony_ci		mbx->mbx_reg = FM10K_VFMBX;
15648c2ecf20Sopenharmony_ci		mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR);
15658c2ecf20Sopenharmony_ci		break;
15668c2ecf20Sopenharmony_ci	case fm10k_mac_pf:
15678c2ecf20Sopenharmony_ci		/* there are only 64 VF <-> PF mailboxes */
15688c2ecf20Sopenharmony_ci		if (id < 64) {
15698c2ecf20Sopenharmony_ci			mbx->mbx_reg = FM10K_MBX(id);
15708c2ecf20Sopenharmony_ci			mbx->mbmem_reg = FM10K_MBMEM_VF(id, 0);
15718c2ecf20Sopenharmony_ci			break;
15728c2ecf20Sopenharmony_ci		}
15738c2ecf20Sopenharmony_ci		fallthrough;
15748c2ecf20Sopenharmony_ci	default:
15758c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_NO_MBX;
15768c2ecf20Sopenharmony_ci	}
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	/* start out in closed state */
15798c2ecf20Sopenharmony_ci	mbx->state = FM10K_STATE_CLOSED;
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	/* validate layout of handlers before assigning them */
15828c2ecf20Sopenharmony_ci	if (fm10k_mbx_validate_handlers(msg_data))
15838c2ecf20Sopenharmony_ci		return FM10K_ERR_PARAM;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	/* initialize the message handlers */
15868c2ecf20Sopenharmony_ci	mbx->msg_data = msg_data;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	/* start mailbox as timed out and let the reset_hw call
15898c2ecf20Sopenharmony_ci	 * set the timeout value to begin communications
15908c2ecf20Sopenharmony_ci	 */
15918c2ecf20Sopenharmony_ci	mbx->timeout = 0;
15928c2ecf20Sopenharmony_ci	mbx->udelay = FM10K_MBX_INIT_DELAY;
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	/* initialize tail and head */
15958c2ecf20Sopenharmony_ci	mbx->tail = 1;
15968c2ecf20Sopenharmony_ci	mbx->head = 1;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	/* initialize CRC seeds */
15998c2ecf20Sopenharmony_ci	mbx->local = FM10K_MBX_CRC_SEED;
16008c2ecf20Sopenharmony_ci	mbx->remote = FM10K_MBX_CRC_SEED;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	/* Split buffer for use by Tx/Rx FIFOs */
16038c2ecf20Sopenharmony_ci	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
16048c2ecf20Sopenharmony_ci	mbx->mbmem_len = FM10K_VFMBMEM_VF_XOR;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	/* initialize the FIFOs, sizes are in 4 byte increments */
16078c2ecf20Sopenharmony_ci	fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
16088c2ecf20Sopenharmony_ci	fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
16098c2ecf20Sopenharmony_ci			FM10K_MBX_RX_BUFFER_SIZE);
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	/* initialize function pointers */
16128c2ecf20Sopenharmony_ci	mbx->ops.connect = fm10k_mbx_connect;
16138c2ecf20Sopenharmony_ci	mbx->ops.disconnect = fm10k_mbx_disconnect;
16148c2ecf20Sopenharmony_ci	mbx->ops.rx_ready = fm10k_mbx_rx_ready;
16158c2ecf20Sopenharmony_ci	mbx->ops.tx_ready = fm10k_mbx_tx_ready;
16168c2ecf20Sopenharmony_ci	mbx->ops.tx_complete = fm10k_mbx_tx_complete;
16178c2ecf20Sopenharmony_ci	mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
16188c2ecf20Sopenharmony_ci	mbx->ops.process = fm10k_mbx_process;
16198c2ecf20Sopenharmony_ci	mbx->ops.register_handlers = fm10k_mbx_register_handlers;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	return 0;
16228c2ecf20Sopenharmony_ci}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci/**
16258c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_create_data_hdr - Generate a mailbox header for local FIFO
16268c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
16278c2ecf20Sopenharmony_ci *
16288c2ecf20Sopenharmony_ci *  This function returns a data mailbox header
16298c2ecf20Sopenharmony_ci **/
16308c2ecf20Sopenharmony_cistatic void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
16318c2ecf20Sopenharmony_ci{
16328c2ecf20Sopenharmony_ci	if (mbx->tail_len)
16338c2ecf20Sopenharmony_ci		mbx->mbx_lock |= FM10K_MBX_REQ;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
16368c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
16378c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD);
16388c2ecf20Sopenharmony_ci}
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci/**
16418c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_create_connect_hdr - Generate a mailbox header for local FIFO
16428c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
16438c2ecf20Sopenharmony_ci *  @err: error flags to report if any
16448c2ecf20Sopenharmony_ci *
16458c2ecf20Sopenharmony_ci *  This function returns a connection mailbox header
16468c2ecf20Sopenharmony_ci **/
16478c2ecf20Sopenharmony_cistatic void fm10k_sm_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx, u8 err)
16488c2ecf20Sopenharmony_ci{
16498c2ecf20Sopenharmony_ci	if (mbx->local)
16508c2ecf20Sopenharmony_ci		mbx->mbx_lock |= FM10K_MBX_REQ;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
16538c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
16548c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD) |
16558c2ecf20Sopenharmony_ci		       FM10K_MSG_HDR_FIELD_SET(err, SM_ERR);
16568c2ecf20Sopenharmony_ci}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci/**
16598c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_connect_reset - Reset following request for reset
16608c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
16618c2ecf20Sopenharmony_ci *
16628c2ecf20Sopenharmony_ci *  This function resets the mailbox to a just connected state
16638c2ecf20Sopenharmony_ci **/
16648c2ecf20Sopenharmony_cistatic void fm10k_sm_mbx_connect_reset(struct fm10k_mbx_info *mbx)
16658c2ecf20Sopenharmony_ci{
16668c2ecf20Sopenharmony_ci	/* flush any uncompleted work */
16678c2ecf20Sopenharmony_ci	fm10k_mbx_reset_work(mbx);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci	/* set local version to max and remote version to 0 */
16708c2ecf20Sopenharmony_ci	mbx->local = FM10K_SM_MBX_VERSION;
16718c2ecf20Sopenharmony_ci	mbx->remote = 0;
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	/* initialize tail and head */
16748c2ecf20Sopenharmony_ci	mbx->tail = 1;
16758c2ecf20Sopenharmony_ci	mbx->head = 1;
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	/* reset state back to connect */
16788c2ecf20Sopenharmony_ci	mbx->state = FM10K_STATE_CONNECT;
16798c2ecf20Sopenharmony_ci}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci/**
16828c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_connect - Start switch manager mailbox connection
16838c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
16848c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
16858c2ecf20Sopenharmony_ci *
16868c2ecf20Sopenharmony_ci *  This function will initiate a mailbox connection with the switch
16878c2ecf20Sopenharmony_ci *  manager.  To do this it will first disconnect the mailbox, and then
16888c2ecf20Sopenharmony_ci *  reconnect it in order to complete a reset of the mailbox.
16898c2ecf20Sopenharmony_ci *
16908c2ecf20Sopenharmony_ci *  This function will return an error if the mailbox has not been initiated
16918c2ecf20Sopenharmony_ci *  or is currently in use.
16928c2ecf20Sopenharmony_ci **/
16938c2ecf20Sopenharmony_cistatic s32 fm10k_sm_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	/* we cannot connect an uninitialized mailbox */
16968c2ecf20Sopenharmony_ci	if (!mbx->rx.buffer)
16978c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_NO_SPACE;
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	/* we cannot connect an already connected mailbox */
17008c2ecf20Sopenharmony_ci	if (mbx->state != FM10K_STATE_CLOSED)
17018c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_BUSY;
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	/* mailbox timeout can now become active */
17048c2ecf20Sopenharmony_ci	mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	/* Place mbx in ready to connect state */
17078c2ecf20Sopenharmony_ci	mbx->state = FM10K_STATE_CONNECT;
17088c2ecf20Sopenharmony_ci	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	/* reset interface back to connect */
17118c2ecf20Sopenharmony_ci	fm10k_sm_mbx_connect_reset(mbx);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	/* enable interrupt and notify other party of new message */
17148c2ecf20Sopenharmony_ci	mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
17158c2ecf20Sopenharmony_ci			FM10K_MBX_INTERRUPT_ENABLE;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	/* generate and load connect header into mailbox */
17188c2ecf20Sopenharmony_ci	fm10k_sm_mbx_create_connect_hdr(mbx, 0);
17198c2ecf20Sopenharmony_ci	fm10k_mbx_write(hw, mbx);
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	return 0;
17228c2ecf20Sopenharmony_ci}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci/**
17258c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_disconnect - Shutdown mailbox connection
17268c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
17278c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
17288c2ecf20Sopenharmony_ci *
17298c2ecf20Sopenharmony_ci *  This function will shut down the mailbox.  It places the mailbox first
17308c2ecf20Sopenharmony_ci *  in the disconnect state, it then allows up to a predefined timeout for
17318c2ecf20Sopenharmony_ci *  the mailbox to transition to close on its own.  If this does not occur
17328c2ecf20Sopenharmony_ci *  then the mailbox will be forced into the closed state.
17338c2ecf20Sopenharmony_ci *
17348c2ecf20Sopenharmony_ci *  Any mailbox transactions not completed before calling this function
17358c2ecf20Sopenharmony_ci *  are not guaranteed to complete and may be dropped.
17368c2ecf20Sopenharmony_ci **/
17378c2ecf20Sopenharmony_cistatic void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw,
17388c2ecf20Sopenharmony_ci				    struct fm10k_mbx_info *mbx)
17398c2ecf20Sopenharmony_ci{
17408c2ecf20Sopenharmony_ci	int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	/* Place mbx in ready to disconnect state */
17438c2ecf20Sopenharmony_ci	mbx->state = FM10K_STATE_DISCONNECT;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	/* trigger interrupt to start shutdown process */
17468c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, mbx->mbx_reg, FM10K_MBX_REQ |
17478c2ecf20Sopenharmony_ci					  FM10K_MBX_INTERRUPT_DISABLE);
17488c2ecf20Sopenharmony_ci	do {
17498c2ecf20Sopenharmony_ci		udelay(FM10K_MBX_POLL_DELAY);
17508c2ecf20Sopenharmony_ci		mbx->ops.process(hw, mbx);
17518c2ecf20Sopenharmony_ci		timeout -= FM10K_MBX_POLL_DELAY;
17528c2ecf20Sopenharmony_ci	} while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	/* in case we didn't close just force the mailbox into shutdown */
17558c2ecf20Sopenharmony_ci	mbx->state = FM10K_STATE_CLOSED;
17568c2ecf20Sopenharmony_ci	mbx->remote = 0;
17578c2ecf20Sopenharmony_ci	fm10k_mbx_reset_work(mbx);
17588c2ecf20Sopenharmony_ci	fm10k_fifo_drop_all(&mbx->tx);
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, mbx->mbmem_reg, 0);
17618c2ecf20Sopenharmony_ci}
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci/**
17648c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_validate_fifo_hdr - Validate fields in the remote FIFO header
17658c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
17668c2ecf20Sopenharmony_ci *
17678c2ecf20Sopenharmony_ci *  This function will parse up the fields in the mailbox header and return
17688c2ecf20Sopenharmony_ci *  an error if the header contains any of a number of invalid configurations
17698c2ecf20Sopenharmony_ci *  including unrecognized offsets or version numbers.
17708c2ecf20Sopenharmony_ci **/
17718c2ecf20Sopenharmony_cistatic s32 fm10k_sm_mbx_validate_fifo_hdr(struct fm10k_mbx_info *mbx)
17728c2ecf20Sopenharmony_ci{
17738c2ecf20Sopenharmony_ci	const u32 *hdr = &mbx->mbx_hdr;
17748c2ecf20Sopenharmony_ci	u16 tail, head, ver;
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
17778c2ecf20Sopenharmony_ci	ver = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_VER);
17788c2ecf20Sopenharmony_ci	head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	switch (ver) {
17818c2ecf20Sopenharmony_ci	case 0:
17828c2ecf20Sopenharmony_ci		break;
17838c2ecf20Sopenharmony_ci	case FM10K_SM_MBX_VERSION:
17848c2ecf20Sopenharmony_ci		if (!head || head > FM10K_SM_MBX_FIFO_LEN)
17858c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_HEAD;
17868c2ecf20Sopenharmony_ci		if (!tail || tail > FM10K_SM_MBX_FIFO_LEN)
17878c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_TAIL;
17888c2ecf20Sopenharmony_ci		if (mbx->tail < head)
17898c2ecf20Sopenharmony_ci			head += mbx->mbmem_len - 1;
17908c2ecf20Sopenharmony_ci		if (tail < mbx->head)
17918c2ecf20Sopenharmony_ci			tail += mbx->mbmem_len - 1;
17928c2ecf20Sopenharmony_ci		if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
17938c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_HEAD;
17948c2ecf20Sopenharmony_ci		if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
17958c2ecf20Sopenharmony_ci			break;
17968c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_TAIL;
17978c2ecf20Sopenharmony_ci	default:
17988c2ecf20Sopenharmony_ci		return FM10K_MBX_ERR_SRC;
17998c2ecf20Sopenharmony_ci	}
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	return 0;
18028c2ecf20Sopenharmony_ci}
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci/**
18058c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_process_error - Process header with error flag set
18068c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
18078c2ecf20Sopenharmony_ci *
18088c2ecf20Sopenharmony_ci *  This function is meant to respond to a request where the error flag
18098c2ecf20Sopenharmony_ci *  is set.  As a result we will terminate a connection if one is present
18108c2ecf20Sopenharmony_ci *  and fall back into the reset state with a connection header of version
18118c2ecf20Sopenharmony_ci *  0 (RESET).
18128c2ecf20Sopenharmony_ci **/
18138c2ecf20Sopenharmony_cistatic void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx)
18148c2ecf20Sopenharmony_ci{
18158c2ecf20Sopenharmony_ci	const enum fm10k_mbx_state state = mbx->state;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	switch (state) {
18188c2ecf20Sopenharmony_ci	case FM10K_STATE_DISCONNECT:
18198c2ecf20Sopenharmony_ci		/* if there is an error just disconnect */
18208c2ecf20Sopenharmony_ci		mbx->remote = 0;
18218c2ecf20Sopenharmony_ci		break;
18228c2ecf20Sopenharmony_ci	case FM10K_STATE_OPEN:
18238c2ecf20Sopenharmony_ci		/* flush any uncompleted work */
18248c2ecf20Sopenharmony_ci		fm10k_sm_mbx_connect_reset(mbx);
18258c2ecf20Sopenharmony_ci		break;
18268c2ecf20Sopenharmony_ci	case FM10K_STATE_CONNECT:
18278c2ecf20Sopenharmony_ci		/* try connnecting at lower version */
18288c2ecf20Sopenharmony_ci		if (mbx->remote) {
18298c2ecf20Sopenharmony_ci			while (mbx->local > 1)
18308c2ecf20Sopenharmony_ci				mbx->local--;
18318c2ecf20Sopenharmony_ci			mbx->remote = 0;
18328c2ecf20Sopenharmony_ci		}
18338c2ecf20Sopenharmony_ci		break;
18348c2ecf20Sopenharmony_ci	default:
18358c2ecf20Sopenharmony_ci		break;
18368c2ecf20Sopenharmony_ci	}
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	fm10k_sm_mbx_create_connect_hdr(mbx, 0);
18398c2ecf20Sopenharmony_ci}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci/**
18428c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_create_error_msg - Process an error in FIFO header
18438c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
18448c2ecf20Sopenharmony_ci *  @err: local error encountered
18458c2ecf20Sopenharmony_ci *
18468c2ecf20Sopenharmony_ci *  This function will interpret the error provided by err, and based on
18478c2ecf20Sopenharmony_ci *  that it may set the error bit in the local message header
18488c2ecf20Sopenharmony_ci **/
18498c2ecf20Sopenharmony_cistatic void fm10k_sm_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
18508c2ecf20Sopenharmony_ci{
18518c2ecf20Sopenharmony_ci	/* only generate an error message for these types */
18528c2ecf20Sopenharmony_ci	switch (err) {
18538c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_TAIL:
18548c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_HEAD:
18558c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_SRC:
18568c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_SIZE:
18578c2ecf20Sopenharmony_ci	case FM10K_MBX_ERR_RSVD0:
18588c2ecf20Sopenharmony_ci		break;
18598c2ecf20Sopenharmony_ci	default:
18608c2ecf20Sopenharmony_ci		return;
18618c2ecf20Sopenharmony_ci	}
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_ci	/* process it as though we received an error, and send error reply */
18648c2ecf20Sopenharmony_ci	fm10k_sm_mbx_process_error(mbx);
18658c2ecf20Sopenharmony_ci	fm10k_sm_mbx_create_connect_hdr(mbx, 1);
18668c2ecf20Sopenharmony_ci}
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci/**
18698c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_receive - Take message from Rx mailbox FIFO and put it in Rx
18708c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
18718c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
18728c2ecf20Sopenharmony_ci *  @tail: tail index of message
18738c2ecf20Sopenharmony_ci *
18748c2ecf20Sopenharmony_ci *  This function will dequeue one message from the Rx switch manager mailbox
18758c2ecf20Sopenharmony_ci *  FIFO and place it in the Rx mailbox FIFO for processing by software.
18768c2ecf20Sopenharmony_ci **/
18778c2ecf20Sopenharmony_cistatic s32 fm10k_sm_mbx_receive(struct fm10k_hw *hw,
18788c2ecf20Sopenharmony_ci				struct fm10k_mbx_info *mbx,
18798c2ecf20Sopenharmony_ci				u16 tail)
18808c2ecf20Sopenharmony_ci{
18818c2ecf20Sopenharmony_ci	/* reduce length by 1 to convert to a mask */
18828c2ecf20Sopenharmony_ci	u16 mbmem_len = mbx->mbmem_len - 1;
18838c2ecf20Sopenharmony_ci	s32 err;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	/* push tail in front of head */
18868c2ecf20Sopenharmony_ci	if (tail < mbx->head)
18878c2ecf20Sopenharmony_ci		tail += mbmem_len;
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	/* copy data to the Rx FIFO */
18908c2ecf20Sopenharmony_ci	err = fm10k_mbx_push_tail(hw, mbx, tail);
18918c2ecf20Sopenharmony_ci	if (err < 0)
18928c2ecf20Sopenharmony_ci		return err;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	/* process messages if we have received any */
18958c2ecf20Sopenharmony_ci	fm10k_mbx_dequeue_rx(hw, mbx);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	/* guarantee head aligns with the end of the last message */
18988c2ecf20Sopenharmony_ci	mbx->head = fm10k_mbx_head_sub(mbx, mbx->pushed);
18998c2ecf20Sopenharmony_ci	mbx->pushed = 0;
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_ci	/* clear any extra bits left over since index adds 1 extra bit */
19028c2ecf20Sopenharmony_ci	if (mbx->head > mbmem_len)
19038c2ecf20Sopenharmony_ci		mbx->head -= mbmem_len;
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	return err;
19068c2ecf20Sopenharmony_ci}
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci/**
19098c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_transmit - Take message from Tx and put it in Tx mailbox FIFO
19108c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
19118c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
19128c2ecf20Sopenharmony_ci *  @head: head index of message
19138c2ecf20Sopenharmony_ci *
19148c2ecf20Sopenharmony_ci *  This function will dequeue one message from the Tx mailbox FIFO and place
19158c2ecf20Sopenharmony_ci *  it in the Tx switch manager mailbox FIFO for processing by hardware.
19168c2ecf20Sopenharmony_ci **/
19178c2ecf20Sopenharmony_cistatic void fm10k_sm_mbx_transmit(struct fm10k_hw *hw,
19188c2ecf20Sopenharmony_ci				  struct fm10k_mbx_info *mbx, u16 head)
19198c2ecf20Sopenharmony_ci{
19208c2ecf20Sopenharmony_ci	struct fm10k_mbx_fifo *fifo = &mbx->tx;
19218c2ecf20Sopenharmony_ci	/* reduce length by 1 to convert to a mask */
19228c2ecf20Sopenharmony_ci	u16 mbmem_len = mbx->mbmem_len - 1;
19238c2ecf20Sopenharmony_ci	u16 tail_len, len = 0;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	/* push head behind tail */
19268c2ecf20Sopenharmony_ci	if (mbx->tail < head)
19278c2ecf20Sopenharmony_ci		head += mbmem_len;
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	fm10k_mbx_pull_head(hw, mbx, head);
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	/* determine msg aligned offset for end of buffer */
19328c2ecf20Sopenharmony_ci	do {
19338c2ecf20Sopenharmony_ci		u32 *msg;
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci		msg = fifo->buffer + fm10k_fifo_head_offset(fifo, len);
19368c2ecf20Sopenharmony_ci		tail_len = len;
19378c2ecf20Sopenharmony_ci		len += FM10K_TLV_DWORD_LEN(*msg);
19388c2ecf20Sopenharmony_ci	} while ((len <= mbx->tail_len) && (len < mbmem_len));
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	/* guarantee we stop on a message boundary */
19418c2ecf20Sopenharmony_ci	if (mbx->tail_len > tail_len) {
19428c2ecf20Sopenharmony_ci		mbx->tail = fm10k_mbx_tail_sub(mbx, mbx->tail_len - tail_len);
19438c2ecf20Sopenharmony_ci		mbx->tail_len = tail_len;
19448c2ecf20Sopenharmony_ci	}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	/* clear any extra bits left over since index adds 1 extra bit */
19478c2ecf20Sopenharmony_ci	if (mbx->tail > mbmem_len)
19488c2ecf20Sopenharmony_ci		mbx->tail -= mbmem_len;
19498c2ecf20Sopenharmony_ci}
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci/**
19528c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_create_reply - Generate reply based on state and remote head
19538c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
19548c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
19558c2ecf20Sopenharmony_ci *  @head: acknowledgement number
19568c2ecf20Sopenharmony_ci *
19578c2ecf20Sopenharmony_ci *  This function will generate an outgoing message based on the current
19588c2ecf20Sopenharmony_ci *  mailbox state and the remote FIFO head.  It will return the length
19598c2ecf20Sopenharmony_ci *  of the outgoing message excluding header on success, and a negative value
19608c2ecf20Sopenharmony_ci *  on error.
19618c2ecf20Sopenharmony_ci **/
19628c2ecf20Sopenharmony_cistatic void fm10k_sm_mbx_create_reply(struct fm10k_hw *hw,
19638c2ecf20Sopenharmony_ci				      struct fm10k_mbx_info *mbx, u16 head)
19648c2ecf20Sopenharmony_ci{
19658c2ecf20Sopenharmony_ci	switch (mbx->state) {
19668c2ecf20Sopenharmony_ci	case FM10K_STATE_OPEN:
19678c2ecf20Sopenharmony_ci	case FM10K_STATE_DISCONNECT:
19688c2ecf20Sopenharmony_ci		/* flush out Tx data */
19698c2ecf20Sopenharmony_ci		fm10k_sm_mbx_transmit(hw, mbx, head);
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci		/* generate new header based on data */
19728c2ecf20Sopenharmony_ci		if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) {
19738c2ecf20Sopenharmony_ci			fm10k_sm_mbx_create_data_hdr(mbx);
19748c2ecf20Sopenharmony_ci		} else {
19758c2ecf20Sopenharmony_ci			mbx->remote = 0;
19768c2ecf20Sopenharmony_ci			fm10k_sm_mbx_create_connect_hdr(mbx, 0);
19778c2ecf20Sopenharmony_ci		}
19788c2ecf20Sopenharmony_ci		break;
19798c2ecf20Sopenharmony_ci	case FM10K_STATE_CONNECT:
19808c2ecf20Sopenharmony_ci	case FM10K_STATE_CLOSED:
19818c2ecf20Sopenharmony_ci		fm10k_sm_mbx_create_connect_hdr(mbx, 0);
19828c2ecf20Sopenharmony_ci		break;
19838c2ecf20Sopenharmony_ci	default:
19848c2ecf20Sopenharmony_ci		break;
19858c2ecf20Sopenharmony_ci	}
19868c2ecf20Sopenharmony_ci}
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci/**
19898c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_process_reset - Process header with version == 0 (RESET)
19908c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
19918c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
19928c2ecf20Sopenharmony_ci *
19938c2ecf20Sopenharmony_ci *  This function is meant to respond to a request where the version data
19948c2ecf20Sopenharmony_ci *  is set to 0.  As such we will either terminate the connection or go
19958c2ecf20Sopenharmony_ci *  into the connect state in order to re-establish the connection.  This
19968c2ecf20Sopenharmony_ci *  function can also be used to respond to an error as the connection
19978c2ecf20Sopenharmony_ci *  resetting would also be a means of dealing with errors.
19988c2ecf20Sopenharmony_ci **/
19998c2ecf20Sopenharmony_cistatic s32 fm10k_sm_mbx_process_reset(struct fm10k_hw *hw,
20008c2ecf20Sopenharmony_ci				      struct fm10k_mbx_info *mbx)
20018c2ecf20Sopenharmony_ci{
20028c2ecf20Sopenharmony_ci	s32 err = 0;
20038c2ecf20Sopenharmony_ci	const enum fm10k_mbx_state state = mbx->state;
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci	switch (state) {
20068c2ecf20Sopenharmony_ci	case FM10K_STATE_DISCONNECT:
20078c2ecf20Sopenharmony_ci		/* drop remote connections and disconnect */
20088c2ecf20Sopenharmony_ci		mbx->state = FM10K_STATE_CLOSED;
20098c2ecf20Sopenharmony_ci		mbx->remote = 0;
20108c2ecf20Sopenharmony_ci		mbx->local = 0;
20118c2ecf20Sopenharmony_ci		break;
20128c2ecf20Sopenharmony_ci	case FM10K_STATE_OPEN:
20138c2ecf20Sopenharmony_ci		/* flush any incomplete work */
20148c2ecf20Sopenharmony_ci		fm10k_sm_mbx_connect_reset(mbx);
20158c2ecf20Sopenharmony_ci		err = FM10K_ERR_RESET_REQUESTED;
20168c2ecf20Sopenharmony_ci		break;
20178c2ecf20Sopenharmony_ci	case FM10K_STATE_CONNECT:
20188c2ecf20Sopenharmony_ci		/* Update remote value to match local value */
20198c2ecf20Sopenharmony_ci		mbx->remote = mbx->local;
20208c2ecf20Sopenharmony_ci	default:
20218c2ecf20Sopenharmony_ci		break;
20228c2ecf20Sopenharmony_ci	}
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail);
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	return err;
20278c2ecf20Sopenharmony_ci}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci/**
20308c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_process_version_1 - Process header with version == 1
20318c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
20328c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
20338c2ecf20Sopenharmony_ci *
20348c2ecf20Sopenharmony_ci *  This function is meant to process messages received when the remote
20358c2ecf20Sopenharmony_ci *  mailbox is active.
20368c2ecf20Sopenharmony_ci **/
20378c2ecf20Sopenharmony_cistatic s32 fm10k_sm_mbx_process_version_1(struct fm10k_hw *hw,
20388c2ecf20Sopenharmony_ci					  struct fm10k_mbx_info *mbx)
20398c2ecf20Sopenharmony_ci{
20408c2ecf20Sopenharmony_ci	const u32 *hdr = &mbx->mbx_hdr;
20418c2ecf20Sopenharmony_ci	u16 head, tail;
20428c2ecf20Sopenharmony_ci	s32 len;
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci	/* pull all fields needed for verification */
20458c2ecf20Sopenharmony_ci	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
20468c2ecf20Sopenharmony_ci	head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	/* if we are in connect and wanting version 1 then start up and go */
20498c2ecf20Sopenharmony_ci	if (mbx->state == FM10K_STATE_CONNECT) {
20508c2ecf20Sopenharmony_ci		if (!mbx->remote)
20518c2ecf20Sopenharmony_ci			goto send_reply;
20528c2ecf20Sopenharmony_ci		if (mbx->remote != 1)
20538c2ecf20Sopenharmony_ci			return FM10K_MBX_ERR_SRC;
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci		mbx->state = FM10K_STATE_OPEN;
20568c2ecf20Sopenharmony_ci	}
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci	do {
20598c2ecf20Sopenharmony_ci		/* abort on message size errors */
20608c2ecf20Sopenharmony_ci		len = fm10k_sm_mbx_receive(hw, mbx, tail);
20618c2ecf20Sopenharmony_ci		if (len < 0)
20628c2ecf20Sopenharmony_ci			return len;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci		/* continue until we have flushed the Rx FIFO */
20658c2ecf20Sopenharmony_ci	} while (len);
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_cisend_reply:
20688c2ecf20Sopenharmony_ci	fm10k_sm_mbx_create_reply(hw, mbx, head);
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	return 0;
20718c2ecf20Sopenharmony_ci}
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci/**
20748c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_process - Process switch manager mailbox interrupt
20758c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
20768c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
20778c2ecf20Sopenharmony_ci *
20788c2ecf20Sopenharmony_ci *  This function will process incoming mailbox events and generate mailbox
20798c2ecf20Sopenharmony_ci *  replies.  It will return a value indicating the number of DWORDs
20808c2ecf20Sopenharmony_ci *  transmitted excluding header on success or a negative value on error.
20818c2ecf20Sopenharmony_ci **/
20828c2ecf20Sopenharmony_cistatic s32 fm10k_sm_mbx_process(struct fm10k_hw *hw,
20838c2ecf20Sopenharmony_ci				struct fm10k_mbx_info *mbx)
20848c2ecf20Sopenharmony_ci{
20858c2ecf20Sopenharmony_ci	s32 err;
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	/* we do not read mailbox if closed */
20888c2ecf20Sopenharmony_ci	if (mbx->state == FM10K_STATE_CLOSED)
20898c2ecf20Sopenharmony_ci		return 0;
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci	/* retrieve data from switch manager */
20928c2ecf20Sopenharmony_ci	err = fm10k_mbx_read(hw, mbx);
20938c2ecf20Sopenharmony_ci	if (err)
20948c2ecf20Sopenharmony_ci		return err;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	err = fm10k_sm_mbx_validate_fifo_hdr(mbx);
20978c2ecf20Sopenharmony_ci	if (err < 0)
20988c2ecf20Sopenharmony_ci		goto fifo_err;
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	if (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_ERR)) {
21018c2ecf20Sopenharmony_ci		fm10k_sm_mbx_process_error(mbx);
21028c2ecf20Sopenharmony_ci		goto fifo_err;
21038c2ecf20Sopenharmony_ci	}
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) {
21068c2ecf20Sopenharmony_ci	case 0:
21078c2ecf20Sopenharmony_ci		err = fm10k_sm_mbx_process_reset(hw, mbx);
21088c2ecf20Sopenharmony_ci		break;
21098c2ecf20Sopenharmony_ci	case FM10K_SM_MBX_VERSION:
21108c2ecf20Sopenharmony_ci		err = fm10k_sm_mbx_process_version_1(hw, mbx);
21118c2ecf20Sopenharmony_ci		break;
21128c2ecf20Sopenharmony_ci	}
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_cififo_err:
21158c2ecf20Sopenharmony_ci	if (err < 0)
21168c2ecf20Sopenharmony_ci		fm10k_sm_mbx_create_error_msg(mbx, err);
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	/* report data to switch manager */
21198c2ecf20Sopenharmony_ci	fm10k_mbx_write(hw, mbx);
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	return err;
21228c2ecf20Sopenharmony_ci}
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci/**
21258c2ecf20Sopenharmony_ci *  fm10k_sm_mbx_init - Initialize mailbox memory for PF/SM mailbox
21268c2ecf20Sopenharmony_ci *  @hw: pointer to hardware structure
21278c2ecf20Sopenharmony_ci *  @mbx: pointer to mailbox
21288c2ecf20Sopenharmony_ci *  @msg_data: handlers for mailbox events
21298c2ecf20Sopenharmony_ci *
21308c2ecf20Sopenharmony_ci *  This function initializes the PF/SM mailbox for use.  It will split the
21318c2ecf20Sopenharmony_ci *  buffer provided and use that to populate both the Tx and Rx FIFO by
21328c2ecf20Sopenharmony_ci *  evenly splitting it.  In order to allow for easy masking of head/tail
21338c2ecf20Sopenharmony_ci *  the value reported in size must be a power of 2 and is reported in
21348c2ecf20Sopenharmony_ci *  DWORDs, not bytes.  Any invalid values will cause the mailbox to return
21358c2ecf20Sopenharmony_ci *  error.
21368c2ecf20Sopenharmony_ci **/
21378c2ecf20Sopenharmony_cis32 fm10k_sm_mbx_init(struct fm10k_hw __always_unused *hw,
21388c2ecf20Sopenharmony_ci		      struct fm10k_mbx_info *mbx,
21398c2ecf20Sopenharmony_ci		      const struct fm10k_msg_data *msg_data)
21408c2ecf20Sopenharmony_ci{
21418c2ecf20Sopenharmony_ci	mbx->mbx_reg = FM10K_GMBX;
21428c2ecf20Sopenharmony_ci	mbx->mbmem_reg = FM10K_MBMEM_PF(0);
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	/* start out in closed state */
21458c2ecf20Sopenharmony_ci	mbx->state = FM10K_STATE_CLOSED;
21468c2ecf20Sopenharmony_ci
21478c2ecf20Sopenharmony_ci	/* validate layout of handlers before assigning them */
21488c2ecf20Sopenharmony_ci	if (fm10k_mbx_validate_handlers(msg_data))
21498c2ecf20Sopenharmony_ci		return FM10K_ERR_PARAM;
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	/* initialize the message handlers */
21528c2ecf20Sopenharmony_ci	mbx->msg_data = msg_data;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	/* start mailbox as timed out and let the reset_hw call
21558c2ecf20Sopenharmony_ci	 * set the timeout value to begin communications
21568c2ecf20Sopenharmony_ci	 */
21578c2ecf20Sopenharmony_ci	mbx->timeout = 0;
21588c2ecf20Sopenharmony_ci	mbx->udelay = FM10K_MBX_INIT_DELAY;
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	/* Split buffer for use by Tx/Rx FIFOs */
21618c2ecf20Sopenharmony_ci	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
21628c2ecf20Sopenharmony_ci	mbx->mbmem_len = FM10K_MBMEM_PF_XOR;
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	/* initialize the FIFOs, sizes are in 4 byte increments */
21658c2ecf20Sopenharmony_ci	fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
21668c2ecf20Sopenharmony_ci	fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
21678c2ecf20Sopenharmony_ci			FM10K_MBX_RX_BUFFER_SIZE);
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	/* initialize function pointers */
21708c2ecf20Sopenharmony_ci	mbx->ops.connect = fm10k_sm_mbx_connect;
21718c2ecf20Sopenharmony_ci	mbx->ops.disconnect = fm10k_sm_mbx_disconnect;
21728c2ecf20Sopenharmony_ci	mbx->ops.rx_ready = fm10k_mbx_rx_ready;
21738c2ecf20Sopenharmony_ci	mbx->ops.tx_ready = fm10k_mbx_tx_ready;
21748c2ecf20Sopenharmony_ci	mbx->ops.tx_complete = fm10k_mbx_tx_complete;
21758c2ecf20Sopenharmony_ci	mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
21768c2ecf20Sopenharmony_ci	mbx->ops.process = fm10k_sm_mbx_process;
21778c2ecf20Sopenharmony_ci	mbx->ops.register_handlers = fm10k_mbx_register_handlers;
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci	return 0;
21808c2ecf20Sopenharmony_ci}
2181