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