Commit 4a0e70ae authored by KY Srinivasan's avatar KY Srinivasan Committed by David S. Miller

Drivers: net: hyperv: Enable offloads on the host

Prior to enabling guest side offloads, enable the offloads on the host.
Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Reviewed-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8a00251a
...@@ -721,6 +721,61 @@ struct ndis_pkt_8021q_info { ...@@ -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) + \ #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
sizeof(struct ndis_pkt_8021q_info)) sizeof(struct ndis_pkt_8021q_info))
......
...@@ -607,6 +607,61 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac) ...@@ -607,6 +607,61 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
return ret; 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) 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, ...@@ -807,6 +862,7 @@ int rndis_filter_device_add(struct hv_device *dev,
struct netvsc_device *net_device; struct netvsc_device *net_device;
struct rndis_device *rndis_device; struct rndis_device *rndis_device;
struct netvsc_device_info *device_info = additional_info; struct netvsc_device_info *device_info = additional_info;
struct ndis_offload_params offloads;
rndis_device = get_rndis_device(); rndis_device = get_rndis_device();
if (!rndis_device) if (!rndis_device)
...@@ -846,6 +902,26 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -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); 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); rndis_filter_query_device_link_status(rndis_device);
device_info->link_state = rndis_device->link_state; device_info->link_state = rndis_device->link_state;
...@@ -855,6 +931,10 @@ int rndis_filter_device_add(struct hv_device *dev, ...@@ -855,6 +931,10 @@ int rndis_filter_device_add(struct hv_device *dev,
device_info->link_state ? "down" : "up"); device_info->link_state ? "down" : "up");
return ret; return ret;
err_dev_remv:
rndis_filter_device_remove(dev);
return ret;
} }
void rndis_filter_device_remove(struct hv_device *dev) void rndis_filter_device_remove(struct hv_device *dev)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment