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