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:
parent
28e10630c2
commit
f900bfc3de
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user