Drivers: net: hyperv: Enable offloads on the host
authorKY Srinivasan <kys@microsoft.com>
Sun, 9 Mar 2014 03:23:15 +0000 (19:23 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 10 Mar 2014 19:51:37 +0000 (15:51 -0400)
Prior to enabling guest side offloads, enable the offloads on the host.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/rndis_filter.c

index 694bf7cada903e4a772d0355ceef37a77057d495..8bc4e766589b6167cf10f36aa45716227e93a27a 100644 (file)
@@ -721,6 +721,61 @@ struct ndis_pkt_8021q_info {
        };
 };
 
+struct ndis_oject_header {
+       u8 type;
+       u8 revision;
+       u16 size;
+};
+
+#define NDIS_OBJECT_TYPE_DEFAULT       0x80
+#define NDIS_OFFLOAD_PARAMETERS_REVISION_3 3
+#define NDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0
+#define NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED  2
+#define NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED  2
+#define NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3
+#define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4
+
+/*
+ * New offload OIDs for NDIS 6
+ */
+#define OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */
+#define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C          /* set only */
+#define OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */
+#define OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */
+#define OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */
+#define OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */
+
+struct ndis_offload_params {
+       struct ndis_oject_header header;
+       u8 ip_v4_csum;
+       u8 tcp_ip_v4_csum;
+       u8 udp_ip_v4_csum;
+       u8 tcp_ip_v6_csum;
+       u8 udp_ip_v6_csum;
+       u8 lso_v1;
+       u8 ip_sec_v1;
+       u8 lso_v2_ipv4;
+       u8 lso_v2_ipv6;
+       u8 tcp_connection_ip_v4;
+       u8 tcp_connection_ip_v6;
+       u32 flags;
+       u8 ip_sec_v2;
+       u8 ip_sec_v2_ip_v4;
+       struct {
+               u8 rsc_ip_v4;
+               u8 rsc_ip_v6;
+       };
+       struct {
+               u8 encapsulated_packet_task_offload;
+               u8 encapsulation_types;
+       };
+};
+
 #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
                sizeof(struct ndis_pkt_8021q_info))
 
index eaa149950af7efb97793dc1e7d3836f6f860770b..42bfb3a11efd490633e20f0a8a9f50e015584b64 100644 (file)
@@ -607,6 +607,61 @@ cleanup:
        return ret;
 }
 
+int rndis_filter_set_offload_params(struct hv_device *hdev,
+                               struct ndis_offload_params *req_offloads)
+{
+       struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+       struct rndis_device *rdev = nvdev->extension;
+       struct net_device *ndev = nvdev->ndev;
+       struct rndis_request *request;
+       struct rndis_set_request *set;
+       struct ndis_offload_params *offload_params;
+       struct rndis_set_complete *set_complete;
+       u32 extlen = sizeof(struct ndis_offload_params);
+       int ret, t;
+
+       request = get_rndis_request(rdev, RNDIS_MSG_SET,
+               RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
+       if (!request)
+               return -ENOMEM;
+
+       set = &request->request_msg.msg.set_req;
+       set->oid = OID_TCP_OFFLOAD_PARAMETERS;
+       set->info_buflen = extlen;
+       set->info_buf_offset = sizeof(struct rndis_set_request);
+       set->dev_vc_handle = 0;
+
+       offload_params = (struct ndis_offload_params *)((ulong)set +
+                               set->info_buf_offset);
+       *offload_params = *req_offloads;
+       offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT;
+       offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3;
+       offload_params->header.size = extlen;
+
+       ret = rndis_filter_send_request(rdev, request);
+       if (ret != 0)
+               goto cleanup;
+
+       t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+       if (t == 0) {
+               netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n");
+               /* can't put_rndis_request, since we may still receive a
+                * send-completion.
+                */
+               return -EBUSY;
+       } else {
+               set_complete = &request->response_msg.msg.set_complete;
+               if (set_complete->status != RNDIS_STATUS_SUCCESS) {
+                       netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
+                                  set_complete->status);
+                       ret = -EINVAL;
+               }
+       }
+
+cleanup:
+       put_rndis_request(rdev, request);
+       return ret;
+}
 
 static int rndis_filter_query_device_link_status(struct rndis_device *dev)
 {
@@ -807,6 +862,7 @@ int rndis_filter_device_add(struct hv_device *dev,
        struct netvsc_device *net_device;
        struct rndis_device *rndis_device;
        struct netvsc_device_info *device_info = additional_info;
+       struct ndis_offload_params offloads;
 
        rndis_device = get_rndis_device();
        if (!rndis_device)
@@ -846,6 +902,26 @@ int rndis_filter_device_add(struct hv_device *dev,
 
        memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
 
+       /* Turn on the offloads; the host supports all of the relevant
+        * offloads.
+        */
+       memset(&offloads, 0, sizeof(struct ndis_offload_params));
+       /* A value of zero means "no change"; now turn on what we
+        * want.
+        */
+       offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
+
+
+       ret = rndis_filter_set_offload_params(dev, &offloads);
+       if (ret)
+               goto err_dev_remv;
+
+
        rndis_filter_query_device_link_status(rndis_device);
 
        device_info->link_state = rndis_device->link_state;
@@ -855,6 +931,10 @@ int rndis_filter_device_add(struct hv_device *dev,
                 device_info->link_state ? "down" : "up");
 
        return ret;
+
+err_dev_remv:
+       rndis_filter_device_remove(dev);
+       return ret;
 }
 
 void rndis_filter_device_remove(struct hv_device *dev)