drivers: eth: gmac: Adding VLAN support to Atmel E70 board
This enables VLAN support in gmac ethernet driver.
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
diff --git a/drivers/ethernet/eth_sam_gmac.c b/drivers/ethernet/eth_sam_gmac.c
index c4f2971..bf901d9 100644
--- a/drivers/ethernet/eth_sam_gmac.c
+++ b/drivers/ethernet/eth_sam_gmac.c
@@ -580,10 +580,30 @@
return rx_frame;
}
+static inline struct net_if *get_iface(struct eth_sam_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 void eth_rx(struct gmac_queue *queue)
{
struct eth_sam_dev_data *dev_data =
CONTAINER_OF(queue, struct eth_sam_dev_data, queue_list);
+ u16_t vlan_tag = NET_VLAN_TAG_UNSPEC;
struct net_pkt *rx_frame;
/* More than one frame could have been received by GMAC, get all
@@ -593,7 +613,36 @@
while (rx_frame) {
SYS_LOG_DBG("ETH rx");
- if (net_recv_data(dev_data->iface, rx_frame) < 0) {
+#if defined(CONFIG_NET_VLAN)
+ /* FIXME: Instead of this, use the GMAC register to get
+ * the used VLAN tag.
+ */
+ {
+ struct net_eth_hdr *hdr = NET_ETH_HDR(rx_frame);
+
+ if (ntohs(hdr->type) == NET_ETH_PTYPE_VLAN) {
+ struct net_eth_vlan_hdr *hdr_vlan =
+ (struct net_eth_vlan_hdr *)
+ NET_ETH_HDR(rx_frame);
+
+ net_pkt_set_vlan_tci(rx_frame,
+ ntohs(hdr_vlan->vlan.tci));
+ vlan_tag = net_pkt_vlan_tag(rx_frame);
+
+#if CONFIG_NET_TC_RX_COUNT > 1
+ {
+ enum net_priority prio;
+
+ prio = net_vlan2priority(
+ net_pkt_vlan_priority(rx_frame));
+ net_pkt_set_priority(rx_frame, prio);
+ }
+#endif
+ }
+ }
+#endif
+ if (net_recv_data(get_iface(dev_data, vlan_tag),
+ rx_frame) < 0) {
net_pkt_unref(rx_frame);
}
@@ -776,12 +825,21 @@
struct device *const dev = net_if_get_device(iface);
struct eth_sam_dev_data *const dev_data = DEV_DATA(dev);
const struct eth_sam_dev_cfg *const cfg = DEV_CFG(dev);
+ static bool init_done;
u32_t gmac_ncfgr_val;
u32_t link_status;
int result;
+ /* For VLAN, this value is only used to get the correct L2 driver */
dev_data->iface = iface;
+ ethernet_init(iface);
+
+ /* The rest of initialization should only be done once */
+ if (init_done) {
+ return;
+ }
+
/* Initialize GMAC driver, maximum frame length is 1518 bytes */
gmac_ncfgr_val =
GMAC_NCFGR_MTIHEN /* Multicast Hash Enable */
@@ -837,11 +895,26 @@
/* Set up link parameters */
link_configure(cfg->regs, link_status);
+
+ init_done = true;
}
+#if defined(CONFIG_NET_VLAN)
+static enum eth_hw_caps eth_capabilities(struct device *dev)
+{
+ ARG_UNUSED(dev);
+
+ return ETH_HW_VLAN;
+}
+#endif
+
static const struct ethernet_api eth0_api = {
.iface_api.init = eth0_iface_init,
.iface_api.send = eth_tx,
+
+#if defined(CONFIG_NET_VLAN)
+ .get_capabilities = eth_capabilities,
+#endif
};
static struct device DEVICE_NAME_GET(eth0_sam_gmac);
@@ -917,6 +990,6 @@
},
};
-NET_DEVICE_INIT(eth0_sam_gmac, CONFIG_ETH_SAM_GMAC_NAME, eth_initialize,
- ð0_data, ð0_config, CONFIG_ETH_INIT_PRIORITY, ð0_api,
- ETHERNET_L2, NET_L2_GET_CTX_TYPE(ETHERNET_L2), GMAC_MTU);
+ETH_NET_DEVICE_INIT(eth0_sam_gmac, CONFIG_ETH_SAM_GMAC_NAME, eth_initialize,
+ ð0_data, ð0_config, CONFIG_ETH_INIT_PRIORITY,
+ ð0_api, GMAC_MTU);