18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * net/dsa/dsa_priv.h - Hardware switch handling
48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009 Marvell Semiconductor
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#ifndef __DSA_PRIV_H
88c2ecf20Sopenharmony_ci#define __DSA_PRIV_H
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/if_bridge.h>
118c2ecf20Sopenharmony_ci#include <linux/phy.h>
128c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/netpoll.h>
148c2ecf20Sopenharmony_ci#include <net/dsa.h>
158c2ecf20Sopenharmony_ci#include <net/gro_cells.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cienum {
188c2ecf20Sopenharmony_ci	DSA_NOTIFIER_AGEING_TIME,
198c2ecf20Sopenharmony_ci	DSA_NOTIFIER_BRIDGE_JOIN,
208c2ecf20Sopenharmony_ci	DSA_NOTIFIER_BRIDGE_LEAVE,
218c2ecf20Sopenharmony_ci	DSA_NOTIFIER_FDB_ADD,
228c2ecf20Sopenharmony_ci	DSA_NOTIFIER_FDB_DEL,
238c2ecf20Sopenharmony_ci	DSA_NOTIFIER_MDB_ADD,
248c2ecf20Sopenharmony_ci	DSA_NOTIFIER_MDB_DEL,
258c2ecf20Sopenharmony_ci	DSA_NOTIFIER_VLAN_ADD,
268c2ecf20Sopenharmony_ci	DSA_NOTIFIER_VLAN_DEL,
278c2ecf20Sopenharmony_ci	DSA_NOTIFIER_MTU,
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* DSA_NOTIFIER_AGEING_TIME */
318c2ecf20Sopenharmony_cistruct dsa_notifier_ageing_time_info {
328c2ecf20Sopenharmony_ci	struct switchdev_trans *trans;
338c2ecf20Sopenharmony_ci	unsigned int ageing_time;
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* DSA_NOTIFIER_BRIDGE_* */
378c2ecf20Sopenharmony_cistruct dsa_notifier_bridge_info {
388c2ecf20Sopenharmony_ci	struct net_device *br;
398c2ecf20Sopenharmony_ci	int tree_index;
408c2ecf20Sopenharmony_ci	int sw_index;
418c2ecf20Sopenharmony_ci	int port;
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* DSA_NOTIFIER_FDB_* */
458c2ecf20Sopenharmony_cistruct dsa_notifier_fdb_info {
468c2ecf20Sopenharmony_ci	int sw_index;
478c2ecf20Sopenharmony_ci	int port;
488c2ecf20Sopenharmony_ci	const unsigned char *addr;
498c2ecf20Sopenharmony_ci	u16 vid;
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* DSA_NOTIFIER_MDB_* */
538c2ecf20Sopenharmony_cistruct dsa_notifier_mdb_info {
548c2ecf20Sopenharmony_ci	const struct switchdev_obj_port_mdb *mdb;
558c2ecf20Sopenharmony_ci	struct switchdev_trans *trans;
568c2ecf20Sopenharmony_ci	int sw_index;
578c2ecf20Sopenharmony_ci	int port;
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/* DSA_NOTIFIER_VLAN_* */
618c2ecf20Sopenharmony_cistruct dsa_notifier_vlan_info {
628c2ecf20Sopenharmony_ci	const struct switchdev_obj_port_vlan *vlan;
638c2ecf20Sopenharmony_ci	struct switchdev_trans *trans;
648c2ecf20Sopenharmony_ci	int sw_index;
658c2ecf20Sopenharmony_ci	int port;
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* DSA_NOTIFIER_MTU */
698c2ecf20Sopenharmony_cistruct dsa_notifier_mtu_info {
708c2ecf20Sopenharmony_ci	bool propagate_upstream;
718c2ecf20Sopenharmony_ci	int sw_index;
728c2ecf20Sopenharmony_ci	int port;
738c2ecf20Sopenharmony_ci	int mtu;
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistruct dsa_slave_priv {
778c2ecf20Sopenharmony_ci	/* Copy of CPU port xmit for faster access in slave transmit hot path */
788c2ecf20Sopenharmony_ci	struct sk_buff *	(*xmit)(struct sk_buff *skb,
798c2ecf20Sopenharmony_ci					struct net_device *dev);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	struct pcpu_sw_netstats	__percpu *stats64;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	struct gro_cells	gcells;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* DSA port data, such as switch, port index, etc. */
868c2ecf20Sopenharmony_ci	struct dsa_port		*dp;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
898c2ecf20Sopenharmony_ci	struct netpoll		*netpoll;
908c2ecf20Sopenharmony_ci#endif
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* TC context */
938c2ecf20Sopenharmony_ci	struct list_head	mall_tc_list;
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* dsa.c */
978c2ecf20Sopenharmony_ciconst struct dsa_device_ops *dsa_tag_driver_get(int tag_protocol);
988c2ecf20Sopenharmony_civoid dsa_tag_driver_put(const struct dsa_device_ops *ops);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cibool dsa_schedule_work(struct work_struct *work);
1018c2ecf20Sopenharmony_ciconst char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciint dsa_legacy_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
1048c2ecf20Sopenharmony_ci		       struct net_device *dev,
1058c2ecf20Sopenharmony_ci		       const unsigned char *addr, u16 vid,
1068c2ecf20Sopenharmony_ci		       u16 flags,
1078c2ecf20Sopenharmony_ci		       struct netlink_ext_ack *extack);
1088c2ecf20Sopenharmony_ciint dsa_legacy_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
1098c2ecf20Sopenharmony_ci		       struct net_device *dev,
1108c2ecf20Sopenharmony_ci		       const unsigned char *addr, u16 vid);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* master.c */
1138c2ecf20Sopenharmony_ciint dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp);
1148c2ecf20Sopenharmony_civoid dsa_master_teardown(struct net_device *dev);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic inline struct net_device *dsa_master_find_slave(struct net_device *dev,
1178c2ecf20Sopenharmony_ci						       int device, int port)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct dsa_port *cpu_dp = dev->dsa_ptr;
1208c2ecf20Sopenharmony_ci	struct dsa_switch_tree *dst = cpu_dp->dst;
1218c2ecf20Sopenharmony_ci	struct dsa_port *dp;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	list_for_each_entry(dp, &dst->ports, list)
1248c2ecf20Sopenharmony_ci		if (dp->ds->index == device && dp->index == port &&
1258c2ecf20Sopenharmony_ci		    dp->type == DSA_PORT_TYPE_USER)
1268c2ecf20Sopenharmony_ci			return dp->slave;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return NULL;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/* port.c */
1328c2ecf20Sopenharmony_ciint dsa_port_set_state(struct dsa_port *dp, u8 state,
1338c2ecf20Sopenharmony_ci		       struct switchdev_trans *trans);
1348c2ecf20Sopenharmony_ciint dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy);
1358c2ecf20Sopenharmony_ciint dsa_port_enable(struct dsa_port *dp, struct phy_device *phy);
1368c2ecf20Sopenharmony_civoid dsa_port_disable_rt(struct dsa_port *dp);
1378c2ecf20Sopenharmony_civoid dsa_port_disable(struct dsa_port *dp);
1388c2ecf20Sopenharmony_ciint dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
1398c2ecf20Sopenharmony_civoid dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
1408c2ecf20Sopenharmony_ciint dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
1418c2ecf20Sopenharmony_ci			    struct switchdev_trans *trans);
1428c2ecf20Sopenharmony_cibool dsa_port_skip_vlan_configuration(struct dsa_port *dp);
1438c2ecf20Sopenharmony_ciint dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
1448c2ecf20Sopenharmony_ci			 struct switchdev_trans *trans);
1458c2ecf20Sopenharmony_ciint dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
1468c2ecf20Sopenharmony_ci			bool propagate_upstream);
1478c2ecf20Sopenharmony_ciint dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
1488c2ecf20Sopenharmony_ci		     u16 vid);
1498c2ecf20Sopenharmony_ciint dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
1508c2ecf20Sopenharmony_ci		     u16 vid);
1518c2ecf20Sopenharmony_ciint dsa_port_fdb_dump(struct dsa_port *dp, dsa_fdb_dump_cb_t *cb, void *data);
1528c2ecf20Sopenharmony_ciint dsa_port_mdb_add(const struct dsa_port *dp,
1538c2ecf20Sopenharmony_ci		     const struct switchdev_obj_port_mdb *mdb,
1548c2ecf20Sopenharmony_ci		     struct switchdev_trans *trans);
1558c2ecf20Sopenharmony_ciint dsa_port_mdb_del(const struct dsa_port *dp,
1568c2ecf20Sopenharmony_ci		     const struct switchdev_obj_port_mdb *mdb);
1578c2ecf20Sopenharmony_ciint dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags,
1588c2ecf20Sopenharmony_ci			      struct switchdev_trans *trans);
1598c2ecf20Sopenharmony_ciint dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags,
1608c2ecf20Sopenharmony_ci			  struct switchdev_trans *trans);
1618c2ecf20Sopenharmony_ciint dsa_port_mrouter(struct dsa_port *dp, bool mrouter,
1628c2ecf20Sopenharmony_ci		     struct switchdev_trans *trans);
1638c2ecf20Sopenharmony_ciint dsa_port_vlan_add(struct dsa_port *dp,
1648c2ecf20Sopenharmony_ci		      const struct switchdev_obj_port_vlan *vlan,
1658c2ecf20Sopenharmony_ci		      struct switchdev_trans *trans);
1668c2ecf20Sopenharmony_ciint dsa_port_vlan_del(struct dsa_port *dp,
1678c2ecf20Sopenharmony_ci		      const struct switchdev_obj_port_vlan *vlan);
1688c2ecf20Sopenharmony_ciint dsa_port_link_register_of(struct dsa_port *dp);
1698c2ecf20Sopenharmony_civoid dsa_port_link_unregister_of(struct dsa_port *dp);
1708c2ecf20Sopenharmony_ciextern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/* slave.c */
1738c2ecf20Sopenharmony_ciextern const struct dsa_device_ops notag_netdev_ops;
1748c2ecf20Sopenharmony_civoid dsa_slave_mii_bus_init(struct dsa_switch *ds);
1758c2ecf20Sopenharmony_ciint dsa_slave_create(struct dsa_port *dp);
1768c2ecf20Sopenharmony_civoid dsa_slave_destroy(struct net_device *slave_dev);
1778c2ecf20Sopenharmony_cibool dsa_slave_dev_check(const struct net_device *dev);
1788c2ecf20Sopenharmony_ciint dsa_slave_suspend(struct net_device *slave_dev);
1798c2ecf20Sopenharmony_ciint dsa_slave_resume(struct net_device *slave_dev);
1808c2ecf20Sopenharmony_ciint dsa_slave_register_notifier(void);
1818c2ecf20Sopenharmony_civoid dsa_slave_unregister_notifier(void);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic inline struct dsa_port *dsa_slave_to_port(const struct net_device *dev)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	struct dsa_slave_priv *p = netdev_priv(dev);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	return p->dp;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic inline struct net_device *
1918c2ecf20Sopenharmony_cidsa_slave_to_master(const struct net_device *dev)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct dsa_port *dp = dsa_slave_to_port(dev);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return dp->cpu_dp->master;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci/* If under a bridge with vlan_filtering=0, make sure to send pvid-tagged
1998c2ecf20Sopenharmony_ci * frames as untagged, since the bridge will not untag them.
2008c2ecf20Sopenharmony_ci */
2018c2ecf20Sopenharmony_cistatic inline struct sk_buff *dsa_untag_bridge_pvid(struct sk_buff *skb)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	struct dsa_port *dp = dsa_slave_to_port(skb->dev);
2048c2ecf20Sopenharmony_ci	struct net_device *br = dp->bridge_dev;
2058c2ecf20Sopenharmony_ci	struct net_device *dev = skb->dev;
2068c2ecf20Sopenharmony_ci	struct net_device *upper_dev;
2078c2ecf20Sopenharmony_ci	u16 vid, pvid, proto;
2088c2ecf20Sopenharmony_ci	int err;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (!br || br_vlan_enabled(br))
2118c2ecf20Sopenharmony_ci		return skb;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	err = br_vlan_get_proto(br, &proto);
2148c2ecf20Sopenharmony_ci	if (err)
2158c2ecf20Sopenharmony_ci		return skb;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* Move VLAN tag from data to hwaccel */
2188c2ecf20Sopenharmony_ci	if (!skb_vlan_tag_present(skb) && skb->protocol == htons(proto)) {
2198c2ecf20Sopenharmony_ci		skb = skb_vlan_untag(skb);
2208c2ecf20Sopenharmony_ci		if (!skb)
2218c2ecf20Sopenharmony_ci			return NULL;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (!skb_vlan_tag_present(skb))
2258c2ecf20Sopenharmony_ci		return skb;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	vid = skb_vlan_tag_get_id(skb);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/* We already run under an RCU read-side critical section since
2308c2ecf20Sopenharmony_ci	 * we are called from netif_receive_skb_list_internal().
2318c2ecf20Sopenharmony_ci	 */
2328c2ecf20Sopenharmony_ci	err = br_vlan_get_pvid_rcu(dev, &pvid);
2338c2ecf20Sopenharmony_ci	if (err)
2348c2ecf20Sopenharmony_ci		return skb;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (vid != pvid)
2378c2ecf20Sopenharmony_ci		return skb;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* The sad part about attempting to untag from DSA is that we
2408c2ecf20Sopenharmony_ci	 * don't know, unless we check, if the skb will end up in
2418c2ecf20Sopenharmony_ci	 * the bridge's data path - br_allowed_ingress() - or not.
2428c2ecf20Sopenharmony_ci	 * For example, there might be an 8021q upper for the
2438c2ecf20Sopenharmony_ci	 * default_pvid of the bridge, which will steal VLAN-tagged traffic
2448c2ecf20Sopenharmony_ci	 * from the bridge's data path. This is a configuration that DSA
2458c2ecf20Sopenharmony_ci	 * supports because vlan_filtering is 0. In that case, we should
2468c2ecf20Sopenharmony_ci	 * definitely keep the tag, to make sure it keeps working.
2478c2ecf20Sopenharmony_ci	 */
2488c2ecf20Sopenharmony_ci	upper_dev = __vlan_find_dev_deep_rcu(br, htons(proto), vid);
2498c2ecf20Sopenharmony_ci	if (upper_dev)
2508c2ecf20Sopenharmony_ci		return skb;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	__vlan_hwaccel_clear_tag(skb);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	return skb;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci/* switch.c */
2588c2ecf20Sopenharmony_ciint dsa_switch_register_notifier(struct dsa_switch *ds);
2598c2ecf20Sopenharmony_civoid dsa_switch_unregister_notifier(struct dsa_switch *ds);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci/* dsa2.c */
2628c2ecf20Sopenharmony_ciextern struct list_head dsa_tree_list;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci#endif
265