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)
|
static int eth_enc28j60_tx(struct device *dev, struct net_pkt *pkt)
|
||||||
{
|
{
|
||||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
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;
|
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;
|
const struct eth_enc28j60_config *config = dev->config->config_info;
|
||||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||||
|
@ -541,12 +560,13 @@ static int eth_enc28j60_rx(struct device *dev)
|
||||||
lengthfr = frm_len;
|
lengthfr = frm_len;
|
||||||
|
|
||||||
/* Get the frame from the buffer */
|
/* Get the frame from the buffer */
|
||||||
pkt = net_pkt_rx_alloc_with_buffer(context->iface, frm_len,
|
pkt = net_pkt_rx_alloc_with_buffer(
|
||||||
AF_UNSPEC, 0,
|
get_iface(context, *vlan_tag), frm_len,
|
||||||
config->timeout);
|
AF_UNSPEC, 0, config->timeout);
|
||||||
if (!pkt) {
|
if (!pkt) {
|
||||||
LOG_ERR("Could not allocate rx buffer");
|
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;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,9 +607,32 @@ static int eth_enc28j60_rx(struct device *dev)
|
||||||
eth_enc28j60_read_mem(dev, NULL, 1);
|
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 */
|
/* Feed buffer frame to IP stack */
|
||||||
LOG_DBG("Received packet of length %u", lengthfr);
|
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);
|
net_pkt_unref(pkt);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
@ -615,6 +658,7 @@ done:
|
||||||
static void eth_enc28j60_rx_thread(struct device *dev)
|
static void eth_enc28j60_rx_thread(struct device *dev)
|
||||||
{
|
{
|
||||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||||
|
u16_t vlan_tag = NET_VLAN_TAG_UNSPEC;
|
||||||
u8_t int_stat;
|
u8_t int_stat;
|
||||||
|
|
||||||
while (true) {
|
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);
|
eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &int_stat);
|
||||||
if (int_stat & ENC28J60_BIT_EIR_PKTIF) {
|
if (int_stat & ENC28J60_BIT_EIR_PKTIF) {
|
||||||
eth_enc28j60_rx(dev);
|
eth_enc28j60_rx(dev, &vlan_tag);
|
||||||
/* Clear rx interruption flag */
|
/* Clear rx interruption flag */
|
||||||
eth_enc28j60_clear_eth_reg(dev, ENC28J60_REG_EIR,
|
eth_enc28j60_clear_eth_reg(dev, ENC28J60_REG_EIR,
|
||||||
ENC28J60_BIT_EIR_PKTIF
|
ENC28J60_BIT_EIR_PKTIF
|
||||||
|
@ -635,7 +679,11 @@ static enum ethernet_hw_caps eth_enc28j60_get_capabilities(struct device *dev)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(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)
|
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,
|
net_if_set_link_addr(iface, context->mac_address,
|
||||||
sizeof(context->mac_address),
|
sizeof(context->mac_address),
|
||||||
NET_LINK_ETHERNET);
|
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);
|
ethernet_init(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -773,10 +829,9 @@ static const struct eth_enc28j60_config eth_enc28j60_0_config = {
|
||||||
.timeout = CONFIG_ETH_ENC28J60_TIMEOUT,
|
.timeout = CONFIG_ETH_ENC28J60_TIMEOUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
NET_DEVICE_INIT(enc28j60_0, DT_INST_0_MICROCHIP_ENC28J60_LABEL,
|
ETH_NET_DEVICE_INIT(enc28j60_0, DT_INST_0_MICROCHIP_ENC28J60_LABEL,
|
||||||
eth_enc28j60_init, ð_enc28j60_0_runtime,
|
eth_enc28j60_init, ð_enc28j60_0_runtime,
|
||||||
ð_enc28j60_0_config, CONFIG_ETH_INIT_PRIORITY, &api_funcs,
|
ð_enc28j60_0_config, CONFIG_ETH_INIT_PRIORITY,
|
||||||
ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2),
|
&api_funcs, NET_ETH_MTU);
|
||||||
NET_ETH_MTU);
|
|
||||||
|
|
||||||
#endif /* CONFIG_ETH_ENC28J60_0 */
|
#endif /* CONFIG_ETH_ENC28J60_0 */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue