diff options
author | Varun Prakash <varun@chelsio.com> | 2015-03-24 09:44:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-24 15:24:38 -0400 |
commit | 84a200b390d60fd84293670a089d0c864e35d0b1 (patch) | |
tree | 805c31ca63e49be9d7ac31cf336c0e33283c0e9a | |
parent | 76fed8a989ba673b15979ba35457020c1716e1f2 (diff) |
cxgb4: add cxgb4_fcoe.c for FCoE
This patch adds cxgb4_fcoe.c and enables FCOE_CRC, FCOE_MTU
net device features.
Signed-off-by: Varun Prakash <varun@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c | 122 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/sge.c | 74 |
3 files changed, 201 insertions, 3 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c new file mode 100644 index 000000000000..062d3c0b5818 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * This file is part of the Chelsio T4 Ethernet driver for Linux. | ||
3 | * | ||
4 | * Copyright (c) 2015 Chelsio Communications, Inc. All rights reserved. | ||
5 | * | ||
6 | * This software is available to you under a choice of one of two | ||
7 | * licenses. You may choose to be licensed under the terms of the GNU | ||
8 | * General Public License (GPL) Version 2, available from the file | ||
9 | * COPYING in the main directory of this source tree, or the | ||
10 | * OpenIB.org BSD license below: | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or | ||
13 | * without modification, are permitted provided that the following | ||
14 | * conditions are met: | ||
15 | * | ||
16 | * - Redistributions of source code must retain the above | ||
17 | * copyright notice, this list of conditions and the following | ||
18 | * disclaimer. | ||
19 | * | ||
20 | * - Redistributions in binary form must reproduce the above | ||
21 | * copyright notice, this list of conditions and the following | ||
22 | * disclaimer in the documentation and/or other materials | ||
23 | * provided with the distribution. | ||
24 | * | ||
25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
26 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
27 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
28 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
29 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
30 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
32 | * SOFTWARE. | ||
33 | */ | ||
34 | |||
35 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
36 | |||
37 | #include <scsi/fc/fc_fs.h> | ||
38 | #include <scsi/libfcoe.h> | ||
39 | #include "cxgb4.h" | ||
40 | |||
41 | bool cxgb_fcoe_sof_eof_supported(struct adapter *adap, struct sk_buff *skb) | ||
42 | { | ||
43 | struct fcoe_hdr *fcoeh = (struct fcoe_hdr *)skb_network_header(skb); | ||
44 | u8 sof = fcoeh->fcoe_sof; | ||
45 | u8 eof = 0; | ||
46 | |||
47 | if ((sof != FC_SOF_I3) && (sof != FC_SOF_N3)) { | ||
48 | dev_err(adap->pdev_dev, "Unsupported SOF 0x%x\n", sof); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | skb_copy_bits(skb, skb->len - 4, &eof, 1); | ||
53 | |||
54 | if ((eof != FC_EOF_N) && (eof != FC_EOF_T)) { | ||
55 | dev_err(adap->pdev_dev, "Unsupported EOF 0x%x\n", eof); | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | return 1; | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * cxgb_fcoe_enable - enable FCoE offload features | ||
64 | * @netdev: net device | ||
65 | * | ||
66 | * Returns 0 on success or -EINVAL on failure. | ||
67 | */ | ||
68 | int cxgb_fcoe_enable(struct net_device *netdev) | ||
69 | { | ||
70 | struct port_info *pi = netdev_priv(netdev); | ||
71 | struct adapter *adap = pi->adapter; | ||
72 | struct cxgb_fcoe *fcoe = &pi->fcoe; | ||
73 | |||
74 | if (is_t4(adap->params.chip)) | ||
75 | return -EINVAL; | ||
76 | |||
77 | if (!(adap->flags & FULL_INIT_DONE)) | ||
78 | return -EINVAL; | ||
79 | |||
80 | dev_info(adap->pdev_dev, "Enabling FCoE offload features\n"); | ||
81 | |||
82 | netdev->features |= NETIF_F_FCOE_CRC; | ||
83 | netdev->vlan_features |= NETIF_F_FCOE_CRC; | ||
84 | netdev->features |= NETIF_F_FCOE_MTU; | ||
85 | netdev->vlan_features |= NETIF_F_FCOE_MTU; | ||
86 | |||
87 | netdev_features_change(netdev); | ||
88 | |||
89 | fcoe->flags |= CXGB_FCOE_ENABLED; | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * cxgb_fcoe_disable - disable FCoE offload | ||
96 | * @netdev: net device | ||
97 | * | ||
98 | * Returns 0 on success or -EINVAL on failure. | ||
99 | */ | ||
100 | int cxgb_fcoe_disable(struct net_device *netdev) | ||
101 | { | ||
102 | struct port_info *pi = netdev_priv(netdev); | ||
103 | struct adapter *adap = pi->adapter; | ||
104 | struct cxgb_fcoe *fcoe = &pi->fcoe; | ||
105 | |||
106 | if (!(fcoe->flags & CXGB_FCOE_ENABLED)) | ||
107 | return -EINVAL; | ||
108 | |||
109 | dev_info(adap->pdev_dev, "Disabling FCoE offload features\n"); | ||
110 | |||
111 | fcoe->flags &= ~CXGB_FCOE_ENABLED; | ||
112 | |||
113 | netdev->features &= ~NETIF_F_FCOE_CRC; | ||
114 | netdev->vlan_features &= ~NETIF_F_FCOE_CRC; | ||
115 | netdev->features &= ~NETIF_F_FCOE_MTU; | ||
116 | netdev->vlan_features &= ~NETIF_F_FCOE_MTU; | ||
117 | |||
118 | netdev_features_change(netdev); | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index dd4b2da6e468..e40e283ff36c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
@@ -1271,6 +1271,10 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, | |||
1271 | txq = 0; | 1271 | txq = 0; |
1272 | } else { | 1272 | } else { |
1273 | txq = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; | 1273 | txq = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; |
1274 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
1275 | if (skb->protocol == htons(ETH_P_FCOE)) | ||
1276 | txq = skb->priority & 0x7; | ||
1277 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
1274 | } | 1278 | } |
1275 | return txq; | 1279 | return txq; |
1276 | } | 1280 | } |
@@ -4578,6 +4582,10 @@ static const struct net_device_ops cxgb4_netdev_ops = { | |||
4578 | #ifdef CONFIG_NET_POLL_CONTROLLER | 4582 | #ifdef CONFIG_NET_POLL_CONTROLLER |
4579 | .ndo_poll_controller = cxgb_netpoll, | 4583 | .ndo_poll_controller = cxgb_netpoll, |
4580 | #endif | 4584 | #endif |
4585 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
4586 | .ndo_fcoe_enable = cxgb_fcoe_enable, | ||
4587 | .ndo_fcoe_disable = cxgb_fcoe_disable, | ||
4588 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
4581 | #ifdef CONFIG_NET_RX_BUSY_POLL | 4589 | #ifdef CONFIG_NET_RX_BUSY_POLL |
4582 | .ndo_busy_poll = cxgb_busy_poll, | 4590 | .ndo_busy_poll = cxgb_busy_poll, |
4583 | #endif | 4591 | #endif |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index b4b9f6048fe7..c46e7a938317 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c | |||
@@ -46,6 +46,9 @@ | |||
46 | #ifdef CONFIG_NET_RX_BUSY_POLL | 46 | #ifdef CONFIG_NET_RX_BUSY_POLL |
47 | #include <net/busy_poll.h> | 47 | #include <net/busy_poll.h> |
48 | #endif /* CONFIG_NET_RX_BUSY_POLL */ | 48 | #endif /* CONFIG_NET_RX_BUSY_POLL */ |
49 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
50 | #include <scsi/fc/fc_fcoe.h> | ||
51 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
49 | #include "cxgb4.h" | 52 | #include "cxgb4.h" |
50 | #include "t4_regs.h" | 53 | #include "t4_regs.h" |
51 | #include "t4_values.h" | 54 | #include "t4_values.h" |
@@ -1044,6 +1047,38 @@ static inline void txq_advance(struct sge_txq *q, unsigned int n) | |||
1044 | q->pidx -= q->size; | 1047 | q->pidx -= q->size; |
1045 | } | 1048 | } |
1046 | 1049 | ||
1050 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
1051 | static inline int | ||
1052 | cxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap, | ||
1053 | const struct port_info *pi, u64 *cntrl) | ||
1054 | { | ||
1055 | const struct cxgb_fcoe *fcoe = &pi->fcoe; | ||
1056 | |||
1057 | if (!(fcoe->flags & CXGB_FCOE_ENABLED)) | ||
1058 | return 0; | ||
1059 | |||
1060 | if (skb->protocol != htons(ETH_P_FCOE)) | ||
1061 | return 0; | ||
1062 | |||
1063 | skb_reset_mac_header(skb); | ||
1064 | skb->mac_len = sizeof(struct ethhdr); | ||
1065 | |||
1066 | skb_set_network_header(skb, skb->mac_len); | ||
1067 | skb_set_transport_header(skb, skb->mac_len + sizeof(struct fcoe_hdr)); | ||
1068 | |||
1069 | if (!cxgb_fcoe_sof_eof_supported(adap, skb)) | ||
1070 | return -ENOTSUPP; | ||
1071 | |||
1072 | /* FC CRC offload */ | ||
1073 | *cntrl = TXPKT_CSUM_TYPE(TX_CSUM_FCOE) | | ||
1074 | TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS | | ||
1075 | TXPKT_CSUM_START(CXGB_FCOE_TXPKT_CSUM_START) | | ||
1076 | TXPKT_CSUM_END(CXGB_FCOE_TXPKT_CSUM_END) | | ||
1077 | TXPKT_CSUM_LOC(CXGB_FCOE_TXPKT_CSUM_END); | ||
1078 | return 0; | ||
1079 | } | ||
1080 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
1081 | |||
1047 | /** | 1082 | /** |
1048 | * t4_eth_xmit - add a packet to an Ethernet Tx queue | 1083 | * t4_eth_xmit - add a packet to an Ethernet Tx queue |
1049 | * @skb: the packet | 1084 | * @skb: the packet |
@@ -1066,6 +1101,9 @@ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1066 | const struct skb_shared_info *ssi; | 1101 | const struct skb_shared_info *ssi; |
1067 | dma_addr_t addr[MAX_SKB_FRAGS + 1]; | 1102 | dma_addr_t addr[MAX_SKB_FRAGS + 1]; |
1068 | bool immediate = false; | 1103 | bool immediate = false; |
1104 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
1105 | int err; | ||
1106 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
1069 | 1107 | ||
1070 | /* | 1108 | /* |
1071 | * The chip min packet length is 10 octets but play safe and reject | 1109 | * The chip min packet length is 10 octets but play safe and reject |
@@ -1082,6 +1120,13 @@ out_free: dev_kfree_skb_any(skb); | |||
1082 | q = &adap->sge.ethtxq[qidx + pi->first_qset]; | 1120 | q = &adap->sge.ethtxq[qidx + pi->first_qset]; |
1083 | 1121 | ||
1084 | reclaim_completed_tx(adap, &q->q, true); | 1122 | reclaim_completed_tx(adap, &q->q, true); |
1123 | cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; | ||
1124 | |||
1125 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
1126 | err = cxgb_fcoe_offload(skb, adap, pi, &cntrl); | ||
1127 | if (unlikely(err == -ENOTSUPP)) | ||
1128 | goto out_free; | ||
1129 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
1085 | 1130 | ||
1086 | flits = calc_tx_flits(skb); | 1131 | flits = calc_tx_flits(skb); |
1087 | ndesc = flits_to_desc(flits); | 1132 | ndesc = flits_to_desc(flits); |
@@ -1153,13 +1198,17 @@ out_free: dev_kfree_skb_any(skb); | |||
1153 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 1198 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1154 | cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS; | 1199 | cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS; |
1155 | q->tx_cso++; | 1200 | q->tx_cso++; |
1156 | } else | 1201 | } |
1157 | cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS; | ||
1158 | } | 1202 | } |
1159 | 1203 | ||
1160 | if (skb_vlan_tag_present(skb)) { | 1204 | if (skb_vlan_tag_present(skb)) { |
1161 | q->vlan_ins++; | 1205 | q->vlan_ins++; |
1162 | cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb)); | 1206 | cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb)); |
1207 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
1208 | if (skb->protocol == htons(ETH_P_FCOE)) | ||
1209 | cntrl |= TXPKT_VLAN( | ||
1210 | ((skb->priority & 0x7) << VLAN_PRIO_SHIFT)); | ||
1211 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
1163 | } | 1212 | } |
1164 | 1213 | ||
1165 | cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) | | 1214 | cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) | |
@@ -1759,6 +1808,9 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, | |||
1759 | struct sge *s = &q->adap->sge; | 1808 | struct sge *s = &q->adap->sge; |
1760 | int cpl_trace_pkt = is_t4(q->adap->params.chip) ? | 1809 | int cpl_trace_pkt = is_t4(q->adap->params.chip) ? |
1761 | CPL_TRACE_PKT : CPL_TRACE_PKT_T5; | 1810 | CPL_TRACE_PKT : CPL_TRACE_PKT_T5; |
1811 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
1812 | struct port_info *pi; | ||
1813 | #endif | ||
1762 | 1814 | ||
1763 | if (unlikely(*(u8 *)rsp == cpl_trace_pkt)) | 1815 | if (unlikely(*(u8 *)rsp == cpl_trace_pkt)) |
1764 | return handle_trace_pkt(q->adap, si); | 1816 | return handle_trace_pkt(q->adap, si); |
@@ -1799,8 +1851,24 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp, | |||
1799 | skb->ip_summed = CHECKSUM_COMPLETE; | 1851 | skb->ip_summed = CHECKSUM_COMPLETE; |
1800 | rxq->stats.rx_cso++; | 1852 | rxq->stats.rx_cso++; |
1801 | } | 1853 | } |
1802 | } else | 1854 | } else { |
1803 | skb_checksum_none_assert(skb); | 1855 | skb_checksum_none_assert(skb); |
1856 | #ifdef CONFIG_CHELSIO_T4_FCOE | ||
1857 | #define CPL_RX_PKT_FLAGS (RXF_PSH_F | RXF_SYN_F | RXF_UDP_F | \ | ||
1858 | RXF_TCP_F | RXF_IP_F | RXF_IP6_F | RXF_LRO_F) | ||
1859 | |||
1860 | pi = netdev_priv(skb->dev); | ||
1861 | if (!(pkt->l2info & cpu_to_be32(CPL_RX_PKT_FLAGS))) { | ||
1862 | if ((pkt->l2info & cpu_to_be32(RXF_FCOE_F)) && | ||
1863 | (pi->fcoe.flags & CXGB_FCOE_ENABLED)) { | ||
1864 | if (!(pkt->err_vec & cpu_to_be16(RXERR_CSUM_F))) | ||
1865 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1866 | } | ||
1867 | } | ||
1868 | |||
1869 | #undef CPL_RX_PKT_FLAGS | ||
1870 | #endif /* CONFIG_CHELSIO_T4_FCOE */ | ||
1871 | } | ||
1804 | 1872 | ||
1805 | if (unlikely(pkt->vlan_ex)) { | 1873 | if (unlikely(pkt->vlan_ex)) { |
1806 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan)); | 1874 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan)); |