Skip to content

Commit a5f9fc2

Browse files
cperera-audcarlescufi
authored andcommitted
drivers: ethernet: stm32: Updated original multicast hash filter change
- Applied changes on the most recent version of the driver - Using CONFIG_ETH_MULTICAST_FILTER to enable/disable the hash filter - Using read-modify-write the hash table for a single address when joining - When leaving rebuild the entire hash table and ensure that multicast addresses used for the hash calcuation doesn't have the joined flag set I have tested these conditions: - IGMP enabled and disabled on my ethernet network - Observed the network utilisation on a STM32H7 device running these changes with the hash filter enabled and disabled while the device is on a ethernet network with high rate multicast traffic - When the application closes a socket for a multicast receive, ensure it doesn't affect the receiption of existing sockets as well as IGMP Fixes #53773 Signed-off-by: Chamira Perera <[email protected]>
1 parent c76aaf3 commit a5f9fc2

File tree

2 files changed

+169
-39
lines changed

2 files changed

+169
-39
lines changed

drivers/ethernet/Kconfig.stm32_hal

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,15 @@ config ETH_STM32_HAL_PTP_CLOCK_INIT_PRIO
188188

189189
endif # SOC_SERIES_STM32F7X || SOC_SERIES_STM32H7X
190190

191+
config ETH_STM32_MULTICAST_FILTER
192+
bool "Multicast hash filter support"
193+
help
194+
Enable support for multicast hash filtering in the MAC.
195+
Once enabled the ethernet MAC performs imperfect filtering
196+
based on a computed hash of the destination MAC address of
197+
the multicast address. Only multicast with the computed
198+
hash set in the multicast table will be received and all
199+
other multicast is dropped by the MAC. If disabled then all
200+
multicast is received by the MAC.
201+
191202
endif # ETH_STM32_HAL

drivers/ethernet/eth_stm32_hal.c

Lines changed: 158 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
1717
#include <zephyr/device.h>
1818
#include <zephyr/sys/__assert.h>
1919
#include <zephyr/sys/util.h>
20-
#include <zephyr/crc.h>
20+
#include <zephyr/sys/crc.h>
2121
#include <errno.h>
2222
#include <stdbool.h>
2323
#include <zephyr/net/net_pkt.h>
@@ -97,8 +97,22 @@ static ETH_DMADescTypeDef dma_tx_desc_tab[ETH_TXBUFNB] __eth_stm32_desc;
9797
static uint8_t dma_rx_buffer[ETH_RXBUFNB][ETH_STM32_RX_BUF_SIZE] __eth_stm32_buf;
9898
static uint8_t dma_tx_buffer[ETH_TXBUFNB][ETH_STM32_TX_BUF_SIZE] __eth_stm32_buf;
9999

100+
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
101+
100102
static struct net_if_mcast_monitor mcast_monitor;
101103

104+
static K_MUTEX_DEFINE(multicast_addr_lock);
105+
106+
#if defined(CONFIG_NET_NATIVE_IPV6)
107+
static struct in6_addr multicast_ipv6_joined_addrs[NET_IF_MAX_IPV6_MADDR] = {0};
108+
#endif /* CONFIG_NET_NATIVE_IPV6 */
109+
110+
#if defined(CONFIG_NET_NATIVE_IPV4)
111+
static struct in_addr multicast_ipv4_joined_addrs[NET_IF_MAX_IPV4_MADDR] = {0};
112+
#endif /* CONFIG_NET_NATIVE_IPV4 */
113+
114+
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
115+
102116
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
103117

104118
BUILD_ASSERT(ETH_STM32_RX_BUF_SIZE % 4 == 0, "Rx buffer size must be a multiple of 4");
@@ -217,16 +231,21 @@ static HAL_StatusTypeDef read_eth_phy_register(ETH_HandleTypeDef *heth,
217231
#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_ETH_STM32_HAL_API_V2 */
218232
}
219233

220-
static inline void disable_mcast_filter(ETH_HandleTypeDef *heth)
234+
static inline void setup_mac_filter(ETH_HandleTypeDef *heth)
221235
{
222236
__ASSERT_NO_MSG(heth != NULL);
223237

224238
#if defined(CONFIG_SOC_SERIES_STM32H7X)
225239
ETH_MACFilterConfigTypeDef MACFilterConf;
226240

227241
HAL_ETH_GetMACFilterConfig(heth, &MACFilterConf);
242+
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
228243
MACFilterConf.HashMulticast = ENABLE;
229244
MACFilterConf.PassAllMulticast = DISABLE;
245+
#else
246+
MACFilterConf.HashMulticast = DISABLE;
247+
MACFilterConf.PassAllMulticast = ENABLE;
248+
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
230249
MACFilterConf.HachOrPerfectFilter = DISABLE;
231250

232251
HAL_ETH_SetMACFilterConfig(heth, &MACFilterConf);
@@ -237,10 +256,15 @@ static inline void disable_mcast_filter(ETH_HandleTypeDef *heth)
237256

238257
/* disable multicast perfect filtering */
239258
tmp &= ~(ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE |
259+
#if !defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
260+
ETH_MULTICASTFRAMESFILTER_HASHTABLE |
261+
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
240262
ETH_MULTICASTFRAMESFILTER_PERFECT);
241263

264+
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
242265
/* enable multicast hash receive filter */
243266
tmp |= ETH_MULTICASTFRAMESFILTER_HASHTABLE;
267+
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
244268

245269
heth->Instance->MACFFR = tmp;
246270

@@ -1189,6 +1213,64 @@ static int eth_initialize(const struct device *dev)
11891213
return 0;
11901214
}
11911215

1216+
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
1217+
1218+
#if defined(CONFIG_NET_NATIVE_IPV6)
1219+
static void add_ipv6_multicast_addr(const struct in6_addr *addr)
1220+
{
1221+
uint32_t i;
1222+
1223+
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
1224+
if (net_ipv6_is_addr_unspecified(&multicast_ipv6_joined_addrs[i])) {
1225+
net_ipv6_addr_copy_raw((uint8_t *)&multicast_ipv6_joined_addrs[i],
1226+
(uint8_t *)addr);
1227+
break;
1228+
}
1229+
}
1230+
}
1231+
1232+
static void remove_ipv6_multicast_addr(const struct in6_addr *addr)
1233+
{
1234+
uint32_t i;
1235+
1236+
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
1237+
if (net_ipv6_addr_cmp_raw(&multicast_ipv6_joined_addrs[i], addr)) {
1238+
net_ipv6_addr_copy_raw((uint8_t *)&multicast_ipv6_joined_addrs[i],
1239+
(uint8_t *)net_ipv6_unspecified_address);
1240+
break;
1241+
}
1242+
}
1243+
}
1244+
#endif /* CONFIG_NET_NATIVE_IPV6 */
1245+
1246+
#if defined(CONFIG_NET_NATIVE_IPV4)
1247+
static void add_ipv4_multicast_addr(const struct in_addr *addr)
1248+
{
1249+
uint32_t i;
1250+
1251+
for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) {
1252+
if (net_ipv4_is_addr_unspecified(&multicast_ipv4_joined_addrs[i])) {
1253+
net_ipv4_addr_copy_raw((uint8_t *)&multicast_ipv4_joined_addrs[i],
1254+
(uint8_t *)addr);
1255+
break;
1256+
}
1257+
}
1258+
}
1259+
1260+
static void remove_ipv4_multicast_addr(const struct in_addr *addr)
1261+
{
1262+
uint32_t i;
1263+
1264+
for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) {
1265+
if (net_ipv4_addr_cmp_raw((uint8_t *)&multicast_ipv4_joined_addrs[i],
1266+
(uint8_t *)addr)) {
1267+
multicast_ipv4_joined_addrs[i].s_addr = 0;
1268+
break;
1269+
}
1270+
}
1271+
}
1272+
#endif /* CONFIG_NET_NATIVE_IPV4 */
1273+
11921274
static uint32_t reverse(uint32_t val)
11931275
{
11941276
uint32_t res = 0;
@@ -1203,89 +1285,124 @@ static uint32_t reverse(uint32_t val)
12031285
return res;
12041286
}
12051287

1206-
static void net_if_mcast_cb(struct net_if *iface,
1288+
static void net_if_stm32_mcast_cb(struct net_if *iface,
12071289
const struct net_addr *addr,
12081290
bool is_joined)
12091291
{
12101292
ARG_UNUSED(addr);
1211-
ARG_UNUSED(is_joined);
12121293

12131294
const struct device *dev;
12141295
struct eth_stm32_hal_dev_data *dev_data;
12151296
ETH_HandleTypeDef *heth;
1216-
#if defined(CONFIG_NET_NATIVE_IPV6)
1217-
struct net_if_ipv6 *ipv6;
1218-
#endif
1219-
#if defined(CONFIG_NET_NATIVE_IPV4)
1220-
struct net_if_ipv4 *ipv4;
1221-
#endif
12221297
struct net_eth_addr mac_addr;
12231298
uint32_t crc;
12241299
uint32_t hash_table[2];
12251300
uint32_t hash_index;
12261301
int i;
12271302

1228-
__ASSERT_NO_MSG(iface != NULL);
1229-
12301303
dev = net_if_get_device(iface);
1231-
__ASSERT_NO_MSG(dev != NULL);
12321304

1233-
dev_data = DEV_DATA(dev);
1234-
__ASSERT_NO_MSG(dev_data != NULL);
1305+
dev_data = (struct eth_stm32_hal_dev_data *)dev->data;
12351306

12361307
heth = &dev_data->heth;
1237-
__ASSERT_NO_MSG(heth != NULL);
12381308

12391309
hash_table[0] = 0;
12401310
hash_table[1] = 0;
12411311

1242-
#if defined(CONFIG_NET_NATIVE_IPV6)
1243-
if (net_if_config_ipv6_get(iface, &ipv6) < 0) {
1244-
return;
1312+
if (is_joined) {
1313+
/* Save a copy of the hash table which we update with
1314+
* the hash for a single multicast address for join
1315+
*/
1316+
#if defined(CONFIG_SOC_SERIES_STM32H7X)
1317+
hash_table[0] = heth->Instance->MACHT0R;
1318+
hash_table[1] = heth->Instance->MACHT1R;
1319+
#else
1320+
hash_table[0] = heth->Instance->MACHTLR;
1321+
hash_table[1] = heth->Instance->MACHTHR;
1322+
#endif /* CONFIG_SOC_SERIES_STM32H7X */
12451323
}
12461324

1247-
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
1248-
if (!ipv6->mcast[i].is_used) {
1249-
continue;
1250-
}
1325+
k_mutex_lock(&multicast_addr_lock, K_FOREVER);
12511326

1252-
net_eth_ipv6_mcast_to_mac_addr(&ipv6->mcast[i].address.in_addr,
1253-
&mac_addr);
1327+
#if defined(CONFIG_NET_NATIVE_IPV6)
1328+
if (is_joined) {
1329+
/* When joining only update the hash filter with the joining
1330+
* multicast address.
1331+
*/
1332+
add_ipv6_multicast_addr(&addr->in6_addr);
1333+
1334+
net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr);
12541335
crc = reverse(crc32_ieee(mac_addr.addr,
1255-
sizeof(struct net_eth_addr)));
1336+
sizeof(struct net_eth_addr)));
12561337
hash_index = (crc >> 26) & 0x3f;
12571338
hash_table[hash_index / 32] |= (1 << (hash_index % 32));
1339+
} else {
1340+
/* When leaving its better to compute the full hash table
1341+
* for all the multicast addresses that we're aware of.
1342+
*/
1343+
remove_ipv6_multicast_addr(&addr->in6_addr);
1344+
1345+
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
1346+
if (net_ipv6_is_addr_unspecified(&multicast_ipv6_joined_addrs[i])) {
1347+
continue;
1348+
}
1349+
1350+
net_eth_ipv6_mcast_to_mac_addr(&multicast_ipv6_joined_addrs[i],
1351+
&mac_addr);
1352+
crc = reverse(crc32_ieee(mac_addr.addr,
1353+
sizeof(struct net_eth_addr)));
1354+
hash_index = (crc >> 26) & 0x3f;
1355+
hash_table[hash_index / 32] |= (1 << (hash_index % 32));
1356+
}
12581357
}
12591358
#endif /* CONFIG_NET_IPV6 */
12601359

12611360
#if defined(CONFIG_NET_NATIVE_IPV4)
1262-
if (net_if_config_ipv4_get(iface, &ipv4) < 0) {
1263-
return;
1264-
}
1265-
1266-
for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) {
1267-
if (!ipv4->mcast[i].is_used) {
1268-
continue;
1269-
}
1361+
if (is_joined) {
1362+
/* When joining only update the hash filter with the joining
1363+
* multicast address.
1364+
*/
1365+
add_ipv4_multicast_addr(&addr->in_addr);
12701366

1271-
net_eth_ipv4_mcast_to_mac_addr(&ipv4->mcast[i].address.in_addr,
1272-
&mac_addr);
1367+
net_eth_ipv4_mcast_to_mac_addr(&addr->in_addr, &mac_addr);
12731368
crc = reverse(crc32_ieee(mac_addr.addr,
1274-
sizeof(struct net_eth_addr)));
1369+
sizeof(struct net_eth_addr)));
12751370
hash_index = (crc >> 26) & 0x3f;
12761371
hash_table[hash_index / 32] |= (1 << (hash_index % 32));
1372+
} else {
1373+
/* When leaving its better to compute the full hash table
1374+
* for all the multicast addresses that we're aware of.
1375+
*/
1376+
remove_ipv4_multicast_addr(&addr->in_addr);
1377+
1378+
for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) {
1379+
if (net_ipv4_is_addr_unspecified(&multicast_ipv4_joined_addrs[i])) {
1380+
continue;
1381+
}
1382+
1383+
net_eth_ipv4_mcast_to_mac_addr(&multicast_ipv4_joined_addrs[i],
1384+
&mac_addr);
1385+
crc = reverse(crc32_ieee(mac_addr.addr,
1386+
sizeof(struct net_eth_addr)));
1387+
hash_index = (crc >> 26) & 0x3f;
1388+
hash_table[hash_index / 32] |= (1 << (hash_index % 32));
1389+
}
12771390
}
12781391
#endif /* CONFIG_NET_IPV4 */
12791392

1393+
k_mutex_unlock(&multicast_addr_lock);
1394+
12801395
#if defined(CONFIG_SOC_SERIES_STM32H7X)
12811396
heth->Instance->MACHT0R = hash_table[0];
12821397
heth->Instance->MACHT1R = hash_table[1];
12831398
#else
12841399
heth->Instance->MACHTLR = hash_table[0];
12851400
heth->Instance->MACHTHR = hash_table[1];
1286-
#endif
1401+
#endif /* CONFIG_SOC_SERIES_STM32H7X */
12871402
}
12881403

1404+
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
1405+
12891406
static void eth_iface_init(struct net_if *iface)
12901407
{
12911408
const struct device *dev;
@@ -1309,7 +1426,9 @@ static void eth_iface_init(struct net_if *iface)
13091426
is_first_init = true;
13101427
}
13111428

1312-
net_if_mcast_mon_register(&mcast_monitor, iface, net_if_mcast_cb);
1429+
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
1430+
net_if_mcast_mon_register(&mcast_monitor, iface, net_if_stm32_mcast_cb);
1431+
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
13131432

13141433
/* Register Ethernet MAC Address with the upper layer */
13151434
net_if_set_link_addr(iface, dev_data->mac_addr,

0 commit comments

Comments
 (0)