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