mlxsw: spectrum: Add couple of lower device helper functions

Add functions that iterate over lower devices and find port device.
As a dependency add netdev_for_each_all_lower_dev and
netdev_for_each_all_lower_dev_rcu macro with
netdev_all_lower_get_next and netdev_all_lower_get_next_rcu shelpers.

Also, add functions to return mlxsw struct according to lower device
found and mlxsw_port struct with a reference to lower device.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jiri Pirko 2016-07-04 08:23:12 +02:00 committed by David S. Miller
parent 61c503f976
commit 7ce856aaaf
4 changed files with 127 additions and 5 deletions

View File

@ -2567,6 +2567,66 @@ static struct mlxsw_driver mlxsw_sp_driver = {
.profile = &mlxsw_sp_config_profile,
};
static bool mlxsw_sp_port_dev_check(const struct net_device *dev)
{
return dev->netdev_ops == &mlxsw_sp_port_netdev_ops;
}
static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev)
{
struct net_device *lower_dev;
struct list_head *iter;
if (mlxsw_sp_port_dev_check(dev))
return netdev_priv(dev);
netdev_for_each_all_lower_dev(dev, lower_dev, iter) {
if (mlxsw_sp_port_dev_check(lower_dev))
return netdev_priv(lower_dev);
}
return NULL;
}
static struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev)
{
struct mlxsw_sp_port *mlxsw_sp_port;
mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev);
return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL;
}
static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev)
{
struct net_device *lower_dev;
struct list_head *iter;
if (mlxsw_sp_port_dev_check(dev))
return netdev_priv(dev);
netdev_for_each_all_lower_dev_rcu(dev, lower_dev, iter) {
if (mlxsw_sp_port_dev_check(lower_dev))
return netdev_priv(lower_dev);
}
return NULL;
}
struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev)
{
struct mlxsw_sp_port *mlxsw_sp_port;
rcu_read_lock();
mlxsw_sp_port = mlxsw_sp_port_dev_lower_find_rcu(dev);
if (mlxsw_sp_port)
dev_hold(mlxsw_sp_port->dev);
rcu_read_unlock();
return mlxsw_sp_port;
}
void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port)
{
dev_put(mlxsw_sp_port->dev);
}
static bool mlxsw_sp_lag_port_fid_member(struct mlxsw_sp_port *lag_port,
u16 fid)
{
@ -2647,11 +2707,6 @@ int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid)
return mlxsw_sp_port_fdb_flush_by_port_fid(mlxsw_sp_port, fid);
}
static bool mlxsw_sp_port_dev_check(const struct net_device *dev)
{
return dev->netdev_ops == &mlxsw_sp_port_netdev_ops;
}
static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp,
struct net_device *br_dev)
{

View File

@ -292,6 +292,9 @@ struct mlxsw_sp_port {
struct list_head vports_list;
};
struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev);
void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port);
static inline bool
mlxsw_sp_port_is_pause_en(const struct mlxsw_sp_port *mlxsw_sp_port)
{

View File

@ -3804,12 +3804,30 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev,
void *netdev_lower_get_next(struct net_device *dev,
struct list_head **iter);
#define netdev_for_each_lower_dev(dev, ldev, iter) \
for (iter = (dev)->adj_list.lower.next, \
ldev = netdev_lower_get_next(dev, &(iter)); \
ldev; \
ldev = netdev_lower_get_next(dev, &(iter)))
struct net_device *netdev_all_lower_get_next(struct net_device *dev,
struct list_head **iter);
struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
struct list_head **iter);
#define netdev_for_each_all_lower_dev(dev, ldev, iter) \
for (iter = (dev)->all_adj_list.lower.next, \
ldev = netdev_all_lower_get_next(dev, &(iter)); \
ldev; \
ldev = netdev_all_lower_get_next(dev, &(iter)))
#define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \
for (iter = (dev)->all_adj_list.lower.next, \
ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \
ldev; \
ldev = netdev_all_lower_get_next_rcu(dev, &(iter)))
void *netdev_adjacent_get_private(struct list_head *adj_list);
void *netdev_lower_get_first_private_rcu(struct net_device *dev);
struct net_device *netdev_master_upper_dev_get(struct net_device *dev);

View File

@ -5444,6 +5444,52 @@ void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter)
}
EXPORT_SYMBOL(netdev_lower_get_next);
/**
* netdev_all_lower_get_next - Get the next device from all lower neighbour list
* @dev: device
* @iter: list_head ** of the current position
*
* Gets the next netdev_adjacent from the dev's all lower neighbour
* list, starting from iter position. The caller must hold RTNL lock or
* its own locking that guarantees that the neighbour all lower
* list will remain unchanged.
*/
struct net_device *netdev_all_lower_get_next(struct net_device *dev, struct list_head **iter)
{
struct netdev_adjacent *lower;
lower = list_entry(*iter, struct netdev_adjacent, list);
if (&lower->list == &dev->all_adj_list.lower)
return NULL;
*iter = lower->list.next;
return lower->dev;
}
EXPORT_SYMBOL(netdev_all_lower_get_next);
/**
* netdev_all_lower_get_next_rcu - Get the next device from all
* lower neighbour list, RCU variant
* @dev: device
* @iter: list_head ** of the current position
*
* Gets the next netdev_adjacent from the dev's all lower neighbour
* list, starting from iter position. The caller must hold RCU read lock.
*/
struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
struct list_head **iter)
{
struct netdev_adjacent *lower;
lower = list_first_or_null_rcu(&dev->all_adj_list.lower,
struct netdev_adjacent, list);
return lower ? lower->dev : NULL;
}
EXPORT_SYMBOL(netdev_all_lower_get_next_rcu);
/**
* netdev_lower_get_first_private_rcu - Get the first ->private from the
* lower neighbour list, RCU