drivers: eth: stm32: Add VLAN support
Add Virtual LAN support to stm32 Ethernet driver. Refactor the eth_iface_init() and move device configuration settings to eth_initialize() as the eth_iface_init() is called multiple times (once / configured VLAN). Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
fe3e12face
commit
36ddeaceca
1 changed files with 108 additions and 51 deletions
|
@ -153,7 +153,26 @@ error:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct net_pkt *eth_rx(struct device *dev)
|
static struct net_if *get_iface(struct eth_stm32_hal_dev_data *ctx,
|
||||||
|
u16_t vlan_tag)
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_NET_VLAN)
|
||||||
|
struct net_if *iface;
|
||||||
|
|
||||||
|
iface = net_eth_get_vlan_iface(ctx->iface, vlan_tag);
|
||||||
|
if (!iface) {
|
||||||
|
return ctx->iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
return iface;
|
||||||
|
#else
|
||||||
|
ARG_UNUSED(vlan_tag);
|
||||||
|
|
||||||
|
return ctx->iface;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct net_pkt *eth_rx(struct device *dev, u16_t *vlan_tag)
|
||||||
{
|
{
|
||||||
struct eth_stm32_hal_dev_data *dev_data;
|
struct eth_stm32_hal_dev_data *dev_data;
|
||||||
ETH_HandleTypeDef *heth;
|
ETH_HandleTypeDef *heth;
|
||||||
|
@ -179,8 +198,8 @@ static struct net_pkt *eth_rx(struct device *dev)
|
||||||
total_len = heth->RxFrameInfos.length;
|
total_len = heth->RxFrameInfos.length;
|
||||||
dma_buffer = (u8_t *)heth->RxFrameInfos.buffer;
|
dma_buffer = (u8_t *)heth->RxFrameInfos.buffer;
|
||||||
|
|
||||||
pkt = net_pkt_rx_alloc_with_buffer(dev_data->iface, total_len,
|
pkt = net_pkt_rx_alloc_with_buffer(get_iface(dev_data, *vlan_tag),
|
||||||
AF_UNSPEC, 0, K_NO_WAIT);
|
total_len, AF_UNSPEC, 0, K_NO_WAIT);
|
||||||
if (!pkt) {
|
if (!pkt) {
|
||||||
LOG_ERR("Failed to obtain RX buffer");
|
LOG_ERR("Failed to obtain RX buffer");
|
||||||
goto release_desc;
|
goto release_desc;
|
||||||
|
@ -217,8 +236,29 @@ release_desc:
|
||||||
heth->Instance->DMARPDR = 0;
|
heth->Instance->DMARPDR = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_NET_VLAN)
|
||||||
|
struct net_eth_hdr *hdr = NET_ETH_HDR(pkt);
|
||||||
|
|
||||||
|
if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) {
|
||||||
|
struct net_eth_vlan_hdr *hdr_vlan =
|
||||||
|
(struct net_eth_vlan_hdr *)NET_ETH_HDR(pkt);
|
||||||
|
|
||||||
|
net_pkt_set_vlan_tci(pkt, ntohs(hdr_vlan->vlan.tci));
|
||||||
|
*vlan_tag = net_pkt_vlan_tag(pkt);
|
||||||
|
|
||||||
|
#if CONFIG_NET_TC_RX_COUNT > 1
|
||||||
|
enum net_priority prio;
|
||||||
|
|
||||||
|
prio = net_vlan2priority(net_pkt_vlan_priority(pkt));
|
||||||
|
net_pkt_set_priority(pkt, prio);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
net_pkt_set_iface(pkt, dev_data->iface);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NET_VLAN */
|
||||||
|
|
||||||
if (!pkt) {
|
if (!pkt) {
|
||||||
eth_stats_update_errors_rx(dev_data->iface);
|
eth_stats_update_errors_rx(get_iface(dev_data, *vlan_tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkt;
|
return pkt;
|
||||||
|
@ -226,6 +266,7 @@ release_desc:
|
||||||
|
|
||||||
static void rx_thread(void *arg1, void *unused1, void *unused2)
|
static void rx_thread(void *arg1, void *unused1, void *unused2)
|
||||||
{
|
{
|
||||||
|
u16_t vlan_tag = NET_VLAN_TAG_UNSPEC;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct eth_stm32_hal_dev_data *dev_data;
|
struct eth_stm32_hal_dev_data *dev_data;
|
||||||
struct net_pkt *pkt;
|
struct net_pkt *pkt;
|
||||||
|
@ -248,12 +289,14 @@ static void rx_thread(void *arg1, void *unused1, void *unused2)
|
||||||
/* semaphore taken, update link status and receive packets */
|
/* semaphore taken, update link status and receive packets */
|
||||||
if (dev_data->link_up != true) {
|
if (dev_data->link_up != true) {
|
||||||
dev_data->link_up = true;
|
dev_data->link_up = true;
|
||||||
net_eth_carrier_on(dev_data->iface);
|
net_eth_carrier_on(get_iface(dev_data,
|
||||||
|
vlan_tag));
|
||||||
}
|
}
|
||||||
while ((pkt = eth_rx(dev)) != NULL) {
|
while ((pkt = eth_rx(dev, &vlan_tag)) != NULL) {
|
||||||
res = net_recv_data(dev_data->iface, pkt);
|
res = net_recv_data(net_pkt_iface(pkt), pkt);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
eth_stats_update_errors_rx(dev_data->iface);
|
eth_stats_update_errors_rx(
|
||||||
|
net_pkt_iface(pkt));
|
||||||
LOG_ERR("Failed to enqueue frame "
|
LOG_ERR("Failed to enqueue frame "
|
||||||
"into RX queue: %d", res);
|
"into RX queue: %d", res);
|
||||||
net_pkt_unref(pkt);
|
net_pkt_unref(pkt);
|
||||||
|
@ -266,12 +309,16 @@ static void rx_thread(void *arg1, void *unused1, void *unused2)
|
||||||
if ((status & PHY_LINKED_STATUS) == PHY_LINKED_STATUS) {
|
if ((status & PHY_LINKED_STATUS) == PHY_LINKED_STATUS) {
|
||||||
if (dev_data->link_up != true) {
|
if (dev_data->link_up != true) {
|
||||||
dev_data->link_up = true;
|
dev_data->link_up = true;
|
||||||
net_eth_carrier_on(dev_data->iface);
|
net_eth_carrier_on(
|
||||||
|
get_iface(dev_data,
|
||||||
|
vlan_tag));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (dev_data->link_up != false) {
|
if (dev_data->link_up != false) {
|
||||||
dev_data->link_up = false;
|
dev_data->link_up = false;
|
||||||
net_eth_carrier_off(dev_data->iface);
|
net_eth_carrier_off(
|
||||||
|
get_iface(dev_data,
|
||||||
|
vlan_tag));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,10 +359,27 @@ void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth_handle)
|
||||||
k_sem_give(&dev_data->rx_int_sem);
|
k_sem_give(&dev_data->rx_int_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_ETH_STM32_HAL_RANDOM_MAC)
|
||||||
|
static void generate_mac(u8_t *mac_addr)
|
||||||
|
{
|
||||||
|
u32_t entropy;
|
||||||
|
|
||||||
|
entropy = sys_rand32_get();
|
||||||
|
|
||||||
|
mac_addr[0] |= 0x02; /* force LAA bit */
|
||||||
|
|
||||||
|
mac_addr[3] = entropy >> 16;
|
||||||
|
mac_addr[4] = entropy >> 8;
|
||||||
|
mac_addr[5] = entropy >> 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int eth_initialize(struct device *dev)
|
static int eth_initialize(struct device *dev)
|
||||||
{
|
{
|
||||||
struct eth_stm32_hal_dev_data *dev_data;
|
struct eth_stm32_hal_dev_data *dev_data;
|
||||||
struct eth_stm32_hal_dev_cfg *cfg;
|
struct eth_stm32_hal_dev_cfg *cfg;
|
||||||
|
ETH_HandleTypeDef *heth;
|
||||||
|
u8_t hal_ret;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
__ASSERT_NO_MSG(dev != NULL);
|
__ASSERT_NO_MSG(dev != NULL);
|
||||||
|
@ -348,43 +412,8 @@ static int eth_initialize(struct device *dev)
|
||||||
|
|
||||||
cfg->config_func();
|
cfg->config_func();
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CONFIG_ETH_STM32_HAL_RANDOM_MAC)
|
|
||||||
static void generate_mac(u8_t *mac_addr)
|
|
||||||
{
|
|
||||||
u32_t entropy;
|
|
||||||
|
|
||||||
entropy = sys_rand32_get();
|
|
||||||
|
|
||||||
mac_addr[0] |= 0x02; /* force LAA bit */
|
|
||||||
|
|
||||||
mac_addr[3] = entropy >> 16;
|
|
||||||
mac_addr[4] = entropy >> 8;
|
|
||||||
mac_addr[5] = entropy >> 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void eth_iface_init(struct net_if *iface)
|
|
||||||
{
|
|
||||||
struct device *dev;
|
|
||||||
struct eth_stm32_hal_dev_data *dev_data;
|
|
||||||
ETH_HandleTypeDef *heth;
|
|
||||||
u8_t hal_ret;
|
|
||||||
|
|
||||||
__ASSERT_NO_MSG(iface != NULL);
|
|
||||||
|
|
||||||
dev = net_if_get_device(iface);
|
|
||||||
__ASSERT_NO_MSG(dev != NULL);
|
|
||||||
|
|
||||||
dev_data = DEV_DATA(dev);
|
|
||||||
__ASSERT_NO_MSG(dev_data != NULL);
|
|
||||||
|
|
||||||
heth = &dev_data->heth;
|
heth = &dev_data->heth;
|
||||||
|
|
||||||
dev_data->iface = iface;
|
|
||||||
|
|
||||||
#if defined(CONFIG_ETH_STM32_HAL_RANDOM_MAC)
|
#if defined(CONFIG_ETH_STM32_HAL_RANDOM_MAC)
|
||||||
generate_mac(dev_data->mac_addr);
|
generate_mac(dev_data->mac_addr);
|
||||||
#endif
|
#endif
|
||||||
|
@ -395,7 +424,6 @@ static void eth_iface_init(struct net_if *iface)
|
||||||
heth->Init.MACAddr = dev_data->mac_addr;
|
heth->Init.MACAddr = dev_data->mac_addr;
|
||||||
|
|
||||||
hal_ret = HAL_ETH_Init(heth);
|
hal_ret = HAL_ETH_Init(heth);
|
||||||
|
|
||||||
if (hal_ret == HAL_TIMEOUT) {
|
if (hal_ret == HAL_TIMEOUT) {
|
||||||
/* HAL Init time out. This could be linked to */
|
/* HAL Init time out. This could be linked to */
|
||||||
/* a recoverable error. Log the issue and continue */
|
/* a recoverable error. Log the issue and continue */
|
||||||
|
@ -403,7 +431,7 @@ static void eth_iface_init(struct net_if *iface)
|
||||||
LOG_ERR("HAL_ETH_Init Timed out");
|
LOG_ERR("HAL_ETH_Init Timed out");
|
||||||
} else if (hal_ret != HAL_OK) {
|
} else if (hal_ret != HAL_OK) {
|
||||||
LOG_ERR("HAL_ETH_Init failed: %d", hal_ret);
|
LOG_ERR("HAL_ETH_Init failed: %d", hal_ret);
|
||||||
return;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_data->link_up = false;
|
dev_data->link_up = false;
|
||||||
|
@ -437,12 +465,37 @@ static void eth_iface_init(struct net_if *iface)
|
||||||
dev_data->mac_addr[2], dev_data->mac_addr[3],
|
dev_data->mac_addr[2], dev_data->mac_addr[3],
|
||||||
dev_data->mac_addr[4], dev_data->mac_addr[5]);
|
dev_data->mac_addr[4], dev_data->mac_addr[5]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eth_iface_init(struct net_if *iface)
|
||||||
|
{
|
||||||
|
struct device *dev;
|
||||||
|
struct eth_stm32_hal_dev_data *dev_data;
|
||||||
|
|
||||||
|
__ASSERT_NO_MSG(iface != NULL);
|
||||||
|
|
||||||
|
dev = net_if_get_device(iface);
|
||||||
|
__ASSERT_NO_MSG(dev != NULL);
|
||||||
|
|
||||||
|
dev_data = DEV_DATA(dev);
|
||||||
|
__ASSERT_NO_MSG(dev_data != NULL);
|
||||||
|
|
||||||
|
/* For VLAN, this value is only used to get the correct L2 driver.
|
||||||
|
* The iface pointer in context should contain the main interface
|
||||||
|
* if the VLANs are enabled.
|
||||||
|
*/
|
||||||
|
if (dev_data->iface == NULL) {
|
||||||
|
dev_data->iface = iface;
|
||||||
|
}
|
||||||
|
|
||||||
/* Register Ethernet MAC Address with the upper layer */
|
/* Register Ethernet MAC Address with the upper layer */
|
||||||
net_if_set_link_addr(iface, dev_data->mac_addr,
|
net_if_set_link_addr(iface, dev_data->mac_addr,
|
||||||
sizeof(dev_data->mac_addr),
|
sizeof(dev_data->mac_addr),
|
||||||
NET_LINK_ETHERNET);
|
NET_LINK_ETHERNET);
|
||||||
|
|
||||||
ethernet_init(iface);
|
ethernet_init(iface);
|
||||||
|
|
||||||
net_if_flag_set(iface, NET_IF_NO_AUTO_START);
|
net_if_flag_set(iface, NET_IF_NO_AUTO_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,7 +503,11 @@ static enum ethernet_hw_caps eth_stm32_hal_get_capabilities(struct device *dev)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(dev);
|
ARG_UNUSED(dev);
|
||||||
|
|
||||||
return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T;
|
return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T
|
||||||
|
#if defined(CONFIG_NET_VLAN)
|
||||||
|
| ETHERNET_HW_VLAN
|
||||||
|
#endif
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int eth_stm32_hal_set_config(struct device *dev,
|
static int eth_stm32_hal_set_config(struct device *dev,
|
||||||
|
@ -536,6 +593,6 @@ static struct eth_stm32_hal_dev_data eth0_data = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
NET_DEVICE_INIT(eth0_stm32_hal, CONFIG_ETH_STM32_HAL_NAME, eth_initialize,
|
ETH_NET_DEVICE_INIT(eth0_stm32_hal, CONFIG_ETH_STM32_HAL_NAME, eth_initialize,
|
||||||
ð0_data, ð0_config, CONFIG_ETH_INIT_PRIORITY, ð_api,
|
ð0_data, ð0_config, CONFIG_ETH_INIT_PRIORITY,
|
||||||
ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), ETH_STM32_HAL_MTU);
|
ð_api, ETH_STM32_HAL_MTU);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue