aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsjur.brandeland@stericsson.com <sjur.brandeland@stericsson.com>2012-02-02 23:36:21 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-04 16:06:28 -0500
commit332ad43f19848ed653a5e44afa8e2f4a7d34ed44 (patch)
tree6085d8765b9fd53bd9c3734b540325027ebb2076
parent576f3cc7fb94a22df2ced8dcba7d48ff42f8e745 (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>
-rw-r--r--drivers/net/caif/caif_hsi.c145
-rw-r--r--include/net/caif/caif_hsi.h1
2 files changed, 104 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
429static 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
429static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) 458static 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)
517static void cfhsi_rx_done(struct cfhsi *cfhsi) 546static 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
606restart: 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
616out_of_sync: 669out_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);
diff --git a/include/net/caif/caif_hsi.h b/include/net/caif/caif_hsi.h
index 8d552519ff67..6db8ecf52aa2 100644
--- a/include/net/caif/caif_hsi.h
+++ b/include/net/caif/caif_hsi.h
@@ -138,6 +138,7 @@ struct cfhsi {
138 u8 *rx_ptr; 138 u8 *rx_ptr;
139 u8 *tx_buf; 139 u8 *tx_buf;
140 u8 *rx_buf; 140 u8 *rx_buf;
141 u8 *rx_flip_buf;
141 spinlock_t lock; 142 spinlock_t lock;
142 int flow_off_sent; 143 int flow_off_sent;
143 u32 q_low_mark; 144 u32 q_low_mark;