diff options
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 1568 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_fcoe.h | 128 |
2 files changed, 1696 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c new file mode 100644 index 000000000000..8574eeefefc7 --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c | |||
@@ -0,0 +1,1568 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * Intel Ethernet Controller XL710 Family Linux Driver | ||
4 | * Copyright(c) 2013 - 2014 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
23 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | * | ||
25 | ******************************************************************************/ | ||
26 | |||
27 | |||
28 | #include <linux/if_ether.h> | ||
29 | #include <scsi/scsi_cmnd.h> | ||
30 | #include <scsi/scsi_device.h> | ||
31 | #include <scsi/fc/fc_fs.h> | ||
32 | #include <scsi/fc/fc_fip.h> | ||
33 | #include <scsi/fc/fc_fcoe.h> | ||
34 | #include <scsi/libfc.h> | ||
35 | #include <scsi/libfcoe.h> | ||
36 | |||
37 | #include "i40e.h" | ||
38 | #include "i40e_fcoe.h" | ||
39 | |||
40 | /** | ||
41 | * i40e_rx_is_fip - returns true if the rx packet type is FIP | ||
42 | * @ptype: the packet type field from rx descriptor write-back | ||
43 | **/ | ||
44 | static inline bool i40e_rx_is_fip(u16 ptype) | ||
45 | { | ||
46 | return ptype == I40E_RX_PTYPE_L2_FIP_PAY2; | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * i40e_rx_is_fcoe - returns true if the rx packet type is FCoE | ||
51 | * @ptype: the packet type field from rx descriptor write-back | ||
52 | **/ | ||
53 | static inline bool i40e_rx_is_fcoe(u16 ptype) | ||
54 | { | ||
55 | return (ptype >= I40E_RX_PTYPE_L2_FCOE_PAY3) && | ||
56 | (ptype <= I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER); | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * i40e_fcoe_sof_is_class2 - returns true if this is a FC Class 2 SOF | ||
61 | * @sof: the FCoE start of frame delimiter | ||
62 | **/ | ||
63 | static inline bool i40e_fcoe_sof_is_class2(u8 sof) | ||
64 | { | ||
65 | return (sof == FC_SOF_I2) || (sof == FC_SOF_N2); | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * i40e_fcoe_sof_is_class3 - returns true if this is a FC Class 3 SOF | ||
70 | * @sof: the FCoE start of frame delimiter | ||
71 | **/ | ||
72 | static inline bool i40e_fcoe_sof_is_class3(u8 sof) | ||
73 | { | ||
74 | return (sof == FC_SOF_I3) || (sof == FC_SOF_N3); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * i40e_fcoe_sof_is_supported - returns true if the FC SOF is supported by HW | ||
79 | * @sof: the input SOF value from the frame | ||
80 | **/ | ||
81 | static inline bool i40e_fcoe_sof_is_supported(u8 sof) | ||
82 | { | ||
83 | return i40e_fcoe_sof_is_class2(sof) || | ||
84 | i40e_fcoe_sof_is_class3(sof); | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * i40e_fcoe_fc_sof - pull the SOF from FCoE header in the frame | ||
89 | * @skb: the frame whose EOF is to be pulled from | ||
90 | **/ | ||
91 | static inline int i40e_fcoe_fc_sof(struct sk_buff *skb, u8 *sof) | ||
92 | { | ||
93 | *sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof; | ||
94 | |||
95 | if (!i40e_fcoe_sof_is_supported(*sof)) | ||
96 | return -EINVAL; | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * i40e_fcoe_eof_is_supported - returns true if the EOF is supported by HW | ||
102 | * @eof: the input EOF value from the frame | ||
103 | **/ | ||
104 | static inline bool i40e_fcoe_eof_is_supported(u8 eof) | ||
105 | { | ||
106 | return (eof == FC_EOF_N) || (eof == FC_EOF_T) || | ||
107 | (eof == FC_EOF_NI) || (eof == FC_EOF_A); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * i40e_fcoe_fc_eof - pull EOF from FCoE trailer in the frame | ||
112 | * @skb: the frame whose EOF is to be pulled from | ||
113 | **/ | ||
114 | static inline int i40e_fcoe_fc_eof(struct sk_buff *skb, u8 *eof) | ||
115 | { | ||
116 | /* the first byte of the last dword is EOF */ | ||
117 | skb_copy_bits(skb, skb->len - 4, eof, 1); | ||
118 | |||
119 | if (!i40e_fcoe_eof_is_supported(*eof)) | ||
120 | return -EINVAL; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * i40e_fcoe_ctxt_eof - convert input FC EOF for descriptor programming | ||
126 | * @eof: the input eof value from the frame | ||
127 | * | ||
128 | * The FC EOF is converted to the value understood by HW for descriptor | ||
129 | * programming. Never call this w/o calling i40e_fcoe_eof_is_supported() | ||
130 | * first. | ||
131 | **/ | ||
132 | static inline u32 i40e_fcoe_ctxt_eof(u8 eof) | ||
133 | { | ||
134 | switch (eof) { | ||
135 | case FC_EOF_N: | ||
136 | return I40E_TX_DESC_CMD_L4T_EOFT_EOF_N; | ||
137 | case FC_EOF_T: | ||
138 | return I40E_TX_DESC_CMD_L4T_EOFT_EOF_T; | ||
139 | case FC_EOF_NI: | ||
140 | return I40E_TX_DESC_CMD_L4T_EOFT_EOF_NI; | ||
141 | case FC_EOF_A: | ||
142 | return I40E_TX_DESC_CMD_L4T_EOFT_EOF_A; | ||
143 | default: | ||
144 | /* FIXME: still returns 0 */ | ||
145 | pr_err("Unrecognized EOF %x\n", eof); | ||
146 | return 0; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * i40e_fcoe_xid_is_valid - returns true if the exchange id is valid | ||
152 | * @xid: the exchange id | ||
153 | **/ | ||
154 | static inline bool i40e_fcoe_xid_is_valid(u16 xid) | ||
155 | { | ||
156 | return (xid != FC_XID_UNKNOWN) && (xid < I40E_FCOE_DDP_MAX); | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * i40e_fcoe_ddp_unmap - unmap the mapped sglist associated | ||
161 | * @pf: pointer to pf | ||
162 | * @ddp: sw DDP context | ||
163 | * | ||
164 | * Unmap the scatter-gather list associated with the given SW DDP context | ||
165 | * | ||
166 | * Returns: data length already ddp-ed in bytes | ||
167 | * | ||
168 | **/ | ||
169 | static inline void i40e_fcoe_ddp_unmap(struct i40e_pf *pf, | ||
170 | struct i40e_fcoe_ddp *ddp) | ||
171 | { | ||
172 | if (test_and_set_bit(__I40E_FCOE_DDP_UNMAPPED, &ddp->flags)) | ||
173 | return; | ||
174 | |||
175 | if (ddp->sgl) { | ||
176 | dma_unmap_sg(&pf->pdev->dev, ddp->sgl, ddp->sgc, | ||
177 | DMA_FROM_DEVICE); | ||
178 | ddp->sgl = NULL; | ||
179 | ddp->sgc = 0; | ||
180 | } | ||
181 | |||
182 | if (ddp->pool) { | ||
183 | dma_pool_free(ddp->pool, ddp->udl, ddp->udp); | ||
184 | ddp->pool = NULL; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * i40e_fcoe_ddp_clear - clear the given SW DDP context | ||
190 | * @ddp - SW DDP context | ||
191 | **/ | ||
192 | static inline void i40e_fcoe_ddp_clear(struct i40e_fcoe_ddp *ddp) | ||
193 | { | ||
194 | memset(ddp, 0, sizeof(struct i40e_fcoe_ddp)); | ||
195 | ddp->xid = FC_XID_UNKNOWN; | ||
196 | ddp->flags = __I40E_FCOE_DDP_NONE; | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * i40e_fcoe_progid_is_fcoe - check if the prog_id is for FCoE | ||
201 | * @id: the prog id for the programming status Rx descriptor write-back | ||
202 | **/ | ||
203 | static inline bool i40e_fcoe_progid_is_fcoe(u8 id) | ||
204 | { | ||
205 | return (id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS) || | ||
206 | (id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS); | ||
207 | } | ||
208 | |||
209 | /** | ||
210 | * i40e_fcoe_fc_get_xid - get xid from the frame header | ||
211 | * @fh: the fc frame header | ||
212 | * | ||
213 | * In case the incoming frame's exchange is originated from | ||
214 | * the initiator, then received frame's exchange id is ANDed | ||
215 | * with fc_cpu_mask bits to get the same cpu on which exchange | ||
216 | * was originated, otherwise just use the current cpu. | ||
217 | * | ||
218 | * Returns ox_id if exchange originator, rx_id if responder | ||
219 | **/ | ||
220 | static inline u16 i40e_fcoe_fc_get_xid(struct fc_frame_header *fh) | ||
221 | { | ||
222 | u32 f_ctl = ntoh24(fh->fh_f_ctl); | ||
223 | |||
224 | return (f_ctl & FC_FC_EX_CTX) ? | ||
225 | be16_to_cpu(fh->fh_ox_id) : | ||
226 | be16_to_cpu(fh->fh_rx_id); | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * i40e_fcoe_fc_frame_header - get fc frame header from skb | ||
231 | * @skb: packet | ||
232 | * | ||
233 | * This checks if there is a VLAN header and returns the data | ||
234 | * pointer to the start of the fc_frame_header. | ||
235 | * | ||
236 | * Returns pointer to the fc_frame_header | ||
237 | **/ | ||
238 | static inline struct fc_frame_header *i40e_fcoe_fc_frame_header( | ||
239 | struct sk_buff *skb) | ||
240 | { | ||
241 | void *fh = skb->data + sizeof(struct fcoe_hdr); | ||
242 | |||
243 | if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)) | ||
244 | fh += sizeof(struct vlan_hdr); | ||
245 | |||
246 | return (struct fc_frame_header *)fh; | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * i40e_fcoe_ddp_put - release the DDP context for a given exchange id | ||
251 | * @netdev: the corresponding net_device | ||
252 | * @xid: the exchange id that corresponding DDP context will be released | ||
253 | * | ||
254 | * This is the implementation of net_device_ops.ndo_fcoe_ddp_done | ||
255 | * and it is expected to be called by ULD, i.e., FCP layer of libfc | ||
256 | * to release the corresponding ddp context when the I/O is done. | ||
257 | * | ||
258 | * Returns : data length already ddp-ed in bytes | ||
259 | **/ | ||
260 | static int i40e_fcoe_ddp_put(struct net_device *netdev, u16 xid) | ||
261 | { | ||
262 | struct i40e_netdev_priv *np = netdev_priv(netdev); | ||
263 | struct i40e_pf *pf = np->vsi->back; | ||
264 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
265 | int len = 0; | ||
266 | struct i40e_fcoe_ddp *ddp = &fcoe->ddp[xid]; | ||
267 | |||
268 | if (!fcoe || !ddp) | ||
269 | goto out; | ||
270 | |||
271 | if (test_bit(__I40E_FCOE_DDP_DONE, &ddp->flags)) | ||
272 | len = ddp->len; | ||
273 | i40e_fcoe_ddp_unmap(pf, ddp); | ||
274 | out: | ||
275 | return len; | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * i40e_fcoe_sw_init - sets up the HW for FCoE | ||
280 | * @pf: pointer to pf | ||
281 | * | ||
282 | * Returns 0 if FCoE is supported otherwise the error code | ||
283 | **/ | ||
284 | int i40e_init_pf_fcoe(struct i40e_pf *pf) | ||
285 | { | ||
286 | struct i40e_hw *hw = &pf->hw; | ||
287 | u32 val; | ||
288 | |||
289 | pf->flags &= ~I40E_FLAG_FCOE_ENABLED; | ||
290 | pf->num_fcoe_qps = 0; | ||
291 | pf->fcoe_hmc_cntx_num = 0; | ||
292 | pf->fcoe_hmc_filt_num = 0; | ||
293 | |||
294 | if (!pf->hw.func_caps.fcoe) { | ||
295 | dev_info(&pf->pdev->dev, "FCoE capability is disabled\n"); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | if (!pf->hw.func_caps.dcb) { | ||
300 | dev_warn(&pf->pdev->dev, | ||
301 | "Hardware is not DCB capable not enabling FCoE.\n"); | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | /* enable FCoE hash filter */ | ||
306 | val = rd32(hw, I40E_PFQF_HENA(1)); | ||
307 | val |= 1 << (I40E_FILTER_PCTYPE_FCOE_OX - 32); | ||
308 | val |= 1 << (I40E_FILTER_PCTYPE_FCOE_RX - 32); | ||
309 | val &= I40E_PFQF_HENA_PTYPE_ENA_MASK; | ||
310 | wr32(hw, I40E_PFQF_HENA(1), val); | ||
311 | |||
312 | /* enable flag */ | ||
313 | pf->flags |= I40E_FLAG_FCOE_ENABLED; | ||
314 | pf->num_fcoe_qps = I40E_DEFAULT_FCOE; | ||
315 | |||
316 | /* Reserve 4K DDP contexts and 20K filter size for FCoE */ | ||
317 | pf->fcoe_hmc_cntx_num = (1 << I40E_DMA_CNTX_SIZE_4K) * | ||
318 | I40E_DMA_CNTX_BASE_SIZE; | ||
319 | pf->fcoe_hmc_filt_num = pf->fcoe_hmc_cntx_num + | ||
320 | (1 << I40E_HASH_FILTER_SIZE_16K) * | ||
321 | I40E_HASH_FILTER_BASE_SIZE; | ||
322 | |||
323 | /* FCoE object: max 16K filter buckets and 4K DMA contexts */ | ||
324 | pf->filter_settings.fcoe_filt_num = I40E_HASH_FILTER_SIZE_16K; | ||
325 | pf->filter_settings.fcoe_cntx_num = I40E_DMA_CNTX_SIZE_4K; | ||
326 | |||
327 | /* Setup max frame with FCoE_MTU plus L2 overheads */ | ||
328 | val = rd32(hw, I40E_GLFCOE_RCTL); | ||
329 | val &= ~I40E_GLFCOE_RCTL_MAX_SIZE_MASK; | ||
330 | val |= ((FCOE_MTU + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) | ||
331 | << I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT); | ||
332 | wr32(hw, I40E_GLFCOE_RCTL, val); | ||
333 | |||
334 | dev_info(&pf->pdev->dev, "FCoE is supported.\n"); | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * i40e_get_fcoe_tc_map - Return TC map for FCoE APP | ||
340 | * @pf: pointer to pf | ||
341 | * | ||
342 | **/ | ||
343 | u8 i40e_get_fcoe_tc_map(struct i40e_pf *pf) | ||
344 | { | ||
345 | struct i40e_ieee_app_priority_table app; | ||
346 | struct i40e_hw *hw = &pf->hw; | ||
347 | u8 enabled_tc = 0; | ||
348 | u8 tc, i; | ||
349 | /* Get the FCoE APP TLV */ | ||
350 | struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config; | ||
351 | |||
352 | for (i = 0; i < dcbcfg->numapps; i++) { | ||
353 | app = dcbcfg->app[i]; | ||
354 | if (app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && | ||
355 | app.protocolid == ETH_P_FCOE) { | ||
356 | tc = dcbcfg->etscfg.prioritytable[app.priority]; | ||
357 | enabled_tc |= (1 << tc); | ||
358 | break; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | /* TC0 if there is no TC defined for FCoE APP TLV */ | ||
363 | enabled_tc = enabled_tc ? enabled_tc : 0x1; | ||
364 | |||
365 | return enabled_tc; | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * i40e_fcoe_vsi_init - prepares the VSI context for creating a FCoE VSI | ||
370 | * @vsi: pointer to the associated VSI struct | ||
371 | * @ctxt: pointer to the associated VSI context to be passed to HW | ||
372 | * | ||
373 | * Returns 0 on success or < 0 on error | ||
374 | **/ | ||
375 | int i40e_fcoe_vsi_init(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt) | ||
376 | { | ||
377 | struct i40e_aqc_vsi_properties_data *info = &ctxt->info; | ||
378 | struct i40e_pf *pf = vsi->back; | ||
379 | struct i40e_hw *hw = &pf->hw; | ||
380 | u8 enabled_tc = 0; | ||
381 | |||
382 | if (!(pf->flags & I40E_FLAG_FCOE_ENABLED)) { | ||
383 | dev_err(&pf->pdev->dev, | ||
384 | "FCoE is not enabled for this device\n"); | ||
385 | return -EPERM; | ||
386 | } | ||
387 | |||
388 | /* initialize the hardware for FCoE */ | ||
389 | ctxt->pf_num = hw->pf_id; | ||
390 | ctxt->vf_num = 0; | ||
391 | ctxt->uplink_seid = vsi->uplink_seid; | ||
392 | ctxt->connection_type = 0x1; | ||
393 | ctxt->flags = I40E_AQ_VSI_TYPE_PF; | ||
394 | |||
395 | /* FCoE VSI would need the following sections */ | ||
396 | info->valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID | | ||
397 | I40E_AQ_VSI_PROP_QUEUE_OPT_VALID); | ||
398 | |||
399 | /* FCoE VSI does not need these sections */ | ||
400 | info->valid_sections &= cpu_to_le16(~(I40E_AQ_VSI_PROP_SECURITY_VALID | | ||
401 | I40E_AQ_VSI_PROP_VLAN_VALID | | ||
402 | I40E_AQ_VSI_PROP_CAS_PV_VALID | | ||
403 | I40E_AQ_VSI_PROP_INGRESS_UP_VALID | | ||
404 | I40E_AQ_VSI_PROP_EGRESS_UP_VALID)); | ||
405 | |||
406 | enabled_tc = i40e_get_fcoe_tc_map(pf); | ||
407 | i40e_vsi_setup_queue_map(vsi, ctxt, enabled_tc, true); | ||
408 | |||
409 | /* set up queue option section: only enable FCoE */ | ||
410 | info->queueing_opt_flags = I40E_AQ_VSI_QUE_OPT_FCOE_ENA; | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | /** | ||
416 | * i40e_fcoe_enable - this is the implementation of ndo_fcoe_enable, | ||
417 | * indicating the upper FCoE protocol stack is ready to use FCoE | ||
418 | * offload features. | ||
419 | * | ||
420 | * @netdev: pointer to the netdev that FCoE is created on | ||
421 | * | ||
422 | * Returns 0 on success | ||
423 | * | ||
424 | * in RTNL | ||
425 | * | ||
426 | **/ | ||
427 | int i40e_fcoe_enable(struct net_device *netdev) | ||
428 | { | ||
429 | struct i40e_netdev_priv *np = netdev_priv(netdev); | ||
430 | struct i40e_vsi *vsi = np->vsi; | ||
431 | struct i40e_pf *pf = vsi->back; | ||
432 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
433 | |||
434 | if (!(pf->flags & I40E_FLAG_FCOE_ENABLED)) { | ||
435 | netdev_err(netdev, "HW does not support FCoE.\n"); | ||
436 | return -ENODEV; | ||
437 | } | ||
438 | |||
439 | if (vsi->type != I40E_VSI_FCOE) { | ||
440 | netdev_err(netdev, "interface does not support FCoE.\n"); | ||
441 | return -EBUSY; | ||
442 | } | ||
443 | |||
444 | atomic_inc(&fcoe->refcnt); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | /** | ||
450 | * i40e_fcoe_disable- disables FCoE for upper FCoE protocol stack. | ||
451 | * @dev: pointer to the netdev that FCoE is created on | ||
452 | * | ||
453 | * Returns 0 on success | ||
454 | * | ||
455 | **/ | ||
456 | int i40e_fcoe_disable(struct net_device *netdev) | ||
457 | { | ||
458 | struct i40e_netdev_priv *np = netdev_priv(netdev); | ||
459 | struct i40e_vsi *vsi = np->vsi; | ||
460 | struct i40e_pf *pf = vsi->back; | ||
461 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
462 | |||
463 | if (!(pf->flags & I40E_FLAG_FCOE_ENABLED)) { | ||
464 | netdev_err(netdev, "device does not support FCoE\n"); | ||
465 | return -ENODEV; | ||
466 | } | ||
467 | if (vsi->type != I40E_VSI_FCOE) | ||
468 | return -EBUSY; | ||
469 | |||
470 | if (!atomic_dec_and_test(&fcoe->refcnt)) | ||
471 | return -EINVAL; | ||
472 | |||
473 | netdev_info(netdev, "FCoE disabled\n"); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | /** | ||
479 | * i40e_fcoe_dma_pool_free - free the per cpu pool for FCoE DDP | ||
480 | * @fcoe: the FCoE sw object | ||
481 | * @dev: the device that the pool is associated with | ||
482 | * @cpu: the cpu for this pool | ||
483 | * | ||
484 | **/ | ||
485 | static void i40e_fcoe_dma_pool_free(struct i40e_fcoe *fcoe, | ||
486 | struct device *dev, | ||
487 | unsigned int cpu) | ||
488 | { | ||
489 | struct i40e_fcoe_ddp_pool *ddp_pool; | ||
490 | |||
491 | ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu); | ||
492 | if (!ddp_pool->pool) { | ||
493 | dev_warn(dev, "DDP pool already freed for cpu %d\n", cpu); | ||
494 | return; | ||
495 | } | ||
496 | dma_pool_destroy(ddp_pool->pool); | ||
497 | ddp_pool->pool = NULL; | ||
498 | } | ||
499 | |||
500 | /** | ||
501 | * i40e_fcoe_dma_pool_create - per cpu pool for FCoE DDP | ||
502 | * @fcoe: the FCoE sw object | ||
503 | * @dev: the device that the pool is associated with | ||
504 | * @cpu: the cpu for this pool | ||
505 | * | ||
506 | * Returns 0 on successful or non zero on failure | ||
507 | * | ||
508 | **/ | ||
509 | static int i40e_fcoe_dma_pool_create(struct i40e_fcoe *fcoe, | ||
510 | struct device *dev, | ||
511 | unsigned int cpu) | ||
512 | { | ||
513 | struct i40e_fcoe_ddp_pool *ddp_pool; | ||
514 | struct dma_pool *pool; | ||
515 | char pool_name[32]; | ||
516 | |||
517 | ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu); | ||
518 | if (ddp_pool && ddp_pool->pool) { | ||
519 | dev_warn(dev, "DDP pool already allocated for cpu %d\n", cpu); | ||
520 | return 0; | ||
521 | } | ||
522 | snprintf(pool_name, sizeof(pool_name), "i40e_fcoe_ddp_%d", cpu); | ||
523 | pool = dma_pool_create(pool_name, dev, I40E_FCOE_DDP_PTR_MAX, | ||
524 | I40E_FCOE_DDP_PTR_ALIGN, PAGE_SIZE); | ||
525 | if (!pool) { | ||
526 | dev_err(dev, "dma_pool_create %s failed\n", pool_name); | ||
527 | return -ENOMEM; | ||
528 | } | ||
529 | ddp_pool->pool = pool; | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * i40e_fcoe_free_ddp_resources - release FCoE DDP resources | ||
535 | * @vsi: the vsi FCoE is associated with | ||
536 | * | ||
537 | **/ | ||
538 | void i40e_fcoe_free_ddp_resources(struct i40e_vsi *vsi) | ||
539 | { | ||
540 | struct i40e_pf *pf = vsi->back; | ||
541 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
542 | int cpu, i; | ||
543 | |||
544 | /* do nothing if not FCoE VSI */ | ||
545 | if (vsi->type != I40E_VSI_FCOE) | ||
546 | return; | ||
547 | |||
548 | /* do nothing if no DDP pools were allocated */ | ||
549 | if (!fcoe->ddp_pool) | ||
550 | return; | ||
551 | |||
552 | for (i = 0; i < I40E_FCOE_DDP_MAX; i++) | ||
553 | i40e_fcoe_ddp_put(vsi->netdev, i); | ||
554 | |||
555 | for_each_possible_cpu(cpu) | ||
556 | i40e_fcoe_dma_pool_free(fcoe, &pf->pdev->dev, cpu); | ||
557 | |||
558 | free_percpu(fcoe->ddp_pool); | ||
559 | fcoe->ddp_pool = NULL; | ||
560 | |||
561 | netdev_info(vsi->netdev, "VSI %d,%d FCoE DDP resources released\n", | ||
562 | vsi->id, vsi->seid); | ||
563 | } | ||
564 | |||
565 | /** | ||
566 | * i40e_fcoe_setup_ddp_resources - allocate per cpu DDP resources | ||
567 | * @vsi: the VSI FCoE is associated with | ||
568 | * | ||
569 | * Returns 0 on successful or non zero on failure | ||
570 | * | ||
571 | **/ | ||
572 | int i40e_fcoe_setup_ddp_resources(struct i40e_vsi *vsi) | ||
573 | { | ||
574 | struct i40e_pf *pf = vsi->back; | ||
575 | struct device *dev = &pf->pdev->dev; | ||
576 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
577 | unsigned int cpu; | ||
578 | int i; | ||
579 | |||
580 | if (vsi->type != I40E_VSI_FCOE) | ||
581 | return -ENODEV; | ||
582 | |||
583 | /* do nothing if no DDP pools were allocated */ | ||
584 | if (fcoe->ddp_pool) | ||
585 | return -EEXIST; | ||
586 | |||
587 | /* allocate per CPU memory to track DDP pools */ | ||
588 | fcoe->ddp_pool = alloc_percpu(struct i40e_fcoe_ddp_pool); | ||
589 | if (!fcoe->ddp_pool) { | ||
590 | dev_err(&pf->pdev->dev, "failed to allocate percpu DDP\n"); | ||
591 | return -ENOMEM; | ||
592 | } | ||
593 | |||
594 | /* allocate pci pool for each cpu */ | ||
595 | for_each_possible_cpu(cpu) { | ||
596 | if (!i40e_fcoe_dma_pool_create(fcoe, dev, cpu)) | ||
597 | continue; | ||
598 | |||
599 | dev_err(dev, "failed to alloc DDP pool on cpu:%d\n", cpu); | ||
600 | i40e_fcoe_free_ddp_resources(vsi); | ||
601 | return -ENOMEM; | ||
602 | } | ||
603 | |||
604 | /* initialize the sw context */ | ||
605 | for (i = 0; i < I40E_FCOE_DDP_MAX; i++) | ||
606 | i40e_fcoe_ddp_clear(&fcoe->ddp[i]); | ||
607 | |||
608 | netdev_info(vsi->netdev, "VSI %d,%d FCoE DDP resources allocated\n", | ||
609 | vsi->id, vsi->seid); | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | /** | ||
615 | * i40e_fcoe_handle_status - check the Programming Status for FCoE | ||
616 | * @rx_ring: the Rx ring for this descriptor | ||
617 | * @rx_desc: the Rx descriptor for Programming Status, not a packet descriptor. | ||
618 | * | ||
619 | * Check if this is the Rx Programming Status descriptor write-back for FCoE. | ||
620 | * This is used to verify if the context/filter programming or invalidation | ||
621 | * requested by SW to the HW is successful or not and take actions accordingly. | ||
622 | **/ | ||
623 | void i40e_fcoe_handle_status(struct i40e_ring *rx_ring, | ||
624 | union i40e_rx_desc *rx_desc, u8 prog_id) | ||
625 | { | ||
626 | struct i40e_pf *pf = rx_ring->vsi->back; | ||
627 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
628 | struct i40e_fcoe_ddp *ddp; | ||
629 | u32 error; | ||
630 | u16 xid; | ||
631 | u64 qw; | ||
632 | |||
633 | /* we only care for FCoE here */ | ||
634 | if (!i40e_fcoe_progid_is_fcoe(prog_id)) | ||
635 | return; | ||
636 | |||
637 | xid = le32_to_cpu(rx_desc->wb.qword0.hi_dword.fcoe_param) & | ||
638 | (I40E_FCOE_DDP_MAX - 1); | ||
639 | |||
640 | if (!i40e_fcoe_xid_is_valid(xid)) | ||
641 | return; | ||
642 | |||
643 | ddp = &fcoe->ddp[xid]; | ||
644 | WARN_ON(xid != ddp->xid); | ||
645 | |||
646 | qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len); | ||
647 | error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >> | ||
648 | I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT; | ||
649 | |||
650 | /* DDP context programming status: failure or success */ | ||
651 | if (prog_id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS) { | ||
652 | if (I40E_RX_PROG_FCOE_ERROR_TBL_FULL(error)) { | ||
653 | dev_err(&pf->pdev->dev, "xid %x ddp->xid %x TABLE FULL\n", | ||
654 | xid, ddp->xid); | ||
655 | ddp->prerr |= I40E_RX_PROG_FCOE_ERROR_TBL_FULL_BIT; | ||
656 | } | ||
657 | if (I40E_RX_PROG_FCOE_ERROR_CONFLICT(error)) { | ||
658 | dev_err(&pf->pdev->dev, "xid %x ddp->xid %x CONFLICT\n", | ||
659 | xid, ddp->xid); | ||
660 | ddp->prerr |= I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | /* DDP context invalidation status: failure or success */ | ||
665 | if (prog_id == I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS) { | ||
666 | if (I40E_RX_PROG_FCOE_ERROR_INVLFAIL(error)) { | ||
667 | dev_err(&pf->pdev->dev, "xid %x ddp->xid %x INVALIDATION FAILURE\n", | ||
668 | xid, ddp->xid); | ||
669 | ddp->prerr |= I40E_RX_PROG_FCOE_ERROR_INVLFAIL_BIT; | ||
670 | } | ||
671 | /* clear the flag so we can retry invalidation */ | ||
672 | clear_bit(__I40E_FCOE_DDP_ABORTED, &ddp->flags); | ||
673 | } | ||
674 | |||
675 | /* unmap DMA */ | ||
676 | i40e_fcoe_ddp_unmap(pf, ddp); | ||
677 | i40e_fcoe_ddp_clear(ddp); | ||
678 | } | ||
679 | |||
680 | /** | ||
681 | * i40e_fcoe_handle_offload - check ddp status and mark it done | ||
682 | * @adapter: i40e adapter | ||
683 | * @rx_desc: advanced rx descriptor | ||
684 | * @skb: the skb holding the received data | ||
685 | * | ||
686 | * This checks ddp status. | ||
687 | * | ||
688 | * Returns : < 0 indicates an error or not a FCOE ddp, 0 indicates | ||
689 | * not passing the skb to ULD, > 0 indicates is the length of data | ||
690 | * being ddped. | ||
691 | * | ||
692 | **/ | ||
693 | int i40e_fcoe_handle_offload(struct i40e_ring *rx_ring, | ||
694 | union i40e_rx_desc *rx_desc, | ||
695 | struct sk_buff *skb) | ||
696 | { | ||
697 | struct i40e_pf *pf = rx_ring->vsi->back; | ||
698 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
699 | struct fc_frame_header *fh = NULL; | ||
700 | struct i40e_fcoe_ddp *ddp = NULL; | ||
701 | u32 status, fltstat; | ||
702 | u32 error, fcerr; | ||
703 | int rc = -EINVAL; | ||
704 | u16 ptype; | ||
705 | u16 xid; | ||
706 | u64 qw; | ||
707 | |||
708 | /* check this rxd is for programming status */ | ||
709 | qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len); | ||
710 | /* packet descriptor, check packet type */ | ||
711 | ptype = (qw & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; | ||
712 | if (!i40e_rx_is_fcoe(ptype)) | ||
713 | goto out_no_ddp; | ||
714 | |||
715 | error = (qw & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; | ||
716 | fcerr = (error >> I40E_RX_DESC_ERROR_L3L4E_SHIFT) & | ||
717 | I40E_RX_DESC_FCOE_ERROR_MASK; | ||
718 | |||
719 | /* check stateless offload error */ | ||
720 | if (unlikely(fcerr == I40E_RX_DESC_ERROR_L3L4E_PROT)) { | ||
721 | dev_err(&pf->pdev->dev, "Protocol Error\n"); | ||
722 | skb->ip_summed = CHECKSUM_NONE; | ||
723 | } else { | ||
724 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
725 | } | ||
726 | |||
727 | /* check hw status on ddp */ | ||
728 | status = (qw & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; | ||
729 | fltstat = (status >> I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) & | ||
730 | I40E_RX_DESC_FLTSTAT_FCMASK; | ||
731 | |||
732 | /* now we are ready to check DDP */ | ||
733 | fh = i40e_fcoe_fc_frame_header(skb); | ||
734 | xid = i40e_fcoe_fc_get_xid(fh); | ||
735 | if (!i40e_fcoe_xid_is_valid(xid)) | ||
736 | goto out_no_ddp; | ||
737 | |||
738 | /* non DDP normal receive, return to the protocol stack */ | ||
739 | if (fltstat == I40E_RX_DESC_FLTSTAT_NOMTCH) | ||
740 | goto out_no_ddp; | ||
741 | |||
742 | /* do we have a sw ddp context setup ? */ | ||
743 | ddp = &fcoe->ddp[xid]; | ||
744 | if (!ddp->sgl) | ||
745 | goto out_no_ddp; | ||
746 | |||
747 | /* fetch xid from hw rxd wb, which should match up the sw ctxt */ | ||
748 | xid = le16_to_cpu(rx_desc->wb.qword0.lo_dword.mirr_fcoe.fcoe_ctx_id); | ||
749 | if (ddp->xid != xid) { | ||
750 | dev_err(&pf->pdev->dev, "xid 0x%x does not match ctx_xid 0x%x\n", | ||
751 | ddp->xid, xid); | ||
752 | goto out_put_ddp; | ||
753 | } | ||
754 | |||
755 | /* the same exchange has already errored out */ | ||
756 | if (ddp->fcerr) { | ||
757 | dev_err(&pf->pdev->dev, "xid 0x%x fcerr 0x%x reported fcer 0x%x\n", | ||
758 | xid, ddp->fcerr, fcerr); | ||
759 | goto out_put_ddp; | ||
760 | } | ||
761 | |||
762 | /* fcoe param is valid by now with correct DDPed length */ | ||
763 | ddp->len = le32_to_cpu(rx_desc->wb.qword0.hi_dword.fcoe_param); | ||
764 | ddp->fcerr = fcerr; | ||
765 | /* header posting only, useful only for target mode and debugging */ | ||
766 | if (fltstat == I40E_RX_DESC_FLTSTAT_DDP) { | ||
767 | /* For target mode, we get header of the last packet but it | ||
768 | * does not have the FCoE trailer field, i.e., CRC and EOF | ||
769 | * Ordered Set since they are offloaded by the HW, so fill | ||
770 | * it up correspondingly to allow the packet to pass through | ||
771 | * to the upper protocol stack. | ||
772 | */ | ||
773 | u32 f_ctl = ntoh24(fh->fh_f_ctl); | ||
774 | |||
775 | if ((f_ctl & FC_FC_END_SEQ) && | ||
776 | (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA)) { | ||
777 | struct fcoe_crc_eof *crc = NULL; | ||
778 | |||
779 | crc = (struct fcoe_crc_eof *)skb_put(skb, sizeof(*crc)); | ||
780 | crc->fcoe_eof = FC_EOF_T; | ||
781 | } else { | ||
782 | /* otherwise, drop the header only frame */ | ||
783 | rc = 0; | ||
784 | goto out_no_ddp; | ||
785 | } | ||
786 | } | ||
787 | |||
788 | out_put_ddp: | ||
789 | /* either we got RSP or we have an error, unmap DMA in both cases */ | ||
790 | i40e_fcoe_ddp_unmap(pf, ddp); | ||
791 | if (ddp->len && !ddp->fcerr) { | ||
792 | int pkts; | ||
793 | |||
794 | rc = ddp->len; | ||
795 | i40e_fcoe_ddp_clear(ddp); | ||
796 | ddp->len = rc; | ||
797 | pkts = DIV_ROUND_UP(rc, 2048); | ||
798 | rx_ring->stats.bytes += rc; | ||
799 | rx_ring->stats.packets += pkts; | ||
800 | rx_ring->q_vector->rx.total_bytes += rc; | ||
801 | rx_ring->q_vector->rx.total_packets += pkts; | ||
802 | set_bit(__I40E_FCOE_DDP_DONE, &ddp->flags); | ||
803 | } | ||
804 | |||
805 | out_no_ddp: | ||
806 | return rc; | ||
807 | } | ||
808 | |||
809 | /** | ||
810 | * i40e_fcoe_ddp_setup - called to set up ddp context | ||
811 | * @netdev: the corresponding net_device | ||
812 | * @xid: the exchange id requesting ddp | ||
813 | * @sgl: the scatter-gather list for this request | ||
814 | * @sgc: the number of scatter-gather items | ||
815 | * @target_mode: indicates this is a DDP request for target | ||
816 | * | ||
817 | * Returns : 1 for success and 0 for no DDP on this I/O | ||
818 | **/ | ||
819 | static int i40e_fcoe_ddp_setup(struct net_device *netdev, u16 xid, | ||
820 | struct scatterlist *sgl, unsigned int sgc, | ||
821 | int target_mode) | ||
822 | { | ||
823 | static const unsigned int bufflen = I40E_FCOE_DDP_BUF_MIN; | ||
824 | struct i40e_netdev_priv *np = netdev_priv(netdev); | ||
825 | struct i40e_fcoe_ddp_pool *ddp_pool; | ||
826 | struct i40e_pf *pf = np->vsi->back; | ||
827 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
828 | unsigned int i, j, dmacount; | ||
829 | struct i40e_fcoe_ddp *ddp; | ||
830 | unsigned int firstoff = 0; | ||
831 | unsigned int thisoff = 0; | ||
832 | unsigned int thislen = 0; | ||
833 | struct scatterlist *sg; | ||
834 | dma_addr_t addr = 0; | ||
835 | unsigned int len; | ||
836 | |||
837 | if (xid >= I40E_FCOE_DDP_MAX) { | ||
838 | dev_warn(&pf->pdev->dev, "xid=0x%x out-of-range\n", xid); | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | /* no DDP if we are already down or resetting */ | ||
843 | if (test_bit(__I40E_DOWN, &pf->state) || | ||
844 | test_bit(__I40E_NEEDS_RESTART, &pf->state)) { | ||
845 | dev_info(&pf->pdev->dev, "xid=0x%x device in reset/down\n", | ||
846 | xid); | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | ddp = &fcoe->ddp[xid]; | ||
851 | if (ddp->sgl) { | ||
852 | dev_info(&pf->pdev->dev, "xid 0x%x w/ non-null sgl=%p nents=%d\n", | ||
853 | xid, ddp->sgl, ddp->sgc); | ||
854 | return 0; | ||
855 | } | ||
856 | i40e_fcoe_ddp_clear(ddp); | ||
857 | |||
858 | if (!fcoe->ddp_pool) { | ||
859 | dev_info(&pf->pdev->dev, "No DDP pool, xid 0x%x\n", xid); | ||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu()); | ||
864 | if (!ddp_pool->pool) { | ||
865 | dev_info(&pf->pdev->dev, "No percpu ddp pool, xid 0x%x\n", xid); | ||
866 | goto out_noddp; | ||
867 | } | ||
868 | |||
869 | /* setup dma from scsi command sgl */ | ||
870 | dmacount = dma_map_sg(&pf->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); | ||
871 | if (dmacount == 0) { | ||
872 | dev_info(&pf->pdev->dev, "dma_map_sg for sgl %p, sgc %d failed\n", | ||
873 | sgl, sgc); | ||
874 | goto out_noddp_unmap; | ||
875 | } | ||
876 | |||
877 | /* alloc the udl from our ddp pool */ | ||
878 | ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp); | ||
879 | if (!ddp->udl) { | ||
880 | dev_info(&pf->pdev->dev, | ||
881 | "Failed allocated ddp context, xid 0x%x\n", xid); | ||
882 | goto out_noddp_unmap; | ||
883 | } | ||
884 | |||
885 | j = 0; | ||
886 | ddp->len = 0; | ||
887 | for_each_sg(sgl, sg, dmacount, i) { | ||
888 | addr = sg_dma_address(sg); | ||
889 | len = sg_dma_len(sg); | ||
890 | ddp->len += len; | ||
891 | while (len) { | ||
892 | /* max number of buffers allowed in one DDP context */ | ||
893 | if (j >= I40E_FCOE_DDP_BUFFCNT_MAX) { | ||
894 | dev_info(&pf->pdev->dev, | ||
895 | "xid=%x:%d,%d,%d:addr=%llx not enough descriptors\n", | ||
896 | xid, i, j, dmacount, (u64)addr); | ||
897 | goto out_noddp_free; | ||
898 | } | ||
899 | |||
900 | /* get the offset of length of current buffer */ | ||
901 | thisoff = addr & ((dma_addr_t)bufflen - 1); | ||
902 | thislen = min_t(unsigned int, (bufflen - thisoff), len); | ||
903 | /* all but the 1st buffer (j == 0) | ||
904 | * must be aligned on bufflen | ||
905 | */ | ||
906 | if ((j != 0) && (thisoff)) | ||
907 | goto out_noddp_free; | ||
908 | |||
909 | /* all but the last buffer | ||
910 | * ((i == (dmacount - 1)) && (thislen == len)) | ||
911 | * must end at bufflen | ||
912 | */ | ||
913 | if (((i != (dmacount - 1)) || (thislen != len)) && | ||
914 | ((thislen + thisoff) != bufflen)) | ||
915 | goto out_noddp_free; | ||
916 | |||
917 | ddp->udl[j] = (u64)(addr - thisoff); | ||
918 | /* only the first buffer may have none-zero offset */ | ||
919 | if (j == 0) | ||
920 | firstoff = thisoff; | ||
921 | len -= thislen; | ||
922 | addr += thislen; | ||
923 | j++; | ||
924 | } | ||
925 | } | ||
926 | /* only the last buffer may have non-full bufflen */ | ||
927 | ddp->lastsize = thisoff + thislen; | ||
928 | ddp->firstoff = firstoff; | ||
929 | ddp->list_len = j; | ||
930 | ddp->pool = ddp_pool->pool; | ||
931 | ddp->sgl = sgl; | ||
932 | ddp->sgc = sgc; | ||
933 | ddp->xid = xid; | ||
934 | if (target_mode) | ||
935 | set_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags); | ||
936 | set_bit(__I40E_FCOE_DDP_INITALIZED, &ddp->flags); | ||
937 | |||
938 | put_cpu(); | ||
939 | return 1; /* Success */ | ||
940 | |||
941 | out_noddp_free: | ||
942 | dma_pool_free(ddp->pool, ddp->udl, ddp->udp); | ||
943 | i40e_fcoe_ddp_clear(ddp); | ||
944 | |||
945 | out_noddp_unmap: | ||
946 | dma_unmap_sg(&pf->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); | ||
947 | out_noddp: | ||
948 | put_cpu(); | ||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | /** | ||
953 | * i40e_fcoe_ddp_get - called to set up ddp context in initiator mode | ||
954 | * @netdev: the corresponding net_device | ||
955 | * @xid: the exchange id requesting ddp | ||
956 | * @sgl: the scatter-gather list for this request | ||
957 | * @sgc: the number of scatter-gather items | ||
958 | * | ||
959 | * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup | ||
960 | * and is expected to be called from ULD, e.g., FCP layer of libfc | ||
961 | * to set up ddp for the corresponding xid of the given sglist for | ||
962 | * the corresponding I/O. | ||
963 | * | ||
964 | * Returns : 1 for success and 0 for no ddp | ||
965 | **/ | ||
966 | static int i40e_fcoe_ddp_get(struct net_device *netdev, u16 xid, | ||
967 | struct scatterlist *sgl, unsigned int sgc) | ||
968 | { | ||
969 | return i40e_fcoe_ddp_setup(netdev, xid, sgl, sgc, 0); | ||
970 | } | ||
971 | |||
972 | /** | ||
973 | * i40e_fcoe_ddp_target - called to set up ddp context in target mode | ||
974 | * @netdev: the corresponding net_device | ||
975 | * @xid: the exchange id requesting ddp | ||
976 | * @sgl: the scatter-gather list for this request | ||
977 | * @sgc: the number of scatter-gather items | ||
978 | * | ||
979 | * This is the implementation of net_device_ops.ndo_fcoe_ddp_target | ||
980 | * and is expected to be called from ULD, e.g., FCP layer of libfc | ||
981 | * to set up ddp for the corresponding xid of the given sglist for | ||
982 | * the corresponding I/O. The DDP in target mode is a write I/O request | ||
983 | * from the initiator. | ||
984 | * | ||
985 | * Returns : 1 for success and 0 for no ddp | ||
986 | **/ | ||
987 | static int i40e_fcoe_ddp_target(struct net_device *netdev, u16 xid, | ||
988 | struct scatterlist *sgl, unsigned int sgc) | ||
989 | { | ||
990 | return i40e_fcoe_ddp_setup(netdev, xid, sgl, sgc, 1); | ||
991 | } | ||
992 | |||
993 | /** | ||
994 | * i40e_fcoe_program_ddp - programs the HW DDP related descriptors | ||
995 | * @tx_ring: transmit ring for this packet | ||
996 | * @skb: the packet to be sent out | ||
997 | * @sof: the SOF to indicate class of service | ||
998 | * | ||
999 | * Determine if it is READ/WRITE command, and finds out if there is | ||
1000 | * a matching SW DDP context for this command. DDP is applicable | ||
1001 | * only in case of READ if initiator or WRITE in case of | ||
1002 | * responder (via checking XFER_RDY). | ||
1003 | * | ||
1004 | * Note: caller checks sof and ddp sw context | ||
1005 | * | ||
1006 | * Returns : none | ||
1007 | * | ||
1008 | **/ | ||
1009 | static void i40e_fcoe_program_ddp(struct i40e_ring *tx_ring, | ||
1010 | struct sk_buff *skb, | ||
1011 | struct i40e_fcoe_ddp *ddp, u8 sof) | ||
1012 | { | ||
1013 | struct i40e_fcoe_filter_context_desc *filter_desc = NULL; | ||
1014 | struct i40e_fcoe_queue_context_desc *queue_desc = NULL; | ||
1015 | struct i40e_fcoe_ddp_context_desc *ddp_desc = NULL; | ||
1016 | struct i40e_pf *pf = tx_ring->vsi->back; | ||
1017 | u16 i = tx_ring->next_to_use; | ||
1018 | struct fc_frame_header *fh; | ||
1019 | u64 flags_rsvd_lanq = 0; | ||
1020 | bool target_mode; | ||
1021 | |||
1022 | /* check if abort is still pending */ | ||
1023 | if (test_bit(__I40E_FCOE_DDP_ABORTED, &ddp->flags)) { | ||
1024 | dev_warn(&pf->pdev->dev, | ||
1025 | "DDP abort is still pending xid:%hx and ddp->flags:%lx:\n", | ||
1026 | ddp->xid, ddp->flags); | ||
1027 | return; | ||
1028 | } | ||
1029 | |||
1030 | /* set the flag to indicate this is programmed */ | ||
1031 | if (test_and_set_bit(__I40E_FCOE_DDP_PROGRAMMED, &ddp->flags)) { | ||
1032 | dev_warn(&pf->pdev->dev, | ||
1033 | "DDP is already programmed for xid:%hx and ddp->flags:%lx:\n", | ||
1034 | ddp->xid, ddp->flags); | ||
1035 | return; | ||
1036 | } | ||
1037 | |||
1038 | /* Prepare the DDP context descriptor */ | ||
1039 | ddp_desc = I40E_DDP_CONTEXT_DESC(tx_ring, i); | ||
1040 | i++; | ||
1041 | if (i == tx_ring->count) | ||
1042 | i = 0; | ||
1043 | |||
1044 | ddp_desc->type_cmd_foff_lsize = | ||
1045 | cpu_to_le64(I40E_TX_DESC_DTYPE_DDP_CTX | | ||
1046 | ((u64)I40E_FCOE_DDP_CTX_DESC_BSIZE_4K << | ||
1047 | I40E_FCOE_DDP_CTX_QW1_CMD_SHIFT) | | ||
1048 | ((u64)ddp->firstoff << | ||
1049 | I40E_FCOE_DDP_CTX_QW1_FOFF_SHIFT) | | ||
1050 | ((u64)ddp->lastsize << | ||
1051 | I40E_FCOE_DDP_CTX_QW1_LSIZE_SHIFT)); | ||
1052 | ddp_desc->rsvd = cpu_to_le64(0); | ||
1053 | |||
1054 | /* target mode needs last packet in the sequence */ | ||
1055 | target_mode = test_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags); | ||
1056 | if (target_mode) | ||
1057 | ddp_desc->type_cmd_foff_lsize |= | ||
1058 | cpu_to_le64(I40E_FCOE_DDP_CTX_DESC_LASTSEQH); | ||
1059 | |||
1060 | /* Prepare queue_context descriptor */ | ||
1061 | queue_desc = I40E_QUEUE_CONTEXT_DESC(tx_ring, i++); | ||
1062 | if (i == tx_ring->count) | ||
1063 | i = 0; | ||
1064 | queue_desc->dmaindx_fbase = cpu_to_le64(ddp->xid | ((u64)ddp->udp)); | ||
1065 | queue_desc->flen_tph = cpu_to_le64(ddp->list_len | | ||
1066 | ((u64)(I40E_FCOE_QUEUE_CTX_DESC_TPHRDESC | | ||
1067 | I40E_FCOE_QUEUE_CTX_DESC_TPHDATA) << | ||
1068 | I40E_FCOE_QUEUE_CTX_QW1_TPH_SHIFT)); | ||
1069 | |||
1070 | /* Prepare filter_context_desc */ | ||
1071 | filter_desc = I40E_FILTER_CONTEXT_DESC(tx_ring, i); | ||
1072 | i++; | ||
1073 | if (i == tx_ring->count) | ||
1074 | i = 0; | ||
1075 | |||
1076 | fh = (struct fc_frame_header *)skb_transport_header(skb); | ||
1077 | filter_desc->param = cpu_to_le32(ntohl(fh->fh_parm_offset)); | ||
1078 | filter_desc->seqn = cpu_to_le16(ntohs(fh->fh_seq_cnt)); | ||
1079 | filter_desc->rsvd_dmaindx = cpu_to_le16(ddp->xid << | ||
1080 | I40E_FCOE_FILTER_CTX_QW0_DMAINDX_SHIFT); | ||
1081 | |||
1082 | flags_rsvd_lanq = I40E_FCOE_FILTER_CTX_DESC_CTYP_DDP; | ||
1083 | flags_rsvd_lanq |= (u64)(target_mode ? | ||
1084 | I40E_FCOE_FILTER_CTX_DESC_ENODE_RSP : | ||
1085 | I40E_FCOE_FILTER_CTX_DESC_ENODE_INIT); | ||
1086 | |||
1087 | flags_rsvd_lanq |= (u64)((sof == FC_SOF_I2 || sof == FC_SOF_N2) ? | ||
1088 | I40E_FCOE_FILTER_CTX_DESC_FC_CLASS2 : | ||
1089 | I40E_FCOE_FILTER_CTX_DESC_FC_CLASS3); | ||
1090 | |||
1091 | flags_rsvd_lanq |= ((u64)skb->queue_mapping << | ||
1092 | I40E_FCOE_FILTER_CTX_QW1_LANQINDX_SHIFT); | ||
1093 | filter_desc->flags_rsvd_lanq = cpu_to_le64(flags_rsvd_lanq); | ||
1094 | |||
1095 | /* By this time, all offload related descriptors has been programmed */ | ||
1096 | tx_ring->next_to_use = i; | ||
1097 | } | ||
1098 | |||
1099 | /** | ||
1100 | * i40e_fcoe_invalidate_ddp - invalidates DDP in case of abort | ||
1101 | * @tx_ring: transmit ring for this packet | ||
1102 | * @skb: the packet associated w/ this DDP invalidation, i.e., ABTS | ||
1103 | * @ddp: the SW DDP context for this DDP | ||
1104 | * | ||
1105 | * Programs the Tx context descriptor to do DDP invalidation. | ||
1106 | **/ | ||
1107 | static void i40e_fcoe_invalidate_ddp(struct i40e_ring *tx_ring, | ||
1108 | struct sk_buff *skb, | ||
1109 | struct i40e_fcoe_ddp *ddp) | ||
1110 | { | ||
1111 | struct i40e_tx_context_desc *context_desc; | ||
1112 | int i; | ||
1113 | |||
1114 | if (test_and_set_bit(__I40E_FCOE_DDP_ABORTED, &ddp->flags)) | ||
1115 | return; | ||
1116 | |||
1117 | i = tx_ring->next_to_use; | ||
1118 | context_desc = I40E_TX_CTXTDESC(tx_ring, i); | ||
1119 | i++; | ||
1120 | if (i == tx_ring->count) | ||
1121 | i = 0; | ||
1122 | |||
1123 | context_desc->tunneling_params = cpu_to_le32(0); | ||
1124 | context_desc->l2tag2 = cpu_to_le16(0); | ||
1125 | context_desc->rsvd = cpu_to_le16(0); | ||
1126 | context_desc->type_cmd_tso_mss = cpu_to_le64( | ||
1127 | I40E_TX_DESC_DTYPE_FCOE_CTX | | ||
1128 | (I40E_FCOE_TX_CTX_DESC_OPCODE_DDP_CTX_INVL << | ||
1129 | I40E_TXD_CTX_QW1_CMD_SHIFT) | | ||
1130 | (I40E_FCOE_TX_CTX_DESC_OPCODE_SINGLE_SEND << | ||
1131 | I40E_TXD_CTX_QW1_CMD_SHIFT)); | ||
1132 | tx_ring->next_to_use = i; | ||
1133 | } | ||
1134 | |||
1135 | /** | ||
1136 | * i40e_fcoe_handle_ddp - check we should setup or invalidate DDP | ||
1137 | * @tx_ring: transmit ring for this packet | ||
1138 | * @skb: the packet to be sent out | ||
1139 | * @sof: the SOF to indicate class of service | ||
1140 | * | ||
1141 | * Determine if it is ABTS/READ/XFER_RDY, and finds out if there is | ||
1142 | * a matching SW DDP context for this command. DDP is applicable | ||
1143 | * only in case of READ if initiator or WRITE in case of | ||
1144 | * responder (via checking XFER_RDY). In case this is an ABTS, send | ||
1145 | * just invalidate the context. | ||
1146 | **/ | ||
1147 | static void i40e_fcoe_handle_ddp(struct i40e_ring *tx_ring, | ||
1148 | struct sk_buff *skb, u8 sof) | ||
1149 | { | ||
1150 | struct i40e_pf *pf = tx_ring->vsi->back; | ||
1151 | struct i40e_fcoe *fcoe = &pf->fcoe; | ||
1152 | struct fc_frame_header *fh; | ||
1153 | struct i40e_fcoe_ddp *ddp; | ||
1154 | u32 f_ctl; | ||
1155 | u8 r_ctl; | ||
1156 | u16 xid; | ||
1157 | |||
1158 | fh = (struct fc_frame_header *)skb_transport_header(skb); | ||
1159 | f_ctl = ntoh24(fh->fh_f_ctl); | ||
1160 | r_ctl = fh->fh_r_ctl; | ||
1161 | ddp = NULL; | ||
1162 | |||
1163 | if ((r_ctl == FC_RCTL_DD_DATA_DESC) && (f_ctl & FC_FC_EX_CTX)) { | ||
1164 | /* exchange responder? if so, XFER_RDY for write */ | ||
1165 | xid = ntohs(fh->fh_rx_id); | ||
1166 | if (i40e_fcoe_xid_is_valid(xid)) { | ||
1167 | ddp = &fcoe->ddp[xid]; | ||
1168 | if ((ddp->xid == xid) && | ||
1169 | (test_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags))) | ||
1170 | i40e_fcoe_program_ddp(tx_ring, skb, ddp, sof); | ||
1171 | } | ||
1172 | } else if (r_ctl == FC_RCTL_DD_UNSOL_CMD) { | ||
1173 | /* exchange originator, check READ cmd */ | ||
1174 | xid = ntohs(fh->fh_ox_id); | ||
1175 | if (i40e_fcoe_xid_is_valid(xid)) { | ||
1176 | ddp = &fcoe->ddp[xid]; | ||
1177 | if ((ddp->xid == xid) && | ||
1178 | (!test_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags))) | ||
1179 | i40e_fcoe_program_ddp(tx_ring, skb, ddp, sof); | ||
1180 | } | ||
1181 | } else if (r_ctl == FC_RCTL_BA_ABTS) { | ||
1182 | /* exchange originator, check ABTS */ | ||
1183 | xid = ntohs(fh->fh_ox_id); | ||
1184 | if (i40e_fcoe_xid_is_valid(xid)) { | ||
1185 | ddp = &fcoe->ddp[xid]; | ||
1186 | if ((ddp->xid == xid) && | ||
1187 | (!test_bit(__I40E_FCOE_DDP_TARGET, &ddp->flags))) | ||
1188 | i40e_fcoe_invalidate_ddp(tx_ring, skb, ddp); | ||
1189 | } | ||
1190 | } | ||
1191 | } | ||
1192 | |||
1193 | /** | ||
1194 | * i40e_fcoe_tso - set up FCoE TSO | ||
1195 | * @tx_ring: ring to send buffer on | ||
1196 | * @skb: send buffer | ||
1197 | * @tx_flags: collected send information | ||
1198 | * @hdr_len: the tso header length | ||
1199 | * @sof: the SOF to indicate class of service | ||
1200 | * | ||
1201 | * Note must already have sof checked to be either class 2 or class 3 before | ||
1202 | * calling this function. | ||
1203 | * | ||
1204 | * Returns 1 to indicate sequence segmentation offload is properly setup | ||
1205 | * or returns 0 to indicate no tso is needed, otherwise returns error | ||
1206 | * code to drop the frame. | ||
1207 | **/ | ||
1208 | static int i40e_fcoe_tso(struct i40e_ring *tx_ring, | ||
1209 | struct sk_buff *skb, | ||
1210 | u32 tx_flags, u8 *hdr_len, u8 sof) | ||
1211 | { | ||
1212 | struct i40e_tx_context_desc *context_desc; | ||
1213 | u32 cd_type, cd_cmd, cd_tso_len, cd_mss; | ||
1214 | struct fc_frame_header *fh; | ||
1215 | u64 cd_type_cmd_tso_mss; | ||
1216 | |||
1217 | /* must match gso type as FCoE */ | ||
1218 | if (!skb_is_gso(skb)) | ||
1219 | return 0; | ||
1220 | |||
1221 | /* is it the expected gso type for FCoE ?*/ | ||
1222 | if (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE) { | ||
1223 | netdev_err(skb->dev, | ||
1224 | "wrong gso type %d:expecting SKB_GSO_FCOE\n", | ||
1225 | skb_shinfo(skb)->gso_type); | ||
1226 | return -EINVAL; | ||
1227 | } | ||
1228 | |||
1229 | /* header and trailer are inserted by hw */ | ||
1230 | *hdr_len = skb_transport_offset(skb) + sizeof(struct fc_frame_header) + | ||
1231 | sizeof(struct fcoe_crc_eof); | ||
1232 | |||
1233 | /* check sof to decide a class 2 or 3 TSO */ | ||
1234 | if (likely(i40e_fcoe_sof_is_class3(sof))) | ||
1235 | cd_cmd = I40E_FCOE_TX_CTX_DESC_OPCODE_TSO_FC_CLASS3; | ||
1236 | else | ||
1237 | cd_cmd = I40E_FCOE_TX_CTX_DESC_OPCODE_TSO_FC_CLASS2; | ||
1238 | |||
1239 | /* param field valid? */ | ||
1240 | fh = (struct fc_frame_header *)skb_transport_header(skb); | ||
1241 | if (fh->fh_f_ctl[2] & FC_FC_REL_OFF) | ||
1242 | cd_cmd |= I40E_FCOE_TX_CTX_DESC_RELOFF; | ||
1243 | |||
1244 | /* fill the field values */ | ||
1245 | cd_type = I40E_TX_DESC_DTYPE_FCOE_CTX; | ||
1246 | cd_tso_len = skb->len - *hdr_len; | ||
1247 | cd_mss = skb_shinfo(skb)->gso_size; | ||
1248 | cd_type_cmd_tso_mss = | ||
1249 | ((u64)cd_type << I40E_TXD_CTX_QW1_DTYPE_SHIFT) | | ||
1250 | ((u64)cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT) | | ||
1251 | ((u64)cd_tso_len << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT) | | ||
1252 | ((u64)cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT); | ||
1253 | |||
1254 | /* grab the next descriptor */ | ||
1255 | context_desc = I40E_TX_CTXTDESC(tx_ring, tx_ring->next_to_use); | ||
1256 | tx_ring->next_to_use++; | ||
1257 | if (tx_ring->next_to_use == tx_ring->count) | ||
1258 | tx_ring->next_to_use = 0; | ||
1259 | |||
1260 | context_desc->tunneling_params = 0; | ||
1261 | context_desc->l2tag2 = cpu_to_le16((tx_flags & I40E_TX_FLAGS_VLAN_MASK) | ||
1262 | >> I40E_TX_FLAGS_VLAN_SHIFT); | ||
1263 | context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss); | ||
1264 | |||
1265 | return 1; | ||
1266 | } | ||
1267 | |||
1268 | /** | ||
1269 | * i40e_fcoe_tx_map - build the tx descriptor | ||
1270 | * @tx_ring: ring to send buffer on | ||
1271 | * @skb: send buffer | ||
1272 | * @first: first buffer info buffer to use | ||
1273 | * @tx_flags: collected send information | ||
1274 | * @hdr_len: ptr to the size of the packet header | ||
1275 | * @eof: the frame eof value | ||
1276 | * | ||
1277 | * Note, for FCoE, sof and eof are already checked | ||
1278 | **/ | ||
1279 | static void i40e_fcoe_tx_map(struct i40e_ring *tx_ring, | ||
1280 | struct sk_buff *skb, | ||
1281 | struct i40e_tx_buffer *first, | ||
1282 | u32 tx_flags, u8 hdr_len, u8 eof) | ||
1283 | { | ||
1284 | u32 td_offset = 0; | ||
1285 | u32 td_cmd = 0; | ||
1286 | u32 maclen; | ||
1287 | |||
1288 | /* insert CRC */ | ||
1289 | td_cmd = I40E_TX_DESC_CMD_ICRC; | ||
1290 | |||
1291 | /* setup MACLEN */ | ||
1292 | maclen = skb_network_offset(skb); | ||
1293 | if (tx_flags & I40E_TX_FLAGS_SW_VLAN) | ||
1294 | maclen += sizeof(struct vlan_hdr); | ||
1295 | |||
1296 | if (skb->protocol == htons(ETH_P_FCOE)) { | ||
1297 | /* for FCoE, maclen should exclude ether type */ | ||
1298 | maclen -= 2; | ||
1299 | /* setup type as FCoE and EOF insertion */ | ||
1300 | td_cmd |= (I40E_TX_DESC_CMD_FCOET | i40e_fcoe_ctxt_eof(eof)); | ||
1301 | /* setup FCoELEN and FCLEN */ | ||
1302 | td_offset |= ((((sizeof(struct fcoe_hdr) + 2) >> 2) << | ||
1303 | I40E_TX_DESC_LENGTH_IPLEN_SHIFT) | | ||
1304 | ((sizeof(struct fc_frame_header) >> 2) << | ||
1305 | I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT)); | ||
1306 | /* trim to exclude trailer */ | ||
1307 | pskb_trim(skb, skb->len - sizeof(struct fcoe_crc_eof)); | ||
1308 | } | ||
1309 | |||
1310 | /* MACLEN is ether header length in words not bytes */ | ||
1311 | td_offset |= (maclen >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT; | ||
1312 | |||
1313 | return i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len, | ||
1314 | td_cmd, td_offset); | ||
1315 | } | ||
1316 | |||
1317 | /** | ||
1318 | * i40e_fcoe_set_skb_header - adjust skb header point for FIP/FCoE/FC | ||
1319 | * @skb: the skb to be adjusted | ||
1320 | * | ||
1321 | * Returns true if this skb is a FCoE/FIP or VLAN carried FCoE/FIP and then | ||
1322 | * adjusts the skb header pointers correspondingly. Otherwise, returns false. | ||
1323 | **/ | ||
1324 | static inline int i40e_fcoe_set_skb_header(struct sk_buff *skb) | ||
1325 | { | ||
1326 | __be16 protocol = skb->protocol; | ||
1327 | |||
1328 | skb_reset_mac_header(skb); | ||
1329 | skb->mac_len = sizeof(struct ethhdr); | ||
1330 | if (protocol == htons(ETH_P_8021Q)) { | ||
1331 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)eth_hdr(skb); | ||
1332 | |||
1333 | protocol = veth->h_vlan_encapsulated_proto; | ||
1334 | skb->mac_len += sizeof(struct vlan_hdr); | ||
1335 | } | ||
1336 | |||
1337 | /* FCoE or FIP only */ | ||
1338 | if ((protocol != htons(ETH_P_FIP)) && | ||
1339 | (protocol != htons(ETH_P_FCOE))) | ||
1340 | return -EINVAL; | ||
1341 | |||
1342 | /* set header to L2 of FCoE/FIP */ | ||
1343 | skb_set_network_header(skb, skb->mac_len); | ||
1344 | if (protocol == htons(ETH_P_FIP)) | ||
1345 | return 0; | ||
1346 | |||
1347 | /* set header to L3 of FC */ | ||
1348 | skb_set_transport_header(skb, skb->mac_len + sizeof(struct fcoe_hdr)); | ||
1349 | return 0; | ||
1350 | } | ||
1351 | |||
1352 | /** | ||
1353 | * i40e_fcoe_xmit_frame - transmit buffer | ||
1354 | * @skb: send buffer | ||
1355 | * @netdev: the fcoe netdev | ||
1356 | * | ||
1357 | * Returns 0 if sent, else an error code | ||
1358 | **/ | ||
1359 | static netdev_tx_t i40e_fcoe_xmit_frame(struct sk_buff *skb, | ||
1360 | struct net_device *netdev) | ||
1361 | { | ||
1362 | struct i40e_netdev_priv *np = netdev_priv(skb->dev); | ||
1363 | struct i40e_vsi *vsi = np->vsi; | ||
1364 | struct i40e_ring *tx_ring = vsi->tx_rings[skb->queue_mapping]; | ||
1365 | struct i40e_tx_buffer *first; | ||
1366 | __be16 protocol = skb->protocol; | ||
1367 | |||
1368 | u32 tx_flags = 0; | ||
1369 | u8 hdr_len = 0; | ||
1370 | u8 sof = 0; | ||
1371 | u8 eof = 0; | ||
1372 | int fso; | ||
1373 | |||
1374 | if (i40e_fcoe_set_skb_header(skb)) | ||
1375 | goto out_drop; | ||
1376 | |||
1377 | if (!i40e_xmit_descriptor_count(skb, tx_ring)) | ||
1378 | return NETDEV_TX_BUSY; | ||
1379 | |||
1380 | /* prepare the xmit flags */ | ||
1381 | if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags)) | ||
1382 | goto out_drop; | ||
1383 | |||
1384 | /* record the location of the first descriptor for this packet */ | ||
1385 | first = &tx_ring->tx_bi[tx_ring->next_to_use]; | ||
1386 | |||
1387 | if (protocol == htons(ETH_P_8021Q)) { | ||
1388 | struct vlan_ethhdr *veth = (struct vlan_ethhdr *)eth_hdr(skb); | ||
1389 | |||
1390 | protocol = veth->h_vlan_encapsulated_proto; | ||
1391 | } | ||
1392 | /* FIP is a regular L2 traffic w/o offload */ | ||
1393 | if (protocol == htons(ETH_P_FIP)) | ||
1394 | goto out_send; | ||
1395 | |||
1396 | /* check sof and eof, only supports FC Class 2 or 3 */ | ||
1397 | if (i40e_fcoe_fc_sof(skb, &sof) || i40e_fcoe_fc_eof(skb, &eof)) { | ||
1398 | netdev_err(netdev, "SOF/EOF error:%02x - %02x\n", sof, eof); | ||
1399 | goto out_drop; | ||
1400 | } | ||
1401 | |||
1402 | /* always do FCCRC for FCoE */ | ||
1403 | tx_flags |= I40E_TX_FLAGS_FCCRC; | ||
1404 | |||
1405 | /* check we should do sequence offload */ | ||
1406 | fso = i40e_fcoe_tso(tx_ring, skb, tx_flags, &hdr_len, sof); | ||
1407 | if (fso < 0) | ||
1408 | goto out_drop; | ||
1409 | else if (fso) | ||
1410 | tx_flags |= I40E_TX_FLAGS_FSO; | ||
1411 | else | ||
1412 | i40e_fcoe_handle_ddp(tx_ring, skb, sof); | ||
1413 | |||
1414 | out_send: | ||
1415 | /* send out the packet */ | ||
1416 | i40e_fcoe_tx_map(tx_ring, skb, first, tx_flags, hdr_len, eof); | ||
1417 | |||
1418 | i40e_maybe_stop_tx(tx_ring, DESC_NEEDED); | ||
1419 | return NETDEV_TX_OK; | ||
1420 | |||
1421 | out_drop: | ||
1422 | dev_kfree_skb_any(skb); | ||
1423 | return NETDEV_TX_OK; | ||
1424 | } | ||
1425 | |||
1426 | /** | ||
1427 | * i40e_fcoe_change_mtu - NDO callback to change the Maximum Transfer Unit | ||
1428 | * @netdev: network interface device structure | ||
1429 | * @new_mtu: new value for maximum frame size | ||
1430 | * | ||
1431 | * Returns error as operation not permitted | ||
1432 | * | ||
1433 | **/ | ||
1434 | static int i40e_fcoe_change_mtu(struct net_device *netdev, int new_mtu) | ||
1435 | { | ||
1436 | netdev_warn(netdev, "MTU change is not supported on FCoE interfaces\n"); | ||
1437 | return -EPERM; | ||
1438 | } | ||
1439 | |||
1440 | /** | ||
1441 | * i40e_fcoe_set_features - set the netdev feature flags | ||
1442 | * @netdev: ptr to the netdev being adjusted | ||
1443 | * @features: the feature set that the stack is suggesting | ||
1444 | * | ||
1445 | **/ | ||
1446 | static int i40e_fcoe_set_features(struct net_device *netdev, | ||
1447 | netdev_features_t features) | ||
1448 | { | ||
1449 | struct i40e_netdev_priv *np = netdev_priv(netdev); | ||
1450 | struct i40e_vsi *vsi = np->vsi; | ||
1451 | |||
1452 | if (features & NETIF_F_HW_VLAN_CTAG_RX) | ||
1453 | i40e_vlan_stripping_enable(vsi); | ||
1454 | else | ||
1455 | i40e_vlan_stripping_disable(vsi); | ||
1456 | |||
1457 | return 0; | ||
1458 | } | ||
1459 | |||
1460 | |||
1461 | static const struct net_device_ops i40e_fcoe_netdev_ops = { | ||
1462 | .ndo_open = i40e_open, | ||
1463 | .ndo_stop = i40e_close, | ||
1464 | .ndo_get_stats64 = i40e_get_netdev_stats_struct, | ||
1465 | .ndo_set_rx_mode = i40e_set_rx_mode, | ||
1466 | .ndo_validate_addr = eth_validate_addr, | ||
1467 | .ndo_set_mac_address = i40e_set_mac, | ||
1468 | .ndo_change_mtu = i40e_fcoe_change_mtu, | ||
1469 | .ndo_do_ioctl = i40e_ioctl, | ||
1470 | .ndo_tx_timeout = i40e_tx_timeout, | ||
1471 | .ndo_vlan_rx_add_vid = i40e_vlan_rx_add_vid, | ||
1472 | .ndo_vlan_rx_kill_vid = i40e_vlan_rx_kill_vid, | ||
1473 | .ndo_setup_tc = i40e_setup_tc, | ||
1474 | |||
1475 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1476 | .ndo_poll_controller = i40e_netpoll, | ||
1477 | #endif | ||
1478 | .ndo_start_xmit = i40e_fcoe_xmit_frame, | ||
1479 | .ndo_fcoe_enable = i40e_fcoe_enable, | ||
1480 | .ndo_fcoe_disable = i40e_fcoe_disable, | ||
1481 | .ndo_fcoe_ddp_setup = i40e_fcoe_ddp_get, | ||
1482 | .ndo_fcoe_ddp_done = i40e_fcoe_ddp_put, | ||
1483 | .ndo_fcoe_ddp_target = i40e_fcoe_ddp_target, | ||
1484 | .ndo_set_features = i40e_fcoe_set_features, | ||
1485 | }; | ||
1486 | |||
1487 | /** | ||
1488 | * i40e_fcoe_config_netdev - prepares the VSI context for creating a FCoE VSI | ||
1489 | * @vsi: pointer to the associated VSI struct | ||
1490 | * @ctxt: pointer to the associated VSI context to be passed to HW | ||
1491 | * | ||
1492 | * Returns 0 on success or < 0 on error | ||
1493 | **/ | ||
1494 | void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi) | ||
1495 | { | ||
1496 | struct i40e_hw *hw = &vsi->back->hw; | ||
1497 | struct i40e_pf *pf = vsi->back; | ||
1498 | |||
1499 | if (vsi->type != I40E_VSI_FCOE) | ||
1500 | return; | ||
1501 | |||
1502 | netdev->features = (NETIF_F_HW_VLAN_CTAG_TX | | ||
1503 | NETIF_F_HW_VLAN_CTAG_RX | | ||
1504 | NETIF_F_HW_VLAN_CTAG_FILTER); | ||
1505 | |||
1506 | netdev->vlan_features = netdev->features; | ||
1507 | netdev->vlan_features &= ~(NETIF_F_HW_VLAN_CTAG_TX | | ||
1508 | NETIF_F_HW_VLAN_CTAG_RX | | ||
1509 | NETIF_F_HW_VLAN_CTAG_FILTER); | ||
1510 | netdev->fcoe_ddp_xid = I40E_FCOE_DDP_MAX - 1; | ||
1511 | netdev->features |= NETIF_F_ALL_FCOE; | ||
1512 | netdev->vlan_features |= NETIF_F_ALL_FCOE; | ||
1513 | netdev->hw_features |= netdev->features; | ||
1514 | netdev->priv_flags |= IFF_UNICAST_FLT; | ||
1515 | netdev->priv_flags |= IFF_SUPP_NOFCS; | ||
1516 | |||
1517 | strlcpy(netdev->name, "fcoe%d", IFNAMSIZ-1); | ||
1518 | netdev->mtu = FCOE_MTU; | ||
1519 | SET_NETDEV_DEV(netdev, &pf->pdev->dev); | ||
1520 | i40e_add_filter(vsi, hw->mac.san_addr, 0, false, false); | ||
1521 | i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0, false, false); | ||
1522 | i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0, false, false); | ||
1523 | i40e_add_filter(vsi, FIP_ALL_ENODE_MACS, 0, false, false); | ||
1524 | i40e_add_filter(vsi, FIP_ALL_VN2VN_MACS, 0, false, false); | ||
1525 | i40e_add_filter(vsi, FIP_ALL_P2P_MACS, 0, false, false); | ||
1526 | |||
1527 | /* use san mac */ | ||
1528 | ether_addr_copy(netdev->dev_addr, hw->mac.san_addr); | ||
1529 | ether_addr_copy(netdev->perm_addr, hw->mac.san_addr); | ||
1530 | /* fcoe netdev ops */ | ||
1531 | netdev->netdev_ops = &i40e_fcoe_netdev_ops; | ||
1532 | } | ||
1533 | |||
1534 | /** | ||
1535 | * i40e_fcoe_vsi_setup - allocate and set up FCoE VSI | ||
1536 | * @pf: the pf that VSI is associated with | ||
1537 | * | ||
1538 | **/ | ||
1539 | void i40e_fcoe_vsi_setup(struct i40e_pf *pf) | ||
1540 | { | ||
1541 | struct i40e_vsi *vsi; | ||
1542 | u16 seid; | ||
1543 | int i; | ||
1544 | |||
1545 | if (!(pf->flags & I40E_FLAG_FCOE_ENABLED)) | ||
1546 | return; | ||
1547 | |||
1548 | BUG_ON(!pf->vsi[pf->lan_vsi]); | ||
1549 | |||
1550 | for (i = 0; i < pf->num_alloc_vsi; i++) { | ||
1551 | vsi = pf->vsi[i]; | ||
1552 | if (vsi && vsi->type == I40E_VSI_FCOE) { | ||
1553 | dev_warn(&pf->pdev->dev, | ||
1554 | "FCoE VSI already created\n"); | ||
1555 | return; | ||
1556 | } | ||
1557 | } | ||
1558 | |||
1559 | seid = pf->vsi[pf->lan_vsi]->seid; | ||
1560 | vsi = i40e_vsi_setup(pf, I40E_VSI_FCOE, seid, 0); | ||
1561 | if (vsi) { | ||
1562 | dev_dbg(&pf->pdev->dev, | ||
1563 | "Successfully created FCoE VSI seid %d id %d uplink_seid %d pf seid %d\n", | ||
1564 | vsi->seid, vsi->id, vsi->uplink_seid, seid); | ||
1565 | } else { | ||
1566 | dev_info(&pf->pdev->dev, "Failed to create FCoE VSI\n"); | ||
1567 | } | ||
1568 | } | ||
diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.h b/drivers/net/ethernet/intel/i40e/i40e_fcoe.h new file mode 100644 index 000000000000..21e0f582031c --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.h | |||
@@ -0,0 +1,128 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * Intel Ethernet Controller XL710 Family Linux Driver | ||
4 | * Copyright(c) 2013 - 2014 Intel Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License along | ||
16 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * The full GNU General Public License is included in this distribution in | ||
19 | * the file called "COPYING". | ||
20 | * | ||
21 | * Contact Information: | ||
22 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
23 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
24 | * | ||
25 | ******************************************************************************/ | ||
26 | |||
27 | #ifndef _I40E_FCOE_H_ | ||
28 | #define _I40E_FCOE_H_ | ||
29 | |||
30 | /* FCoE HW context helper macros */ | ||
31 | #define I40E_DDP_CONTEXT_DESC(R, i) \ | ||
32 | (&(((struct i40e_fcoe_ddp_context_desc *)((R)->desc))[i])) | ||
33 | |||
34 | #define I40E_QUEUE_CONTEXT_DESC(R, i) \ | ||
35 | (&(((struct i40e_fcoe_queue_context_desc *)((R)->desc))[i])) | ||
36 | |||
37 | #define I40E_FILTER_CONTEXT_DESC(R, i) \ | ||
38 | (&(((struct i40e_fcoe_filter_context_desc *)((R)->desc))[i])) | ||
39 | |||
40 | |||
41 | /* receive queue descriptor filter status for FCoE */ | ||
42 | #define I40E_RX_DESC_FLTSTAT_FCMASK 0x3 | ||
43 | #define I40E_RX_DESC_FLTSTAT_NOMTCH 0x0 /* no ddp context match */ | ||
44 | #define I40E_RX_DESC_FLTSTAT_NODDP 0x1 /* no ddp due to error */ | ||
45 | #define I40E_RX_DESC_FLTSTAT_DDP 0x2 /* DDPed payload, post header */ | ||
46 | #define I40E_RX_DESC_FLTSTAT_FCPRSP 0x3 /* FCP_RSP */ | ||
47 | |||
48 | /* receive queue descriptor error codes for FCoE */ | ||
49 | #define I40E_RX_DESC_FCOE_ERROR_MASK \ | ||
50 | (I40E_RX_DESC_ERROR_L3L4E_PROT | \ | ||
51 | I40E_RX_DESC_ERROR_L3L4E_FC | \ | ||
52 | I40E_RX_DESC_ERROR_L3L4E_DMAC_ERR | \ | ||
53 | I40E_RX_DESC_ERROR_L3L4E_DMAC_WARN) | ||
54 | |||
55 | /* receive queue descriptor programming error */ | ||
56 | #define I40E_RX_PROG_FCOE_ERROR_TBL_FULL(e) \ | ||
57 | (((e) >> I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) & 0x1) | ||
58 | |||
59 | #define I40E_RX_PROG_FCOE_ERROR_CONFLICT(e) \ | ||
60 | (((e) >> I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) & 0x1) | ||
61 | |||
62 | #define I40E_RX_PROG_FCOE_ERROR_TBL_FULL_BIT \ | ||
63 | (1 << I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) | ||
64 | #define I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT \ | ||
65 | (1 << I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) | ||
66 | |||
67 | #define I40E_RX_PROG_FCOE_ERROR_INVLFAIL(e) \ | ||
68 | I40E_RX_PROG_FCOE_ERROR_CONFLICT(e) | ||
69 | #define I40E_RX_PROG_FCOE_ERROR_INVLFAIL_BIT \ | ||
70 | I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT | ||
71 | |||
72 | /* FCoE DDP related definitions */ | ||
73 | #define I40E_FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ | ||
74 | #define I40E_FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */ | ||
75 | #define I40E_FCOE_DDP_BUFFCNT_MAX 512 /* 9 bits bufcnt */ | ||
76 | #define I40E_FCOE_DDP_PTR_ALIGN 16 | ||
77 | #define I40E_FCOE_DDP_PTR_MAX (I40E_FCOE_DDP_BUFFCNT_MAX * sizeof(dma_addr_t)) | ||
78 | #define I40E_FCOE_DDP_BUF_MIN 4096 | ||
79 | #define I40E_FCOE_DDP_MAX 2048 | ||
80 | #define I40E_FCOE_FILTER_CTX_QW1_PCTYPE_SHIFT 8 | ||
81 | |||
82 | /* supported netdev features for FCoE */ | ||
83 | #define I40E_FCOE_NETIF_FEATURES (NETIF_F_ALL_FCOE | \ | ||
84 | NETIF_F_HW_VLAN_CTAG_TX | \ | ||
85 | NETIF_F_HW_VLAN_CTAG_RX | \ | ||
86 | NETIF_F_HW_VLAN_CTAG_FILTER) | ||
87 | |||
88 | /* DDP context flags */ | ||
89 | enum i40e_fcoe_ddp_flags { | ||
90 | __I40E_FCOE_DDP_NONE = 1, | ||
91 | __I40E_FCOE_DDP_TARGET, | ||
92 | __I40E_FCOE_DDP_INITALIZED, | ||
93 | __I40E_FCOE_DDP_PROGRAMMED, | ||
94 | __I40E_FCOE_DDP_DONE, | ||
95 | __I40E_FCOE_DDP_ABORTED, | ||
96 | __I40E_FCOE_DDP_UNMAPPED, | ||
97 | }; | ||
98 | |||
99 | /* DDP SW context struct */ | ||
100 | struct i40e_fcoe_ddp { | ||
101 | int len; | ||
102 | u16 xid; | ||
103 | u16 firstoff; | ||
104 | u16 lastsize; | ||
105 | u16 list_len; | ||
106 | u8 fcerr; | ||
107 | u8 prerr; | ||
108 | unsigned long flags; | ||
109 | unsigned int sgc; | ||
110 | struct scatterlist *sgl; | ||
111 | dma_addr_t udp; | ||
112 | u64 *udl; | ||
113 | struct dma_pool *pool; | ||
114 | |||
115 | }; | ||
116 | |||
117 | struct i40e_fcoe_ddp_pool { | ||
118 | struct dma_pool *pool; | ||
119 | }; | ||
120 | |||
121 | struct i40e_fcoe { | ||
122 | unsigned long mode; | ||
123 | atomic_t refcnt; | ||
124 | struct i40e_fcoe_ddp_pool __percpu *ddp_pool; | ||
125 | struct i40e_fcoe_ddp ddp[I40E_FCOE_DDP_MAX]; | ||
126 | }; | ||
127 | |||
128 | #endif /* _I40E_FCOE_H_ */ | ||