net: dsa: add support for offloading HSR
Add support for offloading of HSR/PRP (IEC 62439-3) tag insertion tag removal, duplicate generation and forwarding on DSA switches. Add DSA_NOTIFIER_HSR_JOIN and DSA_NOTIFIER_HSR_LEAVE which trigger calls to .port_hsr_join and .port_hsr_leave in the DSA driver for the switch. The DSA switch driver should then set netdev feature flags for the HSR/PRP operation that it offloads. NETIF_F_HW_HSR_TAG_INS NETIF_F_HW_HSR_TAG_RM NETIF_F_HW_HSR_FWD NETIF_F_HW_HSR_DUP Signed-off-by: George McCollister <george.mccollister@gmail.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
dcf0cd1cc5
Коммит
18596f504a
|
@ -172,6 +172,10 @@ struct dsa_switch_tree {
|
||||||
list_for_each_entry((_dp), &(_dst)->ports, list) \
|
list_for_each_entry((_dp), &(_dst)->ports, list) \
|
||||||
if ((_dp)->lag_dev == (_lag))
|
if ((_dp)->lag_dev == (_lag))
|
||||||
|
|
||||||
|
#define dsa_hsr_foreach_port(_dp, _ds, _hsr) \
|
||||||
|
list_for_each_entry((_dp), &(_ds)->dst->ports, list) \
|
||||||
|
if ((_dp)->ds == (_ds) && (_dp)->hsr_dev == (_hsr))
|
||||||
|
|
||||||
static inline struct net_device *dsa_lag_dev(struct dsa_switch_tree *dst,
|
static inline struct net_device *dsa_lag_dev(struct dsa_switch_tree *dst,
|
||||||
unsigned int id)
|
unsigned int id)
|
||||||
{
|
{
|
||||||
|
@ -264,6 +268,7 @@ struct dsa_port {
|
||||||
struct phylink_config pl_config;
|
struct phylink_config pl_config;
|
||||||
struct net_device *lag_dev;
|
struct net_device *lag_dev;
|
||||||
bool lag_tx_enabled;
|
bool lag_tx_enabled;
|
||||||
|
struct net_device *hsr_dev;
|
||||||
|
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
||||||
|
@ -769,6 +774,14 @@ struct dsa_switch_ops {
|
||||||
struct netdev_lag_upper_info *info);
|
struct netdev_lag_upper_info *info);
|
||||||
int (*port_lag_leave)(struct dsa_switch *ds, int port,
|
int (*port_lag_leave)(struct dsa_switch *ds, int port,
|
||||||
struct net_device *lag);
|
struct net_device *lag);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HSR integration
|
||||||
|
*/
|
||||||
|
int (*port_hsr_join)(struct dsa_switch *ds, int port,
|
||||||
|
struct net_device *hsr);
|
||||||
|
int (*port_hsr_leave)(struct dsa_switch *ds, int port,
|
||||||
|
struct net_device *hsr);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes) \
|
#define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes) \
|
||||||
|
|
|
@ -20,6 +20,8 @@ enum {
|
||||||
DSA_NOTIFIER_BRIDGE_LEAVE,
|
DSA_NOTIFIER_BRIDGE_LEAVE,
|
||||||
DSA_NOTIFIER_FDB_ADD,
|
DSA_NOTIFIER_FDB_ADD,
|
||||||
DSA_NOTIFIER_FDB_DEL,
|
DSA_NOTIFIER_FDB_DEL,
|
||||||
|
DSA_NOTIFIER_HSR_JOIN,
|
||||||
|
DSA_NOTIFIER_HSR_LEAVE,
|
||||||
DSA_NOTIFIER_LAG_CHANGE,
|
DSA_NOTIFIER_LAG_CHANGE,
|
||||||
DSA_NOTIFIER_LAG_JOIN,
|
DSA_NOTIFIER_LAG_JOIN,
|
||||||
DSA_NOTIFIER_LAG_LEAVE,
|
DSA_NOTIFIER_LAG_LEAVE,
|
||||||
|
@ -100,6 +102,13 @@ struct dsa_switchdev_event_work {
|
||||||
u16 vid;
|
u16 vid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* DSA_NOTIFIER_HSR_* */
|
||||||
|
struct dsa_notifier_hsr_info {
|
||||||
|
struct net_device *hsr;
|
||||||
|
int sw_index;
|
||||||
|
int port;
|
||||||
|
};
|
||||||
|
|
||||||
struct dsa_slave_priv {
|
struct dsa_slave_priv {
|
||||||
/* Copy of CPU port xmit for faster access in slave transmit hot path */
|
/* Copy of CPU port xmit for faster access in slave transmit hot path */
|
||||||
struct sk_buff * (*xmit)(struct sk_buff *skb,
|
struct sk_buff * (*xmit)(struct sk_buff *skb,
|
||||||
|
@ -183,6 +192,8 @@ int dsa_port_vlan_del(struct dsa_port *dp,
|
||||||
const struct switchdev_obj_port_vlan *vlan);
|
const struct switchdev_obj_port_vlan *vlan);
|
||||||
int dsa_port_link_register_of(struct dsa_port *dp);
|
int dsa_port_link_register_of(struct dsa_port *dp);
|
||||||
void dsa_port_link_unregister_of(struct dsa_port *dp);
|
void dsa_port_link_unregister_of(struct dsa_port *dp);
|
||||||
|
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr);
|
||||||
|
void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr);
|
||||||
extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
|
extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
|
||||||
|
|
||||||
static inline bool dsa_port_offloads_netdev(struct dsa_port *dp,
|
static inline bool dsa_port_offloads_netdev(struct dsa_port *dp,
|
||||||
|
|
|
@ -868,3 +868,37 @@ int dsa_port_get_phy_sset_count(struct dsa_port *dp)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);
|
EXPORT_SYMBOL_GPL(dsa_port_get_phy_sset_count);
|
||||||
|
|
||||||
|
int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr)
|
||||||
|
{
|
||||||
|
struct dsa_notifier_hsr_info info = {
|
||||||
|
.sw_index = dp->ds->index,
|
||||||
|
.port = dp->index,
|
||||||
|
.hsr = hsr,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
dp->hsr_dev = hsr;
|
||||||
|
|
||||||
|
err = dsa_port_notify(dp, DSA_NOTIFIER_HSR_JOIN, &info);
|
||||||
|
if (err)
|
||||||
|
dp->hsr_dev = NULL;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr)
|
||||||
|
{
|
||||||
|
struct dsa_notifier_hsr_info info = {
|
||||||
|
.sw_index = dp->ds->index,
|
||||||
|
.port = dp->index,
|
||||||
|
.hsr = hsr,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
|
dp->hsr_dev = NULL;
|
||||||
|
|
||||||
|
err = dsa_port_notify(dp, DSA_NOTIFIER_HSR_LEAVE, &info);
|
||||||
|
if (err)
|
||||||
|
pr_err("DSA: failed to notify DSA_NOTIFIER_HSR_LEAVE\n");
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <net/pkt_cls.h>
|
#include <net/pkt_cls.h>
|
||||||
#include <net/tc_act/tc_mirred.h>
|
#include <net/tc_act/tc_mirred.h>
|
||||||
#include <linux/if_bridge.h>
|
#include <linux/if_bridge.h>
|
||||||
|
#include <linux/if_hsr.h>
|
||||||
#include <linux/netpoll.h>
|
#include <linux/netpoll.h>
|
||||||
#include <linux/ptp_classify.h>
|
#include <linux/ptp_classify.h>
|
||||||
|
|
||||||
|
@ -1938,6 +1939,19 @@ static int dsa_slave_changeupper(struct net_device *dev,
|
||||||
dsa_port_lag_leave(dp, info->upper_dev);
|
dsa_port_lag_leave(dp, info->upper_dev);
|
||||||
err = NOTIFY_OK;
|
err = NOTIFY_OK;
|
||||||
}
|
}
|
||||||
|
} else if (is_hsr_master(info->upper_dev)) {
|
||||||
|
if (info->linking) {
|
||||||
|
err = dsa_port_hsr_join(dp, info->upper_dev);
|
||||||
|
if (err == -EOPNOTSUPP) {
|
||||||
|
NL_SET_ERR_MSG_MOD(info->info.extack,
|
||||||
|
"Offloading not supported");
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
err = notifier_from_errno(err);
|
||||||
|
} else {
|
||||||
|
dsa_port_hsr_leave(dp, info->upper_dev);
|
||||||
|
err = NOTIFY_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -166,6 +166,24 @@ static int dsa_switch_fdb_del(struct dsa_switch *ds,
|
||||||
return ds->ops->port_fdb_del(ds, port, info->addr, info->vid);
|
return ds->ops->port_fdb_del(ds, port, info->addr, info->vid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dsa_switch_hsr_join(struct dsa_switch *ds,
|
||||||
|
struct dsa_notifier_hsr_info *info)
|
||||||
|
{
|
||||||
|
if (ds->index == info->sw_index && ds->ops->port_hsr_join)
|
||||||
|
return ds->ops->port_hsr_join(ds, info->port, info->hsr);
|
||||||
|
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dsa_switch_hsr_leave(struct dsa_switch *ds,
|
||||||
|
struct dsa_notifier_hsr_info *info)
|
||||||
|
{
|
||||||
|
if (ds->index == info->sw_index && ds->ops->port_hsr_leave)
|
||||||
|
return ds->ops->port_hsr_leave(ds, info->port, info->hsr);
|
||||||
|
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static int dsa_switch_lag_change(struct dsa_switch *ds,
|
static int dsa_switch_lag_change(struct dsa_switch *ds,
|
||||||
struct dsa_notifier_lag_info *info)
|
struct dsa_notifier_lag_info *info)
|
||||||
{
|
{
|
||||||
|
@ -371,6 +389,12 @@ static int dsa_switch_event(struct notifier_block *nb,
|
||||||
case DSA_NOTIFIER_FDB_DEL:
|
case DSA_NOTIFIER_FDB_DEL:
|
||||||
err = dsa_switch_fdb_del(ds, info);
|
err = dsa_switch_fdb_del(ds, info);
|
||||||
break;
|
break;
|
||||||
|
case DSA_NOTIFIER_HSR_JOIN:
|
||||||
|
err = dsa_switch_hsr_join(ds, info);
|
||||||
|
break;
|
||||||
|
case DSA_NOTIFIER_HSR_LEAVE:
|
||||||
|
err = dsa_switch_hsr_leave(ds, info);
|
||||||
|
break;
|
||||||
case DSA_NOTIFIER_LAG_CHANGE:
|
case DSA_NOTIFIER_LAG_CHANGE:
|
||||||
err = dsa_switch_lag_change(ds, info);
|
err = dsa_switch_lag_change(ds, info);
|
||||||
break;
|
break;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче