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