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:
parent
1edc84f526
commit
b50dabb9fd
1 changed files with 69 additions and 14 deletions
|
@ -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, ð_enc28j60_0_runtime,
|
||||
ð_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, ð_enc28j60_0_runtime,
|
||||
ð_enc28j60_0_config, CONFIG_ETH_INIT_PRIORITY,
|
||||
&api_funcs, NET_ETH_MTU);
|
||||
|
||||
#endif /* CONFIG_ETH_ENC28J60_0 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue