Home | History | Annotate | Line # | Download | only in cxgb
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