Commit e11b220f authored by Mugunthan V N's avatar Mugunthan V N Committed by David S. Miller

drivers: net: cpsw: Add helper functions for VLAN ALE implementation

Add helper functions for VLAN ALE implementations for Add, Delete
Dump VLAN related ALE entries
Signed-off-by: default avatarMugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ca99ca14
...@@ -345,7 +345,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) ...@@ -345,7 +345,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
/* program multicast address list into ALE register */ /* program multicast address list into ALE register */
netdev_for_each_mc_addr(ha, ndev) { netdev_for_each_mc_addr(ha, ndev) {
cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr, 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) ...@@ -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); slave_port = cpsw_get_slave_port(priv, slave->slave_num);
cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, 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, slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
&cpsw_adjust_link, slave->data->phy_if); &cpsw_adjust_link, slave->data->phy_if);
...@@ -624,9 +624,9 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) ...@@ -624,9 +624,9 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
cpsw_ale_control_set(priv->ale, priv->host_port, cpsw_ale_control_set(priv->ale, priv->host_port,
ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); 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, 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) static int cpsw_ndo_open(struct net_device *ndev)
......
...@@ -148,7 +148,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry) ...@@ -148,7 +148,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry)
return idx; 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]; u32 ale_entry[ALE_ENTRY_WORDS];
int type, idx; int type, idx;
...@@ -160,6 +160,8 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr) ...@@ -160,6 +160,8 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
type = cpsw_ale_get_entry_type(ale_entry); type = cpsw_ale_get_entry_type(ale_entry);
if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR)
continue; continue;
if (cpsw_ale_get_vlan_id(ale_entry) != vid)
continue;
cpsw_ale_get_addr(ale_entry, entry_addr); cpsw_ale_get_addr(ale_entry, entry_addr);
if (memcmp(entry_addr, addr, 6) == 0) if (memcmp(entry_addr, addr, 6) == 0)
return idx; return idx;
...@@ -167,6 +169,22 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr) ...@@ -167,6 +169,22 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr)
return -ENOENT; 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) static int cpsw_ale_match_free(struct cpsw_ale *ale)
{ {
u32 ale_entry[ALE_ENTRY_WORDS]; u32 ale_entry[ALE_ENTRY_WORDS];
...@@ -274,19 +292,32 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) ...@@ -274,19 +292,32 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
return 0; return 0;
} }
int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags) static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
int flags, u16 vid)
{
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);
}
}
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}; u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx; int idx;
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
cpsw_ale_set_addr(ale_entry, addr); cpsw_ale_set_addr(ale_entry, addr);
cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); 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_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0);
cpsw_ale_set_port_num(ale_entry, port); 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) if (idx < 0)
idx = cpsw_ale_match_free(ale); idx = cpsw_ale_match_free(ale);
if (idx < 0) if (idx < 0)
...@@ -298,12 +329,13 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags) ...@@ -298,12 +329,13 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags)
return 0; 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}; u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx; int idx;
idx = cpsw_ale_match_addr(ale, addr); idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
if (idx < 0) if (idx < 0)
return -ENOENT; return -ENOENT;
...@@ -313,18 +345,19 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port) ...@@ -313,18 +345,19 @@ 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 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}; u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx, mask; 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) if (idx >= 0)
cpsw_ale_read(ale, idx, ale_entry); cpsw_ale_read(ale, idx, ale_entry);
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);
cpsw_ale_set_addr(ale_entry, 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); cpsw_ale_set_mcast_state(ale_entry, mcast_state);
mask = cpsw_ale_get_port_mask(ale_entry); mask = cpsw_ale_get_port_mask(ale_entry);
...@@ -342,12 +375,13 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, ...@@ -342,12 +375,13 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
return 0; 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}; u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx; int idx;
idx = cpsw_ale_match_addr(ale, addr); idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0);
if (idx < 0) if (idx < 0)
return -EINVAL; return -EINVAL;
...@@ -362,6 +396,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask) ...@@ -362,6 +396,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask)
return 0; 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 { struct ale_control_info {
const char *name; const char *name;
int offset, port_offset; int offset, port_offset;
......
...@@ -64,8 +64,10 @@ enum cpsw_ale_port_state { ...@@ -64,8 +64,10 @@ enum cpsw_ale_port_state {
}; };
/* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */ /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
#define ALE_SECURE 1 #define ALE_SECURE BIT(0)
#define ALE_BLOCKED 2 #define ALE_BLOCKED BIT(1)
#define ALE_SUPER BIT(2)
#define ALE_VLAN BIT(3)
#define ALE_MCAST_FWD 0 #define ALE_MCAST_FWD 0
#define ALE_MCAST_BLOCK_LEARN_FWD 1 #define ALE_MCAST_BLOCK_LEARN_FWD 1
...@@ -81,11 +83,17 @@ void cpsw_ale_stop(struct cpsw_ale *ale); ...@@ -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_set_ageout(struct cpsw_ale *ale, int ageout);
int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); 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_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_add_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);
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 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);
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);
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_get(struct cpsw_ale *ale, int port, int control);
int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int cpsw_ale_control_set(struct cpsw_ale *ale, int port,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment