LCOV - code coverage report
Current view: top level - drivers/net/fm10k/base - fm10k_mbx.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 616 0.0 %
Date: 2025-01-02 22:41:34 Functions: 0 48 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 349 0.0 %

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

Generated by: LCOV version 1.14