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