aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVignesh Raghavendra2020-07-30 12:00:39 -0500
committerVignesh Raghavendra2020-08-03 02:15:10 -0500
commit705dff231a44935978768e5f1919fcd2044977d2 (patch)
tree14b4988d8eee1c18560b10fdf159a29391d19f88
parent8144016363757f82e6c3e8991e771a0b72af7d6b (diff)
downloadkernel-705dff231a44935978768e5f1919fcd2044977d2.tar.gz
kernel-705dff231a44935978768e5f1919fcd2044977d2.tar.xz
kernel-705dff231a44935978768e5f1919fcd2044977d2.zip
net: ti: prueth_switch: Offload multicast filtering for host port
Prueth switch firmware supports offloading of filtering of multicast traffic just for CPU port. The programming model is similar to Dual EMAC mode. Therefore reuse the code to implement offload support in switch mode. Note that in switch mode multicast filtering is always enabled. Currently, therefore no way to disable filter completely because setting ALLMULTI flag on bridge device is no-op. (See net/bridge/br_device.c bridge device's ndo_set_rx_mode is set to br_dev_set_multicast_list() which is an empty function). Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
-rw-r--r--drivers/net/ethernet/ti/prueth.h3
-rw-r--r--drivers/net/ethernet/ti/prueth_core.c34
-rw-r--r--drivers/net/ethernet/ti/prueth_switch.c74
3 files changed, 99 insertions, 12 deletions
diff --git a/drivers/net/ethernet/ti/prueth.h b/drivers/net/ethernet/ti/prueth.h
index ab6fcfe769cb..6720b25a4751 100644
--- a/drivers/net/ethernet/ti/prueth.h
+++ b/drivers/net/ethernet/ti/prueth.h
@@ -505,4 +505,7 @@ static inline void emac_finish_napi(struct prueth_emac *emac,
505 enable_irq(irq); 505 enable_irq(irq);
506} 506}
507 507
508void emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash);
509void emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash);
510u8 emac_get_mc_hash(u8 *mac, u8 *mask);
508#endif /* __NET_TI_PRUETH_H */ 511#endif /* __NET_TI_PRUETH_H */
diff --git a/drivers/net/ethernet/ti/prueth_core.c b/drivers/net/ethernet/ti/prueth_core.c
index 0d06ac433ad3..644014f8349d 100644
--- a/drivers/net/ethernet/ti/prueth_core.c
+++ b/drivers/net/ethernet/ti/prueth_core.c
@@ -2072,7 +2072,7 @@ static void emac_mc_filter_hashmask(struct prueth_emac *emac,
2072 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES); 2072 ICSS_EMAC_FW_MULTICAST_FILTER_MASK_SIZE_BYTES);
2073} 2073}
2074 2074
2075static void emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash) 2075static void emac_mc_filter_bin_update(struct prueth_emac *emac, u8 hash, u8 val)
2076{ 2076{
2077 struct prueth *prueth = emac->prueth; 2077 struct prueth *prueth = emac->prueth;
2078 u32 mc_filter_tbl_base = prueth->fw_offsets->mc_filter_tbl; 2078 u32 mc_filter_tbl_base = prueth->fw_offsets->mc_filter_tbl;
@@ -2083,11 +2083,20 @@ static void emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash)
2083 ram = prueth->mem[PRUETH_MEM_DRAM1].va; 2083 ram = prueth->mem[PRUETH_MEM_DRAM1].va;
2084 2084
2085 mc_filter_tbl = ram + mc_filter_tbl_base; 2085 mc_filter_tbl = ram + mc_filter_tbl_base;
2086 writeb(ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED, 2086 writeb(val, mc_filter_tbl + hash);
2087 mc_filter_tbl + hash);
2088} 2087}
2089 2088
2090static u8 emac_get_mc_hash(u8 *mac, u8 *mask) 2089void emac_mc_filter_bin_allow(struct prueth_emac *emac, u8 hash)
2090{
2091 emac_mc_filter_bin_update(emac, hash, ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_ALLOWED);
2092}
2093
2094void emac_mc_filter_bin_disallow(struct prueth_emac *emac, u8 hash)
2095{
2096 emac_mc_filter_bin_update(emac, hash, ICSS_EMAC_FW_MULTICAST_FILTER_HOST_RCV_NOT_ALLOWED);
2097}
2098
2099u8 emac_get_mc_hash(u8 *mac, u8 *mask)
2091{ 2100{
2092 int j; 2101 int j;
2093 u8 hash; 2102 u8 hash;
@@ -2117,13 +2126,6 @@ static void emac_ndo_set_rx_mode(struct net_device *ndev)
2117 u32 mask; 2126 u32 mask;
2118 u8 hash; 2127 u8 hash;
2119 2128
2120 if (PRUETH_IS_SWITCH(prueth)) {
2121 netdev_dbg(ndev,
2122 "%s: promisc/mc filtering not supported for switch\n",
2123 __func__);
2124 return;
2125 }
2126
2127 if (promisc && PRUETH_IS_LRE(prueth)) { 2129 if (promisc && PRUETH_IS_LRE(prueth)) {
2128 netdev_dbg(ndev, 2130 netdev_dbg(ndev,
2129 "%s: promisc mode not supported for LRE\n", 2131 "%s: promisc mode not supported for LRE\n",
@@ -2166,7 +2168,7 @@ static void emac_ndo_set_rx_mode(struct net_device *ndev)
2166 goto unlock; 2168 goto unlock;
2167 } 2169 }
2168 2170
2169 if (ndev->flags & IFF_ALLMULTI) 2171 if (ndev->flags & IFF_ALLMULTI && !PRUETH_IS_SWITCH(prueth))
2170 goto unlock; 2172 goto unlock;
2171 2173
2172 emac_mc_filter_ctrl(emac, true); /* all multicast blocked */ 2174 emac_mc_filter_ctrl(emac, true); /* all multicast blocked */
@@ -2178,6 +2180,14 @@ static void emac_ndo_set_rx_mode(struct net_device *ndev)
2178 hash = emac_get_mc_hash(ha->addr, emac->mc_filter_mask); 2180 hash = emac_get_mc_hash(ha->addr, emac->mc_filter_mask);
2179 emac_mc_filter_bin_allow(emac, hash); 2181 emac_mc_filter_bin_allow(emac, hash);
2180 } 2182 }
2183
2184 /* Add bridge device's MC addresses as well */
2185 if (prueth->hw_bridge_dev) {
2186 netdev_for_each_mc_addr(ha, prueth->hw_bridge_dev) {
2187 hash = emac_get_mc_hash(ha->addr, emac->mc_filter_mask);
2188 emac_mc_filter_bin_allow(emac, hash);
2189 }
2190 }
2181unlock: 2191unlock:
2182 spin_unlock_irqrestore(&emac->addr_lock, flags); 2192 spin_unlock_irqrestore(&emac->addr_lock, flags);
2183} 2193}
diff --git a/drivers/net/ethernet/ti/prueth_switch.c b/drivers/net/ethernet/ti/prueth_switch.c
index f5891306baad..edb9473928b7 100644
--- a/drivers/net/ethernet/ti/prueth_switch.c
+++ b/drivers/net/ethernet/ti/prueth_switch.c
@@ -1075,6 +1075,68 @@ static int prueth_switchdev_attr_set(struct net_device *ndev,
1075 return err; 1075 return err;
1076} 1076}
1077 1077
1078static int prueth_switchdev_obj_add(struct net_device *ndev,
1079 const struct switchdev_obj *obj,
1080 struct switchdev_trans *trans,
1081 struct netlink_ext_ack *extack)
1082{
1083 struct prueth_emac *emac = netdev_priv(ndev);
1084 struct prueth *prueth = emac->prueth;
1085 struct switchdev_obj_port_mdb *mdb;
1086 int ret = 0;
1087 u8 hash;
1088
1089 if (switchdev_trans_ph_prepare(trans))
1090 return 0;
1091
1092 switch (obj->id) {
1093 case SWITCHDEV_OBJ_ID_HOST_MDB:
1094 mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
1095 dev_dbg(prueth->dev, "MDB add: %s: vid %u:%pM port: %x\n",
1096 ndev->name, mdb->vid, mdb->addr, emac->port_id);
1097 hash = emac_get_mc_hash(mdb->addr, emac->mc_filter_mask);
1098 emac_mc_filter_bin_allow(emac, hash);
1099 break;
1100 default:
1101 ret = -EOPNOTSUPP;
1102 break;
1103 }
1104
1105 return ret;
1106}
1107
1108static int prueth_switchdev_obj_del(struct net_device *ndev,
1109 const struct switchdev_obj *obj)
1110{
1111 struct prueth_emac *emac = netdev_priv(ndev);
1112 struct prueth *prueth = emac->prueth;
1113 struct switchdev_obj_port_mdb *mdb;
1114 struct netdev_hw_addr *ha;
1115 u8 hash, tmp_hash;
1116 int ret = 0;
1117
1118 switch (obj->id) {
1119 case SWITCHDEV_OBJ_ID_HOST_MDB:
1120 mdb = SWITCHDEV_OBJ_PORT_MDB(obj);
1121 dev_dbg(prueth->dev, "MDB del: %s: vid %u:%pM port: %x\n",
1122 ndev->name, mdb->vid, mdb->addr, emac->port_id);
1123 hash = emac_get_mc_hash(mdb->addr, emac->mc_filter_mask);
1124 netdev_for_each_mc_addr(ha, prueth->hw_bridge_dev) {
1125 tmp_hash = emac_get_mc_hash(ha->addr, emac->mc_filter_mask);
1126 /* Another MC address is in the bin. Don't disable. */
1127 if (tmp_hash == hash)
1128 return 0;
1129 }
1130 emac_mc_filter_bin_disallow(emac, hash);
1131 break;
1132 default:
1133 ret = -EOPNOTSUPP;
1134 break;
1135 }
1136
1137 return ret;
1138}
1139
1078/* switchdev notifiers */ 1140/* switchdev notifiers */
1079static int prueth_sw_switchdev_blocking_event(struct notifier_block *unused, 1141static int prueth_sw_switchdev_blocking_event(struct notifier_block *unused,
1080 unsigned long event, void *ptr) 1142 unsigned long event, void *ptr)
@@ -1093,6 +1155,18 @@ static int prueth_sw_switchdev_blocking_event(struct notifier_block *unused,
1093 prueth_sw_port_dev_check, 1155 prueth_sw_port_dev_check,
1094 prueth_switchdev_attr_set); 1156 prueth_switchdev_attr_set);
1095 return notifier_from_errno(err); 1157 return notifier_from_errno(err);
1158
1159 case SWITCHDEV_PORT_OBJ_ADD:
1160 err = switchdev_handle_port_obj_add(ndev, ptr,
1161 prueth_sw_port_dev_check,
1162 prueth_switchdev_obj_add);
1163 return notifier_from_errno(err);
1164
1165 case SWITCHDEV_PORT_OBJ_DEL:
1166 err = switchdev_handle_port_obj_del(ndev, ptr,
1167 prueth_sw_port_dev_check,
1168 prueth_switchdev_obj_del);
1169 return notifier_from_errno(err);
1096 default: 1170 default:
1097 break; 1171 break;
1098 } 1172 }