All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Add CPSW VLAN Support
@ 2013-01-30 19:07 ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-arm-kernel, linux-omap, Mugunthan V N

CPSW is capable of filtering VLAN packets in hardware. This patch series
implements VLAN support to CPSW driver.
This patch series is tested on net-next with AM335x EVM with ping test.

Changes from initial version
* added vlan support to existing add/delete unicast/multicast apis
* Made driver as default VLAN enabled so that drivers need to be recompiled
  when stack is compiled with VLAN

Mugunthan V N (2):
  drivers: net: cpsw: Add helper functions for VLAN ALE implementation
  drivers: net:ethernet: cpsw: add support for VLAN

 Documentation/devicetree/bindings/net/cpsw.txt |    2 +
 drivers/net/ethernet/ti/cpsw.c                 |  100 ++++++++++++++++++++--
 drivers/net/ethernet/ti/cpsw_ale.c             |  106 +++++++++++++++++++++---
 drivers/net/ethernet/ti/cpsw_ale.h             |   20 +++--
 include/linux/platform_data/cpsw.h             |    1 +
 5 files changed, 205 insertions(+), 24 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 0/2] Add CPSW VLAN Support
@ 2013-01-30 19:07 ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-arm-kernel, linux-omap, Mugunthan V N

CPSW is capable of filtering VLAN packets in hardware. This patch series
implements VLAN support to CPSW driver.
This patch series is tested on net-next with AM335x EVM with ping test.

Changes from initial version
* added vlan support to existing add/delete unicast/multicast apis
* Made driver as default VLAN enabled so that drivers need to be recompiled
  when stack is compiled with VLAN

Mugunthan V N (2):
  drivers: net: cpsw: Add helper functions for VLAN ALE implementation
  drivers: net:ethernet: cpsw: add support for VLAN

 Documentation/devicetree/bindings/net/cpsw.txt |    2 +
 drivers/net/ethernet/ti/cpsw.c                 |  100 ++++++++++++++++++++--
 drivers/net/ethernet/ti/cpsw_ale.c             |  106 +++++++++++++++++++++---
 drivers/net/ethernet/ti/cpsw_ale.h             |   20 +++--
 include/linux/platform_data/cpsw.h             |    1 +
 5 files changed, 205 insertions(+), 24 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 0/2] Add CPSW VLAN Support
@ 2013-01-30 19:07 ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: linux-arm-kernel

CPSW is capable of filtering VLAN packets in hardware. This patch series
implements VLAN support to CPSW driver.
This patch series is tested on net-next with AM335x EVM with ping test.

Changes from initial version
* added vlan support to existing add/delete unicast/multicast apis
* Made driver as default VLAN enabled so that drivers need to be recompiled
  when stack is compiled with VLAN

Mugunthan V N (2):
  drivers: net: cpsw: Add helper functions for VLAN ALE implementation
  drivers: net:ethernet: cpsw: add support for VLAN

 Documentation/devicetree/bindings/net/cpsw.txt |    2 +
 drivers/net/ethernet/ti/cpsw.c                 |  100 ++++++++++++++++++++--
 drivers/net/ethernet/ti/cpsw_ale.c             |  106 +++++++++++++++++++++---
 drivers/net/ethernet/ti/cpsw_ale.h             |   20 +++--
 include/linux/platform_data/cpsw.h             |    1 +
 5 files changed, 205 insertions(+), 24 deletions(-)

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
  2013-01-30 19:07 ` Mugunthan V N
  (?)
@ 2013-01-30 19:07   ` Mugunthan V N
  -1 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-arm-kernel, linux-omap, Mugunthan V N

Add helper functions for VLAN ALE implementations for Add, Delete
Dump VLAN related ALE entries

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/net/ethernet/ti/cpsw.c     |    8 +--
 drivers/net/ethernet/ti/cpsw_ale.c |  106 ++++++++++++++++++++++++++++++++----
 drivers/net/ethernet/ti/cpsw_ale.h |   20 +++++--
 3 files changed, 112 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index b35e6a7..a40750e 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -345,7 +345,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 		/* program multicast address list into ALE register */
 		netdev_for_each_mc_addr(ha, ndev) {
 			cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr,
-				ALE_ALL_PORTS << priv->host_port, 0, 0);
+				ALE_ALL_PORTS << priv->host_port, 0, 0, 0);
 		}
 	}
 }
@@ -592,7 +592,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 	slave_port = cpsw_get_slave_port(priv, slave->slave_num);
 
 	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-			   1 << slave_port, 0, ALE_MCAST_FWD_2);
+			   1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
 
 	slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
 				 &cpsw_adjust_link, slave->data->phy_if);
@@ -624,9 +624,9 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
 	cpsw_ale_control_set(priv->ale, priv->host_port,
 			     ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
 
-	cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0);
+	cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0, 0);
 	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-			   1 << priv->host_port, 0, ALE_MCAST_FWD_2);
+			   1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2);
 }
 
 static int cpsw_ndo_open(struct net_device *ndev)
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 0e9ccc2..18b88ce 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -148,7 +148,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry)
 	return idx;
 }
 
-static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
+int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS];
 	int type, idx;
@@ -160,6 +160,8 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
 		type = cpsw_ale_get_entry_type(ale_entry);
 		if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
 			continue;
+		if (cpsw_ale_get_vlan_id(ale_entry) != vid)
+			continue;
 		cpsw_ale_get_addr(ale_entry, entry_addr);
 		if (memcmp(entry_addr, addr, 6) == 0)
 			return idx;
@@ -167,6 +169,22 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
 	return -ENOENT;
 }
 
+int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS];
+	int type, idx;
+
+	for (idx = 0; idx < ale->params.ale_entries; idx++) {
+		cpsw_ale_read(ale, idx, ale_entry);
+		type = cpsw_ale_get_entry_type(ale_entry);
+		if (type != ALE_TYPE_VLAN)
+			continue;
+		if (cpsw_ale_get_vlan_id(ale_entry) == vid)
+			return idx;
+	}
+	return -ENOENT;
+}
+
 static int cpsw_ale_match_free(struct cpsw_ale *ale)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS];
@@ -274,19 +292,26 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
 	return 0;
 }
 
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	if (flags & ALE_VLAN) {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+		cpsw_ale_set_vlan_id(ale_entry, vid);
+	} else {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	}
+
 	cpsw_ale_set_addr(ale_entry, addr);
 	cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
 	cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
 	cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
 	cpsw_ale_set_port_num(ale_entry, port);
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		idx = cpsw_ale_match_free(ale);
 	if (idx < 0)
@@ -298,12 +323,13 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
 	return 0;
 }
 
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		return -ENOENT;
 
@@ -313,18 +339,24 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
 }
 
 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
-			int super, int mcast_state)
+		       int flags, u16 vid, int mcast_state)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx, mask;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx >= 0)
 		cpsw_ale_read(ale, idx, ale_entry);
 
-	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	if (flags & ALE_VLAN) {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+		cpsw_ale_set_vlan_id(ale_entry, vid);
+	} else {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	}
+
 	cpsw_ale_set_addr(ale_entry, addr);
-	cpsw_ale_set_super(ale_entry, super);
+	cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
 	cpsw_ale_set_mcast_state(ale_entry, mcast_state);
 
 	mask = cpsw_ale_get_port_mask(ale_entry);
@@ -342,12 +374,13 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
 	return 0;
 }
 
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		return -EINVAL;
 
@@ -362,6 +395,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
 	return 0;
 }
 
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+		      int reg_mcast, int unreg_mcast)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+	int idx;
+
+	idx = cpsw_ale_match_vlan(ale, vid);
+	if (idx >= 0)
+		cpsw_ale_read(ale, idx, ale_entry);
+
+	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
+	cpsw_ale_set_vlan_id(ale_entry, vid);
+
+	cpsw_ale_set_vlan_untag_force(ale_entry, untag);
+	cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast);
+	cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
+	cpsw_ale_set_vlan_member_list(ale_entry, port);
+
+	if (idx < 0)
+		idx = cpsw_ale_match_free(ale);
+	if (idx < 0)
+		idx = cpsw_ale_find_ageable(ale);
+	if (idx < 0)
+		return -ENOMEM;
+
+	cpsw_ale_write(ale, idx, ale_entry);
+	return 0;
+}
+
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+	int idx;
+
+	idx = cpsw_ale_match_vlan(ale, vid);
+	if (idx < 0)
+		return -ENOENT;
+
+	cpsw_ale_read(ale, idx, ale_entry);
+
+	if (port_mask)
+		cpsw_ale_set_vlan_member_list(ale_entry, port_mask);
+	else
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+
+	cpsw_ale_write(ale, idx, ale_entry);
+	return 0;
+}
+
 struct ale_control_info {
 	const char	*name;
 	int		offset, port_offset;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index 2bd09cb..a002417 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -64,8 +64,10 @@ enum cpsw_ale_port_state {
 };
 
 /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
-#define ALE_SECURE			1
-#define ALE_BLOCKED			2
+#define ALE_SECURE			BIT(0)
+#define ALE_BLOCKED			BIT(1)
+#define ALE_SUPER			BIT(2)
+#define ALE_VLAN			BIT(3)
 
 #define ALE_MCAST_FWD			0
 #define ALE_MCAST_BLOCK_LEARN_FWD	1
@@ -81,11 +83,17 @@ void cpsw_ale_stop(struct cpsw_ale *ale);
 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
 int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask);
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags);
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port);
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid);
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid);
 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
-			int super, int mcast_state);
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask);
+		       int flags, u16 vid, int mcast_state);
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+		       int flags, u16 vid);
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+			int reg_mcast, int unreg_mcast);
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
 
 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
 int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
@ 2013-01-30 19:07   ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-arm-kernel, linux-omap, Mugunthan V N

Add helper functions for VLAN ALE implementations for Add, Delete
Dump VLAN related ALE entries

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/net/ethernet/ti/cpsw.c     |    8 +--
 drivers/net/ethernet/ti/cpsw_ale.c |  106 ++++++++++++++++++++++++++++++++----
 drivers/net/ethernet/ti/cpsw_ale.h |   20 +++++--
 3 files changed, 112 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index b35e6a7..a40750e 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -345,7 +345,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 		/* program multicast address list into ALE register */
 		netdev_for_each_mc_addr(ha, ndev) {
 			cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr,
-				ALE_ALL_PORTS << priv->host_port, 0, 0);
+				ALE_ALL_PORTS << priv->host_port, 0, 0, 0);
 		}
 	}
 }
@@ -592,7 +592,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 	slave_port = cpsw_get_slave_port(priv, slave->slave_num);
 
 	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-			   1 << slave_port, 0, ALE_MCAST_FWD_2);
+			   1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
 
 	slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
 				 &cpsw_adjust_link, slave->data->phy_if);
@@ -624,9 +624,9 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
 	cpsw_ale_control_set(priv->ale, priv->host_port,
 			     ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
 
-	cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0);
+	cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0, 0);
 	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-			   1 << priv->host_port, 0, ALE_MCAST_FWD_2);
+			   1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2);
 }
 
 static int cpsw_ndo_open(struct net_device *ndev)
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 0e9ccc2..18b88ce 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -148,7 +148,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry)
 	return idx;
 }
 
-static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
+int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS];
 	int type, idx;
@@ -160,6 +160,8 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
 		type = cpsw_ale_get_entry_type(ale_entry);
 		if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
 			continue;
+		if (cpsw_ale_get_vlan_id(ale_entry) != vid)
+			continue;
 		cpsw_ale_get_addr(ale_entry, entry_addr);
 		if (memcmp(entry_addr, addr, 6) == 0)
 			return idx;
@@ -167,6 +169,22 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
 	return -ENOENT;
 }
 
+int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS];
+	int type, idx;
+
+	for (idx = 0; idx < ale->params.ale_entries; idx++) {
+		cpsw_ale_read(ale, idx, ale_entry);
+		type = cpsw_ale_get_entry_type(ale_entry);
+		if (type != ALE_TYPE_VLAN)
+			continue;
+		if (cpsw_ale_get_vlan_id(ale_entry) == vid)
+			return idx;
+	}
+	return -ENOENT;
+}
+
 static int cpsw_ale_match_free(struct cpsw_ale *ale)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS];
@@ -274,19 +292,26 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
 	return 0;
 }
 
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	if (flags & ALE_VLAN) {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+		cpsw_ale_set_vlan_id(ale_entry, vid);
+	} else {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	}
+
 	cpsw_ale_set_addr(ale_entry, addr);
 	cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
 	cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
 	cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
 	cpsw_ale_set_port_num(ale_entry, port);
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		idx = cpsw_ale_match_free(ale);
 	if (idx < 0)
@@ -298,12 +323,13 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
 	return 0;
 }
 
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		return -ENOENT;
 
@@ -313,18 +339,24 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
 }
 
 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
-			int super, int mcast_state)
+		       int flags, u16 vid, int mcast_state)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx, mask;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx >= 0)
 		cpsw_ale_read(ale, idx, ale_entry);
 
-	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	if (flags & ALE_VLAN) {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+		cpsw_ale_set_vlan_id(ale_entry, vid);
+	} else {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	}
+
 	cpsw_ale_set_addr(ale_entry, addr);
-	cpsw_ale_set_super(ale_entry, super);
+	cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
 	cpsw_ale_set_mcast_state(ale_entry, mcast_state);
 
 	mask = cpsw_ale_get_port_mask(ale_entry);
@@ -342,12 +374,13 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
 	return 0;
 }
 
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		return -EINVAL;
 
@@ -362,6 +395,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
 	return 0;
 }
 
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+		      int reg_mcast, int unreg_mcast)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+	int idx;
+
+	idx = cpsw_ale_match_vlan(ale, vid);
+	if (idx >= 0)
+		cpsw_ale_read(ale, idx, ale_entry);
+
+	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
+	cpsw_ale_set_vlan_id(ale_entry, vid);
+
+	cpsw_ale_set_vlan_untag_force(ale_entry, untag);
+	cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast);
+	cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
+	cpsw_ale_set_vlan_member_list(ale_entry, port);
+
+	if (idx < 0)
+		idx = cpsw_ale_match_free(ale);
+	if (idx < 0)
+		idx = cpsw_ale_find_ageable(ale);
+	if (idx < 0)
+		return -ENOMEM;
+
+	cpsw_ale_write(ale, idx, ale_entry);
+	return 0;
+}
+
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+	int idx;
+
+	idx = cpsw_ale_match_vlan(ale, vid);
+	if (idx < 0)
+		return -ENOENT;
+
+	cpsw_ale_read(ale, idx, ale_entry);
+
+	if (port_mask)
+		cpsw_ale_set_vlan_member_list(ale_entry, port_mask);
+	else
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+
+	cpsw_ale_write(ale, idx, ale_entry);
+	return 0;
+}
+
 struct ale_control_info {
 	const char	*name;
 	int		offset, port_offset;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index 2bd09cb..a002417 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -64,8 +64,10 @@ enum cpsw_ale_port_state {
 };
 
 /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
-#define ALE_SECURE			1
-#define ALE_BLOCKED			2
+#define ALE_SECURE			BIT(0)
+#define ALE_BLOCKED			BIT(1)
+#define ALE_SUPER			BIT(2)
+#define ALE_VLAN			BIT(3)
 
 #define ALE_MCAST_FWD			0
 #define ALE_MCAST_BLOCK_LEARN_FWD	1
@@ -81,11 +83,17 @@ void cpsw_ale_stop(struct cpsw_ale *ale);
 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
 int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask);
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags);
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port);
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid);
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid);
 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
-			int super, int mcast_state);
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask);
+		       int flags, u16 vid, int mcast_state);
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+		       int flags, u16 vid);
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+			int reg_mcast, int unreg_mcast);
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
 
 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
 int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
@ 2013-01-30 19:07   ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: linux-arm-kernel

Add helper functions for VLAN ALE implementations for Add, Delete
Dump VLAN related ALE entries

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/net/ethernet/ti/cpsw.c     |    8 +--
 drivers/net/ethernet/ti/cpsw_ale.c |  106 ++++++++++++++++++++++++++++++++----
 drivers/net/ethernet/ti/cpsw_ale.h |   20 +++++--
 3 files changed, 112 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index b35e6a7..a40750e 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -345,7 +345,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 		/* program multicast address list into ALE register */
 		netdev_for_each_mc_addr(ha, ndev) {
 			cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr,
-				ALE_ALL_PORTS << priv->host_port, 0, 0);
+				ALE_ALL_PORTS << priv->host_port, 0, 0, 0);
 		}
 	}
 }
@@ -592,7 +592,7 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 	slave_port = cpsw_get_slave_port(priv, slave->slave_num);
 
 	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-			   1 << slave_port, 0, ALE_MCAST_FWD_2);
+			   1 << slave_port, 0, 0, ALE_MCAST_FWD_2);
 
 	slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
 				 &cpsw_adjust_link, slave->data->phy_if);
@@ -624,9 +624,9 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
 	cpsw_ale_control_set(priv->ale, priv->host_port,
 			     ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
 
-	cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0);
+	cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0, 0);
 	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-			   1 << priv->host_port, 0, ALE_MCAST_FWD_2);
+			   1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2);
 }
 
 static int cpsw_ndo_open(struct net_device *ndev)
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 0e9ccc2..18b88ce 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -148,7 +148,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry)
 	return idx;
 }
 
-static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
+int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS];
 	int type, idx;
@@ -160,6 +160,8 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
 		type = cpsw_ale_get_entry_type(ale_entry);
 		if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
 			continue;
+		if (cpsw_ale_get_vlan_id(ale_entry) != vid)
+			continue;
 		cpsw_ale_get_addr(ale_entry, entry_addr);
 		if (memcmp(entry_addr, addr, 6) == 0)
 			return idx;
@@ -167,6 +169,22 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
 	return -ENOENT;
 }
 
+int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS];
+	int type, idx;
+
+	for (idx = 0; idx < ale->params.ale_entries; idx++) {
+		cpsw_ale_read(ale, idx, ale_entry);
+		type = cpsw_ale_get_entry_type(ale_entry);
+		if (type != ALE_TYPE_VLAN)
+			continue;
+		if (cpsw_ale_get_vlan_id(ale_entry) == vid)
+			return idx;
+	}
+	return -ENOENT;
+}
+
 static int cpsw_ale_match_free(struct cpsw_ale *ale)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS];
@@ -274,19 +292,26 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
 	return 0;
 }
 
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	if (flags & ALE_VLAN) {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+		cpsw_ale_set_vlan_id(ale_entry, vid);
+	} else {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	}
+
 	cpsw_ale_set_addr(ale_entry, addr);
 	cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
 	cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
 	cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
 	cpsw_ale_set_port_num(ale_entry, port);
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		idx = cpsw_ale_match_free(ale);
 	if (idx < 0)
@@ -298,12 +323,13 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
 	return 0;
 }
 
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		return -ENOENT;
 
@@ -313,18 +339,24 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port)
 }
 
 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
-			int super, int mcast_state)
+		       int flags, u16 vid, int mcast_state)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx, mask;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx >= 0)
 		cpsw_ale_read(ale, idx, ale_entry);
 
-	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	if (flags & ALE_VLAN) {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+		cpsw_ale_set_vlan_id(ale_entry, vid);
+	} else {
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+	}
+
 	cpsw_ale_set_addr(ale_entry, addr);
-	cpsw_ale_set_super(ale_entry, super);
+	cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
 	cpsw_ale_set_mcast_state(ale_entry, mcast_state);
 
 	mask = cpsw_ale_get_port_mask(ale_entry);
@@ -342,12 +374,13 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
 	return 0;
 }
 
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+		       int flags, u16 vid)
 {
 	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
 	int idx;
 
-	idx = cpsw_ale_match_addr(ale, addr);
+	idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
 	if (idx < 0)
 		return -EINVAL;
 
@@ -362,6 +395,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
 	return 0;
 }
 
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+		      int reg_mcast, int unreg_mcast)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+	int idx;
+
+	idx = cpsw_ale_match_vlan(ale, vid);
+	if (idx >= 0)
+		cpsw_ale_read(ale, idx, ale_entry);
+
+	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
+	cpsw_ale_set_vlan_id(ale_entry, vid);
+
+	cpsw_ale_set_vlan_untag_force(ale_entry, untag);
+	cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast);
+	cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
+	cpsw_ale_set_vlan_member_list(ale_entry, port);
+
+	if (idx < 0)
+		idx = cpsw_ale_match_free(ale);
+	if (idx < 0)
+		idx = cpsw_ale_find_ageable(ale);
+	if (idx < 0)
+		return -ENOMEM;
+
+	cpsw_ale_write(ale, idx, ale_entry);
+	return 0;
+}
+
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
+{
+	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+	int idx;
+
+	idx = cpsw_ale_match_vlan(ale, vid);
+	if (idx < 0)
+		return -ENOENT;
+
+	cpsw_ale_read(ale, idx, ale_entry);
+
+	if (port_mask)
+		cpsw_ale_set_vlan_member_list(ale_entry, port_mask);
+	else
+		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+
+	cpsw_ale_write(ale, idx, ale_entry);
+	return 0;
+}
+
 struct ale_control_info {
 	const char	*name;
 	int		offset, port_offset;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index 2bd09cb..a002417 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -64,8 +64,10 @@ enum cpsw_ale_port_state {
 };
 
 /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
-#define ALE_SECURE			1
-#define ALE_BLOCKED			2
+#define ALE_SECURE			BIT(0)
+#define ALE_BLOCKED			BIT(1)
+#define ALE_SUPER			BIT(2)
+#define ALE_VLAN			BIT(3)
 
 #define ALE_MCAST_FWD			0
 #define ALE_MCAST_BLOCK_LEARN_FWD	1
@@ -81,11 +83,17 @@ void cpsw_ale_stop(struct cpsw_ale *ale);
 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
 int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask);
-int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags);
-int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port);
+int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid);
+int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
+		       int flags, u16 vid);
 int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
-			int super, int mcast_state);
-int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask);
+		       int flags, u16 vid, int mcast_state);
+int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
+		       int flags, u16 vid);
+int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
+			int reg_mcast, int unreg_mcast);
+int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
 
 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
 int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN
  2013-01-30 19:07 ` Mugunthan V N
  (?)
@ 2013-01-30 19:07   ` Mugunthan V N
  -1 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-arm-kernel, linux-omap, Mugunthan V N

adding support for VLAN interface for cpsw.

CPSW VLAN Capability
* Can filter VLAN packets in Hardware

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 Documentation/devicetree/bindings/net/cpsw.txt |    2 +
 drivers/net/ethernet/ti/cpsw.c                 |   92 +++++++++++++++++++++++-
 include/linux/platform_data/cpsw.h             |    1 +
 3 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 6ddd028..99696bf 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -24,6 +24,8 @@ Required properties:
 Optional properties:
 - ti,hwmods		: Must be "cpgmac0"
 - no_bd_ram		: Must be 0 or 1
+- default_vlan		: Specifies Default VLAN for non tagged packets
+			  ALE processing
 
 Note: "ti,hwmods" field is used to fetch the base address and irq
 resources from TI, omap hwmod data base during device registration.
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index a40750e..6c66f01 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -32,6 +32,7 @@
 #include <linux/of.h>
 #include <linux/of_net.h>
 #include <linux/of_device.h>
+#include <linux/if_vlan.h>
 
 #include <linux/platform_data/cpsw.h>
 
@@ -118,6 +119,9 @@ do {								\
 #define TX_PRIORITY_MAPPING	0x33221100
 #define CPDMA_TX_PRIORITY_MAP	0x76543210
 
+#define CPSW_VLAN_AWARE		BIT(1)
+#define CPSW_ALE_VLAN_AWARE	1
+
 #define cpsw_enable_irq(priv)	\
 	do {			\
 		u32 i;		\
@@ -607,14 +611,41 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 	}
 }
 
+static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
+{
+	writel(priv->data.default_vlan, &priv->host_port_regs->port_vlan);
+	if (priv->version == CPSW_VERSION_1) {
+		slave_write(&priv->slaves[0], priv->data.default_vlan,
+			    CPSW1_PORT_VLAN);
+		slave_write(&priv->slaves[1], priv->data.default_vlan,
+			    CPSW1_PORT_VLAN);
+	} else {
+		slave_write(&priv->slaves[0], priv->data.default_vlan,
+			    CPSW2_PORT_VLAN);
+		slave_write(&priv->slaves[1], priv->data.default_vlan,
+			    CPSW2_PORT_VLAN);
+	}
+	cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan,
+			ALE_ALL_PORTS << priv->host_port,
+			ALE_ALL_PORTS << priv->host_port,
+			ALE_ALL_PORTS << priv->host_port,
+			(BIT(1) | BIT(2)) << priv->host_port);
+}
+
 static void cpsw_init_host_port(struct cpsw_priv *priv)
 {
+	u32 control_reg;
+
 	/* soft reset the controller and initialize ale */
 	soft_reset("cpsw", &priv->regs->soft_reset);
 	cpsw_ale_start(priv->ale);
 
 	/* switch to vlan unaware mode */
-	cpsw_ale_control_set(priv->ale, 0, ALE_VLAN_AWARE, 0);
+	cpsw_ale_control_set(priv->ale, priv->host_port, ALE_VLAN_AWARE,
+			     CPSW_ALE_VLAN_AWARE);
+	control_reg = readl(&priv->regs->control);
+	control_reg |= CPSW_VLAN_AWARE;
+	writel(control_reg, &priv->regs->control);
 
 	/* setup host port priority mapping */
 	__raw_writel(CPDMA_TX_PRIORITY_MAP,
@@ -650,6 +681,9 @@ static int cpsw_ndo_open(struct net_device *ndev)
 	cpsw_init_host_port(priv);
 	for_each_slave(priv, cpsw_slave_open, priv);
 
+	/* Add default VLAN */
+	cpsw_add_default_vlan(priv);
+
 	/* setup tx dma to fixed prio and zero offset */
 	cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
 	cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
@@ -933,6 +967,55 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
 }
 #endif
 
+static inline void cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
+				unsigned short vid)
+{
+	cpsw_ale_add_vlan(priv->ale, vid, ALE_ALL_PORTS << priv->host_port,
+			0, ALE_ALL_PORTS << priv->host_port,
+			(BIT(1) | BIT(2)) << priv->host_port);
+	cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
+			priv->host_port, ALE_VLAN, vid);
+	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+			ALE_ALL_PORTS << priv->host_port, ALE_VLAN, vid, 0);
+}
+
+static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
+		unsigned short vid)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+
+	if (vid == priv->data.default_vlan)
+		return 0;
+
+	spin_lock(&priv->lock);
+
+	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
+	cpsw_add_vlan_ale_entry(priv, vid);
+
+	spin_unlock(&priv->lock);
+	return 0;
+}
+
+static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
+		unsigned short vid)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+
+	if (vid == priv->data.default_vlan)
+		return 0;
+
+	spin_lock(&priv->lock);
+
+	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
+	cpsw_ale_del_vlan(priv->ale, vid, 0);
+	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
+			   priv->host_port, ALE_VLAN, vid);
+	cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid);
+
+	spin_unlock(&priv->lock);
+	return 0;
+}
+
 static const struct net_device_ops cpsw_netdev_ops = {
 	.ndo_open		= cpsw_ndo_open,
 	.ndo_stop		= cpsw_ndo_stop,
@@ -947,6 +1030,8 @@ static const struct net_device_ops cpsw_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= cpsw_ndo_poll_controller,
 #endif
+	.ndo_vlan_rx_add_vid	= cpsw_ndo_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= cpsw_ndo_vlan_rx_kill_vid,
 };
 
 static void cpsw_get_drvinfo(struct net_device *ndev,
@@ -1103,6 +1188,9 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 	}
 	data->mac_control = prop;
 
+	if (!of_property_read_u32(node, "default_vlan", &prop))
+		data->default_vlan = prop;
+
 	/*
 	 * Populate all the child nodes here...
 	 */
@@ -1356,7 +1444,7 @@ static int cpsw_probe(struct platform_device *pdev)
 		k++;
 	}
 
-	ndev->flags |= IFF_ALLMULTI;	/* see cpsw_ndo_change_rx_flags() */
+	ndev->features |= NETIF_F_HW_VLAN_FILTER;
 
 	ndev->netdev_ops = &cpsw_netdev_ops;
 	SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h
index 24368a2..e962cfd 100644
--- a/include/linux/platform_data/cpsw.h
+++ b/include/linux/platform_data/cpsw.h
@@ -35,6 +35,7 @@ struct cpsw_platform_data {
 	u32	bd_ram_size;  /*buffer descriptor ram size */
 	u32	rx_descs;	/* Number of Rx Descriptios */
 	u32	mac_control;	/* Mac control register */
+	u16	default_vlan;	/* Def VLAN for ALE lookup in VLAN aware mode*/
 };
 
 #endif /* __CPSW_H__ */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN
@ 2013-01-30 19:07   ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: netdev; +Cc: davem, linux-arm-kernel, linux-omap, Mugunthan V N

adding support for VLAN interface for cpsw.

CPSW VLAN Capability
* Can filter VLAN packets in Hardware

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 Documentation/devicetree/bindings/net/cpsw.txt |    2 +
 drivers/net/ethernet/ti/cpsw.c                 |   92 +++++++++++++++++++++++-
 include/linux/platform_data/cpsw.h             |    1 +
 3 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 6ddd028..99696bf 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -24,6 +24,8 @@ Required properties:
 Optional properties:
 - ti,hwmods		: Must be "cpgmac0"
 - no_bd_ram		: Must be 0 or 1
+- default_vlan		: Specifies Default VLAN for non tagged packets
+			  ALE processing
 
 Note: "ti,hwmods" field is used to fetch the base address and irq
 resources from TI, omap hwmod data base during device registration.
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index a40750e..6c66f01 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -32,6 +32,7 @@
 #include <linux/of.h>
 #include <linux/of_net.h>
 #include <linux/of_device.h>
+#include <linux/if_vlan.h>
 
 #include <linux/platform_data/cpsw.h>
 
@@ -118,6 +119,9 @@ do {								\
 #define TX_PRIORITY_MAPPING	0x33221100
 #define CPDMA_TX_PRIORITY_MAP	0x76543210
 
+#define CPSW_VLAN_AWARE		BIT(1)
+#define CPSW_ALE_VLAN_AWARE	1
+
 #define cpsw_enable_irq(priv)	\
 	do {			\
 		u32 i;		\
@@ -607,14 +611,41 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 	}
 }
 
+static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
+{
+	writel(priv->data.default_vlan, &priv->host_port_regs->port_vlan);
+	if (priv->version == CPSW_VERSION_1) {
+		slave_write(&priv->slaves[0], priv->data.default_vlan,
+			    CPSW1_PORT_VLAN);
+		slave_write(&priv->slaves[1], priv->data.default_vlan,
+			    CPSW1_PORT_VLAN);
+	} else {
+		slave_write(&priv->slaves[0], priv->data.default_vlan,
+			    CPSW2_PORT_VLAN);
+		slave_write(&priv->slaves[1], priv->data.default_vlan,
+			    CPSW2_PORT_VLAN);
+	}
+	cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan,
+			ALE_ALL_PORTS << priv->host_port,
+			ALE_ALL_PORTS << priv->host_port,
+			ALE_ALL_PORTS << priv->host_port,
+			(BIT(1) | BIT(2)) << priv->host_port);
+}
+
 static void cpsw_init_host_port(struct cpsw_priv *priv)
 {
+	u32 control_reg;
+
 	/* soft reset the controller and initialize ale */
 	soft_reset("cpsw", &priv->regs->soft_reset);
 	cpsw_ale_start(priv->ale);
 
 	/* switch to vlan unaware mode */
-	cpsw_ale_control_set(priv->ale, 0, ALE_VLAN_AWARE, 0);
+	cpsw_ale_control_set(priv->ale, priv->host_port, ALE_VLAN_AWARE,
+			     CPSW_ALE_VLAN_AWARE);
+	control_reg = readl(&priv->regs->control);
+	control_reg |= CPSW_VLAN_AWARE;
+	writel(control_reg, &priv->regs->control);
 
 	/* setup host port priority mapping */
 	__raw_writel(CPDMA_TX_PRIORITY_MAP,
@@ -650,6 +681,9 @@ static int cpsw_ndo_open(struct net_device *ndev)
 	cpsw_init_host_port(priv);
 	for_each_slave(priv, cpsw_slave_open, priv);
 
+	/* Add default VLAN */
+	cpsw_add_default_vlan(priv);
+
 	/* setup tx dma to fixed prio and zero offset */
 	cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
 	cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
@@ -933,6 +967,55 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
 }
 #endif
 
+static inline void cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
+				unsigned short vid)
+{
+	cpsw_ale_add_vlan(priv->ale, vid, ALE_ALL_PORTS << priv->host_port,
+			0, ALE_ALL_PORTS << priv->host_port,
+			(BIT(1) | BIT(2)) << priv->host_port);
+	cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
+			priv->host_port, ALE_VLAN, vid);
+	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+			ALE_ALL_PORTS << priv->host_port, ALE_VLAN, vid, 0);
+}
+
+static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
+		unsigned short vid)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+
+	if (vid == priv->data.default_vlan)
+		return 0;
+
+	spin_lock(&priv->lock);
+
+	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
+	cpsw_add_vlan_ale_entry(priv, vid);
+
+	spin_unlock(&priv->lock);
+	return 0;
+}
+
+static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
+		unsigned short vid)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+
+	if (vid == priv->data.default_vlan)
+		return 0;
+
+	spin_lock(&priv->lock);
+
+	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
+	cpsw_ale_del_vlan(priv->ale, vid, 0);
+	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
+			   priv->host_port, ALE_VLAN, vid);
+	cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid);
+
+	spin_unlock(&priv->lock);
+	return 0;
+}
+
 static const struct net_device_ops cpsw_netdev_ops = {
 	.ndo_open		= cpsw_ndo_open,
 	.ndo_stop		= cpsw_ndo_stop,
@@ -947,6 +1030,8 @@ static const struct net_device_ops cpsw_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= cpsw_ndo_poll_controller,
 #endif
+	.ndo_vlan_rx_add_vid	= cpsw_ndo_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= cpsw_ndo_vlan_rx_kill_vid,
 };
 
 static void cpsw_get_drvinfo(struct net_device *ndev,
@@ -1103,6 +1188,9 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 	}
 	data->mac_control = prop;
 
+	if (!of_property_read_u32(node, "default_vlan", &prop))
+		data->default_vlan = prop;
+
 	/*
 	 * Populate all the child nodes here...
 	 */
@@ -1356,7 +1444,7 @@ static int cpsw_probe(struct platform_device *pdev)
 		k++;
 	}
 
-	ndev->flags |= IFF_ALLMULTI;	/* see cpsw_ndo_change_rx_flags() */
+	ndev->features |= NETIF_F_HW_VLAN_FILTER;
 
 	ndev->netdev_ops = &cpsw_netdev_ops;
 	SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h
index 24368a2..e962cfd 100644
--- a/include/linux/platform_data/cpsw.h
+++ b/include/linux/platform_data/cpsw.h
@@ -35,6 +35,7 @@ struct cpsw_platform_data {
 	u32	bd_ram_size;  /*buffer descriptor ram size */
 	u32	rx_descs;	/* Number of Rx Descriptios */
 	u32	mac_control;	/* Mac control register */
+	u16	default_vlan;	/* Def VLAN for ALE lookup in VLAN aware mode*/
 };
 
 #endif /* __CPSW_H__ */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN
@ 2013-01-30 19:07   ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-30 19:07 UTC (permalink / raw)
  To: linux-arm-kernel

adding support for VLAN interface for cpsw.

CPSW VLAN Capability
* Can filter VLAN packets in Hardware

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 Documentation/devicetree/bindings/net/cpsw.txt |    2 +
 drivers/net/ethernet/ti/cpsw.c                 |   92 +++++++++++++++++++++++-
 include/linux/platform_data/cpsw.h             |    1 +
 3 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 6ddd028..99696bf 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -24,6 +24,8 @@ Required properties:
 Optional properties:
 - ti,hwmods		: Must be "cpgmac0"
 - no_bd_ram		: Must be 0 or 1
+- default_vlan		: Specifies Default VLAN for non tagged packets
+			  ALE processing
 
 Note: "ti,hwmods" field is used to fetch the base address and irq
 resources from TI, omap hwmod data base during device registration.
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index a40750e..6c66f01 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -32,6 +32,7 @@
 #include <linux/of.h>
 #include <linux/of_net.h>
 #include <linux/of_device.h>
+#include <linux/if_vlan.h>
 
 #include <linux/platform_data/cpsw.h>
 
@@ -118,6 +119,9 @@ do {								\
 #define TX_PRIORITY_MAPPING	0x33221100
 #define CPDMA_TX_PRIORITY_MAP	0x76543210
 
+#define CPSW_VLAN_AWARE		BIT(1)
+#define CPSW_ALE_VLAN_AWARE	1
+
 #define cpsw_enable_irq(priv)	\
 	do {			\
 		u32 i;		\
@@ -607,14 +611,41 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
 	}
 }
 
+static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
+{
+	writel(priv->data.default_vlan, &priv->host_port_regs->port_vlan);
+	if (priv->version == CPSW_VERSION_1) {
+		slave_write(&priv->slaves[0], priv->data.default_vlan,
+			    CPSW1_PORT_VLAN);
+		slave_write(&priv->slaves[1], priv->data.default_vlan,
+			    CPSW1_PORT_VLAN);
+	} else {
+		slave_write(&priv->slaves[0], priv->data.default_vlan,
+			    CPSW2_PORT_VLAN);
+		slave_write(&priv->slaves[1], priv->data.default_vlan,
+			    CPSW2_PORT_VLAN);
+	}
+	cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan,
+			ALE_ALL_PORTS << priv->host_port,
+			ALE_ALL_PORTS << priv->host_port,
+			ALE_ALL_PORTS << priv->host_port,
+			(BIT(1) | BIT(2)) << priv->host_port);
+}
+
 static void cpsw_init_host_port(struct cpsw_priv *priv)
 {
+	u32 control_reg;
+
 	/* soft reset the controller and initialize ale */
 	soft_reset("cpsw", &priv->regs->soft_reset);
 	cpsw_ale_start(priv->ale);
 
 	/* switch to vlan unaware mode */
-	cpsw_ale_control_set(priv->ale, 0, ALE_VLAN_AWARE, 0);
+	cpsw_ale_control_set(priv->ale, priv->host_port, ALE_VLAN_AWARE,
+			     CPSW_ALE_VLAN_AWARE);
+	control_reg = readl(&priv->regs->control);
+	control_reg |= CPSW_VLAN_AWARE;
+	writel(control_reg, &priv->regs->control);
 
 	/* setup host port priority mapping */
 	__raw_writel(CPDMA_TX_PRIORITY_MAP,
@@ -650,6 +681,9 @@ static int cpsw_ndo_open(struct net_device *ndev)
 	cpsw_init_host_port(priv);
 	for_each_slave(priv, cpsw_slave_open, priv);
 
+	/* Add default VLAN */
+	cpsw_add_default_vlan(priv);
+
 	/* setup tx dma to fixed prio and zero offset */
 	cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1);
 	cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0);
@@ -933,6 +967,55 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
 }
 #endif
 
+static inline void cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
+				unsigned short vid)
+{
+	cpsw_ale_add_vlan(priv->ale, vid, ALE_ALL_PORTS << priv->host_port,
+			0, ALE_ALL_PORTS << priv->host_port,
+			(BIT(1) | BIT(2)) << priv->host_port);
+	cpsw_ale_add_ucast(priv->ale, priv->mac_addr,
+			priv->host_port, ALE_VLAN, vid);
+	cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
+			ALE_ALL_PORTS << priv->host_port, ALE_VLAN, vid, 0);
+}
+
+static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
+		unsigned short vid)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+
+	if (vid == priv->data.default_vlan)
+		return 0;
+
+	spin_lock(&priv->lock);
+
+	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
+	cpsw_add_vlan_ale_entry(priv, vid);
+
+	spin_unlock(&priv->lock);
+	return 0;
+}
+
+static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
+		unsigned short vid)
+{
+	struct cpsw_priv *priv = netdev_priv(ndev);
+
+	if (vid == priv->data.default_vlan)
+		return 0;
+
+	spin_lock(&priv->lock);
+
+	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
+	cpsw_ale_del_vlan(priv->ale, vid, 0);
+	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
+			   priv->host_port, ALE_VLAN, vid);
+	cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid);
+
+	spin_unlock(&priv->lock);
+	return 0;
+}
+
 static const struct net_device_ops cpsw_netdev_ops = {
 	.ndo_open		= cpsw_ndo_open,
 	.ndo_stop		= cpsw_ndo_stop,
@@ -947,6 +1030,8 @@ static const struct net_device_ops cpsw_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= cpsw_ndo_poll_controller,
 #endif
+	.ndo_vlan_rx_add_vid	= cpsw_ndo_vlan_rx_add_vid,
+	.ndo_vlan_rx_kill_vid	= cpsw_ndo_vlan_rx_kill_vid,
 };
 
 static void cpsw_get_drvinfo(struct net_device *ndev,
@@ -1103,6 +1188,9 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
 	}
 	data->mac_control = prop;
 
+	if (!of_property_read_u32(node, "default_vlan", &prop))
+		data->default_vlan = prop;
+
 	/*
 	 * Populate all the child nodes here...
 	 */
@@ -1356,7 +1444,7 @@ static int cpsw_probe(struct platform_device *pdev)
 		k++;
 	}
 
-	ndev->flags |= IFF_ALLMULTI;	/* see cpsw_ndo_change_rx_flags() */
+	ndev->features |= NETIF_F_HW_VLAN_FILTER;
 
 	ndev->netdev_ops = &cpsw_netdev_ops;
 	SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h
index 24368a2..e962cfd 100644
--- a/include/linux/platform_data/cpsw.h
+++ b/include/linux/platform_data/cpsw.h
@@ -35,6 +35,7 @@ struct cpsw_platform_data {
 	u32	bd_ram_size;  /*buffer descriptor ram size */
 	u32	rx_descs;	/* Number of Rx Descriptios */
 	u32	mac_control;	/* Mac control register */
+	u16	default_vlan;	/* Def VLAN for ALE lookup in VLAN aware mode*/
 };
 
 #endif /* __CPSW_H__ */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
  2013-01-30 19:07   ` Mugunthan V N
@ 2013-01-30 22:02     ` Francois Romieu
  -1 siblings, 0 replies; 21+ messages in thread
From: Francois Romieu @ 2013-01-30 22:02 UTC (permalink / raw)
  To: Mugunthan V N; +Cc: netdev, davem, linux-arm-kernel, linux-omap

Mugunthan V N <mugunthanvnm@ti.com> :
[...]
> diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
> index 0e9ccc2..18b88ce 100644
> --- a/drivers/net/ethernet/ti/cpsw_ale.c
> +++ b/drivers/net/ethernet/ti/cpsw_ale.c
[...]
> @@ -274,19 +292,26 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
>  	return 0;
>  }
>  
> -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
> +int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
> +		       int flags, u16 vid)
>  {
>  	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
>  	int idx;
>  
> -	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
> +	if (flags & ALE_VLAN) {
> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
> +		cpsw_ale_set_vlan_id(ale_entry, vid);
> +	} else {
> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
> +	}
> +
[...]
> +	if (flags & ALE_VLAN) {
> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
> +		cpsw_ale_set_vlan_id(ale_entry, vid);
> +	} else {
> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
> +	}
> +

It could be fctored out.

[...]
> @@ -362,6 +395,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
>  	return 0;
>  }
>  
> +int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
> +		      int reg_mcast, int unreg_mcast)
> +{
[...]
> +int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
[...]

Patch #2 doesn't use the returned status code.

-- 
Ueimor

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
@ 2013-01-30 22:02     ` Francois Romieu
  0 siblings, 0 replies; 21+ messages in thread
From: Francois Romieu @ 2013-01-30 22:02 UTC (permalink / raw)
  To: linux-arm-kernel

Mugunthan V N <mugunthanvnm@ti.com> :
[...]
> diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
> index 0e9ccc2..18b88ce 100644
> --- a/drivers/net/ethernet/ti/cpsw_ale.c
> +++ b/drivers/net/ethernet/ti/cpsw_ale.c
[...]
> @@ -274,19 +292,26 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
>  	return 0;
>  }
>  
> -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
> +int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
> +		       int flags, u16 vid)
>  {
>  	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
>  	int idx;
>  
> -	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
> +	if (flags & ALE_VLAN) {
> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
> +		cpsw_ale_set_vlan_id(ale_entry, vid);
> +	} else {
> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
> +	}
> +
[...]
> +	if (flags & ALE_VLAN) {
> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
> +		cpsw_ale_set_vlan_id(ale_entry, vid);
> +	} else {
> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
> +	}
> +

It could be fctored out.

[...]
> @@ -362,6 +395,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
>  	return 0;
>  }
>  
> +int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
> +		      int reg_mcast, int unreg_mcast)
> +{
[...]
> +int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
[...]

Patch #2 doesn't use the returned status code.

-- 
Ueimor

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN
  2013-01-30 19:07   ` Mugunthan V N
@ 2013-01-30 22:02     ` Francois Romieu
  -1 siblings, 0 replies; 21+ messages in thread
From: Francois Romieu @ 2013-01-30 22:02 UTC (permalink / raw)
  To: Mugunthan V N; +Cc: netdev, davem, linux-arm-kernel, linux-omap

Mugunthan V N <mugunthanvnm@ti.com> :
[...]
> diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
> index 6ddd028..99696bf 100644
> --- a/Documentation/devicetree/bindings/net/cpsw.txt
> +++ b/Documentation/devicetree/bindings/net/cpsw.txt
> @@ -24,6 +24,8 @@ Required properties:
>  Optional properties:
>  - ti,hwmods		: Must be "cpgmac0"
>  - no_bd_ram		: Must be 0 or 1
> +- default_vlan		: Specifies Default VLAN for non tagged packets
> +			  ALE processing

Isn't it a device-tree hack for what should belong to a common API ?

[...]
> diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
> index a40750e..6c66f01 100644
> --- a/drivers/net/ethernet/ti/cpsw.c
> +++ b/drivers/net/ethernet/ti/cpsw.c
[...]
> @@ -607,14 +611,41 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
>  	}
>  }
>  
> +static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
> +{
> +	writel(priv->data.default_vlan, &priv->host_port_regs->port_vlan);
> +	if (priv->version == CPSW_VERSION_1) {
> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
> +			    CPSW1_PORT_VLAN);
> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
> +			    CPSW1_PORT_VLAN);
> +	} else {
> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
> +			    CPSW2_PORT_VLAN);
> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
> +			    CPSW2_PORT_VLAN);
> +	}
> +	cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan,
> +			ALE_ALL_PORTS << priv->host_port,
> +			ALE_ALL_PORTS << priv->host_port,
> +			ALE_ALL_PORTS << priv->host_port,
> +			(BIT(1) | BIT(2)) << priv->host_port);
> +}

static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
{
	const int vlan = priv->data.default_vlan;
	const int port = priv->host_port;
	u32 reg;
	int i;

	reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
	      CPSW2_PORT_VLAN;

	writel(vlan, &priv->host_port_regs->port_vlan);

	for (int i = 0; i < 2; i++)
		slave_write(priv->slaves + i, vlan, reg);

	cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
			  ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
			  (BIT(1) | BIT(2)) << port);
}

... or somewhere between both. Your call.

[...]
> @@ -933,6 +967,55 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
>  }
>  #endif
>  
> +static inline void cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
> +				unsigned short vid)
> +{
> +	cpsw_ale_add_vlan(priv->ale, vid, ALE_ALL_PORTS << priv->host_port,
> +			0, ALE_ALL_PORTS << priv->host_port,
> +			(BIT(1) | BIT(2)) << priv->host_port);

"(BIT(1) | BIT(2))" is repeated a couple of times.

[...]
> +static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
> +		unsigned short vid)
> +{
> +	struct cpsw_priv *priv = netdev_priv(ndev);
> +
> +	if (vid == priv->data.default_vlan)
> +		return 0;
> +
> +	spin_lock(&priv->lock);
> +
> +	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
> +	cpsw_add_vlan_ale_entry(priv, vid);
> +
> +	spin_unlock(&priv->lock);
> +	return 0;
> +}
> +
> +static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
> +		unsigned short vid)
> +{
> +	struct cpsw_priv *priv = netdev_priv(ndev);
> +
> +	if (vid == priv->data.default_vlan)
> +		return 0;
> +
> +	spin_lock(&priv->lock);
> +
> +	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
> +	cpsw_ale_del_vlan(priv->ale, vid, 0);
> +	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
> +			   priv->host_port, ALE_VLAN, vid);
> +	cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid);
> +
> +	spin_unlock(&priv->lock);

What are you trying to achieve with the lock ?

It is not used anywhere else and both cpsw_ndo_vlan_rx_{add, kill}_vid are
called under RTNL.

-- 
Ueimor

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN
@ 2013-01-30 22:02     ` Francois Romieu
  0 siblings, 0 replies; 21+ messages in thread
From: Francois Romieu @ 2013-01-30 22:02 UTC (permalink / raw)
  To: linux-arm-kernel

Mugunthan V N <mugunthanvnm@ti.com> :
[...]
> diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
> index 6ddd028..99696bf 100644
> --- a/Documentation/devicetree/bindings/net/cpsw.txt
> +++ b/Documentation/devicetree/bindings/net/cpsw.txt
> @@ -24,6 +24,8 @@ Required properties:
>  Optional properties:
>  - ti,hwmods		: Must be "cpgmac0"
>  - no_bd_ram		: Must be 0 or 1
> +- default_vlan		: Specifies Default VLAN for non tagged packets
> +			  ALE processing

Isn't it a device-tree hack for what should belong to a common API ?

[...]
> diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
> index a40750e..6c66f01 100644
> --- a/drivers/net/ethernet/ti/cpsw.c
> +++ b/drivers/net/ethernet/ti/cpsw.c
[...]
> @@ -607,14 +611,41 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
>  	}
>  }
>  
> +static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
> +{
> +	writel(priv->data.default_vlan, &priv->host_port_regs->port_vlan);
> +	if (priv->version == CPSW_VERSION_1) {
> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
> +			    CPSW1_PORT_VLAN);
> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
> +			    CPSW1_PORT_VLAN);
> +	} else {
> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
> +			    CPSW2_PORT_VLAN);
> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
> +			    CPSW2_PORT_VLAN);
> +	}
> +	cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan,
> +			ALE_ALL_PORTS << priv->host_port,
> +			ALE_ALL_PORTS << priv->host_port,
> +			ALE_ALL_PORTS << priv->host_port,
> +			(BIT(1) | BIT(2)) << priv->host_port);
> +}

static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
{
	const int vlan = priv->data.default_vlan;
	const int port = priv->host_port;
	u32 reg;
	int i;

	reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
	      CPSW2_PORT_VLAN;

	writel(vlan, &priv->host_port_regs->port_vlan);

	for (int i = 0; i < 2; i++)
		slave_write(priv->slaves + i, vlan, reg);

	cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
			  ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
			  (BIT(1) | BIT(2)) << port);
}

... or somewhere between both. Your call.

[...]
> @@ -933,6 +967,55 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
>  }
>  #endif
>  
> +static inline void cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
> +				unsigned short vid)
> +{
> +	cpsw_ale_add_vlan(priv->ale, vid, ALE_ALL_PORTS << priv->host_port,
> +			0, ALE_ALL_PORTS << priv->host_port,
> +			(BIT(1) | BIT(2)) << priv->host_port);

"(BIT(1) | BIT(2))" is repeated a couple of times.

[...]
> +static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
> +		unsigned short vid)
> +{
> +	struct cpsw_priv *priv = netdev_priv(ndev);
> +
> +	if (vid == priv->data.default_vlan)
> +		return 0;
> +
> +	spin_lock(&priv->lock);
> +
> +	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
> +	cpsw_add_vlan_ale_entry(priv, vid);
> +
> +	spin_unlock(&priv->lock);
> +	return 0;
> +}
> +
> +static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
> +		unsigned short vid)
> +{
> +	struct cpsw_priv *priv = netdev_priv(ndev);
> +
> +	if (vid == priv->data.default_vlan)
> +		return 0;
> +
> +	spin_lock(&priv->lock);
> +
> +	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
> +	cpsw_ale_del_vlan(priv->ale, vid, 0);
> +	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
> +			   priv->host_port, ALE_VLAN, vid);
> +	cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid);
> +
> +	spin_unlock(&priv->lock);

What are you trying to achieve with the lock ?

It is not used anywhere else and both cpsw_ndo_vlan_rx_{add, kill}_vid are
called under RTNL.

-- 
Ueimor

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
  2013-01-30 22:02     ` Francois Romieu
  (?)
@ 2013-01-31 11:09       ` Mugunthan V N
  -1 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-31 11:09 UTC (permalink / raw)
  To: Francois Romieu; +Cc: netdev, davem, linux-arm-kernel, linux-omap

On 1/31/2013 3:32 AM, Francois Romieu wrote:
> Mugunthan V N <mugunthanvnm@ti.com> :
> [...]
>> diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
>> index 0e9ccc2..18b88ce 100644
>> --- a/drivers/net/ethernet/ti/cpsw_ale.c
>> +++ b/drivers/net/ethernet/ti/cpsw_ale.c
> [...]
>> @@ -274,19 +292,26 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
>>   	return 0;
>>   }
>>   
>> -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
>> +int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
>> +		       int flags, u16 vid)
>>   {
>>   	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
>>   	int idx;
>>   
>> -	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	if (flags & ALE_VLAN) {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
>> +		cpsw_ale_set_vlan_id(ale_entry, vid);
>> +	} else {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	}
>> +
> [...]
>> +	if (flags & ALE_VLAN) {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
>> +		cpsw_ale_set_vlan_id(ale_entry, vid);
>> +	} else {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	}
>> +
> It could be fctored out.
Are you mentioning to have static inline function for the above two 
statements above?
>
> [...]
>> @@ -362,6 +395,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
>>   	return 0;
>>   }
>>   
>> +int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
>> +		      int reg_mcast, int unreg_mcast)
>> +{
> [...]
>> +int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
> [...]
>
> Patch #2 doesn't use the returned status code.
Will modify the prototype to return void

Regards
Mugunthan V N

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
@ 2013-01-31 11:09       ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-31 11:09 UTC (permalink / raw)
  To: Francois Romieu; +Cc: netdev, davem, linux-arm-kernel, linux-omap

On 1/31/2013 3:32 AM, Francois Romieu wrote:
> Mugunthan V N <mugunthanvnm@ti.com> :
> [...]
>> diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
>> index 0e9ccc2..18b88ce 100644
>> --- a/drivers/net/ethernet/ti/cpsw_ale.c
>> +++ b/drivers/net/ethernet/ti/cpsw_ale.c
> [...]
>> @@ -274,19 +292,26 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
>>   	return 0;
>>   }
>>   
>> -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
>> +int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
>> +		       int flags, u16 vid)
>>   {
>>   	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
>>   	int idx;
>>   
>> -	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	if (flags & ALE_VLAN) {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
>> +		cpsw_ale_set_vlan_id(ale_entry, vid);
>> +	} else {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	}
>> +
> [...]
>> +	if (flags & ALE_VLAN) {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
>> +		cpsw_ale_set_vlan_id(ale_entry, vid);
>> +	} else {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	}
>> +
> It could be fctored out.
Are you mentioning to have static inline function for the above two 
statements above?
>
> [...]
>> @@ -362,6 +395,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
>>   	return 0;
>>   }
>>   
>> +int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
>> +		      int reg_mcast, int unreg_mcast)
>> +{
> [...]
>> +int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
> [...]
>
> Patch #2 doesn't use the returned status code.
Will modify the prototype to return void

Regards
Mugunthan V N

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
@ 2013-01-31 11:09       ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-31 11:09 UTC (permalink / raw)
  To: linux-arm-kernel

On 1/31/2013 3:32 AM, Francois Romieu wrote:
> Mugunthan V N <mugunthanvnm@ti.com> :
> [...]
>> diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
>> index 0e9ccc2..18b88ce 100644
>> --- a/drivers/net/ethernet/ti/cpsw_ale.c
>> +++ b/drivers/net/ethernet/ti/cpsw_ale.c
> [...]
>> @@ -274,19 +292,26 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
>>   	return 0;
>>   }
>>   
>> -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
>> +int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
>> +		       int flags, u16 vid)
>>   {
>>   	u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
>>   	int idx;
>>   
>> -	cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	if (flags & ALE_VLAN) {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
>> +		cpsw_ale_set_vlan_id(ale_entry, vid);
>> +	} else {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	}
>> +
> [...]
>> +	if (flags & ALE_VLAN) {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
>> +		cpsw_ale_set_vlan_id(ale_entry, vid);
>> +	} else {
>> +		cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
>> +	}
>> +
> It could be fctored out.
Are you mentioning to have static inline function for the above two 
statements above?
>
> [...]
>> @@ -362,6 +395,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
>>   	return 0;
>>   }
>>   
>> +int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
>> +		      int reg_mcast, int unreg_mcast)
>> +{
> [...]
>> +int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
> [...]
>
> Patch #2 doesn't use the returned status code.
Will modify the prototype to return void

Regards
Mugunthan V N

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN
  2013-01-30 22:02     ` Francois Romieu
  (?)
@ 2013-01-31 11:09       ` Mugunthan V N
  -1 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-31 11:09 UTC (permalink / raw)
  To: Francois Romieu; +Cc: netdev, davem, linux-arm-kernel, linux-omap

On 1/31/2013 3:32 AM, Francois Romieu wrote:
> Mugunthan V N <mugunthanvnm@ti.com> :
> [...]
>> diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
>> index 6ddd028..99696bf 100644
>> --- a/Documentation/devicetree/bindings/net/cpsw.txt
>> +++ b/Documentation/devicetree/bindings/net/cpsw.txt
>> @@ -24,6 +24,8 @@ Required properties:
>>   Optional properties:
>>   - ti,hwmods		: Must be "cpgmac0"
>>   - no_bd_ram		: Must be 0 or 1
>> +- default_vlan		: Specifies Default VLAN for non tagged packets
>> +			  ALE processing
> Isn't it a device-tree hack for what should belong to a common API ?
Its a hardware feature which stack will not be aware of. It is used in 
the ALE filtering
process with a non-tagged packet arrives.
>
> [...]
>> diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
>> index a40750e..6c66f01 100644
>> --- a/drivers/net/ethernet/ti/cpsw.c
>> +++ b/drivers/net/ethernet/ti/cpsw.c
> [...]
>> @@ -607,14 +611,41 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
>>   	}
>>   }
>>   
>> +static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
>> +{
>> +	writel(priv->data.default_vlan, &priv->host_port_regs->port_vlan);
>> +	if (priv->version == CPSW_VERSION_1) {
>> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
>> +			    CPSW1_PORT_VLAN);
>> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
>> +			    CPSW1_PORT_VLAN);
>> +	} else {
>> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
>> +			    CPSW2_PORT_VLAN);
>> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
>> +			    CPSW2_PORT_VLAN);
>> +	}
>> +	cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			(BIT(1) | BIT(2)) << priv->host_port);
>> +}
> static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
> {
> 	const int vlan = priv->data.default_vlan;
> 	const int port = priv->host_port;
> 	u32 reg;
> 	int i;
>
> 	reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
> 	      CPSW2_PORT_VLAN;
>
> 	writel(vlan, &priv->host_port_regs->port_vlan);
>
> 	for (int i = 0; i < 2; i++)
> 		slave_write(priv->slaves + i, vlan, reg);
>
> 	cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
> 			  ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
> 			  (BIT(1) | BIT(2)) << port);
> }
>
> ... or somewhere between both. Your call.
Will modify the code as this looks simpler
>
> [...]
>> @@ -933,6 +967,55 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
>>   }
>>   #endif
>>   
>> +static inline void cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
>> +				unsigned short vid)
>> +{
>> +	cpsw_ale_add_vlan(priv->ale, vid, ALE_ALL_PORTS << priv->host_port,
>> +			0, ALE_ALL_PORTS << priv->host_port,
>> +			(BIT(1) | BIT(2)) << priv->host_port);
> "(BIT(1) | BIT(2))" is repeated a couple of times.
Will replace with port number defines.
>
> [...]
>> +static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
>> +		unsigned short vid)
>> +{
>> +	struct cpsw_priv *priv = netdev_priv(ndev);
>> +
>> +	if (vid == priv->data.default_vlan)
>> +		return 0;
>> +
>> +	spin_lock(&priv->lock);
>> +
>> +	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
>> +	cpsw_add_vlan_ale_entry(priv, vid);
>> +
>> +	spin_unlock(&priv->lock);
>> +	return 0;
>> +}
>> +
>> +static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
>> +		unsigned short vid)
>> +{
>> +	struct cpsw_priv *priv = netdev_priv(ndev);
>> +
>> +	if (vid == priv->data.default_vlan)
>> +		return 0;
>> +
>> +	spin_lock(&priv->lock);
>> +
>> +	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
>> +	cpsw_ale_del_vlan(priv->ale, vid, 0);
>> +	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
>> +			   priv->host_port, ALE_VLAN, vid);
>> +	cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid);
>> +
>> +	spin_unlock(&priv->lock);
> What are you trying to achieve with the lock ?
>
> It is not used anywhere else and both cpsw_ndo_vlan_rx_{add, kill}_vid are
> called under RTNL.
Will remove the lock from both apis

Regards
Mugunthan V N

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN
@ 2013-01-31 11:09       ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-31 11:09 UTC (permalink / raw)
  To: Francois Romieu; +Cc: netdev, davem, linux-arm-kernel, linux-omap

On 1/31/2013 3:32 AM, Francois Romieu wrote:
> Mugunthan V N <mugunthanvnm@ti.com> :
> [...]
>> diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
>> index 6ddd028..99696bf 100644
>> --- a/Documentation/devicetree/bindings/net/cpsw.txt
>> +++ b/Documentation/devicetree/bindings/net/cpsw.txt
>> @@ -24,6 +24,8 @@ Required properties:
>>   Optional properties:
>>   - ti,hwmods		: Must be "cpgmac0"
>>   - no_bd_ram		: Must be 0 or 1
>> +- default_vlan		: Specifies Default VLAN for non tagged packets
>> +			  ALE processing
> Isn't it a device-tree hack for what should belong to a common API ?
Its a hardware feature which stack will not be aware of. It is used in 
the ALE filtering
process with a non-tagged packet arrives.
>
> [...]
>> diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
>> index a40750e..6c66f01 100644
>> --- a/drivers/net/ethernet/ti/cpsw.c
>> +++ b/drivers/net/ethernet/ti/cpsw.c
> [...]
>> @@ -607,14 +611,41 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
>>   	}
>>   }
>>   
>> +static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
>> +{
>> +	writel(priv->data.default_vlan, &priv->host_port_regs->port_vlan);
>> +	if (priv->version == CPSW_VERSION_1) {
>> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
>> +			    CPSW1_PORT_VLAN);
>> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
>> +			    CPSW1_PORT_VLAN);
>> +	} else {
>> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
>> +			    CPSW2_PORT_VLAN);
>> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
>> +			    CPSW2_PORT_VLAN);
>> +	}
>> +	cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			(BIT(1) | BIT(2)) << priv->host_port);
>> +}
> static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
> {
> 	const int vlan = priv->data.default_vlan;
> 	const int port = priv->host_port;
> 	u32 reg;
> 	int i;
>
> 	reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
> 	      CPSW2_PORT_VLAN;
>
> 	writel(vlan, &priv->host_port_regs->port_vlan);
>
> 	for (int i = 0; i < 2; i++)
> 		slave_write(priv->slaves + i, vlan, reg);
>
> 	cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
> 			  ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
> 			  (BIT(1) | BIT(2)) << port);
> }
>
> ... or somewhere between both. Your call.
Will modify the code as this looks simpler
>
> [...]
>> @@ -933,6 +967,55 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
>>   }
>>   #endif
>>   
>> +static inline void cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
>> +				unsigned short vid)
>> +{
>> +	cpsw_ale_add_vlan(priv->ale, vid, ALE_ALL_PORTS << priv->host_port,
>> +			0, ALE_ALL_PORTS << priv->host_port,
>> +			(BIT(1) | BIT(2)) << priv->host_port);
> "(BIT(1) | BIT(2))" is repeated a couple of times.
Will replace with port number defines.
>
> [...]
>> +static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
>> +		unsigned short vid)
>> +{
>> +	struct cpsw_priv *priv = netdev_priv(ndev);
>> +
>> +	if (vid == priv->data.default_vlan)
>> +		return 0;
>> +
>> +	spin_lock(&priv->lock);
>> +
>> +	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
>> +	cpsw_add_vlan_ale_entry(priv, vid);
>> +
>> +	spin_unlock(&priv->lock);
>> +	return 0;
>> +}
>> +
>> +static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
>> +		unsigned short vid)
>> +{
>> +	struct cpsw_priv *priv = netdev_priv(ndev);
>> +
>> +	if (vid == priv->data.default_vlan)
>> +		return 0;
>> +
>> +	spin_lock(&priv->lock);
>> +
>> +	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
>> +	cpsw_ale_del_vlan(priv->ale, vid, 0);
>> +	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
>> +			   priv->host_port, ALE_VLAN, vid);
>> +	cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid);
>> +
>> +	spin_unlock(&priv->lock);
> What are you trying to achieve with the lock ?
>
> It is not used anywhere else and both cpsw_ndo_vlan_rx_{add, kill}_vid are
> called under RTNL.
Will remove the lock from both apis

Regards
Mugunthan V N

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN
@ 2013-01-31 11:09       ` Mugunthan V N
  0 siblings, 0 replies; 21+ messages in thread
From: Mugunthan V N @ 2013-01-31 11:09 UTC (permalink / raw)
  To: linux-arm-kernel

On 1/31/2013 3:32 AM, Francois Romieu wrote:
> Mugunthan V N <mugunthanvnm@ti.com> :
> [...]
>> diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
>> index 6ddd028..99696bf 100644
>> --- a/Documentation/devicetree/bindings/net/cpsw.txt
>> +++ b/Documentation/devicetree/bindings/net/cpsw.txt
>> @@ -24,6 +24,8 @@ Required properties:
>>   Optional properties:
>>   - ti,hwmods		: Must be "cpgmac0"
>>   - no_bd_ram		: Must be 0 or 1
>> +- default_vlan		: Specifies Default VLAN for non tagged packets
>> +			  ALE processing
> Isn't it a device-tree hack for what should belong to a common API ?
Its a hardware feature which stack will not be aware of. It is used in 
the ALE filtering
process with a non-tagged packet arrives.
>
> [...]
>> diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
>> index a40750e..6c66f01 100644
>> --- a/drivers/net/ethernet/ti/cpsw.c
>> +++ b/drivers/net/ethernet/ti/cpsw.c
> [...]
>> @@ -607,14 +611,41 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
>>   	}
>>   }
>>   
>> +static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
>> +{
>> +	writel(priv->data.default_vlan, &priv->host_port_regs->port_vlan);
>> +	if (priv->version == CPSW_VERSION_1) {
>> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
>> +			    CPSW1_PORT_VLAN);
>> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
>> +			    CPSW1_PORT_VLAN);
>> +	} else {
>> +		slave_write(&priv->slaves[0], priv->data.default_vlan,
>> +			    CPSW2_PORT_VLAN);
>> +		slave_write(&priv->slaves[1], priv->data.default_vlan,
>> +			    CPSW2_PORT_VLAN);
>> +	}
>> +	cpsw_ale_add_vlan(priv->ale, priv->data.default_vlan,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			ALE_ALL_PORTS << priv->host_port,
>> +			(BIT(1) | BIT(2)) << priv->host_port);
>> +}
> static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
> {
> 	const int vlan = priv->data.default_vlan;
> 	const int port = priv->host_port;
> 	u32 reg;
> 	int i;
>
> 	reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
> 	      CPSW2_PORT_VLAN;
>
> 	writel(vlan, &priv->host_port_regs->port_vlan);
>
> 	for (int i = 0; i < 2; i++)
> 		slave_write(priv->slaves + i, vlan, reg);
>
> 	cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
> 			  ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
> 			  (BIT(1) | BIT(2)) << port);
> }
>
> ... or somewhere between both. Your call.
Will modify the code as this looks simpler
>
> [...]
>> @@ -933,6 +967,55 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
>>   }
>>   #endif
>>   
>> +static inline void cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
>> +				unsigned short vid)
>> +{
>> +	cpsw_ale_add_vlan(priv->ale, vid, ALE_ALL_PORTS << priv->host_port,
>> +			0, ALE_ALL_PORTS << priv->host_port,
>> +			(BIT(1) | BIT(2)) << priv->host_port);
> "(BIT(1) | BIT(2))" is repeated a couple of times.
Will replace with port number defines.
>
> [...]
>> +static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
>> +		unsigned short vid)
>> +{
>> +	struct cpsw_priv *priv = netdev_priv(ndev);
>> +
>> +	if (vid == priv->data.default_vlan)
>> +		return 0;
>> +
>> +	spin_lock(&priv->lock);
>> +
>> +	dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
>> +	cpsw_add_vlan_ale_entry(priv, vid);
>> +
>> +	spin_unlock(&priv->lock);
>> +	return 0;
>> +}
>> +
>> +static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
>> +		unsigned short vid)
>> +{
>> +	struct cpsw_priv *priv = netdev_priv(ndev);
>> +
>> +	if (vid == priv->data.default_vlan)
>> +		return 0;
>> +
>> +	spin_lock(&priv->lock);
>> +
>> +	dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
>> +	cpsw_ale_del_vlan(priv->ale, vid, 0);
>> +	cpsw_ale_del_ucast(priv->ale, priv->mac_addr,
>> +			   priv->host_port, ALE_VLAN, vid);
>> +	cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, 0, ALE_VLAN, vid);
>> +
>> +	spin_unlock(&priv->lock);
> What are you trying to achieve with the lock ?
>
> It is not used anywhere else and both cpsw_ndo_vlan_rx_{add, kill}_vid are
> called under RTNL.
Will remove the lock from both apis

Regards
Mugunthan V N

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
  2013-01-31 11:09       ` Mugunthan V N
@ 2013-01-31 21:43         ` Francois Romieu
  -1 siblings, 0 replies; 21+ messages in thread
From: Francois Romieu @ 2013-01-31 21:43 UTC (permalink / raw)
  To: Mugunthan V N; +Cc: netdev, davem, linux-arm-kernel, linux-omap

Mugunthan V N <mugunthanvnm@ti.com> :
> On 1/31/2013 3:32 AM, Francois Romieu wrote:
[...]
> > It could be factored out.
> Are you mentioning to have static inline function for the above two
> statements above?

Yes. The helper function does not need to be inlined if it does not
save space: this path is not performance critical.

[...]
> >Patch #2 doesn't use the returned status code.
> Will modify the prototype to return void

:o(

The driver should notify the upper layers that the request failed instead
of hiding the stuff under the carpet.

-- 
Ueimor

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation
@ 2013-01-31 21:43         ` Francois Romieu
  0 siblings, 0 replies; 21+ messages in thread
From: Francois Romieu @ 2013-01-31 21:43 UTC (permalink / raw)
  To: linux-arm-kernel

Mugunthan V N <mugunthanvnm@ti.com> :
> On 1/31/2013 3:32 AM, Francois Romieu wrote:
[...]
> > It could be factored out.
> Are you mentioning to have static inline function for the above two
> statements above?

Yes. The helper function does not need to be inlined if it does not
save space: this path is not performance critical.

[...]
> >Patch #2 doesn't use the returned status code.
> Will modify the prototype to return void

:o(

The driver should notify the upper layers that the request failed instead
of hiding the stuff under the carpet.

-- 
Ueimor

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2013-01-31 21:43 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-30 19:07 [PATCH v2 0/2] Add CPSW VLAN Support Mugunthan V N
2013-01-30 19:07 ` Mugunthan V N
2013-01-30 19:07 ` Mugunthan V N
2013-01-30 19:07 ` [PATCH v2 1/2] drivers: net: cpsw: Add helper functions for VLAN ALE implementation Mugunthan V N
2013-01-30 19:07   ` Mugunthan V N
2013-01-30 19:07   ` Mugunthan V N
2013-01-30 22:02   ` Francois Romieu
2013-01-30 22:02     ` Francois Romieu
2013-01-31 11:09     ` Mugunthan V N
2013-01-31 11:09       ` Mugunthan V N
2013-01-31 11:09       ` Mugunthan V N
2013-01-31 21:43       ` Francois Romieu
2013-01-31 21:43         ` Francois Romieu
2013-01-30 19:07 ` [PATCH v2 2/2] drivers: net:ethernet: cpsw: add support for VLAN Mugunthan V N
2013-01-30 19:07   ` Mugunthan V N
2013-01-30 19:07   ` Mugunthan V N
2013-01-30 22:02   ` Francois Romieu
2013-01-30 22:02     ` Francois Romieu
2013-01-31 11:09     ` Mugunthan V N
2013-01-31 11:09       ` Mugunthan V N
2013-01-31 11:09       ` Mugunthan V N

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.