aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cxgb4vf
diff options
context:
space:
mode:
authorCasey Leedom <leedom@chelsio.com>2010-11-24 07:23:57 -0500
committerDavid S. Miller <davem@davemloft.net>2010-11-28 14:40:58 -0500
commit42eb59d3a80ff83b4cacb92dcc44b22da7d4969b (patch)
treec053c48b34d4a9c17badc50967c9cd3b5eaee34b /drivers/net/cxgb4vf
parentbcc70bb3aeae7c3d035881d41055685f08a2b745 (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>
Diffstat (limited to 'drivers/net/cxgb4vf')
-rw-r--r--drivers/net/cxgb4vf/cxgb4vf_main.c73
-rw-r--r--drivers/net/cxgb4vf/t4vf_hw.c94
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 */
822static inline int collect_netdev_uc_list_addrs(const struct net_device *dev, 823static 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 */
841static inline int collect_netdev_mc_list_addrs(const struct net_device *dev, 846static 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