diff options
author | sjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com> | 2012-02-02 23:36:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-02-04 16:06:28 -0500 |
commit | 332ad43f19848ed653a5e44afa8e2f4a7d34ed44 (patch) | |
tree | 6085d8765b9fd53bd9c3734b540325027ebb2076 /drivers/net/caif | |
parent | 576f3cc7fb94a22df2ced8dcba7d48ff42f8e745 (diff) |
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>
Diffstat (limited to 'drivers/net/caif')
-rw-r--r-- | drivers/net/caif/caif_hsi.c | 145 |
1 files changed, 103 insertions, 42 deletions
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c index 0a4fc62a381d..c8afd62239e9 100644 --- a/drivers/net/caif/caif_hsi.c +++ b/drivers/net/caif/caif_hsi.c | |||
@@ -426,6 +426,35 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi) | |||
426 | return xfer_sz; | 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 | static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) | 458 | static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) |
430 | { | 459 | { |
431 | int rx_sz = 0; | 460 | int rx_sz = 0; |
@@ -517,8 +546,10 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) | |||
517 | static void cfhsi_rx_done(struct cfhsi *cfhsi) | 546 | static void cfhsi_rx_done(struct cfhsi *cfhsi) |
518 | { | 547 | { |
519 | int res; | 548 | int res; |
520 | int desc_pld_len = 0; | 549 | int desc_pld_len = 0, rx_len, rx_state; |
521 | struct cfhsi_desc *desc = NULL; | 550 | struct cfhsi_desc *desc = NULL; |
551 | u8 *rx_ptr, *rx_buf; | ||
552 | struct cfhsi_desc *piggy_desc = NULL; | ||
522 | 553 | ||
523 | desc = (struct cfhsi_desc *)cfhsi->rx_buf; | 554 | desc = (struct cfhsi_desc *)cfhsi->rx_buf; |
524 | 555 | ||
@@ -534,65 +565,71 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi) | |||
534 | spin_unlock_bh(&cfhsi->lock); | 565 | spin_unlock_bh(&cfhsi->lock); |
535 | 566 | ||
536 | if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) { | 567 | if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) { |
537 | desc_pld_len = cfhsi_rx_desc(desc, cfhsi); | 568 | desc_pld_len = cfhsi_rx_desc_len(desc); |
538 | if (desc_pld_len == -ENOMEM) | 569 | |
539 | goto restart; | 570 | if (desc_pld_len < 0) |
540 | if (desc_pld_len == -EPROTO) | ||
541 | goto out_of_sync; | 571 | goto out_of_sync; |
572 | |||
573 | rx_buf = cfhsi->rx_buf; | ||
574 | rx_len = desc_pld_len; | ||
575 | if (desc_pld_len > 0 && (desc->header & CFHSI_PIGGY_DESC)) | ||
576 | rx_len += CFHSI_DESC_SZ; | ||
577 | if (desc_pld_len == 0) | ||
578 | rx_buf = cfhsi->rx_flip_buf; | ||
542 | } else { | 579 | } else { |
543 | int pld_len; | 580 | rx_buf = cfhsi->rx_flip_buf; |
544 | 581 | ||
545 | if (!cfhsi->rx_state.piggy_desc) { | 582 | rx_len = CFHSI_DESC_SZ; |
546 | pld_len = cfhsi_rx_pld(desc, cfhsi); | 583 | if (cfhsi->rx_state.pld_len > 0 && |
547 | if (pld_len == -ENOMEM) | 584 | (desc->header & CFHSI_PIGGY_DESC)) { |
548 | goto restart; | ||
549 | if (pld_len == -EPROTO) | ||
550 | goto out_of_sync; | ||
551 | cfhsi->rx_state.pld_len = pld_len; | ||
552 | } else { | ||
553 | pld_len = cfhsi->rx_state.pld_len; | ||
554 | } | ||
555 | 585 | ||
556 | if ((pld_len > 0) && (desc->header & CFHSI_PIGGY_DESC)) { | ||
557 | struct cfhsi_desc *piggy_desc; | ||
558 | piggy_desc = (struct cfhsi_desc *) | 586 | piggy_desc = (struct cfhsi_desc *) |
559 | (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ + | 587 | (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ + |
560 | pld_len); | 588 | cfhsi->rx_state.pld_len); |
589 | |||
561 | cfhsi->rx_state.piggy_desc = true; | 590 | cfhsi->rx_state.piggy_desc = true; |
562 | 591 | ||
563 | /* Extract piggy-backed descriptor. */ | 592 | /* Extract payload len from piggy-backed descriptor. */ |
564 | desc_pld_len = cfhsi_rx_desc(piggy_desc, cfhsi); | 593 | desc_pld_len = cfhsi_rx_desc_len(piggy_desc); |
565 | if (desc_pld_len == -ENOMEM) | 594 | if (desc_pld_len < 0) |
566 | goto restart; | 595 | goto out_of_sync; |
596 | |||
597 | if (desc_pld_len > 0) | ||
598 | rx_len = desc_pld_len; | ||
599 | |||
600 | if (desc_pld_len > 0 && | ||
601 | (piggy_desc->header & CFHSI_PIGGY_DESC)) | ||
602 | rx_len += CFHSI_DESC_SZ; | ||
567 | 603 | ||
568 | /* | 604 | /* |
569 | * Copy needed information from the piggy-backed | 605 | * Copy needed information from the piggy-backed |
570 | * descriptor to the descriptor in the start. | 606 | * descriptor to the descriptor in the start. |
571 | */ | 607 | */ |
572 | memcpy((u8 *)desc, (u8 *)piggy_desc, | 608 | memcpy(rx_buf, (u8 *)piggy_desc, |
573 | CFHSI_DESC_SHORT_SZ); | 609 | CFHSI_DESC_SHORT_SZ); |
574 | 610 | /* Mark no embedded frame here */ | |
611 | piggy_desc->offset = 0; | ||
575 | if (desc_pld_len == -EPROTO) | 612 | if (desc_pld_len == -EPROTO) |
576 | goto out_of_sync; | 613 | goto out_of_sync; |
577 | } | 614 | } |
578 | } | 615 | } |
579 | 616 | ||
580 | memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state)); | ||
581 | if (desc_pld_len) { | 617 | if (desc_pld_len) { |
582 | cfhsi->rx_state.state = CFHSI_RX_STATE_PAYLOAD; | 618 | rx_state = CFHSI_RX_STATE_PAYLOAD; |
583 | cfhsi->rx_ptr = cfhsi->rx_buf + CFHSI_DESC_SZ; | 619 | rx_ptr = rx_buf + CFHSI_DESC_SZ; |
584 | cfhsi->rx_len = desc_pld_len; | ||
585 | } else { | 620 | } else { |
586 | cfhsi->rx_state.state = CFHSI_RX_STATE_DESC; | 621 | rx_state = CFHSI_RX_STATE_DESC; |
587 | cfhsi->rx_ptr = cfhsi->rx_buf; | 622 | rx_ptr = rx_buf; |
588 | cfhsi->rx_len = CFHSI_DESC_SZ; | 623 | rx_len = CFHSI_DESC_SZ; |
589 | } | 624 | } |
590 | 625 | ||
626 | /* Initiate next read */ | ||
591 | if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) { | 627 | if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) { |
592 | /* Set up new transfer. */ | 628 | /* Set up new transfer. */ |
593 | dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n", | 629 | dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n", |
594 | __func__); | 630 | __func__); |
595 | res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len, | 631 | |
632 | res = cfhsi->dev->cfhsi_rx(rx_ptr, rx_len, | ||
596 | cfhsi->dev); | 633 | cfhsi->dev); |
597 | if (WARN_ON(res < 0)) { | 634 | if (WARN_ON(res < 0)) { |
598 | dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n", | 635 | dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n", |
@@ -601,16 +638,32 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi) | |||
601 | cfhsi->ndev->stats.rx_dropped++; | 638 | cfhsi->ndev->stats.rx_dropped++; |
602 | } | 639 | } |
603 | } | 640 | } |
604 | return; | ||
605 | 641 | ||
606 | restart: | 642 | if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) { |
607 | if (++cfhsi->rx_state.retries > CFHSI_MAX_RX_RETRIES) { | 643 | /* Extract payload from descriptor */ |
608 | dev_err(&cfhsi->ndev->dev, "%s: No memory available " | 644 | if (cfhsi_rx_desc(desc, cfhsi) < 0) |
609 | "in %d iterations.\n", | 645 | goto out_of_sync; |
610 | __func__, CFHSI_MAX_RX_RETRIES); | 646 | } else { |
611 | BUG(); | 647 | /* Extract payload */ |
648 | if (cfhsi_rx_pld(desc, cfhsi) < 0) | ||
649 | goto out_of_sync; | ||
650 | if (piggy_desc) { | ||
651 | /* Extract any payload in piggyback descriptor. */ | ||
652 | if (cfhsi_rx_desc(piggy_desc, cfhsi) < 0) | ||
653 | goto out_of_sync; | ||
654 | } | ||
612 | } | 655 | } |
613 | mod_timer(&cfhsi->rx_slowpath_timer, jiffies + 1); | 656 | |
657 | /* Update state info */ | ||
658 | memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state)); | ||
659 | cfhsi->rx_state.state = rx_state; | ||
660 | cfhsi->rx_ptr = rx_ptr; | ||
661 | cfhsi->rx_len = rx_len; | ||
662 | cfhsi->rx_state.pld_len = desc_pld_len; | ||
663 | cfhsi->rx_state.piggy_desc = desc->header & CFHSI_PIGGY_DESC; | ||
664 | |||
665 | if (rx_buf != cfhsi->rx_buf) | ||
666 | swap(cfhsi->rx_buf, cfhsi->rx_flip_buf); | ||
614 | return; | 667 | return; |
615 | 668 | ||
616 | out_of_sync: | 669 | out_of_sync: |
@@ -1040,6 +1093,12 @@ int cfhsi_probe(struct platform_device *pdev) | |||
1040 | goto err_alloc_rx; | 1093 | goto err_alloc_rx; |
1041 | } | 1094 | } |
1042 | 1095 | ||
1096 | cfhsi->rx_flip_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL); | ||
1097 | if (!cfhsi->rx_flip_buf) { | ||
1098 | res = -ENODEV; | ||
1099 | goto err_alloc_rx_flip; | ||
1100 | } | ||
1101 | |||
1043 | /* Pre-calculate inactivity timeout. */ | 1102 | /* Pre-calculate inactivity timeout. */ |
1044 | if (inactivity_timeout != -1) { | 1103 | if (inactivity_timeout != -1) { |
1045 | cfhsi->inactivity_timeout = | 1104 | cfhsi->inactivity_timeout = |
@@ -1138,6 +1197,8 @@ int cfhsi_probe(struct platform_device *pdev) | |||
1138 | err_activate: | 1197 | err_activate: |
1139 | destroy_workqueue(cfhsi->wq); | 1198 | destroy_workqueue(cfhsi->wq); |
1140 | err_create_wq: | 1199 | err_create_wq: |
1200 | kfree(cfhsi->rx_flip_buf); | ||
1201 | err_alloc_rx_flip: | ||
1141 | kfree(cfhsi->rx_buf); | 1202 | kfree(cfhsi->rx_buf); |
1142 | err_alloc_rx: | 1203 | err_alloc_rx: |
1143 | kfree(cfhsi->tx_buf); | 1204 | kfree(cfhsi->tx_buf); |