#include <linux/gpio.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
+#include <linux/ipv6.h>
#include <linux/if_ether.h>
#include <linux/etherdevice.h>
#include <linux/device.h>
#include "modem_prj.h"
#include "modem_utils.h"
-
+#include "modem_link_device_shmem.h"
static u16 exynos_build_fr_config(struct io_device *iod, struct link_device *ld,
unsigned int count);
return 0;
}
+#ifdef CONFIG_LINK_DEVICE_NAPI
+#ifdef CONFIG_MODEM_IF_NET_GRO
+static int check_gro_support(struct sk_buff *skb)
+{
+ switch (skb->data[0] & 0xF0) {
+ case 0x40:
+ return (ip_hdr(skb)->protocol == IPPROTO_TCP);
+
+ case 0x60:
+ return (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP);
+ }
+ return 0;
+}
+#else
+static int check_gro_support(struct sk_buff *skb)
+{
+ return 0;
+}
+#endif
+#endif
+
static int rx_multi_pdp(struct sk_buff *skb)
{
struct link_device *ld = skbpriv(skb)->ld;
struct io_device *iod = skbpriv(skb)->iod;
struct net_device *ndev;
struct iphdr *iphdr;
+ struct shmem_link_device *shmd = to_shmem_link_device(ld);
int ret;
ndev = iod->ndev;
}
#ifdef CONFIG_LINK_DEVICE_NAPI
- ret = netif_receive_skb(skb);
- if (ret != NET_RX_SUCCESS) {
- mif_err("%s->%s: ERR! netif_receive_skb (err %d)\n",
- ld->name, iod->name, ret);
+ skb_reset_network_header(skb);
+
+ if (check_gro_support(skb)) {
+ ret = napi_gro_receive(&shmd->mld_napi, skb);
+ if (ret == GRO_DROP) {
+ mif_err_limited("%s: %s<-%s: ERR! napi_gro_receive\n",
+ ld->name, iod->name, iod->mc->name);
+ }
+
+ if (ld->gro_flush)
+ ld->gro_flush(ld);
+ } else {
+ ret = netif_receive_skb(skb);
+ if (ret != NET_RX_SUCCESS) {
+ mif_err_limited("%s->%s: ERR! netif_receive_skb (err %d)\n",
+ ld->name, iod->name, ret);
+ }
}
#else /* !CONFIG_LINK_DEVICE_NAPI */
if (in_interrupt())
ndev->tx_queue_len = 1000;
ndev->mtu = ETH_DATA_LEN;
ndev->watchdog_timeo = 5 * HZ;
+#ifdef CONFIG_MODEM_IF_NET_GRO
+ ndev->features |= NETIF_F_GRO;
+#endif
}
static void vnet_setup_ether(struct net_device *ndev)
ndev->tx_queue_len = 1000;
ndev->mtu = ETH_DATA_LEN;
ndev->watchdog_timeo = 5 * HZ;
+#ifdef CONFIG_MODEM_IF_NET_GRO
+ ndev->features |= NETIF_F_GRO;
+#endif
}
static u16 exynos_build_fr_config(struct io_device *iod, struct link_device *ld,
return 0;
}
+#ifdef CONFIG_MODEM_IF_NET_GRO
+static long gro_flush_time = 100000L;
+module_param(gro_flush_time, long, 0644);
+
+static void gro_flush_timer(struct link_device *ld)
+{
+ struct shmem_link_device *shmd = to_shmem_link_device(ld);
+ struct timespec curr, diff;
+
+ if (!gro_flush_time)
+ return;
+
+ if (unlikely(shmd->flush_time.tv_sec == 0)) {
+ getnstimeofday(&shmd->flush_time);
+ } else {
+ getnstimeofday(&(curr));
+ diff = timespec_sub(curr, shmd->flush_time);
+ if ((diff.tv_sec > 0) || (diff.tv_nsec > gro_flush_time)) {
+ napi_gro_flush(&shmd->mld_napi, false);
+ getnstimeofday(&shmd->flush_time);
+ }
+ }
+}
+#endif
+
#ifdef CONFIG_LINK_DEVICE_NAPI
/*
* shmd_rx_int_poll
ld->acpm_dump = save_acpm_dump;
ld->crash_reason = shmem_crash_reason;
+#ifdef CONFIG_MODEM_IF_NET_GRO
+ ld->gro_flush = gro_flush_timer;
+#endif
+
#ifdef CONFIG_LINK_DEVICE_NAPI
ld->enable_rx_int = shmem_enable_rx_int;
ld->disable_rx_int = shmem_disable_rx_int;
#include <linux/spinlock.h>
#include <linux/cdev.h>
#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
#include "include/modem_v1.h"
#include "include/exynos_ipc.h"
int (*enable_rx_int)(struct link_device *ld);
int (*disable_rx_int)(struct link_device *ld);
#endif /* CONFIG_LINK_DEVICE_NAPI */
+ void (*gro_flush)(struct link_device *ld);
};
/** rx_alloc_skb - allocate an skbuff and set skb's iod, ld