diff options
Diffstat (limited to 'drivers/net/enic/enic_main.c')
-rw-r--r-- | drivers/net/enic/enic_main.c | 330 |
1 files changed, 318 insertions, 12 deletions
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 1232887c243..e125113759a 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/etherdevice.h> | 29 | #include <linux/etherdevice.h> |
30 | #include <linux/if_ether.h> | 30 | #include <linux/if_ether.h> |
31 | #include <linux/if_vlan.h> | 31 | #include <linux/if_vlan.h> |
32 | #include <linux/if_link.h> | ||
32 | #include <linux/ethtool.h> | 33 | #include <linux/ethtool.h> |
33 | #include <linux/in.h> | 34 | #include <linux/in.h> |
34 | #include <linux/ip.h> | 35 | #include <linux/ip.h> |
@@ -40,6 +41,7 @@ | |||
40 | #include "vnic_dev.h" | 41 | #include "vnic_dev.h" |
41 | #include "vnic_intr.h" | 42 | #include "vnic_intr.h" |
42 | #include "vnic_stats.h" | 43 | #include "vnic_stats.h" |
44 | #include "vnic_vic.h" | ||
43 | #include "enic_res.h" | 45 | #include "enic_res.h" |
44 | #include "enic.h" | 46 | #include "enic.h" |
45 | 47 | ||
@@ -49,10 +51,12 @@ | |||
49 | #define ENIC_DESC_MAX_SPLITS (MAX_TSO / WQ_ENET_MAX_DESC_LEN + 1) | 51 | #define ENIC_DESC_MAX_SPLITS (MAX_TSO / WQ_ENET_MAX_DESC_LEN + 1) |
50 | 52 | ||
51 | #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ | 53 | #define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */ |
54 | #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */ | ||
52 | 55 | ||
53 | /* Supported devices */ | 56 | /* Supported devices */ |
54 | static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = { | 57 | static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = { |
55 | { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, | 58 | { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) }, |
59 | { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) }, | ||
56 | { 0, } /* end of table */ | 60 | { 0, } /* end of table */ |
57 | }; | 61 | }; |
58 | 62 | ||
@@ -113,6 +117,11 @@ static const struct enic_stat enic_rx_stats[] = { | |||
113 | static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); | 117 | static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); |
114 | static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); | 118 | static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); |
115 | 119 | ||
120 | static int enic_is_dynamic(struct enic *enic) | ||
121 | { | ||
122 | return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN; | ||
123 | } | ||
124 | |||
116 | static int enic_get_settings(struct net_device *netdev, | 125 | static int enic_get_settings(struct net_device *netdev, |
117 | struct ethtool_cmd *ecmd) | 126 | struct ethtool_cmd *ecmd) |
118 | { | 127 | { |
@@ -810,14 +819,78 @@ static void enic_reset_mcaddrs(struct enic *enic) | |||
810 | 819 | ||
811 | static int enic_set_mac_addr(struct net_device *netdev, char *addr) | 820 | static int enic_set_mac_addr(struct net_device *netdev, char *addr) |
812 | { | 821 | { |
813 | if (!is_valid_ether_addr(addr)) | 822 | struct enic *enic = netdev_priv(netdev); |
814 | return -EADDRNOTAVAIL; | 823 | |
824 | if (enic_is_dynamic(enic)) { | ||
825 | if (!is_valid_ether_addr(addr) && !is_zero_ether_addr(addr)) | ||
826 | return -EADDRNOTAVAIL; | ||
827 | } else { | ||
828 | if (!is_valid_ether_addr(addr)) | ||
829 | return -EADDRNOTAVAIL; | ||
830 | } | ||
815 | 831 | ||
816 | memcpy(netdev->dev_addr, addr, netdev->addr_len); | 832 | memcpy(netdev->dev_addr, addr, netdev->addr_len); |
817 | 833 | ||
818 | return 0; | 834 | return 0; |
819 | } | 835 | } |
820 | 836 | ||
837 | static int enic_dev_add_station_addr(struct enic *enic) | ||
838 | { | ||
839 | int err = 0; | ||
840 | |||
841 | if (is_valid_ether_addr(enic->netdev->dev_addr)) { | ||
842 | spin_lock(&enic->devcmd_lock); | ||
843 | err = vnic_dev_add_addr(enic->vdev, enic->netdev->dev_addr); | ||
844 | spin_unlock(&enic->devcmd_lock); | ||
845 | } | ||
846 | |||
847 | return err; | ||
848 | } | ||
849 | |||
850 | static int enic_dev_del_station_addr(struct enic *enic) | ||
851 | { | ||
852 | int err = 0; | ||
853 | |||
854 | if (is_valid_ether_addr(enic->netdev->dev_addr)) { | ||
855 | spin_lock(&enic->devcmd_lock); | ||
856 | err = vnic_dev_del_addr(enic->vdev, enic->netdev->dev_addr); | ||
857 | spin_unlock(&enic->devcmd_lock); | ||
858 | } | ||
859 | |||
860 | return err; | ||
861 | } | ||
862 | |||
863 | static int enic_set_mac_address_dynamic(struct net_device *netdev, void *p) | ||
864 | { | ||
865 | struct enic *enic = netdev_priv(netdev); | ||
866 | struct sockaddr *saddr = p; | ||
867 | char *addr = saddr->sa_data; | ||
868 | int err; | ||
869 | |||
870 | if (netif_running(enic->netdev)) { | ||
871 | err = enic_dev_del_station_addr(enic); | ||
872 | if (err) | ||
873 | return err; | ||
874 | } | ||
875 | |||
876 | err = enic_set_mac_addr(netdev, addr); | ||
877 | if (err) | ||
878 | return err; | ||
879 | |||
880 | if (netif_running(enic->netdev)) { | ||
881 | err = enic_dev_add_station_addr(enic); | ||
882 | if (err) | ||
883 | return err; | ||
884 | } | ||
885 | |||
886 | return err; | ||
887 | } | ||
888 | |||
889 | static int enic_set_mac_address(struct net_device *netdev, void *p) | ||
890 | { | ||
891 | return -EOPNOTSUPP; | ||
892 | } | ||
893 | |||
821 | /* netif_tx_lock held, BHs disabled */ | 894 | /* netif_tx_lock held, BHs disabled */ |
822 | static void enic_set_multicast_list(struct net_device *netdev) | 895 | static void enic_set_multicast_list(struct net_device *netdev) |
823 | { | 896 | { |
@@ -922,6 +995,213 @@ static void enic_tx_timeout(struct net_device *netdev) | |||
922 | schedule_work(&enic->reset); | 995 | schedule_work(&enic->reset); |
923 | } | 996 | } |
924 | 997 | ||
998 | static int enic_vnic_dev_deinit(struct enic *enic) | ||
999 | { | ||
1000 | int err; | ||
1001 | |||
1002 | spin_lock(&enic->devcmd_lock); | ||
1003 | err = vnic_dev_deinit(enic->vdev); | ||
1004 | spin_unlock(&enic->devcmd_lock); | ||
1005 | |||
1006 | return err; | ||
1007 | } | ||
1008 | |||
1009 | static int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp) | ||
1010 | { | ||
1011 | int err; | ||
1012 | |||
1013 | spin_lock(&enic->devcmd_lock); | ||
1014 | err = vnic_dev_init_prov(enic->vdev, | ||
1015 | (u8 *)vp, vic_provinfo_size(vp)); | ||
1016 | spin_unlock(&enic->devcmd_lock); | ||
1017 | |||
1018 | return err; | ||
1019 | } | ||
1020 | |||
1021 | static int enic_dev_init_done(struct enic *enic, int *done, int *error) | ||
1022 | { | ||
1023 | int err; | ||
1024 | |||
1025 | spin_lock(&enic->devcmd_lock); | ||
1026 | err = vnic_dev_init_done(enic->vdev, done, error); | ||
1027 | spin_unlock(&enic->devcmd_lock); | ||
1028 | |||
1029 | return err; | ||
1030 | } | ||
1031 | |||
1032 | static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac, | ||
1033 | char *name, u8 *instance_uuid, u8 *host_uuid) | ||
1034 | { | ||
1035 | struct vic_provinfo *vp; | ||
1036 | u8 oui[3] = VIC_PROVINFO_CISCO_OUI; | ||
1037 | unsigned short *uuid; | ||
1038 | char uuid_str[38]; | ||
1039 | static char *uuid_fmt = "%04X%04X-%04X-%04X-%04X-%04X%04X%04X"; | ||
1040 | int err; | ||
1041 | |||
1042 | if (!name) | ||
1043 | return -EINVAL; | ||
1044 | |||
1045 | if (!is_valid_ether_addr(mac)) | ||
1046 | return -EADDRNOTAVAIL; | ||
1047 | |||
1048 | vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE); | ||
1049 | if (!vp) | ||
1050 | return -ENOMEM; | ||
1051 | |||
1052 | vic_provinfo_add_tlv(vp, | ||
1053 | VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR, | ||
1054 | strlen(name) + 1, name); | ||
1055 | |||
1056 | vic_provinfo_add_tlv(vp, | ||
1057 | VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR, | ||
1058 | ETH_ALEN, mac); | ||
1059 | |||
1060 | if (instance_uuid) { | ||
1061 | uuid = (unsigned short *)instance_uuid; | ||
1062 | sprintf(uuid_str, uuid_fmt, | ||
1063 | uuid[0], uuid[1], uuid[2], uuid[3], | ||
1064 | uuid[4], uuid[5], uuid[6], uuid[7]); | ||
1065 | vic_provinfo_add_tlv(vp, | ||
1066 | VIC_LINUX_PROV_TLV_CLIENT_UUID_STR, | ||
1067 | sizeof(uuid_str), uuid_str); | ||
1068 | } | ||
1069 | |||
1070 | if (host_uuid) { | ||
1071 | uuid = (unsigned short *)host_uuid; | ||
1072 | sprintf(uuid_str, uuid_fmt, | ||
1073 | uuid[0], uuid[1], uuid[2], uuid[3], | ||
1074 | uuid[4], uuid[5], uuid[6], uuid[7]); | ||
1075 | vic_provinfo_add_tlv(vp, | ||
1076 | VIC_LINUX_PROV_TLV_HOST_UUID_STR, | ||
1077 | sizeof(uuid_str), uuid_str); | ||
1078 | } | ||
1079 | |||
1080 | err = enic_vnic_dev_deinit(enic); | ||
1081 | if (err) | ||
1082 | goto err_out; | ||
1083 | |||
1084 | memset(&enic->pp, 0, sizeof(enic->pp)); | ||
1085 | |||
1086 | err = enic_dev_init_prov(enic, vp); | ||
1087 | if (err) | ||
1088 | goto err_out; | ||
1089 | |||
1090 | enic->pp.request = request; | ||
1091 | memcpy(enic->pp.name, name, PORT_PROFILE_MAX); | ||
1092 | if (instance_uuid) | ||
1093 | memcpy(enic->pp.instance_uuid, | ||
1094 | instance_uuid, PORT_UUID_MAX); | ||
1095 | if (host_uuid) | ||
1096 | memcpy(enic->pp.host_uuid, | ||
1097 | host_uuid, PORT_UUID_MAX); | ||
1098 | |||
1099 | err_out: | ||
1100 | vic_provinfo_free(vp); | ||
1101 | |||
1102 | return err; | ||
1103 | } | ||
1104 | |||
1105 | static int enic_unset_port_profile(struct enic *enic) | ||
1106 | { | ||
1107 | memset(&enic->pp, 0, sizeof(enic->pp)); | ||
1108 | return enic_vnic_dev_deinit(enic); | ||
1109 | } | ||
1110 | |||
1111 | static int enic_set_vf_port(struct net_device *netdev, int vf, | ||
1112 | struct nlattr *port[]) | ||
1113 | { | ||
1114 | struct enic *enic = netdev_priv(netdev); | ||
1115 | char *name = NULL; | ||
1116 | u8 *instance_uuid = NULL; | ||
1117 | u8 *host_uuid = NULL; | ||
1118 | u8 request = PORT_REQUEST_DISASSOCIATE; | ||
1119 | |||
1120 | /* don't support VFs, yet */ | ||
1121 | if (vf != PORT_SELF_VF) | ||
1122 | return -EOPNOTSUPP; | ||
1123 | |||
1124 | if (port[IFLA_PORT_REQUEST]) | ||
1125 | request = nla_get_u8(port[IFLA_PORT_REQUEST]); | ||
1126 | |||
1127 | switch (request) { | ||
1128 | case PORT_REQUEST_ASSOCIATE: | ||
1129 | |||
1130 | if (port[IFLA_PORT_PROFILE]) | ||
1131 | name = nla_data(port[IFLA_PORT_PROFILE]); | ||
1132 | |||
1133 | if (port[IFLA_PORT_INSTANCE_UUID]) | ||
1134 | instance_uuid = | ||
1135 | nla_data(port[IFLA_PORT_INSTANCE_UUID]); | ||
1136 | |||
1137 | if (port[IFLA_PORT_HOST_UUID]) | ||
1138 | host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]); | ||
1139 | |||
1140 | return enic_set_port_profile(enic, request, | ||
1141 | netdev->dev_addr, name, | ||
1142 | instance_uuid, host_uuid); | ||
1143 | |||
1144 | case PORT_REQUEST_DISASSOCIATE: | ||
1145 | |||
1146 | return enic_unset_port_profile(enic); | ||
1147 | |||
1148 | default: | ||
1149 | break; | ||
1150 | } | ||
1151 | |||
1152 | return -EOPNOTSUPP; | ||
1153 | } | ||
1154 | |||
1155 | static int enic_get_vf_port(struct net_device *netdev, int vf, | ||
1156 | struct sk_buff *skb) | ||
1157 | { | ||
1158 | struct enic *enic = netdev_priv(netdev); | ||
1159 | int err, error, done; | ||
1160 | u16 response = PORT_PROFILE_RESPONSE_SUCCESS; | ||
1161 | |||
1162 | /* don't support VFs, yet */ | ||
1163 | if (vf != PORT_SELF_VF) | ||
1164 | return -EOPNOTSUPP; | ||
1165 | |||
1166 | err = enic_dev_init_done(enic, &done, &error); | ||
1167 | |||
1168 | if (err) | ||
1169 | return err; | ||
1170 | |||
1171 | switch (error) { | ||
1172 | case ERR_SUCCESS: | ||
1173 | if (!done) | ||
1174 | response = PORT_PROFILE_RESPONSE_INPROGRESS; | ||
1175 | break; | ||
1176 | case ERR_EINVAL: | ||
1177 | response = PORT_PROFILE_RESPONSE_INVALID; | ||
1178 | break; | ||
1179 | case ERR_EBADSTATE: | ||
1180 | response = PORT_PROFILE_RESPONSE_BADSTATE; | ||
1181 | break; | ||
1182 | case ERR_ENOMEM: | ||
1183 | response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES; | ||
1184 | break; | ||
1185 | default: | ||
1186 | response = PORT_PROFILE_RESPONSE_ERROR; | ||
1187 | break; | ||
1188 | } | ||
1189 | |||
1190 | NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request); | ||
1191 | NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response); | ||
1192 | NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX, | ||
1193 | enic->pp.name); | ||
1194 | NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX, | ||
1195 | enic->pp.instance_uuid); | ||
1196 | NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX, | ||
1197 | enic->pp.host_uuid); | ||
1198 | |||
1199 | return 0; | ||
1200 | |||
1201 | nla_put_failure: | ||
1202 | return -EMSGSIZE; | ||
1203 | } | ||
1204 | |||
925 | static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) | 1205 | static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) |
926 | { | 1206 | { |
927 | struct enic *enic = vnic_dev_priv(rq->vdev); | 1207 | struct enic *enic = vnic_dev_priv(rq->vdev); |
@@ -1440,9 +1720,7 @@ static int enic_open(struct net_device *netdev) | |||
1440 | for (i = 0; i < enic->rq_count; i++) | 1720 | for (i = 0; i < enic->rq_count; i++) |
1441 | vnic_rq_enable(&enic->rq[i]); | 1721 | vnic_rq_enable(&enic->rq[i]); |
1442 | 1722 | ||
1443 | spin_lock(&enic->devcmd_lock); | 1723 | enic_dev_add_station_addr(enic); |
1444 | enic_add_station_addr(enic); | ||
1445 | spin_unlock(&enic->devcmd_lock); | ||
1446 | enic_set_multicast_list(netdev); | 1724 | enic_set_multicast_list(netdev); |
1447 | 1725 | ||
1448 | netif_wake_queue(netdev); | 1726 | netif_wake_queue(netdev); |
@@ -1489,6 +1767,8 @@ static int enic_stop(struct net_device *netdev) | |||
1489 | netif_carrier_off(netdev); | 1767 | netif_carrier_off(netdev); |
1490 | netif_tx_disable(netdev); | 1768 | netif_tx_disable(netdev); |
1491 | 1769 | ||
1770 | enic_dev_del_station_addr(enic); | ||
1771 | |||
1492 | for (i = 0; i < enic->wq_count; i++) { | 1772 | for (i = 0; i < enic->wq_count; i++) { |
1493 | err = vnic_wq_disable(&enic->wq[i]); | 1773 | err = vnic_wq_disable(&enic->wq[i]); |
1494 | if (err) | 1774 | if (err) |
@@ -1774,14 +2054,34 @@ static void enic_clear_intr_mode(struct enic *enic) | |||
1774 | vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); | 2054 | vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); |
1775 | } | 2055 | } |
1776 | 2056 | ||
2057 | static const struct net_device_ops enic_netdev_dynamic_ops = { | ||
2058 | .ndo_open = enic_open, | ||
2059 | .ndo_stop = enic_stop, | ||
2060 | .ndo_start_xmit = enic_hard_start_xmit, | ||
2061 | .ndo_get_stats = enic_get_stats, | ||
2062 | .ndo_validate_addr = eth_validate_addr, | ||
2063 | .ndo_set_multicast_list = enic_set_multicast_list, | ||
2064 | .ndo_set_mac_address = enic_set_mac_address_dynamic, | ||
2065 | .ndo_change_mtu = enic_change_mtu, | ||
2066 | .ndo_vlan_rx_register = enic_vlan_rx_register, | ||
2067 | .ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid, | ||
2068 | .ndo_vlan_rx_kill_vid = enic_vlan_rx_kill_vid, | ||
2069 | .ndo_tx_timeout = enic_tx_timeout, | ||
2070 | .ndo_set_vf_port = enic_set_vf_port, | ||
2071 | .ndo_get_vf_port = enic_get_vf_port, | ||
2072 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
2073 | .ndo_poll_controller = enic_poll_controller, | ||
2074 | #endif | ||
2075 | }; | ||
2076 | |||
1777 | static const struct net_device_ops enic_netdev_ops = { | 2077 | static const struct net_device_ops enic_netdev_ops = { |
1778 | .ndo_open = enic_open, | 2078 | .ndo_open = enic_open, |
1779 | .ndo_stop = enic_stop, | 2079 | .ndo_stop = enic_stop, |
1780 | .ndo_start_xmit = enic_hard_start_xmit, | 2080 | .ndo_start_xmit = enic_hard_start_xmit, |
1781 | .ndo_get_stats = enic_get_stats, | 2081 | .ndo_get_stats = enic_get_stats, |
1782 | .ndo_validate_addr = eth_validate_addr, | 2082 | .ndo_validate_addr = eth_validate_addr, |
1783 | .ndo_set_mac_address = eth_mac_addr, | ||
1784 | .ndo_set_multicast_list = enic_set_multicast_list, | 2083 | .ndo_set_multicast_list = enic_set_multicast_list, |
2084 | .ndo_set_mac_address = enic_set_mac_address, | ||
1785 | .ndo_change_mtu = enic_change_mtu, | 2085 | .ndo_change_mtu = enic_change_mtu, |
1786 | .ndo_vlan_rx_register = enic_vlan_rx_register, | 2086 | .ndo_vlan_rx_register = enic_vlan_rx_register, |
1787 | .ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid, | 2087 | .ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid, |
@@ -2010,11 +2310,13 @@ static int __devinit enic_probe(struct pci_dev *pdev, | |||
2010 | 2310 | ||
2011 | netif_carrier_off(netdev); | 2311 | netif_carrier_off(netdev); |
2012 | 2312 | ||
2013 | err = vnic_dev_init(enic->vdev, 0); | 2313 | if (!enic_is_dynamic(enic)) { |
2014 | if (err) { | 2314 | err = vnic_dev_init(enic->vdev, 0); |
2015 | printk(KERN_ERR PFX | 2315 | if (err) { |
2016 | "vNIC dev init failed, aborting.\n"); | 2316 | printk(KERN_ERR PFX |
2017 | goto err_out_dev_close; | 2317 | "vNIC dev init failed, aborting.\n"); |
2318 | goto err_out_dev_close; | ||
2319 | } | ||
2018 | } | 2320 | } |
2019 | 2321 | ||
2020 | err = enic_dev_init(enic); | 2322 | err = enic_dev_init(enic); |
@@ -2054,7 +2356,11 @@ static int __devinit enic_probe(struct pci_dev *pdev, | |||
2054 | enic->tx_coalesce_usecs = enic->config.intr_timer_usec; | 2356 | enic->tx_coalesce_usecs = enic->config.intr_timer_usec; |
2055 | enic->rx_coalesce_usecs = enic->tx_coalesce_usecs; | 2357 | enic->rx_coalesce_usecs = enic->tx_coalesce_usecs; |
2056 | 2358 | ||
2057 | netdev->netdev_ops = &enic_netdev_ops; | 2359 | if (enic_is_dynamic(enic)) |
2360 | netdev->netdev_ops = &enic_netdev_dynamic_ops; | ||
2361 | else | ||
2362 | netdev->netdev_ops = &enic_netdev_ops; | ||
2363 | |||
2058 | netdev->watchdog_timeo = 2 * HZ; | 2364 | netdev->watchdog_timeo = 2 * HZ; |
2059 | netdev->ethtool_ops = &enic_ethtool_ops; | 2365 | netdev->ethtool_ops = &enic_ethtool_ops; |
2060 | 2366 | ||