Skip to content

Commit

Permalink
drivers: net: cpsw: Add helper functions for VLAN ALE implementation
Browse files Browse the repository at this point in the history
Add helper functions for VLAN ALE implementations for Add, Delete
Dump VLAN related ALE entries

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Mugunthan V N authored and David S. Miller committed Feb 6, 2013
1 parent ca99ca1 commit e11b220
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 22 deletions.
8 changes: 4 additions & 4 deletions drivers/net/ethernet/ti/cpsw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
107 changes: 95 additions & 12 deletions drivers/net/ethernet/ti/cpsw_ale.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -160,13 +160,31 @@ 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;
}
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];
Expand Down Expand Up @@ -274,19 +292,32 @@ 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)
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};
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_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)
Expand All @@ -298,12 +329,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;

Expand All @@ -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 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);
cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid);

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);
Expand All @@ -342,12 +375,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;

Expand All @@ -362,6 +396,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;
Expand Down
20 changes: 14 additions & 6 deletions drivers/net/ethernet/ti/cpsw_ale.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down

0 comments on commit e11b220

Please sign in to comment.