diff options
author | KY Srinivasan <kys@microsoft.com> | 2014-03-08 22:23:15 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-10 15:51:37 -0400 |
commit | 4a0e70ae5e3858052f6d91564bf3484f1eb91dc7 (patch) | |
tree | ad22a782fadd04320ac9ec061036a4f236d39130 /drivers/net/hyperv | |
parent | 8a00251a3682a23649cef36949c8019f8589c021 (diff) |
Drivers: net: hyperv: Enable offloads on the host
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>
Diffstat (limited to 'drivers/net/hyperv')
-rw-r--r-- | drivers/net/hyperv/hyperv_net.h | 55 | ||||
-rw-r--r-- | drivers/net/hyperv/rndis_filter.c | 80 |
2 files changed, 135 insertions, 0 deletions
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 694bf7cada90..8bc4e766589b 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h | |||
@@ -721,6 +721,61 @@ struct ndis_pkt_8021q_info { | |||
721 | }; | 721 | }; |
722 | }; | 722 | }; |
723 | 723 | ||
724 | struct ndis_oject_header { | ||
725 | u8 type; | ||
726 | u8 revision; | ||
727 | u16 size; | ||
728 | }; | ||
729 | |||
730 | #define NDIS_OBJECT_TYPE_DEFAULT 0x80 | ||
731 | #define NDIS_OFFLOAD_PARAMETERS_REVISION_3 3 | ||
732 | #define NDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0 | ||
733 | #define NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1 | ||
734 | #define NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED 2 | ||
735 | #define NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED 2 | ||
736 | #define NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1 | ||
737 | #define NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2 | ||
738 | #define NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1 | ||
739 | #define NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2 | ||
740 | #define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 | ||
741 | #define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 | ||
742 | |||
743 | /* | ||
744 | * New offload OIDs for NDIS 6 | ||
745 | */ | ||
746 | #define OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */ | ||
747 | #define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C /* set only */ | ||
748 | #define OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */ | ||
749 | #define OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */ | ||
750 | #define OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */ | ||
751 | #define OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */ | ||
752 | |||
753 | struct ndis_offload_params { | ||
754 | struct ndis_oject_header header; | ||
755 | u8 ip_v4_csum; | ||
756 | u8 tcp_ip_v4_csum; | ||
757 | u8 udp_ip_v4_csum; | ||
758 | u8 tcp_ip_v6_csum; | ||
759 | u8 udp_ip_v6_csum; | ||
760 | u8 lso_v1; | ||
761 | u8 ip_sec_v1; | ||
762 | u8 lso_v2_ipv4; | ||
763 | u8 lso_v2_ipv6; | ||
764 | u8 tcp_connection_ip_v4; | ||
765 | u8 tcp_connection_ip_v6; | ||
766 | u32 flags; | ||
767 | u8 ip_sec_v2; | ||
768 | u8 ip_sec_v2_ip_v4; | ||
769 | struct { | ||
770 | u8 rsc_ip_v4; | ||
771 | u8 rsc_ip_v6; | ||
772 | }; | ||
773 | struct { | ||
774 | u8 encapsulated_packet_task_offload; | ||
775 | u8 encapsulation_types; | ||
776 | }; | ||
777 | }; | ||
778 | |||
724 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ | 779 | #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ |
725 | sizeof(struct ndis_pkt_8021q_info)) | 780 | sizeof(struct ndis_pkt_8021q_info)) |
726 | 781 | ||
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index eaa149950af7..42bfb3a11efd 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c | |||
@@ -607,6 +607,61 @@ cleanup: | |||
607 | return ret; | 607 | return ret; |
608 | } | 608 | } |
609 | 609 | ||
610 | int rndis_filter_set_offload_params(struct hv_device *hdev, | ||
611 | struct ndis_offload_params *req_offloads) | ||
612 | { | ||
613 | struct netvsc_device *nvdev = hv_get_drvdata(hdev); | ||
614 | struct rndis_device *rdev = nvdev->extension; | ||
615 | struct net_device *ndev = nvdev->ndev; | ||
616 | struct rndis_request *request; | ||
617 | struct rndis_set_request *set; | ||
618 | struct ndis_offload_params *offload_params; | ||
619 | struct rndis_set_complete *set_complete; | ||
620 | u32 extlen = sizeof(struct ndis_offload_params); | ||
621 | int ret, t; | ||
622 | |||
623 | request = get_rndis_request(rdev, RNDIS_MSG_SET, | ||
624 | RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); | ||
625 | if (!request) | ||
626 | return -ENOMEM; | ||
627 | |||
628 | set = &request->request_msg.msg.set_req; | ||
629 | set->oid = OID_TCP_OFFLOAD_PARAMETERS; | ||
630 | set->info_buflen = extlen; | ||
631 | set->info_buf_offset = sizeof(struct rndis_set_request); | ||
632 | set->dev_vc_handle = 0; | ||
633 | |||
634 | offload_params = (struct ndis_offload_params *)((ulong)set + | ||
635 | set->info_buf_offset); | ||
636 | *offload_params = *req_offloads; | ||
637 | offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT; | ||
638 | offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3; | ||
639 | offload_params->header.size = extlen; | ||
640 | |||
641 | ret = rndis_filter_send_request(rdev, request); | ||
642 | if (ret != 0) | ||
643 | goto cleanup; | ||
644 | |||
645 | t = wait_for_completion_timeout(&request->wait_event, 5*HZ); | ||
646 | if (t == 0) { | ||
647 | netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n"); | ||
648 | /* can't put_rndis_request, since we may still receive a | ||
649 | * send-completion. | ||
650 | */ | ||
651 | return -EBUSY; | ||
652 | } else { | ||
653 | set_complete = &request->response_msg.msg.set_complete; | ||
654 | if (set_complete->status != RNDIS_STATUS_SUCCESS) { | ||
655 | netdev_err(ndev, "Fail to set MAC on host side:0x%x\n", | ||
656 | set_complete->status); | ||
657 | ret = -EINVAL; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | cleanup: | ||
662 | put_rndis_request(rdev, request); | ||
663 | return ret; | ||
664 | } | ||
610 | 665 | ||
611 | static int rndis_filter_query_device_link_status(struct rndis_device *dev) | 666 | static int rndis_filter_query_device_link_status(struct rndis_device *dev) |
612 | { | 667 | { |
@@ -807,6 +862,7 @@ int rndis_filter_device_add(struct hv_device *dev, | |||
807 | struct netvsc_device *net_device; | 862 | struct netvsc_device *net_device; |
808 | struct rndis_device *rndis_device; | 863 | struct rndis_device *rndis_device; |
809 | struct netvsc_device_info *device_info = additional_info; | 864 | struct netvsc_device_info *device_info = additional_info; |
865 | struct ndis_offload_params offloads; | ||
810 | 866 | ||
811 | rndis_device = get_rndis_device(); | 867 | rndis_device = get_rndis_device(); |
812 | if (!rndis_device) | 868 | if (!rndis_device) |
@@ -846,6 +902,26 @@ int rndis_filter_device_add(struct hv_device *dev, | |||
846 | 902 | ||
847 | memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); | 903 | memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); |
848 | 904 | ||
905 | /* Turn on the offloads; the host supports all of the relevant | ||
906 | * offloads. | ||
907 | */ | ||
908 | memset(&offloads, 0, sizeof(struct ndis_offload_params)); | ||
909 | /* A value of zero means "no change"; now turn on what we | ||
910 | * want. | ||
911 | */ | ||
912 | offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
913 | offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
914 | offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
915 | offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
916 | offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; | ||
917 | offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED; | ||
918 | |||
919 | |||
920 | ret = rndis_filter_set_offload_params(dev, &offloads); | ||
921 | if (ret) | ||
922 | goto err_dev_remv; | ||
923 | |||
924 | |||
849 | rndis_filter_query_device_link_status(rndis_device); | 925 | rndis_filter_query_device_link_status(rndis_device); |
850 | 926 | ||
851 | device_info->link_state = rndis_device->link_state; | 927 | device_info->link_state = rndis_device->link_state; |
@@ -855,6 +931,10 @@ int rndis_filter_device_add(struct hv_device *dev, | |||
855 | device_info->link_state ? "down" : "up"); | 931 | device_info->link_state ? "down" : "up"); |
856 | 932 | ||
857 | return ret; | 933 | return ret; |
934 | |||
935 | err_dev_remv: | ||
936 | rndis_filter_device_remove(dev); | ||
937 | return ret; | ||
858 | } | 938 | } |
859 | 939 | ||
860 | void rndis_filter_device_remove(struct hv_device *dev) | 940 | void rndis_filter_device_remove(struct hv_device *dev) |