Since the introduction of HSR_PT_INTERLINK in commit
5055cccfc2d1 ("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>
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)
{
{
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_*/
}
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
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));
return 0;
fail_dev_setup:
- kfree(port);
+ list_del_rcu(&port->port_list);
+ kfree_rcu(port, rcu);
return res;
}