Skip to content

Commit

Permalink
Drivers: net: hyperv: Enable offloads on the host
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
KY Srinivasan authored and David S. Miller committed Mar 10, 2014
1 parent 8a00251 commit 4a0e70a
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 0 deletions.
55 changes: 55 additions & 0 deletions drivers/net/hyperv/hyperv_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
80 changes: 80 additions & 0 deletions drivers/net/hyperv/rndis_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,61 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
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)
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down

0 comments on commit 4a0e70a

Please sign in to comment.