diff options
Diffstat (limited to 'drivers/net/cxgb3/cxgb3_offload.c')
-rw-r--r-- | drivers/net/cxgb3/cxgb3_offload.c | 87 |
1 files changed, 56 insertions, 31 deletions
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index f6ed033efb5..199e5066acf 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c | |||
@@ -508,6 +508,7 @@ void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid) | |||
508 | 508 | ||
509 | spin_lock_bh(&td->tid_release_lock); | 509 | spin_lock_bh(&td->tid_release_lock); |
510 | p->ctx = (void *)td->tid_release_list; | 510 | p->ctx = (void *)td->tid_release_list; |
511 | p->client = NULL; | ||
511 | td->tid_release_list = p; | 512 | td->tid_release_list = p; |
512 | if (!p->ctx) | 513 | if (!p->ctx) |
513 | schedule_work(&td->tid_release_task); | 514 | schedule_work(&td->tid_release_task); |
@@ -553,7 +554,9 @@ int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client, | |||
553 | struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; | 554 | struct tid_info *t = &(T3C_DATA(tdev))->tid_maps; |
554 | 555 | ||
555 | spin_lock_bh(&t->atid_lock); | 556 | spin_lock_bh(&t->atid_lock); |
556 | if (t->afree) { | 557 | if (t->afree && |
558 | t->atids_in_use + atomic_read(&t->tids_in_use) + MC5_MIN_TIDS <= | ||
559 | t->ntids) { | ||
557 | union active_open_entry *p = t->afree; | 560 | union active_open_entry *p = t->afree; |
558 | 561 | ||
559 | atid = (p - t->atid_tab) + t->atid_base; | 562 | atid = (p - t->atid_tab) + t->atid_base; |
@@ -621,7 +624,8 @@ static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb) | |||
621 | struct t3c_tid_entry *t3c_tid; | 624 | struct t3c_tid_entry *t3c_tid; |
622 | 625 | ||
623 | t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); | 626 | t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); |
624 | if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers && | 627 | if (t3c_tid && t3c_tid->ctx && t3c_tid->client && |
628 | t3c_tid->client->handlers && | ||
625 | t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) { | 629 | t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) { |
626 | return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb, | 630 | return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb, |
627 | t3c_tid-> | 631 | t3c_tid-> |
@@ -640,7 +644,7 @@ static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb) | |||
640 | struct t3c_tid_entry *t3c_tid; | 644 | struct t3c_tid_entry *t3c_tid; |
641 | 645 | ||
642 | t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); | 646 | t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid); |
643 | if (t3c_tid->ctx && t3c_tid->client->handlers && | 647 | if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && |
644 | t3c_tid->client->handlers[p->opcode]) { | 648 | t3c_tid->client->handlers[p->opcode]) { |
645 | return t3c_tid->client->handlers[p->opcode] (dev, skb, | 649 | return t3c_tid->client->handlers[p->opcode] (dev, skb, |
646 | t3c_tid->ctx); | 650 | t3c_tid->ctx); |
@@ -658,7 +662,7 @@ static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb) | |||
658 | struct t3c_tid_entry *t3c_tid; | 662 | struct t3c_tid_entry *t3c_tid; |
659 | 663 | ||
660 | t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); | 664 | t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); |
661 | if (t3c_tid->ctx && t3c_tid->client->handlers && | 665 | if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && |
662 | t3c_tid->client->handlers[p->opcode]) { | 666 | t3c_tid->client->handlers[p->opcode]) { |
663 | return t3c_tid->client->handlers[p->opcode] | 667 | return t3c_tid->client->handlers[p->opcode] |
664 | (dev, skb, t3c_tid->ctx); | 668 | (dev, skb, t3c_tid->ctx); |
@@ -687,6 +691,28 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb) | |||
687 | } | 691 | } |
688 | } | 692 | } |
689 | 693 | ||
694 | /* | ||
695 | * Returns an sk_buff for a reply CPL message of size len. If the input | ||
696 | * sk_buff has no other users it is trimmed and reused, otherwise a new buffer | ||
697 | * is allocated. The input skb must be of size at least len. Note that this | ||
698 | * operation does not destroy the original skb data even if it decides to reuse | ||
699 | * the buffer. | ||
700 | */ | ||
701 | static struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len, | ||
702 | int gfp) | ||
703 | { | ||
704 | if (likely(!skb_cloned(skb))) { | ||
705 | BUG_ON(skb->len < len); | ||
706 | __skb_trim(skb, len); | ||
707 | skb_get(skb); | ||
708 | } else { | ||
709 | skb = alloc_skb(len, gfp); | ||
710 | if (skb) | ||
711 | __skb_put(skb, len); | ||
712 | } | ||
713 | return skb; | ||
714 | } | ||
715 | |||
690 | static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb) | 716 | static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb) |
691 | { | 717 | { |
692 | union opcode_tid *p = cplhdr(skb); | 718 | union opcode_tid *p = cplhdr(skb); |
@@ -694,30 +720,39 @@ static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb) | |||
694 | struct t3c_tid_entry *t3c_tid; | 720 | struct t3c_tid_entry *t3c_tid; |
695 | 721 | ||
696 | t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); | 722 | t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); |
697 | if (t3c_tid->ctx && t3c_tid->client->handlers && | 723 | if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && |
698 | t3c_tid->client->handlers[p->opcode]) { | 724 | t3c_tid->client->handlers[p->opcode]) { |
699 | return t3c_tid->client->handlers[p->opcode] | 725 | return t3c_tid->client->handlers[p->opcode] |
700 | (dev, skb, t3c_tid->ctx); | 726 | (dev, skb, t3c_tid->ctx); |
701 | } else { | 727 | } else { |
702 | struct cpl_abort_req_rss *req = cplhdr(skb); | 728 | struct cpl_abort_req_rss *req = cplhdr(skb); |
703 | struct cpl_abort_rpl *rpl; | 729 | struct cpl_abort_rpl *rpl; |
730 | struct sk_buff *reply_skb; | ||
731 | unsigned int tid = GET_TID(req); | ||
732 | u8 cmd = req->status; | ||
733 | |||
734 | if (req->status == CPL_ERR_RTX_NEG_ADVICE || | ||
735 | req->status == CPL_ERR_PERSIST_NEG_ADVICE) | ||
736 | goto out; | ||
704 | 737 | ||
705 | struct sk_buff *skb = | 738 | reply_skb = cxgb3_get_cpl_reply_skb(skb, |
706 | alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC); | 739 | sizeof(struct |
707 | if (!skb) { | 740 | cpl_abort_rpl), |
741 | GFP_ATOMIC); | ||
742 | |||
743 | if (!reply_skb) { | ||
708 | printk("do_abort_req_rss: couldn't get skb!\n"); | 744 | printk("do_abort_req_rss: couldn't get skb!\n"); |
709 | goto out; | 745 | goto out; |
710 | } | 746 | } |
711 | skb->priority = CPL_PRIORITY_DATA; | 747 | reply_skb->priority = CPL_PRIORITY_DATA; |
712 | __skb_put(skb, sizeof(struct cpl_abort_rpl)); | 748 | __skb_put(reply_skb, sizeof(struct cpl_abort_rpl)); |
713 | rpl = cplhdr(skb); | 749 | rpl = cplhdr(reply_skb); |
714 | rpl->wr.wr_hi = | 750 | rpl->wr.wr_hi = |
715 | htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); | 751 | htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); |
716 | rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req))); | 752 | rpl->wr.wr_lo = htonl(V_WR_TID(tid)); |
717 | OPCODE_TID(rpl) = | 753 | OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid)); |
718 | htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req))); | 754 | rpl->cmd = cmd; |
719 | rpl->cmd = req->status; | 755 | cxgb3_ofld_send(dev, reply_skb); |
720 | cxgb3_ofld_send(dev, skb); | ||
721 | out: | 756 | out: |
722 | return CPL_RET_BUF_DONE; | 757 | return CPL_RET_BUF_DONE; |
723 | } | 758 | } |
@@ -730,7 +765,7 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) | |||
730 | struct t3c_tid_entry *t3c_tid; | 765 | struct t3c_tid_entry *t3c_tid; |
731 | 766 | ||
732 | t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); | 767 | t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid); |
733 | if (t3c_tid->ctx && t3c_tid->client->handlers && | 768 | if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && |
734 | t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { | 769 | t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) { |
735 | return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] | 770 | return t3c_tid->client->handlers[CPL_ACT_ESTABLISH] |
736 | (dev, skb, t3c_tid->ctx); | 771 | (dev, skb, t3c_tid->ctx); |
@@ -741,17 +776,6 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb) | |||
741 | } | 776 | } |
742 | } | 777 | } |
743 | 778 | ||
744 | static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb) | ||
745 | { | ||
746 | struct cpl_set_tcb_rpl *rpl = cplhdr(skb); | ||
747 | |||
748 | if (rpl->status != CPL_ERR_NONE) | ||
749 | printk(KERN_ERR | ||
750 | "Unexpected SET_TCB_RPL status %u for tid %u\n", | ||
751 | rpl->status, GET_TID(rpl)); | ||
752 | return CPL_RET_BUF_DONE; | ||
753 | } | ||
754 | |||
755 | static int do_trace(struct t3cdev *dev, struct sk_buff *skb) | 779 | static int do_trace(struct t3cdev *dev, struct sk_buff *skb) |
756 | { | 780 | { |
757 | struct cpl_trace_pkt *p = cplhdr(skb); | 781 | struct cpl_trace_pkt *p = cplhdr(skb); |
@@ -771,7 +795,7 @@ static int do_term(struct t3cdev *dev, struct sk_buff *skb) | |||
771 | struct t3c_tid_entry *t3c_tid; | 795 | struct t3c_tid_entry *t3c_tid; |
772 | 796 | ||
773 | t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); | 797 | t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid); |
774 | if (t3c_tid->ctx && t3c_tid->client->handlers && | 798 | if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers && |
775 | t3c_tid->client->handlers[opcode]) { | 799 | t3c_tid->client->handlers[opcode]) { |
776 | return t3c_tid->client->handlers[opcode] (dev, skb, | 800 | return t3c_tid->client->handlers[opcode] (dev, skb, |
777 | t3c_tid->ctx); | 801 | t3c_tid->ctx); |
@@ -970,7 +994,7 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) | |||
970 | for (tid = 0; tid < ti->ntids; tid++) { | 994 | for (tid = 0; tid < ti->ntids; tid++) { |
971 | te = lookup_tid(ti, tid); | 995 | te = lookup_tid(ti, tid); |
972 | BUG_ON(!te); | 996 | BUG_ON(!te); |
973 | if (te->ctx && te->client && te->client->redirect) { | 997 | if (te && te->ctx && te->client && te->client->redirect) { |
974 | update_tcb = te->client->redirect(te->ctx, old, new, e); | 998 | update_tcb = te->client->redirect(te->ctx, old, new, e); |
975 | if (update_tcb) { | 999 | if (update_tcb) { |
976 | l2t_hold(L2DATA(tdev), e); | 1000 | l2t_hold(L2DATA(tdev), e); |
@@ -1213,7 +1237,8 @@ void __init cxgb3_offload_init(void) | |||
1213 | t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl); | 1237 | t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl); |
1214 | t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss); | 1238 | t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss); |
1215 | t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish); | 1239 | t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish); |
1216 | t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl); | 1240 | t3_register_cpl_handler(CPL_SET_TCB_RPL, do_hwtid_rpl); |
1241 | t3_register_cpl_handler(CPL_GET_TCB_RPL, do_hwtid_rpl); | ||
1217 | t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term); | 1242 | t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term); |
1218 | t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl); | 1243 | t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl); |
1219 | t3_register_cpl_handler(CPL_TRACE_PKT, do_trace); | 1244 | t3_register_cpl_handler(CPL_TRACE_PKT, do_trace); |