cxgb_lro.c revision 1.1.4.2 1 1.1.4.2 rmind /**************************************************************************
2 1.1.4.2 rmind
3 1.1.4.2 rmind Copyright (c) 2007, Chelsio Inc.
4 1.1.4.2 rmind All rights reserved.
5 1.1.4.2 rmind
6 1.1.4.2 rmind Redistribution and use in source and binary forms, with or without
7 1.1.4.2 rmind modification, are permitted provided that the following conditions are met:
8 1.1.4.2 rmind
9 1.1.4.2 rmind 1. Redistributions of source code must retain the above copyright notice,
10 1.1.4.2 rmind this list of conditions and the following disclaimer.
11 1.1.4.2 rmind
12 1.1.4.2 rmind 2. Neither the name of the Chelsio Corporation nor the names of its
13 1.1.4.2 rmind contributors may be used to endorse or promote products derived from
14 1.1.4.2 rmind this software without specific prior written permission.
15 1.1.4.2 rmind
16 1.1.4.2 rmind THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 1.1.4.2 rmind AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1.4.2 rmind IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1.4.2 rmind ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 1.1.4.2 rmind LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1.4.2 rmind CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1.4.2 rmind SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1.4.2 rmind INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1.4.2 rmind CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1.4.2 rmind ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1.4.2 rmind POSSIBILITY OF SUCH DAMAGE.
27 1.1.4.2 rmind
28 1.1.4.2 rmind ***************************************************************************/
29 1.1.4.2 rmind
30 1.1.4.2 rmind #include <sys/cdefs.h>
31 1.1.4.2 rmind __KERNEL_RCSID(0, "$NetBSD: cxgb_lro.c,v 1.1.4.2 2010/05/30 05:17:40 rmind Exp $");
32 1.1.4.2 rmind
33 1.1.4.2 rmind
34 1.1.4.2 rmind #include <sys/param.h>
35 1.1.4.2 rmind #include <sys/systm.h>
36 1.1.4.2 rmind #include <sys/kernel.h>
37 1.1.4.2 rmind #include <sys/conf.h>
38 1.1.4.2 rmind #include <machine/bus.h>
39 1.1.4.2 rmind #include <sys/queue.h>
40 1.1.4.2 rmind
41 1.1.4.2 rmind #include <netinet/in_systm.h>
42 1.1.4.2 rmind #include <netinet/in.h>
43 1.1.4.2 rmind #include <netinet/ip.h>
44 1.1.4.2 rmind #include <netinet/tcp.h>
45 1.1.4.2 rmind
46 1.1.4.2 rmind
47 1.1.4.2 rmind #ifdef CONFIG_DEFINED
48 1.1.4.2 rmind #include <dev/pci/cxgb/cxgb_include.h>
49 1.1.4.2 rmind
50 1.1.4.2 rmind #include <machine/in_cksum.h>
51 1.1.4.2 rmind #endif
52 1.1.4.2 rmind
53 1.1.4.2 rmind #include "cxgb_include.h"
54 1.1.4.2 rmind
55 1.1.4.2 rmind #ifndef M_LRO
56 1.1.4.2 rmind #define M_LRO 0x0200
57 1.1.4.2 rmind #endif
58 1.1.4.2 rmind
59 1.1.4.2 rmind #ifdef DEBUG
60 1.1.4.2 rmind #define MBUF_HEADER_CHECK(m) do { \
61 1.1.4.2 rmind if ((m->m_len == 0) || (m->m_pkthdr.len == 0) \
62 1.1.4.2 rmind || ((m->m_flags & M_PKTHDR) == 0)) \
63 1.1.4.2 rmind panic("lro_flush_session - mbuf len=%d pktlen=%d flags=0x%x\n", \
64 1.1.4.2 rmind m->m_len, m->m_pkthdr.len, m->m_flags); \
65 1.1.4.2 rmind if ((m->m_flags & M_PKTHDR) == 0) \
66 1.1.4.2 rmind panic("first mbuf is not packet header - flags=0x%x\n", \
67 1.1.4.2 rmind m->m_flags); \
68 1.1.4.2 rmind if ((m->m_len < ETHER_HDR_LEN) || (m->m_pkthdr.len < ETHER_HDR_LEN)) \
69 1.1.4.2 rmind panic("packet too small len=%d pktlen=%d\n", \
70 1.1.4.2 rmind m->m_len, m->m_pkthdr.len);\
71 1.1.4.2 rmind } while (0)
72 1.1.4.2 rmind #else
73 1.1.4.2 rmind #define MBUF_HEADER_CHECK(m)
74 1.1.4.2 rmind #endif
75 1.1.4.2 rmind
76 1.1.4.2 rmind #define IPH_OFFSET (2 + sizeof (struct cpl_rx_pkt) + ETHER_HDR_LEN)
77 1.1.4.2 rmind #define LRO_SESSION_IDX_HINT_HASH(hash) (hash & (MAX_LRO_SES - 1))
78 1.1.4.2 rmind #define LRO_IDX_INC(idx) idx = (idx + 1) & (MAX_LRO_SES - 1)
79 1.1.4.2 rmind
80 1.1.4.2 rmind static __inline int
81 1.1.4.2 rmind lro_match(struct mbuf *m, struct ip *ih, struct tcphdr *th)
82 1.1.4.2 rmind {
83 1.1.4.2 rmind struct ip *sih = (struct ip *)(mtod(m, uint8_t *) + IPH_OFFSET);
84 1.1.4.2 rmind struct tcphdr *sth = (struct tcphdr *) (sih + 1);
85 1.1.4.2 rmind
86 1.1.4.2 rmind return (th->th_sport == sth->th_sport &&
87 1.1.4.2 rmind th->th_dport == sth->th_dport &&
88 1.1.4.2 rmind ih->ip_src.s_addr == sih->ip_src.s_addr &&
89 1.1.4.2 rmind ih->ip_dst.s_addr == sih->ip_dst.s_addr);
90 1.1.4.2 rmind }
91 1.1.4.2 rmind
92 1.1.4.2 rmind static __inline struct t3_lro_session *
93 1.1.4.2 rmind lro_lookup(struct lro_state *l, int idx, struct ip *ih, struct tcphdr *th)
94 1.1.4.2 rmind {
95 1.1.4.2 rmind struct t3_lro_session *s = NULL;
96 1.1.4.2 rmind int active = l->nactive;
97 1.1.4.2 rmind
98 1.1.4.2 rmind while (active) {
99 1.1.4.2 rmind s = &l->sess[idx];
100 1.1.4.2 rmind if (s->head) {
101 1.1.4.2 rmind if (lro_match(s->head, ih, th))
102 1.1.4.2 rmind break;
103 1.1.4.2 rmind active--;
104 1.1.4.2 rmind }
105 1.1.4.2 rmind LRO_IDX_INC(idx);
106 1.1.4.2 rmind }
107 1.1.4.2 rmind
108 1.1.4.2 rmind return (s);
109 1.1.4.2 rmind }
110 1.1.4.2 rmind
111 1.1.4.2 rmind static __inline int
112 1.1.4.2 rmind can_lro_packet(struct cpl_rx_pkt *cpl, unsigned int rss_hi)
113 1.1.4.2 rmind {
114 1.1.4.2 rmind struct ether_header *eh = (struct ether_header *)(cpl + 1);
115 1.1.4.2 rmind struct ip *ih = (struct ip *)(eh + 1);
116 1.1.4.2 rmind
117 1.1.4.2 rmind /*
118 1.1.4.2 rmind * XXX VLAN support?
119 1.1.4.2 rmind */
120 1.1.4.2 rmind if (__predict_false(G_HASHTYPE(ntohl(rss_hi)) != RSS_HASH_4_TUPLE ||
121 1.1.4.2 rmind (*((uint8_t *)cpl + 1) & 0x90) != 0x10 ||
122 1.1.4.2 rmind cpl->csum != 0xffff || eh->ether_type != ntohs(ETHERTYPE_IP) ||
123 1.1.4.2 rmind ih->ip_hl != (sizeof (*ih) >> 2))) {
124 1.1.4.2 rmind return 0;
125 1.1.4.2 rmind }
126 1.1.4.2 rmind
127 1.1.4.2 rmind return 1;
128 1.1.4.2 rmind }
129 1.1.4.2 rmind
130 1.1.4.2 rmind static int
131 1.1.4.2 rmind can_lro_tcpsegment(struct tcphdr *th)
132 1.1.4.2 rmind {
133 1.1.4.2 rmind int olen = (th->th_off << 2) - sizeof (*th);
134 1.1.4.2 rmind u8 control_bits = *((u8 *)th + 13);
135 1.1.4.2 rmind
136 1.1.4.2 rmind if (__predict_false((control_bits & 0xB7) != 0x10))
137 1.1.4.2 rmind goto no_lro;
138 1.1.4.2 rmind
139 1.1.4.2 rmind if (olen) {
140 1.1.4.2 rmind uint32_t *ptr = (u32 *)(th + 1);
141 1.1.4.2 rmind if (__predict_false(olen != TCPOLEN_TSTAMP_APPA ||
142 1.1.4.2 rmind *ptr != ntohl((TCPOPT_NOP << 24) |
143 1.1.4.2 rmind (TCPOPT_NOP << 16) |
144 1.1.4.2 rmind (TCPOPT_TIMESTAMP << 8) |
145 1.1.4.2 rmind TCPOLEN_TIMESTAMP)))
146 1.1.4.2 rmind goto no_lro;
147 1.1.4.2 rmind }
148 1.1.4.2 rmind
149 1.1.4.2 rmind return 1;
150 1.1.4.2 rmind
151 1.1.4.2 rmind no_lro:
152 1.1.4.2 rmind return 0;
153 1.1.4.2 rmind }
154 1.1.4.2 rmind
155 1.1.4.2 rmind static __inline void
156 1.1.4.2 rmind lro_new_session_init(struct t3_lro_session *s, struct mbuf *m)
157 1.1.4.2 rmind {
158 1.1.4.2 rmind struct ip *ih = (struct ip *)(mtod(m, uint8_t *) + IPH_OFFSET);
159 1.1.4.2 rmind struct tcphdr *th = (struct tcphdr *) (ih + 1);
160 1.1.4.2 rmind int ip_len = ntohs(ih->ip_len);
161 1.1.4.2 rmind
162 1.1.4.2 rmind DPRINTF("%s(s=%p, m=%p)\n", __func__, s, m);
163 1.1.4.2 rmind
164 1.1.4.2 rmind s->head = m;
165 1.1.4.2 rmind
166 1.1.4.2 rmind MBUF_HEADER_CHECK(m);
167 1.1.4.2 rmind s->ip_len = ip_len;
168 1.1.4.2 rmind s->seq = ntohl(th->th_seq) + ip_len - sizeof(*ih) - (th->th_off << 2);
169 1.1.4.2 rmind
170 1.1.4.2 rmind }
171 1.1.4.2 rmind
172 1.1.4.2 rmind static void
173 1.1.4.2 rmind lro_flush_session(struct sge_qset *qs, struct t3_lro_session *s, struct mbuf *m)
174 1.1.4.2 rmind {
175 1.1.4.2 rmind struct lro_state *l = &qs->lro;
176 1.1.4.2 rmind struct mbuf *sm = s->head;
177 1.1.4.2 rmind struct ip *ih = (struct ip *)(mtod(sm, uint8_t *) + IPH_OFFSET);
178 1.1.4.2 rmind
179 1.1.4.2 rmind
180 1.1.4.2 rmind DPRINTF("%s(qs=%p, s=%p, ", __func__,
181 1.1.4.2 rmind qs, s);
182 1.1.4.2 rmind
183 1.1.4.2 rmind if (m)
184 1.1.4.2 rmind DPRINTF("m=%p)\n", m);
185 1.1.4.2 rmind else
186 1.1.4.2 rmind DPRINTF("m=NULL)\n");
187 1.1.4.2 rmind
188 1.1.4.2 rmind ih->ip_len = htons(s->ip_len);
189 1.1.4.2 rmind ih->ip_sum = 0;
190 1.1.4.2 rmind ih->ip_sum = in_cksum_hdr(ih);
191 1.1.4.2 rmind
192 1.1.4.2 rmind MBUF_HEADER_CHECK(sm);
193 1.1.4.2 rmind
194 1.1.4.2 rmind sm->m_flags |= M_LRO;
195 1.1.4.2 rmind t3_rx_eth(qs->port->adapter, &qs->rspq, sm, 2);
196 1.1.4.2 rmind
197 1.1.4.2 rmind if (m) {
198 1.1.4.2 rmind s->head = m;
199 1.1.4.2 rmind lro_new_session_init(s, m);
200 1.1.4.2 rmind } else {
201 1.1.4.2 rmind s->head = NULL;
202 1.1.4.2 rmind l->nactive--;
203 1.1.4.2 rmind }
204 1.1.4.2 rmind
205 1.1.4.2 rmind qs->port_stats[SGE_PSTATS_LRO_FLUSHED]++;
206 1.1.4.2 rmind }
207 1.1.4.2 rmind
208 1.1.4.2 rmind static __inline struct t3_lro_session *
209 1.1.4.2 rmind lro_new_session(struct sge_qset *qs, struct mbuf *m, uint32_t rss_hash)
210 1.1.4.2 rmind {
211 1.1.4.2 rmind struct lro_state *l = &qs->lro;
212 1.1.4.2 rmind int idx = LRO_SESSION_IDX_HINT_HASH(rss_hash);
213 1.1.4.2 rmind struct t3_lro_session *s = &l->sess[idx];
214 1.1.4.2 rmind
215 1.1.4.2 rmind DPRINTF("%s(qs=%p, m=%p, rss_hash=0x%x)\n", __func__,
216 1.1.4.2 rmind qs, m, rss_hash);
217 1.1.4.2 rmind
218 1.1.4.2 rmind if (__predict_true(!s->head))
219 1.1.4.2 rmind goto done;
220 1.1.4.2 rmind
221 1.1.4.2 rmind if (l->nactive > MAX_LRO_SES)
222 1.1.4.2 rmind panic("MAX_LRO_PER_QSET exceeded");
223 1.1.4.2 rmind
224 1.1.4.2 rmind if (l->nactive == MAX_LRO_SES) {
225 1.1.4.2 rmind lro_flush_session(qs, s, m);
226 1.1.4.2 rmind qs->port_stats[SGE_PSTATS_LRO_X_STREAMS]++;
227 1.1.4.2 rmind return s;
228 1.1.4.2 rmind }
229 1.1.4.2 rmind
230 1.1.4.2 rmind while (1) {
231 1.1.4.2 rmind LRO_IDX_INC(idx);
232 1.1.4.2 rmind s = &l->sess[idx];
233 1.1.4.2 rmind if (!s->head)
234 1.1.4.2 rmind break;
235 1.1.4.2 rmind }
236 1.1.4.2 rmind done:
237 1.1.4.2 rmind lro_new_session_init(s, m);
238 1.1.4.2 rmind l->nactive++;
239 1.1.4.2 rmind
240 1.1.4.2 rmind return s;
241 1.1.4.2 rmind }
242 1.1.4.2 rmind
243 1.1.4.2 rmind static __inline int
244 1.1.4.2 rmind lro_update_session(struct t3_lro_session *s, struct mbuf *m)
245 1.1.4.2 rmind {
246 1.1.4.2 rmind struct mbuf *sm = s->head;
247 1.1.4.2 rmind struct cpl_rx_pkt *cpl = (struct cpl_rx_pkt *)(mtod(sm, uint8_t *) + 2);
248 1.1.4.2 rmind struct cpl_rx_pkt *ncpl = (struct cpl_rx_pkt *)(mtod(m, uint8_t *) + 2);
249 1.1.4.2 rmind struct ip *nih = (struct ip *)(mtod(m, uint8_t *) + IPH_OFFSET);
250 1.1.4.2 rmind struct tcphdr *th, *nth = (struct tcphdr *)(nih + 1);
251 1.1.4.2 rmind uint32_t seq = ntohl(nth->th_seq);
252 1.1.4.2 rmind int plen, tcpiphlen, olen = (nth->th_off << 2) - sizeof (*nth);
253 1.1.4.2 rmind
254 1.1.4.2 rmind
255 1.1.4.2 rmind DPRINTF("%s(s=%p, m=%p)\n", __func__, s, m);
256 1.1.4.2 rmind if (cpl->vlan_valid && cpl->vlan != ncpl->vlan) {
257 1.1.4.2 rmind return -1;
258 1.1.4.2 rmind }
259 1.1.4.2 rmind if (__predict_false(seq != s->seq)) {
260 1.1.4.2 rmind DPRINTF("sequence mismatch\n");
261 1.1.4.2 rmind return -1;
262 1.1.4.2 rmind }
263 1.1.4.2 rmind
264 1.1.4.2 rmind MBUF_HEADER_CHECK(sm);
265 1.1.4.2 rmind th = (struct tcphdr *)(mtod(sm, uint8_t *) + IPH_OFFSET + sizeof (struct ip));
266 1.1.4.2 rmind
267 1.1.4.2 rmind if (olen) {
268 1.1.4.2 rmind uint32_t *ptr = (uint32_t *)(th + 1);
269 1.1.4.2 rmind uint32_t *nptr = (uint32_t *)(nth + 1);
270 1.1.4.2 rmind
271 1.1.4.2 rmind if (__predict_false(ntohl(*(ptr + 1)) > ntohl(*(nptr + 1)) ||
272 1.1.4.2 rmind !*(nptr + 2))) {
273 1.1.4.2 rmind return -1;
274 1.1.4.2 rmind }
275 1.1.4.2 rmind *(ptr + 1) = *(nptr + 1);
276 1.1.4.2 rmind *(ptr + 2) = *(nptr + 2);
277 1.1.4.2 rmind }
278 1.1.4.2 rmind th->th_ack = nth->th_ack;
279 1.1.4.2 rmind th->th_win = nth->th_win;
280 1.1.4.2 rmind
281 1.1.4.2 rmind tcpiphlen = (nth->th_off << 2) + sizeof (*nih);
282 1.1.4.2 rmind plen = ntohs(nih->ip_len) - tcpiphlen;
283 1.1.4.2 rmind s->seq += plen;
284 1.1.4.2 rmind s->ip_len += plen;
285 1.1.4.2 rmind sm->m_pkthdr.len += plen;
286 1.1.4.2 rmind
287 1.1.4.2 rmind /*
288 1.1.4.2 rmind * XXX FIX ME
289 1.1.4.2 rmind *
290 1.1.4.2 rmind *
291 1.1.4.2 rmind */
292 1.1.4.2 rmind
293 1.1.4.2 rmind #if 0
294 1.1.4.2 rmind /* XXX this I *do not* understand */
295 1.1.4.2 rmind if (plen > skb_shinfo(s->skb)->gso_size)
296 1.1.4.2 rmind skb_shinfo(s->skb)->gso_size = plen;
297 1.1.4.2 rmind #endif
298 1.1.4.2 rmind DPRINTF("m_adj(%d)\n", (int)(IPH_OFFSET + tcpiphlen));
299 1.1.4.2 rmind m_adj(m, IPH_OFFSET + tcpiphlen);
300 1.1.4.2 rmind #if 0
301 1.1.4.2 rmind if (__predict_false(!skb_shinfo(s->skb)->frag_list))
302 1.1.4.2 rmind skb_shinfo(s->skb)->frag_list = skb;
303 1.1.4.2 rmind
304 1.1.4.2 rmind #endif
305 1.1.4.2 rmind
306 1.1.4.2 rmind #if 0
307 1.1.4.2 rmind
308 1.1.4.2 rmind /*
309 1.1.4.2 rmind * XXX we really need to be able to
310 1.1.4.2 rmind * support vectors of buffers in FreeBSD
311 1.1.4.2 rmind */
312 1.1.4.2 rmind int nr = skb_shinfo(s->skb)->nr_frags;
313 1.1.4.2 rmind skb_shinfo(s->skb)->frags[nr].page = frag->page;
314 1.1.4.2 rmind skb_shinfo(s->skb)->frags[nr].page_offset =
315 1.1.4.2 rmind frag->page_offset + IPH_OFFSET + tcpiphlen;
316 1.1.4.2 rmind skb_shinfo(s->skb)->frags[nr].size = plen;
317 1.1.4.2 rmind skb_shinfo(s->skb)->nr_frags = ++nr;
318 1.1.4.2 rmind
319 1.1.4.2 rmind #endif
320 1.1.4.2 rmind return (0);
321 1.1.4.2 rmind }
322 1.1.4.2 rmind
323 1.1.4.2 rmind void
324 1.1.4.2 rmind t3_rx_eth_lro(adapter_t *adap, struct sge_rspq *rq, struct mbuf *m,
325 1.1.4.2 rmind int ethpad, uint32_t rss_hash, uint32_t rss_csum, int lro)
326 1.1.4.2 rmind {
327 1.1.4.2 rmind struct sge_qset *qs = rspq_to_qset(rq);
328 1.1.4.2 rmind struct cpl_rx_pkt *cpl = (struct cpl_rx_pkt *)(mtod(m, uint8_t *) + ethpad);
329 1.1.4.2 rmind struct ether_header *eh = (struct ether_header *)(cpl + 1);
330 1.1.4.2 rmind struct ip *ih;
331 1.1.4.2 rmind struct tcphdr *th;
332 1.1.4.2 rmind struct t3_lro_session *s = NULL;
333 1.1.4.2 rmind
334 1.1.4.2 rmind if (lro == 0)
335 1.1.4.2 rmind goto no_lro;
336 1.1.4.2 rmind
337 1.1.4.2 rmind if (!can_lro_packet(cpl, rss_csum))
338 1.1.4.2 rmind goto no_lro;
339 1.1.4.2 rmind
340 1.1.4.2 rmind ih = (struct ip *)(eh + 1);
341 1.1.4.2 rmind th = (struct tcphdr *)(ih + 1);
342 1.1.4.2 rmind
343 1.1.4.2 rmind s = lro_lookup(&qs->lro,
344 1.1.4.2 rmind LRO_SESSION_IDX_HINT_HASH(rss_hash), ih, th);
345 1.1.4.2 rmind
346 1.1.4.2 rmind if (__predict_false(!can_lro_tcpsegment(th))) {
347 1.1.4.2 rmind goto no_lro;
348 1.1.4.2 rmind } else if (__predict_false(!s)) {
349 1.1.4.2 rmind s = lro_new_session(qs, m, rss_hash);
350 1.1.4.2 rmind } else {
351 1.1.4.2 rmind if (lro_update_session(s, m)) {
352 1.1.4.2 rmind lro_flush_session(qs, s, m);
353 1.1.4.2 rmind }
354 1.1.4.2 rmind #ifdef notyet
355 1.1.4.2 rmind if (__predict_false(s->head->m_pkthdr.len + pi->ifp->if_mtu > 65535)) {
356 1.1.4.2 rmind lro_flush_session(qs, s, NULL);
357 1.1.4.2 rmind }
358 1.1.4.2 rmind #endif
359 1.1.4.2 rmind }
360 1.1.4.2 rmind
361 1.1.4.2 rmind qs->port_stats[SGE_PSTATS_LRO_QUEUED]++;
362 1.1.4.2 rmind return;
363 1.1.4.2 rmind no_lro:
364 1.1.4.2 rmind if (s)
365 1.1.4.2 rmind lro_flush_session(qs, s, NULL);
366 1.1.4.2 rmind
367 1.1.4.2 rmind if (m->m_len == 0 || m->m_pkthdr.len == 0 || (m->m_flags & M_PKTHDR) == 0)
368 1.1.4.2 rmind DPRINTF("rx_eth_lro mbuf len=%d pktlen=%d flags=0x%x\n",
369 1.1.4.2 rmind m->m_len, m->m_pkthdr.len, m->m_flags);
370 1.1.4.2 rmind
371 1.1.4.2 rmind t3_rx_eth(adap, rq, m, ethpad);
372 1.1.4.2 rmind }
373 1.1.4.2 rmind
374 1.1.4.2 rmind void
375 1.1.4.2 rmind t3_lro_flush(adapter_t *adap, struct sge_qset *qs, struct lro_state *state)
376 1.1.4.2 rmind {
377 1.1.4.2 rmind unsigned int idx = state->active_idx;
378 1.1.4.2 rmind
379 1.1.4.2 rmind while (state->nactive) {
380 1.1.4.2 rmind struct t3_lro_session *s = &state->sess[idx];
381 1.1.4.2 rmind
382 1.1.4.2 rmind if (s->head)
383 1.1.4.2 rmind lro_flush_session(qs, s, NULL);
384 1.1.4.2 rmind LRO_IDX_INC(idx);
385 1.1.4.2 rmind }
386 1.1.4.2 rmind }
387