RDMA/nes: Use LRO
[deliverable/linux.git] / drivers / infiniband / hw / nes / nes_hw.c
index 7c4c0fbf0abd3ff9322a07888afe5cb00d4c34d2..f824ecb9f87970565a2ce5b316b6aec3db156057 100644 (file)
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
 
 #include "nes.h"
 
-u32 crit_err_count = 0;
+static u32 crit_err_count;
 u32 int_mod_timer_init;
 u32 int_mod_cq_depth_256;
 u32 int_mod_cq_depth_128;
@@ -53,6 +54,17 @@ u32 int_mod_cq_depth_1;
 
 #include "nes_cm.h"
 
+static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq);
+static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count);
+static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
+                          u8 OneG_Mode);
+static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
+static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq);
+static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq);
+static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
+                                  struct nes_hw_aeqe *aeqe);
+static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number);
+static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode);
 
 #ifdef CONFIG_INFINIBAND_NES_DEBUG
 static unsigned char *nes_iwarp_state_str[] = {
@@ -156,15 +168,14 @@ static void nes_nic_tune_timer(struct nes_device *nesdev)
 
        spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
 
-       if (shared_timer->cq_count_old < cq_count) {
-               if (cq_count > shared_timer->threshold_low)
-                       shared_timer->cq_direction_downward=0;
-       }
-       if (shared_timer->cq_count_old >= cq_count)
+       if (shared_timer->cq_count_old <= cq_count)
+               shared_timer->cq_direction_downward = 0;
+       else
                shared_timer->cq_direction_downward++;
        shared_timer->cq_count_old = cq_count;
        if (shared_timer->cq_direction_downward > NES_NIC_CQ_DOWNWARD_TREND) {
-               if (cq_count <= shared_timer->threshold_low) {
+               if (cq_count <= shared_timer->threshold_low &&
+                   shared_timer->threshold_low > 4) {
                        shared_timer->threshold_low = shared_timer->threshold_low/2;
                        shared_timer->cq_direction_downward=0;
                        nesdev->currcq_count = 0;
@@ -371,7 +382,7 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
                nesadapter->et_use_adaptive_rx_coalesce = 1;
                nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
                nesadapter->et_rx_coalesce_usecs_irq = 0;
-               printk(PFX "%s: Using Adaptive Interrupt Moderation\n", __FUNCTION__);
+               printk(PFX "%s: Using Adaptive Interrupt Moderation\n", __func__);
        }
        /* Setup and enable the periodic timer */
        if (nesadapter->et_rx_coalesce_usecs_irq)
@@ -383,7 +394,7 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
        nesadapter->base_pd = 1;
 
        nesadapter->device_cap_flags =
-                       IB_DEVICE_ZERO_STAG | IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW;
+               IB_DEVICE_ZERO_STAG | IB_DEVICE_MEM_WINDOW;
 
        nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter)
                        [(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]);
@@ -573,7 +584,7 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
                if (vendor_id == 0xffff)
                        break;
        }
-       nes_debug(NES_DBG_INIT, "%s %d functions found for %s.\n", __FUNCTION__,
+       nes_debug(NES_DBG_INIT, "%s %d functions found for %s.\n", __func__,
                func_index, pci_name(nesdev->pcidev));
        nesadapter->adapter_fcn_count = func_index;
 
@@ -584,7 +595,7 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
 /**
  * nes_reset_adapter_ne020
  */
-unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
+static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
 {
        u32 port_count;
        u32 u32temp;
@@ -626,6 +637,15 @@ unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
                        nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n");
                        return 0;
                }
+
+               i = 0;
+               while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
+                       mdelay(1);
+               if (i >= 10000) {
+                       printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
+                              nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
+                       return 0;
+               }
        }
 
        /* port reset */
@@ -674,17 +694,6 @@ unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
                }
        }
 
-
-
-       i = 0;
-       while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
-               mdelay(1);
-       if (i >= 10000) {
-               printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
-                               nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
-               return 0;
-       }
-
        return port_count;
 }
 
@@ -692,7 +701,8 @@ unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
 /**
  * nes_init_serdes
  */
-int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, u8  OneG_Mode)
+static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
+                          u8 OneG_Mode)
 {
        int i;
        u32 u32temp;
@@ -740,7 +750,7 @@ int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, u8  One
                                & 0x0000000f)) != 0x0000000f) && (i++ < 5000))
                                mdelay(1);
                        if (i >= 5000) {
-                               printk("%s: Init: serdes 1 not ready, status=%x\n", __FUNCTION__, u32temp);
+                               printk("%s: Init: serdes 1 not ready, status=%x\n", __func__, u32temp);
                                /* return 1; */
                        }
                        nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x000bdef7);
@@ -761,7 +771,7 @@ int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count, u8  One
  * nes_init_csr_ne020
  * Initialize registers for ne020 hardware
  */
-void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
+static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
 {
        u32 u32temp;
 
@@ -1205,7 +1215,7 @@ int nes_init_phy(struct nes_device *nesdev)
        if (nesadapter->OneG_Mode) {
                nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
                if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
-                       printk(PFX "%s: Programming mdc config for 1G\n", __FUNCTION__);
+                       printk(PFX "%s: Programming mdc config for 1G\n", __func__);
                        tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
                        tx_config |= 0x04;
                        nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
@@ -1359,13 +1369,32 @@ static void nes_replenish_nic_rq(struct nes_vnic *nesvnic)
 static void nes_rq_wqes_timeout(unsigned long parm)
 {
        struct nes_vnic *nesvnic = (struct nes_vnic *)parm;
-       printk("%s: Timer fired.\n", __FUNCTION__);
+       printk("%s: Timer fired.\n", __func__);
        atomic_set(&nesvnic->rx_skb_timer_running, 0);
        if (atomic_read(&nesvnic->rx_skbs_needed))
                nes_replenish_nic_rq(nesvnic);
 }
 
 
+static int nes_lro_get_skb_hdr(struct sk_buff *skb, void **iphdr,
+                              void **tcph, u64 *hdr_flags, void *priv)
+{
+       unsigned int ip_len;
+       struct iphdr *iph;
+       skb_reset_network_header(skb);
+       iph = ip_hdr(skb);
+       if (iph->protocol != IPPROTO_TCP)
+               return -1;
+       ip_len = ip_hdrlen(skb);
+       skb_set_transport_header(skb, ip_len);
+       *tcph = tcp_hdr(skb);
+
+       *hdr_flags = LRO_IPV4 | LRO_TCP;
+       *iphdr = iph;
+       return 0;
+}
+
+
 /**
  * nes_init_nic_qp
  */
@@ -1583,15 +1612,21 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
        nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout;
        nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic;
        nes_debug(NES_DBG_INIT, "NAPI support Enabled\n");
-
        if (nesdev->nesadapter->et_use_adaptive_rx_coalesce)
        {
                nes_nic_init_timer(nesdev);
                if (netdev->mtu > 1500)
                        jumbomode = 1;
-                nes_nic_init_timer_defaults(nesdev, jumbomode);
-       }
-
+               nes_nic_init_timer_defaults(nesdev, jumbomode);
+       }
+       nesvnic->lro_mgr.max_aggr = NES_LRO_MAX_AGGR;
+       nesvnic->lro_mgr.max_desc = NES_MAX_LRO_DESCRIPTORS;
+       nesvnic->lro_mgr.lro_arr = nesvnic->lro_desc;
+       nesvnic->lro_mgr.get_skb_header = nes_lro_get_skb_hdr;
+       nesvnic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+       nesvnic->lro_mgr.dev = netdev;
+       nesvnic->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+       nesvnic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
        return 0;
 }
 
@@ -1728,7 +1763,6 @@ int nes_napi_isr(struct nes_device *nesdev)
                        nesdev->int_req &= ~NES_INT_TIMER;
                        nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
                        nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
-                       nesadapter->tune_timer.timer_in_use_old = 0;
                }
                nesdev->deepcq_count = 0;
                return 1;
@@ -1867,7 +1901,6 @@ void nes_dpc(unsigned long param)
                                        nesdev->int_req &= ~NES_INT_TIMER;
                                        nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
                                        nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
-                                       nesdev->nesadapter->tune_timer.timer_in_use_old = 0;
                                } else {
                                        nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
                                }
@@ -1912,7 +1945,7 @@ void nes_dpc(unsigned long param)
 /**
  * nes_process_ceq
  */
-void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
+static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
 {
        u64 u64temp;
        struct nes_hw_cq *cq;
@@ -1952,7 +1985,7 @@ void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
 /**
  * nes_process_aeq
  */
-void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
+static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
 {
 //     u64 u64temp;
        u32 head;
@@ -2063,7 +2096,7 @@ static void nes_reset_link(struct nes_device *nesdev, u32 mac_index)
 /**
  * nes_process_mac_intr
  */
-void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
+static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
 {
        unsigned long flags;
        u32 pcs_control_status;
@@ -2166,7 +2199,7 @@ void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                                temp_phy_data = phy_data;
                        } while (1);
                        nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
-                               __FUNCTION__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
+                               __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
 
                } else {
                        phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0;
@@ -2208,7 +2241,7 @@ void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
 
 
 
-void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
+static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
 {
        struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
 
@@ -2247,10 +2280,13 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
        u16 pkt_type;
        u16 rqes_processed = 0;
        u8 sq_cqes = 0;
+       u8 nes_use_lro = 0;
 
        head = cq->cq_head;
        cq_size = cq->cq_size;
        cq->cqes_pending = 1;
+       if (nesvnic->netdev->features & NETIF_F_LRO)
+               nes_use_lro = 1;
        do {
                if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
                                NES_NIC_CQE_VALID) {
@@ -2372,9 +2408,16 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
                                                                >> 16);
                                                nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
                                                                nesvnic->netdev->name, vlan_tag);
-                                               nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
+                                               if (nes_use_lro)
+                                                       lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb,
+                                                                       nesvnic->vlan_grp, vlan_tag, NULL);
+                                               else
+                                                       nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
                                        } else {
-                                               nes_netif_rx(rx_skb);
+                                               if (nes_use_lro)
+                                                       lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
+                                               else
+                                                       nes_netif_rx(rx_skb);
                                        }
                                }
 
@@ -2406,13 +2449,14 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
 
        } while (1);
 
+       if (nes_use_lro)
+               lro_flush_all(&nesvnic->lro_mgr);
        if (sq_cqes) {
                barrier();
                /* restart the queue if it had been stopped */
                if (netif_queue_stopped(nesvnic->netdev))
                        netif_wake_queue(nesvnic->netdev);
        }
-
        cq->cq_head = head;
        /* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n",
                        cq->cq_number, cqe_count, cq->cq_head); */
@@ -2425,13 +2469,13 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
        }
        if (atomic_read(&nesvnic->rx_skbs_needed))
                nes_replenish_nic_rq(nesvnic);
-       }
+}
 
 
 /**
  * nes_cqp_ce_handler
  */
-void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
+static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
 {
        u64 u64temp;
        unsigned long flags;
@@ -2570,7 +2614,8 @@ void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
 /**
  * nes_process_iwarp_aeqe
  */
-void nes_process_iwarp_aeqe(struct nes_device *nesdev, struct nes_hw_aeqe *aeqe)
+static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
+                                  struct nes_hw_aeqe *aeqe)
 {
        u64 context;
        u64 aeqe_context = 0;
@@ -2822,7 +2867,7 @@ void nes_process_iwarp_aeqe(struct nes_device *nesdev, struct nes_hw_aeqe *aeqe)
                                        le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
                        if (resource_allocated) {
                                printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n",
-                                               __FUNCTION__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
+                                               __func__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
                        }
                        break;
                case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
This page took 0.05307 seconds and 5 git commands to generate.