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