162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <linux/if_bridge.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include "lan966x_main.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_cistatic void lan966x_lag_set_aggr_pgids(struct lan966x *lan966x)
862306a36Sopenharmony_ci{
962306a36Sopenharmony_ci	u32 visited = GENMASK(lan966x->num_phys_ports - 1, 0);
1062306a36Sopenharmony_ci	int p, lag, i;
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci	/* Reset destination and aggregation PGIDS */
1362306a36Sopenharmony_ci	for (p = 0; p < lan966x->num_phys_ports; ++p)
1462306a36Sopenharmony_ci		lan_wr(ANA_PGID_PGID_SET(BIT(p)),
1562306a36Sopenharmony_ci		       lan966x, ANA_PGID(p));
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	for (p = PGID_AGGR; p < PGID_SRC; ++p)
1862306a36Sopenharmony_ci		lan_wr(ANA_PGID_PGID_SET(visited),
1962306a36Sopenharmony_ci		       lan966x, ANA_PGID(p));
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	/* The visited ports bitmask holds the list of ports offloading any
2262306a36Sopenharmony_ci	 * bonding interface. Initially we mark all these ports as unvisited,
2362306a36Sopenharmony_ci	 * then every time we visit a port in this bitmask, we know that it is
2462306a36Sopenharmony_ci	 * the lowest numbered port, i.e. the one whose logical ID == physical
2562306a36Sopenharmony_ci	 * port ID == LAG ID. So we mark as visited all further ports in the
2662306a36Sopenharmony_ci	 * bitmask that are offloading the same bonding interface. This way,
2762306a36Sopenharmony_ci	 * we set up the aggregation PGIDs only once per bonding interface.
2862306a36Sopenharmony_ci	 */
2962306a36Sopenharmony_ci	for (p = 0; p < lan966x->num_phys_ports; ++p) {
3062306a36Sopenharmony_ci		struct lan966x_port *port = lan966x->ports[p];
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci		if (!port || !port->bond)
3362306a36Sopenharmony_ci			continue;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci		visited &= ~BIT(p);
3662306a36Sopenharmony_ci	}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/* Now, set PGIDs for each active LAG */
3962306a36Sopenharmony_ci	for (lag = 0; lag < lan966x->num_phys_ports; ++lag) {
4062306a36Sopenharmony_ci		struct lan966x_port *port = lan966x->ports[lag];
4162306a36Sopenharmony_ci		int num_active_ports = 0;
4262306a36Sopenharmony_ci		struct net_device *bond;
4362306a36Sopenharmony_ci		unsigned long bond_mask;
4462306a36Sopenharmony_ci		u8 aggr_idx[16];
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci		if (!port || !port->bond || (visited & BIT(lag)))
4762306a36Sopenharmony_ci			continue;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci		bond = port->bond;
5062306a36Sopenharmony_ci		bond_mask = lan966x_lag_get_mask(lan966x, bond);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		for_each_set_bit(p, &bond_mask, lan966x->num_phys_ports) {
5362306a36Sopenharmony_ci			struct lan966x_port *port = lan966x->ports[p];
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci			if (!port)
5662306a36Sopenharmony_ci				continue;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci			lan_wr(ANA_PGID_PGID_SET(bond_mask),
5962306a36Sopenharmony_ci			       lan966x, ANA_PGID(p));
6062306a36Sopenharmony_ci			if (port->lag_tx_active)
6162306a36Sopenharmony_ci				aggr_idx[num_active_ports++] = p;
6262306a36Sopenharmony_ci		}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		for (i = PGID_AGGR; i < PGID_SRC; ++i) {
6562306a36Sopenharmony_ci			u32 ac;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci			ac = lan_rd(lan966x, ANA_PGID(i));
6862306a36Sopenharmony_ci			ac &= ~bond_mask;
6962306a36Sopenharmony_ci			/* Don't do division by zero if there was no active
7062306a36Sopenharmony_ci			 * port. Just make all aggregation codes zero.
7162306a36Sopenharmony_ci			 */
7262306a36Sopenharmony_ci			if (num_active_ports)
7362306a36Sopenharmony_ci				ac |= BIT(aggr_idx[i % num_active_ports]);
7462306a36Sopenharmony_ci			lan_wr(ANA_PGID_PGID_SET(ac),
7562306a36Sopenharmony_ci			       lan966x, ANA_PGID(i));
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		/* Mark all ports in the same LAG as visited to avoid applying
7962306a36Sopenharmony_ci		 * the same config again.
8062306a36Sopenharmony_ci		 */
8162306a36Sopenharmony_ci		for (p = lag; p < lan966x->num_phys_ports; p++) {
8262306a36Sopenharmony_ci			struct lan966x_port *port = lan966x->ports[p];
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci			if (!port)
8562306a36Sopenharmony_ci				continue;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci			if (port->bond == bond)
8862306a36Sopenharmony_ci				visited |= BIT(p);
8962306a36Sopenharmony_ci		}
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void lan966x_lag_set_port_ids(struct lan966x *lan966x)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct lan966x_port *port;
9662306a36Sopenharmony_ci	u32 bond_mask;
9762306a36Sopenharmony_ci	u32 lag_id;
9862306a36Sopenharmony_ci	int p;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	for (p = 0; p < lan966x->num_phys_ports; ++p) {
10162306a36Sopenharmony_ci		port = lan966x->ports[p];
10262306a36Sopenharmony_ci		if (!port)
10362306a36Sopenharmony_ci			continue;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		lag_id = port->chip_port;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci		bond_mask = lan966x_lag_get_mask(lan966x, port->bond);
10862306a36Sopenharmony_ci		if (bond_mask)
10962306a36Sopenharmony_ci			lag_id = __ffs(bond_mask);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		lan_rmw(ANA_PORT_CFG_PORTID_VAL_SET(lag_id),
11262306a36Sopenharmony_ci			ANA_PORT_CFG_PORTID_VAL,
11362306a36Sopenharmony_ci			lan966x, ANA_PORT_CFG(port->chip_port));
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic void lan966x_lag_update_ids(struct lan966x *lan966x)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	lan966x_lag_set_port_ids(lan966x);
12062306a36Sopenharmony_ci	lan966x_update_fwd_mask(lan966x);
12162306a36Sopenharmony_ci	lan966x_lag_set_aggr_pgids(lan966x);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciint lan966x_lag_port_join(struct lan966x_port *port,
12562306a36Sopenharmony_ci			  struct net_device *brport_dev,
12662306a36Sopenharmony_ci			  struct net_device *bond,
12762306a36Sopenharmony_ci			  struct netlink_ext_ack *extack)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct lan966x *lan966x = port->lan966x;
13062306a36Sopenharmony_ci	struct net_device *dev = port->dev;
13162306a36Sopenharmony_ci	u32 lag_id = -1;
13262306a36Sopenharmony_ci	u32 bond_mask;
13362306a36Sopenharmony_ci	int err;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	bond_mask = lan966x_lag_get_mask(lan966x, bond);
13662306a36Sopenharmony_ci	if (bond_mask)
13762306a36Sopenharmony_ci		lag_id = __ffs(bond_mask);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	port->bond = bond;
14062306a36Sopenharmony_ci	lan966x_lag_update_ids(lan966x);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	err = switchdev_bridge_port_offload(brport_dev, dev, port,
14362306a36Sopenharmony_ci					    &lan966x_switchdev_nb,
14462306a36Sopenharmony_ci					    &lan966x_switchdev_blocking_nb,
14562306a36Sopenharmony_ci					    false, extack);
14662306a36Sopenharmony_ci	if (err)
14762306a36Sopenharmony_ci		goto out;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	lan966x_port_stp_state_set(port, br_port_get_stp_state(brport_dev));
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (lan966x_lag_first_port(port->bond, port->dev) &&
15262306a36Sopenharmony_ci	    lag_id != -1)
15362306a36Sopenharmony_ci		lan966x_mac_lag_replace_port_entry(lan966x,
15462306a36Sopenharmony_ci						   lan966x->ports[lag_id],
15562306a36Sopenharmony_ci						   port);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return 0;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ciout:
16062306a36Sopenharmony_ci	port->bond = NULL;
16162306a36Sopenharmony_ci	lan966x_lag_update_ids(lan966x);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return err;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_civoid lan966x_lag_port_leave(struct lan966x_port *port, struct net_device *bond)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct lan966x *lan966x = port->lan966x;
16962306a36Sopenharmony_ci	u32 bond_mask;
17062306a36Sopenharmony_ci	u32 lag_id;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (lan966x_lag_first_port(port->bond, port->dev)) {
17362306a36Sopenharmony_ci		bond_mask = lan966x_lag_get_mask(lan966x, port->bond);
17462306a36Sopenharmony_ci		bond_mask &= ~BIT(port->chip_port);
17562306a36Sopenharmony_ci		if (bond_mask) {
17662306a36Sopenharmony_ci			lag_id = __ffs(bond_mask);
17762306a36Sopenharmony_ci			lan966x_mac_lag_replace_port_entry(lan966x, port,
17862306a36Sopenharmony_ci							   lan966x->ports[lag_id]);
17962306a36Sopenharmony_ci		} else {
18062306a36Sopenharmony_ci			lan966x_mac_lag_remove_port_entry(lan966x, port);
18162306a36Sopenharmony_ci		}
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	port->bond = NULL;
18562306a36Sopenharmony_ci	lan966x_lag_update_ids(lan966x);
18662306a36Sopenharmony_ci	lan966x_port_stp_state_set(port, BR_STATE_FORWARDING);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic bool lan966x_lag_port_check_hash_types(struct lan966x *lan966x,
19062306a36Sopenharmony_ci					      enum netdev_lag_hash hash_type)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	int p;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	for (p = 0; p < lan966x->num_phys_ports; ++p) {
19562306a36Sopenharmony_ci		struct lan966x_port *port = lan966x->ports[p];
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		if (!port || !port->bond)
19862306a36Sopenharmony_ci			continue;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		if (port->hash_type != hash_type)
20162306a36Sopenharmony_ci			return false;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return true;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ciint lan966x_lag_port_prechangeupper(struct net_device *dev,
20862306a36Sopenharmony_ci				    struct netdev_notifier_changeupper_info *info)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct lan966x_port *port = netdev_priv(dev);
21162306a36Sopenharmony_ci	struct lan966x *lan966x = port->lan966x;
21262306a36Sopenharmony_ci	struct netdev_lag_upper_info *lui;
21362306a36Sopenharmony_ci	struct netlink_ext_ack *extack;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	extack = netdev_notifier_info_to_extack(&info->info);
21662306a36Sopenharmony_ci	lui = info->upper_info;
21762306a36Sopenharmony_ci	if (!lui) {
21862306a36Sopenharmony_ci		port->hash_type = NETDEV_LAG_HASH_NONE;
21962306a36Sopenharmony_ci		return NOTIFY_DONE;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (lui->tx_type != NETDEV_LAG_TX_TYPE_HASH) {
22362306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack,
22462306a36Sopenharmony_ci				   "LAG device using unsupported Tx type");
22562306a36Sopenharmony_ci		return -EINVAL;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (!lan966x_lag_port_check_hash_types(lan966x, lui->hash_type)) {
22962306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack,
23062306a36Sopenharmony_ci				   "LAG devices can have only the same hash_type");
23162306a36Sopenharmony_ci		return -EINVAL;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	switch (lui->hash_type) {
23562306a36Sopenharmony_ci	case NETDEV_LAG_HASH_L2:
23662306a36Sopenharmony_ci		lan_wr(ANA_AGGR_CFG_AC_DMAC_ENA_SET(1) |
23762306a36Sopenharmony_ci		       ANA_AGGR_CFG_AC_SMAC_ENA_SET(1),
23862306a36Sopenharmony_ci		       lan966x, ANA_AGGR_CFG);
23962306a36Sopenharmony_ci		break;
24062306a36Sopenharmony_ci	case NETDEV_LAG_HASH_L34:
24162306a36Sopenharmony_ci		lan_wr(ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA_SET(1) |
24262306a36Sopenharmony_ci		       ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA_SET(1) |
24362306a36Sopenharmony_ci		       ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA_SET(1),
24462306a36Sopenharmony_ci		       lan966x, ANA_AGGR_CFG);
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	case NETDEV_LAG_HASH_L23:
24762306a36Sopenharmony_ci		lan_wr(ANA_AGGR_CFG_AC_DMAC_ENA_SET(1) |
24862306a36Sopenharmony_ci		       ANA_AGGR_CFG_AC_SMAC_ENA_SET(1) |
24962306a36Sopenharmony_ci		       ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA_SET(1) |
25062306a36Sopenharmony_ci		       ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA_SET(1),
25162306a36Sopenharmony_ci		       lan966x, ANA_AGGR_CFG);
25262306a36Sopenharmony_ci		break;
25362306a36Sopenharmony_ci	default:
25462306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack,
25562306a36Sopenharmony_ci				   "LAG device using unsupported hash type");
25662306a36Sopenharmony_ci		return -EINVAL;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	port->hash_type = lui->hash_type;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return NOTIFY_OK;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ciint lan966x_lag_port_changelowerstate(struct net_device *dev,
26562306a36Sopenharmony_ci				      struct netdev_notifier_changelowerstate_info *info)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct netdev_lag_lower_state_info *lag = info->lower_state_info;
26862306a36Sopenharmony_ci	struct lan966x_port *port = netdev_priv(dev);
26962306a36Sopenharmony_ci	struct lan966x *lan966x = port->lan966x;
27062306a36Sopenharmony_ci	bool is_active;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (!port->bond)
27362306a36Sopenharmony_ci		return NOTIFY_DONE;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	is_active = lag->link_up && lag->tx_enabled;
27662306a36Sopenharmony_ci	if (port->lag_tx_active == is_active)
27762306a36Sopenharmony_ci		return NOTIFY_DONE;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	port->lag_tx_active = is_active;
28062306a36Sopenharmony_ci	lan966x_lag_set_aggr_pgids(lan966x);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return NOTIFY_OK;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ciint lan966x_lag_netdev_prechangeupper(struct net_device *dev,
28662306a36Sopenharmony_ci				      struct netdev_notifier_changeupper_info *info)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct lan966x_port *port;
28962306a36Sopenharmony_ci	struct net_device *lower;
29062306a36Sopenharmony_ci	struct list_head *iter;
29162306a36Sopenharmony_ci	int err;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	netdev_for_each_lower_dev(dev, lower, iter) {
29462306a36Sopenharmony_ci		if (!lan966x_netdevice_check(lower))
29562306a36Sopenharmony_ci			continue;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		port = netdev_priv(lower);
29862306a36Sopenharmony_ci		if (port->bond != dev)
29962306a36Sopenharmony_ci			continue;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		err = lan966x_port_prechangeupper(lower, dev, info);
30262306a36Sopenharmony_ci		if (err)
30362306a36Sopenharmony_ci			return err;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	return NOTIFY_DONE;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciint lan966x_lag_netdev_changeupper(struct net_device *dev,
31062306a36Sopenharmony_ci				   struct netdev_notifier_changeupper_info *info)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	struct lan966x_port *port;
31362306a36Sopenharmony_ci	struct net_device *lower;
31462306a36Sopenharmony_ci	struct list_head *iter;
31562306a36Sopenharmony_ci	int err;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	netdev_for_each_lower_dev(dev, lower, iter) {
31862306a36Sopenharmony_ci		if (!lan966x_netdevice_check(lower))
31962306a36Sopenharmony_ci			continue;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		port = netdev_priv(lower);
32262306a36Sopenharmony_ci		if (port->bond != dev)
32362306a36Sopenharmony_ci			continue;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		err = lan966x_port_changeupper(lower, dev, info);
32662306a36Sopenharmony_ci		if (err)
32762306a36Sopenharmony_ci			return err;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return NOTIFY_DONE;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cibool lan966x_lag_first_port(struct net_device *lag, struct net_device *dev)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct lan966x_port *port = netdev_priv(dev);
33662306a36Sopenharmony_ci	struct lan966x *lan966x = port->lan966x;
33762306a36Sopenharmony_ci	unsigned long bond_mask;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (port->bond != lag)
34062306a36Sopenharmony_ci		return false;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	bond_mask = lan966x_lag_get_mask(lan966x, lag);
34362306a36Sopenharmony_ci	if (bond_mask && port->chip_port == __ffs(bond_mask))
34462306a36Sopenharmony_ci		return true;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return false;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ciu32 lan966x_lag_get_mask(struct lan966x *lan966x, struct net_device *bond)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct lan966x_port *port;
35262306a36Sopenharmony_ci	u32 mask = 0;
35362306a36Sopenharmony_ci	int p;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (!bond)
35662306a36Sopenharmony_ci		return mask;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	for (p = 0; p < lan966x->num_phys_ports; p++) {
35962306a36Sopenharmony_ci		port = lan966x->ports[p];
36062306a36Sopenharmony_ci		if (!port)
36162306a36Sopenharmony_ci			continue;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		if (port->bond == bond)
36462306a36Sopenharmony_ci			mask |= BIT(p);
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return mask;
36862306a36Sopenharmony_ci}
369