cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fm10k_mbx.c (63465B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright(c) 2013 - 2019 Intel Corporation. */
      3
      4#include "fm10k_common.h"
      5
      6/**
      7 *  fm10k_fifo_init - Initialize a message FIFO
      8 *  @fifo: pointer to FIFO
      9 *  @buffer: pointer to memory to be used to store FIFO
     10 *  @size: maximum message size to store in FIFO, must be 2^n - 1
     11 **/
     12static void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size)
     13{
     14	fifo->buffer = buffer;
     15	fifo->size = size;
     16	fifo->head = 0;
     17	fifo->tail = 0;
     18}
     19
     20/**
     21 *  fm10k_fifo_used - Retrieve used space in FIFO
     22 *  @fifo: pointer to FIFO
     23 *
     24 *  This function returns the number of DWORDs used in the FIFO
     25 **/
     26static u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo)
     27{
     28	return fifo->tail - fifo->head;
     29}
     30
     31/**
     32 *  fm10k_fifo_unused - Retrieve unused space in FIFO
     33 *  @fifo: pointer to FIFO
     34 *
     35 *  This function returns the number of unused DWORDs in the FIFO
     36 **/
     37static u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo)
     38{
     39	return fifo->size + fifo->head - fifo->tail;
     40}
     41
     42/**
     43 *  fm10k_fifo_empty - Test to verify if FIFO is empty
     44 *  @fifo: pointer to FIFO
     45 *
     46 *  This function returns true if the FIFO is empty, else false
     47 **/
     48static bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo)
     49{
     50	return fifo->head == fifo->tail;
     51}
     52
     53/**
     54 *  fm10k_fifo_head_offset - returns indices of head with given offset
     55 *  @fifo: pointer to FIFO
     56 *  @offset: offset to add to head
     57 *
     58 *  This function returns the indices into the FIFO based on head + offset
     59 **/
     60static u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
     61{
     62	return (fifo->head + offset) & (fifo->size - 1);
     63}
     64
     65/**
     66 *  fm10k_fifo_tail_offset - returns indices of tail with given offset
     67 *  @fifo: pointer to FIFO
     68 *  @offset: offset to add to tail
     69 *
     70 *  This function returns the indices into the FIFO based on tail + offset
     71 **/
     72static u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
     73{
     74	return (fifo->tail + offset) & (fifo->size - 1);
     75}
     76
     77/**
     78 *  fm10k_fifo_head_len - Retrieve length of first message in FIFO
     79 *  @fifo: pointer to FIFO
     80 *
     81 *  This function returns the size of the first message in the FIFO
     82 **/
     83static u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo)
     84{
     85	u32 *head = fifo->buffer + fm10k_fifo_head_offset(fifo, 0);
     86
     87	/* verify there is at least 1 DWORD in the fifo so *head is valid */
     88	if (fm10k_fifo_empty(fifo))
     89		return 0;
     90
     91	/* retieve the message length */
     92	return FM10K_TLV_DWORD_LEN(*head);
     93}
     94
     95/**
     96 *  fm10k_fifo_head_drop - Drop the first message in FIFO
     97 *  @fifo: pointer to FIFO
     98 *
     99 *  This function returns the size of the message dropped from the FIFO
    100 **/
    101static u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo)
    102{
    103	u16 len = fm10k_fifo_head_len(fifo);
    104
    105	/* update head so it is at the start of next frame */
    106	fifo->head += len;
    107
    108	return len;
    109}
    110
    111/**
    112 *  fm10k_fifo_drop_all - Drop all messages in FIFO
    113 *  @fifo: pointer to FIFO
    114 *
    115 *  This function resets the head pointer to drop all messages in the FIFO and
    116 *  ensure the FIFO is empty.
    117 **/
    118static void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
    119{
    120	fifo->head = fifo->tail;
    121}
    122
    123/**
    124 *  fm10k_mbx_index_len - Convert a head/tail index into a length value
    125 *  @mbx: pointer to mailbox
    126 *  @head: head index
    127 *  @tail: head index
    128 *
    129 *  This function takes the head and tail index and determines the length
    130 *  of the data indicated by this pair.
    131 **/
    132static u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail)
    133{
    134	u16 len = tail - head;
    135
    136	/* we wrapped so subtract 2, one for index 0, one for all 1s index */
    137	if (len > tail)
    138		len -= 2;
    139
    140	return len & ((mbx->mbmem_len << 1) - 1);
    141}
    142
    143/**
    144 *  fm10k_mbx_tail_add - Determine new tail value with added offset
    145 *  @mbx: pointer to mailbox
    146 *  @offset: length to add to tail offset
    147 *
    148 *  This function takes the local tail index and recomputes it for
    149 *  a given length added as an offset.
    150 **/
    151static u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset)
    152{
    153	u16 tail = (mbx->tail + offset + 1) & ((mbx->mbmem_len << 1) - 1);
    154
    155	/* add/sub 1 because we cannot have offset 0 or all 1s */
    156	return (tail > mbx->tail) ? --tail : ++tail;
    157}
    158
    159/**
    160 *  fm10k_mbx_tail_sub - Determine new tail value with subtracted offset
    161 *  @mbx: pointer to mailbox
    162 *  @offset: length to add to tail offset
    163 *
    164 *  This function takes the local tail index and recomputes it for
    165 *  a given length added as an offset.
    166 **/
    167static u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset)
    168{
    169	u16 tail = (mbx->tail - offset - 1) & ((mbx->mbmem_len << 1) - 1);
    170
    171	/* sub/add 1 because we cannot have offset 0 or all 1s */
    172	return (tail < mbx->tail) ? ++tail : --tail;
    173}
    174
    175/**
    176 *  fm10k_mbx_head_add - Determine new head value with added offset
    177 *  @mbx: pointer to mailbox
    178 *  @offset: length to add to head offset
    179 *
    180 *  This function takes the local head index and recomputes it for
    181 *  a given length added as an offset.
    182 **/
    183static u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset)
    184{
    185	u16 head = (mbx->head + offset + 1) & ((mbx->mbmem_len << 1) - 1);
    186
    187	/* add/sub 1 because we cannot have offset 0 or all 1s */
    188	return (head > mbx->head) ? --head : ++head;
    189}
    190
    191/**
    192 *  fm10k_mbx_head_sub - Determine new head value with subtracted offset
    193 *  @mbx: pointer to mailbox
    194 *  @offset: length to add to head offset
    195 *
    196 *  This function takes the local head index and recomputes it for
    197 *  a given length added as an offset.
    198 **/
    199static u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset)
    200{
    201	u16 head = (mbx->head - offset - 1) & ((mbx->mbmem_len << 1) - 1);
    202
    203	/* sub/add 1 because we cannot have offset 0 or all 1s */
    204	return (head < mbx->head) ? ++head : --head;
    205}
    206
    207/**
    208 *  fm10k_mbx_pushed_tail_len - Retrieve the length of message being pushed
    209 *  @mbx: pointer to mailbox
    210 *
    211 *  This function will return the length of the message currently being
    212 *  pushed onto the tail of the Rx queue.
    213 **/
    214static u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx)
    215{
    216	u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0);
    217
    218	/* pushed tail is only valid if pushed is set */
    219	if (!mbx->pushed)
    220		return 0;
    221
    222	return FM10K_TLV_DWORD_LEN(*tail);
    223}
    224
    225/**
    226 *  fm10k_fifo_write_copy - pulls data off of msg and places it in FIFO
    227 *  @fifo: pointer to FIFO
    228 *  @msg: message array to populate
    229 *  @tail_offset: additional offset to add to tail pointer
    230 *  @len: length of FIFO to copy into message header
    231 *
    232 *  This function will take a message and copy it into a section of the
    233 *  FIFO.  In order to get something into a location other than just
    234 *  the tail you can use tail_offset to adjust the pointer.
    235 **/
    236static void fm10k_fifo_write_copy(struct fm10k_mbx_fifo *fifo,
    237				  const u32 *msg, u16 tail_offset, u16 len)
    238{
    239	u16 end = fm10k_fifo_tail_offset(fifo, tail_offset);
    240	u32 *tail = fifo->buffer + end;
    241
    242	/* track when we should cross the end of the FIFO */
    243	end = fifo->size - end;
    244
    245	/* copy end of message before start of message */
    246	if (end < len)
    247		memcpy(fifo->buffer, msg + end, (len - end) << 2);
    248	else
    249		end = len;
    250
    251	/* Copy remaining message into Tx FIFO */
    252	memcpy(tail, msg, end << 2);
    253}
    254
    255/**
    256 *  fm10k_fifo_enqueue - Enqueues the message to the tail of the FIFO
    257 *  @fifo: pointer to FIFO
    258 *  @msg: message array to read
    259 *
    260 *  This function enqueues a message up to the size specified by the length
    261 *  contained in the first DWORD of the message and will place at the tail
    262 *  of the FIFO.  It will return 0 on success, or a negative value on error.
    263 **/
    264static s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg)
    265{
    266	u16 len = FM10K_TLV_DWORD_LEN(*msg);
    267
    268	/* verify parameters */
    269	if (len > fifo->size)
    270		return FM10K_MBX_ERR_SIZE;
    271
    272	/* verify there is room for the message */
    273	if (len > fm10k_fifo_unused(fifo))
    274		return FM10K_MBX_ERR_NO_SPACE;
    275
    276	/* Copy message into FIFO */
    277	fm10k_fifo_write_copy(fifo, msg, 0, len);
    278
    279	/* memory barrier to guarantee FIFO is written before tail update */
    280	wmb();
    281
    282	/* Update Tx FIFO tail */
    283	fifo->tail += len;
    284
    285	return 0;
    286}
    287
    288/**
    289 *  fm10k_mbx_validate_msg_size - Validate incoming message based on size
    290 *  @mbx: pointer to mailbox
    291 *  @len: length of data pushed onto buffer
    292 *
    293 *  This function analyzes the frame and will return a non-zero value when
    294 *  the start of a message larger than the mailbox is detected.
    295 **/
    296static u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len)
    297{
    298	struct fm10k_mbx_fifo *fifo = &mbx->rx;
    299	u16 total_len = 0, msg_len;
    300
    301	/* length should include previous amounts pushed */
    302	len += mbx->pushed;
    303
    304	/* offset in message is based off of current message size */
    305	do {
    306		u32 *msg;
    307
    308		msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len);
    309		msg_len = FM10K_TLV_DWORD_LEN(*msg);
    310		total_len += msg_len;
    311	} while (total_len < len);
    312
    313	/* message extends out of pushed section, but fits in FIFO */
    314	if ((len < total_len) && (msg_len <= mbx->max_size))
    315		return 0;
    316
    317	/* return length of invalid section */
    318	return (len < total_len) ? len : (len - total_len);
    319}
    320
    321/**
    322 *  fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem
    323 *  @hw: pointer to hardware structure
    324 *  @mbx: pointer to mailbox
    325 *
    326 *  This function will take a section of the Tx FIFO and copy it into the
    327 *  mailbox memory.  The offset in mbmem is based on the lower bits of the
    328 *  tail and len determines the length to copy.
    329 **/
    330static void fm10k_mbx_write_copy(struct fm10k_hw *hw,
    331				 struct fm10k_mbx_info *mbx)
    332{
    333	struct fm10k_mbx_fifo *fifo = &mbx->tx;
    334	u32 mbmem = mbx->mbmem_reg;
    335	u32 *head = fifo->buffer;
    336	u16 end, len, tail, mask;
    337
    338	if (!mbx->tail_len)
    339		return;
    340
    341	/* determine data length and mbmem tail index */
    342	mask = mbx->mbmem_len - 1;
    343	len = mbx->tail_len;
    344	tail = fm10k_mbx_tail_sub(mbx, len);
    345	if (tail > mask)
    346		tail++;
    347
    348	/* determine offset in the ring */
    349	end = fm10k_fifo_head_offset(fifo, mbx->pulled);
    350	head += end;
    351
    352	/* memory barrier to guarantee data is ready to be read */
    353	rmb();
    354
    355	/* Copy message from Tx FIFO */
    356	for (end = fifo->size - end; len; head = fifo->buffer) {
    357		do {
    358			/* adjust tail to match offset for FIFO */
    359			tail &= mask;
    360			if (!tail)
    361				tail++;
    362
    363			mbx->tx_mbmem_pulled++;
    364
    365			/* write message to hardware FIFO */
    366			fm10k_write_reg(hw, mbmem + tail++, *(head++));
    367		} while (--len && --end);
    368	}
    369}
    370
    371/**
    372 *  fm10k_mbx_pull_head - Pulls data off of head of Tx FIFO
    373 *  @hw: pointer to hardware structure
    374 *  @mbx: pointer to mailbox
    375 *  @head: acknowledgement number last received
    376 *
    377 *  This function will push the tail index forward based on the remote
    378 *  head index.  It will then pull up to mbmem_len DWORDs off of the
    379 *  head of the FIFO and will place it in the MBMEM registers
    380 *  associated with the mailbox.
    381 **/
    382static void fm10k_mbx_pull_head(struct fm10k_hw *hw,
    383				struct fm10k_mbx_info *mbx, u16 head)
    384{
    385	u16 mbmem_len, len, ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
    386	struct fm10k_mbx_fifo *fifo = &mbx->tx;
    387
    388	/* update number of bytes pulled and update bytes in transit */
    389	mbx->pulled += mbx->tail_len - ack;
    390
    391	/* determine length of data to pull, reserve space for mbmem header */
    392	mbmem_len = mbx->mbmem_len - 1;
    393	len = fm10k_fifo_used(fifo) - mbx->pulled;
    394	if (len > mbmem_len)
    395		len = mbmem_len;
    396
    397	/* update tail and record number of bytes in transit */
    398	mbx->tail = fm10k_mbx_tail_add(mbx, len - ack);
    399	mbx->tail_len = len;
    400
    401	/* drop pulled messages from the FIFO */
    402	for (len = fm10k_fifo_head_len(fifo);
    403	     len && (mbx->pulled >= len);
    404	     len = fm10k_fifo_head_len(fifo)) {
    405		mbx->pulled -= fm10k_fifo_head_drop(fifo);
    406		mbx->tx_messages++;
    407		mbx->tx_dwords += len;
    408	}
    409
    410	/* Copy message out from the Tx FIFO */
    411	fm10k_mbx_write_copy(hw, mbx);
    412}
    413
    414/**
    415 *  fm10k_mbx_read_copy - pulls data off of mbmem and places it in Rx FIFO
    416 *  @hw: pointer to hardware structure
    417 *  @mbx: pointer to mailbox
    418 *
    419 *  This function will take a section of the mailbox memory and copy it
    420 *  into the Rx FIFO.  The offset is based on the lower bits of the
    421 *  head and len determines the length to copy.
    422 **/
    423static void fm10k_mbx_read_copy(struct fm10k_hw *hw,
    424				struct fm10k_mbx_info *mbx)
    425{
    426	struct fm10k_mbx_fifo *fifo = &mbx->rx;
    427	u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len;
    428	u32 *tail = fifo->buffer;
    429	u16 end, len, head;
    430
    431	/* determine data length and mbmem head index */
    432	len = mbx->head_len;
    433	head = fm10k_mbx_head_sub(mbx, len);
    434	if (head >= mbx->mbmem_len)
    435		head++;
    436
    437	/* determine offset in the ring */
    438	end = fm10k_fifo_tail_offset(fifo, mbx->pushed);
    439	tail += end;
    440
    441	/* Copy message into Rx FIFO */
    442	for (end = fifo->size - end; len; tail = fifo->buffer) {
    443		do {
    444			/* adjust head to match offset for FIFO */
    445			head &= mbx->mbmem_len - 1;
    446			if (!head)
    447				head++;
    448
    449			mbx->rx_mbmem_pushed++;
    450
    451			/* read message from hardware FIFO */
    452			*(tail++) = fm10k_read_reg(hw, mbmem + head++);
    453		} while (--len && --end);
    454	}
    455
    456	/* memory barrier to guarantee FIFO is written before tail update */
    457	wmb();
    458}
    459
    460/**
    461 *  fm10k_mbx_push_tail - Pushes up to 15 DWORDs on to tail of FIFO
    462 *  @hw: pointer to hardware structure
    463 *  @mbx: pointer to mailbox
    464 *  @tail: tail index of message
    465 *
    466 *  This function will first validate the tail index and size for the
    467 *  incoming message.  It then updates the acknowledgment number and
    468 *  copies the data into the FIFO.  It will return the number of messages
    469 *  dequeued on success and a negative value on error.
    470 **/
    471static s32 fm10k_mbx_push_tail(struct fm10k_hw *hw,
    472			       struct fm10k_mbx_info *mbx,
    473			       u16 tail)
    474{
    475	struct fm10k_mbx_fifo *fifo = &mbx->rx;
    476	u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail);
    477
    478	/* determine length of data to push */
    479	len = fm10k_fifo_unused(fifo) - mbx->pushed;
    480	if (len > seq)
    481		len = seq;
    482
    483	/* update head and record bytes received */
    484	mbx->head = fm10k_mbx_head_add(mbx, len);
    485	mbx->head_len = len;
    486
    487	/* nothing to do if there is no data */
    488	if (!len)
    489		return 0;
    490
    491	/* Copy msg into Rx FIFO */
    492	fm10k_mbx_read_copy(hw, mbx);
    493
    494	/* determine if there are any invalid lengths in message */
    495	if (fm10k_mbx_validate_msg_size(mbx, len))
    496		return FM10K_MBX_ERR_SIZE;
    497
    498	/* Update pushed */
    499	mbx->pushed += len;
    500
    501	/* flush any completed messages */
    502	for (len = fm10k_mbx_pushed_tail_len(mbx);
    503	     len && (mbx->pushed >= len);
    504	     len = fm10k_mbx_pushed_tail_len(mbx)) {
    505		fifo->tail += len;
    506		mbx->pushed -= len;
    507		mbx->rx_messages++;
    508		mbx->rx_dwords += len;
    509	}
    510
    511	return 0;
    512}
    513
    514/* pre-generated data for generating the CRC based on the poly 0xAC9A. */
    515static const u16 fm10k_crc_16b_table[256] = {
    516	0x0000, 0x7956, 0xF2AC, 0x8BFA, 0xBC6D, 0xC53B, 0x4EC1, 0x3797,
    517	0x21EF, 0x58B9, 0xD343, 0xAA15, 0x9D82, 0xE4D4, 0x6F2E, 0x1678,
    518	0x43DE, 0x3A88, 0xB172, 0xC824, 0xFFB3, 0x86E5, 0x0D1F, 0x7449,
    519	0x6231, 0x1B67, 0x909D, 0xE9CB, 0xDE5C, 0xA70A, 0x2CF0, 0x55A6,
    520	0x87BC, 0xFEEA, 0x7510, 0x0C46, 0x3BD1, 0x4287, 0xC97D, 0xB02B,
    521	0xA653, 0xDF05, 0x54FF, 0x2DA9, 0x1A3E, 0x6368, 0xE892, 0x91C4,
    522	0xC462, 0xBD34, 0x36CE, 0x4F98, 0x780F, 0x0159, 0x8AA3, 0xF3F5,
    523	0xE58D, 0x9CDB, 0x1721, 0x6E77, 0x59E0, 0x20B6, 0xAB4C, 0xD21A,
    524	0x564D, 0x2F1B, 0xA4E1, 0xDDB7, 0xEA20, 0x9376, 0x188C, 0x61DA,
    525	0x77A2, 0x0EF4, 0x850E, 0xFC58, 0xCBCF, 0xB299, 0x3963, 0x4035,
    526	0x1593, 0x6CC5, 0xE73F, 0x9E69, 0xA9FE, 0xD0A8, 0x5B52, 0x2204,
    527	0x347C, 0x4D2A, 0xC6D0, 0xBF86, 0x8811, 0xF147, 0x7ABD, 0x03EB,
    528	0xD1F1, 0xA8A7, 0x235D, 0x5A0B, 0x6D9C, 0x14CA, 0x9F30, 0xE666,
    529	0xF01E, 0x8948, 0x02B2, 0x7BE4, 0x4C73, 0x3525, 0xBEDF, 0xC789,
    530	0x922F, 0xEB79, 0x6083, 0x19D5, 0x2E42, 0x5714, 0xDCEE, 0xA5B8,
    531	0xB3C0, 0xCA96, 0x416C, 0x383A, 0x0FAD, 0x76FB, 0xFD01, 0x8457,
    532	0xAC9A, 0xD5CC, 0x5E36, 0x2760, 0x10F7, 0x69A1, 0xE25B, 0x9B0D,
    533	0x8D75, 0xF423, 0x7FD9, 0x068F, 0x3118, 0x484E, 0xC3B4, 0xBAE2,
    534	0xEF44, 0x9612, 0x1DE8, 0x64BE, 0x5329, 0x2A7F, 0xA185, 0xD8D3,
    535	0xCEAB, 0xB7FD, 0x3C07, 0x4551, 0x72C6, 0x0B90, 0x806A, 0xF93C,
    536	0x2B26, 0x5270, 0xD98A, 0xA0DC, 0x974B, 0xEE1D, 0x65E7, 0x1CB1,
    537	0x0AC9, 0x739F, 0xF865, 0x8133, 0xB6A4, 0xCFF2, 0x4408, 0x3D5E,
    538	0x68F8, 0x11AE, 0x9A54, 0xE302, 0xD495, 0xADC3, 0x2639, 0x5F6F,
    539	0x4917, 0x3041, 0xBBBB, 0xC2ED, 0xF57A, 0x8C2C, 0x07D6, 0x7E80,
    540	0xFAD7, 0x8381, 0x087B, 0x712D, 0x46BA, 0x3FEC, 0xB416, 0xCD40,
    541	0xDB38, 0xA26E, 0x2994, 0x50C2, 0x6755, 0x1E03, 0x95F9, 0xECAF,
    542	0xB909, 0xC05F, 0x4BA5, 0x32F3, 0x0564, 0x7C32, 0xF7C8, 0x8E9E,
    543	0x98E6, 0xE1B0, 0x6A4A, 0x131C, 0x248B, 0x5DDD, 0xD627, 0xAF71,
    544	0x7D6B, 0x043D, 0x8FC7, 0xF691, 0xC106, 0xB850, 0x33AA, 0x4AFC,
    545	0x5C84, 0x25D2, 0xAE28, 0xD77E, 0xE0E9, 0x99BF, 0x1245, 0x6B13,
    546	0x3EB5, 0x47E3, 0xCC19, 0xB54F, 0x82D8, 0xFB8E, 0x7074, 0x0922,
    547	0x1F5A, 0x660C, 0xEDF6, 0x94A0, 0xA337, 0xDA61, 0x519B, 0x28CD };
    548
    549/**
    550 *  fm10k_crc_16b - Generate a 16 bit CRC for a region of 16 bit data
    551 *  @data: pointer to data to process
    552 *  @seed: seed value for CRC
    553 *  @len: length measured in 16 bits words
    554 *
    555 *  This function will generate a CRC based on the polynomial 0xAC9A and
    556 *  whatever value is stored in the seed variable.  Note that this
    557 *  value inverts the local seed and the result in order to capture all
    558 *  leading and trailing zeros.
    559 */
    560static u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len)
    561{
    562	u32 result = seed;
    563
    564	while (len--) {
    565		result ^= *(data++);
    566		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
    567		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
    568
    569		if (!(len--))
    570			break;
    571
    572		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
    573		result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
    574	}
    575
    576	return (u16)result;
    577}
    578
    579/**
    580 *  fm10k_fifo_crc - generate a CRC based off of FIFO data
    581 *  @fifo: pointer to FIFO
    582 *  @offset: offset point for start of FIFO
    583 *  @len: number of DWORDS words to process
    584 *  @seed: seed value for CRC
    585 *
    586 *  This function generates a CRC for some region of the FIFO
    587 **/
    588static u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset,
    589			  u16 len, u16 seed)
    590{
    591	u32 *data = fifo->buffer + offset;
    592
    593	/* track when we should cross the end of the FIFO */
    594	offset = fifo->size - offset;
    595
    596	/* if we are in 2 blocks process the end of the FIFO first */
    597	if (offset < len) {
    598		seed = fm10k_crc_16b(data, seed, offset * 2);
    599		data = fifo->buffer;
    600		len -= offset;
    601	}
    602
    603	/* process any remaining bits */
    604	return fm10k_crc_16b(data, seed, len * 2);
    605}
    606
    607/**
    608 *  fm10k_mbx_update_local_crc - Update the local CRC for outgoing data
    609 *  @mbx: pointer to mailbox
    610 *  @head: head index provided by remote mailbox
    611 *
    612 *  This function will generate the CRC for all data from the end of the
    613 *  last head update to the current one.  It uses the result of the
    614 *  previous CRC as the seed for this update.  The result is stored in
    615 *  mbx->local.
    616 **/
    617static void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head)
    618{
    619	u16 len = mbx->tail_len - fm10k_mbx_index_len(mbx, head, mbx->tail);
    620
    621	/* determine the offset for the start of the region to be pulled */
    622	head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled);
    623
    624	/* update local CRC to include all of the pulled data */
    625	mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local);
    626}
    627
    628/**
    629 *  fm10k_mbx_verify_remote_crc - Verify the CRC is correct for current data
    630 *  @mbx: pointer to mailbox
    631 *
    632 *  This function will take all data that has been provided from the remote
    633 *  end and generate a CRC for it.  This is stored in mbx->remote.  The
    634 *  CRC for the header is then computed and if the result is non-zero this
    635 *  is an error and we signal an error dropping all data and resetting the
    636 *  connection.
    637 */
    638static s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx)
    639{
    640	struct fm10k_mbx_fifo *fifo = &mbx->rx;
    641	u16 len = mbx->head_len;
    642	u16 offset = fm10k_fifo_tail_offset(fifo, mbx->pushed) - len;
    643	u16 crc;
    644
    645	/* update the remote CRC if new data has been received */
    646	if (len)
    647		mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote);
    648
    649	/* process the full header as we have to validate the CRC */
    650	crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1);
    651
    652	/* notify other end if we have a problem */
    653	return crc ? FM10K_MBX_ERR_CRC : 0;
    654}
    655
    656/**
    657 *  fm10k_mbx_rx_ready - Indicates that a message is ready in the Rx FIFO
    658 *  @mbx: pointer to mailbox
    659 *
    660 *  This function returns true if there is a message in the Rx FIFO to dequeue.
    661 **/
    662static bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx)
    663{
    664	u16 msg_size = fm10k_fifo_head_len(&mbx->rx);
    665
    666	return msg_size && (fm10k_fifo_used(&mbx->rx) >= msg_size);
    667}
    668
    669/**
    670 *  fm10k_mbx_tx_ready - Indicates that the mailbox is in state ready for Tx
    671 *  @mbx: pointer to mailbox
    672 *  @len: verify free space is >= this value
    673 *
    674 *  This function returns true if the mailbox is in a state ready to transmit.
    675 **/
    676static bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len)
    677{
    678	u16 fifo_unused = fm10k_fifo_unused(&mbx->tx);
    679
    680	return (mbx->state == FM10K_STATE_OPEN) && (fifo_unused >= len);
    681}
    682
    683/**
    684 *  fm10k_mbx_tx_complete - Indicates that the Tx FIFO has been emptied
    685 *  @mbx: pointer to mailbox
    686 *
    687 *  This function returns true if the Tx FIFO is empty.
    688 **/
    689static bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx)
    690{
    691	return fm10k_fifo_empty(&mbx->tx);
    692}
    693
    694/**
    695 *  fm10k_mbx_dequeue_rx - Dequeues the message from the head in the Rx FIFO
    696 *  @hw: pointer to hardware structure
    697 *  @mbx: pointer to mailbox
    698 *
    699 *  This function dequeues messages and hands them off to the TLV parser.
    700 *  It will return the number of messages processed when called.
    701 **/
    702static u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw,
    703				struct fm10k_mbx_info *mbx)
    704{
    705	struct fm10k_mbx_fifo *fifo = &mbx->rx;
    706	s32 err;
    707	u16 cnt;
    708
    709	/* parse Rx messages out of the Rx FIFO to empty it */
    710	for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) {
    711		err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head,
    712					  mbx, mbx->msg_data);
    713		if (err < 0)
    714			mbx->rx_parse_err++;
    715
    716		fm10k_fifo_head_drop(fifo);
    717	}
    718
    719	/* shift remaining bytes back to start of FIFO */
    720	memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2);
    721
    722	/* shift head and tail based on the memory we moved */
    723	fifo->tail -= fifo->head;
    724	fifo->head = 0;
    725
    726	return cnt;
    727}
    728
    729/**
    730 *  fm10k_mbx_enqueue_tx - Enqueues the message to the tail of the Tx FIFO
    731 *  @hw: pointer to hardware structure
    732 *  @mbx: pointer to mailbox
    733 *  @msg: message array to read
    734 *
    735 *  This function enqueues a message up to the size specified by the length
    736 *  contained in the first DWORD of the message and will place at the tail
    737 *  of the FIFO.  It will return 0 on success, or a negative value on error.
    738 **/
    739static s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw,
    740				struct fm10k_mbx_info *mbx, const u32 *msg)
    741{
    742	u32 countdown = mbx->timeout;
    743	s32 err;
    744
    745	switch (mbx->state) {
    746	case FM10K_STATE_CLOSED:
    747	case FM10K_STATE_DISCONNECT:
    748		return FM10K_MBX_ERR_NO_MBX;
    749	default:
    750		break;
    751	}
    752
    753	/* enqueue the message on the Tx FIFO */
    754	err = fm10k_fifo_enqueue(&mbx->tx, msg);
    755
    756	/* if it failed give the FIFO a chance to drain */
    757	while (err && countdown) {
    758		countdown--;
    759		udelay(mbx->udelay);
    760		mbx->ops.process(hw, mbx);
    761		err = fm10k_fifo_enqueue(&mbx->tx, msg);
    762	}
    763
    764	/* if we failed treat the error */
    765	if (err) {
    766		mbx->timeout = 0;
    767		mbx->tx_busy++;
    768	}
    769
    770	/* begin processing message, ignore errors as this is just meant
    771	 * to start the mailbox flow so we are not concerned if there
    772	 * is a bad error, or the mailbox is already busy with a request
    773	 */
    774	if (!mbx->tail_len)
    775		mbx->ops.process(hw, mbx);
    776
    777	return 0;
    778}
    779
    780/**
    781 *  fm10k_mbx_read - Copies the mbmem to local message buffer
    782 *  @hw: pointer to hardware structure
    783 *  @mbx: pointer to mailbox
    784 *
    785 *  This function copies the message from the mbmem to the message array
    786 **/
    787static s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
    788{
    789	/* only allow one reader in here at a time */
    790	if (mbx->mbx_hdr)
    791		return FM10K_MBX_ERR_BUSY;
    792
    793	/* read to capture initial interrupt bits */
    794	if (fm10k_read_reg(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT)
    795		mbx->mbx_lock = FM10K_MBX_ACK;
    796
    797	/* write back interrupt bits to clear */
    798	fm10k_write_reg(hw, mbx->mbx_reg,
    799			FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT);
    800
    801	/* read remote header */
    802	mbx->mbx_hdr = fm10k_read_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len);
    803
    804	return 0;
    805}
    806
    807/**
    808 *  fm10k_mbx_write - Copies the local message buffer to mbmem
    809 *  @hw: pointer to hardware structure
    810 *  @mbx: pointer to mailbox
    811 *
    812 *  This function copies the message from the the message array to mbmem
    813 **/
    814static void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
    815{
    816	u32 mbmem = mbx->mbmem_reg;
    817
    818	/* write new msg header to notify recipient of change */
    819	fm10k_write_reg(hw, mbmem, mbx->mbx_hdr);
    820
    821	/* write mailbox to send interrupt */
    822	if (mbx->mbx_lock)
    823		fm10k_write_reg(hw, mbx->mbx_reg, mbx->mbx_lock);
    824
    825	/* we no longer are using the header so free it */
    826	mbx->mbx_hdr = 0;
    827	mbx->mbx_lock = 0;
    828}
    829
    830/**
    831 *  fm10k_mbx_create_connect_hdr - Generate a connect mailbox header
    832 *  @mbx: pointer to mailbox
    833 *
    834 *  This function returns a connection mailbox header
    835 **/
    836static void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx)
    837{
    838	mbx->mbx_lock |= FM10K_MBX_REQ;
    839
    840	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) |
    841		       FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) |
    842		       FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE);
    843}
    844
    845/**
    846 *  fm10k_mbx_create_data_hdr - Generate a data mailbox header
    847 *  @mbx: pointer to mailbox
    848 *
    849 *  This function returns a data mailbox header
    850 **/
    851static void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
    852{
    853	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) |
    854		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
    855		  FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
    856	struct fm10k_mbx_fifo *fifo = &mbx->tx;
    857	u16 crc;
    858
    859	if (mbx->tail_len)
    860		mbx->mbx_lock |= FM10K_MBX_REQ;
    861
    862	/* generate CRC for data in flight and header */
    863	crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled),
    864			     mbx->tail_len, mbx->local);
    865	crc = fm10k_crc_16b(&hdr, crc, 1);
    866
    867	/* load header to memory to be written */
    868	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
    869}
    870
    871/**
    872 *  fm10k_mbx_create_disconnect_hdr - Generate a disconnect mailbox header
    873 *  @mbx: pointer to mailbox
    874 *
    875 *  This function returns a disconnect mailbox header
    876 **/
    877static void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
    878{
    879	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
    880		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
    881		  FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
    882	u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
    883
    884	mbx->mbx_lock |= FM10K_MBX_ACK;
    885
    886	/* load header to memory to be written */
    887	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
    888}
    889
    890/**
    891 *  fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mbox hdr
    892 *  @mbx: pointer to mailbox
    893 *
    894 *  This function creates a fake disconnect header for loading into remote
    895 *  mailbox header. The primary purpose is to prevent errors on immediate
    896 *  start up after mbx->connect.
    897 **/
    898static void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
    899{
    900	u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
    901		  FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
    902		  FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
    903	u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
    904
    905	mbx->mbx_lock |= FM10K_MBX_ACK;
    906
    907	/* load header to memory to be written */
    908	mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
    909}
    910
    911/**
    912 *  fm10k_mbx_create_error_msg - Generate an error message
    913 *  @mbx: pointer to mailbox
    914 *  @err: local error encountered
    915 *
    916 *  This function will interpret the error provided by err, and based on
    917 *  that it may shift the message by 1 DWORD and then place an error header
    918 *  at the start of the message.
    919 **/
    920static void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
    921{
    922	/* only generate an error message for these types */
    923	switch (err) {
    924	case FM10K_MBX_ERR_TAIL:
    925	case FM10K_MBX_ERR_HEAD:
    926	case FM10K_MBX_ERR_TYPE:
    927	case FM10K_MBX_ERR_SIZE:
    928	case FM10K_MBX_ERR_RSVD0:
    929	case FM10K_MBX_ERR_CRC:
    930		break;
    931	default:
    932		return;
    933	}
    934
    935	mbx->mbx_lock |= FM10K_MBX_REQ;
    936
    937	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) |
    938		       FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) |
    939		       FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
    940}
    941
    942/**
    943 *  fm10k_mbx_validate_msg_hdr - Validate common fields in the message header
    944 *  @mbx: pointer to mailbox
    945 *
    946 *  This function will parse up the fields in the mailbox header and return
    947 *  an error if the header contains any of a number of invalid configurations
    948 *  including unrecognized type, invalid route, or a malformed message.
    949 **/
    950static s32 fm10k_mbx_validate_msg_hdr(struct fm10k_mbx_info *mbx)
    951{
    952	u16 type, rsvd0, head, tail, size;
    953	const u32 *hdr = &mbx->mbx_hdr;
    954
    955	type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE);
    956	rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0);
    957	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
    958	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
    959	size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
    960
    961	if (rsvd0)
    962		return FM10K_MBX_ERR_RSVD0;
    963
    964	switch (type) {
    965	case FM10K_MSG_DISCONNECT:
    966		/* validate that all data has been received */
    967		if (tail != mbx->head)
    968			return FM10K_MBX_ERR_TAIL;
    969
    970		fallthrough;
    971	case FM10K_MSG_DATA:
    972		/* validate that head is moving correctly */
    973		if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
    974			return FM10K_MBX_ERR_HEAD;
    975		if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
    976			return FM10K_MBX_ERR_HEAD;
    977
    978		/* validate that tail is moving correctly */
    979		if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL)))
    980			return FM10K_MBX_ERR_TAIL;
    981		if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
    982			break;
    983
    984		return FM10K_MBX_ERR_TAIL;
    985	case FM10K_MSG_CONNECT:
    986		/* validate size is in range and is power of 2 mask */
    987		if ((size < FM10K_VFMBX_MSG_MTU) || (size & (size + 1)))
    988			return FM10K_MBX_ERR_SIZE;
    989
    990		fallthrough;
    991	case FM10K_MSG_ERROR:
    992		if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
    993			return FM10K_MBX_ERR_HEAD;
    994		/* neither create nor error include a tail offset */
    995		if (tail)
    996			return FM10K_MBX_ERR_TAIL;
    997
    998		break;
    999	default:
   1000		return FM10K_MBX_ERR_TYPE;
   1001	}
   1002
   1003	return 0;
   1004}
   1005
   1006/**
   1007 *  fm10k_mbx_create_reply - Generate reply based on state and remote head
   1008 *  @hw: pointer to hardware structure
   1009 *  @mbx: pointer to mailbox
   1010 *  @head: acknowledgement number
   1011 *
   1012 *  This function will generate an outgoing message based on the current
   1013 *  mailbox state and the remote FIFO head.  It will return the length
   1014 *  of the outgoing message excluding header on success, and a negative value
   1015 *  on error.
   1016 **/
   1017static s32 fm10k_mbx_create_reply(struct fm10k_hw *hw,
   1018				  struct fm10k_mbx_info *mbx, u16 head)
   1019{
   1020	switch (mbx->state) {
   1021	case FM10K_STATE_OPEN:
   1022	case FM10K_STATE_DISCONNECT:
   1023		/* update our checksum for the outgoing data */
   1024		fm10k_mbx_update_local_crc(mbx, head);
   1025
   1026		/* as long as other end recognizes us keep sending data */
   1027		fm10k_mbx_pull_head(hw, mbx, head);
   1028
   1029		/* generate new header based on data */
   1030		if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN))
   1031			fm10k_mbx_create_data_hdr(mbx);
   1032		else
   1033			fm10k_mbx_create_disconnect_hdr(mbx);
   1034		break;
   1035	case FM10K_STATE_CONNECT:
   1036		/* send disconnect even if we aren't connected */
   1037		fm10k_mbx_create_connect_hdr(mbx);
   1038		break;
   1039	case FM10K_STATE_CLOSED:
   1040		/* generate new header based on data */
   1041		fm10k_mbx_create_disconnect_hdr(mbx);
   1042		break;
   1043	default:
   1044		break;
   1045	}
   1046
   1047	return 0;
   1048}
   1049
   1050/**
   1051 *  fm10k_mbx_reset_work- Reset internal pointers for any pending work
   1052 *  @mbx: pointer to mailbox
   1053 *
   1054 *  This function will reset all internal pointers so any work in progress
   1055 *  is dropped.  This call should occur every time we transition from the
   1056 *  open state to the connect state.
   1057 **/
   1058static void fm10k_mbx_reset_work(struct fm10k_mbx_info *mbx)
   1059{
   1060	u16 len, head, ack;
   1061
   1062	/* reset our outgoing max size back to Rx limits */
   1063	mbx->max_size = mbx->rx.size - 1;
   1064
   1065	/* update mbx->pulled to account for tail_len and ack */
   1066	head = FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, HEAD);
   1067	ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
   1068	mbx->pulled += mbx->tail_len - ack;
   1069
   1070	/* now drop any messages which have started or finished transmitting */
   1071	while (fm10k_fifo_head_len(&mbx->tx) && mbx->pulled) {
   1072		len = fm10k_fifo_head_drop(&mbx->tx);
   1073		mbx->tx_dropped++;
   1074		if (mbx->pulled >= len)
   1075			mbx->pulled -= len;
   1076		else
   1077			mbx->pulled = 0;
   1078	}
   1079
   1080	/* just do a quick resysnc to start of message */
   1081	mbx->pushed = 0;
   1082	mbx->pulled = 0;
   1083	mbx->tail_len = 0;
   1084	mbx->head_len = 0;
   1085	mbx->rx.tail = 0;
   1086	mbx->rx.head = 0;
   1087}
   1088
   1089/**
   1090 *  fm10k_mbx_update_max_size - Update the max_size and drop any large messages
   1091 *  @mbx: pointer to mailbox
   1092 *  @size: new value for max_size
   1093 *
   1094 *  This function updates the max_size value and drops any outgoing messages
   1095 *  at the head of the Tx FIFO if they are larger than max_size. It does not
   1096 *  drop all messages, as this is too difficult to parse and remove them from
   1097 *  the FIFO. Instead, rely on the checking to ensure that messages larger
   1098 *  than max_size aren't pushed into the memory buffer.
   1099 **/
   1100static void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size)
   1101{
   1102	u16 len;
   1103
   1104	mbx->max_size = size;
   1105
   1106	/* flush any oversized messages from the queue */
   1107	for (len = fm10k_fifo_head_len(&mbx->tx);
   1108	     len > size;
   1109	     len = fm10k_fifo_head_len(&mbx->tx)) {
   1110		fm10k_fifo_head_drop(&mbx->tx);
   1111		mbx->tx_dropped++;
   1112	}
   1113}
   1114
   1115/**
   1116 *  fm10k_mbx_connect_reset - Reset following request for reset
   1117 *  @mbx: pointer to mailbox
   1118 *
   1119 *  This function resets the mailbox to either a disconnected state
   1120 *  or a connect state depending on the current mailbox state
   1121 **/
   1122static void fm10k_mbx_connect_reset(struct fm10k_mbx_info *mbx)
   1123{
   1124	/* just do a quick resysnc to start of frame */
   1125	fm10k_mbx_reset_work(mbx);
   1126
   1127	/* reset CRC seeds */
   1128	mbx->local = FM10K_MBX_CRC_SEED;
   1129	mbx->remote = FM10K_MBX_CRC_SEED;
   1130
   1131	/* we cannot exit connect until the size is good */
   1132	if (mbx->state == FM10K_STATE_OPEN)
   1133		mbx->state = FM10K_STATE_CONNECT;
   1134	else
   1135		mbx->state = FM10K_STATE_CLOSED;
   1136}
   1137
   1138/**
   1139 *  fm10k_mbx_process_connect - Process connect header
   1140 *  @hw: pointer to hardware structure
   1141 *  @mbx: pointer to mailbox
   1142 *
   1143 *  This function will read an incoming connect header and reply with the
   1144 *  appropriate message.  It will return a value indicating the number of
   1145 *  data DWORDs on success, or will return a negative value on failure.
   1146 **/
   1147static s32 fm10k_mbx_process_connect(struct fm10k_hw *hw,
   1148				     struct fm10k_mbx_info *mbx)
   1149{
   1150	const enum fm10k_mbx_state state = mbx->state;
   1151	const u32 *hdr = &mbx->mbx_hdr;
   1152	u16 size, head;
   1153
   1154	/* we will need to pull all of the fields for verification */
   1155	size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
   1156	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
   1157
   1158	switch (state) {
   1159	case FM10K_STATE_DISCONNECT:
   1160	case FM10K_STATE_OPEN:
   1161		/* reset any in-progress work */
   1162		fm10k_mbx_connect_reset(mbx);
   1163		break;
   1164	case FM10K_STATE_CONNECT:
   1165		/* we cannot exit connect until the size is good */
   1166		if (size > mbx->rx.size) {
   1167			mbx->max_size = mbx->rx.size - 1;
   1168		} else {
   1169			/* record the remote system requesting connection */
   1170			mbx->state = FM10K_STATE_OPEN;
   1171
   1172			fm10k_mbx_update_max_size(mbx, size);
   1173		}
   1174		break;
   1175	default:
   1176		break;
   1177	}
   1178
   1179	/* align our tail index to remote head index */
   1180	mbx->tail = head;
   1181
   1182	return fm10k_mbx_create_reply(hw, mbx, head);
   1183}
   1184
   1185/**
   1186 *  fm10k_mbx_process_data - Process data header
   1187 *  @hw: pointer to hardware structure
   1188 *  @mbx: pointer to mailbox
   1189 *
   1190 *  This function will read an incoming data header and reply with the
   1191 *  appropriate message.  It will return a value indicating the number of
   1192 *  data DWORDs on success, or will return a negative value on failure.
   1193 **/
   1194static s32 fm10k_mbx_process_data(struct fm10k_hw *hw,
   1195				  struct fm10k_mbx_info *mbx)
   1196{
   1197	const u32 *hdr = &mbx->mbx_hdr;
   1198	u16 head, tail;
   1199	s32 err;
   1200
   1201	/* we will need to pull all of the fields for verification */
   1202	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
   1203	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
   1204
   1205	/* if we are in connect just update our data and go */
   1206	if (mbx->state == FM10K_STATE_CONNECT) {
   1207		mbx->tail = head;
   1208		mbx->state = FM10K_STATE_OPEN;
   1209	}
   1210
   1211	/* abort on message size errors */
   1212	err = fm10k_mbx_push_tail(hw, mbx, tail);
   1213	if (err < 0)
   1214		return err;
   1215
   1216	/* verify the checksum on the incoming data */
   1217	err = fm10k_mbx_verify_remote_crc(mbx);
   1218	if (err)
   1219		return err;
   1220
   1221	/* process messages if we have received any */
   1222	fm10k_mbx_dequeue_rx(hw, mbx);
   1223
   1224	return fm10k_mbx_create_reply(hw, mbx, head);
   1225}
   1226
   1227/**
   1228 *  fm10k_mbx_process_disconnect - Process disconnect header
   1229 *  @hw: pointer to hardware structure
   1230 *  @mbx: pointer to mailbox
   1231 *
   1232 *  This function will read an incoming disconnect header and reply with the
   1233 *  appropriate message.  It will return a value indicating the number of
   1234 *  data DWORDs on success, or will return a negative value on failure.
   1235 **/
   1236static s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw,
   1237					struct fm10k_mbx_info *mbx)
   1238{
   1239	const enum fm10k_mbx_state state = mbx->state;
   1240	const u32 *hdr = &mbx->mbx_hdr;
   1241	u16 head;
   1242	s32 err;
   1243
   1244	/* we will need to pull the header field for verification */
   1245	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
   1246
   1247	/* We should not be receiving disconnect if Rx is incomplete */
   1248	if (mbx->pushed)
   1249		return FM10K_MBX_ERR_TAIL;
   1250
   1251	/* we have already verified mbx->head == tail so we know this is 0 */
   1252	mbx->head_len = 0;
   1253
   1254	/* verify the checksum on the incoming header is correct */
   1255	err = fm10k_mbx_verify_remote_crc(mbx);
   1256	if (err)
   1257		return err;
   1258
   1259	switch (state) {
   1260	case FM10K_STATE_DISCONNECT:
   1261	case FM10K_STATE_OPEN:
   1262		/* state doesn't change if we still have work to do */
   1263		if (!fm10k_mbx_tx_complete(mbx))
   1264			break;
   1265
   1266		/* verify the head indicates we completed all transmits */
   1267		if (head != mbx->tail)
   1268			return FM10K_MBX_ERR_HEAD;
   1269
   1270		/* reset any in-progress work */
   1271		fm10k_mbx_connect_reset(mbx);
   1272		break;
   1273	default:
   1274		break;
   1275	}
   1276
   1277	return fm10k_mbx_create_reply(hw, mbx, head);
   1278}
   1279
   1280/**
   1281 *  fm10k_mbx_process_error - Process error header
   1282 *  @hw: pointer to hardware structure
   1283 *  @mbx: pointer to mailbox
   1284 *
   1285 *  This function will read an incoming error header and reply with the
   1286 *  appropriate message.  It will return a value indicating the number of
   1287 *  data DWORDs on success, or will return a negative value on failure.
   1288 **/
   1289static s32 fm10k_mbx_process_error(struct fm10k_hw *hw,
   1290				   struct fm10k_mbx_info *mbx)
   1291{
   1292	const u32 *hdr = &mbx->mbx_hdr;
   1293	u16 head;
   1294
   1295	/* we will need to pull all of the fields for verification */
   1296	head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
   1297
   1298	switch (mbx->state) {
   1299	case FM10K_STATE_OPEN:
   1300	case FM10K_STATE_DISCONNECT:
   1301		/* flush any uncompleted work */
   1302		fm10k_mbx_reset_work(mbx);
   1303
   1304		/* reset CRC seeds */
   1305		mbx->local = FM10K_MBX_CRC_SEED;
   1306		mbx->remote = FM10K_MBX_CRC_SEED;
   1307
   1308		/* reset tail index and size to prepare for reconnect */
   1309		mbx->tail = head;
   1310
   1311		/* if open then reset max_size and go back to connect */
   1312		if (mbx->state == FM10K_STATE_OPEN) {
   1313			mbx->state = FM10K_STATE_CONNECT;
   1314			break;
   1315		}
   1316
   1317		/* send a connect message to get data flowing again */
   1318		fm10k_mbx_create_connect_hdr(mbx);
   1319		return 0;
   1320	default:
   1321		break;
   1322	}
   1323
   1324	return fm10k_mbx_create_reply(hw, mbx, mbx->tail);
   1325}
   1326
   1327/**
   1328 *  fm10k_mbx_process - Process mailbox interrupt
   1329 *  @hw: pointer to hardware structure
   1330 *  @mbx: pointer to mailbox
   1331 *
   1332 *  This function will process incoming mailbox events and generate mailbox
   1333 *  replies.  It will return a value indicating the number of DWORDs
   1334 *  transmitted excluding header on success or a negative value on error.
   1335 **/
   1336static s32 fm10k_mbx_process(struct fm10k_hw *hw,
   1337			     struct fm10k_mbx_info *mbx)
   1338{
   1339	s32 err;
   1340
   1341	/* we do not read mailbox if closed */
   1342	if (mbx->state == FM10K_STATE_CLOSED)
   1343		return 0;
   1344
   1345	/* copy data from mailbox */
   1346	err = fm10k_mbx_read(hw, mbx);
   1347	if (err)
   1348		return err;
   1349
   1350	/* validate type, source, and destination */
   1351	err = fm10k_mbx_validate_msg_hdr(mbx);
   1352	if (err < 0)
   1353		goto msg_err;
   1354
   1355	switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, TYPE)) {
   1356	case FM10K_MSG_CONNECT:
   1357		err = fm10k_mbx_process_connect(hw, mbx);
   1358		break;
   1359	case FM10K_MSG_DATA:
   1360		err = fm10k_mbx_process_data(hw, mbx);
   1361		break;
   1362	case FM10K_MSG_DISCONNECT:
   1363		err = fm10k_mbx_process_disconnect(hw, mbx);
   1364		break;
   1365	case FM10K_MSG_ERROR:
   1366		err = fm10k_mbx_process_error(hw, mbx);
   1367		break;
   1368	default:
   1369		err = FM10K_MBX_ERR_TYPE;
   1370		break;
   1371	}
   1372
   1373msg_err:
   1374	/* notify partner of errors on our end */
   1375	if (err < 0)
   1376		fm10k_mbx_create_error_msg(mbx, err);
   1377
   1378	/* copy data from mailbox */
   1379	fm10k_mbx_write(hw, mbx);
   1380
   1381	return err;
   1382}
   1383
   1384/**
   1385 *  fm10k_mbx_disconnect - Shutdown mailbox connection
   1386 *  @hw: pointer to hardware structure
   1387 *  @mbx: pointer to mailbox
   1388 *
   1389 *  This function will shut down the mailbox.  It places the mailbox first
   1390 *  in the disconnect state, it then allows up to a predefined timeout for
   1391 *  the mailbox to transition to close on its own.  If this does not occur
   1392 *  then the mailbox will be forced into the closed state.
   1393 *
   1394 *  Any mailbox transactions not completed before calling this function
   1395 *  are not guaranteed to complete and may be dropped.
   1396 **/
   1397static void fm10k_mbx_disconnect(struct fm10k_hw *hw,
   1398				 struct fm10k_mbx_info *mbx)
   1399{
   1400	int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
   1401
   1402	/* Place mbx in ready to disconnect state */
   1403	mbx->state = FM10K_STATE_DISCONNECT;
   1404
   1405	/* trigger interrupt to start shutdown process */
   1406	fm10k_write_reg(hw, mbx->mbx_reg, FM10K_MBX_REQ |
   1407					  FM10K_MBX_INTERRUPT_DISABLE);
   1408	do {
   1409		udelay(FM10K_MBX_POLL_DELAY);
   1410		mbx->ops.process(hw, mbx);
   1411		timeout -= FM10K_MBX_POLL_DELAY;
   1412	} while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
   1413
   1414	/* in case we didn't close, just force the mailbox into shutdown and
   1415	 * drop all left over messages in the FIFO.
   1416	 */
   1417	fm10k_mbx_connect_reset(mbx);
   1418	fm10k_fifo_drop_all(&mbx->tx);
   1419
   1420	fm10k_write_reg(hw, mbx->mbmem_reg, 0);
   1421}
   1422
   1423/**
   1424 *  fm10k_mbx_connect - Start mailbox connection
   1425 *  @hw: pointer to hardware structure
   1426 *  @mbx: pointer to mailbox
   1427 *
   1428 *  This function will initiate a mailbox connection.  It will populate the
   1429 *  mailbox with a broadcast connect message and then initialize the lock.
   1430 *  This is safe since the connect message is a single DWORD so the mailbox
   1431 *  transaction is guaranteed to be atomic.
   1432 *
   1433 *  This function will return an error if the mailbox has not been initiated
   1434 *  or is currently in use.
   1435 **/
   1436static s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
   1437{
   1438	/* we cannot connect an uninitialized mailbox */
   1439	if (!mbx->rx.buffer)
   1440		return FM10K_MBX_ERR_NO_SPACE;
   1441
   1442	/* we cannot connect an already connected mailbox */
   1443	if (mbx->state != FM10K_STATE_CLOSED)
   1444		return FM10K_MBX_ERR_BUSY;
   1445
   1446	/* mailbox timeout can now become active */
   1447	mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
   1448
   1449	/* Place mbx in ready to connect state */
   1450	mbx->state = FM10K_STATE_CONNECT;
   1451
   1452	fm10k_mbx_reset_work(mbx);
   1453
   1454	/* initialize header of remote mailbox */
   1455	fm10k_mbx_create_fake_disconnect_hdr(mbx);
   1456	fm10k_write_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len, mbx->mbx_hdr);
   1457
   1458	/* enable interrupt and notify other party of new message */
   1459	mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
   1460			FM10K_MBX_INTERRUPT_ENABLE;
   1461
   1462	/* generate and load connect header into mailbox */
   1463	fm10k_mbx_create_connect_hdr(mbx);
   1464	fm10k_mbx_write(hw, mbx);
   1465
   1466	return 0;
   1467}
   1468
   1469/**
   1470 *  fm10k_mbx_validate_handlers - Validate layout of message parsing data
   1471 *  @msg_data: handlers for mailbox events
   1472 *
   1473 *  This function validates the layout of the message parsing data.  This
   1474 *  should be mostly static, but it is important to catch any errors that
   1475 *  are made when constructing the parsers.
   1476 **/
   1477static s32 fm10k_mbx_validate_handlers(const struct fm10k_msg_data *msg_data)
   1478{
   1479	const struct fm10k_tlv_attr *attr;
   1480	unsigned int id;
   1481
   1482	/* Allow NULL mailboxes that transmit but don't receive */
   1483	if (!msg_data)
   1484		return 0;
   1485
   1486	while (msg_data->id != FM10K_TLV_ERROR) {
   1487		/* all messages should have a function handler */
   1488		if (!msg_data->func)
   1489			return FM10K_ERR_PARAM;
   1490
   1491		/* parser is optional */
   1492		attr = msg_data->attr;
   1493		if (attr) {
   1494			while (attr->id != FM10K_TLV_ERROR) {
   1495				id = attr->id;
   1496				attr++;
   1497				/* ID should always be increasing */
   1498				if (id >= attr->id)
   1499					return FM10K_ERR_PARAM;
   1500				/* ID should fit in results array */
   1501				if (id >= FM10K_TLV_RESULTS_MAX)
   1502					return FM10K_ERR_PARAM;
   1503			}
   1504
   1505			/* verify terminator is in the list */
   1506			if (attr->id != FM10K_TLV_ERROR)
   1507				return FM10K_ERR_PARAM;
   1508		}
   1509
   1510		id = msg_data->id;
   1511		msg_data++;
   1512		/* ID should always be increasing */
   1513		if (id >= msg_data->id)
   1514			return FM10K_ERR_PARAM;
   1515	}
   1516
   1517	/* verify terminator is in the list */
   1518	if ((msg_data->id != FM10K_TLV_ERROR) || !msg_data->func)
   1519		return FM10K_ERR_PARAM;
   1520
   1521	return 0;
   1522}
   1523
   1524/**
   1525 *  fm10k_mbx_register_handlers - Register a set of handler ops for mailbox
   1526 *  @mbx: pointer to mailbox
   1527 *  @msg_data: handlers for mailbox events
   1528 *
   1529 *  This function associates a set of message handling ops with a mailbox.
   1530 **/
   1531static s32 fm10k_mbx_register_handlers(struct fm10k_mbx_info *mbx,
   1532				       const struct fm10k_msg_data *msg_data)
   1533{
   1534	/* validate layout of handlers before assigning them */
   1535	if (fm10k_mbx_validate_handlers(msg_data))
   1536		return FM10K_ERR_PARAM;
   1537
   1538	/* initialize the message handlers */
   1539	mbx->msg_data = msg_data;
   1540
   1541	return 0;
   1542}
   1543
   1544/**
   1545 *  fm10k_pfvf_mbx_init - Initialize mailbox memory for PF/VF mailbox
   1546 *  @hw: pointer to hardware structure
   1547 *  @mbx: pointer to mailbox
   1548 *  @msg_data: handlers for mailbox events
   1549 *  @id: ID reference for PF as it supports up to 64 PF/VF mailboxes
   1550 *
   1551 *  This function initializes the mailbox for use.  It will split the
   1552 *  buffer provided and use that to populate both the Tx and Rx FIFO by
   1553 *  evenly splitting it.  In order to allow for easy masking of head/tail
   1554 *  the value reported in size must be a power of 2 and is reported in
   1555 *  DWORDs, not bytes.  Any invalid values will cause the mailbox to return
   1556 *  error.
   1557 **/
   1558s32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
   1559			const struct fm10k_msg_data *msg_data, u8 id)
   1560{
   1561	/* initialize registers */
   1562	switch (hw->mac.type) {
   1563	case fm10k_mac_vf:
   1564		mbx->mbx_reg = FM10K_VFMBX;
   1565		mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR);
   1566		break;
   1567	case fm10k_mac_pf:
   1568		/* there are only 64 VF <-> PF mailboxes */
   1569		if (id < 64) {
   1570			mbx->mbx_reg = FM10K_MBX(id);
   1571			mbx->mbmem_reg = FM10K_MBMEM_VF(id, 0);
   1572			break;
   1573		}
   1574		fallthrough;
   1575	default:
   1576		return FM10K_MBX_ERR_NO_MBX;
   1577	}
   1578
   1579	/* start out in closed state */
   1580	mbx->state = FM10K_STATE_CLOSED;
   1581
   1582	/* validate layout of handlers before assigning them */
   1583	if (fm10k_mbx_validate_handlers(msg_data))
   1584		return FM10K_ERR_PARAM;
   1585
   1586	/* initialize the message handlers */
   1587	mbx->msg_data = msg_data;
   1588
   1589	/* start mailbox as timed out and let the reset_hw call
   1590	 * set the timeout value to begin communications
   1591	 */
   1592	mbx->timeout = 0;
   1593	mbx->udelay = FM10K_MBX_INIT_DELAY;
   1594
   1595	/* initialize tail and head */
   1596	mbx->tail = 1;
   1597	mbx->head = 1;
   1598
   1599	/* initialize CRC seeds */
   1600	mbx->local = FM10K_MBX_CRC_SEED;
   1601	mbx->remote = FM10K_MBX_CRC_SEED;
   1602
   1603	/* Split buffer for use by Tx/Rx FIFOs */
   1604	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
   1605	mbx->mbmem_len = FM10K_VFMBMEM_VF_XOR;
   1606
   1607	/* initialize the FIFOs, sizes are in 4 byte increments */
   1608	fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
   1609	fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
   1610			FM10K_MBX_RX_BUFFER_SIZE);
   1611
   1612	/* initialize function pointers */
   1613	mbx->ops.connect = fm10k_mbx_connect;
   1614	mbx->ops.disconnect = fm10k_mbx_disconnect;
   1615	mbx->ops.rx_ready = fm10k_mbx_rx_ready;
   1616	mbx->ops.tx_ready = fm10k_mbx_tx_ready;
   1617	mbx->ops.tx_complete = fm10k_mbx_tx_complete;
   1618	mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
   1619	mbx->ops.process = fm10k_mbx_process;
   1620	mbx->ops.register_handlers = fm10k_mbx_register_handlers;
   1621
   1622	return 0;
   1623}
   1624
   1625/**
   1626 *  fm10k_sm_mbx_create_data_hdr - Generate a mailbox header for local FIFO
   1627 *  @mbx: pointer to mailbox
   1628 *
   1629 *  This function returns a data mailbox header
   1630 **/
   1631static void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
   1632{
   1633	if (mbx->tail_len)
   1634		mbx->mbx_lock |= FM10K_MBX_REQ;
   1635
   1636	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
   1637		       FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
   1638		       FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD);
   1639}
   1640
   1641/**
   1642 *  fm10k_sm_mbx_create_connect_hdr - Generate a mailbox header for local FIFO
   1643 *  @mbx: pointer to mailbox
   1644 *  @err: error flags to report if any
   1645 *
   1646 *  This function returns a connection mailbox header
   1647 **/
   1648static void fm10k_sm_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx, u8 err)
   1649{
   1650	if (mbx->local)
   1651		mbx->mbx_lock |= FM10K_MBX_REQ;
   1652
   1653	mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
   1654		       FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
   1655		       FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD) |
   1656		       FM10K_MSG_HDR_FIELD_SET(err, SM_ERR);
   1657}
   1658
   1659/**
   1660 *  fm10k_sm_mbx_connect_reset - Reset following request for reset
   1661 *  @mbx: pointer to mailbox
   1662 *
   1663 *  This function resets the mailbox to a just connected state
   1664 **/
   1665static void fm10k_sm_mbx_connect_reset(struct fm10k_mbx_info *mbx)
   1666{
   1667	/* flush any uncompleted work */
   1668	fm10k_mbx_reset_work(mbx);
   1669
   1670	/* set local version to max and remote version to 0 */
   1671	mbx->local = FM10K_SM_MBX_VERSION;
   1672	mbx->remote = 0;
   1673
   1674	/* initialize tail and head */
   1675	mbx->tail = 1;
   1676	mbx->head = 1;
   1677
   1678	/* reset state back to connect */
   1679	mbx->state = FM10K_STATE_CONNECT;
   1680}
   1681
   1682/**
   1683 *  fm10k_sm_mbx_connect - Start switch manager mailbox connection
   1684 *  @hw: pointer to hardware structure
   1685 *  @mbx: pointer to mailbox
   1686 *
   1687 *  This function will initiate a mailbox connection with the switch
   1688 *  manager.  To do this it will first disconnect the mailbox, and then
   1689 *  reconnect it in order to complete a reset of the mailbox.
   1690 *
   1691 *  This function will return an error if the mailbox has not been initiated
   1692 *  or is currently in use.
   1693 **/
   1694static s32 fm10k_sm_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
   1695{
   1696	/* we cannot connect an uninitialized mailbox */
   1697	if (!mbx->rx.buffer)
   1698		return FM10K_MBX_ERR_NO_SPACE;
   1699
   1700	/* we cannot connect an already connected mailbox */
   1701	if (mbx->state != FM10K_STATE_CLOSED)
   1702		return FM10K_MBX_ERR_BUSY;
   1703
   1704	/* mailbox timeout can now become active */
   1705	mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
   1706
   1707	/* Place mbx in ready to connect state */
   1708	mbx->state = FM10K_STATE_CONNECT;
   1709	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
   1710
   1711	/* reset interface back to connect */
   1712	fm10k_sm_mbx_connect_reset(mbx);
   1713
   1714	/* enable interrupt and notify other party of new message */
   1715	mbx->mbx_lock = FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT |
   1716			FM10K_MBX_INTERRUPT_ENABLE;
   1717
   1718	/* generate and load connect header into mailbox */
   1719	fm10k_sm_mbx_create_connect_hdr(mbx, 0);
   1720	fm10k_mbx_write(hw, mbx);
   1721
   1722	return 0;
   1723}
   1724
   1725/**
   1726 *  fm10k_sm_mbx_disconnect - Shutdown mailbox connection
   1727 *  @hw: pointer to hardware structure
   1728 *  @mbx: pointer to mailbox
   1729 *
   1730 *  This function will shut down the mailbox.  It places the mailbox first
   1731 *  in the disconnect state, it then allows up to a predefined timeout for
   1732 *  the mailbox to transition to close on its own.  If this does not occur
   1733 *  then the mailbox will be forced into the closed state.
   1734 *
   1735 *  Any mailbox transactions not completed before calling this function
   1736 *  are not guaranteed to complete and may be dropped.
   1737 **/
   1738static void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw,
   1739				    struct fm10k_mbx_info *mbx)
   1740{
   1741	int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
   1742
   1743	/* Place mbx in ready to disconnect state */
   1744	mbx->state = FM10K_STATE_DISCONNECT;
   1745
   1746	/* trigger interrupt to start shutdown process */
   1747	fm10k_write_reg(hw, mbx->mbx_reg, FM10K_MBX_REQ |
   1748					  FM10K_MBX_INTERRUPT_DISABLE);
   1749	do {
   1750		udelay(FM10K_MBX_POLL_DELAY);
   1751		mbx->ops.process(hw, mbx);
   1752		timeout -= FM10K_MBX_POLL_DELAY;
   1753	} while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
   1754
   1755	/* in case we didn't close just force the mailbox into shutdown */
   1756	mbx->state = FM10K_STATE_CLOSED;
   1757	mbx->remote = 0;
   1758	fm10k_mbx_reset_work(mbx);
   1759	fm10k_fifo_drop_all(&mbx->tx);
   1760
   1761	fm10k_write_reg(hw, mbx->mbmem_reg, 0);
   1762}
   1763
   1764/**
   1765 *  fm10k_sm_mbx_validate_fifo_hdr - Validate fields in the remote FIFO header
   1766 *  @mbx: pointer to mailbox
   1767 *
   1768 *  This function will parse up the fields in the mailbox header and return
   1769 *  an error if the header contains any of a number of invalid configurations
   1770 *  including unrecognized offsets or version numbers.
   1771 **/
   1772static s32 fm10k_sm_mbx_validate_fifo_hdr(struct fm10k_mbx_info *mbx)
   1773{
   1774	const u32 *hdr = &mbx->mbx_hdr;
   1775	u16 tail, head, ver;
   1776
   1777	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
   1778	ver = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_VER);
   1779	head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
   1780
   1781	switch (ver) {
   1782	case 0:
   1783		break;
   1784	case FM10K_SM_MBX_VERSION:
   1785		if (!head || head > FM10K_SM_MBX_FIFO_LEN)
   1786			return FM10K_MBX_ERR_HEAD;
   1787		if (!tail || tail > FM10K_SM_MBX_FIFO_LEN)
   1788			return FM10K_MBX_ERR_TAIL;
   1789		if (mbx->tail < head)
   1790			head += mbx->mbmem_len - 1;
   1791		if (tail < mbx->head)
   1792			tail += mbx->mbmem_len - 1;
   1793		if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
   1794			return FM10K_MBX_ERR_HEAD;
   1795		if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
   1796			break;
   1797		return FM10K_MBX_ERR_TAIL;
   1798	default:
   1799		return FM10K_MBX_ERR_SRC;
   1800	}
   1801
   1802	return 0;
   1803}
   1804
   1805/**
   1806 *  fm10k_sm_mbx_process_error - Process header with error flag set
   1807 *  @mbx: pointer to mailbox
   1808 *
   1809 *  This function is meant to respond to a request where the error flag
   1810 *  is set.  As a result we will terminate a connection if one is present
   1811 *  and fall back into the reset state with a connection header of version
   1812 *  0 (RESET).
   1813 **/
   1814static void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx)
   1815{
   1816	const enum fm10k_mbx_state state = mbx->state;
   1817
   1818	switch (state) {
   1819	case FM10K_STATE_DISCONNECT:
   1820		/* if there is an error just disconnect */
   1821		mbx->remote = 0;
   1822		break;
   1823	case FM10K_STATE_OPEN:
   1824		/* flush any uncompleted work */
   1825		fm10k_sm_mbx_connect_reset(mbx);
   1826		break;
   1827	case FM10K_STATE_CONNECT:
   1828		/* try connnecting at lower version */
   1829		if (mbx->remote) {
   1830			while (mbx->local > 1)
   1831				mbx->local--;
   1832			mbx->remote = 0;
   1833		}
   1834		break;
   1835	default:
   1836		break;
   1837	}
   1838
   1839	fm10k_sm_mbx_create_connect_hdr(mbx, 0);
   1840}
   1841
   1842/**
   1843 *  fm10k_sm_mbx_create_error_msg - Process an error in FIFO header
   1844 *  @mbx: pointer to mailbox
   1845 *  @err: local error encountered
   1846 *
   1847 *  This function will interpret the error provided by err, and based on
   1848 *  that it may set the error bit in the local message header
   1849 **/
   1850static void fm10k_sm_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
   1851{
   1852	/* only generate an error message for these types */
   1853	switch (err) {
   1854	case FM10K_MBX_ERR_TAIL:
   1855	case FM10K_MBX_ERR_HEAD:
   1856	case FM10K_MBX_ERR_SRC:
   1857	case FM10K_MBX_ERR_SIZE:
   1858	case FM10K_MBX_ERR_RSVD0:
   1859		break;
   1860	default:
   1861		return;
   1862	}
   1863
   1864	/* process it as though we received an error, and send error reply */
   1865	fm10k_sm_mbx_process_error(mbx);
   1866	fm10k_sm_mbx_create_connect_hdr(mbx, 1);
   1867}
   1868
   1869/**
   1870 *  fm10k_sm_mbx_receive - Take message from Rx mailbox FIFO and put it in Rx
   1871 *  @hw: pointer to hardware structure
   1872 *  @mbx: pointer to mailbox
   1873 *  @tail: tail index of message
   1874 *
   1875 *  This function will dequeue one message from the Rx switch manager mailbox
   1876 *  FIFO and place it in the Rx mailbox FIFO for processing by software.
   1877 **/
   1878static s32 fm10k_sm_mbx_receive(struct fm10k_hw *hw,
   1879				struct fm10k_mbx_info *mbx,
   1880				u16 tail)
   1881{
   1882	/* reduce length by 1 to convert to a mask */
   1883	u16 mbmem_len = mbx->mbmem_len - 1;
   1884	s32 err;
   1885
   1886	/* push tail in front of head */
   1887	if (tail < mbx->head)
   1888		tail += mbmem_len;
   1889
   1890	/* copy data to the Rx FIFO */
   1891	err = fm10k_mbx_push_tail(hw, mbx, tail);
   1892	if (err < 0)
   1893		return err;
   1894
   1895	/* process messages if we have received any */
   1896	fm10k_mbx_dequeue_rx(hw, mbx);
   1897
   1898	/* guarantee head aligns with the end of the last message */
   1899	mbx->head = fm10k_mbx_head_sub(mbx, mbx->pushed);
   1900	mbx->pushed = 0;
   1901
   1902	/* clear any extra bits left over since index adds 1 extra bit */
   1903	if (mbx->head > mbmem_len)
   1904		mbx->head -= mbmem_len;
   1905
   1906	return err;
   1907}
   1908
   1909/**
   1910 *  fm10k_sm_mbx_transmit - Take message from Tx and put it in Tx mailbox FIFO
   1911 *  @hw: pointer to hardware structure
   1912 *  @mbx: pointer to mailbox
   1913 *  @head: head index of message
   1914 *
   1915 *  This function will dequeue one message from the Tx mailbox FIFO and place
   1916 *  it in the Tx switch manager mailbox FIFO for processing by hardware.
   1917 **/
   1918static void fm10k_sm_mbx_transmit(struct fm10k_hw *hw,
   1919				  struct fm10k_mbx_info *mbx, u16 head)
   1920{
   1921	struct fm10k_mbx_fifo *fifo = &mbx->tx;
   1922	/* reduce length by 1 to convert to a mask */
   1923	u16 mbmem_len = mbx->mbmem_len - 1;
   1924	u16 tail_len, len = 0;
   1925
   1926	/* push head behind tail */
   1927	if (mbx->tail < head)
   1928		head += mbmem_len;
   1929
   1930	fm10k_mbx_pull_head(hw, mbx, head);
   1931
   1932	/* determine msg aligned offset for end of buffer */
   1933	do {
   1934		u32 *msg;
   1935
   1936		msg = fifo->buffer + fm10k_fifo_head_offset(fifo, len);
   1937		tail_len = len;
   1938		len += FM10K_TLV_DWORD_LEN(*msg);
   1939	} while ((len <= mbx->tail_len) && (len < mbmem_len));
   1940
   1941	/* guarantee we stop on a message boundary */
   1942	if (mbx->tail_len > tail_len) {
   1943		mbx->tail = fm10k_mbx_tail_sub(mbx, mbx->tail_len - tail_len);
   1944		mbx->tail_len = tail_len;
   1945	}
   1946
   1947	/* clear any extra bits left over since index adds 1 extra bit */
   1948	if (mbx->tail > mbmem_len)
   1949		mbx->tail -= mbmem_len;
   1950}
   1951
   1952/**
   1953 *  fm10k_sm_mbx_create_reply - Generate reply based on state and remote head
   1954 *  @hw: pointer to hardware structure
   1955 *  @mbx: pointer to mailbox
   1956 *  @head: acknowledgement number
   1957 *
   1958 *  This function will generate an outgoing message based on the current
   1959 *  mailbox state and the remote FIFO head.  It will return the length
   1960 *  of the outgoing message excluding header on success, and a negative value
   1961 *  on error.
   1962 **/
   1963static void fm10k_sm_mbx_create_reply(struct fm10k_hw *hw,
   1964				      struct fm10k_mbx_info *mbx, u16 head)
   1965{
   1966	switch (mbx->state) {
   1967	case FM10K_STATE_OPEN:
   1968	case FM10K_STATE_DISCONNECT:
   1969		/* flush out Tx data */
   1970		fm10k_sm_mbx_transmit(hw, mbx, head);
   1971
   1972		/* generate new header based on data */
   1973		if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) {
   1974			fm10k_sm_mbx_create_data_hdr(mbx);
   1975		} else {
   1976			mbx->remote = 0;
   1977			fm10k_sm_mbx_create_connect_hdr(mbx, 0);
   1978		}
   1979		break;
   1980	case FM10K_STATE_CONNECT:
   1981	case FM10K_STATE_CLOSED:
   1982		fm10k_sm_mbx_create_connect_hdr(mbx, 0);
   1983		break;
   1984	default:
   1985		break;
   1986	}
   1987}
   1988
   1989/**
   1990 *  fm10k_sm_mbx_process_reset - Process header with version == 0 (RESET)
   1991 *  @hw: pointer to hardware structure
   1992 *  @mbx: pointer to mailbox
   1993 *
   1994 *  This function is meant to respond to a request where the version data
   1995 *  is set to 0.  As such we will either terminate the connection or go
   1996 *  into the connect state in order to re-establish the connection.  This
   1997 *  function can also be used to respond to an error as the connection
   1998 *  resetting would also be a means of dealing with errors.
   1999 **/
   2000static s32 fm10k_sm_mbx_process_reset(struct fm10k_hw *hw,
   2001				      struct fm10k_mbx_info *mbx)
   2002{
   2003	s32 err = 0;
   2004	const enum fm10k_mbx_state state = mbx->state;
   2005
   2006	switch (state) {
   2007	case FM10K_STATE_DISCONNECT:
   2008		/* drop remote connections and disconnect */
   2009		mbx->state = FM10K_STATE_CLOSED;
   2010		mbx->remote = 0;
   2011		mbx->local = 0;
   2012		break;
   2013	case FM10K_STATE_OPEN:
   2014		/* flush any incomplete work */
   2015		fm10k_sm_mbx_connect_reset(mbx);
   2016		err = FM10K_ERR_RESET_REQUESTED;
   2017		break;
   2018	case FM10K_STATE_CONNECT:
   2019		/* Update remote value to match local value */
   2020		mbx->remote = mbx->local;
   2021		break;
   2022	default:
   2023		break;
   2024	}
   2025
   2026	fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail);
   2027
   2028	return err;
   2029}
   2030
   2031/**
   2032 *  fm10k_sm_mbx_process_version_1 - Process header with version == 1
   2033 *  @hw: pointer to hardware structure
   2034 *  @mbx: pointer to mailbox
   2035 *
   2036 *  This function is meant to process messages received when the remote
   2037 *  mailbox is active.
   2038 **/
   2039static s32 fm10k_sm_mbx_process_version_1(struct fm10k_hw *hw,
   2040					  struct fm10k_mbx_info *mbx)
   2041{
   2042	const u32 *hdr = &mbx->mbx_hdr;
   2043	u16 head, tail;
   2044	s32 len;
   2045
   2046	/* pull all fields needed for verification */
   2047	tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
   2048	head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
   2049
   2050	/* if we are in connect and wanting version 1 then start up and go */
   2051	if (mbx->state == FM10K_STATE_CONNECT) {
   2052		if (!mbx->remote)
   2053			goto send_reply;
   2054		if (mbx->remote != 1)
   2055			return FM10K_MBX_ERR_SRC;
   2056
   2057		mbx->state = FM10K_STATE_OPEN;
   2058	}
   2059
   2060	do {
   2061		/* abort on message size errors */
   2062		len = fm10k_sm_mbx_receive(hw, mbx, tail);
   2063		if (len < 0)
   2064			return len;
   2065
   2066		/* continue until we have flushed the Rx FIFO */
   2067	} while (len);
   2068
   2069send_reply:
   2070	fm10k_sm_mbx_create_reply(hw, mbx, head);
   2071
   2072	return 0;
   2073}
   2074
   2075/**
   2076 *  fm10k_sm_mbx_process - Process switch manager mailbox interrupt
   2077 *  @hw: pointer to hardware structure
   2078 *  @mbx: pointer to mailbox
   2079 *
   2080 *  This function will process incoming mailbox events and generate mailbox
   2081 *  replies.  It will return a value indicating the number of DWORDs
   2082 *  transmitted excluding header on success or a negative value on error.
   2083 **/
   2084static s32 fm10k_sm_mbx_process(struct fm10k_hw *hw,
   2085				struct fm10k_mbx_info *mbx)
   2086{
   2087	s32 err;
   2088
   2089	/* we do not read mailbox if closed */
   2090	if (mbx->state == FM10K_STATE_CLOSED)
   2091		return 0;
   2092
   2093	/* retrieve data from switch manager */
   2094	err = fm10k_mbx_read(hw, mbx);
   2095	if (err)
   2096		return err;
   2097
   2098	err = fm10k_sm_mbx_validate_fifo_hdr(mbx);
   2099	if (err < 0)
   2100		goto fifo_err;
   2101
   2102	if (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_ERR)) {
   2103		fm10k_sm_mbx_process_error(mbx);
   2104		goto fifo_err;
   2105	}
   2106
   2107	switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) {
   2108	case 0:
   2109		err = fm10k_sm_mbx_process_reset(hw, mbx);
   2110		break;
   2111	case FM10K_SM_MBX_VERSION:
   2112		err = fm10k_sm_mbx_process_version_1(hw, mbx);
   2113		break;
   2114	}
   2115
   2116fifo_err:
   2117	if (err < 0)
   2118		fm10k_sm_mbx_create_error_msg(mbx, err);
   2119
   2120	/* report data to switch manager */
   2121	fm10k_mbx_write(hw, mbx);
   2122
   2123	return err;
   2124}
   2125
   2126/**
   2127 *  fm10k_sm_mbx_init - Initialize mailbox memory for PF/SM mailbox
   2128 *  @hw: pointer to hardware structure
   2129 *  @mbx: pointer to mailbox
   2130 *  @msg_data: handlers for mailbox events
   2131 *
   2132 *  This function initializes the PF/SM mailbox for use.  It will split the
   2133 *  buffer provided and use that to populate both the Tx and Rx FIFO by
   2134 *  evenly splitting it.  In order to allow for easy masking of head/tail
   2135 *  the value reported in size must be a power of 2 and is reported in
   2136 *  DWORDs, not bytes.  Any invalid values will cause the mailbox to return
   2137 *  error.
   2138 **/
   2139s32 fm10k_sm_mbx_init(struct fm10k_hw __always_unused *hw,
   2140		      struct fm10k_mbx_info *mbx,
   2141		      const struct fm10k_msg_data *msg_data)
   2142{
   2143	mbx->mbx_reg = FM10K_GMBX;
   2144	mbx->mbmem_reg = FM10K_MBMEM_PF(0);
   2145
   2146	/* start out in closed state */
   2147	mbx->state = FM10K_STATE_CLOSED;
   2148
   2149	/* validate layout of handlers before assigning them */
   2150	if (fm10k_mbx_validate_handlers(msg_data))
   2151		return FM10K_ERR_PARAM;
   2152
   2153	/* initialize the message handlers */
   2154	mbx->msg_data = msg_data;
   2155
   2156	/* start mailbox as timed out and let the reset_hw call
   2157	 * set the timeout value to begin communications
   2158	 */
   2159	mbx->timeout = 0;
   2160	mbx->udelay = FM10K_MBX_INIT_DELAY;
   2161
   2162	/* Split buffer for use by Tx/Rx FIFOs */
   2163	mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
   2164	mbx->mbmem_len = FM10K_MBMEM_PF_XOR;
   2165
   2166	/* initialize the FIFOs, sizes are in 4 byte increments */
   2167	fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
   2168	fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
   2169			FM10K_MBX_RX_BUFFER_SIZE);
   2170
   2171	/* initialize function pointers */
   2172	mbx->ops.connect = fm10k_sm_mbx_connect;
   2173	mbx->ops.disconnect = fm10k_sm_mbx_disconnect;
   2174	mbx->ops.rx_ready = fm10k_mbx_rx_ready;
   2175	mbx->ops.tx_ready = fm10k_mbx_tx_ready;
   2176	mbx->ops.tx_complete = fm10k_mbx_tx_complete;
   2177	mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
   2178	mbx->ops.process = fm10k_sm_mbx_process;
   2179	mbx->ops.register_handlers = fm10k_mbx_register_handlers;
   2180
   2181	return 0;
   2182}