net: hsr: create an API to get hsr port type

Since the introduction of HSR_PT_INTERLINK in commit 5055cccfc2 ("net:
hsr: Provide RedBox support (HSR-SAN)"), we see that different port
types require different settings for hardware offload, which was not the
case before when we only had HSR_PT_SLAVE_A and HSR_PT_SLAVE_B. But
there is currently no way to know which port is which type, so create
the hsr_get_port_type() API function and export it.

When hsr_get_port_type() is called from the device driver, the port can
must be found in the HSR port list. An important use case is for this
function to work from offloading drivers' NETDEV_CHANGEUPPER handler,
which is triggered by hsr_portdev_setup() -> netdev_master_upper_dev_link().
Therefore, we need to move the addition of the hsr_port to the HSR port
list prior to calling hsr_portdev_setup(). This makes the error
restoration path also more similar to hsr_del_port(), where
kfree_rcu(port) is already used.

Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Lukasz Majewski <lukma@denx.de>
Signed-off-by: Xiaoliang Yang <xiaoliang.yang_1@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Łukasz Majewski <lukma@nabladev.com>
Link: https://patch.msgid.link/20251130131657.65080-3-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Xiaoliang Yang 2025-11-30 15:16:44 +02:00 committed by Jakub Kicinski
parent 3b87e60d21
commit a0244e7621
3 changed files with 33 additions and 3 deletions

View File

@ -43,6 +43,8 @@ extern bool is_hsr_master(struct net_device *dev);
extern int hsr_get_version(struct net_device *dev, enum hsr_version *ver);
struct net_device *hsr_get_port_ndev(struct net_device *ndev,
enum hsr_port_type pt);
int hsr_get_port_type(struct net_device *hsr_dev, struct net_device *dev,
enum hsr_port_type *type);
#else
static inline bool is_hsr_master(struct net_device *dev)
{
@ -59,6 +61,13 @@ static inline struct net_device *hsr_get_port_ndev(struct net_device *ndev,
{
return ERR_PTR(-EINVAL);
}
static inline int hsr_get_port_type(struct net_device *hsr_dev,
struct net_device *dev,
enum hsr_port_type *type)
{
return -EINVAL;
}
#endif /* CONFIG_HSR */
#endif /*_LINUX_IF_HSR_H_*/

View File

@ -690,6 +690,26 @@ struct net_device *hsr_get_port_ndev(struct net_device *ndev,
}
EXPORT_SYMBOL(hsr_get_port_ndev);
int hsr_get_port_type(struct net_device *hsr_dev, struct net_device *dev,
enum hsr_port_type *type)
{
struct hsr_priv *hsr = netdev_priv(hsr_dev);
struct hsr_port *port;
rcu_read_lock();
hsr_for_each_port(hsr, port) {
if (port->dev == dev) {
*type = port->type;
rcu_read_unlock();
return 0;
}
}
rcu_read_unlock();
return -EINVAL;
}
EXPORT_SYMBOL(hsr_get_port_type);
/* Default multicast address for HSR Supervision frames */
static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = {
0x01, 0x15, 0x4e, 0x00, 0x01, 0x00

View File

@ -207,14 +207,14 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev,
port->type = type;
ether_addr_copy(port->original_macaddress, dev->dev_addr);
list_add_tail_rcu(&port->port_list, &hsr->ports);
if (type != HSR_PT_MASTER) {
res = hsr_portdev_setup(hsr, dev, port, extack);
if (res)
goto fail_dev_setup;
}
list_add_tail_rcu(&port->port_list, &hsr->ports);
master = hsr_port_get_hsr(hsr, HSR_PT_MASTER);
netdev_update_features(master->dev);
dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
@ -222,7 +222,8 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev,
return 0;
fail_dev_setup:
kfree(port);
list_del_rcu(&port->port_list);
kfree_rcu(port, rcu);
return res;
}