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_ */ | ||
