dpdk/drivers/net/fm10k/base/fm10k_mbx.c
<<
>>
Prefs
   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 **/
  13STATIC void fm10k_fifo_init(struct fm10k_mbx_fifo *fifo, u32 *buffer, u16 size)
  14{
  15        fifo->buffer = buffer;
  16        fifo->size = size;
  17        fifo->head = 0;
  18        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 **/
  27STATIC u16 fm10k_fifo_used(struct fm10k_mbx_fifo *fifo)
  28{
  29        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 **/
  38STATIC u16 fm10k_fifo_unused(struct fm10k_mbx_fifo *fifo)
  39{
  40        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 **/
  49STATIC bool fm10k_fifo_empty(struct fm10k_mbx_fifo *fifo)
  50{
  51        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 **/
  61STATIC u16 fm10k_fifo_head_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
  62{
  63        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 **/
  73STATIC u16 fm10k_fifo_tail_offset(struct fm10k_mbx_fifo *fifo, u16 offset)
  74{
  75        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 **/
  84STATIC u16 fm10k_fifo_head_len(struct fm10k_mbx_fifo *fifo)
  85{
  86        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        if (fm10k_fifo_empty(fifo))
  90                return 0;
  91
  92        /* retieve the message length */
  93        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 **/
 102STATIC 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        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 **/
 119STATIC void fm10k_fifo_drop_all(struct fm10k_mbx_fifo *fifo)
 120{
 121        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 **/
 133STATIC u16 fm10k_mbx_index_len(struct fm10k_mbx_info *mbx, u16 head, u16 tail)
 134{
 135        u16 len = tail - head;
 136
 137        /* we wrapped so subtract 2, one for index 0, one for all 1s index */
 138        if (len > tail)
 139                len -= 2;
 140
 141        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 **/
 152STATIC u16 fm10k_mbx_tail_add(struct fm10k_mbx_info *mbx, u16 offset)
 153{
 154        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        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 **/
 168STATIC u16 fm10k_mbx_tail_sub(struct fm10k_mbx_info *mbx, u16 offset)
 169{
 170        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        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 **/
 184STATIC u16 fm10k_mbx_head_add(struct fm10k_mbx_info *mbx, u16 offset)
 185{
 186        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        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 **/
 200STATIC u16 fm10k_mbx_head_sub(struct fm10k_mbx_info *mbx, u16 offset)
 201{
 202        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        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 **/
 215STATIC u16 fm10k_mbx_pushed_tail_len(struct fm10k_mbx_info *mbx)
 216{
 217        u32 *tail = mbx->rx.buffer + fm10k_fifo_tail_offset(&mbx->rx, 0);
 218
 219        /* pushed tail is only valid if pushed is set */
 220        if (!mbx->pushed)
 221                return 0;
 222
 223        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 **/
 237STATIC 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        u32 *tail = fifo->buffer + end;
 242
 243        /* track when we should cross the end of the FIFO */
 244        end = fifo->size - end;
 245
 246        /* copy end of message before start of message */
 247        if (end < len)
 248                memcpy(fifo->buffer, msg + end, (len - end) << 2);
 249        else
 250                end = len;
 251
 252        /* Copy remaining message into Tx FIFO */
 253        memcpy(tail, msg, end << 2);
 254}
 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 **/
 265STATIC s32 fm10k_fifo_enqueue(struct fm10k_mbx_fifo *fifo, const u32 *msg)
 266{
 267        u16 len = FM10K_TLV_DWORD_LEN(*msg);
 268
 269        DEBUGFUNC("fm10k_fifo_enqueue");
 270
 271        /* verify parameters */
 272        if (len > fifo->size)
 273                return FM10K_MBX_ERR_SIZE;
 274
 275        /* verify there is room for the message */
 276        if (len > fm10k_fifo_unused(fifo))
 277                return FM10K_MBX_ERR_NO_SPACE;
 278
 279        /* Copy message into FIFO */
 280        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        fifo->tail += len;
 287
 288        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 **/
 299STATIC 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        DEBUGFUNC("fm10k_mbx_validate_msg_size");
 306
 307        /* length should include previous amounts pushed */
 308        len += mbx->pushed;
 309
 310        /* offset in message is based off of current message size */
 311        do {
 312                msg = fifo->buffer + fm10k_fifo_tail_offset(fifo, total_len);
 313                msg_len = FM10K_TLV_DWORD_LEN(*msg);
 314                total_len += msg_len;
 315        } while (total_len < len);
 316
 317        /* message extends out of pushed section, but fits in FIFO */
 318        if ((len < total_len) && (msg_len <= mbx->max_size))
 319                return 0;
 320
 321        /* return length of invalid section */
 322        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 **/
 334STATIC 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        u32 mbmem = mbx->mbmem_reg;
 339        u32 *head = fifo->buffer;
 340        u16 end, len, tail, mask;
 341
 342        DEBUGFUNC("fm10k_mbx_write_copy");
 343
 344        if (!mbx->tail_len)
 345                return;
 346
 347        /* determine data length and mbmem tail index */
 348        mask = mbx->mbmem_len - 1;
 349        len = mbx->tail_len;
 350        tail = fm10k_mbx_tail_sub(mbx, len);
 351        if (tail > mask)
 352                tail++;
 353
 354        /* determine offset in the ring */
 355        end = fm10k_fifo_head_offset(fifo, mbx->pulled);
 356        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        for (end = fifo->size - end; len; head = fifo->buffer) {
 363                do {
 364                        /* adjust tail to match offset for FIFO */
 365                        tail &= mask;
 366                        if (!tail)
 367                                tail++;
 368
 369                        mbx->tx_mbmem_pulled++;
 370
 371                        /* write message to hardware FIFO */
 372                        FM10K_WRITE_MBX(hw, mbmem + tail++, *(head++));
 373                } 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 **/
 388STATIC void fm10k_mbx_pull_head(struct fm10k_hw *hw,
 389                                struct fm10k_mbx_info *mbx, u16 head)
 390{
 391        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        mbx->pulled += mbx->tail_len - ack;
 396
 397        /* determine length of data to pull, reserve space for mbmem header */
 398        mbmem_len = mbx->mbmem_len - 1;
 399        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        mbx->tail = fm10k_mbx_tail_add(mbx, len - ack);
 405        mbx->tail_len = len;
 406
 407        /* drop pulled messages from the FIFO */
 408        for (len = fm10k_fifo_head_len(fifo);
 409             len && (mbx->pulled >= len);
 410             len = fm10k_fifo_head_len(fifo)) {
 411                mbx->pulled -= fm10k_fifo_head_drop(fifo);
 412                mbx->tx_messages++;
 413                mbx->tx_dwords += len;
 414        }
 415
 416        /* Copy message out from the Tx FIFO */
 417        fm10k_mbx_write_copy(hw, mbx);
 418}
 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 **/
 429STATIC 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        u32 mbmem = mbx->mbmem_reg ^ mbx->mbmem_len;
 434        u32 *tail = fifo->buffer;
 435        u16 end, len, head;
 436
 437        DEBUGFUNC("fm10k_mbx_read_copy");
 438
 439        /* determine data length and mbmem head index */
 440        len = mbx->head_len;
 441        head = fm10k_mbx_head_sub(mbx, len);
 442        if (head >= mbx->mbmem_len)
 443                head++;
 444
 445        /* determine offset in the ring */
 446        end = fm10k_fifo_tail_offset(fifo, mbx->pushed);
 447        tail += end;
 448
 449        /* Copy message into Rx FIFO */
 450        for (end = fifo->size - end; len; tail = fifo->buffer) {
 451                do {
 452                        /* adjust head to match offset for FIFO */
 453                        head &= mbx->mbmem_len - 1;
 454                        if (!head)
 455                                head++;
 456
 457                        mbx->rx_mbmem_pushed++;
 458
 459                        /* read message from hardware FIFO */
 460                        *(tail++) = FM10K_READ_MBX(hw, mbmem + head++);
 461                } while (--len && --end);
 462        }
 463
 464        /* memory barrier to guarantee FIFO is written before tail update */
 465        FM10K_WMB();
 466}
 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 **/
 479STATIC 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        u16 len, seq = fm10k_mbx_index_len(mbx, mbx->head, tail);
 485
 486        DEBUGFUNC("fm10k_mbx_push_tail");
 487
 488        /* determine length of data to push */
 489        len = fm10k_fifo_unused(fifo) - mbx->pushed;
 490        if (len > seq)
 491                len = seq;
 492
 493        /* update head and record bytes received */
 494        mbx->head = fm10k_mbx_head_add(mbx, len);
 495        mbx->head_len = len;
 496
 497        /* nothing to do if there is no data */
 498        if (!len)
 499                return FM10K_SUCCESS;
 500
 501        /* Copy msg into Rx FIFO */
 502        fm10k_mbx_read_copy(hw, mbx);
 503
 504        /* determine if there are any invalid lengths in message */
 505        if (fm10k_mbx_validate_msg_size(mbx, len))
 506                return FM10K_MBX_ERR_SIZE;
 507
 508        /* Update pushed */
 509        mbx->pushed += len;
 510
 511        /* flush any completed messages */
 512        for (len = fm10k_mbx_pushed_tail_len(mbx);
 513             len && (mbx->pushed >= len);
 514             len = fm10k_mbx_pushed_tail_len(mbx)) {
 515                fifo->tail += len;
 516                mbx->pushed -= len;
 517                mbx->rx_messages++;
 518                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. */
 525static 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 */
 570STATIC u16 fm10k_crc_16b(const u32 *data, u16 seed, u16 len)
 571{
 572        u32 result = seed;
 573
 574        while (len--) {
 575                result ^= *(data++);
 576                result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
 577                result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
 578
 579                if (!(len--))
 580                        break;
 581
 582                result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
 583                result = (result >> 8) ^ fm10k_crc_16b_table[result & 0xFF];
 584        }
 585
 586        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 **/
 598STATIC u16 fm10k_fifo_crc(struct fm10k_mbx_fifo *fifo, u16 offset,
 599                          u16 len, u16 seed)
 600{
 601        u32 *data = fifo->buffer + offset;
 602
 603        /* track when we should cross the end of the FIFO */
 604        offset = fifo->size - offset;
 605
 606        /* if we are in 2 blocks process the end of the FIFO first */
 607        if (offset < len) {
 608                seed = fm10k_crc_16b(data, seed, offset * 2);
 609                data = fifo->buffer;
 610                len -= offset;
 611        }
 612
 613        /* process any remaining bits */
 614        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 **/
 627STATIC void fm10k_mbx_update_local_crc(struct fm10k_mbx_info *mbx, u16 head)
 628{
 629        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        head = fm10k_fifo_head_offset(&mbx->tx, mbx->pulled);
 633
 634        /* update local CRC to include all of the pulled data */
 635        mbx->local = fm10k_fifo_crc(&mbx->tx, head, len, mbx->local);
 636}
 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 */
 648STATIC s32 fm10k_mbx_verify_remote_crc(struct fm10k_mbx_info *mbx)
 649{
 650        struct fm10k_mbx_fifo *fifo = &mbx->rx;
 651        u16 len = mbx->head_len;
 652        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        if (len)
 657                mbx->remote = fm10k_fifo_crc(fifo, offset, len, mbx->remote);
 658
 659        /* process the full header as we have to validate the CRC */
 660        crc = fm10k_crc_16b(&mbx->mbx_hdr, mbx->remote, 1);
 661
 662        /* notify other end if we have a problem */
 663        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 **/
 672STATIC bool fm10k_mbx_rx_ready(struct fm10k_mbx_info *mbx)
 673{
 674        u16 msg_size = fm10k_fifo_head_len(&mbx->rx);
 675
 676        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 **/
 686STATIC bool fm10k_mbx_tx_ready(struct fm10k_mbx_info *mbx, u16 len)
 687{
 688        u16 fifo_unused = fm10k_fifo_unused(&mbx->tx);
 689
 690        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 **/
 699STATIC bool fm10k_mbx_tx_complete(struct fm10k_mbx_info *mbx)
 700{
 701        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 **/
 712STATIC 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        for (cnt = 0; !fm10k_fifo_empty(fifo); cnt++) {
 721                err = fm10k_tlv_msg_parse(hw, fifo->buffer + fifo->head,
 722                                          mbx, mbx->msg_data);
 723                if (err < 0)
 724                        mbx->rx_parse_err++;
 725
 726                fm10k_fifo_head_drop(fifo);
 727        }
 728
 729        /* shift remaining bytes back to start of FIFO */
 730        memmove(fifo->buffer, fifo->buffer + fifo->tail, mbx->pushed << 2);
 731
 732        /* shift head and tail based on the memory we moved */
 733        fifo->tail -= fifo->head;
 734        fifo->head = 0;
 735
 736        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 **/
 749STATIC s32 fm10k_mbx_enqueue_tx(struct fm10k_hw *hw,
 750                                struct fm10k_mbx_info *mbx, const u32 *msg)
 751{
 752        u32 countdown = mbx->timeout;
 753        s32 err;
 754
 755        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        err = fm10k_fifo_enqueue(&mbx->tx, msg);
 765
 766        /* if it failed give the FIFO a chance to drain */
 767        while (err && countdown) {
 768                countdown--;
 769                usec_delay(mbx->usec_delay);
 770                mbx->ops.process(hw, mbx);
 771                err = fm10k_fifo_enqueue(&mbx->tx, msg);
 772        }
 773
 774        /* if we failed treat the error */
 775        if (err) {
 776                mbx->timeout = 0;
 777                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        if (!mbx->tail_len)
 785                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 **/
 797STATIC s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
 798{
 799        DEBUGFUNC("fm10k_mbx_read");
 800
 801        /* only allow one reader in here at a time */
 802        if (mbx->mbx_hdr)
 803                return FM10K_MBX_ERR_BUSY;
 804
 805        /* read to capture initial interrupt bits */
 806        if (FM10K_READ_MBX(hw, mbx->mbx_reg) & FM10K_MBX_REQ_INTERRUPT)
 807                mbx->mbx_lock = FM10K_MBX_ACK;
 808
 809        /* write back interrupt bits to clear */
 810        FM10K_WRITE_MBX(hw, mbx->mbx_reg,
 811                        FM10K_MBX_REQ_INTERRUPT | FM10K_MBX_ACK_INTERRUPT);
 812
 813        /* read remote header */
 814        mbx->mbx_hdr = FM10K_READ_MBX(hw, mbx->mbmem_reg ^ mbx->mbmem_len);
 815
 816        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 **/
 826STATIC void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
 827{
 828        u32 mbmem = mbx->mbmem_reg;
 829
 830        DEBUGFUNC("fm10k_mbx_write");
 831
 832        /* write new msg header to notify recipient of change */
 833        FM10K_WRITE_MBX(hw, mbmem, mbx->mbx_hdr);
 834
 835        /* write mailbox to send interrupt */
 836        if (mbx->mbx_lock)
 837                FM10K_WRITE_MBX(hw, mbx->mbx_reg, mbx->mbx_lock);
 838
 839        /* we no longer are using the header so free it */
 840        mbx->mbx_hdr = 0;
 841        mbx->mbx_lock = 0;
 842}
 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 **/
 850STATIC void fm10k_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx)
 851{
 852        mbx->mbx_lock |= FM10K_MBX_REQ;
 853
 854        mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_CONNECT, TYPE) |
 855                       FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD) |
 856                       FM10K_MSG_HDR_FIELD_SET(mbx->rx.size - 1, CONNECT_SIZE);
 857}
 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 **/
 865STATIC void fm10k_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
 866{
 867        u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DATA, TYPE) |
 868                  FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
 869                  FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
 870        struct fm10k_mbx_fifo *fifo = &mbx->tx;
 871        u16 crc;
 872
 873        if (mbx->tail_len)
 874                mbx->mbx_lock |= FM10K_MBX_REQ;
 875
 876        /* generate CRC for data in flight and header */
 877        crc = fm10k_fifo_crc(fifo, fm10k_fifo_head_offset(fifo, mbx->pulled),
 878                             mbx->tail_len, mbx->local);
 879        crc = fm10k_crc_16b(&hdr, crc, 1);
 880
 881        /* load header to memory to be written */
 882        mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
 883}
 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 **/
 891STATIC void fm10k_mbx_create_disconnect_hdr(struct fm10k_mbx_info *mbx)
 892{
 893        u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
 894                  FM10K_MSG_HDR_FIELD_SET(mbx->tail, TAIL) |
 895                  FM10K_MSG_HDR_FIELD_SET(mbx->head, HEAD);
 896        u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
 897
 898        mbx->mbx_lock |= FM10K_MBX_ACK;
 899
 900        /* load header to memory to be written */
 901        mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
 902}
 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 **/
 912STATIC void fm10k_mbx_create_fake_disconnect_hdr(struct fm10k_mbx_info *mbx)
 913{
 914        u32 hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_DISCONNECT, TYPE) |
 915                  FM10K_MSG_HDR_FIELD_SET(mbx->head, TAIL) |
 916                  FM10K_MSG_HDR_FIELD_SET(mbx->tail, HEAD);
 917        u16 crc = fm10k_crc_16b(&hdr, mbx->local, 1);
 918
 919        mbx->mbx_lock |= FM10K_MBX_ACK;
 920
 921        /* load header to memory to be written */
 922        mbx->mbx_hdr = hdr | FM10K_MSG_HDR_FIELD_SET(crc, CRC);
 923}
 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 **/
 934STATIC void fm10k_mbx_create_error_msg(struct fm10k_mbx_info *mbx, s32 err)
 935{
 936        /* only generate an error message for these types */
 937        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        mbx->mbx_lock |= FM10K_MBX_REQ;
 950
 951        mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(FM10K_MSG_ERROR, TYPE) |
 952                       FM10K_MSG_HDR_FIELD_SET(err, ERR_NO) |
 953                       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 **/
 964STATIC 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        DEBUGFUNC("fm10k_mbx_validate_msg_hdr");
 970
 971        type = FM10K_MSG_HDR_FIELD_GET(*hdr, TYPE);
 972        rsvd0 = FM10K_MSG_HDR_FIELD_GET(*hdr, RSVD0);
 973        tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
 974        head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
 975        size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
 976
 977        if (rsvd0)
 978                return FM10K_MBX_ERR_RSVD0;
 979
 980        switch (type) {
 981        case FM10K_MSG_DISCONNECT:
 982                /* validate that all data has been received */
 983                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                if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
 990                        return FM10K_MBX_ERR_HEAD;
 991                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                if (!tail || (tail == FM10K_MSG_HDR_MASK(TAIL)))
 996                        return FM10K_MBX_ERR_TAIL;
 997                if (fm10k_mbx_index_len(mbx, mbx->head, tail) < mbx->mbmem_len)
 998                        break;
 999
1000                return FM10K_MBX_ERR_TAIL;
1001        case FM10K_MSG_CONNECT:
1002                /* validate size is in range and is power of 2 mask */
1003                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                if (!head || (head == FM10K_MSG_HDR_MASK(HEAD)))
1009                        return FM10K_MBX_ERR_HEAD;
1010                /* neither create nor error include a tail offset */
1011                if (tail)
1012                        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 **/
1033STATIC s32 fm10k_mbx_create_reply(struct fm10k_hw *hw,
1034                                  struct fm10k_mbx_info *mbx, u16 head)
1035{
1036        switch (mbx->state) {
1037        case FM10K_STATE_OPEN:
1038        case FM10K_STATE_DISCONNECT:
1039                /* update our checksum for the outgoing data */
1040                fm10k_mbx_update_local_crc(mbx, head);
1041
1042                /* as long as other end recognizes us keep sending data */
1043                fm10k_mbx_pull_head(hw, mbx, head);
1044
1045                /* generate new header based on data */
1046                if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN))
1047                        fm10k_mbx_create_data_hdr(mbx);
1048                else
1049                        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        case FM10K_STATE_CLOSED:
1056                /* generate new header based on data */
1057                fm10k_mbx_create_disconnect_hdr(mbx);
1058        default:
1059                break;
1060        }
1061
1062        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 **/
1073STATIC 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        mbx->max_size = mbx->rx.size - 1;
1079
1080        /* update mbx->pulled to account for tail_len and ack */
1081        head = FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, HEAD);
1082        ack = fm10k_mbx_index_len(mbx, head, mbx->tail);
1083        mbx->pulled += mbx->tail_len - ack;
1084
1085        /* now drop any messages which have started or finished transmitting */
1086        while (fm10k_fifo_head_len(&mbx->tx) && mbx->pulled) {
1087                len = fm10k_fifo_head_drop(&mbx->tx);
1088                mbx->tx_dropped++;
1089                if (mbx->pulled >= len)
1090                        mbx->pulled -= len;
1091                else
1092                        mbx->pulled = 0;
1093        }
1094
1095        /* just do a quick resysnc to start of message */
1096        mbx->pushed = 0;
1097        mbx->pulled = 0;
1098        mbx->tail_len = 0;
1099        mbx->head_len = 0;
1100        mbx->rx.tail = 0;
1101        mbx->rx.head = 0;
1102}
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 **/
1115STATIC void fm10k_mbx_update_max_size(struct fm10k_mbx_info *mbx, u16 size)
1116{
1117        u16 len;
1118
1119        DEBUGFUNC("fm10k_mbx_update_max_size");
1120
1121        mbx->max_size = size;
1122
1123        /* flush any oversized messages from the queue */
1124        for (len = fm10k_fifo_head_len(&mbx->tx);
1125             len > size;
1126             len = fm10k_fifo_head_len(&mbx->tx)) {
1127                fm10k_fifo_head_drop(&mbx->tx);
1128                mbx->tx_dropped++;
1129        }
1130}
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 **/
1139STATIC void fm10k_mbx_connect_reset(struct fm10k_mbx_info *mbx)
1140{
1141        /* just do a quick resysnc to start of frame */
1142        fm10k_mbx_reset_work(mbx);
1143
1144        /* reset CRC seeds */
1145        mbx->local = FM10K_MBX_CRC_SEED;
1146        mbx->remote = FM10K_MBX_CRC_SEED;
1147
1148        /* we cannot exit connect until the size is good */
1149        if (mbx->state == FM10K_STATE_OPEN)
1150                mbx->state = FM10K_STATE_CONNECT;
1151        else
1152                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 **/
1164STATIC s32 fm10k_mbx_process_connect(struct fm10k_hw *hw,
1165                                     struct fm10k_mbx_info *mbx)
1166{
1167        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        size = FM10K_MSG_HDR_FIELD_GET(*hdr, CONNECT_SIZE);
1173        head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1174
1175        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        case FM10K_STATE_CONNECT:
1182                /* we cannot exit connect until the size is good */
1183                if (size > mbx->rx.size) {
1184                        mbx->max_size = mbx->rx.size - 1;
1185                } else {
1186                        /* record the remote system requesting connection */
1187                        mbx->state = FM10K_STATE_OPEN;
1188
1189                        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        mbx->tail = head;
1198
1199        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 **/
1211STATIC 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        DEBUGFUNC("fm10k_mbx_process_data");
1219
1220        /* we will need to pull all of the fields for verification */
1221        head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1222        tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
1223
1224        /* if we are in connect just update our data and go */
1225        if (mbx->state == FM10K_STATE_CONNECT) {
1226                mbx->tail = head;
1227                mbx->state = FM10K_STATE_OPEN;
1228        }
1229
1230        /* abort on message size errors */
1231        err = fm10k_mbx_push_tail(hw, mbx, tail);
1232        if (err < 0)
1233                return err;
1234
1235        /* verify the checksum on the incoming data */
1236        err = fm10k_mbx_verify_remote_crc(mbx);
1237        if (err)
1238                return err;
1239
1240        /* process messages if we have received any */
1241        fm10k_mbx_dequeue_rx(hw, mbx);
1242
1243        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 **/
1255STATIC s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw,
1256                                        struct fm10k_mbx_info *mbx)
1257{
1258        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        head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1265
1266        /* We should not be receiving disconnect if Rx is incomplete */
1267        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        mbx->head_len = 0;
1272
1273        /* verify the checksum on the incoming header is correct */
1274        err = fm10k_mbx_verify_remote_crc(mbx);
1275        if (err)
1276                return err;
1277
1278        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                if (!fm10k_mbx_tx_complete(mbx))
1283                        break;
1284
1285                /* verify the head indicates we completed all transmits */
1286                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        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 **/
1308STATIC 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        head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
1316
1317        switch (mbx->state) {
1318        case FM10K_STATE_OPEN:
1319        case FM10K_STATE_DISCONNECT:
1320                /* flush any uncompleted work */
1321                fm10k_mbx_reset_work(mbx);
1322
1323                /* reset CRC seeds */
1324                mbx->local = FM10K_MBX_CRC_SEED;
1325                mbx->remote = FM10K_MBX_CRC_SEED;
1326
1327                /* reset tail index and size to prepare for reconnect */
1328                mbx->tail = head;
1329
1330                /* if open then reset max_size and go back to connect */
1331                if (mbx->state == FM10K_STATE_OPEN) {
1332                        mbx->state = FM10K_STATE_CONNECT;
1333                        break;
1334                }
1335
1336                /* send a connect message to get data flowing again */
1337                fm10k_mbx_create_connect_hdr(mbx);
1338                return FM10K_SUCCESS;
1339        default:
1340                break;
1341        }
1342
1343        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 **/
1355STATIC s32 fm10k_mbx_process(struct fm10k_hw *hw,
1356                             struct fm10k_mbx_info *mbx)
1357{
1358        s32 err;
1359
1360        DEBUGFUNC("fm10k_mbx_process");
1361
1362        /* we do not read mailbox if closed */
1363        if (mbx->state == FM10K_STATE_CLOSED)
1364                return FM10K_SUCCESS;
1365
1366        /* copy data from mailbox */
1367        err = fm10k_mbx_read(hw, mbx);
1368        if (err)
1369                return err;
1370
1371        /* validate type, source, and destination */
1372        err = fm10k_mbx_validate_msg_hdr(mbx);
1373        if (err < 0)
1374                goto msg_err;
1375
1376        switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, TYPE)) {
1377        case FM10K_MSG_CONNECT:
1378                err = fm10k_mbx_process_connect(hw, mbx);
1379                break;
1380        case FM10K_MSG_DATA:
1381                err = fm10k_mbx_process_data(hw, mbx);
1382                break;
1383        case FM10K_MSG_DISCONNECT:
1384                err = fm10k_mbx_process_disconnect(hw, mbx);
1385                break;
1386        case FM10K_MSG_ERROR:
1387                err = fm10k_mbx_process_error(hw, mbx);
1388                break;
1389        default:
1390                err = FM10K_MBX_ERR_TYPE;
1391                break;
1392        }
1393
1394msg_err:
1395        /* notify partner of errors on our end */
1396        if (err < 0)
1397                fm10k_mbx_create_error_msg(mbx, err);
1398
1399        /* copy data from mailbox */
1400        fm10k_mbx_write(hw, mbx);
1401
1402        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 **/
1418STATIC void fm10k_mbx_disconnect(struct fm10k_hw *hw,
1419                                 struct fm10k_mbx_info *mbx)
1420{
1421        int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
1422
1423        DEBUGFUNC("fm10k_mbx_disconnect");
1424
1425        /* Place mbx in ready to disconnect state */
1426        mbx->state = FM10K_STATE_DISCONNECT;
1427
1428        /* trigger interrupt to start shutdown process */
1429        FM10K_WRITE_MBX(hw, mbx->mbx_reg, FM10K_MBX_REQ |
1430                                          FM10K_MBX_INTERRUPT_DISABLE);
1431        do {
1432                usec_delay(FM10K_MBX_POLL_DELAY);
1433                mbx->ops.process(hw, mbx);
1434                timeout -= FM10K_MBX_POLL_DELAY;
1435        } 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        FM10K_WRITE_MBX(hw, mbx->mbmem_reg, 0);
1444}
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 **/
1459STATIC s32 fm10k_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
1460{
1461        DEBUGFUNC("fm10k_mbx_connect");
1462
1463        /* we cannot connect an uninitialized mailbox */
1464        if (!mbx->rx.buffer)
1465                return FM10K_MBX_ERR_NO_SPACE;
1466
1467        /* we cannot connect an already connected mailbox */
1468        if (mbx->state != FM10K_STATE_CLOSED)
1469                return FM10K_MBX_ERR_BUSY;
1470
1471        /* mailbox timeout can now become active */
1472        mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
1473
1474        /* Place mbx in ready to connect state */
1475        mbx->state = FM10K_STATE_CONNECT;
1476
1477        fm10k_mbx_reset_work(mbx);
1478
1479        /* initialize header of remote mailbox */
1480        fm10k_mbx_create_fake_disconnect_hdr(mbx);
1481        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        fm10k_mbx_write(hw, mbx);
1490
1491        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 **/
1502STATIC 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        DEBUGFUNC("fm10k_mbx_validate_handlers");
1508
1509        /* Allow NULL mailboxes that transmit but don't receive */
1510        if (!msg_data)
1511                return FM10K_SUCCESS;
1512
1513        while (msg_data->id != FM10K_TLV_ERROR) {
1514                /* all messages should have a function handler */
1515                if (!msg_data->func)
1516                        return FM10K_ERR_PARAM;
1517
1518                /* parser is optional */
1519                attr = msg_data->attr;
1520                if (attr) {
1521                        while (attr->id != FM10K_TLV_ERROR) {
1522                                id = attr->id;
1523                                attr++;
1524                                /* ID should always be increasing */
1525                                if (id >= attr->id)
1526                                        return FM10K_ERR_PARAM;
1527                                /* ID should fit in results array */
1528                                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                msg_data++;
1539                /* ID should always be increasing */
1540                if (id >= msg_data->id)
1541                        return FM10K_ERR_PARAM;
1542        }
1543
1544        /* verify terminator is in the list */
1545        if ((msg_data->id != FM10K_TLV_ERROR) || !msg_data->func)
1546                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 **/
1558STATIC s32 fm10k_mbx_register_handlers(struct fm10k_mbx_info *mbx,
1559                                       const struct fm10k_msg_data *msg_data)
1560{
1561        DEBUGFUNC("fm10k_mbx_register_handlers");
1562
1563        /* validate layout of handlers before assigning them */
1564        if (fm10k_mbx_validate_handlers(msg_data))
1565                return FM10K_ERR_PARAM;
1566
1567        /* initialize the message handlers */
1568        mbx->msg_data = msg_data;
1569
1570        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 **/
1587s32 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        DEBUGFUNC("fm10k_pfvf_mbx_init");
1591
1592        /* initialize registers */
1593        switch (hw->mac.type) {
1594        case fm10k_mac_vf:
1595                mbx->mbx_reg = FM10K_VFMBX;
1596                mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR);
1597                break;
1598        case fm10k_mac_pf:
1599                /* there are only 64 VF <-> PF mailboxes */
1600                if (id < 64) {
1601                        mbx->mbx_reg = FM10K_MBX(id);
1602                        mbx->mbmem_reg = FM10K_MBMEM_VF(id, 0);
1603                        break;
1604                }
1605                /* fallthough */
1606        default:
1607                return FM10K_MBX_ERR_NO_MBX;
1608        }
1609
1610        /* start out in closed state */
1611        mbx->state = FM10K_STATE_CLOSED;
1612
1613        /* validate layout of handlers before assigning them */
1614        if (fm10k_mbx_validate_handlers(msg_data))
1615                return FM10K_ERR_PARAM;
1616
1617        /* initialize the message handlers */
1618        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        mbx->timeout = 0;
1624        mbx->usec_delay = FM10K_MBX_INIT_DELAY;
1625
1626        /* initialize tail and head */
1627        mbx->tail = 1;
1628        mbx->head = 1;
1629
1630        /* initialize CRC seeds */
1631        mbx->local = FM10K_MBX_CRC_SEED;
1632        mbx->remote = FM10K_MBX_CRC_SEED;
1633
1634        /* Split buffer for use by Tx/Rx FIFOs */
1635        mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
1636        mbx->mbmem_len = FM10K_VFMBMEM_VF_XOR;
1637
1638        /* initialize the FIFOs, sizes are in 4 byte increments */
1639        fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
1640        fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
1641                        FM10K_MBX_RX_BUFFER_SIZE);
1642
1643        /* initialize function pointers */
1644        mbx->ops.connect = fm10k_mbx_connect;
1645        mbx->ops.disconnect = fm10k_mbx_disconnect;
1646        mbx->ops.rx_ready = fm10k_mbx_rx_ready;
1647        mbx->ops.tx_ready = fm10k_mbx_tx_ready;
1648        mbx->ops.tx_complete = fm10k_mbx_tx_complete;
1649        mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
1650        mbx->ops.process = fm10k_mbx_process;
1651        mbx->ops.register_handlers = fm10k_mbx_register_handlers;
1652
1653        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 **/
1662STATIC void fm10k_sm_mbx_create_data_hdr(struct fm10k_mbx_info *mbx)
1663{
1664        if (mbx->tail_len)
1665                mbx->mbx_lock |= FM10K_MBX_REQ;
1666
1667        mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
1668                       FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
1669                       FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD);
1670}
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 **/
1679STATIC void fm10k_sm_mbx_create_connect_hdr(struct fm10k_mbx_info *mbx, u8 err)
1680{
1681        if (mbx->local)
1682                mbx->mbx_lock |= FM10K_MBX_REQ;
1683
1684        mbx->mbx_hdr = FM10K_MSG_HDR_FIELD_SET(mbx->tail, SM_TAIL) |
1685                       FM10K_MSG_HDR_FIELD_SET(mbx->remote, SM_VER) |
1686                       FM10K_MSG_HDR_FIELD_SET(mbx->head, SM_HEAD) |
1687                       FM10K_MSG_HDR_FIELD_SET(err, SM_ERR);
1688}
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 **/
1696STATIC void fm10k_sm_mbx_connect_reset(struct fm10k_mbx_info *mbx)
1697{
1698        /* flush any uncompleted work */
1699        fm10k_mbx_reset_work(mbx);
1700
1701        /* set local version to max and remote version to 0 */
1702        mbx->local = FM10K_SM_MBX_VERSION;
1703        mbx->remote = 0;
1704
1705        /* initialize tail and head */
1706        mbx->tail = 1;
1707        mbx->head = 1;
1708
1709        /* reset state back to connect */
1710        mbx->state = FM10K_STATE_CONNECT;
1711}
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 **/
1725STATIC s32 fm10k_sm_mbx_connect(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
1726{
1727        DEBUGFUNC("fm10k_sm_mbx_connect");
1728
1729        /* we cannot connect an uninitialized mailbox */
1730        if (!mbx->rx.buffer)
1731                return FM10K_MBX_ERR_NO_SPACE;
1732
1733        /* we cannot connect an already connected mailbox */
1734        if (mbx->state != FM10K_STATE_CLOSED)
1735                return FM10K_MBX_ERR_BUSY;
1736
1737        /* mailbox timeout can now become active */
1738        mbx->timeout = FM10K_MBX_INIT_TIMEOUT;
1739
1740        /* Place mbx in ready to connect state */
1741        mbx->state = FM10K_STATE_CONNECT;
1742        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        fm10k_mbx_write(hw, mbx);
1754
1755        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 **/
1771STATIC void fm10k_sm_mbx_disconnect(struct fm10k_hw *hw,
1772                                    struct fm10k_mbx_info *mbx)
1773{
1774        int timeout = mbx->timeout ? FM10K_MBX_DISCONNECT_TIMEOUT : 0;
1775
1776        DEBUGFUNC("fm10k_sm_mbx_disconnect");
1777
1778        /* Place mbx in ready to disconnect state */
1779        mbx->state = FM10K_STATE_DISCONNECT;
1780
1781        /* trigger interrupt to start shutdown process */
1782        FM10K_WRITE_REG(hw, mbx->mbx_reg, FM10K_MBX_REQ |
1783                                          FM10K_MBX_INTERRUPT_DISABLE);
1784        do {
1785                usec_delay(FM10K_MBX_POLL_DELAY);
1786                mbx->ops.process(hw, mbx);
1787                timeout -= FM10K_MBX_POLL_DELAY;
1788        } while ((timeout > 0) && (mbx->state != FM10K_STATE_CLOSED));
1789
1790        /* in case we didn't close just force the mailbox into shutdown */
1791        mbx->state = FM10K_STATE_CLOSED;
1792        mbx->remote = 0;
1793        fm10k_mbx_reset_work(mbx);
1794        fm10k_fifo_drop_all(&mbx->tx);
1795
1796        FM10K_WRITE_REG(hw, mbx->mbmem_reg, 0);
1797}
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 **/
1807STATIC 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        DEBUGFUNC("fm10k_sm_mbx_validate_fifo_hdr");
1813
1814        tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
1815        ver = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_VER);
1816        head = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_HEAD);
1817
1818        switch (ver) {
1819        case 0:
1820                break;
1821        case FM10K_SM_MBX_VERSION:
1822                if (!head || head > FM10K_SM_MBX_FIFO_LEN)
1823                        return FM10K_MBX_ERR_HEAD;
1824                if (!tail || tail > FM10K_SM_MBX_FIFO_LEN)
1825                        return FM10K_MBX_ERR_TAIL;
1826                if (mbx->tail < head)
1827                        head += mbx->mbmem_len - 1;
1828                if (tail < mbx->head)
1829                        tail += mbx->mbmem_len - 1;
1830                if (fm10k_mbx_index_len(mbx, head, mbx->tail) > mbx->tail_len)
1831                        return FM10K_MBX_ERR_HEAD;
1832                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 **/
1851STATIC void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx)
1852{
1853        const enum fm10k_mbx_state state = mbx->state;
1854
1855        switch (state) {
1856        case FM10K_STATE_DISCONNECT:
1857                /* if there is an error just disconnect */
1858                mbx->remote = 0;
1859                break;
1860        case FM10K_STATE_OPEN:
1861                /* flush any uncompleted work */
1862                fm10k_sm_mbx_connect_reset(mbx);
1863                break;
1864        case FM10K_STATE_CONNECT:
1865                /* try connnecting at lower version */
1866                if (mbx->remote) {
1867                        while (mbx->local > 1)
1868                                mbx->local--;
1869                        mbx->remote = 0;
1870                }
1871                break;
1872        default:
1873                break;
1874        }
1875
1876        fm10k_sm_mbx_create_connect_hdr(mbx, 0);
1877}
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 **/
1887STATIC 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        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        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 **/
1915STATIC 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        u16 mbmem_len = mbx->mbmem_len - 1;
1921        s32 err;
1922
1923        DEBUGFUNC("fm10k_sm_mbx_receive");
1924
1925        /* push tail in front of head */
1926        if (tail < mbx->head)
1927                tail += mbmem_len;
1928
1929        /* copy data to the Rx FIFO */
1930        err = fm10k_mbx_push_tail(hw, mbx, tail);
1931        if (err < 0)
1932                return err;
1933
1934        /* process messages if we have received any */
1935        fm10k_mbx_dequeue_rx(hw, mbx);
1936
1937        /* guarantee head aligns with the end of the last message */
1938        mbx->head = fm10k_mbx_head_sub(mbx, mbx->pushed);
1939        mbx->pushed = 0;
1940
1941        /* clear any extra bits left over since index adds 1 extra bit */
1942        if (mbx->head > mbmem_len)
1943                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 **/
1957STATIC 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        u16 mbmem_len = mbx->mbmem_len - 1;
1963        u16 tail_len, len = 0;
1964        u32 *msg;
1965
1966        DEBUGFUNC("fm10k_sm_mbx_transmit");
1967
1968        /* push head behind tail */
1969        if (mbx->tail < head)
1970                head += mbmem_len;
1971
1972        fm10k_mbx_pull_head(hw, mbx, head);
1973
1974        /* determine msg aligned offset for end of buffer */
1975        do {
1976                msg = fifo->buffer + fm10k_fifo_head_offset(fifo, len);
1977                tail_len = len;
1978                len += FM10K_TLV_DWORD_LEN(*msg);
1979        } while ((len <= mbx->tail_len) && (len < mbmem_len));
1980
1981        /* guarantee we stop on a message boundary */
1982        if (mbx->tail_len > tail_len) {
1983                mbx->tail = fm10k_mbx_tail_sub(mbx, mbx->tail_len - tail_len);
1984                mbx->tail_len = tail_len;
1985        }
1986
1987        /* clear any extra bits left over since index adds 1 extra bit */
1988        if (mbx->tail > mbmem_len)
1989                mbx->tail -= mbmem_len;
1990}
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 **/
2003STATIC void fm10k_sm_mbx_create_reply(struct fm10k_hw *hw,
2004                                      struct fm10k_mbx_info *mbx, u16 head)
2005{
2006        switch (mbx->state) {
2007        case FM10K_STATE_OPEN:
2008        case FM10K_STATE_DISCONNECT:
2009                /* flush out Tx data */
2010                fm10k_sm_mbx_transmit(hw, mbx, head);
2011
2012                /* generate new header based on data */
2013                if (mbx->tail_len || (mbx->state == FM10K_STATE_OPEN)) {
2014                        fm10k_sm_mbx_create_data_hdr(mbx);
2015                } else {
2016                        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}
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 **/
2040STATIC s32 fm10k_sm_mbx_process_reset(struct fm10k_hw *hw,
2041                                      struct fm10k_mbx_info *mbx)
2042{
2043        s32 err = FM10K_SUCCESS;
2044        const enum fm10k_mbx_state state = mbx->state;
2045
2046        switch (state) {
2047        case FM10K_STATE_DISCONNECT:
2048                /* drop remote connections and disconnect */
2049                mbx->state = FM10K_STATE_CLOSED;
2050                mbx->remote = 0;
2051                mbx->local = 0;
2052                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                break;
2058        case FM10K_STATE_CONNECT:
2059                /* Update remote value to match local value */
2060                mbx->remote = mbx->local;
2061        default:
2062                break;
2063        }
2064
2065        fm10k_sm_mbx_create_reply(hw, mbx, mbx->tail);
2066
2067        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 **/
2078STATIC 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        tail = FM10K_MSG_HDR_FIELD_GET(*hdr, SM_TAIL);
2087        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        if (mbx->state == FM10K_STATE_CONNECT) {
2091                if (!mbx->remote)
2092                        goto send_reply;
2093                if (mbx->remote != 1)
2094                        return FM10K_MBX_ERR_SRC;
2095
2096                mbx->state = FM10K_STATE_OPEN;
2097        }
2098
2099        do {
2100                /* abort on message size errors */
2101                len = fm10k_sm_mbx_receive(hw, mbx, tail);
2102                if (len < 0)
2103                        return len;
2104
2105                /* continue until we have flushed the Rx FIFO */
2106        } while (len);
2107
2108send_reply:
2109        fm10k_sm_mbx_create_reply(hw, mbx, head);
2110
2111        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 **/
2123STATIC s32 fm10k_sm_mbx_process(struct fm10k_hw *hw,
2124                                struct fm10k_mbx_info *mbx)
2125{
2126        s32 err;
2127
2128        DEBUGFUNC("fm10k_sm_mbx_process");
2129
2130        /* we do not read mailbox if closed */
2131        if (mbx->state == FM10K_STATE_CLOSED)
2132                return FM10K_SUCCESS;
2133
2134        /* retrieve data from switch manager */
2135        err = fm10k_mbx_read(hw, mbx);
2136        if (err)
2137                return err;
2138
2139        err = fm10k_sm_mbx_validate_fifo_hdr(mbx);
2140        if (err < 0)
2141                goto fifo_err;
2142
2143        if (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_ERR)) {
2144                fm10k_sm_mbx_process_error(mbx);
2145                goto fifo_err;
2146        }
2147
2148        switch (FM10K_MSG_HDR_FIELD_GET(mbx->mbx_hdr, SM_VER)) {
2149        case 0:
2150                err = fm10k_sm_mbx_process_reset(hw, mbx);
2151                break;
2152        case FM10K_SM_MBX_VERSION:
2153                err = fm10k_sm_mbx_process_version_1(hw, mbx);
2154                break;
2155        }
2156
2157fifo_err:
2158        if (err < 0)
2159                fm10k_sm_mbx_create_error_msg(mbx, err);
2160
2161        /* report data to switch manager */
2162        fm10k_mbx_write(hw, mbx);
2163
2164        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 **/
2180s32 fm10k_sm_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx,
2181                      const struct fm10k_msg_data *msg_data)
2182{
2183        DEBUGFUNC("fm10k_sm_mbx_init");
2184        UNREFERENCED_1PARAMETER(hw);
2185
2186        mbx->mbx_reg = FM10K_GMBX;
2187        mbx->mbmem_reg = FM10K_MBMEM_PF(0);
2188
2189        /* start out in closed state */
2190        mbx->state = FM10K_STATE_CLOSED;
2191
2192        /* validate layout of handlers before assigning them */
2193        if (fm10k_mbx_validate_handlers(msg_data))
2194                return FM10K_ERR_PARAM;
2195
2196        /* initialize the message handlers */
2197        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        mbx->timeout = 0;
2203        mbx->usec_delay = FM10K_MBX_INIT_DELAY;
2204
2205        /* Split buffer for use by Tx/Rx FIFOs */
2206        mbx->max_size = FM10K_MBX_MSG_MAX_SIZE;
2207        mbx->mbmem_len = FM10K_MBMEM_PF_XOR;
2208
2209        /* initialize the FIFOs, sizes are in 4 byte increments */
2210        fm10k_fifo_init(&mbx->tx, mbx->buffer, FM10K_MBX_TX_BUFFER_SIZE);
2211        fm10k_fifo_init(&mbx->rx, &mbx->buffer[FM10K_MBX_TX_BUFFER_SIZE],
2212                        FM10K_MBX_RX_BUFFER_SIZE);
2213
2214        /* initialize function pointers */
2215        mbx->ops.connect = fm10k_sm_mbx_connect;
2216        mbx->ops.disconnect = fm10k_sm_mbx_disconnect;
2217        mbx->ops.rx_ready = fm10k_mbx_rx_ready;
2218        mbx->ops.tx_ready = fm10k_mbx_tx_ready;
2219        mbx->ops.tx_complete = fm10k_mbx_tx_complete;
2220        mbx->ops.enqueue_tx = fm10k_mbx_enqueue_tx;
2221        mbx->ops.process = fm10k_sm_mbx_process;
2222        mbx->ops.register_handlers = fm10k_mbx_register_handlers;
2223
2224        return FM10K_SUCCESS;
2225}
2226