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