Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

caif-hsi: Add RX flip buffer

Implement RX flip buffer in the cfhsi_rx_done function,
piggy-backed frames is also supported.
This gives a significant performance gain for CAIF over HSI.

Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

sjur.brandeland@stericsson.com and committed by
David S. Miller
332ad43f 576f3cc7

+104 -42
+103 -42
drivers/net/caif/caif_hsi.c
··· 426 426 return xfer_sz; 427 427 } 428 428 429 + static int cfhsi_rx_desc_len(struct cfhsi_desc *desc) 430 + { 431 + int xfer_sz = 0; 432 + int nfrms = 0; 433 + u16 *plen; 434 + 435 + if ((desc->header & ~CFHSI_PIGGY_DESC) || 436 + (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) { 437 + 438 + pr_err("Invalid descriptor. %x %x\n", desc->header, 439 + desc->offset); 440 + return -EPROTO; 441 + } 442 + 443 + /* Calculate transfer length. */ 444 + plen = desc->cffrm_len; 445 + while (nfrms < CFHSI_MAX_PKTS && *plen) { 446 + xfer_sz += *plen; 447 + plen++; 448 + nfrms++; 449 + } 450 + 451 + if (xfer_sz % 4) { 452 + pr_err("Invalid payload len: %d, ignored.\n", xfer_sz); 453 + return -EPROTO; 454 + } 455 + return xfer_sz; 456 + } 457 + 429 458 static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) 430 459 { 431 460 int rx_sz = 0; ··· 546 517 static void cfhsi_rx_done(struct cfhsi *cfhsi) 547 518 { 548 519 int res; 549 - int desc_pld_len = 0; 520 + int desc_pld_len = 0, rx_len, rx_state; 550 521 struct cfhsi_desc *desc = NULL; 522 + u8 *rx_ptr, *rx_buf; 523 + struct cfhsi_desc *piggy_desc = NULL; 551 524 552 525 desc = (struct cfhsi_desc *)cfhsi->rx_buf; 553 526 ··· 565 534 spin_unlock_bh(&cfhsi->lock); 566 535 567 536 if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) { 568 - desc_pld_len = cfhsi_rx_desc(desc, cfhsi); 569 - if (desc_pld_len == -ENOMEM) 570 - goto restart; 571 - if (desc_pld_len == -EPROTO) 537 + desc_pld_len = cfhsi_rx_desc_len(desc); 538 + 539 + if (desc_pld_len < 0) 572 540 goto out_of_sync; 541 + 542 + rx_buf = cfhsi->rx_buf; 543 + rx_len = desc_pld_len; 544 + if (desc_pld_len > 0 && (desc->header & CFHSI_PIGGY_DESC)) 545 + rx_len += CFHSI_DESC_SZ; 546 + if (desc_pld_len == 0) 547 + rx_buf = cfhsi->rx_flip_buf; 573 548 } else { 574 - int pld_len; 549 + rx_buf = cfhsi->rx_flip_buf; 575 550 576 - if (!cfhsi->rx_state.piggy_desc) { 577 - pld_len = cfhsi_rx_pld(desc, cfhsi); 578 - if (pld_len == -ENOMEM) 579 - goto restart; 580 - if (pld_len == -EPROTO) 581 - goto out_of_sync; 582 - cfhsi->rx_state.pld_len = pld_len; 583 - } else { 584 - pld_len = cfhsi->rx_state.pld_len; 585 - } 551 + rx_len = CFHSI_DESC_SZ; 552 + if (cfhsi->rx_state.pld_len > 0 && 553 + (desc->header & CFHSI_PIGGY_DESC)) { 586 554 587 - if ((pld_len > 0) && (desc->header & CFHSI_PIGGY_DESC)) { 588 - struct cfhsi_desc *piggy_desc; 589 555 piggy_desc = (struct cfhsi_desc *) 590 556 (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ + 591 - pld_len); 557 + cfhsi->rx_state.pld_len); 558 + 592 559 cfhsi->rx_state.piggy_desc = true; 593 560 594 - /* Extract piggy-backed descriptor. */ 595 - desc_pld_len = cfhsi_rx_desc(piggy_desc, cfhsi); 596 - if (desc_pld_len == -ENOMEM) 597 - goto restart; 561 + /* Extract payload len from piggy-backed descriptor. */ 562 + desc_pld_len = cfhsi_rx_desc_len(piggy_desc); 563 + if (desc_pld_len < 0) 564 + goto out_of_sync; 565 + 566 + if (desc_pld_len > 0) 567 + rx_len = desc_pld_len; 568 + 569 + if (desc_pld_len > 0 && 570 + (piggy_desc->header & CFHSI_PIGGY_DESC)) 571 + rx_len += CFHSI_DESC_SZ; 598 572 599 573 /* 600 574 * Copy needed information from the piggy-backed 601 575 * descriptor to the descriptor in the start. 602 576 */ 603 - memcpy((u8 *)desc, (u8 *)piggy_desc, 577 + memcpy(rx_buf, (u8 *)piggy_desc, 604 578 CFHSI_DESC_SHORT_SZ); 605 - 579 + /* Mark no embedded frame here */ 580 + piggy_desc->offset = 0; 606 581 if (desc_pld_len == -EPROTO) 607 582 goto out_of_sync; 608 583 } 609 584 } 610 585 611 - memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state)); 612 586 if (desc_pld_len) { 613 - cfhsi->rx_state.state = CFHSI_RX_STATE_PAYLOAD; 614 - cfhsi->rx_ptr = cfhsi->rx_buf + CFHSI_DESC_SZ; 615 - cfhsi->rx_len = desc_pld_len; 587 + rx_state = CFHSI_RX_STATE_PAYLOAD; 588 + rx_ptr = rx_buf + CFHSI_DESC_SZ; 616 589 } else { 617 - cfhsi->rx_state.state = CFHSI_RX_STATE_DESC; 618 - cfhsi->rx_ptr = cfhsi->rx_buf; 619 - cfhsi->rx_len = CFHSI_DESC_SZ; 590 + rx_state = CFHSI_RX_STATE_DESC; 591 + rx_ptr = rx_buf; 592 + rx_len = CFHSI_DESC_SZ; 620 593 } 621 594 595 + /* Initiate next read */ 622 596 if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) { 623 597 /* Set up new transfer. */ 624 598 dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n", 625 - __func__); 626 - res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len, 599 + __func__); 600 + 601 + res = cfhsi->dev->cfhsi_rx(rx_ptr, rx_len, 627 602 cfhsi->dev); 628 603 if (WARN_ON(res < 0)) { 629 604 dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n", ··· 638 601 cfhsi->ndev->stats.rx_dropped++; 639 602 } 640 603 } 641 - return; 642 604 643 - restart: 644 - if (++cfhsi->rx_state.retries > CFHSI_MAX_RX_RETRIES) { 645 - dev_err(&cfhsi->ndev->dev, "%s: No memory available " 646 - "in %d iterations.\n", 647 - __func__, CFHSI_MAX_RX_RETRIES); 648 - BUG(); 605 + if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) { 606 + /* Extract payload from descriptor */ 607 + if (cfhsi_rx_desc(desc, cfhsi) < 0) 608 + goto out_of_sync; 609 + } else { 610 + /* Extract payload */ 611 + if (cfhsi_rx_pld(desc, cfhsi) < 0) 612 + goto out_of_sync; 613 + if (piggy_desc) { 614 + /* Extract any payload in piggyback descriptor. */ 615 + if (cfhsi_rx_desc(piggy_desc, cfhsi) < 0) 616 + goto out_of_sync; 617 + } 649 618 } 650 - mod_timer(&cfhsi->rx_slowpath_timer, jiffies + 1); 619 + 620 + /* Update state info */ 621 + memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state)); 622 + cfhsi->rx_state.state = rx_state; 623 + cfhsi->rx_ptr = rx_ptr; 624 + cfhsi->rx_len = rx_len; 625 + cfhsi->rx_state.pld_len = desc_pld_len; 626 + cfhsi->rx_state.piggy_desc = desc->header & CFHSI_PIGGY_DESC; 627 + 628 + if (rx_buf != cfhsi->rx_buf) 629 + swap(cfhsi->rx_buf, cfhsi->rx_flip_buf); 651 630 return; 652 631 653 632 out_of_sync: ··· 1093 1040 goto err_alloc_rx; 1094 1041 } 1095 1042 1043 + cfhsi->rx_flip_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL); 1044 + if (!cfhsi->rx_flip_buf) { 1045 + res = -ENODEV; 1046 + goto err_alloc_rx_flip; 1047 + } 1048 + 1096 1049 /* Pre-calculate inactivity timeout. */ 1097 1050 if (inactivity_timeout != -1) { 1098 1051 cfhsi->inactivity_timeout = ··· 1197 1138 err_activate: 1198 1139 destroy_workqueue(cfhsi->wq); 1199 1140 err_create_wq: 1141 + kfree(cfhsi->rx_flip_buf); 1142 + err_alloc_rx_flip: 1200 1143 kfree(cfhsi->rx_buf); 1201 1144 err_alloc_rx: 1202 1145 kfree(cfhsi->tx_buf);
+1
include/net/caif/caif_hsi.h
··· 138 138 u8 *rx_ptr; 139 139 u8 *tx_buf; 140 140 u8 *rx_buf; 141 + u8 *rx_flip_buf; 141 142 spinlock_t lock; 142 143 int flow_off_sent; 143 144 u32 q_low_mark;