]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/enic/enic_main.c
enic: Feature Add: Replace LRO with GRO
[net-next-2.6.git] / drivers / net / enic / enic_main.c
index e125113759a5e1a09e6851b3a145f4042d0b0040..c2b848f58c2962db333e6d11f838671abd05f2b6 100644 (file)
@@ -1029,127 +1029,133 @@ static int enic_dev_init_done(struct enic *enic, int *done, int *error)
        return err;
 }
 
-static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
-       char *name, u8 *instance_uuid, u8 *host_uuid)
+static int enic_set_port_profile(struct enic *enic, u8 *mac)
 {
        struct vic_provinfo *vp;
        u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
-       unsigned short *uuid;
+       u8 *uuid;
        char uuid_str[38];
-       static char *uuid_fmt = "%04X%04X-%04X-%04X-%04X-%04X%04X%04X";
+       static char *uuid_fmt = "%02X%02X%02X%02X-%02X%02X-%02X%02X-"
+               "%02X%02X-%02X%02X%02X%02X%0X%02X";
        int err;
 
-       if (!name)
-               return -EINVAL;
+       err = enic_vnic_dev_deinit(enic);
+       if (err)
+               return err;
 
-       if (!is_valid_ether_addr(mac))
-               return -EADDRNOTAVAIL;
+       switch (enic->pp.request) {
 
-       vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE);
-       if (!vp)
-               return -ENOMEM;
+       case PORT_REQUEST_ASSOCIATE:
 
-       vic_provinfo_add_tlv(vp,
-               VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
-               strlen(name) + 1, name);
+               if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name))
+                       return -EINVAL;
 
-       vic_provinfo_add_tlv(vp,
-               VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
-               ETH_ALEN, mac);
+               if (!is_valid_ether_addr(mac))
+                       return -EADDRNOTAVAIL;
 
-       if (instance_uuid) {
-               uuid = (unsigned short *)instance_uuid;
-               sprintf(uuid_str, uuid_fmt,
-                       uuid[0], uuid[1], uuid[2], uuid[3],
-                       uuid[4], uuid[5], uuid[6], uuid[7]);
-               vic_provinfo_add_tlv(vp,
-                       VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
-                       sizeof(uuid_str), uuid_str);
-       }
+               vp = vic_provinfo_alloc(GFP_KERNEL, oui,
+                       VIC_PROVINFO_LINUX_TYPE);
+               if (!vp)
+                       return -ENOMEM;
 
-       if (host_uuid) {
-               uuid = (unsigned short *)host_uuid;
-               sprintf(uuid_str, uuid_fmt,
-                       uuid[0], uuid[1], uuid[2], uuid[3],
-                       uuid[4], uuid[5], uuid[6], uuid[7]);
                vic_provinfo_add_tlv(vp,
-                       VIC_LINUX_PROV_TLV_HOST_UUID_STR,
-                       sizeof(uuid_str), uuid_str);
-       }
+                       VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
+                       strlen(enic->pp.name) + 1, enic->pp.name);
 
-       err = enic_vnic_dev_deinit(enic);
-       if (err)
-               goto err_out;
-
-       memset(&enic->pp, 0, sizeof(enic->pp));
+               vic_provinfo_add_tlv(vp,
+                       VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
+                       ETH_ALEN, mac);
+
+               if (enic->pp.set & ENIC_SET_INSTANCE) {
+                       uuid = enic->pp.instance_uuid;
+                       sprintf(uuid_str, uuid_fmt,
+                               uuid[0],  uuid[1],  uuid[2],  uuid[3],
+                               uuid[4],  uuid[5],  uuid[6],  uuid[7],
+                               uuid[8],  uuid[9],  uuid[10], uuid[11],
+                               uuid[12], uuid[13], uuid[14], uuid[15]);
+                       vic_provinfo_add_tlv(vp,
+                               VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
+                               sizeof(uuid_str), uuid_str);
+               }
 
-       err = enic_dev_init_prov(enic, vp);
-       if (err)
-               goto err_out;
+               if (enic->pp.set & ENIC_SET_HOST) {
+                       uuid = enic->pp.host_uuid;
+                       sprintf(uuid_str, uuid_fmt,
+                               uuid[0],  uuid[1],  uuid[2],  uuid[3],
+                               uuid[4],  uuid[5],  uuid[6],  uuid[7],
+                               uuid[8],  uuid[9],  uuid[10], uuid[11],
+                               uuid[12], uuid[13], uuid[14], uuid[15]);
+                       vic_provinfo_add_tlv(vp,
+                               VIC_LINUX_PROV_TLV_HOST_UUID_STR,
+                               sizeof(uuid_str), uuid_str);
+               }
 
-       enic->pp.request = request;
-       memcpy(enic->pp.name, name, PORT_PROFILE_MAX);
-       if (instance_uuid)
-               memcpy(enic->pp.instance_uuid,
-                       instance_uuid, PORT_UUID_MAX);
-       if (host_uuid)
-               memcpy(enic->pp.host_uuid,
-                       host_uuid, PORT_UUID_MAX);
+               err = enic_dev_init_prov(enic, vp);
+               vic_provinfo_free(vp);
+               if (err)
+                       return err;
+               break;
 
-err_out:
-       vic_provinfo_free(vp);
+       case PORT_REQUEST_DISASSOCIATE:
+               break;
 
-       return err;
-}
+       default:
+               return -EINVAL;
+       }
 
-static int enic_unset_port_profile(struct enic *enic)
-{
-       memset(&enic->pp, 0, sizeof(enic->pp));
-       return enic_vnic_dev_deinit(enic);
+       enic->pp.set |= ENIC_SET_APPLIED;
+       return 0;
 }
 
 static int enic_set_vf_port(struct net_device *netdev, int vf,
        struct nlattr *port[])
 {
        struct enic *enic = netdev_priv(netdev);
-       char *name = NULL;
-       u8 *instance_uuid = NULL;
-       u8 *host_uuid = NULL;
-       u8 request = PORT_REQUEST_DISASSOCIATE;
 
-       /* don't support VFs, yet */
-       if (vf != PORT_SELF_VF)
-               return -EOPNOTSUPP;
+       memset(&enic->pp, 0, sizeof(enic->pp));
 
-       if (port[IFLA_PORT_REQUEST])
-               request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+       if (port[IFLA_PORT_REQUEST]) {
+               enic->pp.set |= ENIC_SET_REQUEST;
+               enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+       }
 
-       switch (request) {
-       case PORT_REQUEST_ASSOCIATE:
+       if (port[IFLA_PORT_PROFILE]) {
+               enic->pp.set |= ENIC_SET_NAME;
+               memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),
+                       PORT_PROFILE_MAX);
+       }
 
-               if (port[IFLA_PORT_PROFILE])
-                       name = nla_data(port[IFLA_PORT_PROFILE]);
+       if (port[IFLA_PORT_INSTANCE_UUID]) {
+               enic->pp.set |= ENIC_SET_INSTANCE;
+               memcpy(enic->pp.instance_uuid,
+                       nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
+       }
 
-               if (port[IFLA_PORT_INSTANCE_UUID])
-                       instance_uuid =
-                               nla_data(port[IFLA_PORT_INSTANCE_UUID]);
+       if (port[IFLA_PORT_HOST_UUID]) {
+               enic->pp.set |= ENIC_SET_HOST;
+               memcpy(enic->pp.host_uuid,
+                       nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
+       }
 
-               if (port[IFLA_PORT_HOST_UUID])
-                       host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]);
+       /* don't support VFs, yet */
+       if (vf != PORT_SELF_VF)
+               return -EOPNOTSUPP;
 
-               return enic_set_port_profile(enic, request,
-                       netdev->dev_addr, name,
-                       instance_uuid, host_uuid);
+       if (!(enic->pp.set & ENIC_SET_REQUEST))
+               return -EOPNOTSUPP;
 
-       case PORT_REQUEST_DISASSOCIATE:
+       if (enic->pp.request == PORT_REQUEST_ASSOCIATE) {
 
-               return enic_unset_port_profile(enic);
+               /* If the interface mac addr hasn't been assigned,
+                * assign a random mac addr before setting port-
+                * profile.
+                */
 
-       default:
-               break;
+               if (is_zero_ether_addr(netdev->dev_addr))
+                       random_ether_addr(netdev->dev_addr);
        }
 
-       return -EOPNOTSUPP;
+       return enic_set_port_profile(enic, netdev->dev_addr);
 }
 
 static int enic_get_vf_port(struct net_device *netdev, int vf,
@@ -1159,14 +1165,12 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
        int err, error, done;
        u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
 
-       /* don't support VFs, yet */
-       if (vf != PORT_SELF_VF)
-               return -EOPNOTSUPP;
+       if (!(enic->pp.set & ENIC_SET_APPLIED))
+               return -ENODATA;
 
        err = enic_dev_init_done(enic, &done, &error);
-
        if (err)
-               return err;
+               error = err;
 
        switch (error) {
        case ERR_SUCCESS:
@@ -1189,12 +1193,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
 
        NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
        NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
-       NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
-               enic->pp.name);
-       NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
-               enic->pp.instance_uuid);
-       NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
-               enic->pp.host_uuid);
+       if (enic->pp.set & ENIC_SET_NAME)
+               NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
+                       enic->pp.name);
+       if (enic->pp.set & ENIC_SET_INSTANCE)
+               NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
+                       enic->pp.instance_uuid);
+       if (enic->pp.set & ENIC_SET_HOST)
+               NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
+                       enic->pp.host_uuid);
 
        return 0;
 
@@ -1280,51 +1287,6 @@ static int enic_set_rq_alloc_buf(struct enic *enic)
        return 0;
 }
 
-static int enic_get_skb_header(struct sk_buff *skb, void **iphdr,
-       void **tcph, u64 *hdr_flags, void *priv)
-{
-       struct cq_enet_rq_desc *cq_desc = priv;
-       unsigned int ip_len;
-       struct iphdr *iph;
-
-       u8 type, color, eop, sop, ingress_port, vlan_stripped;
-       u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
-       u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
-       u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
-       u8 packet_error;
-       u16 q_number, completed_index, bytes_written, vlan, checksum;
-       u32 rss_hash;
-
-       cq_enet_rq_desc_dec(cq_desc,
-               &type, &color, &q_number, &completed_index,
-               &ingress_port, &fcoe, &eop, &sop, &rss_type,
-               &csum_not_calc, &rss_hash, &bytes_written,
-               &packet_error, &vlan_stripped, &vlan, &checksum,
-               &fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
-               &fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
-               &ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
-               &fcs_ok);
-
-       if (!(ipv4 && tcp && !ipv4_fragment))
-               return -1;
-
-       skb_reset_network_header(skb);
-       iph = ip_hdr(skb);
-
-       ip_len = ip_hdrlen(skb);
-       skb_set_transport_header(skb, ip_len);
-
-       /* check if ip header and tcp header are complete */
-       if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb))
-               return -1;
-
-       *hdr_flags = LRO_IPV4 | LRO_TCP;
-       *tcph = tcp_hdr(skb);
-       *iphdr = iph;
-
-       return 0;
-}
-
 static void enic_rq_indicate_buf(struct vnic_rq *rq,
        struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
        int skipped, void *opaque)
@@ -1390,18 +1352,17 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
 
                if (enic->vlan_group && vlan_stripped) {
 
-                       if ((netdev->features & NETIF_F_LRO) && ipv4)
-                               lro_vlan_hwaccel_receive_skb(&enic->lro_mgr,
-                                       skb, enic->vlan_group,
-                                       vlan, cq_desc);
+                       if (netdev->features & NETIF_F_GRO)
+                               vlan_gro_receive(&enic->napi, enic->vlan_group,
+                                       vlan, skb);
                        else
                                vlan_hwaccel_receive_skb(skb,
                                        enic->vlan_group, vlan);
 
                } else {
 
-                       if ((netdev->features & NETIF_F_LRO) && ipv4)
-                               lro_receive_skb(&enic->lro_mgr, skb, cq_desc);
+                       if (netdev->features & NETIF_F_GRO)
+                               napi_gro_receive(&enic->napi, skb);
                        else
                                netif_receive_skb(skb);
 
@@ -1431,7 +1392,6 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
 static int enic_poll(struct napi_struct *napi, int budget)
 {
        struct enic *enic = container_of(napi, struct enic, napi);
-       struct net_device *netdev = enic->netdev;
        unsigned int rq_work_to_do = budget;
        unsigned int wq_work_to_do = -1; /* no limit */
        unsigned int  work_done, rq_work_done, wq_work_done;
@@ -1471,12 +1431,9 @@ static int enic_poll(struct napi_struct *napi, int budget)
        if (rq_work_done < rq_work_to_do) {
 
                /* Some work done, but not enough to stay in polling,
-                * flush all LROs and exit polling
+                * exit polling
                 */
 
-               if (netdev->features & NETIF_F_LRO)
-                       lro_flush_all(&enic->lro_mgr);
-
                napi_complete(napi);
                vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]);
        }
@@ -1487,7 +1444,6 @@ static int enic_poll(struct napi_struct *napi, int budget)
 static int enic_poll_msix(struct napi_struct *napi, int budget)
 {
        struct enic *enic = container_of(napi, struct enic, napi);
-       struct net_device *netdev = enic->netdev;
        unsigned int work_to_do = budget;
        unsigned int work_done;
        int err;
@@ -1521,12 +1477,9 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
        if (work_done < work_to_do) {
 
                /* Some work done, but not enough to stay in polling,
-                * flush all LROs and exit polling
+                * exit polling
                 */
 
-               if (netdev->features & NETIF_F_LRO)
-                       lro_flush_all(&enic->lro_mgr);
-
                napi_complete(napi);
                vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]);
        }
@@ -2371,21 +2324,12 @@ static int __devinit enic_probe(struct pci_dev *pdev,
                netdev->features |= NETIF_F_TSO |
                        NETIF_F_TSO6 | NETIF_F_TSO_ECN;
        if (ENIC_SETTING(enic, LRO))
-               netdev->features |= NETIF_F_LRO;
+               netdev->features |= NETIF_F_GRO;
        if (using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
 
        enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM);
 
-       enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR;
-       enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC;
-       enic->lro_mgr.lro_arr = enic->lro_desc;
-       enic->lro_mgr.get_skb_header = enic_get_skb_header;
-       enic->lro_mgr.features  = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
-       enic->lro_mgr.dev = netdev;
-       enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE;
-       enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
-
        err = register_netdev(netdev);
        if (err) {
                printk(KERN_ERR PFX