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