drivers: ethernet: eth_stm32: Rework HW MAC address filtering

Rework the driver to use HW MAC address filtering as an ethernet
capability.
Use a counter table for CRC indexes added/removed.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
This commit is contained in:
Pieter De Gendt 2024-03-01 10:58:53 +01:00 committed by Alberto Escolar
parent 28e10630c2
commit f900bfc3de
2 changed files with 30 additions and 164 deletions

View File

@ -100,22 +100,6 @@ static ETH_DMADescTypeDef dma_tx_desc_tab[ETH_TXBUFNB] __eth_stm32_desc;
static uint8_t dma_rx_buffer[ETH_RXBUFNB][ETH_STM32_RX_BUF_SIZE] __eth_stm32_buf;
static uint8_t dma_tx_buffer[ETH_TXBUFNB][ETH_STM32_TX_BUF_SIZE] __eth_stm32_buf;
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
static struct net_if_mcast_monitor mcast_monitor;
static K_MUTEX_DEFINE(multicast_addr_lock);
#if defined(CONFIG_NET_NATIVE_IPV6)
static struct in6_addr multicast_ipv6_joined_addrs[NET_IF_MAX_IPV6_MADDR] = {0};
#endif /* CONFIG_NET_NATIVE_IPV6 */
#if defined(CONFIG_NET_NATIVE_IPV4)
static struct in_addr multicast_ipv4_joined_addrs[NET_IF_MAX_IPV4_MADDR] = {0};
#endif /* CONFIG_NET_NATIVE_IPV4 */
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
#if defined(CONFIG_ETH_STM32_HAL_API_V2)
BUILD_ASSERT(ETH_STM32_RX_BUF_SIZE % 4 == 0, "Rx buffer size must be a multiple of 4");
@ -1305,62 +1289,6 @@ static int eth_initialize(const struct device *dev)
}
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
#if defined(CONFIG_NET_NATIVE_IPV6)
static void add_ipv6_multicast_addr(const struct in6_addr *addr)
{
uint32_t i;
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
if (net_ipv6_is_addr_unspecified(&multicast_ipv6_joined_addrs[i])) {
net_ipv6_addr_copy_raw((uint8_t *)&multicast_ipv6_joined_addrs[i],
(uint8_t *)addr);
break;
}
}
}
static void remove_ipv6_multicast_addr(const struct in6_addr *addr)
{
uint32_t i;
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
if (net_ipv6_addr_cmp(&multicast_ipv6_joined_addrs[i], addr)) {
net_ipv6_addr_copy_raw((uint8_t *)&multicast_ipv6_joined_addrs[i],
(uint8_t *)net_ipv6_unspecified_address);
break;
}
}
}
#endif /* CONFIG_NET_NATIVE_IPV6 */
#if defined(CONFIG_NET_NATIVE_IPV4)
static void add_ipv4_multicast_addr(const struct in_addr *addr)
{
uint32_t i;
for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) {
if (net_ipv4_is_addr_unspecified(&multicast_ipv4_joined_addrs[i])) {
net_ipv4_addr_copy_raw((uint8_t *)&multicast_ipv4_joined_addrs[i],
(uint8_t *)addr);
break;
}
}
}
static void remove_ipv4_multicast_addr(const struct in_addr *addr)
{
uint32_t i;
for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) {
if (net_ipv4_addr_cmp(&multicast_ipv4_joined_addrs[i], addr)) {
multicast_ipv4_joined_addrs[i].s_addr = 0;
break;
}
}
}
#endif /* CONFIG_NET_NATIVE_IPV4 */
static uint32_t reverse(uint32_t val)
{
uint32_t res = 0;
@ -1375,112 +1303,43 @@ static uint32_t reverse(uint32_t val)
return res;
}
static void net_if_stm32_mcast_cb(struct net_if *iface,
const struct net_addr *addr,
bool is_joined)
static void eth_stm32_mcast_filter(const struct device *dev, const struct ethernet_filter *filter)
{
ARG_UNUSED(addr);
const struct device *dev;
struct eth_stm32_hal_dev_data *dev_data;
struct eth_stm32_hal_dev_data *dev_data = (struct eth_stm32_hal_dev_data *)dev->data;
ETH_HandleTypeDef *heth;
struct net_eth_addr mac_addr;
uint32_t crc;
uint32_t hash_table[2];
uint32_t hash_index;
int i;
dev = net_if_get_device(iface);
dev_data = (struct eth_stm32_hal_dev_data *)dev->data;
heth = &dev_data->heth;
hash_table[0] = 0;
hash_table[1] = 0;
crc = reverse(crc32_ieee(filter->mac_address.addr, sizeof(struct net_eth_addr)));
hash_index = (crc >> 26) & 0x3f;
__ASSERT_NO_MSG(hash_index < ARRAY_SIZE(dev_data->hash_index_cnt));
if (is_joined) {
/* Save a copy of the hash table which we update with
* the hash for a single multicast address for join
*/
#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X)
hash_table[0] = heth->Instance->MACHT0R;
hash_table[1] = heth->Instance->MACHT1R;
hash_table[0] = heth->Instance->MACHT0R;
hash_table[1] = heth->Instance->MACHT1R;
#else
hash_table[0] = heth->Instance->MACHTLR;
hash_table[1] = heth->Instance->MACHTHR;
hash_table[0] = heth->Instance->MACHTLR;
hash_table[1] = heth->Instance->MACHTHR;
#endif /* CONFIG_SOC_SERIES_STM32H7X || CONFIG_SOC_SERIES_STM32H5X */
}
k_mutex_lock(&multicast_addr_lock, K_FOREVER);
#if defined(CONFIG_NET_NATIVE_IPV6)
if (is_joined) {
/* When joining only update the hash filter with the joining
* multicast address.
*/
add_ipv6_multicast_addr(&addr->in6_addr);
net_eth_ipv6_mcast_to_mac_addr(&addr->in6_addr, &mac_addr);
crc = reverse(crc32_ieee(mac_addr.addr,
sizeof(struct net_eth_addr)));
hash_index = (crc >> 26) & 0x3f;
if (filter->set) {
dev_data->hash_index_cnt[hash_index]++;
hash_table[hash_index / 32] |= (1 << (hash_index % 32));
} else {
/* When leaving its better to compute the full hash table
* for all the multicast addresses that we're aware of.
*/
remove_ipv6_multicast_addr(&addr->in6_addr);
if (dev_data->hash_index_cnt[hash_index] == 0) {
__ASSERT_NO_MSG(false);
return;
}
for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) {
if (net_ipv6_is_addr_unspecified(&multicast_ipv6_joined_addrs[i])) {
continue;
}
net_eth_ipv6_mcast_to_mac_addr(&multicast_ipv6_joined_addrs[i],
&mac_addr);
crc = reverse(crc32_ieee(mac_addr.addr,
sizeof(struct net_eth_addr)));
hash_index = (crc >> 26) & 0x3f;
hash_table[hash_index / 32] |= (1 << (hash_index % 32));
dev_data->hash_index_cnt[hash_index]--;
if (dev_data->hash_index_cnt[hash_index] == 0) {
hash_table[hash_index / 32] &= ~(1 << (hash_index % 32));
}
}
#endif /* CONFIG_NET_IPV6 */
#if defined(CONFIG_NET_NATIVE_IPV4)
if (is_joined) {
/* When joining only update the hash filter with the joining
* multicast address.
*/
add_ipv4_multicast_addr(&addr->in_addr);
net_eth_ipv4_mcast_to_mac_addr(&addr->in_addr, &mac_addr);
crc = reverse(crc32_ieee(mac_addr.addr,
sizeof(struct net_eth_addr)));
hash_index = (crc >> 26) & 0x3f;
hash_table[hash_index / 32] |= (1 << (hash_index % 32));
} else {
/* When leaving its better to compute the full hash table
* for all the multicast addresses that we're aware of.
*/
remove_ipv4_multicast_addr(&addr->in_addr);
for (i = 0; i < NET_IF_MAX_IPV4_MADDR; i++) {
if (net_ipv4_is_addr_unspecified(&multicast_ipv4_joined_addrs[i])) {
continue;
}
net_eth_ipv4_mcast_to_mac_addr(&multicast_ipv4_joined_addrs[i],
&mac_addr);
crc = reverse(crc32_ieee(mac_addr.addr,
sizeof(struct net_eth_addr)));
hash_index = (crc >> 26) & 0x3f;
hash_table[hash_index / 32] |= (1 << (hash_index % 32));
}
}
#endif /* CONFIG_NET_IPV4 */
k_mutex_unlock(&multicast_addr_lock);
#if defined(CONFIG_SOC_SERIES_STM32H7X) || defined(CONFIG_SOC_SERIES_STM32H5X)
heth->Instance->MACHT0R = hash_table[0];
@ -1516,10 +1375,6 @@ static void eth_iface_init(struct net_if *iface)
is_first_init = true;
}
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
net_if_mcast_mon_register(&mcast_monitor, iface, net_if_stm32_mcast_cb);
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
/* Register Ethernet MAC Address with the upper layer */
net_if_set_link_addr(iface, dev_data->mac_addr,
sizeof(dev_data->mac_addr),
@ -1575,6 +1430,9 @@ static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(const struct device
#endif
#if defined(CONFIG_NET_DSA)
| ETHERNET_DSA_MASTER_PORT
#endif
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
| ETHERNET_HW_FILTERING
#endif
;
}
@ -1622,6 +1480,11 @@ static int eth_stm32_hal_set_config(const struct device *dev,
ret = 0;
#endif /* CONFIG_NET_PROMISCUOUS_MODE */
break;
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
case ETHERNET_CONFIG_TYPE_FILTER:
eth_stm32_mcast_filter(dev, &config->filter);
break;
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
default:
break;
}

View File

@ -49,6 +49,9 @@ struct eth_stm32_hal_dev_data {
CONFIG_ETH_STM32_HAL_RX_THREAD_STACK_SIZE);
struct k_thread rx_thread;
bool link_up;
#if defined(CONFIG_ETH_STM32_MULTICAST_FILTER)
uint8_t hash_index_cnt[64];
#endif /* CONFIG_ETH_STM32_MULTICAST_FILTER */
#if defined(CONFIG_PTP_CLOCK_STM32_HAL)
const struct device *ptp_clock;
float clk_ratio;