1f48298d3SIoana Ciornei /* SPDX-License-Identifier: GPL-2.0 */
2f48298d3SIoana Ciornei /*
3f48298d3SIoana Ciornei * DPAA2 Ethernet Switch declarations
4f48298d3SIoana Ciornei *
5f48298d3SIoana Ciornei * Copyright 2014-2016 Freescale Semiconductor Inc.
6f48298d3SIoana Ciornei * Copyright 2017-2021 NXP
7f48298d3SIoana Ciornei *
8f48298d3SIoana Ciornei */
9f48298d3SIoana Ciornei
10f48298d3SIoana Ciornei #ifndef __ETHSW_H
11f48298d3SIoana Ciornei #define __ETHSW_H
12f48298d3SIoana Ciornei
13f48298d3SIoana Ciornei #include <linux/netdevice.h>
14f48298d3SIoana Ciornei #include <linux/etherdevice.h>
15f48298d3SIoana Ciornei #include <linux/rtnetlink.h>
16f48298d3SIoana Ciornei #include <linux/if_vlan.h>
17f48298d3SIoana Ciornei #include <uapi/linux/if_bridge.h>
18f48298d3SIoana Ciornei #include <net/switchdev.h>
19f48298d3SIoana Ciornei #include <linux/if_bridge.h>
20f48298d3SIoana Ciornei #include <linux/fsl/mc.h>
214ba28c1aSIoana Ciornei #include <net/pkt_cls.h>
22f48298d3SIoana Ciornei #include <soc/fsl/dpaa2-io.h>
23f48298d3SIoana Ciornei
2484cba729SIoana Ciornei #include "dpaa2-mac.h"
25f48298d3SIoana Ciornei #include "dpsw.h"
26f48298d3SIoana Ciornei
27f48298d3SIoana Ciornei /* Number of IRQs supported */
28f48298d3SIoana Ciornei #define DPSW_IRQ_NUM 2
29f48298d3SIoana Ciornei
30f48298d3SIoana Ciornei /* Port is member of VLAN */
31f48298d3SIoana Ciornei #define ETHSW_VLAN_MEMBER 1
32f48298d3SIoana Ciornei /* VLAN to be treated as untagged on egress */
33f48298d3SIoana Ciornei #define ETHSW_VLAN_UNTAGGED 2
34f48298d3SIoana Ciornei /* Untagged frames will be assigned to this VLAN */
35f48298d3SIoana Ciornei #define ETHSW_VLAN_PVID 4
36f48298d3SIoana Ciornei /* VLAN configured on the switch */
37f48298d3SIoana Ciornei #define ETHSW_VLAN_GLOBAL 8
38f48298d3SIoana Ciornei
39f48298d3SIoana Ciornei /* Maximum Frame Length supported by HW (currently 10k) */
40f48298d3SIoana Ciornei #define DPAA2_MFL (10 * 1024)
41f48298d3SIoana Ciornei #define ETHSW_MAX_FRAME_LENGTH (DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN)
42f48298d3SIoana Ciornei #define ETHSW_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN)
43f48298d3SIoana Ciornei
44f48298d3SIoana Ciornei #define ETHSW_FEATURE_MAC_ADDR BIT(0)
45f48298d3SIoana Ciornei
46f48298d3SIoana Ciornei /* Number of receive queues (one RX and one TX_CONF) */
47f48298d3SIoana Ciornei #define DPAA2_SWITCH_RX_NUM_FQS 2
48f48298d3SIoana Ciornei
49f48298d3SIoana Ciornei /* Hardware requires alignment for ingress/egress buffer addresses */
50f48298d3SIoana Ciornei #define DPAA2_SWITCH_RX_BUF_RAW_SIZE PAGE_SIZE
51f48298d3SIoana Ciornei #define DPAA2_SWITCH_RX_BUF_TAILROOM \
52f48298d3SIoana Ciornei SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
53f48298d3SIoana Ciornei #define DPAA2_SWITCH_RX_BUF_SIZE \
54f48298d3SIoana Ciornei (DPAA2_SWITCH_RX_BUF_RAW_SIZE - DPAA2_SWITCH_RX_BUF_TAILROOM)
55f48298d3SIoana Ciornei
56f48298d3SIoana Ciornei #define DPAA2_SWITCH_STORE_SIZE 16
57f48298d3SIoana Ciornei
58f48298d3SIoana Ciornei /* Buffer management */
59f48298d3SIoana Ciornei #define BUFS_PER_CMD 7
60f48298d3SIoana Ciornei #define DPAA2_ETHSW_NUM_BUFS (1024 * BUFS_PER_CMD)
61f48298d3SIoana Ciornei #define DPAA2_ETHSW_REFILL_THRESH (DPAA2_ETHSW_NUM_BUFS * 5 / 6)
62f48298d3SIoana Ciornei
63f48298d3SIoana Ciornei /* Number of times to retry DPIO portal operations while waiting
64f48298d3SIoana Ciornei * for portal to finish executing current command and become
65f48298d3SIoana Ciornei * available. We want to avoid being stuck in a while loop in case
66f48298d3SIoana Ciornei * hardware becomes unresponsive, but not give up too easily if
67f48298d3SIoana Ciornei * the portal really is busy for valid reasons
68f48298d3SIoana Ciornei */
69f48298d3SIoana Ciornei #define DPAA2_SWITCH_SWP_BUSY_RETRIES 1000
70f48298d3SIoana Ciornei
71f48298d3SIoana Ciornei /* Hardware annotation buffer size */
72f48298d3SIoana Ciornei #define DPAA2_SWITCH_HWA_SIZE 64
73f48298d3SIoana Ciornei /* Software annotation buffer size */
74f48298d3SIoana Ciornei #define DPAA2_SWITCH_SWA_SIZE 64
75f48298d3SIoana Ciornei
76f48298d3SIoana Ciornei #define DPAA2_SWITCH_TX_BUF_ALIGN 64
77f48298d3SIoana Ciornei
78f48298d3SIoana Ciornei #define DPAA2_SWITCH_TX_DATA_OFFSET \
79f48298d3SIoana Ciornei (DPAA2_SWITCH_HWA_SIZE + DPAA2_SWITCH_SWA_SIZE)
80f48298d3SIoana Ciornei
81f48298d3SIoana Ciornei #define DPAA2_SWITCH_NEEDED_HEADROOM \
82f48298d3SIoana Ciornei (DPAA2_SWITCH_TX_DATA_OFFSET + DPAA2_SWITCH_TX_BUF_ALIGN)
83f48298d3SIoana Ciornei
8490f07102SIoana Ciornei #define DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES 16
851110318dSIoana Ciornei #define DPAA2_ETHSW_PORT_DEFAULT_TRAPS 1
861110318dSIoana Ciornei
871a64ed12SIoana Ciornei #define DPAA2_ETHSW_PORT_ACL_CMD_BUF_SIZE 256
8890f07102SIoana Ciornei
89f48298d3SIoana Ciornei extern const struct ethtool_ops dpaa2_switch_port_ethtool_ops;
90f48298d3SIoana Ciornei
91f48298d3SIoana Ciornei struct ethsw_core;
92f48298d3SIoana Ciornei
93f48298d3SIoana Ciornei struct dpaa2_switch_fq {
94f48298d3SIoana Ciornei struct ethsw_core *ethsw;
95f48298d3SIoana Ciornei enum dpsw_queue_type type;
96f48298d3SIoana Ciornei struct dpaa2_io_store *store;
97f48298d3SIoana Ciornei struct dpaa2_io_notification_ctx nctx;
98f48298d3SIoana Ciornei struct napi_struct napi;
99f48298d3SIoana Ciornei u32 fqid;
100f48298d3SIoana Ciornei };
101f48298d3SIoana Ciornei
102f48298d3SIoana Ciornei struct dpaa2_switch_fdb {
103f48298d3SIoana Ciornei struct net_device *bridge_dev;
104f48298d3SIoana Ciornei u16 fdb_id;
105f48298d3SIoana Ciornei bool in_use;
106f48298d3SIoana Ciornei };
107f48298d3SIoana Ciornei
1081110318dSIoana Ciornei struct dpaa2_switch_acl_entry {
1091110318dSIoana Ciornei struct list_head list;
1101110318dSIoana Ciornei u16 prio;
1111110318dSIoana Ciornei unsigned long cookie;
1121110318dSIoana Ciornei
1131110318dSIoana Ciornei struct dpsw_acl_entry_cfg cfg;
1141110318dSIoana Ciornei struct dpsw_acl_key key;
1151110318dSIoana Ciornei };
1161110318dSIoana Ciornei
117e0ead825SIoana Ciornei struct dpaa2_switch_mirror_entry {
118e0ead825SIoana Ciornei struct list_head list;
119e0ead825SIoana Ciornei struct dpsw_reflection_cfg cfg;
120e0ead825SIoana Ciornei unsigned long cookie;
121e0ead825SIoana Ciornei u16 if_id;
122e0ead825SIoana Ciornei };
123e0ead825SIoana Ciornei
124adcb7aa3SIoana Ciornei struct dpaa2_switch_filter_block {
1251110318dSIoana Ciornei struct ethsw_core *ethsw;
1261110318dSIoana Ciornei u64 ports;
1271b0f14b6SIoana Ciornei bool in_use;
128adcb7aa3SIoana Ciornei
129adcb7aa3SIoana Ciornei struct list_head acl_entries;
130adcb7aa3SIoana Ciornei u16 acl_id;
131adcb7aa3SIoana Ciornei u8 num_acl_rules;
132e0ead825SIoana Ciornei
133e0ead825SIoana Ciornei struct list_head mirror_entries;
1341b0f14b6SIoana Ciornei };
1351b0f14b6SIoana Ciornei
1361110318dSIoana Ciornei static inline bool
dpaa2_switch_acl_tbl_is_full(struct dpaa2_switch_filter_block * filter_block)137adcb7aa3SIoana Ciornei dpaa2_switch_acl_tbl_is_full(struct dpaa2_switch_filter_block *filter_block)
1381110318dSIoana Ciornei {
139adcb7aa3SIoana Ciornei if ((filter_block->num_acl_rules + DPAA2_ETHSW_PORT_DEFAULT_TRAPS) >=
1401110318dSIoana Ciornei DPAA2_ETHSW_PORT_MAX_ACL_ENTRIES)
1411110318dSIoana Ciornei return true;
1421110318dSIoana Ciornei return false;
1431110318dSIoana Ciornei }
1441110318dSIoana Ciornei
145f48298d3SIoana Ciornei /* Per port private data */
146f48298d3SIoana Ciornei struct ethsw_port_priv {
147f48298d3SIoana Ciornei struct net_device *netdev;
148f48298d3SIoana Ciornei u16 idx;
149f48298d3SIoana Ciornei struct ethsw_core *ethsw_data;
150f48298d3SIoana Ciornei u8 link_state;
151f48298d3SIoana Ciornei u8 stp_state;
152f48298d3SIoana Ciornei
153f48298d3SIoana Ciornei u8 vlans[VLAN_VID_MASK + 1];
154f48298d3SIoana Ciornei u16 pvid;
155f48298d3SIoana Ciornei u16 tx_qdid;
156f48298d3SIoana Ciornei
157f48298d3SIoana Ciornei struct dpaa2_switch_fdb *fdb;
158b54eb093SIoana Ciornei bool bcast_flood;
1596253d5e3SIoana Ciornei bool ucast_flood;
16062734c74SIoana Ciornei bool learn_ena;
16190f07102SIoana Ciornei
162adcb7aa3SIoana Ciornei struct dpaa2_switch_filter_block *filter_block;
16384cba729SIoana Ciornei struct dpaa2_mac *mac;
164*3c7f44faSVladimir Oltean /* Protects against changes to port_priv->mac */
165*3c7f44faSVladimir Oltean struct mutex mac_lock;
166f48298d3SIoana Ciornei };
167f48298d3SIoana Ciornei
168f48298d3SIoana Ciornei /* Switch data */
169f48298d3SIoana Ciornei struct ethsw_core {
170f48298d3SIoana Ciornei struct device *dev;
171f48298d3SIoana Ciornei struct fsl_mc_io *mc_io;
172f48298d3SIoana Ciornei u16 dpsw_handle;
173f48298d3SIoana Ciornei struct dpsw_attr sw_attr;
174f48298d3SIoana Ciornei u16 major, minor;
175f48298d3SIoana Ciornei unsigned long features;
176f48298d3SIoana Ciornei int dev_id;
177f48298d3SIoana Ciornei struct ethsw_port_priv **ports;
178f48298d3SIoana Ciornei struct iommu_domain *iommu_domain;
179f48298d3SIoana Ciornei
180f48298d3SIoana Ciornei u8 vlans[VLAN_VID_MASK + 1];
181f48298d3SIoana Ciornei
182f48298d3SIoana Ciornei struct workqueue_struct *workqueue;
183f48298d3SIoana Ciornei
184f48298d3SIoana Ciornei struct dpaa2_switch_fq fq[DPAA2_SWITCH_RX_NUM_FQS];
185f48298d3SIoana Ciornei struct fsl_mc_device *dpbp_dev;
186f48298d3SIoana Ciornei int buf_count;
187f48298d3SIoana Ciornei u16 bpid;
188f48298d3SIoana Ciornei int napi_users;
189f48298d3SIoana Ciornei
190f48298d3SIoana Ciornei struct dpaa2_switch_fdb *fdbs;
191adcb7aa3SIoana Ciornei struct dpaa2_switch_filter_block *filter_blocks;
192e0ead825SIoana Ciornei u16 mirror_port;
193f48298d3SIoana Ciornei };
194f48298d3SIoana Ciornei
dpaa2_switch_get_index(struct ethsw_core * ethsw,struct net_device * netdev)1951110318dSIoana Ciornei static inline int dpaa2_switch_get_index(struct ethsw_core *ethsw,
1961110318dSIoana Ciornei struct net_device *netdev)
1971110318dSIoana Ciornei {
1981110318dSIoana Ciornei int i;
1991110318dSIoana Ciornei
2001110318dSIoana Ciornei for (i = 0; i < ethsw->sw_attr.num_ifs; i++)
2011110318dSIoana Ciornei if (ethsw->ports[i]->netdev == netdev)
2021110318dSIoana Ciornei return ethsw->ports[i]->idx;
2031110318dSIoana Ciornei
2041110318dSIoana Ciornei return -EINVAL;
2051110318dSIoana Ciornei }
2061110318dSIoana Ciornei
dpaa2_switch_supports_cpu_traffic(struct ethsw_core * ethsw)207f48298d3SIoana Ciornei static inline bool dpaa2_switch_supports_cpu_traffic(struct ethsw_core *ethsw)
208f48298d3SIoana Ciornei {
209f48298d3SIoana Ciornei if (ethsw->sw_attr.options & DPSW_OPT_CTRL_IF_DIS) {
210f48298d3SIoana Ciornei dev_err(ethsw->dev, "Control Interface is disabled, cannot probe\n");
211f48298d3SIoana Ciornei return false;
212f48298d3SIoana Ciornei }
213f48298d3SIoana Ciornei
214f48298d3SIoana Ciornei if (ethsw->sw_attr.flooding_cfg != DPSW_FLOODING_PER_FDB) {
215f48298d3SIoana Ciornei dev_err(ethsw->dev, "Flooding domain is not per FDB, cannot probe\n");
216f48298d3SIoana Ciornei return false;
217f48298d3SIoana Ciornei }
218f48298d3SIoana Ciornei
219f48298d3SIoana Ciornei if (ethsw->sw_attr.broadcast_cfg != DPSW_BROADCAST_PER_FDB) {
220f48298d3SIoana Ciornei dev_err(ethsw->dev, "Broadcast domain is not per FDB, cannot probe\n");
221f48298d3SIoana Ciornei return false;
222f48298d3SIoana Ciornei }
223f48298d3SIoana Ciornei
224f48298d3SIoana Ciornei if (ethsw->sw_attr.max_fdbs < ethsw->sw_attr.num_ifs) {
225f48298d3SIoana Ciornei dev_err(ethsw->dev, "The number of FDBs is lower than the number of ports, cannot probe\n");
226f48298d3SIoana Ciornei return false;
227f48298d3SIoana Ciornei }
228f48298d3SIoana Ciornei
229f48298d3SIoana Ciornei return true;
230f48298d3SIoana Ciornei }
231f48298d3SIoana Ciornei
23284cba729SIoana Ciornei static inline bool
dpaa2_switch_port_is_type_phy(struct ethsw_port_priv * port_priv)23384cba729SIoana Ciornei dpaa2_switch_port_is_type_phy(struct ethsw_port_priv *port_priv)
23484cba729SIoana Ciornei {
235320fefa9SVladimir Oltean return dpaa2_mac_is_type_phy(port_priv->mac);
23684cba729SIoana Ciornei }
23784cba729SIoana Ciornei
dpaa2_switch_port_has_mac(struct ethsw_port_priv * port_priv)23884cba729SIoana Ciornei static inline bool dpaa2_switch_port_has_mac(struct ethsw_port_priv *port_priv)
23984cba729SIoana Ciornei {
24084cba729SIoana Ciornei return port_priv->mac ? true : false;
24184cba729SIoana Ciornei }
24284cba729SIoana Ciornei
243f48298d3SIoana Ciornei bool dpaa2_switch_port_dev_check(const struct net_device *netdev);
244f48298d3SIoana Ciornei
245f48298d3SIoana Ciornei int dpaa2_switch_port_vlans_add(struct net_device *netdev,
246f48298d3SIoana Ciornei const struct switchdev_obj_port_vlan *vlan);
247f48298d3SIoana Ciornei
248f48298d3SIoana Ciornei int dpaa2_switch_port_vlans_del(struct net_device *netdev,
249f48298d3SIoana Ciornei const struct switchdev_obj_port_vlan *vlan);
250f48298d3SIoana Ciornei
251f48298d3SIoana Ciornei typedef int dpaa2_switch_fdb_cb_t(struct ethsw_port_priv *port_priv,
252f48298d3SIoana Ciornei struct fdb_dump_entry *fdb_entry,
253f48298d3SIoana Ciornei void *data);
2541110318dSIoana Ciornei
2551110318dSIoana Ciornei /* TC offload */
2561110318dSIoana Ciornei
257adcb7aa3SIoana Ciornei int dpaa2_switch_cls_flower_replace(struct dpaa2_switch_filter_block *block,
2581110318dSIoana Ciornei struct flow_cls_offload *cls);
2591110318dSIoana Ciornei
260adcb7aa3SIoana Ciornei int dpaa2_switch_cls_flower_destroy(struct dpaa2_switch_filter_block *block,
2611110318dSIoana Ciornei struct flow_cls_offload *cls);
2624ba28c1aSIoana Ciornei
263adcb7aa3SIoana Ciornei int dpaa2_switch_cls_matchall_replace(struct dpaa2_switch_filter_block *block,
2644ba28c1aSIoana Ciornei struct tc_cls_matchall_offload *cls);
2654ba28c1aSIoana Ciornei
266adcb7aa3SIoana Ciornei int dpaa2_switch_cls_matchall_destroy(struct dpaa2_switch_filter_block *block,
2674ba28c1aSIoana Ciornei struct tc_cls_matchall_offload *cls);
26816617954SIoana Ciornei
269adcb7aa3SIoana Ciornei int dpaa2_switch_acl_entry_add(struct dpaa2_switch_filter_block *block,
27016617954SIoana Ciornei struct dpaa2_switch_acl_entry *entry);
2717a91f907SIoana Ciornei
2727a91f907SIoana Ciornei int dpaa2_switch_block_offload_mirror(struct dpaa2_switch_filter_block *block,
2737a91f907SIoana Ciornei struct ethsw_port_priv *port_priv);
2747a91f907SIoana Ciornei
2757a91f907SIoana Ciornei int dpaa2_switch_block_unoffload_mirror(struct dpaa2_switch_filter_block *block,
2767a91f907SIoana Ciornei struct ethsw_port_priv *port_priv);
277f48298d3SIoana Ciornei #endif /* __ETHSW_H */
278