aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorVasanthy Kolluri <vkolluri@cisco.com>2010-06-24 06:51:59 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-25 23:50:24 -0400
commit1825aca667196f75b193e2d509ea96ffdc8db0ca (patch)
treeae8814b42ad649e983c41cebdf8af1c91d06e7fd /drivers
parentb5bab85c15ed3d1ae7f917a7c077086ac6c04572 (diff)
enic: Feature Add: Add loopback capability to enic devices
Hardware has the loopback capability to queue the packets transmitted from a device to the receive queue of the same device. enic now supports the loopback capability. Signed-off-by: Scott Feldman <scofeldm@cisco.com> Signed-off-by: Vasanthy Kolluri <vkolluri@cisco.com> Signed-off-by: Roopa Prabhu <roprabhu@cisco.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/enic/enic.h2
-rw-r--r--drivers/net/enic/enic_main.c42
-rw-r--r--drivers/net/enic/enic_res.c1
-rw-r--r--drivers/net/enic/enic_res.h25
-rw-r--r--drivers/net/enic/vnic_enet.h2
5 files changed, 45 insertions, 27 deletions
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 3588ef5e7e4c..7280314804a3 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -110,6 +110,8 @@ struct enic {
110 spinlock_t wq_lock[ENIC_WQ_MAX]; 110 spinlock_t wq_lock[ENIC_WQ_MAX];
111 unsigned int wq_count; 111 unsigned int wq_count;
112 struct vlan_group *vlan_group; 112 struct vlan_group *vlan_group;
113 u16 loop_enable;
114 u16 loop_tag;
113 115
114 /* receive queue cache line section */ 116 /* receive queue cache line section */
115 ____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX]; 117 ____cacheline_aligned struct vnic_rq rq[ENIC_RQ_MAX];
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 413e362e3275..eda5530004dc 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -594,7 +594,7 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data)
594 594
595static inline void enic_queue_wq_skb_cont(struct enic *enic, 595static inline void enic_queue_wq_skb_cont(struct enic *enic,
596 struct vnic_wq *wq, struct sk_buff *skb, 596 struct vnic_wq *wq, struct sk_buff *skb,
597 unsigned int len_left) 597 unsigned int len_left, int loopback)
598{ 598{
599 skb_frag_t *frag; 599 skb_frag_t *frag;
600 600
@@ -606,13 +606,14 @@ static inline void enic_queue_wq_skb_cont(struct enic *enic,
606 frag->page_offset, frag->size, 606 frag->page_offset, frag->size,
607 PCI_DMA_TODEVICE), 607 PCI_DMA_TODEVICE),
608 frag->size, 608 frag->size,
609 (len_left == 0)); /* EOP? */ 609 (len_left == 0), /* EOP? */
610 loopback);
610 } 611 }
611} 612}
612 613
613static inline void enic_queue_wq_skb_vlan(struct enic *enic, 614static inline void enic_queue_wq_skb_vlan(struct enic *enic,
614 struct vnic_wq *wq, struct sk_buff *skb, 615 struct vnic_wq *wq, struct sk_buff *skb,
615 int vlan_tag_insert, unsigned int vlan_tag) 616 int vlan_tag_insert, unsigned int vlan_tag, int loopback)
616{ 617{
617 unsigned int head_len = skb_headlen(skb); 618 unsigned int head_len = skb_headlen(skb);
618 unsigned int len_left = skb->len - head_len; 619 unsigned int len_left = skb->len - head_len;
@@ -628,15 +629,15 @@ static inline void enic_queue_wq_skb_vlan(struct enic *enic,
628 head_len, PCI_DMA_TODEVICE), 629 head_len, PCI_DMA_TODEVICE),
629 head_len, 630 head_len,
630 vlan_tag_insert, vlan_tag, 631 vlan_tag_insert, vlan_tag,
631 eop); 632 eop, loopback);
632 633
633 if (!eop) 634 if (!eop)
634 enic_queue_wq_skb_cont(enic, wq, skb, len_left); 635 enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
635} 636}
636 637
637static inline void enic_queue_wq_skb_csum_l4(struct enic *enic, 638static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
638 struct vnic_wq *wq, struct sk_buff *skb, 639 struct vnic_wq *wq, struct sk_buff *skb,
639 int vlan_tag_insert, unsigned int vlan_tag) 640 int vlan_tag_insert, unsigned int vlan_tag, int loopback)
640{ 641{
641 unsigned int head_len = skb_headlen(skb); 642 unsigned int head_len = skb_headlen(skb);
642 unsigned int len_left = skb->len - head_len; 643 unsigned int len_left = skb->len - head_len;
@@ -656,15 +657,15 @@ static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
656 csum_offset, 657 csum_offset,
657 hdr_len, 658 hdr_len,
658 vlan_tag_insert, vlan_tag, 659 vlan_tag_insert, vlan_tag,
659 eop); 660 eop, loopback);
660 661
661 if (!eop) 662 if (!eop)
662 enic_queue_wq_skb_cont(enic, wq, skb, len_left); 663 enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
663} 664}
664 665
665static inline void enic_queue_wq_skb_tso(struct enic *enic, 666static inline void enic_queue_wq_skb_tso(struct enic *enic,
666 struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss, 667 struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss,
667 int vlan_tag_insert, unsigned int vlan_tag) 668 int vlan_tag_insert, unsigned int vlan_tag, int loopback)
668{ 669{
669 unsigned int frag_len_left = skb_headlen(skb); 670 unsigned int frag_len_left = skb_headlen(skb);
670 unsigned int len_left = skb->len - frag_len_left; 671 unsigned int len_left = skb->len - frag_len_left;
@@ -701,7 +702,7 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
701 len, 702 len,
702 mss, hdr_len, 703 mss, hdr_len,
703 vlan_tag_insert, vlan_tag, 704 vlan_tag_insert, vlan_tag,
704 eop && (len == frag_len_left)); 705 eop && (len == frag_len_left), loopback);
705 frag_len_left -= len; 706 frag_len_left -= len;
706 offset += len; 707 offset += len;
707 } 708 }
@@ -727,7 +728,8 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
727 dma_addr, 728 dma_addr,
728 len, 729 len,
729 (len_left == 0) && 730 (len_left == 0) &&
730 (len == frag_len_left)); /* EOP? */ 731 (len == frag_len_left), /* EOP? */
732 loopback);
731 frag_len_left -= len; 733 frag_len_left -= len;
732 offset += len; 734 offset += len;
733 } 735 }
@@ -740,22 +742,26 @@ static inline void enic_queue_wq_skb(struct enic *enic,
740 unsigned int mss = skb_shinfo(skb)->gso_size; 742 unsigned int mss = skb_shinfo(skb)->gso_size;
741 unsigned int vlan_tag = 0; 743 unsigned int vlan_tag = 0;
742 int vlan_tag_insert = 0; 744 int vlan_tag_insert = 0;
745 int loopback = 0;
743 746
744 if (enic->vlan_group && vlan_tx_tag_present(skb)) { 747 if (enic->vlan_group && vlan_tx_tag_present(skb)) {
745 /* VLAN tag from trunking driver */ 748 /* VLAN tag from trunking driver */
746 vlan_tag_insert = 1; 749 vlan_tag_insert = 1;
747 vlan_tag = vlan_tx_tag_get(skb); 750 vlan_tag = vlan_tx_tag_get(skb);
751 } else if (enic->loop_enable) {
752 vlan_tag = enic->loop_tag;
753 loopback = 1;
748 } 754 }
749 755
750 if (mss) 756 if (mss)
751 enic_queue_wq_skb_tso(enic, wq, skb, mss, 757 enic_queue_wq_skb_tso(enic, wq, skb, mss,
752 vlan_tag_insert, vlan_tag); 758 vlan_tag_insert, vlan_tag, loopback);
753 else if (skb->ip_summed == CHECKSUM_PARTIAL) 759 else if (skb->ip_summed == CHECKSUM_PARTIAL)
754 enic_queue_wq_skb_csum_l4(enic, wq, skb, 760 enic_queue_wq_skb_csum_l4(enic, wq, skb,
755 vlan_tag_insert, vlan_tag); 761 vlan_tag_insert, vlan_tag, loopback);
756 else 762 else
757 enic_queue_wq_skb_vlan(enic, wq, skb, 763 enic_queue_wq_skb_vlan(enic, wq, skb,
758 vlan_tag_insert, vlan_tag); 764 vlan_tag_insert, vlan_tag, loopback);
759} 765}
760 766
761/* netif_tx_lock held, process context with BHs disabled, or BH */ 767/* netif_tx_lock held, process context with BHs disabled, or BH */
@@ -1275,7 +1281,7 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
1275 struct enic *enic = vnic_dev_priv(rq->vdev); 1281 struct enic *enic = vnic_dev_priv(rq->vdev);
1276 struct net_device *netdev = enic->netdev; 1282 struct net_device *netdev = enic->netdev;
1277 struct sk_buff *skb; 1283 struct sk_buff *skb;
1278 unsigned int len = netdev->mtu + ETH_HLEN; 1284 unsigned int len = netdev->mtu + VLAN_ETH_HLEN;
1279 unsigned int os_buf_index = 0; 1285 unsigned int os_buf_index = 0;
1280 dma_addr_t dma_addr; 1286 dma_addr_t dma_addr;
1281 1287
@@ -2441,6 +2447,12 @@ static int __devinit enic_probe(struct pci_dev *pdev,
2441 netdev->ethtool_ops = &enic_ethtool_ops; 2447 netdev->ethtool_ops = &enic_ethtool_ops;
2442 2448
2443 netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; 2449 netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
2450 if (ENIC_SETTING(enic, LOOP)) {
2451 netdev->features &= ~NETIF_F_HW_VLAN_TX;
2452 enic->loop_enable = 1;
2453 enic->loop_tag = enic->config.loop_tag;
2454 dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag);
2455 }
2444 if (ENIC_SETTING(enic, TXCSUM)) 2456 if (ENIC_SETTING(enic, TXCSUM))
2445 netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; 2457 netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
2446 if (ENIC_SETTING(enic, TSO)) 2458 if (ENIC_SETTING(enic, TSO))
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index 478928b7cc09..2cc7e278caae 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -70,6 +70,7 @@ int enic_get_vnic_config(struct enic *enic)
70 GET_CONFIG(intr_timer_type); 70 GET_CONFIG(intr_timer_type);
71 GET_CONFIG(intr_mode); 71 GET_CONFIG(intr_mode);
72 GET_CONFIG(intr_timer_usec); 72 GET_CONFIG(intr_timer_usec);
73 GET_CONFIG(loop_tag);
73 74
74 c->wq_desc_count = 75 c->wq_desc_count =
75 min_t(u32, ENIC_MAX_WQ_DESCS, 76 min_t(u32, ENIC_MAX_WQ_DESCS,
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index 3f6e039c2fd2..8b25a07a67d1 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -43,7 +43,7 @@ static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq,
43 void *os_buf, dma_addr_t dma_addr, unsigned int len, 43 void *os_buf, dma_addr_t dma_addr, unsigned int len,
44 unsigned int mss_or_csum_offset, unsigned int hdr_len, 44 unsigned int mss_or_csum_offset, unsigned int hdr_len,
45 int vlan_tag_insert, unsigned int vlan_tag, 45 int vlan_tag_insert, unsigned int vlan_tag,
46 int offload_mode, int cq_entry, int sop, int eop) 46 int offload_mode, int cq_entry, int sop, int eop, int loopback)
47{ 47{
48 struct wq_enet_desc *desc = vnic_wq_next_desc(wq); 48 struct wq_enet_desc *desc = vnic_wq_next_desc(wq);
49 49
@@ -56,61 +56,62 @@ static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq,
56 0, /* fcoe_encap */ 56 0, /* fcoe_encap */
57 (u8)vlan_tag_insert, 57 (u8)vlan_tag_insert,
58 (u16)vlan_tag, 58 (u16)vlan_tag,
59 0 /* loopback */); 59 (u8)loopback);
60 60
61 vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop); 61 vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop);
62} 62}
63 63
64static inline void enic_queue_wq_desc_cont(struct vnic_wq *wq, 64static inline void enic_queue_wq_desc_cont(struct vnic_wq *wq,
65 void *os_buf, dma_addr_t dma_addr, unsigned int len, int eop) 65 void *os_buf, dma_addr_t dma_addr, unsigned int len,
66 int eop, int loopback)
66{ 67{
67 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, 68 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
68 0, 0, 0, 0, 0, 69 0, 0, 0, 0, 0,
69 eop, 0 /* !SOP */, eop); 70 eop, 0 /* !SOP */, eop, loopback);
70} 71}
71 72
72static inline void enic_queue_wq_desc(struct vnic_wq *wq, void *os_buf, 73static inline void enic_queue_wq_desc(struct vnic_wq *wq, void *os_buf,
73 dma_addr_t dma_addr, unsigned int len, int vlan_tag_insert, 74 dma_addr_t dma_addr, unsigned int len, int vlan_tag_insert,
74 unsigned int vlan_tag, int eop) 75 unsigned int vlan_tag, int eop, int loopback)
75{ 76{
76 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, 77 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
77 0, 0, vlan_tag_insert, vlan_tag, 78 0, 0, vlan_tag_insert, vlan_tag,
78 WQ_ENET_OFFLOAD_MODE_CSUM, 79 WQ_ENET_OFFLOAD_MODE_CSUM,
79 eop, 1 /* SOP */, eop); 80 eop, 1 /* SOP */, eop, loopback);
80} 81}
81 82
82static inline void enic_queue_wq_desc_csum(struct vnic_wq *wq, 83static inline void enic_queue_wq_desc_csum(struct vnic_wq *wq,
83 void *os_buf, dma_addr_t dma_addr, unsigned int len, 84 void *os_buf, dma_addr_t dma_addr, unsigned int len,
84 int ip_csum, int tcpudp_csum, int vlan_tag_insert, 85 int ip_csum, int tcpudp_csum, int vlan_tag_insert,
85 unsigned int vlan_tag, int eop) 86 unsigned int vlan_tag, int eop, int loopback)
86{ 87{
87 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, 88 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
88 (ip_csum ? 1 : 0) + (tcpudp_csum ? 2 : 0), 89 (ip_csum ? 1 : 0) + (tcpudp_csum ? 2 : 0),
89 0, vlan_tag_insert, vlan_tag, 90 0, vlan_tag_insert, vlan_tag,
90 WQ_ENET_OFFLOAD_MODE_CSUM, 91 WQ_ENET_OFFLOAD_MODE_CSUM,
91 eop, 1 /* SOP */, eop); 92 eop, 1 /* SOP */, eop, loopback);
92} 93}
93 94
94static inline void enic_queue_wq_desc_csum_l4(struct vnic_wq *wq, 95static inline void enic_queue_wq_desc_csum_l4(struct vnic_wq *wq,
95 void *os_buf, dma_addr_t dma_addr, unsigned int len, 96 void *os_buf, dma_addr_t dma_addr, unsigned int len,
96 unsigned int csum_offset, unsigned int hdr_len, 97 unsigned int csum_offset, unsigned int hdr_len,
97 int vlan_tag_insert, unsigned int vlan_tag, int eop) 98 int vlan_tag_insert, unsigned int vlan_tag, int eop, int loopback)
98{ 99{
99 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, 100 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
100 csum_offset, hdr_len, vlan_tag_insert, vlan_tag, 101 csum_offset, hdr_len, vlan_tag_insert, vlan_tag,
101 WQ_ENET_OFFLOAD_MODE_CSUM_L4, 102 WQ_ENET_OFFLOAD_MODE_CSUM_L4,
102 eop, 1 /* SOP */, eop); 103 eop, 1 /* SOP */, eop, loopback);
103} 104}
104 105
105static inline void enic_queue_wq_desc_tso(struct vnic_wq *wq, 106static inline void enic_queue_wq_desc_tso(struct vnic_wq *wq,
106 void *os_buf, dma_addr_t dma_addr, unsigned int len, 107 void *os_buf, dma_addr_t dma_addr, unsigned int len,
107 unsigned int mss, unsigned int hdr_len, int vlan_tag_insert, 108 unsigned int mss, unsigned int hdr_len, int vlan_tag_insert,
108 unsigned int vlan_tag, int eop) 109 unsigned int vlan_tag, int eop, int loopback)
109{ 110{
110 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len, 111 enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
111 mss, hdr_len, vlan_tag_insert, vlan_tag, 112 mss, hdr_len, vlan_tag_insert, vlan_tag,
112 WQ_ENET_OFFLOAD_MODE_TSO, 113 WQ_ENET_OFFLOAD_MODE_TSO,
113 eop, 1 /* SOP */, eop); 114 eop, 1 /* SOP */, eop, loopback);
114} 115}
115 116
116static inline void enic_queue_rq_desc(struct vnic_rq *rq, 117static inline void enic_queue_rq_desc(struct vnic_rq *rq,
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
index 8eeb6758491b..42baaa13ce59 100644
--- a/drivers/net/enic/vnic_enet.h
+++ b/drivers/net/enic/vnic_enet.h
@@ -35,6 +35,7 @@ struct vnic_enet_config {
35 u8 intr_mode; 35 u8 intr_mode;
36 char devname[16]; 36 char devname[16];
37 u32 intr_timer_usec; 37 u32 intr_timer_usec;
38 u16 loop_tag;
38}; 39};
39 40
40#define VENETF_TSO 0x1 /* TSO enabled */ 41#define VENETF_TSO 0x1 /* TSO enabled */
@@ -48,5 +49,6 @@ struct vnic_enet_config {
48#define VENETF_RSSHASH_TCPIPV6 0x100 /* Hash on TCP + IPv6 fields */ 49#define VENETF_RSSHASH_TCPIPV6 0x100 /* Hash on TCP + IPv6 fields */
49#define VENETF_RSSHASH_IPV6_EX 0x200 /* Hash on IPv6 extended fields */ 50#define VENETF_RSSHASH_IPV6_EX 0x200 /* Hash on IPv6 extended fields */
50#define VENETF_RSSHASH_TCPIPV6_EX 0x400 /* Hash on TCP + IPv6 ext. fields */ 51#define VENETF_RSSHASH_TCPIPV6_EX 0x400 /* Hash on TCP + IPv6 ext. fields */
52#define VENETF_LOOP 0x800 /* Loopback enabled */
51 53
52#endif /* _VNIC_ENIC_H_ */ 54#endif /* _VNIC_ENIC_H_ */