| /* |
| * This file contains pieces of the Linux TCP/IP stack needed for modular |
| * TOE support. |
| * |
| * Copyright (C) 2006-2009 Chelsio Communications. All rights reserved. |
| * See the corresponding files in the Linux tree for copyrights of the |
| * original Linux code a lot of this file is based on. |
| * |
| * Written by Dimitris Michailidis (dm@chelsio.com) |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this |
| * release for licensing terms and conditions. |
| */ |
| |
| /* The following tags are used by the out-of-kernel Makefile to identify |
| * supported kernel versions if a module_support-<kver> file is not found. |
| * Do not remove these tags. |
| * $SUPPORTED KERNEL 2.6.16$ |
| * $SUPPORTED KERNEL 2.6.17$ |
| * $SUPPORTED KERNEL 2.6.18$ |
| * $SUPPORTED KERNEL 2.6.19$ |
| * $SUPPORTED KERNEL 2.6.20$ |
| * $SUPPORTED KERNEL 2.6.21$ |
| * $SUPPORTED KERNEL 2.6.22$ |
| */ |
| |
| #include <net/tcp.h> |
| #include <linux/pkt_sched.h> |
| #include "defs.h" |
| |
| #if defined(KPROBES_SYMBOL_NAME) |
| #include <linux/kprobes.h> |
| #endif |
| |
| #if defined(CONFIG_SMP) && !defined(PPC64_TLB_BATCH_NR) |
| static unsigned long (*kallsyms_lookup_name_p)(const char *name); |
| static void (*flush_tlb_mm_p)(struct mm_struct *mm); |
| static void (*flush_tlb_page_p)(struct vm_area_struct *vma, |
| unsigned long va); |
| #endif |
| void flush_tlb_mm_offload(struct mm_struct *mm); |
| |
| void flush_tlb_page_offload(struct vm_area_struct *vma, unsigned long addr) |
| { |
| #if defined(CONFIG_SMP) && !defined(PPC64_TLB_BATCH_NR) |
| flush_tlb_page_p(vma, addr); |
| #endif |
| } |
| |
| int sysctl_tcp_window_scaling = 1; |
| int sysctl_tcp_adv_win_scale = 2; |
| |
| #define ECN_OR_COST(class) TC_PRIO_##class |
| |
| __u8 ip_tos2prio[16] = { |
| TC_PRIO_BESTEFFORT, |
| ECN_OR_COST(FILLER), |
| TC_PRIO_BESTEFFORT, |
| ECN_OR_COST(BESTEFFORT), |
| TC_PRIO_BULK, |
| ECN_OR_COST(BULK), |
| TC_PRIO_BULK, |
| ECN_OR_COST(BULK), |
| TC_PRIO_INTERACTIVE, |
| ECN_OR_COST(INTERACTIVE), |
| TC_PRIO_INTERACTIVE, |
| ECN_OR_COST(INTERACTIVE), |
| TC_PRIO_INTERACTIVE_BULK, |
| ECN_OR_COST(INTERACTIVE_BULK), |
| TC_PRIO_INTERACTIVE_BULK, |
| ECN_OR_COST(INTERACTIVE_BULK) |
| }; |
| |
| /* |
| * Adapted from tcp_minisocks.c |
| */ |
| void tcp_time_wait(struct sock *sk, int state, int timeo) |
| { |
| struct inet_timewait_sock *tw = NULL; |
| const struct inet_connection_sock *icsk = inet_csk(sk); |
| const struct tcp_sock *tp = tcp_sk(sk); |
| int recycle_ok = 0; |
| |
| if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) |
| tw = inet_twsk_alloc(sk, state); |
| |
| if (tw != NULL) { |
| struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); |
| const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); |
| |
| tw->tw_rcv_wscale = tp->rx_opt.rcv_wscale; |
| tcptw->tw_rcv_nxt = tp->rcv_nxt; |
| tcptw->tw_snd_nxt = tp->snd_nxt; |
| tcptw->tw_rcv_wnd = tcp_receive_window(tp); |
| tcptw->tw_ts_recent = tp->rx_opt.ts_recent; |
| tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp; |
| |
| /* Linkage updates. */ |
| __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); |
| |
| /* Get the TIME_WAIT timeout firing. */ |
| if (timeo < rto) |
| timeo = rto; |
| |
| if (recycle_ok) { |
| tw->tw_timeout = rto; |
| } else { |
| tw->tw_timeout = TCP_TIMEWAIT_LEN; |
| if (state == TCP_TIME_WAIT) |
| timeo = TCP_TIMEWAIT_LEN; |
| } |
| |
| inet_twsk_schedule(tw, &tcp_death_row, timeo, |
| TCP_TIMEWAIT_LEN); |
| inet_twsk_put(tw); |
| } else { |
| /* Sorry, if we're out of memory, just CLOSE this |
| * socket up. We've got bigger problems than |
| * non-graceful socket closings. |
| */ |
| if (net_ratelimit()) |
| printk(KERN_INFO |
| "TCP: time wait bucket table overflow\n"); |
| } |
| |
| tcp_done(sk); |
| } |
| |
| void flush_tlb_mm_offload(struct mm_struct *mm) |
| { |
| #if defined(CONFIG_SMP) && !defined(PPC64_TLB_BATCH_NR) |
| if (flush_tlb_mm_p) |
| flush_tlb_mm_p(mm); |
| #endif |
| } |
| |
| #if defined(CONFIG_SMP) && !defined(PPC64_TLB_BATCH_NR) |
| static int find_kallsyms_lookup_name(void) |
| { |
| int err = 0; |
| |
| #if defined(KALLSYMS_LOOKUP_NAME) |
| kallsyms_lookup_name_p = kallsyms_lookup_name; |
| |
| #elif defined(KPROBES_KALLSYMS) |
| struct kprobe kp; |
| |
| memset(&kp, 0, sizeof kp); |
| kp.symbol_name = "kallsyms_lookup_name"; |
| err = register_kprobe(&kp); |
| if (!err) { |
| kallsyms_lookup_name_p = (void *)kp.addr; |
| unregister_kprobe(&kp); |
| } |
| #else |
| kallsyms_lookup_name_p = (void *)KALLSYMS_LOOKUP; |
| #endif |
| if (!err) |
| err = kallsyms_lookup_name_p == NULL; |
| |
| return err; |
| } |
| #endif |
| |
| int prepare_tom_for_offload(void) |
| { |
| #if defined(CONFIG_SMP) && !defined(PPC64_TLB_BATCH_NR) |
| if (!kallsyms_lookup_name_p) { |
| int err = find_kallsyms_lookup_name(); |
| if (err) |
| return err; |
| } |
| |
| flush_tlb_mm_p = (void *)kallsyms_lookup_name_p("flush_tlb_mm"); |
| if (!flush_tlb_mm_p) { |
| printk(KERN_ERR "Could not locate flush_tlb_mm"); |
| return -1; |
| } |
| |
| flush_tlb_page_p = (void *)kallsyms_lookup_name_p("flush_tlb_page"); |
| if (!flush_tlb_page_p) { |
| printk(KERN_ERR "Could not locate flush_tlb_page"); |
| return -1; |
| } |
| #endif |
| return 0; |
| } |