drivers: eth: enc28j60: Add VLAN support

Add Virtual LAN support to enc28j60 Ethernet driver.

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2020-02-27 00:14:24 +02:00
commit b50dabb9fd

View file

@ -410,6 +410,25 @@ static void eth_enc28j60_init_phy(struct device *dev)
}
}
static struct net_if *get_iface(struct eth_enc28j60_runtime *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 int eth_enc28j60_tx(struct device *dev, struct net_pkt *pkt)
{
struct eth_enc28j60_runtime *context = dev->driver_data;
@ -483,7 +502,7 @@ static int eth_enc28j60_tx(struct device *dev, struct net_pkt *pkt)
return 0;
}
static int eth_enc28j60_rx(struct device *dev)
static int eth_enc28j60_rx(struct device *dev, u16_t *vlan_tag)
{
const struct eth_enc28j60_config *config = dev->config->config_info;
struct eth_enc28j60_runtime *context = dev->driver_data;
@ -541,12 +560,13 @@ static int eth_enc28j60_rx(struct device *dev)
lengthfr = frm_len;
/* Get the frame from the buffer */
pkt = net_pkt_rx_alloc_with_buffer(context->iface, frm_len,
AF_UNSPEC, 0,
config->timeout);
pkt = net_pkt_rx_alloc_with_buffer(
get_iface(context, *vlan_tag), frm_len,
AF_UNSPEC, 0, config->timeout);
if (!pkt) {
LOG_ERR("Could not allocate rx buffer");
eth_stats_update_errors_rx(context->iface);
eth_stats_update_errors_rx(get_iface(context,
*vlan_tag));
goto done;
}
@ -587,9 +607,32 @@ static int eth_enc28j60_rx(struct device *dev)
eth_enc28j60_read_mem(dev, NULL, 1);
}
#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, context->iface);
}
#else /* CONFIG_NET_VLAN */
net_pkt_set_iface(pkt, context->iface);
#endif /* CONFIG_NET_VLAN */
/* Feed buffer frame to IP stack */
LOG_DBG("Received packet of length %u", lengthfr);
if (net_recv_data(context->iface, pkt) < 0) {
if (net_recv_data(net_pkt_iface(pkt), pkt) < 0) {
net_pkt_unref(pkt);
}
done:
@ -615,6 +658,7 @@ done:
static void eth_enc28j60_rx_thread(struct device *dev)
{
struct eth_enc28j60_runtime *context = dev->driver_data;
u16_t vlan_tag = NET_VLAN_TAG_UNSPEC;
u8_t int_stat;
while (true) {
@ -622,7 +666,7 @@ static void eth_enc28j60_rx_thread(struct device *dev)
eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &int_stat);
if (int_stat & ENC28J60_BIT_EIR_PKTIF) {
eth_enc28j60_rx(dev);
eth_enc28j60_rx(dev, &vlan_tag);
/* Clear rx interruption flag */
eth_enc28j60_clear_eth_reg(dev, ENC28J60_REG_EIR,
ENC28J60_BIT_EIR_PKTIF
@ -635,7 +679,11 @@ static enum ethernet_hw_caps eth_enc28j60_get_capabilities(struct device *dev)
{
ARG_UNUSED(dev);
return ETHERNET_LINK_10BASE_T;
return ETHERNET_LINK_10BASE_T
#if defined(CONFIG_NET_VLAN)
| ETHERNET_HW_VLAN
#endif
;
}
static void eth_enc28j60_iface_init(struct net_if *iface)
@ -646,7 +694,15 @@ static void eth_enc28j60_iface_init(struct net_if *iface)
net_if_set_link_addr(iface, context->mac_address,
sizeof(context->mac_address),
NET_LINK_ETHERNET);
context->iface = iface;
/* 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 (context->iface == NULL) {
context->iface = iface;
}
ethernet_init(iface);
}
@ -773,10 +829,9 @@ static const struct eth_enc28j60_config eth_enc28j60_0_config = {
.timeout = CONFIG_ETH_ENC28J60_TIMEOUT,
};
NET_DEVICE_INIT(enc28j60_0, DT_INST_0_MICROCHIP_ENC28J60_LABEL,
eth_enc28j60_init, &eth_enc28j60_0_runtime,
&eth_enc28j60_0_config, CONFIG_ETH_INIT_PRIORITY, &api_funcs,
ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2),
NET_ETH_MTU);
ETH_NET_DEVICE_INIT(enc28j60_0, DT_INST_0_MICROCHIP_ENC28J60_LABEL,
eth_enc28j60_init, &eth_enc28j60_0_runtime,
&eth_enc28j60_0_config, CONFIG_ETH_INIT_PRIORITY,
&api_funcs, NET_ETH_MTU);
#endif /* CONFIG_ETH_ENC28J60_0 */