aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorYi Zou <yi.zou@intel.com>2009-05-13 09:11:29 -0400
committerDavid S. Miller <davem@davemloft.net>2009-05-17 15:00:07 -0400
commitd0ed89373f2da1a0d83697d87441e519caf18cf7 (patch)
tree8917458d830101a8b340725240cb25e467a3d076 /drivers/net
parenteacd73f79a106c6a0bc429003ab691024860ab2d (diff)
ixgbe: Add infrastructure code for FCoE large receive offload to 82599
This adds infrastructure code for FCoE Rx side offload feature to 82599, which provides large receive offload for FCoE by Direct Data Placement (DDP). The ixgbe_fcoe_ddp_get() and ixgbe_fcoe_ddp_put() pair corresponds to the netdev support to FCoE by the function pointers provided in net_device_ops as ndo_fcoe_ddp_setup and ndo_fcoe_ddp_done. The implementation of these in ixgbe is shown in the next patch. Signed-off-by: Yi Zou <yi.zou@intel.com> Signed-off-by: Chris Leech <christopher.leech@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ixgbe/ixgbe.h3
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.c340
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.h2
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 */
44static 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 */
64static 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 */
85int 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
122out_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 */
140int 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
266out_noddp_free:
267 pci_pool_free(fcoe->pool, ddp->udl, ddp->udp);
268 ixgbe_fcoe_clear_ddp(ddp);
269
270out_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 */
285int 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
339ddp_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,
178void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) 483void 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 */
520void 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
60struct ixgbe_fcoe { 60struct ixgbe_fcoe {