diff options
author | Scott Feldman <scofeldm@cisco.com> | 2010-05-18 01:50:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-18 01:50:19 -0400 |
commit | f8bd909183acffad68780b10c1cdf36161cfd5d1 (patch) | |
tree | aefec6e6f1e67e93bc1b2ec223f974a4cd34f00f /drivers/net/enic | |
parent | 57b610805ce92dbd79fc97509f80fa5391b99623 (diff) |
net: Add ndo_{set|get}_vf_port support for enic dynamic vnics
Add enic ndo_{set|get}_vf_port ops to support setting/getting
port-profile for enic dynamic devices. Enic dynamic devices are just like
normal enic eth devices except dynamic enics require an extra configuration
step to assign a port-profile identifier to the interface before the
interface is useable. Once a port-profile is assigned, link comes up on the
interface and is ready for I/O. The port-profile is used to configure the
network port assigned to the interface. The network port configuration
includes VLAN membership, QoS policies, and port security settings typical
of a data center network.
A dynamic enic initially has a zero-mac address. Before a port-profile is
assigned, a valid non-zero unicast mac address should be assign to the
dynamic enic interface.
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
Signed-off-by: Roopa Prabhu <roprabhu@cisco.com>
Diffstat (limited to 'drivers/net/enic')
-rw-r--r-- | drivers/net/enic/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/enic/enic.h | 10 | ||||
-rw-r--r-- | drivers/net/enic/enic_main.c | 330 | ||||
-rw-r--r-- | drivers/net/enic/enic_res.c | 5 | ||||
-rw-r--r-- | drivers/net/enic/enic_res.h | 1 | ||||
-rw-r--r-- | drivers/net/enic/vnic_dev.c | 58 | ||||
-rw-r--r-- | drivers/net/enic/vnic_dev.h | 7 | ||||
-rw-r--r-- | drivers/net/enic/vnic_vic.c | 73 | ||||
-rw-r--r-- | drivers/net/enic/vnic_vic.h | 59 |
9 files changed, 521 insertions, 24 deletions
diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile index 391c3bce5b79..e7b6c31880ba 100644 --- a/drivers/net/enic/Makefile +++ b/drivers/net/enic/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-$(CONFIG_ENIC) := enic.o | 1 | obj-$(CONFIG_ENIC) := enic.o |
2 | 2 | ||
3 | enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ | 3 | enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ |
4 | enic_res.o vnic_dev.o vnic_rq.o | 4 | enic_res.o vnic_dev.o vnic_rq.o vnic_vic.o |
5 | 5 | ||
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 5fa56f1e5590..85f2a2e7030a 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | #define DRV_NAME "enic" | 35 | #define DRV_NAME "enic" |
36 | #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" | 36 | #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" |
37 | #define DRV_VERSION "1.3.1.1" | 37 | #define DRV_VERSION "1.3.1.1-pp" |
38 | #define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc" | 38 | #define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc" |
39 | #define PFX DRV_NAME ": " | 39 | #define PFX DRV_NAME ": " |
40 | 40 | ||
@@ -74,6 +74,13 @@ struct enic_msix_entry { | |||
74 | void *devid; | 74 | void *devid; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | struct enic_port_profile { | ||
78 | u8 request; | ||
79 | char name[PORT_PROFILE_MAX]; | ||
80 | u8 instance_uuid[PORT_UUID_MAX]; | ||
81 | u8 host_uuid[PORT_UUID_MAX]; | ||
82 | }; | ||
83 | |||
77 | /* Per-instance private data structure */ | 84 | /* Per-instance private data structure */ |
78 | struct enic { | 85 | struct enic { |
79 | struct net_device *netdev; | 86 | struct net_device *netdev; |
@@ -95,6 +102,7 @@ struct enic { | |||
95 | u32 port_mtu; | 102 | u32 port_mtu; |
96 | u32 rx_coalesce_usecs; | 103 | u32 rx_coalesce_usecs; |
97 | u32 tx_coalesce_usecs; | 104 | u32 tx_coalesce_usecs; |
105 | struct enic_port_profile pp; | ||
98 | 106 | ||
99 | /* work queue cache line section */ | 107 | /* work queue cache line section */ |
100 | ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX]; | 108 | ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX]; |
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 1232887c243d..e125113759a5 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 | ||
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index 02839bf0fe8b..9b18840cba96 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c | |||
@@ -103,11 +103,6 @@ int enic_get_vnic_config(struct enic *enic) | |||
103 | return 0; | 103 | return 0; |
104 | } | 104 | } |
105 | 105 | ||
106 | void enic_add_station_addr(struct enic *enic) | ||
107 | { | ||
108 | vnic_dev_add_addr(enic->vdev, enic->mac_addr); | ||
109 | } | ||
110 | |||
111 | void enic_add_multicast_addr(struct enic *enic, u8 *addr) | 106 | void enic_add_multicast_addr(struct enic *enic, u8 *addr) |
112 | { | 107 | { |
113 | vnic_dev_add_addr(enic->vdev, addr); | 108 | vnic_dev_add_addr(enic->vdev, addr); |
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h index abc19741ab02..494664f7fccc 100644 --- a/drivers/net/enic/enic_res.h +++ b/drivers/net/enic/enic_res.h | |||
@@ -131,7 +131,6 @@ static inline void enic_queue_rq_desc(struct vnic_rq *rq, | |||
131 | struct enic; | 131 | struct enic; |
132 | 132 | ||
133 | int enic_get_vnic_config(struct enic *); | 133 | int enic_get_vnic_config(struct enic *); |
134 | void enic_add_station_addr(struct enic *enic); | ||
135 | void enic_add_multicast_addr(struct enic *enic, u8 *addr); | 134 | void enic_add_multicast_addr(struct enic *enic, u8 *addr); |
136 | void enic_del_multicast_addr(struct enic *enic, u8 *addr); | 135 | void enic_del_multicast_addr(struct enic *enic, u8 *addr); |
137 | void enic_add_vlan(struct enic *enic, u16 vlanid); | 136 | void enic_add_vlan(struct enic *enic, u16 vlanid); |
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index d43a9d43bbff..2b3e16db5c82 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c | |||
@@ -530,7 +530,7 @@ void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, | |||
530 | printk(KERN_ERR "Can't set packet filter\n"); | 530 | printk(KERN_ERR "Can't set packet filter\n"); |
531 | } | 531 | } |
532 | 532 | ||
533 | void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) | 533 | int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) |
534 | { | 534 | { |
535 | u64 a0 = 0, a1 = 0; | 535 | u64 a0 = 0, a1 = 0; |
536 | int wait = 1000; | 536 | int wait = 1000; |
@@ -543,9 +543,11 @@ void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) | |||
543 | err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); | 543 | err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); |
544 | if (err) | 544 | if (err) |
545 | printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err); | 545 | printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err); |
546 | |||
547 | return err; | ||
546 | } | 548 | } |
547 | 549 | ||
548 | void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) | 550 | int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) |
549 | { | 551 | { |
550 | u64 a0 = 0, a1 = 0; | 552 | u64 a0 = 0, a1 = 0; |
551 | int wait = 1000; | 553 | int wait = 1000; |
@@ -558,6 +560,8 @@ void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) | |||
558 | err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); | 560 | err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); |
559 | if (err) | 561 | if (err) |
560 | printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err); | 562 | printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err); |
563 | |||
564 | return err; | ||
561 | } | 565 | } |
562 | 566 | ||
563 | int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr) | 567 | int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr) |
@@ -682,6 +686,56 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg) | |||
682 | return r; | 686 | return r; |
683 | } | 687 | } |
684 | 688 | ||
689 | int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err) | ||
690 | { | ||
691 | u64 a0 = 0, a1 = 0; | ||
692 | int wait = 1000; | ||
693 | int ret; | ||
694 | |||
695 | *done = 0; | ||
696 | |||
697 | ret = vnic_dev_cmd(vdev, CMD_INIT_STATUS, &a0, &a1, wait); | ||
698 | if (ret) | ||
699 | return ret; | ||
700 | |||
701 | *done = (a0 == 0); | ||
702 | |||
703 | *err = (a0 == 0) ? a1 : 0; | ||
704 | |||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len) | ||
709 | { | ||
710 | u64 a0, a1 = len; | ||
711 | int wait = 1000; | ||
712 | u64 prov_pa; | ||
713 | void *prov_buf; | ||
714 | int ret; | ||
715 | |||
716 | prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa); | ||
717 | if (!prov_buf) | ||
718 | return -ENOMEM; | ||
719 | |||
720 | memcpy(prov_buf, buf, len); | ||
721 | |||
722 | a0 = prov_pa; | ||
723 | |||
724 | ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO, &a0, &a1, wait); | ||
725 | |||
726 | pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa); | ||
727 | |||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | int vnic_dev_deinit(struct vnic_dev *vdev) | ||
732 | { | ||
733 | u64 a0 = 0, a1 = 0; | ||
734 | int wait = 1000; | ||
735 | |||
736 | return vnic_dev_cmd(vdev, CMD_DEINIT, &a0, &a1, wait); | ||
737 | } | ||
738 | |||
685 | int vnic_dev_link_status(struct vnic_dev *vdev) | 739 | int vnic_dev_link_status(struct vnic_dev *vdev) |
686 | { | 740 | { |
687 | if (vdev->linkstatus) | 741 | if (vdev->linkstatus) |
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index f5be640b0b5c..caccce36957b 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h | |||
@@ -103,8 +103,8 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats); | |||
103 | int vnic_dev_hang_notify(struct vnic_dev *vdev); | 103 | int vnic_dev_hang_notify(struct vnic_dev *vdev); |
104 | void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, | 104 | void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, |
105 | int broadcast, int promisc, int allmulti); | 105 | int broadcast, int promisc, int allmulti); |
106 | void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr); | 106 | int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr); |
107 | void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr); | 107 | int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr); |
108 | int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); | 108 | int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); |
109 | int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr); | 109 | int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr); |
110 | int vnic_dev_notify_setcmd(struct vnic_dev *vdev, | 110 | int vnic_dev_notify_setcmd(struct vnic_dev *vdev, |
@@ -124,6 +124,9 @@ int vnic_dev_disable(struct vnic_dev *vdev); | |||
124 | int vnic_dev_open(struct vnic_dev *vdev, int arg); | 124 | int vnic_dev_open(struct vnic_dev *vdev, int arg); |
125 | int vnic_dev_open_done(struct vnic_dev *vdev, int *done); | 125 | int vnic_dev_open_done(struct vnic_dev *vdev, int *done); |
126 | int vnic_dev_init(struct vnic_dev *vdev, int arg); | 126 | int vnic_dev_init(struct vnic_dev *vdev, int arg); |
127 | int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err); | ||
128 | int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len); | ||
129 | int vnic_dev_deinit(struct vnic_dev *vdev); | ||
127 | int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg); | 130 | int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg); |
128 | int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done); | 131 | int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done); |
129 | void vnic_dev_set_intr_mode(struct vnic_dev *vdev, | 132 | void vnic_dev_set_intr_mode(struct vnic_dev *vdev, |
diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c new file mode 100644 index 000000000000..d769772998c6 --- /dev/null +++ b/drivers/net/enic/vnic_vic.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Cisco Systems, Inc. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you may redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; version 2 of the License. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
11 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
12 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
15 | * SOFTWARE. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #include "vnic_vic.h" | ||
25 | |||
26 | struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type) | ||
27 | { | ||
28 | struct vic_provinfo *vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags); | ||
29 | |||
30 | if (!vp || !oui) | ||
31 | return NULL; | ||
32 | |||
33 | memcpy(vp->oui, oui, sizeof(vp->oui)); | ||
34 | vp->type = type; | ||
35 | vp->length = htonl(sizeof(vp->num_tlvs)); | ||
36 | |||
37 | return vp; | ||
38 | } | ||
39 | |||
40 | void vic_provinfo_free(struct vic_provinfo *vp) | ||
41 | { | ||
42 | kfree(vp); | ||
43 | } | ||
44 | |||
45 | int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, | ||
46 | void *value) | ||
47 | { | ||
48 | struct vic_provinfo_tlv *tlv; | ||
49 | |||
50 | if (!vp || !value) | ||
51 | return -EINVAL; | ||
52 | |||
53 | if (ntohl(vp->length) + sizeof(*tlv) + length > | ||
54 | VIC_PROVINFO_MAX_TLV_DATA) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | tlv = (struct vic_provinfo_tlv *)((u8 *)vp->tlv + | ||
58 | ntohl(vp->length) - sizeof(vp->num_tlvs)); | ||
59 | |||
60 | tlv->type = htons(type); | ||
61 | tlv->length = htons(length); | ||
62 | memcpy(tlv->value, value, length); | ||
63 | |||
64 | vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1); | ||
65 | vp->length = htonl(ntohl(vp->length) + sizeof(*tlv) + length); | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | size_t vic_provinfo_size(struct vic_provinfo *vp) | ||
71 | { | ||
72 | return vp ? ntohl(vp->length) + sizeof(*vp) - sizeof(vp->num_tlvs) : 0; | ||
73 | } | ||
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h new file mode 100644 index 000000000000..085c2a274cb1 --- /dev/null +++ b/drivers/net/enic/vnic_vic.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Cisco Systems, Inc. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you may redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; version 2 of the License. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
11 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
12 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
15 | * SOFTWARE. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef _VNIC_VIC_H_ | ||
20 | #define _VNIC_VIC_H_ | ||
21 | |||
22 | /* Note: All integer fields in NETWORK byte order */ | ||
23 | |||
24 | /* Note: String field lengths include null char */ | ||
25 | |||
26 | #define VIC_PROVINFO_CISCO_OUI { 0x00, 0x00, 0x0c } | ||
27 | #define VIC_PROVINFO_LINUX_TYPE 0x2 | ||
28 | |||
29 | enum vic_linux_prov_tlv_type { | ||
30 | VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR = 0, | ||
31 | VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR = 1, /* u8[6] */ | ||
32 | VIC_LINUX_PROV_TLV_CLIENT_NAME_STR = 2, | ||
33 | VIC_LINUX_PROV_TLV_HOST_UUID_STR = 8, | ||
34 | VIC_LINUX_PROV_TLV_CLIENT_UUID_STR = 9, | ||
35 | }; | ||
36 | |||
37 | struct vic_provinfo { | ||
38 | u8 oui[3]; /* OUI of data provider */ | ||
39 | u8 type; /* provider-specific type */ | ||
40 | u32 length; /* length of data below */ | ||
41 | u32 num_tlvs; /* number of tlvs */ | ||
42 | struct vic_provinfo_tlv { | ||
43 | u16 type; | ||
44 | u16 length; | ||
45 | u8 value[0]; | ||
46 | } tlv[0]; | ||
47 | } __attribute__ ((packed)); | ||
48 | |||
49 | #define VIC_PROVINFO_MAX_DATA 1385 | ||
50 | #define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \ | ||
51 | sizeof(struct vic_provinfo)) | ||
52 | |||
53 | struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type); | ||
54 | void vic_provinfo_free(struct vic_provinfo *vp); | ||
55 | int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length, | ||
56 | void *value); | ||
57 | size_t vic_provinfo_size(struct vic_provinfo *vp); | ||
58 | |||
59 | #endif /* _VNIC_VIC_H_ */ | ||