diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ixgbe/ixgbe.h | 3 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_fcoe.c | 340 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_fcoe.h | 2 |
3 files changed, 344 insertions, 1 deletions
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 06859f687f19..5581fa3976df 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h | |||
@@ -336,6 +336,9 @@ struct ixgbe_adapter { | |||
336 | struct timer_list sfp_timer; | 336 | struct timer_list sfp_timer; |
337 | struct work_struct multispeed_fiber_task; | 337 | struct work_struct multispeed_fiber_task; |
338 | struct work_struct sfp_config_module_task; | 338 | struct work_struct sfp_config_module_task; |
339 | #ifdef IXGBE_FCOE | ||
340 | struct ixgbe_fcoe fcoe; | ||
341 | #endif /* IXGBE_FCOE */ | ||
339 | u64 rsc_count; | 342 | u64 rsc_count; |
340 | u32 wol; | 343 | u32 wol; |
341 | u16 eeprom_version; | 344 | u16 eeprom_version; |
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index e20facd1f2df..a11c6207b748 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c | |||
@@ -36,6 +36,311 @@ | |||
36 | #include <scsi/libfcoe.h> | 36 | #include <scsi/libfcoe.h> |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * ixgbe_rx_is_fcoe - check the rx desc for incoming pkt type | ||
40 | * @rx_desc: advanced rx descriptor | ||
41 | * | ||
42 | * Returns : true if it is FCoE pkt | ||
43 | */ | ||
44 | static inline bool ixgbe_rx_is_fcoe(union ixgbe_adv_rx_desc *rx_desc) | ||
45 | { | ||
46 | u16 p; | ||
47 | |||
48 | p = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info); | ||
49 | if (p & IXGBE_RXDADV_PKTTYPE_ETQF) { | ||
50 | p &= IXGBE_RXDADV_PKTTYPE_ETQF_MASK; | ||
51 | p >>= IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT; | ||
52 | return p == IXGBE_ETQF_FILTER_FCOE; | ||
53 | } | ||
54 | return false; | ||
55 | } | ||
56 | |||
57 | /** | ||
58 | * ixgbe_fcoe_clear_ddp - clear the given ddp context | ||
59 | * @ddp - ptr to the ixgbe_fcoe_ddp | ||
60 | * | ||
61 | * Returns : none | ||
62 | * | ||
63 | */ | ||
64 | static inline void ixgbe_fcoe_clear_ddp(struct ixgbe_fcoe_ddp *ddp) | ||
65 | { | ||
66 | ddp->len = 0; | ||
67 | ddp->err = 0; | ||
68 | ddp->udl = NULL; | ||
69 | ddp->udp = 0UL; | ||
70 | ddp->sgl = NULL; | ||
71 | ddp->sgc = 0; | ||
72 | } | ||
73 | |||
74 | /** | ||
75 | * ixgbe_fcoe_ddp_put - free the ddp context for a given xid | ||
76 | * @netdev: the corresponding net_device | ||
77 | * @xid: the xid that corresponding ddp will be freed | ||
78 | * | ||
79 | * This is the implementation of net_device_ops.ndo_fcoe_ddp_done | ||
80 | * and it is expected to be called by ULD, i.e., FCP layer of libfc | ||
81 | * to release the corresponding ddp context when the I/O is done. | ||
82 | * | ||
83 | * Returns : data length already ddp-ed in bytes | ||
84 | */ | ||
85 | int ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid) | ||
86 | { | ||
87 | int len = 0; | ||
88 | struct ixgbe_fcoe *fcoe; | ||
89 | struct ixgbe_adapter *adapter; | ||
90 | struct ixgbe_fcoe_ddp *ddp; | ||
91 | |||
92 | if (!netdev) | ||
93 | goto out_ddp_put; | ||
94 | |||
95 | if (xid >= IXGBE_FCOE_DDP_MAX) | ||
96 | goto out_ddp_put; | ||
97 | |||
98 | adapter = netdev_priv(netdev); | ||
99 | fcoe = &adapter->fcoe; | ||
100 | ddp = &fcoe->ddp[xid]; | ||
101 | if (!ddp->udl) | ||
102 | goto out_ddp_put; | ||
103 | |||
104 | len = ddp->len; | ||
105 | /* if there an error, force to invalidate ddp context */ | ||
106 | if (ddp->err) { | ||
107 | spin_lock_bh(&fcoe->lock); | ||
108 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCFLT, 0); | ||
109 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCFLTRW, | ||
110 | (xid | IXGBE_FCFLTRW_WE)); | ||
111 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCBUFF, 0); | ||
112 | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCDMARW, | ||
113 | (xid | IXGBE_FCDMARW_WE)); | ||
114 | spin_unlock_bh(&fcoe->lock); | ||
115 | } | ||
116 | if (ddp->sgl) | ||
117 | pci_unmap_sg(adapter->pdev, ddp->sgl, ddp->sgc, | ||
118 | DMA_FROM_DEVICE); | ||
119 | pci_pool_free(fcoe->pool, ddp->udl, ddp->udp); | ||
120 | ixgbe_fcoe_clear_ddp(ddp); | ||
121 | |||
122 | out_ddp_put: | ||
123 | return len; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * ixgbe_fcoe_ddp_get - called to set up ddp context | ||
128 | * @netdev: the corresponding net_device | ||
129 | * @xid: the exchange id requesting ddp | ||
130 | * @sgl: the scatter-gather list for this request | ||
131 | * @sgc: the number of scatter-gather items | ||
132 | * | ||
133 | * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup | ||
134 | * and is expected to be called from ULD, e.g., FCP layer of libfc | ||
135 | * to set up ddp for the corresponding xid of the given sglist for | ||
136 | * the corresponding I/O. | ||
137 | * | ||
138 | * Returns : 1 for success and 0 for no ddp | ||
139 | */ | ||
140 | int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, | ||
141 | struct scatterlist *sgl, unsigned int sgc) | ||
142 | { | ||
143 | struct ixgbe_adapter *adapter; | ||
144 | struct ixgbe_hw *hw; | ||
145 | struct ixgbe_fcoe *fcoe; | ||
146 | struct ixgbe_fcoe_ddp *ddp; | ||
147 | struct scatterlist *sg; | ||
148 | unsigned int i, j, dmacount; | ||
149 | unsigned int len; | ||
150 | static const unsigned int bufflen = 4096; | ||
151 | unsigned int firstoff = 0; | ||
152 | unsigned int lastsize; | ||
153 | unsigned int thisoff = 0; | ||
154 | unsigned int thislen = 0; | ||
155 | u32 fcbuff, fcdmarw, fcfltrw; | ||
156 | dma_addr_t addr; | ||
157 | |||
158 | if (!netdev || !sgl) | ||
159 | return 0; | ||
160 | |||
161 | adapter = netdev_priv(netdev); | ||
162 | if (xid >= IXGBE_FCOE_DDP_MAX) { | ||
163 | DPRINTK(DRV, WARNING, "xid=0x%x out-of-range\n", xid); | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | fcoe = &adapter->fcoe; | ||
168 | if (!fcoe->pool) { | ||
169 | DPRINTK(DRV, WARNING, "xid=0x%x no ddp pool for fcoe\n", xid); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | ddp = &fcoe->ddp[xid]; | ||
174 | if (ddp->sgl) { | ||
175 | DPRINTK(DRV, ERR, "xid 0x%x w/ non-null sgl=%p nents=%d\n", | ||
176 | xid, ddp->sgl, ddp->sgc); | ||
177 | return 0; | ||
178 | } | ||
179 | ixgbe_fcoe_clear_ddp(ddp); | ||
180 | |||
181 | /* setup dma from scsi command sgl */ | ||
182 | dmacount = pci_map_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE); | ||
183 | if (dmacount == 0) { | ||
184 | DPRINTK(DRV, ERR, "xid 0x%x DMA map error\n", xid); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | /* alloc the udl from our ddp pool */ | ||
189 | ddp->udl = pci_pool_alloc(fcoe->pool, GFP_KERNEL, &ddp->udp); | ||
190 | if (!ddp->udl) { | ||
191 | DPRINTK(DRV, ERR, "failed allocated ddp context\n"); | ||
192 | goto out_noddp_unmap; | ||
193 | } | ||
194 | ddp->sgl = sgl; | ||
195 | ddp->sgc = sgc; | ||
196 | |||
197 | j = 0; | ||
198 | for_each_sg(sgl, sg, dmacount, i) { | ||
199 | addr = sg_dma_address(sg); | ||
200 | len = sg_dma_len(sg); | ||
201 | while (len) { | ||
202 | /* get the offset of length of current buffer */ | ||
203 | thisoff = addr & ((dma_addr_t)bufflen - 1); | ||
204 | thislen = min((bufflen - thisoff), len); | ||
205 | /* | ||
206 | * all but the 1st buffer (j == 0) | ||
207 | * must be aligned on bufflen | ||
208 | */ | ||
209 | if ((j != 0) && (thisoff)) | ||
210 | goto out_noddp_free; | ||
211 | /* | ||
212 | * all but the last buffer | ||
213 | * ((i == (dmacount - 1)) && (thislen == len)) | ||
214 | * must end at bufflen | ||
215 | */ | ||
216 | if (((i != (dmacount - 1)) || (thislen != len)) | ||
217 | && ((thislen + thisoff) != bufflen)) | ||
218 | goto out_noddp_free; | ||
219 | |||
220 | ddp->udl[j] = (u64)(addr - thisoff); | ||
221 | /* only the first buffer may have none-zero offset */ | ||
222 | if (j == 0) | ||
223 | firstoff = thisoff; | ||
224 | len -= thislen; | ||
225 | addr += thislen; | ||
226 | j++; | ||
227 | /* max number of buffers allowed in one DDP context */ | ||
228 | if (j > IXGBE_BUFFCNT_MAX) { | ||
229 | DPRINTK(DRV, ERR, "xid=%x:%d,%d,%d:addr=%llx " | ||
230 | "not enough descriptors\n", | ||
231 | xid, i, j, dmacount, (u64)addr); | ||
232 | goto out_noddp_free; | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | /* only the last buffer may have non-full bufflen */ | ||
237 | lastsize = thisoff + thislen; | ||
238 | |||
239 | fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); | ||
240 | fcbuff |= (j << IXGBE_FCBUFF_BUFFCNT_SHIFT); | ||
241 | fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); | ||
242 | fcbuff |= (IXGBE_FCBUFF_VALID); | ||
243 | |||
244 | fcdmarw = xid; | ||
245 | fcdmarw |= IXGBE_FCDMARW_WE; | ||
246 | fcdmarw |= (lastsize << IXGBE_FCDMARW_LASTSIZE_SHIFT); | ||
247 | |||
248 | fcfltrw = xid; | ||
249 | fcfltrw |= IXGBE_FCFLTRW_WE; | ||
250 | |||
251 | /* program DMA context */ | ||
252 | hw = &adapter->hw; | ||
253 | spin_lock_bh(&fcoe->lock); | ||
254 | IXGBE_WRITE_REG(hw, IXGBE_FCPTRL, ddp->udp & DMA_32BIT_MASK); | ||
255 | IXGBE_WRITE_REG(hw, IXGBE_FCPTRH, (u64)ddp->udp >> 32); | ||
256 | IXGBE_WRITE_REG(hw, IXGBE_FCBUFF, fcbuff); | ||
257 | IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, fcdmarw); | ||
258 | /* program filter context */ | ||
259 | IXGBE_WRITE_REG(hw, IXGBE_FCPARAM, 0); | ||
260 | IXGBE_WRITE_REG(hw, IXGBE_FCFLT, IXGBE_FCFLT_VALID); | ||
261 | IXGBE_WRITE_REG(hw, IXGBE_FCFLTRW, fcfltrw); | ||
262 | spin_unlock_bh(&fcoe->lock); | ||
263 | |||
264 | return 1; | ||
265 | |||
266 | out_noddp_free: | ||
267 | pci_pool_free(fcoe->pool, ddp->udl, ddp->udp); | ||
268 | ixgbe_fcoe_clear_ddp(ddp); | ||
269 | |||
270 | out_noddp_unmap: | ||
271 | pci_unmap_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /** | ||
276 | * ixgbe_fcoe_ddp - check ddp status and mark it done | ||
277 | * @adapter: ixgbe adapter | ||
278 | * @rx_desc: advanced rx descriptor | ||
279 | * @skb: the skb holding the received data | ||
280 | * | ||
281 | * This checks ddp status. | ||
282 | * | ||
283 | * Returns : 0 for success and skb will not be delivered to ULD | ||
284 | */ | ||
285 | int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, | ||
286 | union ixgbe_adv_rx_desc *rx_desc, | ||
287 | struct sk_buff *skb) | ||
288 | { | ||
289 | u16 xid; | ||
290 | u32 sterr, fceofe, fcerr, fcstat; | ||
291 | int rc = -EINVAL; | ||
292 | struct ixgbe_fcoe *fcoe; | ||
293 | struct ixgbe_fcoe_ddp *ddp; | ||
294 | struct fc_frame_header *fh; | ||
295 | |||
296 | if (!ixgbe_rx_is_fcoe(rx_desc)) | ||
297 | goto ddp_out; | ||
298 | |||
299 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
300 | sterr = le32_to_cpu(rx_desc->wb.upper.status_error); | ||
301 | fcerr = (sterr & IXGBE_RXDADV_ERR_FCERR); | ||
302 | fceofe = (sterr & IXGBE_RXDADV_ERR_FCEOFE); | ||
303 | if (fcerr == IXGBE_FCERR_BADCRC) | ||
304 | skb->ip_summed = CHECKSUM_NONE; | ||
305 | |||
306 | skb_reset_network_header(skb); | ||
307 | skb_set_transport_header(skb, skb_network_offset(skb) + | ||
308 | sizeof(struct fcoe_hdr)); | ||
309 | fh = (struct fc_frame_header *)skb_transport_header(skb); | ||
310 | xid = be16_to_cpu(fh->fh_ox_id); | ||
311 | if (xid >= IXGBE_FCOE_DDP_MAX) | ||
312 | goto ddp_out; | ||
313 | |||
314 | fcoe = &adapter->fcoe; | ||
315 | ddp = &fcoe->ddp[xid]; | ||
316 | if (!ddp->udl) | ||
317 | goto ddp_out; | ||
318 | |||
319 | ddp->err = (fcerr | fceofe); | ||
320 | if (ddp->err) | ||
321 | goto ddp_out; | ||
322 | |||
323 | fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT); | ||
324 | if (fcstat) { | ||
325 | /* update length of DDPed data */ | ||
326 | ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); | ||
327 | /* unmap the sg list when FCP_RSP is received */ | ||
328 | if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_FCPRSP) { | ||
329 | pci_unmap_sg(adapter->pdev, ddp->sgl, | ||
330 | ddp->sgc, DMA_FROM_DEVICE); | ||
331 | ddp->sgl = NULL; | ||
332 | ddp->sgc = 0; | ||
333 | } | ||
334 | /* return 0 to bypass going to ULD for DDPed data */ | ||
335 | if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_DDP) | ||
336 | rc = 0; | ||
337 | } | ||
338 | |||
339 | ddp_out: | ||
340 | return rc; | ||
341 | } | ||
342 | |||
343 | /** | ||
39 | * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO) | 344 | * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO) |
40 | * @adapter: ixgbe adapter | 345 | * @adapter: ixgbe adapter |
41 | * @tx_ring: tx desc ring | 346 | * @tx_ring: tx desc ring |
@@ -178,7 +483,20 @@ int ixgbe_fso(struct ixgbe_adapter *adapter, | |||
178 | void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) | 483 | void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) |
179 | { | 484 | { |
180 | struct ixgbe_hw *hw = &adapter->hw; | 485 | struct ixgbe_hw *hw = &adapter->hw; |
486 | struct ixgbe_fcoe *fcoe = &adapter->fcoe; | ||
487 | |||
488 | /* create the pool for ddp if not created yet */ | ||
489 | if (!fcoe->pool) { | ||
490 | /* allocate ddp pool */ | ||
491 | fcoe->pool = pci_pool_create("ixgbe_fcoe_ddp", | ||
492 | adapter->pdev, IXGBE_FCPTR_MAX, | ||
493 | IXGBE_FCPTR_ALIGN, PAGE_SIZE); | ||
494 | if (!fcoe->pool) | ||
495 | DPRINTK(DRV, ERR, | ||
496 | "failed to allocated FCoE DDP pool\n"); | ||
181 | 497 | ||
498 | spin_lock_init(&fcoe->lock); | ||
499 | } | ||
182 | /* L2 filter for FCoE: default to queue 0 */ | 500 | /* L2 filter for FCoE: default to queue 0 */ |
183 | IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), | 501 | IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), |
184 | (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); | 502 | (ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN)); |
@@ -190,3 +508,25 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) | |||
190 | IXGBE_FCRXCTRL_FCCRCBO | | 508 | IXGBE_FCRXCTRL_FCCRCBO | |
191 | (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); | 509 | (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); |
192 | } | 510 | } |
511 | |||
512 | /** | ||
513 | * ixgbe_cleanup_fcoe - release all fcoe ddp context resources | ||
514 | * @adapter : ixgbe adapter | ||
515 | * | ||
516 | * Cleans up outstanding ddp context resources | ||
517 | * | ||
518 | * Returns : none | ||
519 | */ | ||
520 | void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) | ||
521 | { | ||
522 | int i; | ||
523 | struct ixgbe_fcoe *fcoe = &adapter->fcoe; | ||
524 | |||
525 | /* release ddp resource */ | ||
526 | if (fcoe->pool) { | ||
527 | for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++) | ||
528 | ixgbe_fcoe_ddp_put(adapter->netdev, i); | ||
529 | pci_pool_destroy(fcoe->pool); | ||
530 | fcoe->pool = NULL; | ||
531 | } | ||
532 | } | ||
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h index d054c1dada50..b7f9b63aa49f 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ixgbe/ixgbe_fcoe.h | |||
@@ -54,7 +54,7 @@ struct ixgbe_fcoe_ddp { | |||
54 | unsigned int sgc; | 54 | unsigned int sgc; |
55 | struct scatterlist *sgl; | 55 | struct scatterlist *sgl; |
56 | dma_addr_t udp; | 56 | dma_addr_t udp; |
57 | unsigned long *udl; | 57 | u64 *udl; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | struct ixgbe_fcoe { | 60 | struct ixgbe_fcoe { |