diff options
| author | Casey Leedom <leedom@chelsio.com> | 2010-11-24 07:23:57 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2010-11-28 14:40:58 -0500 |
| commit | 42eb59d3a80ff83b4cacb92dcc44b22da7d4969b (patch) | |
| tree | c053c48b34d4a9c17badc50967c9cd3b5eaee34b | |
| parent | bcc70bb3aeae7c3d035881d41055685f08a2b745 (diff) | |
cxgb4vf: fix setting unicast/multicast addresses ...
We were truncating the number of unicast and multicast MAC addresses
supported. Additionally, we were incorrectly computing the MAC Address
hash (a "1 << N" where we needed a "1ULL << N").
Signed-off-by: Casey Leedom <leedom@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/cxgb4vf/cxgb4vf_main.c | 73 | ||||
| -rw-r--r-- | drivers/net/cxgb4vf/t4vf_hw.c | 94 |
2 files changed, 104 insertions, 63 deletions
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index c3449bbc585a..d887a76cd39d 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c | |||
| @@ -816,40 +816,48 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev) | |||
| 816 | } | 816 | } |
| 817 | 817 | ||
| 818 | /* | 818 | /* |
| 819 | * Collect up to maxaddrs worth of a netdevice's unicast addresses into an | 819 | * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting |
| 820 | * array of addrss pointers and return the number collected. | 820 | * at a specified offset within the list, into an array of addrss pointers and |
| 821 | * return the number collected. | ||
| 821 | */ | 822 | */ |
| 822 | static inline int collect_netdev_uc_list_addrs(const struct net_device *dev, | 823 | static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev, |
| 823 | const u8 **addr, | 824 | const u8 **addr, |
| 824 | unsigned int maxaddrs) | 825 | unsigned int offset, |
| 826 | unsigned int maxaddrs) | ||
| 825 | { | 827 | { |
| 828 | unsigned int index = 0; | ||
| 826 | unsigned int naddr = 0; | 829 | unsigned int naddr = 0; |
| 827 | const struct netdev_hw_addr *ha; | 830 | const struct netdev_hw_addr *ha; |
| 828 | 831 | ||
| 829 | for_each_dev_addr(dev, ha) { | 832 | for_each_dev_addr(dev, ha) |
| 830 | addr[naddr++] = ha->addr; | 833 | if (index++ >= offset) { |
| 831 | if (naddr >= maxaddrs) | 834 | addr[naddr++] = ha->addr; |
| 832 | break; | 835 | if (naddr >= maxaddrs) |
| 833 | } | 836 | break; |
| 837 | } | ||
| 834 | return naddr; | 838 | return naddr; |
| 835 | } | 839 | } |
| 836 | 840 | ||
| 837 | /* | 841 | /* |
| 838 | * Collect up to maxaddrs worth of a netdevice's multicast addresses into an | 842 | * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting |
| 839 | * array of addrss pointers and return the number collected. | 843 | * at a specified offset within the list, into an array of addrss pointers and |
| 844 | * return the number collected. | ||
| 840 | */ | 845 | */ |
| 841 | static inline int collect_netdev_mc_list_addrs(const struct net_device *dev, | 846 | static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev, |
| 842 | const u8 **addr, | 847 | const u8 **addr, |
| 843 | unsigned int maxaddrs) | 848 | unsigned int offset, |
| 849 | unsigned int maxaddrs) | ||
| 844 | { | 850 | { |
| 851 | unsigned int index = 0; | ||
| 845 | unsigned int naddr = 0; | 852 | unsigned int naddr = 0; |
| 846 | const struct netdev_hw_addr *ha; | 853 | const struct netdev_hw_addr *ha; |
| 847 | 854 | ||
| 848 | netdev_for_each_mc_addr(ha, dev) { | 855 | netdev_for_each_mc_addr(ha, dev) |
| 849 | addr[naddr++] = ha->addr; | 856 | if (index++ >= offset) { |
| 850 | if (naddr >= maxaddrs) | 857 | addr[naddr++] = ha->addr; |
| 851 | break; | 858 | if (naddr >= maxaddrs) |
| 852 | } | 859 | break; |
| 860 | } | ||
| 853 | return naddr; | 861 | return naddr; |
| 854 | } | 862 | } |
| 855 | 863 | ||
| @@ -862,16 +870,20 @@ static int set_addr_filters(const struct net_device *dev, bool sleep) | |||
| 862 | u64 mhash = 0; | 870 | u64 mhash = 0; |
| 863 | u64 uhash = 0; | 871 | u64 uhash = 0; |
| 864 | bool free = true; | 872 | bool free = true; |
| 865 | u16 filt_idx[7]; | 873 | unsigned int offset, naddr; |
| 866 | const u8 *addr[7]; | 874 | const u8 *addr[7]; |
| 867 | int ret, naddr = 0; | 875 | int ret; |
| 868 | const struct port_info *pi = netdev_priv(dev); | 876 | const struct port_info *pi = netdev_priv(dev); |
| 869 | 877 | ||
| 870 | /* first do the secondary unicast addresses */ | 878 | /* first do the secondary unicast addresses */ |
| 871 | naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr)); | 879 | for (offset = 0; ; offset += naddr) { |
| 872 | if (naddr > 0) { | 880 | naddr = collect_netdev_uc_list_addrs(dev, addr, offset, |
| 881 | ARRAY_SIZE(addr)); | ||
| 882 | if (naddr == 0) | ||
| 883 | break; | ||
| 884 | |||
| 873 | ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, | 885 | ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, |
| 874 | naddr, addr, filt_idx, &uhash, sleep); | 886 | naddr, addr, NULL, &uhash, sleep); |
| 875 | if (ret < 0) | 887 | if (ret < 0) |
| 876 | return ret; | 888 | return ret; |
| 877 | 889 | ||
| @@ -879,12 +891,17 @@ static int set_addr_filters(const struct net_device *dev, bool sleep) | |||
| 879 | } | 891 | } |
| 880 | 892 | ||
| 881 | /* next set up the multicast addresses */ | 893 | /* next set up the multicast addresses */ |
| 882 | naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr)); | 894 | for (offset = 0; ; offset += naddr) { |
| 883 | if (naddr > 0) { | 895 | naddr = collect_netdev_mc_list_addrs(dev, addr, offset, |
| 896 | ARRAY_SIZE(addr)); | ||
| 897 | if (naddr == 0) | ||
| 898 | break; | ||
| 899 | |||
| 884 | ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, | 900 | ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, |
| 885 | naddr, addr, filt_idx, &mhash, sleep); | 901 | naddr, addr, NULL, &mhash, sleep); |
| 886 | if (ret < 0) | 902 | if (ret < 0) |
| 887 | return ret; | 903 | return ret; |
| 904 | free = false; | ||
| 888 | } | 905 | } |
| 889 | 906 | ||
| 890 | return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0, | 907 | return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0, |
diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c index e306c20dfaee..19520afe1a12 100644 --- a/drivers/net/cxgb4vf/t4vf_hw.c +++ b/drivers/net/cxgb4vf/t4vf_hw.c | |||
| @@ -1014,48 +1014,72 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free, | |||
| 1014 | unsigned int naddr, const u8 **addr, u16 *idx, | 1014 | unsigned int naddr, const u8 **addr, u16 *idx, |
| 1015 | u64 *hash, bool sleep_ok) | 1015 | u64 *hash, bool sleep_ok) |
| 1016 | { | 1016 | { |
| 1017 | int i, ret; | 1017 | int offset, ret = 0; |
| 1018 | unsigned nfilters = 0; | ||
| 1019 | unsigned int rem = naddr; | ||
| 1018 | struct fw_vi_mac_cmd cmd, rpl; | 1020 | struct fw_vi_mac_cmd cmd, rpl; |
| 1019 | struct fw_vi_mac_exact *p; | ||
| 1020 | size_t len16; | ||
| 1021 | 1021 | ||
| 1022 | if (naddr > ARRAY_SIZE(cmd.u.exact)) | 1022 | if (naddr > FW_CLS_TCAM_NUM_ENTRIES) |
| 1023 | return -EINVAL; | 1023 | return -EINVAL; |
| 1024 | len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, | ||
| 1025 | u.exact[naddr]), 16); | ||
| 1026 | 1024 | ||
| 1027 | memset(&cmd, 0, sizeof(cmd)); | 1025 | for (offset = 0; offset < naddr; /**/) { |
| 1028 | cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | | 1026 | unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact) |
| 1029 | FW_CMD_REQUEST | | 1027 | ? rem |
| 1030 | FW_CMD_WRITE | | 1028 | : ARRAY_SIZE(cmd.u.exact)); |
| 1031 | (free ? FW_CMD_EXEC : 0) | | 1029 | size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd, |
| 1032 | FW_VI_MAC_CMD_VIID(viid)); | 1030 | u.exact[fw_naddr]), 16); |
| 1033 | cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) | | 1031 | struct fw_vi_mac_exact *p; |
| 1034 | FW_CMD_LEN16(len16)); | 1032 | int i; |
| 1035 | 1033 | ||
| 1036 | for (i = 0, p = cmd.u.exact; i < naddr; i++, p++) { | 1034 | memset(&cmd, 0, sizeof(cmd)); |
| 1037 | p->valid_to_idx = | 1035 | cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | |
| 1038 | cpu_to_be16(FW_VI_MAC_CMD_VALID | | 1036 | FW_CMD_REQUEST | |
| 1039 | FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); | 1037 | FW_CMD_WRITE | |
| 1040 | memcpy(p->macaddr, addr[i], sizeof(p->macaddr)); | 1038 | (free ? FW_CMD_EXEC : 0) | |
| 1041 | } | 1039 | FW_VI_MAC_CMD_VIID(viid)); |
| 1040 | cmd.freemacs_to_len16 = | ||
| 1041 | cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) | | ||
| 1042 | FW_CMD_LEN16(len16)); | ||
| 1043 | |||
| 1044 | for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) { | ||
| 1045 | p->valid_to_idx = cpu_to_be16( | ||
| 1046 | FW_VI_MAC_CMD_VALID | | ||
| 1047 | FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); | ||
| 1048 | memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr)); | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | |||
| 1052 | ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, | ||
| 1053 | sleep_ok); | ||
| 1054 | if (ret && ret != -ENOMEM) | ||
| 1055 | break; | ||
| 1042 | 1056 | ||
| 1043 | ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok); | 1057 | for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) { |
| 1044 | if (ret) | 1058 | u16 index = FW_VI_MAC_CMD_IDX_GET( |
| 1045 | return ret; | 1059 | be16_to_cpu(p->valid_to_idx)); |
| 1046 | 1060 | ||
| 1047 | for (i = 0, p = rpl.u.exact; i < naddr; i++, p++) { | 1061 | if (idx) |
| 1048 | u16 index = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx)); | 1062 | idx[offset+i] = |
| 1049 | 1063 | (index >= FW_CLS_TCAM_NUM_ENTRIES | |
| 1050 | if (idx) | 1064 | ? 0xffff |
| 1051 | idx[i] = (index >= FW_CLS_TCAM_NUM_ENTRIES | 1065 | : index); |
| 1052 | ? 0xffff | 1066 | if (index < FW_CLS_TCAM_NUM_ENTRIES) |
| 1053 | : index); | 1067 | nfilters++; |
| 1054 | if (index < FW_CLS_TCAM_NUM_ENTRIES) | 1068 | else if (hash) |
| 1055 | ret++; | 1069 | *hash |= (1ULL << hash_mac_addr(addr[offset+i])); |
| 1056 | else if (hash) | 1070 | } |
| 1057 | *hash |= (1 << hash_mac_addr(addr[i])); | 1071 | |
| 1072 | free = false; | ||
| 1073 | offset += fw_naddr; | ||
| 1074 | rem -= fw_naddr; | ||
| 1058 | } | 1075 | } |
| 1076 | |||
| 1077 | /* | ||
| 1078 | * If there were no errors or we merely ran out of room in our MAC | ||
| 1079 | * address arena, return the number of filters actually written. | ||
| 1080 | */ | ||
| 1081 | if (ret == 0 || ret == -ENOMEM) | ||
| 1082 | ret = nfilters; | ||
| 1059 | return ret; | 1083 | return ret; |
| 1060 | } | 1084 | } |
| 1061 | 1085 | ||
