Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright(c) 2013 - 2019 Intel Corporation. */
0003 
0004 #include "fm10k_common.h"
0005 
0006 /**
0007  *  fm10k_fifo_init - Initialize a message FIFO
0008  *  @fifo: pointer to FIFO
0009  *  @buffer: pointer to memory to be used to store FIFO
0010  *  @size: maximum message size to store in FIFO, must be 2^n - 1
0011  **/
0012 static void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size)
0013 {
0014     fifo->buffer = buffer;
0015     fifo->size = size;
0016     fifo->head = 0;
0017     fifo->tail = 0;
0018 }
0019 
0020 /**
0021  *  fm10k_fifo_used - Retrieve used space in FIFO
0022  *  @fifo: pointer to FIFO
0023  *
0024  *  This function returns the number of DWORDs used in the FIFO
0025  **/
0026 static u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo)
0027 {
0028     return fifo->tail - fifo->head;
0029 }
0030 
0031 /**
0032  *  fm10k_fifo_unused - Retrieve unused space in FIFO
0033  *  @fifo: pointer to FIFO
0034  *
0035  *  This function returns the number of unused DWORDs in the FIFO
0036  **/
0037 static u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo)
0038 {
0039     return fifo->size + fifo->head - fifo->tail;
0040 }
0041 
0042 /**
0043  *  fm10k_fifo_empty - Test to verify if FIFO is empty
0044  *  @fifo: pointer to FIFO
0045  *
0046  *  This function returns true if the FIFO is empty, else false
0047  **/
0048 static bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo)
0049 {
0050     return fifo->head == fifo->tail;
0051 }
0052 
0053 /**
0054  *  fm10k_fifo_head_offset - returns indices of head with given offset
0055  *  @fifo: pointer to FIFO
0056  *  @offset: offset to add to head
0057  *
0058  *  This function returns the indices into the FIFO based on head + offset
0059  **/
0060 static u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
0061 {
0062     return (fifo->head + offset) & (fifo->size - 1);
0063 }
0064 
0065 /**
0066  *  fm10k_fifo_tail_offset - returns indices of tail with given offset
0067  *  @fifo: pointer to FIFO
0068  *  @offset: offset to add to tail
0069  *
0070  *  This function returns the indices into the FIFO based on tail + offset
0071  **/
0072 static u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
0073 {
0074     return (fifo->tail + offset) & (fifo->size - 1);
0075 }
0076 
0077 /**
0078  *  fm10k_fifo_head_len - Retrieve length of first message in FIFO
0079  *  @fifo: pointer to FIFO
0080  *
0081  *  This function returns the size of the first message in the FIFO
0082  **/
0083 static u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo)
0084 {
0085     u32 *head = fifo->buffer + fm10k_fifo_head_offset(fifo, 0);
0086 
0087     /* verify there is at least 1 DWORD in the fifo so *head is valid */
0088     if (fm10k_fifo_empty(fifo))
0089         return 0;
0090 
0091     /* retieve the message length */
0092     return FM10K_TLV_DWORD_LEN(*head);
0093 }
0094 
0095 /**
0096  *  fm10k_fifo_head_drop - Drop the first message in FIFO
0097  *  @fifo: pointer to FIFO
0098  *
0099  *  This function returns the size of the message dropped from the FIFO
0100  **/
0101 static u16 fm10k_fifo_head_drop(struct fm10k_mbx_fifo *fifo)
0102 {
0103     u16 len = fm10k_fifo_head_len(fifo);
0104 
0105     /* update head so it is at the start of next frame */
0106     fifo->head += len;
0107 
0108     return len;
0109 }
0110 
0111 /**
0112  *  fm10k_fifo_drop_all - Drop all messages in FIFO
0113  *  @fifo: pointer to FIFO
0114  *
0115  *  This function resets the head pointer to drop all messages in the FIFO and
0116  *  ensure the FIFO is empty.
0117  **/
0118 static void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
0119 {
0120     fifo->head = fifo->tail;
0121 }
0122 
0123 /**
0124  *  fm10k_mbx_index_len - Convert a head/tail index into a length value
0125  *  @mbx: pointer to mailbox
0126  *  @head: head index
0127  *  @tail: head index
0128  *
0129  *  This function takes the head and tail index and determines the length
0130  *  of the data indicated by this pair.
0131  **/
0132 static u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail)
0133 {
0134     u16 len = tail - head;
0135 
0136     /* we wrapped so subtract 2, one for index 0, one for all 1s index */
0137     if (len > tail)
0138         len -= 2;
0139 
0140     return len & ((mbx->mbmem_len << 1) - 1);
0141 }
0142 
0143 /**
0144  *  fm10k_mbx_tail_add - Determine new tail value with added offset
0145  *  @mbx: pointer to mailbox
0146  *  @offset: length to add to tail offset
0147  *
0148  *  This function takes the local tail index and recomputes it for
0149  *  a given length added as an offset.
0150  **/
0151 static u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset)
0152 {
0153     u16 tail = (mbx->tail + offset + 1) & ((mbx->mbmem_len << 1) - 1);
0154 
0155     /* add/sub 1 because we cannot have offset 0 or all 1s */
0156     return (tail > mbx->tail) ? --tail : ++tail;
0157 }
0158 
0159 /**
0160  *  fm10k_mbx_tail_sub - Determine new tail value with subtracted offset
0161  *  @mbx: pointer to mailbox
0162  *  @offset: length to add to tail offset
0163  *
0164  *  This function takes the local tail index and recomputes it for
0165  *  a given length added as an offset.
0166  **/
0167 static u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset)
0168 {
0169     u16 tail = (mbx->tail - offset - 1) & ((mbx->mbmem_len << 1) - 1);
0170 
0171     /* sub/add 1 because we cannot have offset 0 or all 1s */
0172     return (tail < mbx->tail) ? ++tail : --tail;
0173 }
0174 
0175 /**
0176  *  fm10k_mbx_head_add - Determine new head value with added offset
0177  *  @mbx: pointer to mailbox
0178  *  @offset: length to add to head offset
0179  *
0180  *  This function takes the local head index and recomputes it for
0181  *  a given length added as an offset.
0182  **/
0183 static u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset)
0184 {
0185     u16 head = (mbx->head + offset + 1) & ((mbx->mbmem_len << 1) - 1);
0186 
0187     /* add/sub 1 because we cannot have offset 0 or all 1s */
0188     return (head > mbx->head) ? --head : ++head;
0189 }
0190 
0191 /**
0192  *  fm10k_mbx_head_sub - Determine new head value with subtracted offset
0193  *  @mbx: pointer to mailbox
0194  *  @offset: length to add to head offset
0195  *
0196  *  This function takes the local head index and recomputes it for
0197  *  a given length added as an offset.
0198  **/
0199 static u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset)
0200 {
0201     u16 head = (mbx->head - offset - 1) & ((mbx->mbmem_len << 1) - 1);
0202 
0203     /* sub/add 1 because we cannot have offset 0 or all 1s */
0204     return (head < mbx->head) ? ++head : --head;
0205 }
0206 
0207 /**
0208  *  fm10k_mbx_pushed_tail_len - Retrieve the length of message being pushed
0209  *  @mbx: pointer to mailbox
0210  *
0211  *  This function will return the length of the message currently being
0212  *  pushed onto the tail of the Rx queue.
0213  **/
0214 static u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx)
0215 {
0216     u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0);
0217 
0218     /* pushed tail is only valid if pushed is set */
0219     if (!mbx->pushed)
0220         return 0;
0221 
0222     return FM10K_TLV_DWORD_LEN(*tail);
0223 }
0224 
0225 /**
0226  *  fm10k_fifo_write_copy - pulls data off of msg and places it in FIFO
0227  *  @fifo: pointer to FIFO
0228  *  @msg: message array to populate
0229  *  @tail_offset: additional offset to add to tail pointer
0230  *  @len: length of FIFO to copy into message header
0231  *
0232  *  This function will take a message and copy it into a section of the
0233  *  FIFO.  In order to get something into a location other than just
0234  *  the tail you can use tail_offset to adjust the pointer.
0235  **/
0236 static void fm10k_fifo_write_copy(struct fm10k_mbx_fifo *fifo,
0237                   const u32 *msg, u16 tail_offset, u16 len)
0238 {
0239     u16 end = fm10k_fifo_tail_offset(fifo, tail_offset);
0240     u32 *tail = fifo->buffer + end;
0241 
0242     /* track when we should cross the end of the FIFO */
0243     end = fifo->size - end;
0244 
0245     /* copy end of message before start of message */
0246     if (end < len)
0247         memcpy(fifo->buffer, msg + end, (len - end) << 2);
0248     else
0249         end = len;
0250 
0251     /* Copy remaining message into Tx FIFO */
0252     memcpy(tail, msg, end << 2);
0253 }
0254 
0255 /**
0256  *  fm10k_fifo_enqueue - Enqueues the message to the tail of the FIFO
0257  *  @fifo: pointer to FIFO
0258  *  @msg: message array to read
0259  *
0260  *  This function enqueues a message up to the size specified by the length
0261  *  contained in the first DWORD of the message and will place at the tail
0262  *  of the FIFO.  It will return 0 on success, or a negative value on error.
0263  **/
0264 static s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg)
0265 {
0266     u16 len = FM10K_TLV_DWORD_LEN(*msg);
0267 
0268     /* verify parameters */
0269     if (len > fifo->size)
0270         return FM10K_MBX_ERR_SIZE;
0271 
0272     /* verify there is room for the message */
0273     if (len > fm10k_fifo_unused(fifo))
0274         return FM10K_MBX_ERR_NO_SPACE;
0275 
0276     /* Copy message into FIFO */
0277     fm10k_fifo_write_copy(fifo, msg, 0, len);
0278 
0279     /* memory barrier to guarantee FIFO is written before tail update */
0280     wmb();
0281 
0282     /* Update Tx FIFO tail */
0283     fifo->tail += len;
0284 
0285     return 0;
0286 }
0287 
0288 /**
0289  *  fm10k_mbx_validate_msg_size - Validate incoming message based on size
0290  *  @mbx: pointer to mailbox
0291  *  @len: length of data pushed onto buffer
0292  *
0293  *  This function analyzes the frame and will return a non-zero value when
0294  *  the start of a message larger than the mailbox is detected.
0295  **/
0296 static u16 fm10k_mbx_validate_msg_size(struct fm10k_mbx_info *mbx, u16 len)
0297 {
0298     struct fm10k_mbx_fifo *fifo = &mbx->rx;
0299     u16 total_len = 0, msg_len;
0300 
0301     /* length should include previous amounts pushed */
0302     len += mbx->pushed;
0303 
0304     /* offset in message is based off of current message size */
0305     do {
0306         u32 *msg;
0307 
0308         msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len);
0309         msg_len = FM10K_TLV_DWORD_LEN(*msg);
0310         total_len += msg_len;
0311     } while (total_len < len);
0312 
0313     /* message extends out of pushed section, but fits in FIFO */
0314     if ((len < total_len) && (msg_len <= mbx->max_size))
0315         return 0;
0316 
0317     /* return length of invalid section */
0318     return (len < total_len) ? len : (len - total_len);
0319 }
0320 
0321 /**
0322  *  fm10k_mbx_write_copy - pulls data off of Tx FIFO and places it in mbmem
0323  *  @hw: pointer to hardware structure
0324  *  @mbx: pointer to mailbox
0325  *
0326  *  This function will take a section of the Tx FIFO and copy it into the
0327  *  mailbox memory.  The offset in mbmem is based on the lower bits of the
0328  *  tail and len determines the length to copy.
0329  **/
0330 static void fm10k_mbx_write_copy(struct fm10k_hw *hw,
0331                  struct fm10k_mbx_info *mbx)
0332 {
0333     struct fm10k_mbx_fifo *fifo = &mbx->tx;
0334     u32 mbmem = mbx->mbmem_reg;
0335     u32 *head = fifo->buffer;
0336     u16 end, len, tail, mask;
0337 
0338     if (!mbx->tail_len)
0339         return;
0340 
0341     /* determine data length and mbmem tail index */
0342     mask = mbx->mbmem_len - 1;
0343     len = mbx->tail_len;
0344     tail = fm10k_mbx_tail_sub(mbx, len);
0345     if (tail > mask)
0346         tail++;
0347 
0348     /* determine offset in the ring */
0349     end = fm10k_fifo_head_offset(fifo, mbx->pulled);
0350     head += end;
0351 
0352     /* memory barrier to guarantee data is ready to be read */
0353     rmb();
0354 
0355     /* Copy message from Tx FIFO */
0356     for (end = fifo->size - end; len; head = fifo->buffer) {
0357         do {
0358             /* adjust tail to match offset for FIFO */
0359             tail &= mask;
0360             if (!tail)
0361                 tail++;
0362 
0363             mbx->tx_mbmem_pulled++;
0364 
0365             /* write message to hardware FIFO */
0366             fm10k_write_reg(hw, mbmem + tail++, *(head++));
0367         } while (--len && --end);
0368     }
0369 }
0370 
0371 /**
0372  *  fm10k_mbx_pull_head - Pulls data off of head of Tx FIFO
0373  *  @hw: pointer to hardware structure
0374  *  @mbx: pointer to mailbox
0375  *  @head: acknowledgement number last received
0376  *
0377  *  This function will push the tail index forward based on the remote
0378  *  head index.  It will then pull up to mbmem_len DWORDs off of the
0379  *  head of the FIFO and will place it in the MBMEM registers
0380  *  associated with the mailbox.
0381  **/
0382 static void fm10k_mbx_pull_head(struct fm10k_hw *hw,
0383                 struct fm10k_mbx_info *mbx, u16 head)
0384 {
0385     u16 mbmem_len, len, ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
0386     struct fm10k_mbx_fifo *fifo = &mbx->tx;
0387 
0388     /* update number of bytes pulled and update bytes in transit */
0389     mbx->pulled += mbx->tail_len - ack;
0390 
0391     /* determine length of data to pull, reserve space for mbmem header */
0392     mbmem_len = mbx->mbmem_len - 1;
0393     len = fm10k_fifo_used(fifo) - mbx->pulled;
0394     if (len > mbmem_len)
0395         len = mbmem_len;
0396 
0397     /* update tail and record number of bytes in transit */
0398     mbx->tail = fm10k_mbx_tail_add(mbx, len - ack);
0399     mbx->tail_len = len;
0400 
0401     /* drop pulled messages from the FIFO */
0402     for (len = fm10k_fifo_head_len(fifo);
0403          len && (mbx->pulled >= len);
0404          len = fm10k_fifo_head_len(fifo)) {
0405         mbx->pulled -= fm10k_fifo_head_drop(fifo);
0406         mbx->tx_messages++;
0407         mbx->tx_dwords += len;
0408     }
0409 
0410     /* Copy message out from the Tx FIFO */
0411     fm10k_mbx_write_copy(hw, mbx);
0412 }
0413 
0414 /**
0415  *  fm10k_mbx_read_copy - pulls data off of mbmem and places it in Rx FIFO
0416  *  @hw: pointer to hardware structure
0417  *  @mbx: pointer to mailbox
0418  *
0419  *  This function will take a section of the mailbox memory and copy it
0420  *  into the Rx FIFO.  The offset is based on the lower bits of the
0421  *  head and len determines the length to copy.
0422  **/
0423 static void fm10k_mbx_read_copy(struct fm10k_hw *hw,
0424                 struct fm10k_mbx_info *mbx)
0425 {
0426     struct fm10k_mbx_fifo *fifo = &mbx->rx;
0427     u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len;
0428     u32 *tail = fifo->buffer;
0429     u16 end, len, head;
0430 
0431     /* determine data length and mbmem head index */
0432     len = mbx->head_len;
0433     head = fm10k_mbx_head_sub(mbx, len);
0434     if (head >= mbx->mbmem_len)
0435         head++;
0436 
0437     /* determine offset in the ring */
0438     end = fm10k_fifo_tail_offset(fifo, mbx->pushed);
0439     tail += end;
0440 
0441     /* Copy message into Rx FIFO */
0442     for (end = fifo->size - end; len; tail = fifo->buffer) {
0443         do {
0444             /* adjust head to match offset for FIFO */
0445             head &= mbx->mbmem_len - 1;
0446             if (!head)
0447                 head++;
0448 
0449             mbx->rx_mbmem_pushed++;
0450 
0451             /* read message from hardware FIFO */
0452             *(tail++) = fm10k_read_reg(hw, mbmem + head++);
0453         } while (--len && --end);
0454     }
0455 
0456     /* memory barrier to guarantee FIFO is written before tail update */
0457     wmb();
0458 }
0459 
0460 /**
0461  *  fm10k_mbx_push_tail - Pushes up to 15 DWORDs on to tail of FIFO
0462  *  @hw: pointer to hardware structure
0463  *  @mbx: pointer to mailbox
0464  *  @tail: tail index of message
0465  *
0466  *  This function will first validate the tail index and size for the
0467  *  incoming message.  It then updates the acknowledgment number and
0468  *  copies the data into the FIFO.  It will return the number of messages
0469  *  dequeued on success and a negative value on error.
0470  **/
0471 static s32 fm10k_mbx_push_tail(struct fm10k_hw *hw,
0472                    struct fm10k_mbx_info *mbx,
0473                    u16 tail)
0474 {
0475     struct fm10k_mbx_fifo *fifo = &mbx->rx;
0476     u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail);
0477 
0478     /* determine length of data to push */
0479     len = fm10k_fifo_unused(fifo) - mbx->pushed;
0480     if (len > seq)
0481         len = seq;
0482 
0483     /* update head and record bytes received */
0484     mbx->head = fm10k_mbx_head_add(mbx, len);
0485     mbx->head_len = len;
0486 
0487     /* nothing to do if there is no data */
0488     if (!len)
0489         return 0;
0490 
0491     /* Copy msg into Rx FIFO */
0492     fm10k_mbx_read_copy(hw, mbx);
0493 
0494     /* determine if there are any invalid lengths in message */
0495     if (fm10k_mbx_validate_msg_size(mbx, len))
0496         return FM10K_MBX_ERR_SIZE;
0497 
0498     /* Update pushed */
0499     mbx->pushed += len;
0500 
0501     /* flush any completed messages */
0502     for (len = fm10k_mbx_pushed_tail_len(mbx);
0503          len && (mbx->pushed >= len);
0504          len = fm10k_mbx_pushed_tail_len(mbx)) {
0505         fifo->tail += len;
0506         mbx->pushed -= len;
0507         mbx->rx_messages++;
0508         mbx->rx_dwords += len;
0509     }
0510 
0511     return 0;
0512 }
0513 
0514 /* pre-generated data for generating the CRC based on the poly 0xAC9A. */
0515 static const u16 fm10k_crc_16b_table[256] = {
0516     0x0000, 0x7956, 0xF2AC, 0x8BFA, 0xBC6D, 0xC53B, 0x4EC1, 0x3797,
0517     0x21EF, 0x58B9, 0xD343, 0xAA15, 0x9D82, 0xE4D4, 0x6F2E, 0x1678,
0518     0x43DE, 0x3A88, 0xB172, 0xC824, 0xFFB3, 0x86E5, 0x0D1F, 0x7449,
0519     0x6231, 0x1B67, 0x909D, 0xE9CB, 0xDE5C, 0xA70A, 0x2CF0, 0x55A6,
0520     0x87BC, 0xFEEA, 0x7510, 0x0C46, 0x3BD1, 0x4287, 0xC97D, 0xB02B,
0521     0xA653, 0xDF05, 0x54FF, 0x2DA9, 0x1A3E, 0x6368, 0xE892, 0x91C4,
0522     0xC462, 0xBD34, 0x36CE, 0x4F98, 0x780F, 0x0159, 0x8AA3, 0xF3F5,
0523     0xE58D, 0x9CDB, 0x1721, 0x6E77, 0x59E0, 0x20B6, 0xAB4C, 0xD21A,
0524     0x564D, 0x2F1B, 0xA4E1, 0xDDB7, 0xEA20, 0x9376, 0x188C, 0x61DA,
0525     0x77A2, 0x0EF4, 0x850E, 0xFC58, 0xCBCF, 0xB299, 0x3963, 0x4035,
0526     0x1593, 0x6CC5, 0xE73F, 0x9E69, 0xA9FE, 0xD0A8, 0x5B52, 0x2204,
0527     0x347C, 0x4D2A, 0xC6D0, 0xBF86, 0x8811, 0xF147, 0x7ABD, 0x03EB,
0528     0xD1F1, 0xA8A7, 0x235D, 0x5A0B, 0x6D9C, 0x14CA, 0x9F30, 0xE666,
0529     0xF01E, 0x8948, 0x02B2, 0x7BE4, 0x4C73, 0x3525, 0xBEDF, 0xC789,
0530     0x922F, 0xEB79, 0x6083, 0x19D5, 0x2E42, 0x5714, 0xDCEE, 0xA5B8,
0531     0xB3C0, 0xCA96, 0x416C, 0x383A, 0x0FAD, 0x76FB, 0xFD01, 0x8457,
0532     0xAC9A, 0xD5CC, 0x5E36, 0x2760, 0x10F7, 0x69A1, 0xE25B, 0x9B0D,
0533     0x8D75, 0xF423, 0x7FD9, 0x068F, 0x3118, 0x484E, 0xC3B4, 0xBAE2,
0534     0xEF44, 0x9612, 0x1DE8, 0x64BE, 0x5329, 0x2A7F, 0xA185, 0xD8D3,
0535     0xCEAB, 0xB7FD, 0x3C07, 0x4551, 0x72C6, 0x0B90, 0x806A, 0xF93C,
0536     0x2B26, 0x5270, 0xD98A, 0xA0DC, 0x974B, 0xEE1D, 0x65E7, 0x1CB1,
0537     0x0AC9, 0x739F, 0xF865, 0x8133, 0xB6A4, 0xCFF2, 0x4408, 0x3D5E,
0538     0x68F8, 0x11AE, 0x9A54, 0xE302, 0xD495, 0xADC3, 0x2639, 0x5F6F,
0539     0x4917, 0x3041, 0xBBBB, 0xC2ED, 0xF57A, 0x8C2C, 0x07D6, 0x7E80,
0540     0xFAD7, 0x8381, 0x087B, 0x712D, 0x46BA, 0x3FEC, 0xB416, 0xCD40,
0541     0xDB38, 0xA26E, 0x2994, 0x50C2, 0x6755, 0x1E03, 0x95F9, 0xECAF,
0542     0xB909, 0xC05F, 0x4BA5, 0x32F3, 0x0564, 0x7C32, 0xF7C8, 0x8E9E,
0543     0x98E6, 0xE1B0, 0x6A4A, 0x131C, 0x248B, 0x5DDD, 0xD627, 0xAF71,
0544     0x7D6B, 0x043D, 0x8FC7, 0xF691, 0xC106, 0xB850, 0x33AA, 0x4AFC,
0545     0x5C84, 0x25D2, 0xAE28, 0xD77E, 0xE0E9, 0x99BF, 0x1245, 0x6B13,
0546     0x3EB5, 0x47E3, 0xCC19, 0xB54F, 0x82D8, 0xFB8E, 0x7074, 0x0922,
0547     0x1F5A, 0x660C, 0xEDF6, 0x94A0, 0xA337, 0xDA61, 0x519B, 0x28CD };
0548 
0549 /**
0550  *  fm10k_crc_16b - Generate a 16 bit CRC for a region of 16 bit data
0551  *  @data: pointer to data to process
0552  *  @seed: seed value for CRC
0553  *  @len: length measured in 16 bits words
0554  *
0555  *  This function will generate a CRC based on the polynomial 0xAC9A and
0556  *  whatever value is stored in the seed variable.  Note that this
0557  *  value inverts the local seed and the result in order to capture all
0558  *  leading and trailing zeros.
0559  */
0560 static u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len)
0561 {
0562     u32 result = seed;
0563 
0564     while (len--) {
0565         result ^= *(data++);
0566         result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
0567         result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
0568 
0569         if (!(len--))
0570             break;
0571 
0572         result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
0573         result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
0574     }
0575 
0576     return (u16)result;
0577 }
0578 
0579 /**
0580  *  fm10k_fifo_crc - generate a CRC based off of FIFO data
0581  *  @fifo: pointer to FIFO
0582  *  @offset: offset point for start of FIFO
0583  *  @len: number of DWORDS words to process
0584  *  @seed: seed value for CRC
0585  *
0586  *  This function generates a CRC for some region of the FIFO
0587  **/
0588 static u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset,
0589               u16 len, u16 seed)
0590 {
0591     u32 *data = fifo->buffer + offset;
0592 
0593     /* track when we should cross the end of the FIFO */
0594     offset = fifo->size - offset;
0595 
0596     /* if we are in 2 blocks process the end of the FIFO first */
0597     if (offset < len) {
0598         seed = fm10k_crc_16b(data, seed, offset * 2);
0599         data = fifo->buffer;
0600         len -= offset;
0601     }
0602 
0603     /* process any remaining bits */
0604     return fm10k_crc_16b(data, seed, len * 2);
0605 }
0606 
0607 /**
0608  *  fm10k_mbx_update_local_crc - Update the local CRC for outgoing data
0609  *  @mbx: pointer to mailbox
0610  *  @head: head index provided by remote mailbox
0611  *
0612  *  This function will generate the CRC for all data from the end of the
0613  *  last head update to the current one.  It uses the result of the
0614  *  previous CRC as the seed for this update.  The result is stored in
0615  *  mbx->local.
0616  **/
0617 static void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head)
0618 {
0619     u16 len = mbx->tail_len - fm10k_mbx_index_len(mbx, head, mbx->tail);
0620 
0621     /* determine the offset for the start of the region to be pulled */
0622     head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled);
0623 
0624     /* update local CRC to include all of the pulled data */
0625     mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local);
0626 }
0627 
0628 /**
0629  *  fm10k_mbx_verify_remote_crc - Verify the CRC is correct for current data
0630  *  @mbx: pointer to mailbox
0631  *
0632  *  This function will take all data that has been provided from the remote
0633  *  end and generate a CRC for it.  This is stored in mbx->remote.  The
0634  *  CRC for the header is then computed and if the result is non-zero this
0635  *  is an error and we signal an error dropping all data and resetting the
0636  *  connection.
0637  */
0638 static s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx)
0639 {
0640     struct fm10k_mbx_fifo *fifo = &mbx->rx;
0641     u16 len = mbx->head_len;
0642     u16 offset = fm10k_fifo_tail_offset(fifo, mbx->pushed) - len;
0643     u16 crc;
0644 
0645     /* update the remote CRC if new data has been received */
0646     if (len)
0647         mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote);
0648 
0649     /* process the full header as we have to validate the CRC */
0650     crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1);
0651 
0652     /* notify other end if we have a problem */
0653     return crc ? FM10K_MBX_ERR_CRC : 0;
0654 }
0655 
0656 /**
0657  *  fm10k_mbx_rx_ready - Indicates that a message is ready in the Rx FIFO
0658  *  @mbx: pointer to mailbox
0659  *
0660  *  This function returns true if there is a message in the Rx FIFO to dequeue.
0661  **/
0662 static bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx)
0663 {
0664     u16 msg_size = fm10k_fifo_head_len(&mbx->rx);
0665 
0666     return msg_size && (fm10k_fifo_used(&mbx->rx) >= msg_size);
0667 }
0668 
0669 /**
0670  *  fm10k_mbx_tx_ready - Indicates that the mailbox is in state ready for Tx
0671  *  @mbx: pointer to mailbox
0672  *  @len: verify free space is >= this value
0673  *
0674  *  This function returns true if the mailbox is in a state ready to transmit.
0675  **/
0676 static bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len)
0677 {
0678     u16 fifo_unused = fm10k_fifo_unused(&mbx->tx);
0679 
0680     return (mbx->state == FM10K_STATE_OPEN) && (fifo_unused >= len);
0681 }
0682 
0683 /**
0684  *  fm10k_mbx_tx_complete - Indicates that the Tx FIFO has been emptied
0685  *  @mbx: pointer to mailbox
0686  *
0687  *  This function returns true if the Tx FIFO is empty.
0688  **/
0689 static bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx)
0690 {
0691     return fm10k_fifo_empty(&mbx->tx);
0692 }
0693 
0694 /**
0695  *  fm10k_mbx_dequeue_rx - Dequeues the message from the head in the Rx FIFO
0696  *  @hw: pointer to hardware structure
0697  *  @mbx: pointer to mailbox
0698  *
0699  *  This function dequeues messages and hands them off to the TLV parser.
0700  *  It will return the number of messages processed when called.
0701  **/
0702 static u16 fm10k_mbx_dequeue_rx(struct fm10k_hw *hw,
0703                 struct fm10k_mbx_info *mbx)
0704 {
0705     struct fm10k_mbx_fifo *fifo = &mbx->rx;
0706     s32 err;
0707     u16 cnt;
0708 
0709     /* parse Rx messages out of the Rx FIFO to empty it */
0710     for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) {
0711         err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head,
0712                       mbx, mbx->msg_data);
0713         if (err < 0)
0714             mbx->rx_parse_err++;
0715 
0716         fm10k_fifo_head_drop(fifo);
0717     }
0718 
0719     /* shift remaining bytes back to start of FIFO */
0720     memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2);
0721 
0722     /* shift head and tail based on the memory we moved */
0723     fifo->tail -= fifo->head;
0724     fifo->head = 0;
0725 
0726     return cnt;
0727 }
0728 
0729 /**
0730  *  fm10k_mbx_enqueue_tx - Enqueues the message to the tail of the Tx FIFO
0731  *  @hw: pointer to hardware structure
0732  *  @mbx: pointer to mailbox
0733  *  @msg: message array to read
0734  *
0735  *  This function enqueues a message up to the size specified by the length
0736  *  contained in the first DWORD of the message and will place at the tail
0737  *  of the FIFO.  It will return 0 on success, or a negative value on error.
0738  **/
0739 static s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw,
0740                 struct fm10k_mbx_info *mbx, const u32 *msg)
0741 {
0742     u32 countdown = mbx->timeout;
0743     s32 err;
0744 
0745     switch (mbx->state) {
0746     case FM10K_STATE_CLOSED:
0747     case FM10K_STATE_DISCONNECT:
0748         return FM10K_MBX_ERR_NO_MBX;
0749     default:
0750         break;
0751     }
0752 
0753     /* enqueue the message on the Tx FIFO */
0754     err = fm10k_fifo_enqueue(&mbx->tx, msg);
0755 
0756     /* if it failed give the FIFO a chance to drain */
0757     while (err && countdown) {
0758         countdown--;
0759         udelay(mbx->udelay);
0760         mbx->ops.process(hw, mbx);
0761         err = fm10k_fifo_enqueue(&mbx->tx, msg);
0762     }
0763 
0764     /* if we failed treat the error */
0765     if (err) {
0766         mbx->timeout = 0;
0767         mbx->tx_busy++;
0768     }
0769 
0770     /* begin processing message, ignore errors as this is just meant
0771      * to start the mailbox flow so we are not concerned if there
0772      * is a bad error, or the mailbox is already busy with a request
0773      */
0774     if (!mbx->tail_len)
0775         mbx->ops.process(hw, mbx);
0776 
0777     return 0;
0778 }
0779 
0780 /**
0781  *  fm10k_mbx_read - Copies the mbmem to local message buffer
0782  *  @hw: pointer to hardware structure
0783  *  @mbx: pointer to mailbox
0784  *
0785  *  This function copies the message from the mbmem to the message array
0786  **/
0787 static s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
0788 {
0789     /* only allow one reader in here at a time */
0790     if (mbx->mbx_hdr)
0791         return FM10K_MBX_ERR_BUSY;
0792 
0793     /* read to capture initial interrupt bits */
0794     if (fm10k_read_reg(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT)
0795         mbx->mbx_lock = FM10K_MBX_ACK;
0796 
0797     /* write back interrupt bits to clear */
0798     fm10k_write_reg(hw, mbx->mbx_reg,
0799             FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT);
0800 
0801     /* read remote header */
0802     mbx->mbx_hdr = fm10k_read_reg(hw, mbx->mbmem_reg ^ mbx->mbmem_len);
0803 
0804     return 0;
0805 }
0806 
0807 /**
0808  *  fm10k_mbx_write - Copies the local message buffer to mbmem
0809  *  @hw: pointer to hardware structure
0810  *  @mbx: pointer to mailbox
0811  *
0812  *  This function copies the message from the message array to mbmem
0813  **/
0814 static void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
0815 {
0816     u32 mbmem = mbx->mbmem_reg;
0817 
0818     /* write new msg header to notify recipient of change */
0819     fm10k_write_reg(hw, mbmem, mbx->mbx_hdr);
0820 
0821     /* write mailbox to send interrupt */
0822     if (mbx->mbx_lock)
0823         fm10k_write_reg(hw, mbx->mbx_reg, mbx->mbx_lock);
0824 
0825     /* we no longer are using the header so free it */
0826     mbx->mbx_hdr = 0;
0827     mbx->mbx_lock = 0;
0828 }
0829 
0830 /**
0831  *  fm10k_mbx_create_connect_hdr - Generate a connect mailbox header
0832  *  @mbx: pointer to mailbox
0833  *
0834  *  This function returns a connection mailbox header
0835  **/
0836 static void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx)
0837 {
0838     mbx->mbx_lock |= FM10K_MBX_REQ;
0839 
0840     mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) |
0841                FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) |
0842                FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE);
0843 }
0844 
0845 /**
0846  *  fm10k_mbx_create_data_hdr - Generate a data mailbox header
0847  *  @mbx: pointer to mailbox
0848  *
0849  *  This function returns a data mailbox header
0850  **/
0851 static void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
0852 {
0853     u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) |
0854           FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
0855           FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
0856     struct fm10k_mbx_fifo *fifo = &mbx->tx;
0857     u16 crc;
0858 
0859     if (mbx->tail_len)
0860         mbx->mbx_lock |= FM10K_MBX_REQ;
0861 
0862     /* generate CRC for data in flight and header */
0863     crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled),
0864                  mbx->tail_len, mbx->local);
0865     crc = fm10k_crc_16b(&hdr, crc, 1);
0866 
0867     /* load header to memory to be written */
0868     mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
0869 }
0870 
0871 /**
0872  *  fm10k_mbx_create_disconnect_hdr - Generate a disconnect mailbox header
0873  *  @mbx: pointer to mailbox
0874  *
0875  *  This function returns a disconnect mailbox header
0876  **/
0877 static void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
0878 {
0879     u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
0880           FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
0881           FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
0882     u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
0883 
0884     mbx->mbx_lock |= FM10K_MBX_ACK;
0885 
0886     /* load header to memory to be written */
0887     mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
0888 }
0889 
0890 /**
0891  *  fm10k_mbx_create_fake_disconnect_hdr - Generate a false disconnect mbox hdr
0892  *  @mbx: pointer to mailbox
0893  *
0894  *  This function creates a fake disconnect header for loading into remote
0895  *  mailbox header. The primary purpose is to prevent errors on immediate
0896  *  start up after mbx->connect.
0897  **/
0898 static void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
0899 {
0900     u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
0901           FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
0902           FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
0903     u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
0904 
0905     mbx->mbx_lock |= FM10K_MBX_ACK;
0906 
0907     /* load header to memory to be written */
0908     mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
0909 }
0910 
0911 /**
0912  *  fm10k_mbx_create_error_msg - Generate an error message
0913  *  @mbx: pointer to mailbox
0914  *  @err: local error encountered
0915  *
0916  *  This function will interpret the error provided by err, and based on
0917  *  that it may shift the message by 1 DWORD and then place an error header
0918  *  at the start of the message.
0919  **/
0920 static void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
0921 {
0922     /* only generate an error message for these types */
0923     switch (err) {
0924     case FM10K_MBX_ERR_TAIL:
0925     case FM10K_MBX_ERR_HEAD:
0926     case FM10K_MBX_ERR_TYPE:
0927     case FM10K_MBX_ERR_SIZE:
0928     case FM10K_MBX_ERR_RSVD0:
0929     case FM10K_MBX_ERR_CRC:
0930         break;
0931     default:
0932         return;
0933     }
0934 
0935     mbx->mbx_lock |= FM10K_MBX_REQ;
0936 
0937     mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) |
0938                FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) |
0939                FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
0940 }
0941 
0942 /**
0943  *  fm10k_mbx_validate_msg_hdr - Validate common fields in the message header
0944  *  @mbx: pointer to mailbox
0945  *
0946  *  This function will parse up the fields in the mailbox header and return
0947  *  an error if the header contains any of a number of invalid configurations
0948  *  including unrecognized type, invalid route, or a malformed message.
0949  **/
0950 static s32 fm10k_mbx_validate_msg_hdr(struct fm10k_mbx_info *mbx)
0951 {
0952     u16 type, rsvd0, head, tail, size;
0953     const u32 *hdr = &mbx->mbx_hdr;
0954 
0955     type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE);
0956     rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0);
0957     tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
0958     head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
0959     size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
0960 
0961     if (rsvd0)
0962         return FM10K_MBX_ERR_RSVD0;
0963 
0964     switch (type) {
0965     case FM10K_MSG_DISCONNECT:
0966         /* validate that all data has been received */
0967         if (tail != mbx->head)
0968             return FM10K_MBX_ERR_TAIL;
0969 
0970         fallthrough;
0971     case FM10K_MSG_DATA:
0972         /* validate that head is moving correctly */
0973         if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
0974             return FM10K_MBX_ERR_HEAD;
0975         if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
0976             return FM10K_MBX_ERR_HEAD;
0977 
0978         /* validate that tail is moving correctly */
0979         if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL)))
0980             return FM10K_MBX_ERR_TAIL;
0981         if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
0982             break;
0983 
0984         return FM10K_MBX_ERR_TAIL;
0985     case FM10K_MSG_CONNECT:
0986         /* validate size is in range and is power of 2 mask */
0987         if ((size < FM10K_VFMBX_MSG_MTU) || (size & (size + 1)))
0988             return FM10K_MBX_ERR_SIZE;
0989 
0990         fallthrough;
0991     case FM10K_MSG_ERROR:
0992         if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
0993             return FM10K_MBX_ERR_HEAD;
0994         /* neither create nor error include a tail offset */
0995         if (tail)
0996             return FM10K_MBX_ERR_TAIL;
0997 
0998         break;
0999     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  **/
1017 static 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  **/
1058 static 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  **/
1100 static 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  **/
1122 static 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  **/
1147 static 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  **/
1194 static 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  **/
1236 static 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  **/
1289 static 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  **/
1336 static 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 
1373 msg_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  **/
1397 static 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  **/
1436 static 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  **/
1477 static 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  **/
1531 static 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  **/
1558 s32 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  **/
1631 static 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  **/
1648 static 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  **/
1665 static 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  **/
1694 static 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  **/
1738 static 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  **/
1772 static 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  **/
1814 static 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 connecting 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  **/
1850 static 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  **/
1878 static 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  **/
1918 static 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  **/
1963 static 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  **/
2000 static 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  **/
2039 static 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 
2069 send_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  **/
2084 static 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 
2116 fifo_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  **/
2139 s32 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 }